Initial commit of Command & Conquer Red Alert source code.

This commit is contained in:
LFeenanEA 2025-02-27 16:15:05 +00:00
parent b685cea758
commit 5e733d5dcc
No known key found for this signature in database
GPG key ID: C6EBE8C2EA08F7E0
2082 changed files with 797727 additions and 0 deletions

4848
CODE/2KEYFBUF.ASM Normal file

File diff suppressed because it is too large Load diff

583
CODE/2KEYFRAM.CPP Normal file
View file

@ -0,0 +1,583 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/2KEYFRAM.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : KEYFRAME.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 06/25/95 *
* *
* Last Update : June 25, 1995 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* Get_Build_Frame_Count -- Fetches the number of frames in data block. *
* Get_Build_Frame_Width -- Fetches the width of the shape image. *
* Get_Build_Frame_Height -- Fetches the height of the shape image. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
#define SUBFRAMEOFFS 7 // 3 1/2 frame offsets loaded (2 offsets/frame)
#define Apply_Delta(buffer, delta) Apply_XOR_Delta((char*)(buffer), (char*)(delta))
typedef struct {
unsigned short frames;
unsigned short x;
unsigned short y;
unsigned short width;
unsigned short height;
unsigned short largest_frame_size;
short flags;
} KeyFrameHeaderType;
#define INITIAL_BIG_SHAPE_BUFFER_SIZE 8000000
#define THEATER_BIG_SHAPE_BUFFER_SIZE 4000000
#define UNCOMPRESS_MAGIC_NUMBER 56789
unsigned BigShapeBufferLength = INITIAL_BIG_SHAPE_BUFFER_SIZE;
unsigned TheaterShapeBufferLength = THEATER_BIG_SHAPE_BUFFER_SIZE;
extern "C"{
char *BigShapeBufferStart = NULL;
char *TheaterShapeBufferStart = NULL;
BOOL UseBigShapeBuffer = FALSE;
bool IsTheaterShape = false;
}
#ifdef FIXIT_SCORE_CRASH
/*
** Global required to fix the score screen crash bug by allowing disabling of uncompressed shapes.
*/
bool OriginalUseBigShapeBuffer = false;
#endif //FIXIT
char *BigShapeBufferPtr = NULL;
int TotalBigShapes=0;
BOOL ReallocShapeBufferFlag = FALSE;
char *TheaterShapeBufferPtr = NULL;
int TotalTheaterShapes = 0;
#define MAX_SLOTS 1500
#define THEATER_SLOT_START 1000
char **KeyFrameSlots [MAX_SLOTS];
int TotalSlotsUsed=0;
int TheaterSlotsUsed = THEATER_SLOT_START;
typedef struct tShapeHeaderType{
unsigned draw_flags;
char *shape_data;
int shape_buffer; //1 if shape is in theater buffer
} ShapeHeaderType;
static int Length;
void *Get_Shape_Header_Data(void *ptr)
{
if (UseBigShapeBuffer) {
ShapeHeaderType *header = (ShapeHeaderType*) ptr;
return ((void*) (header->shape_data + (long)(header->shape_buffer ? TheaterShapeBufferStart : BigShapeBufferStart) ) );
} else {
return (ptr);
}
}
int Get_Last_Frame_Length(void)
{
return(Length);
}
void Reset_Theater_Shapes (void)
{
/*
** Delete any previously allocated slots
*/
for (int i=THEATER_SLOT_START ; i<TheaterSlotsUsed ; i++) {
delete [] KeyFrameSlots [i];
}
TheaterShapeBufferPtr = TheaterShapeBufferStart;
TotalTheaterShapes = 0;
TheaterSlotsUsed = THEATER_SLOT_START;
}
void Reallocate_Big_Shape_Buffer(void)
{
if (ReallocShapeBufferFlag) {
BigShapeBufferLength += 2000000; //Extra 2 Mb of uncompressed shape space
BigShapeBufferPtr -= (unsigned)BigShapeBufferStart;
Memory_Error = NULL;
BigShapeBufferStart = (char*)Resize_Alloc(BigShapeBufferStart, BigShapeBufferLength);
Memory_Error = &Memory_Error_Handler;
/*
** If we have run out of memory then disable the uncompressed shapes
** It may still be possible to continue with compressed shapes
*/
if (!BigShapeBufferStart) {
UseBigShapeBuffer = false;
return;
}
BigShapeBufferPtr += (unsigned)BigShapeBufferStart;
ReallocShapeBufferFlag = FALSE;
}
}
#ifdef FIXIT_SCORE_CRASH
/***********************************************************************************************
* Disable_Uncompressed_Shapes -- Temporarily turns off shape decompression *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 11/19/96 2:37PM ST : Created *
*=============================================================================================*/
void Disable_Uncompressed_Shapes (void)
{
UseBigShapeBuffer = false;
}
/***********************************************************************************************
* Enable_Uncompressed_Shapes -- Restores state of shape decompression before it was disabled *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 11/19/96 2:37PM ST : Created *
*=============================================================================================*/
void Enable_Uncompressed_Shapes (void)
{
UseBigShapeBuffer = OriginalUseBigShapeBuffer;
}
#endif //FIXIT
void Check_Use_Compressed_Shapes (void)
{
MEMORYSTATUS mem_info;
mem_info.dwLength=sizeof(mem_info);
GlobalMemoryStatus(&mem_info);
UseBigShapeBuffer = (mem_info.dwTotalPhys > 16*1024*1024) ? TRUE : FALSE;
#ifdef FIXIT_SCORE_CRASH
/*
** Keep track of our original decision about whether to use cached shapes.
** This is needed for the score screen crash fix.
*/
OriginalUseBigShapeBuffer = UseBigShapeBuffer;
#endif //FIXIT
}
unsigned long Build_Frame(void const *dataptr, unsigned short framenumber, void *buffptr)
{
#ifdef FIXIT_SCORE_CRASH
char *ptr;
unsigned long offcurr, offdiff;
#else
char *ptr, *lockptr;//, *uncomp_ptr;
unsigned long offcurr, off16, offdiff;
#endif
unsigned long offset[SUBFRAMEOFFS];
KeyFrameHeaderType *keyfr;
unsigned short buffsize, currframe, subframe;
unsigned long length = 0;
char frameflags;
unsigned long return_value;
char *temp_shape_ptr;
//
// valid pointer??
//
Length = 0;
if ( !dataptr || !buffptr ) {
return(0);
}
//
// look at header then check that frame to build is not greater
// than total frames
//
keyfr = (KeyFrameHeaderType *) dataptr;
if ( framenumber >= keyfr->frames ) {
return(0);
}
if (UseBigShapeBuffer) {
/*
** If we havnt yet allocated memory for uncompressed shapes then do so now.
**
*/
if (!BigShapeBufferStart) {
BigShapeBufferStart = (char*)Alloc(BigShapeBufferLength, MEM_NORMAL);
BigShapeBufferPtr = BigShapeBufferStart;
/*
** Allocate memory for theater specific uncompressed shapes
*/
TheaterShapeBufferStart = (char*) Alloc (TheaterShapeBufferLength, MEM_NORMAL);
TheaterShapeBufferPtr = TheaterShapeBufferStart;
}
/*
** If we are running out of memory (<10k left) for uncompressed shapes
** then allocate some more.
*/
if (( (unsigned)BigShapeBufferStart + BigShapeBufferLength) - (unsigned)BigShapeBufferPtr < 128000) {
ReallocShapeBufferFlag = TRUE;
}
/*
** If this animation was not previously uncompressed then
** allocate memory to keep the pointers to the uncompressed data
** for these animation frames
*/
if (keyfr->x != UNCOMPRESS_MAGIC_NUMBER) {
keyfr->x = UNCOMPRESS_MAGIC_NUMBER;
if (IsTheaterShape) {
keyfr->y = TheaterSlotsUsed;
TheaterSlotsUsed++;
} else {
keyfr->y = TotalSlotsUsed;
TotalSlotsUsed++;
}
/*
** Allocate and clear the memory for the shape info
*/
KeyFrameSlots[keyfr->y]= new char *[keyfr->frames];
memset (KeyFrameSlots[keyfr->y] , 0 , keyfr->frames*4);
}
/*
** If this frame was previously uncompressed then just return
** a pointer to the raw data
*/
if (*(KeyFrameSlots[keyfr->y]+framenumber)) {
if (IsTheaterShape) {
return ((unsigned long)TheaterShapeBufferStart + (unsigned long)*(KeyFrameSlots[keyfr->y]+framenumber));
} else {
return ((unsigned long)BigShapeBufferStart + (unsigned long)*(KeyFrameSlots[keyfr->y]+framenumber));
}
}
}
// calc buff size
buffsize = keyfr->width * keyfr->height;
// get offset into data
ptr = (char *)Add_Long_To_Pointer( dataptr, (((unsigned long)framenumber << 3) + sizeof(KeyFrameHeaderType)) );
Mem_Copy( ptr, &offset[0], 12L );
frameflags = (char)(offset[0] >> 24);
if ( (frameflags & KF_KEYFRAME) ) {
ptr = (char *)Add_Long_To_Pointer( dataptr, (offset[0] & 0x00FFFFFFL) );
if (keyfr->flags & 1 ) {
ptr = (char *)Add_Long_To_Pointer( ptr, 768L );
}
length = LCW_Uncompress( ptr, buffptr, buffsize );
} else { // key delta or delta
if ( (frameflags & KF_DELTA) ) {
currframe = (unsigned short)offset[1];
ptr = (char *)Add_Long_To_Pointer( dataptr, (((unsigned long)currframe << 3) + sizeof(KeyFrameHeaderType)) );
Mem_Copy( ptr, &offset[0], (long)(SUBFRAMEOFFS * sizeof(unsigned long)) );
}
// key frame
offcurr = offset[1] & 0x00FFFFFFL;
// key delta
offdiff = (offset[0] & 0x00FFFFFFL) - offcurr;
ptr = (char *)Add_Long_To_Pointer( dataptr, offcurr );
if (keyfr->flags & 1 ) {
ptr = (char *)Add_Long_To_Pointer( ptr, 768L );
}
#ifndef FIXIT_SCORE_CRASH
off16 = (unsigned long)lockptr & 0x00003FFFL;
#endif
length = LCW_Uncompress( ptr, buffptr, buffsize );
if (length > buffsize) {
return(0);
}
#ifndef FIXIT_SCORE_CRASH
if ( ((offset[2] & 0x00FFFFFFL) - offcurr) >= (0x00010000L - off16) ) {
ptr = (char *)Add_Long_To_Pointer( ptr, offdiff );
off16 = (unsigned long)ptr & 0x00003FFFL;
offcurr += offdiff;
offdiff = 0;
}
#endif
length = buffsize;
Apply_Delta(buffptr, Add_Long_To_Pointer(ptr, offdiff));
if ( (frameflags & KF_DELTA) ) {
// adjust to delta after the keydelta
currframe++;
subframe = 2;
while (currframe <= framenumber) {
offdiff = (offset[subframe] & 0x00FFFFFFL) - offcurr;
#ifndef FIXIT_SCORE_CRASH
if ( ((offset[subframe+2] & 0x00FFFFFFL) - offcurr) >= (0x00010000L - off16) ) {
ptr = (char *)Add_Long_To_Pointer( ptr, offdiff );
off16 = (unsigned long)lockptr & 0x00003FFFL;
offcurr += offdiff;
offdiff = 0;
}
#endif
length = buffsize;
Apply_Delta(buffptr, Add_Long_To_Pointer(ptr, offdiff));
currframe++;
subframe += 2;
if ( subframe >= (SUBFRAMEOFFS - 1) &&
currframe <= framenumber ) {
Mem_Copy( Add_Long_To_Pointer( dataptr,
(((unsigned long)currframe << 3) +
sizeof(KeyFrameHeaderType)) ),
&offset[0], (long)(SUBFRAMEOFFS * sizeof(unsigned long)) );
subframe = 0;
}
}
}
}
if (UseBigShapeBuffer) {
/*
** Save the uncompressed shape data so we dont have to uncompress it
** again next time its drawn.
** We keep a space free before the raw shape data so we can add line
** header info before the shape is drawn for the first time
*/
if (IsTheaterShape) {
/*
** Shape is a theater specific shape
*/
return_value = (unsigned long) TheaterShapeBufferPtr;
temp_shape_ptr = TheaterShapeBufferPtr + keyfr->height+sizeof(ShapeHeaderType);
/*
** align the actual shape data
*/
if (3 & (unsigned)temp_shape_ptr) {
temp_shape_ptr = (char *) ((unsigned)(temp_shape_ptr + 3) & 0xfffffffc);
}
memcpy (temp_shape_ptr , buffptr , length);
((ShapeHeaderType *)TheaterShapeBufferPtr)->draw_flags = -1; //Flag that headers need to be generated
((ShapeHeaderType *)TheaterShapeBufferPtr)->shape_data = temp_shape_ptr - (unsigned)TheaterShapeBufferStart; //pointer to old raw shape data
((ShapeHeaderType *)TheaterShapeBufferPtr)->shape_buffer = 1; //Theater buffer
*(KeyFrameSlots[keyfr->y]+framenumber) = TheaterShapeBufferPtr - (unsigned)TheaterShapeBufferStart;
TheaterShapeBufferPtr = (char*)(length + (unsigned)temp_shape_ptr);
/*
** Align the next shape
*/
if (3 & (unsigned)TheaterShapeBufferPtr) {
TheaterShapeBufferPtr = (char *)((unsigned)(TheaterShapeBufferPtr + 3) & 0xfffffffc);
}
Length = length;
return (return_value);
} else {
return_value=(unsigned long)BigShapeBufferPtr;
temp_shape_ptr = BigShapeBufferPtr + keyfr->height+sizeof(ShapeHeaderType);
/*
** align the actual shape data
*/
if (3 & (unsigned)temp_shape_ptr) {
temp_shape_ptr = (char *) ((unsigned)(temp_shape_ptr + 3) & 0xfffffffc);
}
memcpy (temp_shape_ptr , buffptr , length);
((ShapeHeaderType *)BigShapeBufferPtr)->draw_flags = -1; //Flag that headers need to be generated
((ShapeHeaderType *)BigShapeBufferPtr)->shape_data = temp_shape_ptr - (unsigned)BigShapeBufferStart; //pointer to old raw shape data
((ShapeHeaderType *)BigShapeBufferPtr)->shape_buffer = 0; //Normal Big Shape Buffer
*(KeyFrameSlots[keyfr->y]+framenumber) = BigShapeBufferPtr - (unsigned)BigShapeBufferStart;
BigShapeBufferPtr = (char*)(length + (unsigned)temp_shape_ptr);
// Align the next shape
if (3 & (unsigned)BigShapeBufferPtr) {
BigShapeBufferPtr = (char *)((unsigned)(BigShapeBufferPtr + 3) & 0xfffffffc);
}
Length = length;
return (return_value);
}
} else {
return ((unsigned long)buffptr);
}
}
/***********************************************************************************************
* Get_Build_Frame_Count -- Fetches the number of frames in data block. *
* *
* Use this routine to determine the number of shapes within the data block. *
* *
* INPUT: dataptr -- Pointer to the keyframe shape data block. *
* *
* OUTPUT: Returns with the number of shapes in the data block. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/25/1995 JLB : Commented. *
*=============================================================================================*/
unsigned short Get_Build_Frame_Count(void const *dataptr)
{
if (dataptr) {
return(((KeyFrameHeaderType const *)dataptr)->frames);
}
return(0);
}
unsigned short Get_Build_Frame_X(void const *dataptr)
{
if (dataptr) {
return(((KeyFrameHeaderType const *)dataptr)->x);
}
return(0);
}
unsigned short Get_Build_Frame_Y(void const *dataptr)
{
if (dataptr) {
return(((KeyFrameHeaderType const *)dataptr)->y);
}
return(0);
}
/***********************************************************************************************
* Get_Build_Frame_Width -- Fetches the width of the shape image. *
* *
* Use this routine to fetch the width of the shapes within the keyframe shape data block. *
* All shapes within the block have the same width. *
* *
* INPUT: dataptr -- Pointer to the keyframe shape data block. *
* *
* OUTPUT: Returns with the width of the shapes in the block -- expressed in pixels. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/25/1995 JLB : Commented *
*=============================================================================================*/
unsigned short Get_Build_Frame_Width(void const *dataptr)
{
if (dataptr) {
return(((KeyFrameHeaderType const *)dataptr)->width);
}
return(0);
}
/***********************************************************************************************
* Get_Build_Frame_Height -- Fetches the height of the shape image. *
* *
* Use this routine to fetch the height of the shapes within the keyframe shape data block. *
* All shapes within the block have the same height. *
* *
* INPUT: dataptr -- Pointer to the keyframe shape data block. *
* *
* OUTPUT: Returns with the height of the shapes in the block -- expressed in pixels. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/25/1995 JLB : Commented *
*=============================================================================================*/
unsigned short Get_Build_Frame_Height(void const *dataptr)
{
if (dataptr) {
return(((KeyFrameHeaderType const *)dataptr)->height);
}
return(0);
}
bool Get_Build_Frame_Palette(void const * dataptr, void * palette)
{
if (dataptr && (((KeyFrameHeaderType const *)dataptr)->flags & 1)) {
char const * ptr = (char const *)Add_Long_To_Pointer( dataptr,
( (( (long)sizeof(unsigned long) << 1) *
((KeyFrameHeaderType *) dataptr)->frames ) +
16 + sizeof(KeyFrameHeaderType) ) );
memcpy(palette, ptr, 768L);
return(true);
}
return(false);
}

564
CODE/2SUPPORT.ASM Normal file
View file

@ -0,0 +1,564 @@
;
; Command & Conquer Red Alert(tm)
; Copyright 2025 Electronic Arts Inc.
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
;
; $Header: F:\projects\c&c0\vcs\code\2support.asv 5.0 11 Nov 1996 09:40:36 JOE_BOSTIC $
;***************************************************************************
;** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S **
;***************************************************************************
;* *
;* Project Name : Command & Conquer *
;* *
;* File Name : SUPPORT.ASM *
;* *
;* Programmer : Joe L. Bostic *
;* *
;* Start Date : September 23, 1993 *
;* *
;* Last Update : May 10, 1994 [JLB] *
;* *
;*-------------------------------------------------------------------------*
;* Functions: *
;* strtrim -- Remove the trailing white space from a string. *
;* Fat_Put_Pixel -- Draws a fat pixel. *
;* Conquer_Build_Fading_Table -- Builds custom shadow/light fading table.*
;* Remove_From_List -- Removes a pointer from a list of pointers. *
;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *
IDEAL
P386
MODEL USE32 FLAT
INCLUDE "gbuffer.inc"
DISPLAY "Command & Conquer assembly support routines."
CODESEG
;***************************************************************************
;* Fat_Put_Pixel -- Draws a fat pixel. *
;* *
;* Use this routine to draw a "pixel" that is bigger than 1 pixel *
;* across. This routine is faster than drawing a similar small shape *
;* and faster than calling Fill_Rect. *
;* *
;* INPUT: x,y -- Screen coordinates to draw the pixel's upper *
;* left corner. *
;* *
;* color -- The color to render the pixel in. *
;* *
;* size -- The number of pixels width of the big "pixel". *
;* *
;* page -- The pointer to a GraphicBuffer class or something *
;* *
;* OUTPUT: none *
;* *
;* WARNINGS: none *
;* *
;* HISTORY: *
;* 03/17/1994 JLB : Created. *
;*=========================================================================*
; VOID cdecl Fat_Put_Pixel(long x, long y, long color, long size, void *page)
GLOBAL C Fat_Put_Pixel:NEAR
PROC Fat_Put_Pixel C near
USES eax, ebx, ecx, edx, edi, esi
ARG x:DWORD ; X coordinate of upper left pixel corner.
ARG y:DWORD ; Y coordinate of upper left pixel corner.
ARG color:DWORD ; Color to use for the "pixel".
ARG siz:DWORD ; Size of "pixel" to plot (square).
ARG gpage:DWORD ; graphic page address to plot onto
cmp [siz],0
je short ??exit
; Set EDI to point to start of logical page memory.
;*===================================================================
; Get the viewport information and put bytes per row in ecx
;*===================================================================
mov ebx,[gpage] ; get a pointer to viewport
mov edi,[(GraphicViewPort ebx).GVPOffset] ; get the correct offset
; Verify the the Y pixel offset is legal.
mov eax,[y]
cmp eax,[(GraphicViewPort ebx).GVPHeight] ;YPIXEL_MAX
jae short ??exit
mov ecx,[(GraphicViewPort ebx).GVPWidth]
add ecx,[(GraphicViewPort ebx).GVPXAdd]
add ecx,[(GraphicViewPort ebx).GVPPitch]
mul ecx
add edi,eax
; Verify the the X pixel offset is legal.
mov edx,[(GraphicViewPort ebx).GVPWidth]
cmp edx,[x]
mov edx,ecx
jbe short ??exit
add edi,[x]
; Write the pixel to the screen.
mov ebx,[siz] ; Copy of pixel size.
sub edx,ebx ; Modulo to reach start of next row.
mov eax,[color]
??again:
mov ecx,ebx
rep stosb
add edi,edx ; EDI points to start of next row.
dec [siz]
jnz short ??again
??exit:
ret
ENDP Fat_Put_Pixel
if 0
;***************************************************************************
;* strtrim -- Remove the trailing white space from a string. *
;* *
;* Use this routine to remove white space characters from the beginning *
;* and end of the string. The string is modified in place by *
;* this routine. *
;* *
;* INPUT: buffer -- Pointer to the string to modify. *
;* *
;* OUTPUT: none *
;* *
;* WARNINGS: none *
;* *
;* HISTORY: *
;* 10/07/1992 JLB : Created. *
;*=========================================================================*
; VOID cdecl strtrim(BYTE *buffer);
GLOBAL C strtrim :NEAR
PROC strtrim C near
USES ax, edi, esi
ARG buffer:DWORD ; Pointer to string to modify.
cmp [buffer],0
je short ??fini
; Prepare for string scanning by loading pointers.
cld
mov esi,[buffer]
mov edi,esi
; Strip white space from the start of the string.
??looper:
lodsb
cmp al,20h ; Space
je short ??looper
cmp al,9 ; TAB
je short ??looper
stosb
; Copy the rest of the string.
??gruntloop:
lodsb
stosb
or al,al
jnz short ??gruntloop
dec edi
; Strip the white space from the end of the string.
??looper2:
mov [edi],al
dec edi
mov ah,[edi]
cmp ah,20h
je short ??looper2
cmp ah,9
je short ??looper2
??fini:
ret
ENDP strtrim
;***************************************************************************
;* Conquer_Build_Fading_Table -- Builds custom shadow/light fading table. *
;* *
;* This routine is used to build a special fading table for C&C. There *
;* are certain colors that get faded to and cannot be faded again. *
;* With this rule, it is possible to draw a shadow multiple times and *
;* not have it get any lighter or darker. *
;* *
;* INPUT: palette -- Pointer to the 768 byte IBM palette to build from. *
;* *
;* dest -- Pointer to the 256 byte remap table. *
;* *
;* color -- Color index of the color to "fade to". *
;* *
;* frac -- The fraction to fade to the specified color *
;* *
;* OUTPUT: Returns with pointer to the remap table. *
;* *
;* WARNINGS: none *
;* *
;* HISTORY: *
;* 10/07/1992 JLB : Created. *
;*=========================================================================*/
;VOID * cdecl Conquer_Build_Fading_Table(VOID *palette, VOID *dest, long color, long frac);
GLOBAL C Conquer_Build_Fading_Table : NEAR
PROC Conquer_Build_Fading_Table C near
USES ebx, ecx, edi, esi
ARG palette:DWORD
ARG dest:DWORD
ARG color:DWORD
ARG frac:DWORD
LOCAL matchvalue:DWORD ; Last recorded match value.
LOCAL targetred:BYTE ; Target gun red.
LOCAL targetgreen:BYTE ; Target gun green.
LOCAL targetblue:BYTE ; Target gun blue.
LOCAL idealred:BYTE
LOCAL idealgreen:BYTE
LOCAL idealblue:BYTE
LOCAL matchcolor:BYTE ; Tentative match color.
ALLOWED_COUNT EQU 16
ALLOWED_START EQU 256-ALLOWED_COUNT
cld
; If the source palette is NULL, then just return with current fading table pointer.
cmp [palette],0
je ??fini1
cmp [dest],0
je ??fini1
; Fractions above 255 become 255.
mov eax,[frac]
cmp eax,0100h
jb short ??ok
mov [frac],0FFh
??ok:
; Record the target gun values.
mov esi,[palette]
mov ebx,[color]
add esi,ebx
add esi,ebx
add esi,ebx
lodsb
mov [targetred],al
lodsb
mov [targetgreen],al
lodsb
mov [targetblue],al
; Main loop.
xor ebx,ebx ; Remap table index.
; Transparent black never gets remapped.
mov edi,[dest]
mov [edi],bl
inc edi
; EBX = source palette logical number (1..255).
; EDI = running pointer into dest remap table.
??mainloop:
inc ebx
mov esi,[palette]
add esi,ebx
add esi,ebx
add esi,ebx
mov edx,[frac]
shr edx,1
; new = orig - ((orig-target) * fraction);
lodsb ; orig
mov dh,al ; preserve it for later.
sub al,[targetred] ; al = (orig-target)
imul dl ; ax = (orig-target)*fraction
shl eax,1
sub dh,ah ; dh = orig - ((orig-target) * fraction)
mov [idealred],dh ; preserve ideal color gun value.
lodsb ; orig
mov dh,al ; preserve it for later.
sub al,[targetgreen] ; al = (orig-target)
imul dl ; ax = (orig-target)*fraction
shl eax,1
sub dh,ah ; dh = orig - ((orig-target) * fraction)
mov [idealgreen],dh ; preserve ideal color gun value.
lodsb ; orig
mov dh,al ; preserve it for later.
sub al,[targetblue] ; al = (orig-target)
imul dl ; ax = (orig-target)*fraction
shl eax,1
sub dh,ah ; dh = orig - ((orig-target) * fraction)
mov [idealblue],dh ; preserve ideal color gun value.
; Sweep through a limited set of existing colors to find the closest
; matching color.
mov eax,[color]
mov [matchcolor],al ; Default color (self).
mov [matchvalue],-1 ; Ridiculous match value init.
mov ecx,ALLOWED_COUNT
mov esi,[palette] ; Pointer to original palette.
add esi,(ALLOWED_START)*3
; BH = color index.
mov bh,ALLOWED_START
??innerloop:
xor edx,edx ; Comparison value starts null.
; Build the comparison value based on the sum of the differences of the color
; guns squared.
lodsb
sub al,[idealred]
mov ah,al
imul ah
add edx,eax
lodsb
sub al,[idealgreen]
mov ah,al
imul ah
add edx,eax
lodsb
sub al,[idealblue]
mov ah,al
imul ah
add edx,eax
jz short ??perfect ; If perfect match found then quit early.
cmp edx,[matchvalue]
jae short ??notclose
mov [matchvalue],edx ; Record new possible color.
mov [matchcolor],bh
??notclose:
inc bh ; Checking color index.
loop ??innerloop
mov bh,[matchcolor]
??perfect:
mov [matchcolor],bh
xor bh,bh ; Make BX valid main index again.
; When the loop exits, we have found the closest match.
mov al,[matchcolor]
stosb
cmp ebx,ALLOWED_START-1
jne ??mainloop
; Fill the remainder of the remap table with values
; that will remap the color to itself.
mov ecx,ALLOWED_COUNT
??fillerloop:
inc bl
mov al,bl
stosb
loop ??fillerloop
??fini1:
mov esi,[dest]
mov eax,esi
ret
ENDP Conquer_Build_Fading_Table
;***************************************************************************
;* Remove_From_List -- Removes a pointer from a list of pointers. *
;* *
;* This low level routine is used to remove a pointer from a list of *
;* pointers. The trailing pointers are moved downward to fill the *
;* hole. *
;* *
;* INPUT: list -- Pointer to list of pointer. *
;* *
;* index -- Pointer to length of pointer list. *
;* *
;* ptr -- The pointer value to search for and remove. *
;* *
;* OUTPUT: none *
;* *
;* WARNINGS: none *
;* *
;* HISTORY: *
;* 04/11/1994 JLB : Created. *
;* 04/22/1994 JLB : Convert to assembly language. *
;* 05/10/1994 JLB : Short pointers now. *
;*=========================================================================*/
;VOID cdecl Remove_From_List(VOID **list, long *index, long ptr);
GLOBAL C Remove_From_List:NEAR
PROC Remove_From_List C near
USES edi, esi, ecx, eax
ARG list:DWORD ; Pointer to list.
ARG index:DWORD ; Pointer to count.
ARG element:DWORD ; Element to remove.
; Fetch the number of elements in the list. If there are no
; elements, then just exit quickly.
mov edi,[index]
mov ecx,[edi]
jcxz short ??fini2
; Fetch pointer to list.
cmp [list],0
je short ??fini2
mov edi,[list]
; Loop through all elements searching for a match.
mov eax,[element]
repne scasd
jne short ??fini2 ; No match found.
; Copy all remaining elements down. If this is the
; last element in the list then nothing needs to be
; copied -- just decrement the list size.
jcxz short ??nocopy ; No copy necessary.
mov esi,edi
sub edi,4
rep movsd
; Reduce the list count by one.
??nocopy:
mov edi,[index]
dec [DWORD PTR edi]
??fini2:
ret
ENDP Remove_From_List
; long cdecl Get_EAX();
GLOBAL C Get_EAX :NEAR
PROC Get_EAX C near
ret
ENDP Get_EAX
endif
DATASEG
TabA DD 6949350
DD 4913933
DD 3474675
DD 2456966
DD 1737338
DD 1228483
DD 868669
DD 614242
DD 434334
DD 307121
DD 217167
DD 153560
DD 108584
DD 76780
DD 54292
DD 38390
DD 27146
DD 19195
DD 13573
DD 9598
DD 6786
DD 4799
DD 3393
DD 2399
DD 1697
DD 1200
DD 848
DD 600
DD 424
DD 300
DD 212
DD 150
DD 106
TabB DD 154
DD 218
DD 309
DD 437
DD 618
DD 874
DD 1236
DD 1748
DD 2472
DD 3496
DD 4944
DD 6992
DD 9888
DD 13983
DD 19775
DD 27967
DD 39551
DD 55933
DD 79101
DD 111866
DD 158203
DD 223732
DD 316405
DD 447465
DD 632811
DD 894929
DD 1265621
DD 1789859
DD 2531243
DD 3579718
DD 5062486
DD 7159436
DD 10124971
CODESEG
;***********************************************************************************************
;* Square_Root -- Finds the square root of the fixed pointer parameter. *
;* *
;* INPUT: val -- The fixed point (16:16) value to find the square root of. *
;* *
;* OUTPUT: Returns with the square root of the fixed pointer parameter. *
;* *
;* WARNINGS: none *
;* *
;* HISTORY: *
;* 10/04/1995 JLB : Adapted. *
;*=============================================================================================*/
;unsigned Square_Root(unsigned val);
GLOBAL C Square_Root :NEAR
PROC Square_Root C near
USES ebx,edx
bsr ebx,eax
jz ??zero
mul [DWORD 4*ebx + OFFSET TabA]
shrd eax,edx,10h
add eax, [4*ebx + OFFSET TabB]
??zero:
ret
ENDP Square_Root
;----------------------------------------------------------------------------
END

507
CODE/2TXTPRNT.ASM Normal file
View file

@ -0,0 +1,507 @@
;
; Command & Conquer Red Alert(tm)
; Copyright 2025 Electronic Arts Inc.
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
;
;***************************************************************************
;** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S **
;***************************************************************************
;* *
;* Project Name : Westwood 32 bit Library *
;* *
;* File Name : TXTPRNT.ASM *
;* *
;* Programmer : Phil W. Gorrow *
;* *
;* Start Date : January 17, 1995 *
;* *
;* Last Update : January 17, 1995 [PWG] *
;* *
;*-------------------------------------------------------------------------*
;* Functions: *
;* MCGA_Print -- Assembly MCGA text print routine *
;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *
IDEAL
P386
MODEL USE32 FLAT
;INCLUDE "mcgaprim.inc"
;INCLUDE ".\gbuffer.inc"
GLOBAL C Buffer_Print : NEAR
STRUC GraphicViewPort
GVPOffset DD ? ; offset to virtual viewport
GVPWidth DD ? ; width of virtual viewport
GVPHeight DD ? ; height of virtual viewport
GVPXAdd DD ? ; x mod to get to next line
GVPXPos DD ? ; x pos relative to Graphic Buff
GVPYPos DD ? ; y pos relative to Graphic Buff
GVPPitch dd ? ; modulo of graphic view port
GVPBuffPtr DD ? ; ptr to associated Graphic Buff
ENDS
;*=========================================================================*
;* Extern the font pointer which is defined by the font class *
;*=========================================================================*
GLOBAL C FontPtr:DWORD
GLOBAL C FontXSpacing:DWORD
GLOBAL C FontYSpacing:DWORD
GLOBAL C ColorXlat:BYTE
;*=========================================================================*
;* Define the necessary equates for structures and bounds checking *
;*=========================================================================*
; The header of the font file looks like this:
; UWORD FontLength; 0
; BYTE FontCompress; 2
; BYTE FontDataBlocks; 3
; UWORD InfoBlockOffset; 4
; UWORD OffsetBlockOffset; 6
; UWORD WidthBlockOffset; 8
; UWORD DataBlockOffset; 10
; UWORD HeightOffset; 12
; For this reason the following equates have these values:
FONTINFOBLOCK EQU 4
FONTOFFSETBLOCK EQU 6
FONTWIDTHBLOCK EQU 8
FONTDATABLOCK EQU 10
FONTHEIGHTBLOCK EQU 12
FONTINFOMAXHEIGHT EQU 4
FONTINFOMAXWIDTH EQU 5
LOCALS ??
;*=========================================================================*
;* Define the color xlate table in the data segment *
;*=========================================================================*
DATASEG
ColorXlat DB 000H,001H,002H,003H,004H,005H,006H,007H
DB 008H,009H,00AH,00BH,00CH,00DH,00EH,00FH
DB 001H,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 002H,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 003H,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 004H,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 005H,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 006H,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 007H,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 008H,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 009H,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 00AH,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 00BH,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 00CH,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 00DH,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 00EH,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 00FH
CODESEG
;***************************************************************************
;* MCGA_PRINT -- Assembly MCGA text print routine *
;* *
;* *
;* *
;* INPUT: *
;* *
;* OUTPUT: *
;* *
;* PROTO: *
;* *
;* WARNINGS: *
;* *
;* HISTORY: *
;* 01/17/1995 PWG : Created. *
;*=========================================================================*
PROC Buffer_Print C near
USES ebx,ecx,edx,esi,edi
ARG this:DWORD
ARG string:DWORD
ARG x_pixel:DWORD
ARG y_pixel:DWORD
ARG fcolor:DWORD
ARG bcolor:DWORD
LOCAL infoblock:DWORD ; pointer to info block
LOCAL offsetblock:DWORD ; pointer to offset block (UWORD *)
LOCAL widthblock:DWORD ; pointer to width block (BYTE *)
LOCAL heightblock:DWORD ; pointer to height block (UWORD *)
LOCAL curline:DWORD ; pointer to first column of current row.
LOCAL bufferwidth:DWORD ; width of buffer (vpwidth + Xadd)
LOCAL nextdraw:DWORD ; bufferwidth - width of cur character.
LOCAL startdraw:DWORD ; where next character will start being drawn.
LOCAL char:DWORD ; current character value.
LOCAL maxheight:BYTE ; max height of characters in font.
LOCAL bottomblank:BYTE ; amount of empty space below current character.
LOCAL charheight:BYTE ; true height of current character.
LOCAL vpwidth:DWORD
LOCAL vpheight:DWORD
LOCAL original_x:DWORD ; Starting X position.
;-------------------------------- Where to draw -----------------------------------------------
; Set up memory location to start drawing.
mov ebx,[this] ; get a pointer to dest
mov eax,[(GraphicViewPort ebx).GVPHeight] ; get height of viewport
mov [vpheight],eax ; save off height of viewport
mov eax,[(GraphicViewPort ebx).GVPWidth] ; get width of viewport
mov [vpwidth],eax ; save it off for later
add eax,[(GraphicViewPort ebx).GVPXAdd] ; add in xadd for bytes_per_line
add eax,[(GraphicViewPort ebx).GVPPitch] ; add in pitch of direct draw surface
mov [bufferwidth],eax ; save it off for later use.
mul [y_pixel] ; multiply rowsize * y_pixel start.
mov edi,[(GraphicViewPort ebx).GVPOffset] ; get start of the viewport
add edi,eax ; add y position to start of vp
mov [curline],edi ; save 0,y address for line feed stuff.
add edi,[x_pixel] ; add to get starting column in starting row.
mov [startdraw],edi ; save it off.
mov eax,[x_pixel]
mov [original_x],eax
;-------------------------------- Create block pointers ----------------------------------------
; Get the pointer to the font.
; We could check for NULL but why waste the time.
; It is up to programmer to make sure it is set.
mov esi,[FontPtr] ; Get the font pointer
or esi,esi
jz ??overflow
; Set up some pointers to the different memory blocks.
; esi (FontPtr) is added to each to get the true address of each block.
; Many registers are used for P5 optimizations.
; ebx is used for InfoBlock which is then used in the next section.
movzx eax,[WORD PTR esi+FONTOFFSETBLOCK] ; get offset to offset block
movzx ebx,[WORD PTR esi+FONTINFOBLOCK] ; get offset to info block (must be ebx for height test)
movzx ecx,[WORD PTR esi+FONTWIDTHBLOCK] ; get offset to width block
movzx edx,[WORD PTR esi+FONTHEIGHTBLOCK] ; get offset to height block
add eax,esi ; add offset of FontPtr to offset block
add ebx,esi ; add offset of FontPtr to info block
add ecx,esi ; add offset of FontPtr to width block
add edx,esi ; add offset of FontPtr to height block
mov [offsetblock],eax ; save offset to offset block
mov [infoblock],ebx ; save offset to info block
mov [widthblock],ecx ; save offset to width block
mov [heightblock],edx ; save offset to height block
;------------------------------------------ Test for fit ----------------------------------------------
; Test to make sure the height of the max character will fit on this line
; and and not fall out of the viewport.
; remember we set ebx to FONTINFOBLOCK above.
movzx eax,[BYTE PTR ebx + FONTINFOMAXHEIGHT]; get the max height in font.
mov [maxheight],al ; save it for later use.
add eax,[y_pixel] ; add current y_value.
cmp eax,[vpheight] ; are we over the edge?
jg ??overflow ; if so, we're outa here.
mov [y_pixel],eax ; save for next line feed. y value for next line.
cld ; Make sure we are always forward copying.
;------------------------ Set palette foreground and background ----------------------------------
mov eax,[fcolor] ; foreground color
mov [ColorXlat+1],al
mov [ColorXlat+16],al
mov eax,[bcolor] ; background color
mov [ColorXlat],al
;-------------------------------------------------------------------------------------------------
;----------------------------------------- Main loop ----------------------------------------------
; Now we go into the main loop of reading each character in the string and doing
; something with it.
??next_char:
; while (*string++)
xor eax,eax ; zero out since we will just load al.
mov esi,[string] ; get address on next character.
lodsb ; load the character into al.
test eax,0FFH ; test to see if character is a NULL
jz ??done ; character is NULL, get outa here.
mov edi,[startdraw] ; Load the starting address.
mov [string],esi ; save index into string. (incremented by lodsb)
cmp al,10 ; is the character a line feed?
je ??line_feed ; if so, go to special case.
cmp al,13 ; is the character a line feed?
je ??line_feed ; if so, go to special case.
mov [char],eax ; save the character off for later reference.
mov ebx,eax ; save it in ebx for later use also.
add eax,[widthblock] ; figure address of width of character.
mov ecx,[x_pixel] ; get current x_pixel.
movzx edx,[BYTE PTR eax] ; get the width of the character in dl.
add ecx,edx ; add width of char to current x_pixel.
mov eax,[FontXSpacing]
add ecx,eax
add [startdraw],edx ; save start draw for next character.
add [startdraw],eax ; adjust for the font spacing value
cmp ecx,[vpwidth] ; is the pixel greater then the vp width?
jg ??force_line_feed ; if so, force a line feed.
mov [x_pixel],ecx ; save value of start of next character.
mov ecx,[bufferwidth] ; get amount to next y same x (one row down)
sub ecx,edx ; take the current width off.
mov [nextdraw],ecx ; save it to add to edi when done with a row.
; At this point we got the character. It is now time to find out specifics
; about drawing the darn thing.
; ebx = char so they can be used as an indexes.
; edx = width of character for loop later.
; get offset of data for character into esi.
shl ebx,1 ; mult by 2 to later use as a WORD index.
mov esi,[offsetblock] ; get pointer to begining of offset block.
add esi,ebx ; index into offset block.
movzx esi,[WORD PTR esi] ; get true offset into data block from FontPtr.
add esi,[FontPtr] ; Now add FontPtr address to get true address.
; Get top and bottom blank sizes and the true height of the character.
add ebx,[heightblock] ; point ebx to element in height array.
mov al,[ebx+1] ; load the data height into dl.
mov cl,[ebx] ; load the first data row into cl.
mov bl,[maxheight] ; get the max height of characters.
mov [charheight],al ; get number of rows with data.
add al,cl ; add the two heights.
sub bl,al ; subract topblank + char height from maxheight.
mov [bottomblank],bl ; save off the number of blank rows on the bottom.
; leaving this section:
; dl is still the width of the character.
; cl is the height of the top blank area.
mov ebx,OFFSET ColorXlat ; setup ebx for xlat commands.
mov dh,dl ; save the width of the character to restore each loop.
cmp cl,0 ; is there any blank rows on top?
jz ??draw_char ; if not go and draw the real character.
xor eax,eax ; get color 0 for background.
xlat [ebx] ; get translated color into al
test al,al ; is it transparent black
jnz ??loop_top ; if not go and write the color
;----------------------------------------- skip Top blank area ----------------------------------------
; this case, the top is transparrent, but we need to increase our dest pointer to correct row.
movzx eax,cl ; get number of rows into eax;
mov ecx,edx ; save width since edx will be destroyed by mul.
mul [bufferwidth] ; multiply that by the width of the buffer.
mov edx,ecx ; restore the width
add edi,eax ; update the pointer.
jmp short ??draw_char ; now go draw the character.
;----------------------------------------- fill Top blank area ----------------------------------------
; edi was set a long time ago.
; al is the translated color
??loop_top:
stosb ; store the value
dec dh ; decrement our width.
jnz ??loop_top ; if more width, continue on.
add edi,[nextdraw] ; add amount for entire row.
dec cl ; decrement or row count
mov dh,dl ; restore width in dh for loop.
jz ??draw_char ; we are done here, go draw the character.
jmp short ??loop_top ; go back to top of loop.
;----------------------------------------- Draw character ----------------------------------------------
??draw_char:
movzx ecx,[charheight] ; get the height of character to count down rows.
test ecx,ecx ; is there any data? (blank would not have any)
jz ??next_char ; if no data, go on to next character.
??while_data:
lodsb ; get byte value from font data
mov ah,al ; save hinibble
and eax,0F00FH ; mask of low nibble in al hi nibble in ah.
xlat [ebx] ; get new color
test al,al ; is it a transparent?
jz short ??skiplo ; skip over write
mov [es:edi],al ; write it out
??skiplo:
inc edi
dec dh ; decrement our width.
jz short ??nextrow ; check if done with width of char
mov al,ah ; restore to get
; test the time difference between looking up in a large table when shr al,4 is not done as
; compared to using only a 16 byte table when using the shr al,4
;shr al,4 ; shift the hi nibble down to low nibble
xlat [ebx] ; get new color
test al,al ; is it a transparent?
jz short ??skiphi ; skip over write
mov [es:edi],al ; write it out
??skiphi:
inc edi
dec dh ; decrement our width.
jnz short ??while_data ; check if done with width of char
??nextrow:
add edi,[nextdraw] ; go to next line.
dec ecx ; decrement the number of rows to go
mov dh,dl ; restore our column count for row.
jnz ??while_data ; more data for character.
; Now it is time to setup for clearing out the bottom of the character.
movzx ecx,[bottomblank] ; get amount on bottom that is blank
cmp ecx,0 ; if there is no blank bottom...
jz ??next_char ; then skip to go to next character
xor eax,eax ; get color 0 for background.
xlat [ebx] ; get translated color into al
test al,al ; is it transparent black
jz ??next_char ; skip the top black section to let the background through
mov dh,dl ; restore width in dh for loop.
;----------------------------------------- Blank below character -----------------------------------
??loop_bottom:
stosb ; store the value
dec dh ; decrement our width.
jnz ??loop_bottom ; if more width, continue on.
add edi,[nextdraw] ; add amount for entire row.
mov dh,dl ; restore width in dh for loop.
dec cl ; decrement or row count
jz ??next_char ; we are done here, go to the next character.
jmp short ??loop_bottom ; go back to top of loop.
;----------------------------------- end of next_char (main) loop ------------------------------------
;-------------------------------------------------------------------------------------------------
;----------------------------------- special case line feeds ----------------------------------------
??force_line_feed:
; decrement pointer *string so that it will be back at same character
; when it goes through the loop.
mov eax,[string] ; get string pointer.
dec eax ; decrement it to point to previos char
mov [string],eax ; save it back off.
xor eax,eax
; Now go into the line feed code.....
??line_feed:
mov bl,al
mov edx,[y_pixel] ; get the current y pixel value.
movzx ecx,[maxheight] ; get max height for later use.
add ecx,[FontYSpacing]
add edx,ecx ; add max height to y_pixel
cmp edx,[vpheight] ; are we over the edge?
jg ??overflow ; if so, we are outa here.
mov eax,[bufferwidth] ; get bytes to next line.
mov edi,[curline] ; get start of current line.
mul ecx ; mult max height * next line.
add edi,eax ; add adjustment to current line.
add [y_pixel],ecx ; increment to our next y position.
;;; DRD
mov [curline],edi ; save it off for next line_feed.
; Move the cursor to either the left edge of the screen
; or the left margin of the print position depending
; on whether <CR> or <LF> was specified. <CR> = left margin
; <LF> = left edge of screen
xor eax,eax
cmp bl,10
je ??lfeed
mov eax,[original_x]
??lfeed:
mov [x_pixel],eax ; zero out x_pixel
add edi,eax
;;; DRD mov [curline],edi ; save it off for next line_feed.
mov [startdraw],edi ; save it off so we know where to draw next char.w
jmp ??next_char
??overflow:
mov [startdraw],0 ; Indicate that there is no valid next pos.
??done:
mov eax,[startdraw] ; return this so calling routine
ret ; can figure out where to draw next.
ENDP Buffer_Print
;***************************************************************************
;* GET_FONT_PALETTE_PTR -- Returns a pointer to the 256 byte font palette *
;* *
;* INPUT: none *
;* *
;* OUTPUT: none *
;* *
;* PROTO: void *Get_Font_Palette_Ptr(void); *
;* *
;* HISTORY: *
;* 08/18/1995 PWG : Created. *
;*=========================================================================*
GLOBAL C Get_Font_Palette_Ptr:NEAR
PROC Get_Font_Palette_Ptr C near
mov eax, OFFSET ColorXlat
ret
ENDP Get_Font_Palette_Ptr
END

655
CODE/AADATA.CPP Normal file
View file

@ -0,0 +1,655 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/AADATA.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : AADATA.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : July 22, 1994 *
* *
* Last Update : July 9, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* AircraftTypeClass::AircraftTypeClass -- Constructor for aircraft objects. *
* AircraftTypeClass::As_Reference -- Given an aircraft type, find the matching type object. *
* AircraftTypeClass::Create_And_Place -- Creates and places aircraft using normal game syste*
* AircraftTypeClass::Create_One_Of -- Creates an aircraft object of the appropriate type. *
* AircraftTypeClass::Dimensions -- Fetches the graphic dimensions of the aircraft type. *
* AircraftTypeClass::Display -- Displays a generic version of the aircraft type. *
* AircraftTypeClass::From_Name -- Converts an ASCII name into an aircraft type number. *
* AircraftTypeClass::Init_Heap -- Initialize the aircraft type class heap. *
* AircraftTypeClass::Max_Pips -- Fetches the maximum number of pips allowed. *
* AircraftTypeClass::Occupy_List -- Returns with occupation list for landed aircraft. *
* AircraftTypeClass::One_Time -- Performs one time initialization of the aircraft type class*
* AircraftTypeClass::Overlap_List -- Determines the overlap list for a landed aircraft. *
* AircraftTypeClass::Prep_For_Add -- Prepares the scenario editor for adding an aircraft obj*
* AircraftTypeClass::operator delete -- Returns aircraft type to special memory pool. *
* AircraftTypeClass::operator new -- Allocates an aircraft type object from special pool. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
void const * AircraftTypeClass::LRotorData = NULL;
void const * AircraftTypeClass::RRotorData = NULL;
// Badger bomber
static AircraftTypeClass const BadgerPlane(
AIRCRAFT_BADGER, // What kind of aircraft is this.
TXT_BADGER, // Translated text number for aircraft.
"BADR", // INI name of aircraft.
0x0000, // Vertical offset.
0x0000, // Primary weapon offset along turret centerline.
0x0000, // Primary weapon lateral offset along turret centerline.
true, // Fixed wing aircraft?
false, // Equipped with a rotor?
false, // Custom rotor sets for each facing?
false, // Can this aircraft land on clear terrain?
true, // Is it invisible on radar?
false, // Can the player select it so as to give it orders?
true, // Can it be assigned as a target for attack.
false, // Is it insignificant (won't be announced)?
false, // Is it immune to normal combat damage?
STRUCT_NONE, // Preferred landing building.
0xFF, // Landing speed
16, // Number of rotation stages.
MISSION_HUNT // Default mission for aircraft.
);
// Photo recon plane.
static AircraftTypeClass const U2Plane(
AIRCRAFT_U2, // What kind of aircraft is this.
TXT_U2, // Translated text number for aircraft.
"U2", // INI name of aircraft.
0x0000, // Vertical offset.
0x0000, // Primary weapon offset along turret centerline.
0x0000, // Primary weapon lateral offset along turret centerline.
true, // Fixed wing aircraft?
false, // Equipped with a rotor?
false, // Custom rotor sets for each facing?
false, // Can this aircraft land on clear terrain?
true, // Is it invisible on radar?
false, // Can the player select it so as to give it orders?
true, // Can it be assigned as a target for attack.
false, // Is it insignificant (won't be announced)?
false, // Is it immune to normal combat damage?
STRUCT_NONE, // Preferred landing building.
0xFF, // Landing speed
16, // Number of rotation stages.
MISSION_HUNT // Default mission for aircraft.
);
// Mig attack aircraft.
static AircraftTypeClass const MigPlane(
AIRCRAFT_MIG, // What kind of aircraft is this.
TXT_MIG, // Translated text number for aircraft.
"MIG", // INI name of aircraft.
0x0000, // Vertical offset.
0x0020, // Primary weapon offset along turret centerline.
0x0020, // Primary weapon lateral offset along turret centerline.
true, // Fixed wing aircraft?
false, // Equipped with a rotor?
false, // Custom rotor sets for each facing?
false, // Can this aircraft land on clear terrain?
true, // Is it invisible on radar?
true, // Can the player select it so as to give it orders?
true, // Can it be assigned as a target for attack.
false, // Is it insignificant (won't be announced)?
false, // Is it immune to normal combat damage?
STRUCT_AIRSTRIP, // Preferred landing building.
0xC0, // Landing speed
16, // Number of rotation stages.
MISSION_HUNT // Default mission for aircraft.
);
// Yak attack aircraft.
static AircraftTypeClass const YakPlane(
AIRCRAFT_YAK, // What kind of aircraft is this.
TXT_YAK, // Translated text number for aircraft.
"YAK", // INI name of aircraft.
0x0000, // Vertical offset.
0x0020, // Primary weapon offset along turret centerline.
0x0020, // Primary weapon lateral offset along turret centerline.
true, // Fixed wing aircraft?
false, // Equipped with a rotor?
false, // Custom rotor sets for each facing?
false, // Can this aircraft land on clear terrain?
true, // Is it invisible on radar?
true, // Can the player select it so as to give it orders?
true, // Can it be assigned as a target for attack.
false, // Is it insignificant (won't be announced)?
false, // Is it immune to normal combat damage?
STRUCT_AIRSTRIP, // Preferred landing building.
0xFF, // Landing speed
16, // Number of rotation stages.
MISSION_HUNT // Default mission for aircraft.
);
// Transport helicopter.
static AircraftTypeClass const TransportHeli(
AIRCRAFT_TRANSPORT, // What kind of aircraft is this.
TXT_TRANS, // Translated text number for aircraft.
"TRAN", // INI name of aircraft.
0x0000, // Vertical offset.
0x0000, // Primary weapon offset along turret centerline.
0x0000, // Primary weapon lateral offset along turret centerline.
false, // Fixed wing aircraft?
true, // Equipped with a rotor?
true, // Custom rotor sets for each facing?
true, // Can this aircraft land on clear terrain?
true, // Is it invisible on radar?
true, // Can the player select it so as to give it orders?
true, // Can it be assigned as a target for attack.
false, // Is it insignificant (won't be announced)?
false, // Is it immune to normal combat damage?
STRUCT_NONE, // Preferred landing building.
0xFF, // Landing speed
32, // Number of rotation stages.
MISSION_HUNT // Default mission for aircraft.
);
// Longbow attack helicopter
static AircraftTypeClass const AttackHeli(
AIRCRAFT_LONGBOW, // What kind of aircraft is this.
TXT_HELI, // Translated text number for aircraft.
"HELI", // INI name of aircraft.
0x0000, // Vertical offset.
0x0040, // Primary weapon offset along turret centerline.
0x0000, // Primary weapon lateral offset along turret centerline.
false, // Fixed wing aircraft?
true, // Equipped with a rotor?
false, // Custom rotor sets for each facing?
false, // Can this aircraft land on clear terrain?
true, // Is it invisible on radar?
true, // Can the player select it so as to give it orders?
true, // Can it be assigned as a target for attack.
false, // Is it insignificant (won't be announced)?
false, // Is it immune to normal combat damage?
STRUCT_HELIPAD, // Preferred landing building.
0xFF, // Landing speed
32, // Number of rotation stages.
MISSION_HUNT // Default mission for aircraft.
);
// Hind
static AircraftTypeClass const OrcaHeli(
AIRCRAFT_HIND, // What kind of aircraft is this.
TXT_ORCA, // Translated text number for aircraft.
"HIND", // INI name of aircraft.
0x0000, // Vertical offset.
0x0040, // Primary weapon offset along turret centerline.
0x0000, // Primary weapon lateral offset along turret centerline.
false, // Fixed wing aircraft?
true, // Equipped with a rotor?
false, // Custom rotor sets for each facing?
false, // Can this aircraft land on clear terrain?
true, // Is it invisible on radar?
true, // Can the player select it so as to give it orders?
true, // Can it be assigned as a target for attack.
false, // Is it insignificant (won't be announced)?
false, // Is it immune to normal combat damage?
STRUCT_HELIPAD, // Preferred landing building.
0xFF, // Landing speed
32, // Number of rotation stages.
MISSION_HUNT // Default mission for aircraft.
);
/***********************************************************************************************
* AircraftTypeClass::AircraftTypeClass -- Constructor for aircraft objects. *
* *
* This is the constructor for the aircraft object. *
* *
* INPUT: see below... *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/26/1994 JLB : Created. *
*=============================================================================================*/
AircraftTypeClass::AircraftTypeClass(
AircraftType airtype,
int name,
char const * ininame,
int verticaloffset,
int primaryoffset,
int primarylateral,
bool is_fixedwing,
bool is_rotorequipped,
bool is_rotorcustom,
bool is_landable,
bool is_stealthy,
bool is_selectable,
bool is_legal_target,
bool is_insignificant,
bool is_immune,
StructType building,
int landingspeed,
int rotation,
MissionType deforder
) :
TechnoTypeClass(RTTI_AIRCRAFTTYPE,
int(airtype),
name,
ininame,
REMAP_NORMAL,
verticaloffset,
primaryoffset,
primarylateral,
primaryoffset,
primarylateral,
false,
is_stealthy,
is_selectable,
is_legal_target,
is_insignificant,
is_immune,
false,
false,
true,
true,
rotation,
SPEED_WINGED),
IsFixedWing(is_fixedwing),
IsLandable(is_landable),
IsRotorEquipped(is_rotorequipped),
IsRotorCustom(is_rotorcustom),
Type(airtype),
Mission(deforder),
Building(building),
LandingSpeed(landingspeed)
{
/*
** Forced aircraft overrides from the default.
*/
Speed = SPEED_WINGED;
}
/***********************************************************************************************
* AircraftTypeClass::operator new -- Allocates an aircraft type object from special pool. *
* *
* This will allocate an aircraft type class object from the memory pool of that purpose. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with a pointer to the newly allocated aircraft type class object. If there *
* was insufficient memory to fulfill the request, then NULL is returned. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/09/1996 JLB : Created. *
*=============================================================================================*/
void * AircraftTypeClass::operator new(size_t)
{
return(AircraftTypes.Alloc());
}
/***********************************************************************************************
* AircraftTypeClass::operator delete -- Returns aircraft type to special memory pool. *
* *
* This will return the aircraft type class object back to the special memory pool that *
* it was allocated from. *
* *
* INPUT: pointer -- Pointer to the aircraft type class object to delete. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/09/1996 JLB : Created. *
*=============================================================================================*/
void AircraftTypeClass::operator delete(void * pointer)
{
AircraftTypes.Free((AircraftTypeClass *)pointer);
}
/***********************************************************************************************
* AircraftTypeClass::Init_Heap -- Initialize the aircraft type class heap. *
* *
* This will initialize the aircraft type class heap by pre-allocating all known aircraft *
* types. It should be called once and before the rules.ini file is processed. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/09/1996 JLB : Created. *
*=============================================================================================*/
void AircraftTypeClass::Init_Heap(void)
{
/*
** These aircraft type class objects must be allocated in the exact order that they
** are specified in the AircraftSmen enumeration. This is necessary because the heap
** allocation block index serves double duty as the type number index.
*/
new AircraftTypeClass(TransportHeli);
new AircraftTypeClass(BadgerPlane);
new AircraftTypeClass(U2Plane);
new AircraftTypeClass(MigPlane);
new AircraftTypeClass(YakPlane);
new AircraftTypeClass(AttackHeli);
new AircraftTypeClass(OrcaHeli);
}
/***********************************************************************************************
* AircraftTypeClass::From_Name -- Converts an ASCII name into an aircraft type number. *
* *
* This routine is used to convert an ASCII representation of an aircraft into the *
* matching aircraft type number. This is used by the scenario INI reader code. *
* *
* INPUT: name -- Pointer to ASCII name to translate. *
* *
* OUTPUT: Returns the aircraft type number that matches the ASCII name provided. If no *
* match could be found, then AIRCRAFT_NONE is returned. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/26/1994 JLB : Created. *
*=============================================================================================*/
AircraftType AircraftTypeClass::From_Name(char const * name)
{
if (name != NULL) {
for (AircraftType classid = AIRCRAFT_FIRST; classid < AIRCRAFT_COUNT; classid++) {
if (stricmp(As_Reference(classid).IniName, name) == 0) {
return(classid);
}
}
}
return(AIRCRAFT_NONE);
}
/***********************************************************************************************
* AircraftTypeClass::One_Time -- Performs one time initialization of the aircraft type class. *
* *
* This routine is used to perform the onetime initialization of the aircraft type. This *
* includes primarily the shape and other graphic data loading. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: This goes to disk and also must only be called ONCE. *
* *
* HISTORY: *
* 07/26/1994 JLB : Created. *
*=============================================================================================*/
void AircraftTypeClass::One_Time(void)
{
for (AircraftType index = AIRCRAFT_FIRST; index < AIRCRAFT_COUNT; index++) {
char fullname[_MAX_FNAME+_MAX_EXT];
AircraftTypeClass const & uclass = As_Reference(index);
/*
** Fetch the supporting data files for the unit.
*/
char buffer[_MAX_FNAME];
sprintf(buffer, "%sICON", uclass.Graphic_Name());
_makepath(fullname, NULL, NULL, buffer, ".SHP");
((void const *&)uclass.CameoData) = MFCD::Retrieve(fullname);
/*
** Generic shape for all houses load method.
*/
_makepath(fullname, NULL, NULL, uclass.Graphic_Name(), ".SHP");
((void const *&)uclass.ImageData) = MFCD::Retrieve(fullname);
}
LRotorData = MFCD::Retrieve("LROTOR.SHP");
RRotorData = MFCD::Retrieve("RROTOR.SHP");
}
/***********************************************************************************************
* AircraftTypeClass::Create_One_Of -- Creates an aircraft object of the appropriate type. *
* *
* This routine is used to create an aircraft object that matches the aircraft type. It *
* serves as a shortcut to creating an object using the "new" operator and "if" checks. *
* *
* INPUT: house -- The house owner of the aircraft that is to be created. *
* *
* OUTPUT: Returns with a pointer to the aircraft created. If the aircraft could not be *
* created, then a NULL is returned. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/26/1994 JLB : Created. *
*=============================================================================================*/
ObjectClass * AircraftTypeClass::Create_One_Of(HouseClass * house) const
{
return(new AircraftClass(Type, house->Class->House));
}
#ifdef SCENARIO_EDITOR
/***********************************************************************************************
* AircraftTypeClass::Prep_For_Add -- Prepares the scenario editor for adding an aircraft objec*
* *
* This routine is used by the scenario editor to prepare for the adding operation. It *
* builds a list of pointers to object types that can be added. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/26/1994 JLB : Created. *
*=============================================================================================*/
void AircraftTypeClass::Prep_For_Add(void)
{
for (AircraftType index = AIRCRAFT_FIRST; index < AIRCRAFT_COUNT; index++) {
if (As_Reference(index).Get_Image_Data()) {
Map.Add_To_List(&As_Reference(index));
}
}
}
/***********************************************************************************************
* AircraftTypeClass::Display -- Displays a generic version of the aircraft type. *
* *
* This routine is used by the scenario editor to display a generic version of the object *
* type. This is displayed in the object selection dialog box. *
* *
* INPUT: x,y -- The coordinates to draw the aircraft at (centered). *
* *
* window -- The window to base the coordinates upon. *
* *
* house -- The owner of this generic aircraft. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/26/1994 JLB : Created. *
*=============================================================================================*/
void AircraftTypeClass::Display(int x, int y, WindowNumberType window, HousesType ) const
{
int shape = 0;
void const * ptr = Get_Cameo_Data();
if (ptr == NULL) {
ptr = Get_Image_Data();
shape = 5;
}
CC_Draw_Shape(ptr, shape, x, y, window, SHAPE_CENTER|SHAPE_WIN_REL);
}
#endif
/***********************************************************************************************
* AircraftTypeClass::Occupy_List -- Returns with occupation list for landed aircraft. *
* *
* This determines the occupation list for the aircraft (if it was landed). *
* *
* INPUT: placement -- Is this for placement legality checking only? The normal condition *
* is for marking occupation flags. *
* *
* OUTPUT: Returns with a pointer to a cell offset occupation list for the aircraft. *
* *
* WARNINGS: This occupation list is only valid if the aircraft is landed. *
* *
* HISTORY: *
* 07/26/1994 JLB : Created. *
*=============================================================================================*/
short const * AircraftTypeClass::Occupy_List(bool) const
{
static short const _list[] = {0, REFRESH_EOL};
return(_list);
}
/***********************************************************************************************
* AircraftTypeClass::Overlap_List -- Determines the overlap list for a landed aircraft. *
* *
* This routine figures out the overlap list for the aircraft as if it were landed. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the cell offset overlap list for the aircraft. *
* *
* WARNINGS: This overlap list is only valid when the aircraft is landed. *
* *
* HISTORY: *
* 07/26/1994 JLB : Created. *
*=============================================================================================*/
short const * AircraftTypeClass::Overlap_List(void) const
{
static short const _list[] = {-(MAP_CELL_W-1), -MAP_CELL_W, -(MAP_CELL_W+1), -1, 1, (MAP_CELL_W-1), MAP_CELL_W, (MAP_CELL_W+1), REFRESH_EOL};
return(_list);
}
/***********************************************************************************************
* AircraftTypeClass::Max_Pips -- Fetches the maximum number of pips allowed. *
* *
* Use this routine to retrieve the maximum pip count allowed for this aircraft. This is *
* the maximum number of passengers. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the maximum number of pips for this aircraft. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/26/1995 JLB : Created. *
*=============================================================================================*/
int AircraftTypeClass::Max_Pips(void) const
{
if (PrimaryWeapon != NULL) {
return(5);
}
return(Max_Passengers());
}
/***********************************************************************************************
* AircraftTypeClass::Create_And_Place -- Creates and places aircraft using normal game system *
* *
* This routine is used to create and place an aircraft through the normal game system. *
* Since creation of aircraft in this fashion is prohibited, this routine does nothing. *
* *
* INPUT: na *
* *
* OUTPUT: Always returns a failure code (false). *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/07/1995 JLB : Created. *
*=============================================================================================*/
bool AircraftTypeClass::Create_And_Place(CELL, HousesType) const
{
return(false);
}
/***********************************************************************************************
* AircraftTypeClass::Dimensions -- Fetches the graphic dimensions of the aircraft type. *
* *
* This routine will fetch the pixel dimensions of this aircraft type. These dimensions *
* are used to control map refresh and select box rendering. *
* *
* INPUT: width -- Reference to variable that will be filled in with aircraft width. *
* *
* height -- Reference to variable that will be filled in with aircraft height. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/07/1995 JLB : Created. *
*=============================================================================================*/
void AircraftTypeClass::Dimensions(int &width, int &height) const
{
if (Type == AIRCRAFT_BADGER) {
width = 56;
height = 56;
} else {
width = 21;
height = 20;
}
}
/***********************************************************************************************
* AircraftTypeClass::As_Reference -- Given an aircraft type, find the matching type object. *
* *
* This routine is used to fetch a reference to the aircraft type class object that matches *
* the aircraft type specified. *
* *
* INPUT: aircraft -- The aircraft type to fetch a reference to the type class object of. *
* *
* OUTPUT: Returns with a reference to the type class object of this aircraft type. *
* *
* WARNINGS: Be sure that the aircraft type specified is legal. Illegal values will result *
* in undefined behavior. *
* *
* HISTORY: *
* 07/09/1996 JLB : Created. *
*=============================================================================================*/
AircraftTypeClass & AircraftTypeClass::As_Reference(AircraftType aircraft)
{
return(*AircraftTypes.Ptr(aircraft));
}

216
CODE/ABSTRACT.CPP Normal file
View file

@ -0,0 +1,216 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/ABSTRACT.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : ABSTRACT.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 01/26/95 *
* *
* Last Update : July 10, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* AbstractClass::Debug_Dump -- Display debug information to mono screen. *
* AbstractClass::Distance -- Determines distance to target. *
* AbstractTypeClass::AbstractTypeClass -- Constructor for abstract type objects. *
* AbstractTypeClass::Coord_Fixup -- Performs custom adjustments to location coordinate. *
* AbstractTypeClass::Full_Name -- Returns the full name (number) of this object type. *
* AbstractTypeClass::Get_Ownable -- Fetch the ownable bits for this object. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
/***********************************************************************************************
* AbstractClass::Debug_Dump -- Display debug information to mono screen. *
* *
* This debug only routine will display various information about this abstract class *
* object to the monochrome screen specified. *
* *
* INPUT: mono -- Pointer to the monochrome screen to display the debug information to. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/10/1996 JLB : Created. *
*=============================================================================================*/
#ifdef CHEAT_KEYS
void AbstractClass::Debug_Dump(MonoClass * mono) const
{
assert(IsActive);
mono->Set_Cursor(11, 5);mono->Printf("%08X", As_Target());
mono->Set_Cursor(20, 1);mono->Printf("%08X", Coord);
mono->Set_Cursor(29, 1);mono->Printf("%3d", Height);
if (Owner() != HOUSE_NONE) {
mono->Set_Cursor(1, 3);
mono->Printf("%-18s", Text_String(HouseTypeClass::As_Reference(Owner()).FullName));
}
}
#endif
/***********************************************************************************************
* AbstractClass::Distance -- Determines distance to target. *
* *
* This will determine the distance (direct line) to the target. The distance is in *
* 'leptons'. This routine is typically used for weapon range checks. *
* *
* INPUT: target -- The target to determine range to. *
* *
* OUTPUT: Returns with the range to the specified target (in leptons). *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/17/1994 JLB : Created. *
*=============================================================================================*/
int AbstractClass::Distance(TARGET target) const
{
/*
** Should subtract a fudge-factor distance for building targets.
*/
BuildingClass * obj = As_Building(target);
int dist = Distance(As_Coord(target));
/*
** If the object is a building the adjust it by the average radius
** of the object.
*/
if (obj) {
dist -= ((obj->Class->Width() + obj->Class->Height()) * (0x100 / 4));
if (dist < 0) dist = 0;
}
/*
** Return the distance to the target
*/
return(dist);
}
/***********************************************************************************************
* AbstractTypeClass::AbstractTypeClass -- Constructor for abstract type objects. *
* *
* This is the constructor for AbstractTypeClass objects. It initializes the INI name and *
* the text name for this object type. *
* *
* INPUT: name -- Text number for the full name of the object. *
* *
* ini -- The ini name for this object type. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/22/1995 JLB : Created. *
*=============================================================================================*/
AbstractTypeClass::AbstractTypeClass(RTTIType rtti, int id, int name, char const * ini) :
RTTI(rtti),
ID(id),
FullName(name)
{
strncpy((char *)IniName, ini, sizeof(IniName));
((char &)IniName[sizeof(IniName)-1]) = '\0';
}
/***********************************************************************************************
* AbstractTypeClass::Coord_Fixup -- Performs custom adjustments to location coordinate. *
* *
* This routine is called when the placement coordinate should be fixed up according *
* to any special rules specific to this object type. At this level, no transformation *
* occurs. Derived classes will transform the coordinate as necessary. *
* *
* INPUT: coord -- The proposed coordinate that this object type will be placed down at. *
* *
* OUTPUT: Returns with the adjusted coordinate that the object should be placed down at. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/21/1995 JLB : Created. *
*=============================================================================================*/
COORDINATE AbstractTypeClass::Coord_Fixup(COORDINATE coord) const
{
return(coord);
}
/***********************************************************************************************
* AbstractTypeClass::Full_Name -- Returns the full name (number) of this object type. *
* *
* This routine is used to fetch the full name of this object type. The name value *
* returned is actually the index number into the text array. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the full name index number for this object type. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/21/1995 JLB : Created. *
*=============================================================================================*/
int AbstractTypeClass::Full_Name(void) const
{
#ifdef FIXIT_NAME_OVERRIDE
for (int index = 0; index < ARRAY_SIZE(NameOverride); index++) {
if (NameIDOverride[index] == ((RTTI+1) * 100) + ID) {
return(-(index+1));
}
}
#endif
return(FullName);
}
/***********************************************************************************************
* AbstractTypeClass::Get_Ownable -- Fetch the ownable bits for this object. *
* *
* This returns a bit flag that indicates which houses are allowed to own this object *
* type. At this level, all houses have ownership rights. This routine will be overridden *
* by object types that restrict ownership. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with a bit flag indicating which houses have ownership rights. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/21/1995 JLB : Created. *
*=============================================================================================*/
int AbstractTypeClass::Get_Ownable(void) const
{
return(HOUSEF_ALLIES | HOUSEF_SOVIET | HOUSEF_OTHERS);
}

135
CODE/ABSTRACT.H Normal file
View file

@ -0,0 +1,135 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/ABSTRACT.H 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : ABSTRACT.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 01/26/95 *
* *
* Last Update : January 26, 1995 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef ABSTRACT_H
#define ABSTRACT_H
DirType Direction(CELL cell1, CELL cell2);
DirType Direction(COORDINATE coord1, COORDINATE coord2);
int Distance(COORDINATE coord1, COORDINATE coord2);
COORDINATE As_Coord(TARGET target);
class AbstractTypeClass;
/*
** This class is the base class for all game objects that have an existence on the
** battlefield.
*/
class AbstractClass
{
public:
/*
** This specifies the type of object and the unique ID number
** associated with it. The ID number happens to match the index into
** the object heap appropriate for this object type.
*/
RTTIType RTTI;
int ID;
/*
** The coordinate location of the unit. For vehicles, this is the center
** point. For buildings, it is the upper left corner.
*/
COORDINATE Coord;
/*
** This is the height of the object above ground (expressed in leptons).
*/
int Height;
/*
** The actual object ram-space is located in arrays in the data segment. This flag
** is used to indicate which objects are free to be reused and which are currently
** in use by the game.
*/
unsigned IsActive:1;
/*-----------------------------------------------------------------------------------
** Constructor & destructors.
*/
AbstractClass(RTTIType rtti, int id) : RTTI(rtti), ID(id), Coord(0xFFFFFFFFL), Height(0) {};
AbstractClass(NoInitClass const & x) {x();};
virtual ~AbstractClass(void) {};
/*
** Query functions.
*/
virtual char const * Name(void) const {return("");}
virtual HousesType Owner(void) const {return HOUSE_NONE;};
TARGET As_Target(void) const {return(Build_Target(RTTI, ID));};
RTTIType What_Am_I(void) const {return(RTTI);};
/*
** Scenario and debug support.
*/
#ifdef CHEAT_KEYS
virtual void Debug_Dump(MonoClass * mono) const;
#endif
/*
** Coordinate query support functions.
*/
virtual COORDINATE Center_Coord(void) const {return Coord;};
virtual COORDINATE Target_Coord(void) const {return Coord;};
/*
** Coordinate inquiry functions. These are used for both display and
** combat purposes.
*/
DirType Direction(AbstractClass const * object) const {return ::Direction(Center_Coord(), object->Target_Coord());};
DirType Direction(COORDINATE coord) const {return ::Direction(Center_Coord(), coord);};
DirType Direction(TARGET target) const {return ::Direction(Center_Coord(), As_Coord(target));};
DirType Direction(CELL cell) const {return ::Direction(Coord_Cell(Center_Coord()), cell);};
int Distance(TARGET target) const;
int Distance(COORDINATE coord) const {return ::Distance(Center_Coord(), coord);};
int Distance(AbstractClass const * object) const {return ::Distance(Center_Coord(), object->Target_Coord());};
/*
** Object entry and exit from the game system.
*/
virtual MoveType Can_Enter_Cell(CELL , FacingType = FACING_NONE) const {return MOVE_OK;};
/*
** AI.
*/
virtual void AI(void) {};
};
#endif

1847
CODE/ADAMTEMP.MAK Normal file

File diff suppressed because it is too large Load diff

2361
CODE/ADATA.CPP Normal file

File diff suppressed because it is too large Load diff

83
CODE/ADPCM.CPP Normal file
View file

@ -0,0 +1,83 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "function.h"
extern "C" {
#include "soscomp.h"
#include "itable.cpp"
#include "dtable.cpp"
void sosCODECInitStream(_SOS_COMPRESS_INFO* info)
{
info->dwSampleIndex = 0;
info->dwPredicted = 0;
}
unsigned long sosCODECDecompressData(_SOS_COMPRESS_INFO* info, unsigned long numbytes)
{
unsigned long token;
long sample;
unsigned int fastindex;
unsigned char *inbuff;
unsigned short *outbuff;
inbuff = (unsigned char *)info->lpSource;
outbuff = (unsigned short *)info->lpDest;
// Preload variables before the big loop
fastindex = (unsigned int)info->dwSampleIndex;
sample = info->dwPredicted;
if (!numbytes)
goto SkipLoop;
do {
// First nibble
token = *inbuff++;
fastindex += token & 0x0f;
sample += DiffTable[fastindex];
fastindex = IndexTable[fastindex];
if (sample > 32767L)
sample = 32767L;
if (sample < -32768L)
sample = -32768L;
*outbuff++ = (unsigned short)sample;
// Second nibble
fastindex += token >> 4;
sample += DiffTable[fastindex];
fastindex = IndexTable[fastindex];
if (sample > 32767L)
sample = 32767L;
if (sample < -32768L)
sample = -32768L;
*outbuff++ = (unsigned short)sample;
} while(--numbytes);
SkipLoop:
// Put local vars back
info->dwSampleIndex = (unsigned long)fastindex;
info->dwPredicted = sample;
return(numbytes << 2);
}
}

4375
CODE/AIRCRAFT.CPP Normal file

File diff suppressed because it is too large Load diff

248
CODE/AIRCRAFT.H Normal file
View file

@ -0,0 +1,248 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/AIRCRAFT.H 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : AIRCRAFT.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : July 22, 1994 *
* *
* Last Update : November 28, 1994 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef AIRCRAFT_H
#define AIRCRAFT_H
#include "radio.h"
#include "fly.h"
#include "target.h"
/*
** This aircraft class is used for all flying sentient objects. This includes fixed wing
** aircraft as well as helicopters. It excludes bullets even though some bullets might
** be considered to be "flying" in a loose interpretatin of the word.
*/
class AircraftClass : public FootClass, public FlyClass
{
public:
/*
** This is a pointer to the class control structure for the aircraft.
*/
CCPtr<AircraftTypeClass> Class;
//-----------------------------------------------------------------------------
static void * operator new(size_t);
static void * operator new(size_t, void * ptr) {return(ptr);};
static void operator delete(void *);
operator AircraftType(void) const {return Class->Type;};
AircraftClass(AircraftType classid, HousesType house);
AircraftClass(NoInitClass const & x) : FootClass(x), FlyClass(x), Class(x), SecondaryFacing(x), SightTimer(x) {};
virtual ~AircraftClass(void);
static void Init(void);
virtual int Mission_Attack(void);
virtual int Mission_Unload(void);
virtual int Mission_Hunt(void);
virtual int Mission_Retreat(void);
virtual int Mission_Move(void);
virtual int Mission_Enter(void);
virtual int Mission_Guard(void);
virtual int Mission_Guard_Area(void);
virtual void Assign_Destination(TARGET target);
/*
** State machine support routines.
*/
bool Process_Take_Off(void);
bool Process_Landing(void);
int Process_Fly_To(bool slowdown, TARGET dest);
/*
** Query functions.
*/
virtual LayerType In_Which_Layer(void) const;
virtual DirType Turret_Facing(void) const {return(SecondaryFacing.Current());}
int Shape_Number(void) const;
virtual MoveType Can_Enter_Cell(CELL cell, FacingType facing=FACING_NONE) const;
virtual ObjectTypeClass const & Class_Of(void) const {return *Class;};
virtual ActionType What_Action(ObjectClass const * target) const;
virtual ActionType What_Action(CELL cell) const;
virtual DirType Desired_Load_Dir(ObjectClass * passenger, CELL & moveto) const;
virtual int Pip_Count(void) const;
TARGET Good_Fire_Location(TARGET target) const;
bool Cell_Seems_Ok(CELL cell, bool landing=false) const;
DirType Pose_Dir(void) const;
TARGET Good_LZ(void) const;
virtual DirType Fire_Direction(void) const;
virtual FireErrorType Can_Fire(TARGET target, int which) const;
/*
** Landing zone support functionality.
*/
virtual void Per_Cell_Process(PCPType why);
bool Is_LZ_Clear(TARGET target) const;
TARGET New_LZ(TARGET oldlz) const;
/*
** Coordinate inquiry functions. These are used for both display and
** combat purposes.
*/
virtual COORDINATE Sort_Y(void) const;
/*
** Object entry and exit from the game system.
*/
virtual bool Unlimbo(COORDINATE , DirType facing = DIR_N);
/*
** Display and rendering support functionality. Supports imagery and how
** object interacts with the map and thus indirectly controls rendering.
*/
virtual void Look(bool incremental=false);
void Draw_Rotors(int x, int y, WindowNumberType window) const;
virtual int Exit_Object(TechnoClass *);
virtual short const * Overlap_List(bool redraw=false) const;
virtual void Draw_It(int x, int y, WindowNumberType window) const;
virtual void Set_Speed(int speed);
/*
** User I/O.
*/
virtual void Active_Click_With(ActionType action, ObjectClass * object);
virtual void Active_Click_With(ActionType action, CELL cell);
virtual void Player_Assign_Mission(MissionType mission, TARGET target=TARGET_NONE, TARGET destination=TARGET_NONE);
virtual void Response_Select(void);
virtual void Response_Move(void);
virtual void Response_Attack(void);
/*
** Combat related.
*/
virtual ResultType Take_Damage(int & damage, int distance, WarheadType warhead, TechnoClass * source, bool forced=false);
virtual BulletClass * Fire_At(TARGET target, int which);
/*
** AI.
*/
bool Landing_Takeoff_AI(void);
bool Edge_Of_World_AI(void);
void Movement_AI(void);
void Rotation_AI(void);
int Paradrop_Cargo(void);
virtual void AI(void);
virtual void Enter_Idle_Mode(bool initial = false);
virtual RadioMessageType Receive_Message(RadioClass * from, RadioMessageType message, long & param);
virtual void Scatter(COORDINATE threat, bool forced=false, bool nokidding=false);
/*
** Scenario and debug support.
*/
#ifdef CHEAT_KEYS
virtual void Debug_Dump(MonoClass *mono) const;
#endif
/*
** File I/O.
*/
static void Read_INI(CCINIClass & ini);
static char * INI_Name(void) {return "AIRCRAFT";};
bool Load(Straw & file);
bool Save(Pipe & file) const;
public:
/*
** This is the facing used for the body of the aircraft. Typically, this is the same
** as the PrimaryFacing, but in the case of helicopters, it can be different.
*/
FacingClass SecondaryFacing;
/*
** If this is a passenger carrying aircraft then this flag will be set. This is
** necessary because once the passengers are unloaded, the fact that it was a
** passenger carrier must still be known.
*/
bool Passenger;
private:
/*
** Aircraft can be in either state of landing, taking off, or in steady altitude.
** These flags are used to control transition between flying and landing. It is
** necessary to handle the transition in this manner so that it occurs smoothly
** during the graphic processing section.
*/
unsigned IsLanding:1;
unsigned IsTakingOff:1;
/*
** It is very common for aircraft to be homing in on a target. When this flag is
** true, the aircraft will constantly adjust its facing toward the TarCom. When the
** target is very close (one cell away or less), then this flag is automatically cleared.
** This is because the homing algorithm is designed to get the aircraft to the destination
** but no more. Checking when this flag is cleared is a way of flagging transition into
** a new mode. Example: Transport helicopters go into a hovering into correct position
** mode when the target is reached.
*/
unsigned IsHoming:1;
/*
** Helicopters that are about to land must hover into a position exactly above the landing
** zone. When this flag is true, the aircraft will be adjusted so that it is exactly over
** the TarCom. The facing of the aircraft is not altered by this movement. The affect
** like the helicopter is hovering and shifting sideways to position over the landing
** zone. When the position is over the landing zone, then this flag is set to false.
*/
unsigned IsHovering:1;
/*
** This is the jitter tracker to be used when the aircraft is a helicopter and
** is flying. It is most noticeable when the helicopter is hovering.
*/
unsigned char Jitter;
private:
/*
** This timer controls when the aircraft will reveal the terrain around itself.
** When this timer expires and this aircraft has a sight range, then the
** look around process will occur.
*/
CDTimerClass<FrameTimerClass> SightTimer;
/*
** Most attack aircraft can make several attack runs. This value contains the
** number of attack runs the aircraft has left. When this value reaches
** zero then the aircraft is technically out of ammo.
*/
char AttacksRemaining;
};
#endif

590
CODE/ALLOC.CPP Normal file
View file

@ -0,0 +1,590 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/***************************************************************************
** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S **
***************************************************************************
* *
* Project Name : Westwood Library *
* *
* File Name : ALLOC.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : February 1, 1992 *
* *
* Last Update : March 9, 1995 [JLB] *
* *
*-------------------------------------------------------------------------*
* Functions: *
* Alloc -- Allocates system RAM. *
* Ram_Free -- Determines the largest free chunk of RAM. *
* Free -- Free an Alloc'ed block of RAM. *
* Resize_Alloc -- Change the size of an allocated block. *
* Heap_Size -- Size of the heap we have. *
* Total_Ram_Free -- Total amount of free RAM. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <dos.h>
#include <bios.h>
#include <stdio.h>
#ifndef WWMEM_H
#include "wwmem.h"
#endif
extern "C" unsigned long Largest_Mem_Block ( void ) ;
//
// use double-word alignment for allocs
//
#define LONG_ALIGNMENT 1
/*
** Define the equates necessary to call a DPMI interrupt.
*/
#define DPMI_INT 0x0031
#define DPMI_LOCK_MEM 0x0600
#define DPMI_UNLOCK_MEM 0x0601
#define LOGGING FALSE
/*=========================================================================*/
/* The following PRIVATE functions are in this file: */
/*=========================================================================*/
/*= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
unsigned long MinRam=0L; // Record of least memory at worst case.
unsigned long MaxRam=0L; // Record of total allocated at worst case.
static unsigned long TotalRam = 0L;
static unsigned long Memory_Calls = 0L;
static unsigned long RequestedSystemRam = 8*1024*1024;
static unsigned long LargestRamBlock = 0L;
void (*Memory_Error)(void) = NULL;
void (*Memory_Error_Exit)(char *string) = NULL;
/***************************************************************************
* DPMI_LOCK -- handles locking a block of DPMI memory *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 06/23/1995 PWG : Created. *
*=========================================================================*/
#include"mono.h"
void DPMI_Lock(VOID const *ptr, long const size)
{
union REGS regs;
struct SREGS sregs;
/*
** Lock memory
** AX = 0x600
** BX:CX = starting linear address of memory to lock
** SI:DI = size of region to lock (in bytes)
** - If Failure, carry flag is set.
*/
memset (&regs, 0 ,sizeof(regs));
segread (&sregs);
regs.x.eax = DPMI_LOCK_MEM;
regs.x.ebx = ((long)ptr & 0xffff0000) >> 16;
regs.x.ecx = ((long)ptr & 0x0000ffff);
regs.x.esi = ((long)size & 0xffff0000) >> 16;
regs.x.edi = ((long)size & 0x0000ffff);
int386x (DPMI_INT, &regs, &regs, &sregs); // call DPMI
// if (regs.x.cflag) {
// }
#if(0)
char *temp = (char *)ptr;
char hold;
for (int lp = 0; lp < size; lp += 2048) {
hold = *temp;
temp += 2048;
}
#endif
}
/***************************************************************************
* DPMI_UNLOCK -- Handles unlocking a locked block of DPMI *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 06/23/1995 PWG : Created. *
*=========================================================================*/
void DPMI_Unlock(void const *ptr, long const size)
{
union REGS regs;
struct SREGS sregs;
/*
** Unlock the memory
*/
memset (&regs, 0 ,sizeof(regs));
segread (&sregs);
regs.x.eax = DPMI_UNLOCK_MEM; // DPMI function to call
regs.x.ebx = ((long)ptr & 0xffff0000) >> 16;
regs.x.ecx = ((long)ptr & 0x0000ffff);
regs.x.esi = ((long)size & 0xffff0000) >> 16;
regs.x.edi = ((long)size & 0x0000ffff);
int386x (DPMI_INT, &regs, &regs, &sregs); // call DPMI
// if (regs.x.cflag) {
// }
}
/***************************************************************************
* Alloc -- Allocates system RAM. *
* *
* This is the basic RAM allocation function. It is used for all *
* memory allocations needed by the system or the main program. *
* *
* INPUT: bytes_to_alloc -- LONG value of the number of bytes to alloc. *
* *
* flags -- Memory allocation control flags. *
* MEM_NORMAL: No special flags. *
* MEM_CLEAR: Zero out memory block. *
* MEM_NEW: Called by a new. *
* *
* OUTPUT: Returns with pointer to allocated block. If NULL was returned *
* it indicates a failure to allocate. Note: NULL will never be *
* returned if the standard library allocation error routine is *
* used. *
* *
* WARNINGS: If you replace the standard memory allocation error routine *
* and make it so that Alloc CAN return with a NULL, be sure *
* and check for this in your code. *
* *
* HISTORY: *
* 09/03/1991 JLB : Documented. *
* 08/09/1993 JLB : Updated with EMS memory support. *
* 04/28/1994 JAW : Updated to 32bit Protected mode. *
* 03/09/1995 JLB : Fixed *
*=========================================================================*/
void *Alloc(unsigned long bytes_to_alloc, MemoryFlagType flags)
{
union REGS regs ;
struct SREGS sregs ;
unsigned char *retval=NULL; // Pointer to allocated block.
unsigned long original_size; // Original allocation size.
unsigned long bytesfree; // Number of free bytes.
long *longptr=NULL; // Pointer used to store selector
static unsigned char _allocinit=0;
//
// Init memory system by finding largest block to alloc
// then allocate it to get one large heap and free it.
// There may be more memory available from DPMI but we only are
// for now allocating and freeing the first largest block.
//
if ( !_allocinit ) {
unsigned long largestblock = Largest_Mem_Block();
largestblock -= 1024; // subtract for heap header and misc
largestblock &= 0xffff0000; // forcing to 64K boundary
if ( largestblock ) {
LargestRamBlock = MIN( largestblock, RequestedSystemRam );
unsigned char *lptr = (unsigned char *)malloc( LargestRamBlock );
if ( lptr ) {
free( (void *)lptr );
}
}
/*
** Initialize the total ram available value.
*/
TotalRam = Total_Ram_Free(MEM_NORMAL);
_allocinit = 1;
}
/*
** Save the original allocated space size so that we can clear the
** exact amount of RAM if they specified MEM_CLEAR.
*/
original_size = bytes_to_alloc;
/*
** Reserve one byte for the header of the memory we allocated.
** We will store the flags variable there for later use.
*/
#if (LONG_ALIGNMENT)
bytes_to_alloc += (flags & MEM_LOCK) ? 8 : 4;
#else
bytes_to_alloc += (flags & MEM_LOCK) ? 5 : 1;
#endif
// Try to allocate the memory out of the protected mode memory
// chain if we did not require a real mode allocation. If this
// fails we will have to try to allocate it out of real mode memory.
// Real mode memory is a last resort because some types of applications
// require real mode memory.
if (!(flags & MEM_REAL)) {
retval = (unsigned char*)malloc(bytes_to_alloc);
}
// Try to allocate the memory out of the real mode memory using DPMI
// service 0x100. Note that retval will be null if we are requesting
// real mode memory so that we do not have to explicitly check for the
// real mode flag. Remember we need to reserve room for the dos
// selector value at the beginning of our allocated block so rather than
// adding fifteen and rounding, we need to add 19 and round.
if (!retval) {
flags = (MemoryFlagType)(flags | MEM_REAL);
regs.x.eax = 0x100;
regs.x.ebx = (bytes_to_alloc + 19) >> 4;
if (regs.x.ebx & 0xFFFF0000) {
retval = NULL;
} else {
segread ( & sregs ) ;
int386x ( 0x31 , & regs, & regs , & sregs ) ;
if (regs.x.cflag)
retval = NULL;
else {
#if (LONG_ALIGNMENT)
longptr = (long *)(((regs.x.eax & 0xFFFF) << 4)+ 4);
#else
longptr = (long *)(((regs.x.eax & 0xFFFF) << 4)+ 1);
#endif
*longptr++ = regs.x.edx & 0xFFFF;
retval = (unsigned char *)longptr;
}
}
}
// If the alloc failed then we need to signify a memory error.
if (retval == NULL) {
if (Memory_Error != NULL)
Memory_Error();
return NULL;
}
// If the memory needs to be DPMI locked then we should store the
// original size in the header before we store the flags.
if (flags & MEM_LOCK) {
longptr = (long *)retval;
*longptr++ = original_size;
retval = (unsigned char *)longptr;
}
// Now that we know the alloc was sucessful (and for an extra byte
// more than the user wanted) we need to stick in the memory flags.
#if (LONG_ALIGNMENT)
if ( !(flags & (MEM_LOCK|MEM_REAL)) ) {
//
// WARNING!!!!!!!!!!
// USE this only with the WATCOM malloc ALLOCATION!!!!!!!!!
// it reads the actual block size before the ptr returned.
// then eors and uses the upper word for a validation later on free.
//
longptr = (long *)retval;
*longptr = ((*(longptr - 1)) ^ 0xffffffff) & 0xffff0000;
*retval++ = flags;
*retval++ = (unsigned char)(flags ^ 0xff);
retval += 2;
}
else {
*retval++ = flags;
*retval++ = (unsigned char)(flags ^ 0xff);
*retval++ = 0;
*retval++ = 0;
}
#else
*retval++ = (unsigned char)(flags | (((flags ^ 0x07) & 0x07) << 5));
#endif
// If the memory needed to be DPMI locked then set it up so it
// is locked.
if (flags & MEM_LOCK) {
DPMI_Lock(retval, original_size);
}
/* Clear the space if they wanted it clear */
if (flags & MEM_CLEAR) {
unsigned char *ptr; // Working memory block pointer.
ptr = retval;
memset(ptr, '\0', original_size);
}
bytesfree = Total_Ram_Free(MEM_NORMAL);
if (bytesfree < MinRam) {
MinRam = bytesfree;
}
if (TotalRam-bytesfree > MaxRam) {
MaxRam = TotalRam-bytesfree;
}
Memory_Calls++;
#if(LOGGING)
int val = _heapchk();
FILE *file = fopen("mem.txt","at");
fprintf(file, "%P Alloc size = %d, Actual Size = %d, flags = %d, heap = %d\n",
retval,
original_size,
bytes_to_alloc,
flags,
val);
fclose(file);
#endif
return(retval);
}
/***************************************************************************
* Free -- Free an Alloc'ed block of RAM. *
* *
* FUNCTION: *
* *
* INPUT: A pointer to a block of RAM from Alloc. *
* *
* OUTPUT: None. *
* *
* WARNINGS: Don't use this for an Alloc_Block'ed RAM block. *
* *
* HISTORY: *
* 05/25/1990 : Created. *
***************************************************************************/
void Free(void const *pointer)
{
union REGS regs ;
struct SREGS sregs ;
// void const *original = pointer;
char string[80];
if (pointer) {
/*
** Get a pointer to the flags that we stored off.
*/
#if (LONG_ALIGNMENT)
unsigned char *byteptr = ((unsigned char *)pointer) - 4;
//
// validate the flags with and eor of the flags
//
if ( *byteptr != ((*(byteptr + 1)) ^ 0xff) ) {
if (Memory_Error_Exit != NULL) {
sprintf( string, "Error freeing pointer %p. Header invalid!!!\n", pointer );
Memory_Error_Exit( string );
}
}
else {
if ( !(*byteptr & (MEM_LOCK|MEM_REAL)) ) {
unsigned short *wordptr = (unsigned short *)(byteptr - 2);
//
// WARNING!!!!!!!!!!
// USE this only with the WATCOM malloc ALLOCATION!!!!!!!!!
// it reads the actual block size before the ptr to be freed.
// then compares with the EOR to the value stored during allocation.
//
if ( *wordptr != ((*(wordptr + 2)) ^ 0xffff) ) {
if (Memory_Error_Exit != NULL) {
sprintf( string, "Error freeing pointer %p. Header invalid!!!\n", pointer );
Memory_Error_Exit( string );
}
}
}
else if ( *(byteptr + 2) || *(byteptr + 3) ) {
if (Memory_Error_Exit != NULL) {
sprintf( string, "Error freeing pointer %p. Header invalid!!!\n", pointer );
Memory_Error_Exit( string );
}
}
}
// if ( *byteptr != (*(byteptr + 1) ^ 0xff) ||
// *(byteptr + 2) || *(byteptr + 3) ) {
// if (Memory_Error_Exit != NULL) {
// sprintf( string, "Error freeing pointer %p. Header invalid!!!\n", pointer );
// Memory_Error_Exit( string );
// }
// }
#else
unsigned char *byteptr = ((unsigned char *)pointer) - 1;
if ( (*byteptr & 0xe0) != (((*byteptr ^ 0x07) & 0x07) << 5) ) {
if (Memory_Error_Exit != NULL) {
sprintf( string, "Error freeing pointer %p. Header invalid!!!\n", pointer );
Memory_Error_Exit( string );
}
}
#endif
/*
** Check to see if this was locked me and if it was unlock it.
*/
if (*byteptr & MEM_LOCK) {
long *longptr = ((long *)byteptr) - 1;
DPMI_Unlock(pointer, *longptr);
pointer = (void *)longptr;
} else
pointer = (void *)byteptr;
#if(LOGGING)
int val = _heapchk();
FILE *file = fopen("mem.txt","at");
fprintf(file, "%P Free flags = %d, Heap = %d\n",
original,
*byteptr,
val);
fclose(file);
#endif
// If the pointer is a real mode pointer than it will point to the
// first megabyte of system memory. If it does than we need to
// use DPMI to free it.
if (*byteptr & MEM_REAL) {
regs.x.eax = 0x101;
regs.x.edx = *(((long *)pointer) - 1);
segread ( & sregs ) ;
int386x(0x31, &regs, &regs, &sregs);
} else {
free((void *)pointer);
}
Memory_Calls--;
}
}
/***************************************************************************
* Resize_Alloc -- Change the size of an allocated block. *
* *
* This routine will take a previously allocated block and change its *
* size without unnecessarily altering its contents. *
* *
* INPUT: pointer -- Pointer to the original memory allocation. *
* *
* new_size -- Size in bytes that it will be converted to. *
* *
* OUTPUT: Returns with a pointer to the new allocation. *
* *
* WARNINGS: ??? *
* *
* HISTORY: *
* 02/01/1992 JLB : Commented. *
*=========================================================================*/
void *Resize_Alloc(void *original_ptr, unsigned long new_size_in_bytes)
{
unsigned long *temp;
// unsigned long diff, flags;
temp = (unsigned long*)original_ptr;
/* ReAlloc the space */
temp = (unsigned long *)realloc(temp, new_size_in_bytes);
if (temp == NULL) {
if (Memory_Error != NULL)
Memory_Error();
return NULL;
}
return(temp);
}
/***************************************************************************
* Ram_Free -- Determines the largest free chunk of RAM. *
* *
* Use this routine to determine the largest free chunk of available *
* RAM for allocation. It also performs a check of the memory chain. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the size of the largest free chunk of RAM. *
* *
* WARNINGS: This does not return the TOTAL memory free, only the *
* largest free chunk. *
* *
* HISTORY: *
* 09/03/1991 JLB : Commented. *
*=========================================================================*/
long Ram_Free(MemoryFlagType)
{
return(_memmax());
// return Largest_Mem_Block();
}
/***************************************************************************
* Heap_Size -- Size of the heap we have. *
* *
* *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 06/21/1994 SKB : Created. *
*=========================================================================*/
long Heap_Size(MemoryFlagType )
{
if (!TotalRam) {
TotalRam = Total_Ram_Free(MEM_NORMAL);
}
return(TotalRam);
}
/***************************************************************************
* Total_Ram_Free -- Total amount of free RAM. *
* *
* *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 06/21/1994 SKB : Created. *
* 03/09/1995 JLB : Uses prerecorded heap size maximum. *
*=========================================================================*/
long Total_Ram_Free(MemoryFlagType )
{
return(_memavl());
// return Largest_Mem_Block () ;
}

1108
CODE/ANIM.CPP Normal file

File diff suppressed because it is too large Load diff

1062
CODE/ANIM.CPP.BAK Normal file

File diff suppressed because it is too large Load diff

156
CODE/ANIM.H Normal file
View file

@ -0,0 +1,156 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/ANIM.H 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : ANIM.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : May 30, 1994 *
* *
* Last Update : May 30, 1994 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef ANIM_H
#define ANIM_H
#include "type.h"
/**********************************************************************************************
** This is the class that controls the shape animation objects. Shape animation objects are
** displayed over the top of the game map. Typically, they are used for explosion and fire
** effects.
*/
class AnimClass : public ObjectClass, public StageClass {
/*
** This points to the type of animation object this is.
*/
CCPtr<AnimTypeClass> Class;
public:
AnimClass(AnimType animnum, COORDINATE coord, unsigned char timedelay=0, unsigned char loop=1);
AnimClass(NoInitClass const & x) : ObjectClass(x), Class(x), StageClass(x) {};
virtual ~AnimClass(void);
operator AnimType(void) const {return Class->Type;};
static void * operator new(size_t size);
static void * operator new(size_t , void * ptr) {return(ptr);};
static void operator delete(void *ptr);
/*---------------------------------------------------------------------
** Member function prototypes.
*/
static void Init(void);
void Attach_To(ObjectClass *obj);
void Make_Invisible(void) {IsInvisible = true;};
static void Do_Atom_Damage(HousesType ownerhouse, CELL cell);
virtual bool Can_Place_Here(COORDINATE ) const {return true;}
virtual bool Mark(MarkType mark=MARK_CHANGE);
virtual bool Render(bool forced) const;
virtual COORDINATE Center_Coord(void) const;
virtual COORDINATE Sort_Y(void) const;
virtual LayerType In_Which_Layer(void) const;
virtual ObjectTypeClass const & Class_Of(void) const {return *Class;};
virtual short const * Occupy_List(bool = false) const;
virtual short const * Overlap_List(void) const;
virtual void Draw_It(int x, int y, WindowNumberType window) const;
virtual void AI(void);
virtual void Detach(TARGET target, bool all);
/*
** File I/O.
*/
bool Load(Straw & file);
bool Save(FileClass & file);
/*
** If this animation is attached to an object, then this points to that object. An
** animation that is attached will follow that object as it moves. This is important
** for animations such as flames and smoke.
*/
TARGET xObject;
/*
** If this animation has an owner, then it will be recorded here. An owner
** is used when damage is caused by this animation during the middle of its
** animation.
*/
HousesType OwnerHouse;
/*
** This counter tells how many more times the animation should loop before it
** terminates.
*/
unsigned char Loops;
protected:
void Middle(void);
void Start(void);
private:
/*
** Delete this animation at the next opportunity. This is flagged when the
** animation is to be prematurely ended as a result of some outside event.
*/
unsigned IsToDelete:1;
/*
** If the animation has just been created, then don't do any animation
** processing until it has been through the render loop at least once.
*/
unsigned IsBrandNew:1;
/*
** If this animation is invisible, then this flag will be true. An invisible
** animation is one that is created for the sole purpose of keeping all
** machines synchronized. It will not be displayed.
*/
unsigned IsInvisible:1;
/*
** Is this animation in a temporary suspended state? If so, then it won't
** be rendered until this value is zero. The flag will be set to false
** after the first countdown timer reaches 0.
*/
int Delay;
/*
** If this is an animation that damages whatever it is attached to, then this
** value holds the accumulation of fractional damage points. When the accumulated
** fractions reach 256, then one damage point is applied to the attached object.
*/
fixed Accum;
};
#endif

763
CODE/AUDIO.CPP Normal file
View file

@ -0,0 +1,763 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/AUDIO.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : AUDIO.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : September 10, 1993 *
* *
* Last Update : November 1, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* Is_Speaking -- Checks to see if the eva voice is still playing. *
* Sound_Effect -- General purpose sound player. *
* Sound_Effect -- Plays a sound effect in the tactical map. *
* Speak -- Computer speaks to the player. *
* Speak_AI -- Handles starting the EVA voices. *
* Speech_Name -- Fetches the name for the voice specified. *
* Stop_Speaking -- Forces the EVA voice to stop talking. *
* Voc_From_Name -- Fetch VocType from ASCII name specified. *
* Voc_Name -- Fetches the name for the sound effect. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
/***************************************************************************
** Controls what special effects may occur on the sound effect.
*/
typedef enum {
IN_NOVAR, // No variation or alterations allowed.
IN_VAR // Infantry variance response modification.
} ContextType;
static struct {
char const * Name; // Digitized voice file name.
int Priority; // Playback priority of this sample.
ContextType Where; // In what game context does this sample exist.
} SoundEffectName[VOC_COUNT] = {
/*
** Civilian voices (technicians too).
*/
{"GIRLOKAY", 20, IN_NOVAR}, // VOC_GIRL_OKAY
{"GIRLYEAH", 20, IN_NOVAR}, // VOC_GIRL_YEAH
{"GUYOKAY1", 20, IN_NOVAR}, // VOC_GUY_OKAY
{"GUYYEAH1", 20, IN_NOVAR}, // VOC_GUY_YEAH
{"MINELAY1", 5, IN_VAR}, // VOC_MINELAY1
/*
** Infantry and vehicle responses.
*/
{"ACKNO", 20, IN_VAR}, // VOC_ACKNOWL "acknowledged"
{"AFFIRM1", 20, IN_VAR}, // VOC_AFFIRM "affirmative"
{"AWAIT1", 20, IN_VAR}, // VOC_AWAIT1 "awaiting orders"
{"EAFFIRM1", 20, IN_NOVAR}, // VOC_ENG_AFFIRM Engineer: "affirmative"
{"EENGIN1", 20, IN_NOVAR}, // VOC_ENG_ENG Engineer: "engineering"
{"NOPROB", 20, IN_VAR}, // VOC_NO_PROB "not a problem"
{"READY", 20, IN_VAR}, // VOC_READY "ready and waiting"
{"REPORT1", 20, IN_VAR}, // VOC_REPORT "reporting"
{"RITAWAY", 20, IN_VAR}, // VOC_RIGHT_AWAY "right away sir"
{"ROGER", 20, IN_VAR}, // VOC_ROGER "roger"
{"UGOTIT", 20, IN_VAR}, // VOC_UGOTIT "you got it"
{"VEHIC1", 20, IN_VAR}, // VOC_VEHIC1 "vehicle reporting"
{"YESSIR1", 20, IN_VAR}, // VOC_YESSIR "yes sir"
{"DEDMAN1", 10, IN_NOVAR}, // VOC_SCREAM1 short infantry scream
{"DEDMAN2", 10, IN_NOVAR}, // VOC_SCREAM3 short infantry scream
{"DEDMAN3", 10, IN_NOVAR}, // VOC_SCREAM4 short infantry scream
{"DEDMAN4", 10, IN_NOVAR}, // VOC_SCREAM5 short infantry scream
{"DEDMAN5", 10, IN_NOVAR}, // VOC_SCREAM6 short infantry scream
{"DEDMAN6", 10, IN_NOVAR}, // VOC_SCREAM7 short infantry scream
{"DEDMAN7", 10, IN_NOVAR}, // VOC_SCREAM10 short infantry scream
{"DEDMAN8", 10, IN_NOVAR}, // VOC_SCREAM11 short infantry scream
{"DEDMAN10", 10, IN_NOVAR}, // VOC_YELL1 long infantry scream
{"CHRONO2", 5, IN_NOVAR}, // VOC_CHRONO Chronosphere sound
{"CANNON1", 1, IN_NOVAR}, // VOC_CANNON1 Cannon sound (medium).
{"CANNON2", 1, IN_NOVAR}, // VOC_CANNON2 Cannon sound (short).
{"IRONCUR9", 10, IN_NOVAR}, // VOC_IRON1
{"EMOVOUT1", 20, IN_NOVAR}, // VOC_ENG_MOVEOUT Engineer: "movin' out"
{"SONPULSE", 10, IN_NOVAR}, // VOC_SONAR
{"SANDBAG2", 5, IN_NOVAR}, // VOC_SANDBAG sand bag crunch
{"MINEBLO1", 5, IN_NOVAR}, // VOC_MINEBLOW weird mine explosion
{"CHUTE1", 1, IN_NOVAR}, // VOC_CHUTE1 Wind swoosh sound.
{"DOGY1", 5, IN_NOVAR}, // VOC_DOG_BARK Dog bark.
{"DOGW5", 10, IN_NOVAR}, // VOC_DOG_WHINE Dog whine.
{"DOGG5P", 10, IN_NOVAR}, // VOC_DOG_GROWL2 Strong dog growl.
{"FIREBL3", 1, IN_NOVAR}, // VOC_FIRE_LAUNCH Fireball launch sound.
{"FIRETRT1", 1, IN_NOVAR}, // VOC_FIRE_EXPLODE Fireball explode sound.
{"GRENADE1", 1, IN_NOVAR}, // VOC_GRENADE_TOSS Grenade toss.
{"GUN11", 1, IN_NOVAR}, // VOC_GUN_5 5 round gun burst (slow).
{"GUN13", 1, IN_NOVAR}, // VOC_GUN_7 7 round gun burst (fast).
{"EYESSIR1", 20, IN_NOVAR}, // VOC_ENG_YES, Engineer: "yes sir"
{"GUN27", 1, IN_NOVAR}, // VOC_GUN_RIFLE Rifle shot.
{"HEAL2", 1, IN_NOVAR}, // VOC_HEAL Healing effect.
{"HYDROD1", 1, IN_NOVAR}, // VOC_DOOR Hyrdrolic door.
{"INVUL2", 1, IN_NOVAR}, // VOC_INVULNERABLE Invulnerability effect.
{"KABOOM1", 1, IN_NOVAR}, // VOC_KABOOM1 Long explosion (muffled).
{"KABOOM12", 1, IN_NOVAR}, // VOC_KABOOM12 Very long explosion (muffled).
{"KABOOM15", 1, IN_NOVAR}, // VOC_KABOOM15 Very long explosion (muffled).
{"SPLASH9", 5, IN_NOVAR}, // VOC_SPLASH water splash
{"KABOOM22", 1, IN_NOVAR}, // VOC_KABOOM22 Long explosion (sharp).
{"AACANON3", 1, IN_NOVAR},
{"TANDETH1", 10, IN_NOVAR},
{"MGUNINF1", 1, IN_NOVAR}, // VOC_GUN_5F 5 round gun burst (fast).
{"MISSILE1", 1, IN_NOVAR}, // VOC_MISSILE_1 Missile with high tech effect.
{"MISSILE6", 1, IN_NOVAR}, // VOC_MISSILE_2 Long missile launch.
{"MISSILE7", 1, IN_NOVAR}, // VOC_MISSILE_3 Short missile launch.
{"x", 1, IN_NOVAR},
{"PILLBOX1", 1, IN_NOVAR}, // VOC_GUN_5R 5 round gun burst (rattles).
{"RABEEP1", 1, IN_NOVAR}, // VOC_BEEP Generic beep sound.
{"RAMENU1", 1, IN_NOVAR}, // VOC_CLICK Generic click sound.
{"SILENCER", 1, IN_NOVAR}, // VOC_SILENCER Silencer.
{"TANK5", 1, IN_NOVAR}, // VOC_CANNON6 Long muffled cannon shot.
{"TANK6", 1, IN_NOVAR}, // VOC_CANNON7 Sharp mechanical cannon fire.
{"TORPEDO1", 1, IN_NOVAR}, // VOC_TORPEDO Torpedo launch.
{"TURRET1", 1, IN_NOVAR}, // VOC_CANNON8 Sharp cannon fire.
{"TSLACHG2", 10, IN_NOVAR}, // VOC_TESLA_POWER_UP Hum charge up.
{"TESLA1", 10, IN_NOVAR}, // VOC_TESLA_ZAP Tesla zap effect.
{"SQUISHY2", 10, IN_NOVAR}, // VOC_SQUISH Squish effect.
{"SCOLDY1", 10, IN_NOVAR}, // VOC_SCOLD Scold bleep.
{"RADARON2", 20, IN_NOVAR}, // VOC_RADAR_ON Powering up electronics.
{"RADARDN1", 10, IN_NOVAR}, // VOC_RADAR_OFF B movie power down effect.
{"PLACBLDG", 10, IN_NOVAR}, // VOC_PLACE_BUILDING_DOWN Building slam down sound.
{"KABOOM30", 1, IN_NOVAR}, // VOC_KABOOM30 Short explosion (HE).
{"KABOOM25", 10, IN_NOVAR}, // VOC_KABOOM25 Short growling explosion.
{"x", 10, IN_NOVAR},
{"DOGW7", 10, IN_NOVAR}, // VOC_DOG_HURT Dog whine (loud).
{"DOGW3PX", 10, IN_NOVAR}, // VOC_DOG_YES Dog 'yes sir'.
{"CRMBLE2", 10, IN_NOVAR}, // VOC_CRUMBLE Building crumble.
{"CASHUP1", 10, IN_NOVAR}, // VOC_MONEY_UP Rising money tick.
{"CASHDN1", 10, IN_NOVAR}, // VOC_MONEY_DOWN Falling money tick.
{"BUILD5", 10, IN_NOVAR}, // VOC_CONSTRUCTION Building construction sound.
{"BLEEP9", 10, IN_NOVAR}, // VOC_GAME_CLOSED Long bleep.
{"BLEEP6", 10, IN_NOVAR}, // VOC_INCOMING_MESSAGE Soft happy warble.
{"BLEEP5", 10, IN_NOVAR}, // VOC_SYS_ERROR Sharp soft warble.
{"BLEEP17", 10, IN_NOVAR}, // VOC_OPTIONS_CHANGED Mid range soft warble.
{"BLEEP13", 10, IN_NOVAR}, // VOC_GAME_FORMING Long warble.
{"BLEEP12", 10, IN_NOVAR}, // VOC_PLAYER_LEFT Chirp sequence.
{"BLEEP11", 10, IN_NOVAR}, // VOC_PLAYER_JOINED Reverse chirp sequence.
{"H2OBOMB2", 10, IN_NOVAR}, // VOC_DEPTH_CHARGE Distant explosion sound.
{"CASHTURN", 10, IN_NOVAR}, // VOC_CASHTURN Airbrake.
{"TUFFGUY1", 20, IN_NOVAR}, // VOC_TANYA_CHEW Tanya: "Chew on this"
{"ROKROLL1", 20, IN_NOVAR}, // VOC_TANYA_ROCK Tanya: "Let's rock"
{"LAUGH1", 20, IN_NOVAR}, // VOC_TANYA_LAUGH Tanya: "ha ha ha"
{"CMON1", 20, IN_NOVAR}, // VOC_TANYA_SHAKE Tanya: "Shake it baby"
{"BOMBIT1", 20, IN_NOVAR}, // VOC_TANYA_CHING Tanya: "Cha Ching"
{"GOTIT1", 20, IN_NOVAR}, // VOC_TANYA_GOT Tanya: "That's all you got"
{"KEEPEM1", 20, IN_NOVAR}, // VOC_TANYA_KISS Tanya: "Kiss it bye bye"
{"ONIT1", 20, IN_NOVAR}, // VOC_TANYA_THERE Tanya: "I'm there"
{"LEFTY1", 20, IN_NOVAR}, // VOC_TANYA_GIVE Tanya: "Give it to me"
{"YEAH1", 20, IN_NOVAR}, // VOC_TANYA_YEA Tanya: "Yea?"
{"YES1", 20, IN_NOVAR}, // VOC_TANYA_YES Tanya: "Yes sir?"
{"YO1", 20, IN_NOVAR}, // VOC_TANYA_WHATS Tanya: "What's up."
{"WALLKIL2", 5, IN_NOVAR}, // VOC_WALLKILL2 Crushing wall sound.
{"x", 10, IN_NOVAR},
{"GUN5", 5, IN_NOVAR}, // VOC_TRIPLE_SHOT Three quick shots in succession.
{"SUBSHOW1", 5, IN_NOVAR}, // VOC_SUBSHOW Submarine surface sound.
{"EINAH1", 20, IN_NOVAR}, // VOC_E_AH, Einstien "ah"
{"EINOK1", 20, IN_NOVAR}, // VOC_E_OK, Einstien "ok"
{"EINYES1", 20, IN_NOVAR}, // VOC_E_YES, Einstien "yes"
{"MINE1", 10, IN_NOVAR}, // VOC_TRIP_MINE mine explosion sound
{"SCOMND1", 20, IN_NOVAR}, // VOC_SPY_COMMANDER Spy: "commander?"
{"SYESSIR1", 20, IN_NOVAR}, // VOC_SPY_YESSIR Spy: "yes sir"
{"SINDEED1", 20, IN_NOVAR}, // VOC_SPY_INDEED Spy: "indeed"
{"SONWAY1", 20, IN_NOVAR}, // VOC_SPY_ONWAY Spy: "on my way"
{"SKING1", 20, IN_NOVAR}, // VOC_SPY_KING Spy: "for king and country"
{"MRESPON1", 20, IN_NOVAR}, // VOC_MED_REPORTING Medic: "reporting"
{"MYESSIR1", 20, IN_NOVAR}, // VOC_MED_YESSIR Medic: "yes sir"
{"MAFFIRM1", 20, IN_NOVAR}, // VOC_MED_AFFIRM Medic: "affirmative"
{"MMOVOUT1", 20, IN_NOVAR}, // VOC_MED_MOVEOUT Medic: "movin' out"
{"BEEPSLCT", 10, IN_NOVAR}, // VOC_BEEP_SELECT map selection beep
{"SYEAH1", 20, IN_NOVAR}, // VOC_THIEF_YEA Thief: "yea?"
{"ANTDIE", 20, IN_NOVAR}, // VOC_ANTDIE
{"ANTBITE", 20, IN_NOVAR}, // VOC_ANTBITE
{"SMOUT1", 20, IN_NOVAR}, // VOC_THIEF_MOVEOUT Thief: "movin' out"
{"SOKAY1", 20, IN_NOVAR}, // VOC_THIEF_OKAY Thief: "ok"
{"x", 20, IN_NOVAR},
{"SWHAT1", 20, IN_NOVAR}, // VOC_THIEF_WHAT Thief: "what"
{"SAFFIRM1", 20, IN_NOVAR}, // VOC_THIEF_AFFIRM Thief: "affirmative"
//ADDED VG 2/24/97
{"STAVCMDR", 20, IN_NOVAR},
{"STAVCRSE", 20, IN_NOVAR},
{"STAVYES", 20, IN_NOVAR},
{"STAVMOV", 20, IN_NOVAR},
{"BUZZY1", 20, IN_NOVAR},
{"RAMBO1", 20, IN_NOVAR},
{"RAMBO2", 20, IN_NOVAR},
{"RAMBO3", 20, IN_NOVAR},
#ifdef FIXIT_CSII // checked - ajw 9/28/98
{"MYES1", 20, IN_NOVAR}, // VOC_MECHYES1 Mechanic: "Yes sir!"
{"MHOWDY1", 20, IN_NOVAR}, // VOC_MECHHOWDY1 Mechanic: "Howdy!"
{"MRISE1", 20, IN_NOVAR}, // VOC_MECHRISE1 Mechanic: "Rise 'n shine!"
{"MHUH1", 20, IN_NOVAR}, // VOC_MECHHUH1 Mechanic: "Huh?"
{"MHEAR1", 20, IN_NOVAR}, // VOC_MECHHEAR1 Mechanic: "I Hear Ya!"
{"MLAFF1", 20, IN_NOVAR}, // VOC_MECHLAFF1 Mechanic: guffaw
{"MBOSS1", 20, IN_NOVAR}, // VOC_MECHBOSS1 Mechanic: "Sure Thing, Boss!"
{"MYEEHAW1", 20, IN_NOVAR}, // VOC_MECHYEEHAW1 Mechanic: "Yee Haw!"
{"MHOTDIG1", 20, IN_NOVAR}, // VOC_MECHHOTDIG1 Mechanic: "Hot Diggity Dog!"
{"MWRENCH1", 20, IN_NOVAR}, // VOC_MECHWRENCH1 Mechanic: "I'll get my wrench."
{"JBURN1", 20, IN_NOVAR}, // VOC_STBURN1 Shock Trooper: "Burn baby burn!"
{"JCHRGE1", 20, IN_NOVAR}, // VOC_STCHRGE1 Shock Trooper: "Fully charged!"
{"JCRISP1", 20, IN_NOVAR}, // VOC_STCRISP1 Shock Trooper: "Extra Crispy!"
{"JDANCE1", 20, IN_NOVAR}, // VOC_STDANCE1 Shock Trooper: "Let's Dance!"
{"JJUICE1", 20, IN_NOVAR}, // VOC_STJUICE1 Shock Trooper: "Got juice?"
{"JJUMP1", 20, IN_NOVAR}, // VOC_STJUMP1 Shock Trooper: "Need a jump?"
{"JLIGHT1", 20, IN_NOVAR}, // VOC_STLIGHT1 Shock Trooper: "Lights out!"
{"JPOWER1", 20, IN_NOVAR}, // VOC_STPOWER1 Shock Trooper: "Power on!"
{"JSHOCK1", 20, IN_NOVAR}, // VOC_STSHOCK1 Shock Trooper: "Shocking!"
{"JYES1", 20, IN_NOVAR}, // VOC_STYES1 Shock Trooper: "Yesssss!"
{"CHROTNK1", 20, IN_NOVAR}, // VOC_CHRONOTANK1 Chrono tank teleport
{"FIXIT1", 20, IN_NOVAR}, // VOC_MECH_FIXIT1 Mechanic fixes something
{"MADCHRG2", 20, IN_NOVAR}, // VOC_MAD_CHARGE MAD tank charges up
{"MADEXPLO", 20, IN_NOVAR}, // VOC_MAD_EXPLODE MAD tank explodes
{"SHKTROP1", 20, IN_NOVAR}, // VOC_SHOCK_TROOP1 Shock Trooper fires
#endif
};
/***********************************************************************************************
* Voc_From_Name -- Fetch VocType from ASCII name specified. *
* *
* This will find the corresponding VocType from the ASCII string specified. It does this *
* by finding a root filename that matches the string. *
* *
* INPUT: name -- Pointer to the ASCII string that will be converted into a VocType. *
* *
* OUTPUT: Returns with the VocType that matches the string specified. If no match could be *
* found, then VOC_NONE is returned. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/06/1996 JLB : Created. *
*=============================================================================================*/
VocType Voc_From_Name(char const * name)
{
if (name == NULL) return(VOC_NONE);
for (VocType voc = VOC_FIRST; voc < VOC_COUNT; voc++) {
if (stricmp(name, SoundEffectName[voc].Name) == 0) {
return(voc);
}
}
return(VOC_NONE);
}
/***********************************************************************************************
* Voc_Name -- Fetches the name for the sound effect. *
* *
* This routine returns the descriptive name of the sound effect. Currently, this is just *
* the root of the file name. *
* *
* INPUT: voc -- The VocType that the corresponding name is requested. *
* *
* OUTPUT: Returns with a pointer to the text string the represents the sound effect. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/06/1996 JLB : Created. *
*=============================================================================================*/
char const * Voc_Name(VocType voc)
{
if (voc == VOC_NONE) return("none");
return(SoundEffectName[voc].Name);
}
/***********************************************************************************************
* Sound_Effect -- Plays a sound effect in the tactical map. *
* *
* This routine is used when a sound effect occurs in the game world. It handles fading *
* the sound according to distance. *
* *
* INPUT: voc -- The sound effect number to play. *
* *
* coord -- The world location that the sound originates from. *
* *
* variation -- This is the optional variation number to use when playing special *
* sound effects that have variations. For normal sound effects, this *
* parameter is ignored. *
* *
* house -- This specifies the optional house override value to use when playing *
* sound effects that have a variation. If not specified, then the current *
* player is examined for the house variation to use. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/12/1994 JLB : Created. *
* 01/05/1995 JLB : Reduces sound more dramatically when off screen. *
* 09/15/1996 JLB : Revamped volume logic. *
* 11/01/1996 JLB : House override control. *
*=============================================================================================*/
void Sound_Effect(VocType voc, COORDINATE coord, int variation, HousesType house)
{
CELL cell_pos = 0;
int pan_value;
if (Debug_Quiet || Options.Volume == 0 || voc == VOC_NONE || !SoundOn || SampleType == SAMPLE_NONE) {
return;
}
if (coord) {
cell_pos = Coord_Cell(coord);
}
fixed volume = 1;
pan_value = 0;
if (coord && !Map.In_View(cell_pos)) {
int distance = Distance(coord, Map.TacticalCoord) / CELL_LEPTON_W;
fixed dfixed = fixed(distance, 128+64);
dfixed.Sub_Saturate(1);
volume = fixed(1) - dfixed;
pan_value = Cell_X(cell_pos);
pan_value -= Coord_XCell(Map.TacticalCoord) + (Lepton_To_Cell(Map.TacLeptonWidth) / 2);
if (ABS(pan_value) > Lepton_To_Cell(Map.TacLeptonWidth / 2)) {
pan_value *= 0x8000;
pan_value /= (MAP_CELL_W >> 2);
pan_value = Bound(pan_value, -0x7FFF, 0x7FFF);
} else {
pan_value = 0;
}
}
Sound_Effect(voc, volume, variation, pan_value, house);
}
/***********************************************************************************************
* Sound_Effect -- General purpose sound player. *
* *
* This is used for general purpose sound effects. These are sounds that occur outside *
* of the game world. They do not have a corresponding game world location as their source. *
* *
* INPUT: voc -- The sound effect number to play. *
* *
* volume -- The volume to assign to this sound effect. *
* *
* variation -- This is the optional variation number to use when playing special *
* sound effects that have variations. For normal sound effects, this *
* parameter is ignored. *
* *
* house -- This specifies the optional house override value to use when playing *
* sound effects that have a variation. If not specified, then the current *
* player is examined for the house variation to use. *
* *
* OUTPUT: Returns with the sound handle (-1 if no sound was played). *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/12/1994 JLB : Created. *
* 11/12/1994 JLB : Handles cache logic. *
* 05/04/1995 JLB : Variation adjustments. *
* 11/01/1996 JLB : House override control. *
*=============================================================================================*/
int Sound_Effect(VocType voc, fixed volume, int variation, signed short pan_value, HousesType house)
{
char name[_MAX_FNAME+_MAX_EXT]; // Working filename of sound effect.
if (Debug_Quiet || Options.Volume == 0 || voc == VOC_NONE || !SoundOn || SampleType == SAMPLE_NONE) {
return(-1);
}
/*
** Alter the volume according to the game volume setting.
*/
volume = volume * Options.Volume;
/*
** Fetch a pointer to the sound effect data. Modify the sound as appropriate and desired.
*/
char const * ext = ".AUD";
if (SoundEffectName[voc].Where == IN_VAR) {
/*
** If there is no forced house, then use the current player
** act like house.
*/
if (house == HOUSE_NONE) {
house = PlayerPtr->ActLike;
}
/*
** Change the extension based on the variation and house accent requested.
*/
if (((1 << house) & HOUSEF_ALLIES) != 0) {
/*
** For infantry, use a variation on the response. For vehicles, always
** use the vehicle response table.
*/
if (variation < 0) {
if (ABS(variation) % 2) {
ext = ".V00";
} else {
ext = ".V02";
}
} else {
if (variation % 2) {
ext = ".V01";
} else {
ext = ".V03";
}
}
} else {
if (variation < 0) {
if (ABS(variation) % 2) {
ext = ".R00";
} else {
ext = ".R02";
}
} else {
if (variation % 2) {
ext = ".R01";
} else {
ext = ".R03";
}
}
}
}
_makepath(name, NULL, NULL, SoundEffectName[voc].Name, ext);
void const * ptr = MFCD::Retrieve(name);
/*
** If the sound data pointer is not null, then presume that it is valid.
*/
if (ptr != NULL) {
volume.Sub_Saturate(1);
return(Play_Sample(ptr, SoundEffectName[voc].Priority * volume, volume*256, pan_value));
}
return(-1);
}
/*
** This elaborates all the EVA speech voices.
*/
static char const * Speech[VOX_COUNT] = {
"MISNWON1", // VOX_ACCOMPLISHED mission accomplished
"MISNLST1", // VOX_FAIL your mission has failed
"PROGRES1", // VOX_NO_FACTORY unable to comply, building in progress
"CONSCMP1", // VOX_CONSTRUCTION construction complete
"UNITRDY1", // VOX_UNIT_READY unit ready
"NEWOPT1", // VOX_NEW_CONSTRUCT new construction options
"NODEPLY1", // VOX_DEPLOY cannot deploy here
"STRCKIL1", // VOX_STRUCTURE_DESTROYED, structure destroyed
"NOPOWR1", // VOX_INSUFFICIENT_POWER, insufficient power
"NOFUNDS1", // VOX_NO_CASH insufficient funds
"BCT1", // VOX_CONTROL_EXIT battle control terminated
"REINFOR1", // VOX_REINFORCEMENTS reinforcements have arrived
"CANCLD1", // VOX_CANCELED canceled
"ABLDGIN1", // VOX_BUILDING building
"LOPOWER1", // VOX_LOW_POWER low power
"NOFUNDS1", // VOX_NEED_MO_MONEY insufficent funds
"BASEATK1", // VOX_BASE_UNDER_ATTACK our base is under attack
"NOBUILD1", // VOX_UNABLE_TO_BUILD unable to build more
"PRIBLDG1", // VOX_PRIMARY_SELECTED primary building selected
#ifdef FIXIT_CSII // checked - ajw 9/28/98
#ifdef ENGLISH
"TANK01", // VOX_MADTANK_DEPLOYED M.A.D. Tank Deployed
#else
"none",
#endif
#else
"none",
#endif
"none", // VOX_SOVIET_CAPTURED Allied building captured
"UNITLST1", // VOX_UNIT_LOST unit lost
"SLCTTGT1", // VOX_SELECT_TARGET select target
"ENMYAPP1", // VOX_PREPARE enemy approaching
"SILOND1", // VOX_NEED_MO_CAPACITY silos needed
"ONHOLD1", // VOX_SUSPENDED on hold
"REPAIR1", // VOX_REPAIRING repairing
"none",
"none",
"AUNITL1", // VOX_AIRCRAFT_LOST airborne unit lost
"none",
"AAPPRO1", // VOX_ALLIED_FORCES_APPROACHING allied forces approaching
"AARRIVE1", // VOX_ALLIED_APPROACHING allied reinforcements have arrived
"none",
"none",
"BLDGINF1", // VOX_BUILDING_INFILTRATED building infiltrated
"CHROCHR1", // VOX_CHRONO_CHARGING chronosphere charging
"CHRORDY1", // VOX_CHRONO_READY chronosphere ready
"CHROYES1", // VOX_CHRONO_TEST chronosphere test successful
"CMDCNTR1", // VOX_HQ_UNDER_ATTACK command center under attack
"CNTLDED1", // VOX_CENTER_DEACTIVATED control center deactivated
"CONVYAP1", // VOX_CONVOY_APPROACHING convoy approaching
"CONVLST1", // VOX_CONVOY_UNIT_LOST convoy unit lost
"XPLOPLC1", // VOX_EXPLOSIVE_PLACED explosive charge placed
"CREDIT1", // VOX_MONEY_STOLEN credits stolen
"NAVYLST1", // VOX_SHIP_LOST naval unit lost
"SATLNCH1", // VOX_SATALITE_LAUNCHED satalite launched
"PULSE1", // VOX_SONAR_AVAILABLE sonar pulse available
"none",
"SOVFAPP1", // VOX_SOVIET_FORCES_APPROACHING soviet forces approaching
"SOVREIN1", // VOX_SOVIET_REINFROCEMENTS soviet reinforcements have arrived
"TRAIN1", // VOX_TRAINING training
"AREADY1", // VOX_ABOMB_READY
"ALAUNCH1", // VOX_ABOMB_LAUNCH
"AARRIVN1", // VOX_ALLIES_N
"AARRIVS1", // VOX_ALLIES_S
"AARIVE1", // VOX_ALLIES_E
"AARRIVW1", // VOX_ALLIES_W
"1OBJMET1", // VOX_OBJECTIVE1
"2OBJMET1", // VOX_OBJECTIVE2
"3OBJMET1", // VOX_OBJECTIVE3
"IRONCHG1", // VOX_IRON_CHARGING
"IRONRDY1", // VOX_IRON_READY
"KOSYRES1", // VOX_RESCUED
"OBJNMET1", // VOX_OBJECTIVE_NOT
"FLAREN1", // VOX_SIGNAL_N
"FLARES1", // VOX_SIGNAL_S
"FLAREE1", // VOX_SIGNAL_E
"FLAREW1", // VOX_SIGNAL_W
"SPYPLN1", // VOX_SPY_PLANE
"TANYAF1", // VOX_FREED
"ARMORUP1", // VOX_UPGRADE_ARMOR
"FIREPO1", // VOX_UPGRADE_FIREPOWER
"UNITSPD1", // VOX_UPGRADE_SPEED
"MTIMEIN1", // VOX_MISSION_TIMER
"UNITFUL1", // VOX_UNIT_FULL
"UNITREP1", // VOX_UNIT_REPAIRED
"40MINR", // VOX_TIME_40
"30MINR", // VOX_TIME_30
"20MINR", // VOX_TIME_20
"10MINR", // VOX_TIME_10
"5MINR", // VOX_TIME_5
"4MINR", // VOX_TIME_4
"3MINR", // VOX_TIME_3
"2MINR", // VOX_TIME_2
"1MINR", // VOX_TIME_1
"TIMERNO1", // VOX_TIME_STOP
"UNITSLD1", // VOX_UNIT_SOLD
"TIMERGO1", // VOX_TIMER_STARTED
"TARGRES1", // VOX_TARGET_RESCUED
"TARGFRE1", // VOX_TARGET_FREED
"TANYAR1", // VOX_TANYA_RESCUED
"STRUSLD1", // VOX_STRUCTURE_SOLD
"SOVFORC1", // VOX_SOVIET_FORCES_FALLEN
"SOVEMP1", // VOX_SOVIET_SELECTED
"SOVEFAL1", // VOX_SOVIET_EMPIRE_FALLEN
"OPTERM1", // VOX_OPERATION_TERMINATED
"OBJRCH1", // VOX_OBJECTIVE_REACHED
"OBJNRCH1", // VOX_OBJECTIVE_NOT_REACHED
"OBJMET1", // VOX_OBJECTIVE_MET
"MERCR1", // VOX_MERCENARY_RESCUED
"MERCF1", // VOX_MERCENARY_FREED
"KOSYFRE1", // VOX_KOSOYGEN_FREED
"FLARE1", // VOX_FLARE_DETECTED
"COMNDOR1", // VOX_COMMANDO_RESCUED
"COMNDOF1", // VOX_COMMANDO_FREED
"BLDGPRG1", // VOX_BUILDING_IN_PROGRESS
"ATPREP1", // VOX_ATOM_PREPPING
"ASELECT1", // VOX_ALLIED_SELECTED
"APREP1", // VOX_ABOMB_PREPPING
"ATLNCH1", // VOX_ATOM_LAUNCHED
"AFALLEN1", // VOX_ALLIED_FORCES_FALLEN
"AAVAIL1", // VOX_ABOMB_AVAILABLE
"AARRIVE1", // VOX_ALLIED_REINFORCEMENTS
"SAVE1", // VOX_MISSION_SAVED
"LOAD1" // VOX_MISSION_LOADED
};
static VoxType CurrentVoice = VOX_NONE;
/***********************************************************************************************
* Speech_Name -- Fetches the name for the voice specified. *
* *
* Use this routine to fetch the ASCII name of the speech id specified. Typical use of this *
* would be to build a displayable list of the speech types. The trigger system uses this *
* so that a speech type can be selected. *
* *
* INPUT: speech -- The speech type id to convert to ASCII string. *
* *
* OUTPUT: Returns with a pointer to the speech ASCII representation of the speech id type. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/01/1996 JLB : Created. *
*=============================================================================================*/
char const * Speech_Name(VoxType speech)
{
if (speech == VOX_NONE) return("none");
return(Speech[speech]);
}
/***********************************************************************************************
* Speak -- Computer speaks to the player. *
* *
* This routine is used to have the game computer (EVA) speak to the player. *
* *
* INPUT: voice -- The voice number to speak (see defines.h). *
* *
* OUTPUT: Returns with the handle of the playing speech (-1 if no voice started). *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/12/1994 JLB : Created. *
*=============================================================================================*/
void Speak(VoxType voice)
{
if (!Debug_Quiet && Options.Volume != 0 && SampleType != 0 && voice != VOX_NONE && voice != SpeakQueue && voice != CurrentVoice && SpeakQueue == VOX_NONE) {
SpeakQueue = voice;
Speak_AI();
}
}
/***********************************************************************************************
* Speak_AI -- Handles starting the EVA voices. *
* *
* This starts the EVA voice talking as well. If there is any speech request in the queue, *
* it will be started when the current voice is finished. Call this routine as often as *
* possible (once per game tick is sufficient). *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/27/1994 JLB : Created. *
* 10/11/1996 JLB : Handles multiple speech buffers. *
*=============================================================================================*/
void Speak_AI(void)
{
static int _index = 0;
if (Debug_Quiet || SampleType == 0) return;
if (!Is_Sample_Playing(SpeechBuffer[_index])) {
CurrentVoice = VOX_NONE;
if (SpeakQueue != VOX_NONE) {
/*
** Try to find a previously loaded copy of the EVA speech in one of the
** speech buffers.
*/
void const * speech = NULL;
for (int index = 0; index < ARRAY_SIZE(SpeechRecord); index++) {
if (SpeechRecord[index] == SpeakQueue) break;
}
/*
** If a previous copy could not be located, then load the requested
** voice into the oldest buffer available.
*/
if (speech == NULL) {
_index = (_index + 1) % ARRAY_SIZE(SpeechRecord);
char name[_MAX_FNAME+_MAX_EXT];
_makepath(name, NULL, NULL, Speech[SpeakQueue], ".AUD");
CCFileClass file(name);
if (file.Is_Available() && file.Read(SpeechBuffer[_index], SPEECH_BUFFER_SIZE)) {
speech = SpeechBuffer[_index];
SpeechRecord[_index] = SpeakQueue;
}
}
/*
** Since the speech file was loaded, play it.
*/
if (speech != NULL) {
Play_Sample(speech, 254, Options.Volume * 256);
CurrentVoice = SpeakQueue;
}
SpeakQueue = VOX_NONE;
}
}
}
/***********************************************************************************************
* Stop_Speaking -- Forces the EVA voice to stop talking. *
* *
* Use this routine to immediately stop the EVA voice from speaking. It also clears out *
* the pending voice queue. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/27/1994 JLB : Created. *
*=============================================================================================*/
void Stop_Speaking(void)
{
SpeakQueue = VOX_NONE;
Stop_Sample_Playing(SpeechBuffer);
}
/***********************************************************************************************
* Is_Speaking -- Checks to see if the eva voice is still playing. *
* *
* Call this routine when the EVA voice being played needs to be checked. A typical use *
* of this would be when some action needs to be delayed until the voice has finished -- *
* say the end of the game. *
* *
* INPUT: none *
* *
* OUTPUT: bool; Is the EVA voice still playing? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 03/12/1995 JLB : Created. *
*=============================================================================================*/
bool Is_Speaking(void)
{
Speak_AI();
if (!Debug_Quiet && SampleType != 0 && (SpeakQueue != VOX_NONE || Is_Sample_Playing(SpeechBuffer))) {
return(true);
}
return(false);
}

656
CODE/AUDIO.CPP.BAK Normal file
View file

@ -0,0 +1,656 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: F:\projects\c&c0\vcs\code\audio.cpv 4.78 03 Oct 1996 09:20:46 JOE_BOSTIC $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : AUDIO.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : September 10, 1993 *
* *
* Last Update : September 15, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* Is_Speaking -- Checks to see if the eva voice is still playing. *
* Sound_Effect -- General purpose sound player. *
* Sound_Effect -- Plays a sound effect in the tactical map. *
* Speak -- Computer speaks to the player. *
* Speak_AI -- Handles starting the EVA voices. *
* Speech_Name -- Fetches the name for the voice specified. *
* Stop_Speaking -- Forces the EVA voice to stop talking. *
* Voc_From_Name -- Fetch VocType from ASCII name specified. *
* Voc_Name -- Fetches the name for the sound effect. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
/***************************************************************************
** Controls what special effects may occur on the sound effect.
*/
typedef enum {
IN_NOVAR, // No variation or alterations allowed.
IN_VAR // Infantry variance response modification.
} ContextType;
static struct {
char const * Name; // Digitized voice file name.
int Priority; // Playback priority of this sample.
ContextType Where; // In what game context does this sample exist.
} SoundEffectName[VOC_COUNT] = {
/*
** Civilian voices (technicians too).
*/
{"GIRLOKAY", 20, IN_NOVAR}, // VOC_GIRL_OKAY
{"GIRLYEAH", 20, IN_NOVAR}, // VOC_GIRL_YEAH
{"GUYOKAY1", 20, IN_NOVAR}, // VOC_GUY_OKAY
{"GUYYEAH1", 20, IN_NOVAR}, // VOC_GUY_YEAH
{"MINELAY1", 5, IN_VAR}, // VOC_MINELAY1
/*
** Infantry and vehicle responses.
*/
{"ACKNO", 20, IN_VAR}, // VOC_ACKNOWL "acknowledged"
{"AFFIRM1", 20, IN_VAR}, // VOC_AFFIRM "affirmative"
{"AWAIT1", 20, IN_VAR}, // VOC_AWAIT1 "awaiting orders"
{"EAFFIRM1", 20, IN_NOVAR}, // VOC_ENG_AFFIRM Engineer: "affirmative"
{"EENGIN1", 20, IN_VAR}, // VOC_ENG_ENG Engineer: "engineering"
{"NOPROB", 20, IN_VAR}, // VOC_NO_PROB "not a problem"
{"READY", 20, IN_VAR}, // VOC_READY "ready and waiting"
{"REPORT1", 20, IN_VAR}, // VOC_REPORT "reporting"
{"RITAWAY", 20, IN_VAR}, // VOC_RIGHT_AWAY "right away sir"
{"ROGER", 20, IN_VAR}, // VOC_ROGER "roger"
{"UGOTIT", 20, IN_VAR}, // VOC_UGOTIT "you got it"
{"VEHIC1", 20, IN_VAR}, // VOC_VEHIC1 "vehicle reporting"
{"YESSIR1", 20, IN_VAR}, // VOC_YESSIR "yes sir"
{"DEDMAN1", 10, IN_NOVAR}, // VOC_SCREAM1 short infantry scream
{"DEDMAN2", 10, IN_NOVAR}, // VOC_SCREAM3 short infantry scream
{"DEDMAN3", 10, IN_NOVAR}, // VOC_SCREAM4 short infantry scream
{"DEDMAN4", 10, IN_NOVAR}, // VOC_SCREAM5 short infantry scream
{"DEDMAN5", 10, IN_NOVAR}, // VOC_SCREAM6 short infantry scream
{"DEDMAN6", 10, IN_NOVAR}, // VOC_SCREAM7 short infantry scream
{"DEDMAN7", 10, IN_NOVAR}, // VOC_SCREAM10 short infantry scream
{"DEDMAN8", 10, IN_NOVAR}, // VOC_SCREAM11 short infantry scream
{"DEDMAN10", 10, IN_NOVAR}, // VOC_YELL1 long infantry scream
{"CHRONO2", 5, IN_NOVAR}, // VOC_CHRONO Chronosphere sound
{"CANNON1", 1, IN_NOVAR}, // VOC_CANNON1 Cannon sound (medium).
{"CANNON2", 1, IN_NOVAR}, // VOC_CANNON2 Cannon sound (short).
{"IRONCUR1", 5, IN_NOVAR}, // VOC_IRON1
{"EMOVOUT1", 20, IN_NOVAR}, // VOC_ENG_MOVEOUT Engineer: "movin' out"
{"IRONCUR2", 5, IN_NOVAR}, // VOC_IRON2
{"x", 1, IN_NOVAR},
{"x", 1, IN_NOVAR},
{"CHUTE1", 1, IN_NOVAR}, // VOC_CHUTE1 Wind swoosh sound.
{"DOGY1", 5, IN_NOVAR}, // VOC_DOG_BARK Dog bark.
{"DOGW5", 10, IN_NOVAR}, // VOC_DOG_WHINE Dog whine.
{"DOGG5P", 10, IN_NOVAR}, // VOC_DOG_GROWL2 Strong dog growl.
{"FIREBL3", 1, IN_NOVAR}, // VOC_FIRE_LAUNCH Fireball launch sound.
{"FIRETRT1", 1, IN_NOVAR}, // VOC_FIRE_EXPLODE Fireball explode sound.
{"GRENADE1", 1, IN_NOVAR}, // VOC_GRENADE_TOSS Grenade toss.
{"GUN11", 1, IN_NOVAR}, // VOC_GUN_5 5 round gun burst (slow).
{"GUN13", 1, IN_NOVAR}, // VOC_GUN_7 7 round gun burst (fast).
{"EYESSIR1", 20, IN_NOVAR}, // VOC_ENG_YES, Engineer: "yes sir"
{"GUN27", 1, IN_NOVAR}, // VOC_GUN_RIFLE Rifle shot.
{"HEAL2", 1, IN_NOVAR}, // VOC_HEAL Healing effect.
{"HYDROD1", 1, IN_NOVAR}, // VOC_DOOR Hyrdrolic door.
{"INVUL2", 1, IN_NOVAR}, // VOC_INVULNERABLE Invulnerability effect.
{"KABOOM1", 1, IN_NOVAR}, // VOC_KABOOM1 Long explosion (muffled).
{"KABOOM12", 1, IN_NOVAR}, // VOC_KABOOM12 Very long explosion (muffled).
{"KABOOM15", 1, IN_NOVAR}, // VOC_KABOOM15 Very long explosion (muffled).
{"x", 1, IN_NOVAR},
{"KABOOM22", 1, IN_NOVAR}, // VOC_KABOOM22 Long explosion (sharp).
{"x", 1, IN_NOVAR},
{"x", 1, IN_NOVAR},
{"MGUNINF1", 1, IN_NOVAR}, // VOC_GUN_5F 5 round gun burst (fast).
{"MISSILE1", 1, IN_NOVAR}, // VOC_MISSILE_1 Missile with high tech effect.
{"MISSILE6", 1, IN_NOVAR}, // VOC_MISSILE_2 Long missile launch.
{"MISSILE7", 1, IN_NOVAR}, // VOC_MISSILE_3 Short missile launch.
{"x", 1, IN_NOVAR},
{"PILLBOX1", 1, IN_NOVAR}, // VOC_GUN_5R 5 round gun burst (rattles).
{"RABEEP1", 1, IN_NOVAR}, // VOC_BEEP Generic beep sound.
{"RAMENU1", 1, IN_NOVAR}, // VOC_CLICK Generic click sound.
{"SILENCER", 1, IN_NOVAR}, // VOC_SILENCER Silencer.
{"TANK5", 1, IN_NOVAR}, // VOC_CANNON6 Long muffled cannon shot.
{"TANK6", 1, IN_NOVAR}, // VOC_CANNON7 Sharp mechanical cannon fire.
{"TORPEDO1", 1, IN_NOVAR}, // VOC_TORPEDO Torpedo launch.
{"TURRET1", 1, IN_NOVAR}, // VOC_CANNON8 Sharp cannon fire.
{"TSLACHG2", 10, IN_NOVAR}, // VOC_TESLA_POWER_UP Hum charge up.
{"TESLA1", 10, IN_NOVAR}, // VOC_TESLA_ZAP Tesla zap effect.
{"SQUISHY2", 10, IN_NOVAR}, // VOC_SQUISH Squish effect.
{"SCOLDY1", 10, IN_NOVAR}, // VOC_SCOLD Scold bleep.
{"RADARON2", 20, IN_NOVAR}, // VOC_RADAR_ON Powering up electronics.
{"RADARDN1", 10, IN_NOVAR}, // VOC_RADAR_OFF B movie power down effect.
{"PLACBLDG", 10, IN_NOVAR}, // VOC_PLACE_BUILDING_DOWN Building slam down sound.
{"KABOOM30", 1, IN_NOVAR}, // VOC_KABOOM30 Short explosion (HE).
{"KABOOM25", 10, IN_NOVAR}, // VOC_KABOOM25 Short growling explosion.
{"x", 10, IN_NOVAR},
{"DOGW7", 10, IN_NOVAR}, // VOC_DOG_HURT Dog whine (loud).
{"DOGW3PX", 10, IN_NOVAR}, // VOC_DOG_YES Dog 'yes sir'.
{"CRMBLE2", 10, IN_NOVAR}, // VOC_CRUMBLE Building crumble.
{"CASHUP1", 10, IN_NOVAR}, // VOC_MONEY_UP Rising money tick.
{"CASHDN1", 10, IN_NOVAR}, // VOC_MONEY_DOWN Falling money tick.
{"BUILD5", 10, IN_NOVAR}, // VOC_CONSTRUCTION Building construction sound.
{"BLEEP9", 10, IN_NOVAR}, // VOC_GAME_CLOSED Long bleep.
{"BLEEP6", 10, IN_NOVAR}, // VOC_INCOMING_MESSAGE Soft happy warble.
{"BLEEP5", 10, IN_NOVAR}, // VOC_SYS_ERROR Sharp soft warble.
{"BLEEP17", 10, IN_NOVAR}, // VOC_OPTIONS_CHANGED Mid range soft warble.
{"BLEEP13", 10, IN_NOVAR}, // VOC_GAME_FORMING Long warble.
{"BLEEP12", 10, IN_NOVAR}, // VOC_PLAYER_LEFT Chirp sequence.
{"BLEEP11", 10, IN_NOVAR}, // VOC_PLAYER_JOINED Reverse chirp sequence.
{"H2OBOMB2", 10, IN_NOVAR}, // VOC_DEPTH_CHARGE Distant explosion sound.
{"CASHTURN", 10, IN_NOVAR}, // VOC_CASHTURN Airbrake.
{"TUFFGUY1", 20, IN_NOVAR}, // VOC_TANYA_CHEW Tanya: "Chew on this"
{"ROKROLL1", 20, IN_NOVAR}, // VOC_TANYA_ROCK Tanya: "Let's rock"
{"LAUGH1", 20, IN_NOVAR}, // VOC_TANYA_LAUGH Tanya: "ha ha ha"
{"CMON1", 20, IN_NOVAR}, // VOC_TANYA_SHAKE Tanya: "Shake it baby"
{"BOMBIT1", 20, IN_NOVAR}, // VOC_TANYA_CHING Tanya: "Cha Ching"
{"GOTIT1", 20, IN_NOVAR}, // VOC_TANYA_GOT Tanya: "That's all you got"
{"KEEPEM1", 20, IN_NOVAR}, // VOC_TANYA_KISS Tanya: "Kiss it bye bye"
{"ONIT1", 20, IN_NOVAR}, // VOC_TANYA_THERE Tanya: "I'm there"
{"LEFTY1", 20, IN_NOVAR}, // VOC_TANYA_GIVE Tanya: "Give it to me"
{"YEAH1", 20, IN_NOVAR}, // VOC_TANYA_YEA Tanya: "Yea?"
{"YES1", 20, IN_NOVAR}, // VOC_TANYA_YES Tanya: "Yes sir?"
{"YO1", 20, IN_NOVAR}, // VOC_TANYA_WHATS Tanya: "What's up."
{"WALLKIL2", 5, IN_NOVAR}, // VOC_WALLKILL2 Crushing wall sound.
{"x", 10, IN_NOVAR},
{"GUN5", 5, IN_NOVAR}, // VOC_TRIPLE_SHOT Three quick shots in succession.
{"SUBSHOW1", 5, IN_NOVAR}, // VOC_SUBSHOW Submarine surface sound.
{"EINAH1", 20, IN_NOVAR}, // VOC_E_AH, Einstien "ah"
{"EINOK1", 20, IN_NOVAR}, // VOC_E_OK, Einstien "ok"
{"EINYES1", 20, IN_NOVAR}, // VOC_E_YES, Einstien "yes"
{"MINE1", 10, IN_NOVAR}, // VOC_TRIP_MINE mine explosion sound
{"SCOMND1", 20, IN_NOVAR}, // VOC_SPY_COMMANDER Spy: "commander?"
{"SYESSIR1", 20, IN_NOVAR}, // VOC_SPY_YESSIR Spy: "yes sir"
{"SINDEED1", 20, IN_NOVAR}, // VOC_SPY_INDEED Spy: "indeed"
{"SONWAY1", 20, IN_NOVAR}, // VOC_SPY_ONWAY Spy: "on my way"
{"SKING1", 20, IN_NOVAR}, // VOC_SPY_KING Spy: "for king and country"
{"MRESPON1", 20, IN_NOVAR}, // VOC_MED_REPORTING Medic: "reporting"
{"MYESSIR1", 20, IN_NOVAR}, // VOC_MED_YESSIR Medic: "yes sir"
{"MAFFIRM1", 20, IN_NOVAR}, // VOC_MED_AFFIRM Medic: "affirmative"
{"MMOVOUT1", 20, IN_NOVAR}, // VOC_MED_MOVEOUT Medic: "movin' out"
{"BEEPSLCT", 10, IN_NOVAR}, // VOC_BEEP_SELECT map selection beep
{"SYEAH1", 20, IN_NOVAR}, // VOC_THIEF_YEA Thief: "yea?"
{"x", 20, IN_NOVAR},
{"x", 20, IN_NOVAR},
{"SMOUT1", 20, IN_NOVAR}, // VOC_THIEF_MOVEOUT Thief: "movin' out"
{"SOKAY1", 20, IN_NOVAR}, // VOC_THIEF_OKAY Thief: "ok"
{"x", 20, IN_NOVAR},
{"SWHAT1", 20, IN_NOVAR}, // VOC_THIEF_WHAT Thief: "what"
{"SAFFIRM1", 20, IN_NOVAR}, // VOC_THIEF_AFFIRM Thief: "affirmative"
};
/***********************************************************************************************
* Voc_From_Name -- Fetch VocType from ASCII name specified. *
* *
* This will find the corresponding VocType from the ASCII string specified. It does this *
* by finding a root filename that matches the string. *
* *
* INPUT: name -- Pointer to the ASCII string that will be converted into a VocType. *
* *
* OUTPUT: Returns with the VocType that matches the string specified. If no match could be *
* found, then VOC_NONE is returned. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/06/1996 JLB : Created. *
*=============================================================================================*/
VocType Voc_From_Name(char const * name)
{
#ifdef 0
if (name == NULL) return(VOC_NONE);
for (VocType voc = VOC_FIRST; voc < VOC_COUNT; voc++) {
if (stricmp(name, SoundEffectName[voc].Name) == 0) {
return(voc);
}
}
#endif
return(VOC_NONE);
}
/***********************************************************************************************
* Voc_Name -- Fetches the name for the sound effect. *
* *
* This routine returns the descriptive name of the sound effect. Currently, this is just *
* the root of the file name. *
* *
* INPUT: voc -- The VocType that the corresponding name is requested. *
* *
* OUTPUT: Returns with a pointer to the text string the represents the sound effect. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/06/1996 JLB : Created. *
*=============================================================================================*/
char const * Voc_Name(VocType voc)
{
if (voc == VOC_NONE) return("none");
return(SoundEffectName[voc].Name);
}
/***********************************************************************************************
* Sound_Effect -- Plays a sound effect in the tactical map. *
* *
* This routine is used when a sound effect occurs in the game world. It handles fading *
* the sound according to distance. *
* *
* INPUT: voc -- The sound effect number to play. *
* *
* coord -- The world location that the sound originates from. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/12/1994 JLB : Created. *
* 01/05/1995 JLB : Reduces sound more dramatically when off screen. *
* 09/15/1996 JLB : Revamped volume logic. *
*=============================================================================================*/
void Sound_Effect(VocType voc, COORDINATE coord, int variation)
{
#ifdef 0
CELL cell_pos = 0;
int pan_value;
if (Debug_Quiet || Options.Volume == 0 || voc == VOC_NONE || !SoundOn || SampleType == SAMPLE_NONE) {
return;
}
if (coord) {
cell_pos = Coord_Cell(coord);
}
fixed volume = 1;
pan_value = 0;
if (coord && !Map.In_View(cell_pos)) {
int distance = Distance(coord, Map.TacticalCoord) / CELL_LEPTON_W;
fixed dfixed = fixed(distance, 128+64);
dfixed.Sub_Saturate(1);
volume = fixed(1) - dfixed;
pan_value = Cell_X(cell_pos);
pan_value -= Coord_XCell(Map.TacticalCoord) + (Lepton_To_Cell(Map.TacLeptonWidth) / 2);
if (ABS(pan_value) > Lepton_To_Cell(Map.TacLeptonWidth / 2)) {
pan_value *= 0x8000;
pan_value /= (MAP_CELL_W >> 2);
pan_value = Bound(pan_value, -0x7FFF, 0x7FFF);
} else {
pan_value = 0;
}
}
Sound_Effect(voc, volume, variation, pan_value);
#endif
}
/***********************************************************************************************
* Sound_Effect -- General purpose sound player. *
* *
* This is used for general purpose sound effects. These are sounds that occur outside *
* of the game world. They do not have a corresponding game world location as their source. *
* *
* INPUT: voc -- The sound effect number to play. *
* *
* volume -- The volume to assign to this sound effect. *
* *
* OUTPUT: Returns with the sound handle (-1 if no sound was played). *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/12/1994 JLB : Created. *
* 11/12/1994 JLB : Handles cache logic. *
* 05/04/1995 JLB : Variation adjustments. *
*=============================================================================================*/
int Sound_Effect(VocType voc, fixed volume, int variation, signed short pan_value)
{
#ifdef 0
char name[_MAX_FNAME+_MAX_EXT]; // Working filename of sound effect.
if (Debug_Quiet || Options.Volume == 0 || voc == VOC_NONE || !SoundOn || SampleType == SAMPLE_NONE) {
return(-1);
}
/*
** Alter the volume according to the game volume setting.
*/
volume = volume * Options.Volume;
/*
** Fetch a pointer to the sound effect data. Modify the sound as appropriate and desired.
*/
char const * ext = ".AUD";
if (SoundEffectName[voc].Where == IN_VAR) {
/*
** For infantry, use a variation on the response. For vehicles, always
** use the vehicle response table.
*/
if (variation < 0) {
if (ABS(variation) % 2) {
ext = ".V00";
} else {
ext = ".V02";
}
} else {
if (variation % 2) {
ext = ".V01";
} else {
ext = ".V03";
}
}
}
_makepath(name, NULL, NULL, SoundEffectName[voc].Name, ext);
void const * ptr = MFCD::Retrieve(name);
/*
** If the sound data pointer is not null, then presume that it is valid.
*/
if (ptr != NULL) {
volume.Sub_Saturate(1);
return(Play_Sample(ptr, SoundEffectName[voc].Priority * volume, volume*256, pan_value));
// } else {
// Mono_Printf("Cannot find '%s'.\n", name);
}
#endif
return(-1);
}
/*
** This elaborates all the EVA speech voices.
*/
static char const * Speech[VOX_COUNT] = {
"MISNWON1", // VOX_ACCOMPLISHED mission accomplished
"MISNLST1", // VOX_FAIL your mission has failed
"PROGRES1", // VOX_NO_FACTORY unable to comply, building in progress
"CONSCMP1", // VOX_CONSTRUCTION construction complete
"UNITRDY1", // VOX_UNIT_READY unit ready
"NEWOPT1", // VOX_NEW_CONSTRUCT new construction options
"NODEPLY1", // VOX_DEPLOY cannot deploy here
"STRCKIL1", // VOX_STRUCTURE_DESTROYED, structure destroyed
"NOPOWR1", // VOX_INSUFFICIENT_POWER, insufficient power
"NOFUNDS1", // VOX_NO_CASH insufficient funds
"BCT1", // VOX_CONTROL_EXIT battle control terminated
"REINFOR1", // VOX_REINFORCEMENTS reinforcements have arrived
"CANCLD1", // VOX_CANCELED canceled
"ABLDGIN1", // VOX_BUILDING building
"LOPOWER1", // VOX_LOW_POWER low power
"NOFUNDS1", // VOX_NEED_MO_MONEY insufficent funds
"BASEATK1", // VOX_BASE_UNDER_ATTACK our base is under attack
"NOBUILD1", // VOX_UNABLE_TO_BUILD unable to build more
"PRIBLDG1", // VOX_PRIMARY_SELECTED primary building selected
"none",
"none", // VOX_SOVIET_CAPTURED Allied building captured
"UNITLST1", // VOX_UNIT_LOST unit lost
"SLCTTGT1", // VOX_SELECT_TARGET select target
"ENMYAPP1", // VOX_PREPARE enemy approaching
"SILOND1", // VOX_NEED_MO_CAPACITY silos needed
"ONHOLD1", // VOX_SUSPENDED on hold
"REPAIR1", // VOX_REPAIRING repairing
"none",
"none",
"AUNITL1", // VOX_AIRCRAFT_LOST airborne unit lost
"none",
"AAPPRO1", // VOX_ALLIED_FORCES_APPROACHING allied forces approaching
"AARRIVE1", // VOX_ALLIED_APPROACHING allied reinforcements have arrived
"none",
"none",
"BLDGINF1", // VOX_BUILDING_INFILTRATED building infiltrated
"CHROCHR1", // VOX_CHRONO_CHARGING chronosphere charging
"CHRORDY1", // VOX_CHRONO_READY chronosphere ready
"CHROYES1", // VOX_CHRONO_TEST chronosphere test successful
"CMDCNTR1", // VOX_HQ_UNDER_ATTACK command center under attack
"CNTLDED1", // VOX_CENTER_DEACTIVATED control center deactivated
"CONVYAP1", // VOX_CONVOY_APPROACHING convoy approaching
"CONVLST1", // VOX_CONVOY_UNIT_LOST convoy unit lost
"XPLOPLC1", // VOX_EXPLOSIVE_PLACED explosive charge placed
"CREDIT1", // VOX_MONEY_STOLEN credits stolen
"NAVYLST1", // VOX_SHIP_LOST naval unit lost
"SATLNCH1", // VOX_SATALITE_LAUNCHED satalite launched
"PULSE1", // VOX_SONAR_AVAILABLE sonar pulse available
"none",
"SOVFAPP1", // VOX_SOVIET_FORCES_APPROACHING soviet forces approaching
"SOVREIN1", // VOX_SOVIET_REINFROCEMENTS soviet reinforcements have arrived
"TRAIN1", // VOX_TRAINING training
"AREADY1", // VOX_ABOMB_READY
"ALAUNCH1", // VOX_ABOMB_LAUNCH
"AARRIVN1", // VOX_ALLIES_N
"AARRIVS1", // VOX_ALLIES_S
"AARIVE1", // VOX_ALLIES_E
"AARRIVW1", // VOX_ALLIES_W
"1OBJMET1", // VOX_OBJECTIVE1
"2OBJMET1", // VOX_OBJECTIVE2
"3OBJMET1", // VOX_OBJECTIVE3
"IRONCHG1", // VOX_IRON_CHARGING
"IRONRDY1", // VOX_IRON_READY
"KOSYRES1", // VOX_RESCUED
"OBJNMET1", // VOX_OBJECTIVE_NOT
"FLAREN1", // VOX_SIGNAL_N
"FLARES1", // VOX_SIGNAL_S
"FLAREE1", // VOX_SIGNAL_E
"FLAREW1", // VOX_SIGNAL_W
"SPYPLN1", // VOX_SPY_PLANE
"TANYAF1", // VOX_FREED
"ARMORUP1", // VOX_UPGRADE_ARMOR
"FIREPO1", // VOX_UPGRADE_FIREPOWER
"UNITSPD1", // VOX_UPGRADE_SPEED
"MTIMEIN1", // VOX_MISSION_TIMER
"UNITFUL1", // VOX_UNIT_FULL
"UNITREP1", // VOX_UNIT_REPAIRED
"40MINR", // VOX_TIME_40
"30MINR", // VOX_TIME_30
"20MINR", // VOX_TIME_20
"10MINR", // VOX_TIME_10
"5MINR", // VOX_TIME_5
"4MINR", // VOX_TIME_4
"3MINR", // VOX_TIME_3
"2MINR", // VOX_TIME_2
"1MINR", // VOX_TIME_1
"TIMERNO1", // VOX_TIME_STOP
"UNITSLD1", // VOX_UNIT_SOLD
"TIMERGO1", // VOX_TIMER_STARTED
"TARGRES1", // VOX_TARGET_RESCUED
"TARGFRE1", // VOX_TARGET_FREED
"TANYAR1", // VOX_TANYA_RESCUED
"STRUSLD1", // VOX_STRUCTURE_SOLD
"SOVFORC1", // VOX_SOVIET_FORCES_FALLEN
"SOVEMP1", // VOX_SOVIET_SELECTED
"SOVEFAL1", // VOX_SOVIET_EMPIRE_FALLEN
"OPTERM1", // VOX_OPERATION_TERMINATED
"OBJRCH1", // VOX_OBJECTIVE_REACHED
"OBJNRCH1", // VOX_OBJECTIVE_NOT_REACHED
"OBJMET1", // VOX_OBJECTIVE_MET
"MERCR1", // VOX_MERCENARY_RESCUED
"MERCF1", // VOX_MERCENARY_FREED
"KOSYFRE1", // VOX_KOSOYGEN_FREED
"FLARE1", // VOX_FLARE_DETECTED
"COMNDOR1", // VOX_COMMANDO_RESCUED
"COMNDOF1", // VOX_COMMANDO_FREED
"BLDGPRG1", // VOX_BUILDING_IN_PROGRESS
"ATPREP1", // VOX_ATOM_PREPPING
"ASELECT1", // VOX_ALLIED_SELECTED
"APREP1", // VOX_ABOMB_PREPPING
"ATLNCH1", // VOX_ATOM_LAUNCHED
"AFALLEN1", // VOX_ALLIED_FORCES_FALLEN
"AAVAIL1", // VOX_ABOMB_AVAILABLE
"AARRIVE1", // VOX_ALLIED_REINFORCEMENTS
"SAVE1", // VOX_MISSION_SAVED
"LOAD1" // VOX_MISSION_LOADED
};
static VoxType CurrentVoice = VOX_NONE;
/***********************************************************************************************
* Speech_Name -- Fetches the name for the voice specified. *
* *
* Use this routine to fetch the ASCII name of the speech id specified. Typical use of this *
* would be to build a displayable list of the speech types. The trigger system uses this *
* so that a speech type can be selected. *
* *
* INPUT: speech -- The speech type id to convert to ASCII string. *
* *
* OUTPUT: Returns with a pointer to the speech ASCII representation of the speech id type. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/01/1996 JLB : Created. *
*=============================================================================================*/
char const * Speech_Name(VoxType speech)
{
if (speech == VOX_NONE) return("none");
return(Speech[speech]);
}
/***********************************************************************************************
* Speak -- Computer speaks to the player. *
* *
* This routine is used to have the game computer (EVA) speak to the player. *
* *
* INPUT: voice -- The voice number to speak (see defines.h). *
* *
* OUTPUT: Returns with the handle of the playing speech (-1 if no voice started). *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/12/1994 JLB : Created. *
*=============================================================================================*/
void Speak(VoxType voice)
{
if (!Debug_Quiet && Options.Volume != 0 && SampleType != 0 && voice != VOX_NONE && voice != SpeakQueue && voice != CurrentVoice && SpeakQueue == VOX_NONE) {
SpeakQueue = voice;
Speak_AI();
}
}
/***********************************************************************************************
* Speak_AI -- Handles starting the EVA voices. *
* *
* This starts the EVA voice talking as well. If there is any speech request in the queue, *
* it will be started when the current voice is finished. Call this routine as often as *
* possible (once per game tick is sufficient). *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/27/1994 JLB : Created. *
*=============================================================================================*/
void Speak_AI(void)
{
static VoxType _last = VOX_NONE;
if (Debug_Quiet || SampleType == 0) return;
if (!Is_Sample_Playing(SpeechBuffer)) {
CurrentVoice = VOX_NONE;
if (SpeakQueue != VOX_NONE) {
if (SpeakQueue != _last) {
char name[_MAX_FNAME+_MAX_EXT];
_makepath(name, NULL, NULL, Speech[SpeakQueue], ".AUD");
CCFileClass file(name);
if (file.Is_Available() && file.Read(SpeechBuffer, SPEECH_BUFFER_SIZE)) {
Play_Sample(SpeechBuffer, 254, Options.Volume * 256);
CurrentVoice = SpeakQueue;
}
_last = SpeakQueue;
} else {
Play_Sample(SpeechBuffer, 254, Options.Volume * 256);
}
SpeakQueue = VOX_NONE;
}
}
}
/***********************************************************************************************
* Stop_Speaking -- Forces the EVA voice to stop talking. *
* *
* Use this routine to immediately stop the EVA voice from speaking. It also clears out *
* the pending voice queue. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/27/1994 JLB : Created. *
*=============================================================================================*/
void Stop_Speaking(void)
{
SpeakQueue = VOX_NONE;
Stop_Sample_Playing(SpeechBuffer);
}
/***********************************************************************************************
* Is_Speaking -- Checks to see if the eva voice is still playing. *
* *
* Call this routine when the EVA voice being played needs to be checked. A typical use *
* of this would be when some action needs to be delayed until the voice has finished -- *
* say the end of the game. *
* *
* INPUT: none *
* *
* OUTPUT: bool; Is the EVA voice still playing? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 03/12/1995 JLB : Created. *
*=============================================================================================*/
bool Is_Speaking(void)
{
Speak_AI();
if (!Debug_Quiet && SampleType != 0 && (SpeakQueue != VOX_NONE || Is_Sample_Playing(SpeechBuffer))) {
return(true);
}
return(false);
}

99
CODE/AUDIO.H Normal file
View file

@ -0,0 +1,99 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: F:\projects\c&c0\vcs\code\audio.h_v 4.43 05 Jul 1996 17:58:10 JOE_BOSTIC $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : AUDIO.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : June 21, 1994 *
* *
* Last Update : June 21, 1994 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef AUDIO_H
#define AUDIO_H
#include "memory.h"
class AudioClass {
char const * Name; // Name of audio asset.
void const * Data; // Loaded audio data.
int Handle; // Handle of asset (as it is playing).
MemoryClass *Mem; // Pointer to memory handler class.
unsigned IsMIDI:1; // Is this a midi file?
public:
AudioClass(void);
AudioClass(char const *name, MemoryClass &mem);
virtual ~AudioClass(void);
bool Load(char const *name = 0);
bool Free(void);
bool Play(int volume = 0xFF);
bool Stop(void);
bool Pause(void);
bool Resume(void);
bool Set_Name(char const *name);
bool Is_Playing(void) const;
bool Is_Loaded(void) const;
bool Is_MIDI(void) const;
};
inline AudioClass::AudioClass(void)
{
Name = 0;
Data = 0;
Mem = 0;
Handle = -1;
};
inline AudioClass::AudioClass(char const *name, MemoryClass &mem)
{
if (mem) {
Mem = &mem;
} else {
Mem = &::Mem; // Uses global default memory handler.
}
Name = strdup(name);
Data = 0;
Handle = -1;
};
inline AudioClass::~AudioClass(void)
{
if (GameActive) {
if (Name) free(Name);
if (Data) Mem->Free(Data);
Name = 0;
Data = 0;
Handle = -1;
}
};
#endif

165
CODE/B64PIPE.CPP Normal file
View file

@ -0,0 +1,165 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/B64PIPE.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : B64PIPE.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 06/30/96 *
* *
* Last Update : July 3, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* Base64Pipe::Put -- Processes a block of data through the pipe. *
* Base64Pipe::Flush -- Flushes the final pending data through the pipe. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "b64pipe.h"
#include "base64.h"
#include <string.h>
/***********************************************************************************************
* Base64Pipe::Put -- Processes a block of data through the pipe. *
* *
* This will take the data submitted and either Base64 encode or decode it (as specified *
* in the pipe's constructor). The nature of Base64 encoding means that the data will *
* grow 30% in size when encoding and decrease by a like amount when decoding. *
* *
* INPUT: source -- Pointer to the data to be translated. *
* *
* length -- The number of bytes to translate. *
* *
* OUTPUT: Returns with the actual number of bytes output at the far distant final end of *
* the pipe chain. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/03/1996 JLB : Created. *
*=============================================================================================*/
int Base64Pipe::Put(void const * source, int slen)
{
if (source == NULL || slen < 1) {
return(Pipe::Put(source, slen));
}
int total = 0;
char * from;
int fromsize;
char * to;
int tosize;
if (Control == ENCODE) {
from = PBuffer;
fromsize = sizeof(PBuffer);
to = CBuffer;
tosize = sizeof(CBuffer);
} else {
from = CBuffer;
fromsize = sizeof(CBuffer);
to = PBuffer;
tosize = sizeof(PBuffer);
}
if (Counter > 0) {
int len = (slen < (fromsize-Counter)) ? slen : (fromsize-Counter);
memmove(&from[Counter], source, len);
Counter += len;
slen -= len;
source = ((char *)source) + len;
if (Counter == fromsize) {
int outcount;
if (Control == ENCODE) {
outcount = Base64_Encode(from, fromsize, to, tosize);
} else {
outcount = Base64_Decode(from, fromsize, to, tosize);
}
total += Pipe::Put(to, outcount);
Counter = 0;
}
}
while (slen >= fromsize) {
int outcount;
if (Control == ENCODE) {
outcount = Base64_Encode(source, fromsize, to, tosize);
} else {
outcount = Base64_Decode(source, fromsize, to, tosize);
}
source = ((char *)source) + fromsize;
total += Pipe::Put(to, outcount);
slen -= fromsize;
}
if (slen > 0) {
memmove(from, source, slen);
Counter = slen;
}
return(total);
}
/***********************************************************************************************
* Base64Pipe::Flush -- Flushes the final pending data through the pipe. *
* *
* If there is any non-processed data accumulated in the holding buffer (quite likely when *
* encoding), then it will be processed and flushed out the end of the pipe. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the number of bytes output at the far distant final end of the pipe *
* chain. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/03/1996 JLB : Created. *
*=============================================================================================*/
int Base64Pipe::Flush(void)
{
int len = 0;
if (Counter) {
if (Control == ENCODE) {
int chars = Base64_Encode(PBuffer, Counter, CBuffer, sizeof(CBuffer));
len += Pipe::Put(CBuffer, chars);
} else {
int chars = Base64_Decode(CBuffer, Counter, PBuffer, sizeof(PBuffer));
len += Pipe::Put(PBuffer, chars);
}
Counter = 0;
}
len += Pipe::Flush();
return(len);
}

92
CODE/B64PIPE.H Normal file
View file

@ -0,0 +1,92 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/B64PIPE.H 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : B64PIPE.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 06/30/96 *
* *
* Last Update : June 30, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef B64PIPE_H
#define B64PIPE_H
#include "pipe.h"
/*
** This class performs Base64 encoding/decoding to the data that is piped through. Note that
** encoded data will grow in size by about 30%. The reverse occurs when decoding.
*/
class Base64Pipe : public Pipe
{
public:
typedef enum CodeControl {
ENCODE,
DECODE
} CodeControl;
Base64Pipe(CodeControl control) : Control(control), Counter(0) {}
virtual int Flush(void);
virtual int Put(void const * source, int slen);
private:
/*
** Indicates if this is for encoding or decoding of Base64 data.
*/
CodeControl Control;
/*
** The counter of the number of accumulated bytes pending for processing.
*/
int Counter;
/*
** Buffer that holds the Base64 coded bytes. This will be the staging buffer if
** this is for a decoding process. Otherwise, it will be used as a scratch buffer.
*/
char CBuffer[4];
/*
** Buffer that holds the plain bytes. This will be the staging buffer if this
** is for an encoding process. Otherwise, it will be used as a scratch buffer.
*/
char PBuffer[3];
/*
** Explicitly disable the copy constructor and the assignment operator.
*/
Base64Pipe(Base64Pipe & rvalue);
Base64Pipe & operator = (Base64Pipe const & pipe);
};
#endif

117
CODE/B64STRAW.CPP Normal file
View file

@ -0,0 +1,117 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/B64STRAW.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : B64STRAW.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 07/02/96 *
* *
* Last Update : July 3, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* Base64Straw::Get -- Fetch data and convert it to/from base 64 encoding. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "b64straw.h"
#include "base64.h"
#include <string.h>
/***********************************************************************************************
* Base64Straw::Get -- Fetch data and convert it to/from base 64 encoding. *
* *
* This routine will fetch the number of bytes requested and perform any conversion as *
* necessary upon the data. The nature of Base 64 encoding means that the data will *
* increase in size by 30% when encoding and decrease in like manner when decoding. *
* *
* INPUT: source -- The buffer to hold the processed data. *
* *
* length -- The number of bytes requested. *
* *
* OUTPUT: Returns with the number of bytes stored into the buffer. If the number is less *
* than requested, then this indicates that the data stream has been exhausted. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/03/1996 JLB : Created. *
*=============================================================================================*/
int Base64Straw::Get(void * source, int slen)
{
int total = 0;
char * from;
int fromsize;
char * to;
int tosize;
if (Control == ENCODE) {
from = PBuffer;
fromsize = sizeof(PBuffer);
to = CBuffer;
tosize = sizeof(CBuffer);
} else {
from = CBuffer;
fromsize = sizeof(CBuffer);
to = PBuffer;
tosize = sizeof(PBuffer);
}
/*
** Process the byte request in code blocks until there are either
** no more source bytes available or the request has been fulfilled.
*/
while (slen > 0) {
/*
** Transfer any processed bytes available to the request buffer.
*/
if (Counter > 0) {
int len = (slen < Counter) ? slen : Counter;
memmove(source, &to[tosize-Counter], len);
Counter -= len;
slen -= len;
source = ((char *)source) + len;
total += len;
}
if (slen == 0) break;
/*
** More bytes are needed, so fetch and process another base 64 block.
*/
int incount = Straw::Get(from, fromsize);
if (Control == ENCODE) {
Counter = Base64_Encode(from, incount, to, tosize);
} else {
Counter = Base64_Decode(from, incount, to, tosize);
}
if (Counter == 0) break;
}
return(total);
}

91
CODE/B64STRAW.H Normal file
View file

@ -0,0 +1,91 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/B64STRAW.H 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : B64STRAW.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 07/02/96 *
* *
* Last Update : July 2, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef B64STRAW_H
#define B64STRAW_H
#include "straw.h"
/*
** Performs Base 64 encoding/decoding on the data that is drawn through the straw. Note that
** encoding increases the data size by about 30%. The reverse occurs when decoding.
*/
class Base64Straw : public Straw
{
public:
typedef enum CodeControl {
ENCODE,
DECODE
} CodeControl;
Base64Straw(CodeControl control) : Control(control), Counter(0) {}
virtual int Get(void * source, int slen);
private:
/*
** Indicates if this is for encoding or decoding of Base64 data.
*/
CodeControl Control;
/*
** The counter of the number of accumulated bytes pending for processing.
*/
int Counter;
/*
** Buffer that holds the Base64 coded bytes. This will be the staging buffer if
** this is for a decoding process. Otherwise, it will be used as a scratch buffer.
*/
char CBuffer[4];
/*
** Buffer that holds the plain bytes. This will be the staging buffer if this
** is for an encoding process. Otherwise, it will be used as a scratch buffer.
*/
char PBuffer[3];
/*
** Explicitly disable the copy constructor and the assignment operator.
*/
Base64Straw(Base64Straw & rvalue);
Base64Straw & operator = (Base64Straw const & pipe);
};
#endif

239
CODE/BAR.CPP Normal file
View file

@ -0,0 +1,239 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/BAR.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : BAR.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 08/16/96 *
* *
* Last Update : August 16, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* ProgressBarClass::Is_Horizontal -- Determines if the bargraph is horizontal or not. *
* ProgressBarClass::Outline -- Draw an outline around the bargraph if supposed to. *
* ProgressBarClass::ProgressBarClass -- Constructor for the bargraph object. *
* ProgressBarClass::Redraw -- Redraw the bargraph. *
* ProgressBarClass::Set_Limit -- Set the logic tracking value. *
* ProgressBarClass::Update -- Update the value and redraw as necessary. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
#include "bar.h"
#include "fixed.h"
/***********************************************************************************************
* ProgressBarClass::ProgressBarClass -- Constructor for the bargraph object. *
* *
* This is the constructor for the bargraph object. It establishes the dimensions and *
* coordinate of the bargraph as well as the colors it will use when drawn. *
* *
* INPUT: w,y -- Pixel coordinate of the upper left corner of the bargraph. *
* *
* width,height -- Dimensions of the bargraph. *
* *
* forecolor -- The color to use for the filled portion of the bargraph. *
* *
* backcolor -- The color to use for the non-filled portion of the bargraph. *
* *
* bordercolor -- Optional border color. If not zero, then the bargraph will be *
* outlined with this color. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/16/1996 JLB : Created. *
*=============================================================================================*/
ProgressBarClass::ProgressBarClass(int x, int y, int width, int height, int forecolor, int backcolor, int bordercolor) :
X(x),
Y(y),
Width(width),
Height(height),
BarColor(forecolor),
BackColor(backcolor),
BorderColor(bordercolor),
CurrentValue(0),
LastDisplayCurrent(0),
IsDrawn(false)
{
}
/***********************************************************************************************
* ProgressBarClass::Is_Horizontal -- Determines if the bargraph is horizontal or not. *
* *
* If the bargraph is oriented horizontally, then this function will return TRUE. *
* *
* INPUT: none *
* *
* OUTPUT: bool; Is this bargraph horizontal? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/16/1996 JLB : Created. *
*=============================================================================================*/
bool ProgressBarClass::Is_Horizontal(void) const
{
if (Width > Height) return(true);
return(false);
}
/***********************************************************************************************
* ProgressBarClass::Update -- Update the value and redraw as necessary. *
* *
* This will update the value of the bargraph to the fill ratio specified and then *
* redraw it if required. Very small changes to the bargraph value might not result in a *
* visual change. *
* *
* INPUT: value -- The new value to assign to this bargraph. *
* *
* OUTPUT: none *
* *
* WARNINGS: bool; Did this update result in a redraw? *
* *
* HISTORY: *
* 08/16/1996 JLB : Created. *
*=============================================================================================*/
bool ProgressBarClass::Update(fixed value)
{
CurrentValue = value;
if (!IsDrawn || value - LastDisplayCurrent >= fixed(1, 10)) {
Redraw();
return(true);
}
return(false);
}
/***********************************************************************************************
* ProgressBarClass::Outline -- Draw an outline around the bargraph if supposed to. *
* *
* This routine will draw a border around the bargraph if this bargraph has a color *
* specified for the border. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/16/1996 JLB : Created. *
*=============================================================================================*/
void ProgressBarClass::Outline(void) const
{
if (Is_Outlined()) {
LogicPage->Draw_Line(X, Y, X+Width, Y, BorderColor);
LogicPage->Draw_Line(X, Y, X, Y+Height, BorderColor);
LogicPage->Draw_Line(X, Y+Height, X, Y+Height, BorderColor);
LogicPage->Draw_Line(X+Width, Y, X+Width, Y+Height, BorderColor);
}
}
/***********************************************************************************************
* ProgressBarClass::Redraw -- Redraw the bargraph. *
* *
* This will redraw the entire bargraph. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/16/1996 JLB : Created. *
*=============================================================================================*/
void ProgressBarClass::Redraw(void) const
{
Hide_Mouse();
Outline();
/*
** Determine the inner dimensions of the bargraph. This will be
** somewhat smaller than indicated if it has a border.
*/
int x = X;
int y = Y;
int w = Width;
int h = Height;
if (Is_Outlined()) {
x += 1;
y += 1;
w -= 2;
h -= 2;
}
/*
** The working "length" of the bargraph is dependant on whether the
** bargraph is horizontal or vertical.
*/
int size = Is_Horizontal() ? w : h;
/*
** Determine the number of pixels to fill in the bargraph depending on the
** size of the internal value. The larger the internal value the more
** filled the bargraph becomes.
*/
int fill = CurrentValue * size;
/*
** Draw the filled portion of the bargraph if there is any pixels to draw.
*/
if (fill > 0) {
if (Is_Horizontal()) {
LogicPage->Fill_Rect(x, y, x+fill, y+h, BarColor);
} else {
LogicPage->Fill_Rect(x, y+fill, x+w, y+h, BarColor);
}
}
/*
** Draw the unfilled portion of the bargraph if there are any pixels to
** draw of it.
*/
if (w-fill > 0) {
if (Is_Horizontal()) {
LogicPage->Fill_Rect(x+fill, y, x+w, y+h, BackColor);
} else {
LogicPage->Fill_Rect(x, y, x+w, y+fill-1, BackColor);
}
}
Show_Mouse();
ProgressBarClass * me = (ProgressBarClass *)this;
me->LastDisplayCurrent = CurrentValue;
me->IsDrawn = true;
}

111
CODE/BAR.H Normal file
View file

@ -0,0 +1,111 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/BAR.H 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : BAR.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 08/16/96 *
* *
* Last Update : August 16, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef BAR_H
#define BAR_H
/*
** The "bool" integral type was defined by the C++ committee in
** November of '94. Until the compiler supports this, use the following
** definition.
*/
#ifndef __BORLANDC__
#ifndef TRUE_FALSE_DEFINED
#define TRUE_FALSE_DEFINED
enum {false=0,true=1};
typedef int bool;
#endif
#endif
#include "fixed.h"
/*
** This is a manager for a progress (or other) bargraph. Such a graph consists of a fill
** and a background region. The fill percentage of the bargraph is controlled by an
** update value. The bargraph can be optionally outlined.
*/
class ProgressBarClass
{
public:
ProgressBarClass(int x, int y, int width, int height, int forecolor, int backcolor, int bordercolor=0);
bool Update(fixed value);
void Redraw(void) const;
private:
void Outline(void) const;
bool Is_Horizontal(void) const;
bool Is_Outlined(void) const {return(BorderColor != 0);}
/*
** This is the upper left coordinates of the bargraph.
*/
int X,Y;
/*
** This is the dimensions of the bargraph.
*/
int Width, Height;
/*
** These are the colors to use when drawing the progress bar.
*/
int BarColor;
int BackColor;
int BorderColor;
/*
** This is the current value of the bargraph.
*/
fixed CurrentValue;
/*
** This is the current value as of the last time the bargraph was rendered.
*/
fixed LastDisplayCurrent;
/*
** If the bargraph has been drawn at least once, then this flag will
** be true.
*/
unsigned IsDrawn:1;
};
#endif

548
CODE/BASE.CPP Normal file
View file

@ -0,0 +1,548 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/BASE.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : BASE.CPP *
* *
* Programmer : Bill Randolph *
* *
* Start Date : 03/27/95 *
* *
* Last Update : July 30, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* BaseClass::Get_Building -- Returns ptr to the built building for the given node *
* BaseClass::Get_Node -- Finds the node that matches the cell specified. *
* BaseClass::Get_Node -- Returns ptr to the node corresponding to given object *
* BaseClass::Is_Built -- Tells if given item in the list has been built yet *
* BaseClass::Is_Node -- Tells if the given building is part of our base list *
* BaseClass::Load -- loads from a saved game file *
* BaseClass::Next_Buildable -- returns ptr to the next node that needs to be built *
* BaseClass::Read_INI -- INI reading routine *
* BaseClass::Save -- saves to a saved game file *
* BaseClass::Write_INI -- Writes all the base information to the INI database. *
* BaseNodeClass::operator != -- inequality operator *
* BaseNodeClass::operator == -- equality operator *
* BaseNodeClass::operator > -- greater-than operator *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
/***********************************************************************************************
* BaseNodeClass::operator == -- equality operator *
* *
* INPUT: *
* node node to test against *
* *
* OUTPUT: *
* true = equal, false = not equal *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 03/24/1995 BRR : Created. *
*=============================================================================================*/
int BaseNodeClass::operator == (BaseNodeClass const & node)
{
return(Type == node.Type && Cell == node.Cell);
}
/***********************************************************************************************
* BaseNodeClass::operator != -- inequality operator *
* *
* INPUT: *
* node node to test against *
* *
* OUTPUT: *
* comparison result *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 03/24/1995 BRR : Created. *
*=============================================================================================*/
int BaseNodeClass::operator !=(BaseNodeClass const & node)
{
return(!(*this == node));
}
/***********************************************************************************************
* BaseNodeClass::operator > -- greater-than operator *
* *
* INPUT: *
* node node to test against *
* *
* OUTPUT: *
* comparison result *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 03/24/1995 BRR : Created. *
*=============================================================================================*/
int BaseNodeClass::operator > (BaseNodeClass const & )
{
return(true);
}
/***********************************************************************************************
* BaseClass::Load -- loads from a saved game file *
* *
* INPUT: *
* file open file *
* *
* OUTPUT: *
* true = success, false = failure *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 03/24/1995 BRR : Created. *
* 07/04/1996 JLB : Converted to demand driven data source. *
*=============================================================================================*/
bool BaseClass::Load(Straw & file)
{
int num_struct;
int i;
BaseNodeClass node;
/*
** Read in & check the size of this class
*/
if (file.Get(&i, sizeof(i)) != sizeof(i)) {
return(false);
}
if (i != sizeof(*this)) {
return(false);
}
/*
** Read in the House & the number of structures in the base
*/
if (file.Get(&House, sizeof(House)) != sizeof(House)) {
return(false);
}
if (file.Get(&num_struct, sizeof(num_struct)) != sizeof(num_struct)) {
return(false);
}
/*
** Read each node entry & add it to the list
*/
for (i = 0; i < num_struct; i++) {
if (file.Get(&node, sizeof(node)) != sizeof(node)) {
return(false);
}
Nodes.Add(node);
}
return(true);
}
/***********************************************************************************************
* BaseClass::Save -- saves to a saved game file *
* *
* INPUT: *
* file open file *
* *
* OUTPUT: *
* true = success, false = failure *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 03/24/1995 BRR : Created. *
* 07/04/1996 JLB : Converted to supply driven data output. *
*=============================================================================================*/
bool BaseClass::Save(Pipe & file) const
{
int num_struct;
int i;
BaseNodeClass node;
/*
** Write the size of this class
*/
i = sizeof(*this);
file.Put(&i, sizeof(i));
/*
** Write the House & the number of structures in the base
*/
file.Put(&House, sizeof(House));
num_struct = Nodes.Count();
file.Put(&num_struct, sizeof(num_struct));
/*
** Write each node entry
*/
for (i = 0; i < num_struct; i++) {
node = Nodes[i];
file.Put(&node, sizeof(node));
}
return(true);
}
/***********************************************************************************************
* BaseClass::Is_Built -- Tells if given item in the list has been built yet *
* *
* INPUT: *
* index index into base list *
* *
* OUTPUT: *
* true = yes, false = no *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 03/24/1995 BRR : Created. *
*=============================================================================================*/
bool BaseClass::Is_Built(int index) const
{
if (Get_Building(index) != NULL) {
return(true);
} else {
return(false);
}
}
/***********************************************************************************************
* BaseClass::Get_Building -- Returns ptr to the built building for the given node *
* *
* INPUT: *
* obj pointer to building to test *
* *
* OUTPUT: *
* ptr to already-built building, NULL if none *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 03/24/1995 BRR : Created. *
* 07/30/1996 JLB : Handle arbitrary overlapper list length. *
*=============================================================================================*/
BuildingClass * BaseClass::Get_Building(int index) const
{
ObjectClass * obj[1 + ARRAY_SIZE(Map[(CELL)0].Overlapper)];
/*
** Check the location on the map where this building should be; if it's
** there, return a pointer to it.
*/
CELL cell = Nodes[index].Cell;
obj[0] = Map[cell].Cell_Building();
int count = 1;
for (int xindex = 0; xindex < ARRAY_SIZE(Map[cell].Overlapper); xindex++) {
if (Map[cell].Overlapper[xindex] != NULL) {
obj[count++] = Map[cell].Overlapper[xindex];
}
}
BuildingClass * bldg = NULL;
for (int i = 0; i < count; i++) {
if (obj[i] &&
Coord_Cell(obj[i]->Coord) == Nodes[index].Cell &&
obj[i]->What_Am_I() == RTTI_BUILDING &&
((BuildingClass *)obj[i])->Class->Type == Nodes[index].Type) {
bldg = (BuildingClass *)obj[i];
break;
}
}
return(bldg);
}
/***********************************************************************************************
* BaseClass::Is_Node -- Tells if the given building is part of our base list *
* *
* INPUT: *
* obj pointer to building to test *
* *
* OUTPUT: *
* true = building is a node in the list, false = isn't *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 03/24/1995 BRR : Created. *
*=============================================================================================*/
bool BaseClass::Is_Node(BuildingClass const * obj)
{
if (Get_Node(obj) != NULL) {
return(true);
} else {
return(false);
}
}
/***********************************************************************************************
* BaseClass::Get_Node -- Returns ptr to the node corresponding to given object *
* *
* INPUT: *
* obj pointer to building to test *
* *
* OUTPUT: *
* ptr to node *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 03/24/1995 BRR : Created. *
*=============================================================================================*/
BaseNodeClass * BaseClass::Get_Node(BuildingClass const * obj)
{
for (int i = 0; i < Nodes.Count(); i++) {
if (obj->Class->Type == Nodes[i].Type && Coord_Cell(obj->Coord) == Nodes[i].Cell) {
return(&Nodes[i]);
}
}
return(NULL);
}
/***********************************************************************************************
* BaseClass::Get_Node -- Finds the node that matches the cell specified. *
* *
* This routine is used to find a matching node the corresponds to the cell specified. *
* *
* INPUT: cell -- The cell to use in finding a match. *
* *
* OUTPUT: Returns a pointer to the matching node if found. If not found, then NULL is *
* returned. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 03/12/1996 JLB : Created. *
*=============================================================================================*/
BaseNodeClass * BaseClass::Get_Node(CELL cell)
{
for (int index = 0; index < Nodes.Count(); index++) {
if (cell == Nodes[index].Cell) {
return(&Nodes[index]);
}
}
return(NULL);
}
/***********************************************************************************************
* BaseClass::Next_Buildable -- returns ptr to the next node that needs to be built *
* *
* If 'type' is not NONE, returns ptr to the next "hole" in the list of the given type. *
* Otherwise, returns ptr to the next hole in the list of any type. *
* *
* INPUT: *
* type type of building to check for *
* *
* OUTPUT: *
* ptr to a BaseNodeClass, NULL if none *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 03/24/1995 BRR : Created. *
*=============================================================================================*/
BaseNodeClass * BaseClass::Next_Buildable(StructType type)
{
/*
** Loop through all node entries, returning a pointer to the first
** un-built one that matches the requested type.
*/
for (int i = 0; i < Nodes.Count(); i++) {
/*
** For STRUCT_NONE, return the first hole found
*/
if (type == STRUCT_NONE) {
if (!Is_Built(i)) {
return(&Nodes[i]);
}
} else {
/*
** For a "real" building type, return the first hold for that type
*/
if (Nodes[i].Type==type && !Is_Built(i)) {
return(&Nodes[i]);
}
}
}
// If no entry could be found, then create a fake one that will allow
// placement of the building. Make it static and reuse the next time this
// routine is called.
return(NULL);
}
/***********************************************************************************************
* BaseClass::Read_INI -- INI reading routine *
* *
* INI entry format: *
* BLDG=COORDINATE *
* BLDG=COORDINATE *
* ... *
* *
* INPUT: *
* buffer pointer to loaded INI file *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* This routines assumes there is only one base defined for the scenario. *
* *
* HISTORY: *
* 03/24/1995 BRR : Created. *
* 02/20/1996 JLB : Fixed to know what house to build base from. *
*=============================================================================================*/
void BaseClass::Read_INI(CCINIClass & ini)
{
char buf[128];
char uname[10];
BaseNodeClass node; // node to add to list
Mono_Clear_Screen();
/*
** First, determine the house of the human player, and set the Base's house
** accordingly.
*/
House = ini.Get_HousesType(INI_Name(), "Player", PlayerPtr->Class->House);
/*
** Read the number of buildings that will go into the base node list
*/
int count = ini.Get_Int(INI_Name(), "Count", 0);
/*
** Read each entry in turn, in the same order they were written out.
*/
for (int i = 0; i < count; i++) {
/*
** Get an INI entry
*/
sprintf(uname,"%03d",i);
ini.Get_String(INI_Name(), uname, NULL, buf, sizeof(buf));
/*
** Set the node's building type
*/
node.Type = BuildingTypeClass::From_Name(strtok(buf,","));
/*
** Read & set the node's coordinate
*/
node.Cell = atoi(strtok(NULL,","));
/*
** Add this node to the Base's list
*/
Nodes.Add(node);
}
}
/***********************************************************************************************
* BaseClass::Write_INI -- Writes all the base information to the INI database. *
* *
* Use this routine to write all prebuild base information to the INI database specified. *
* *
* INPUT: ini -- Reference to the INI database to store the data to. *
* *
* OUTPUT: none *
* *
* WARNINGS: If there was any preexisting prebuild base data in the database, it will be *
* be erased by this routine. *
* *
* HISTORY: *
* 07/30/1996 JLB : Created. *
*=============================================================================================*/
void BaseClass::Write_INI(CCINIClass & ini)
{
/*
** Clear out all existing base data from the ini file.
*/
ini.Clear(INI_Name());
if (House != HOUSE_NONE) {
/*
** Write out the owner of this buildable list.
*/
ini.Put_HousesType(INI_Name(), "Player", House);
/*
** Save the # of buildings in the Nodes list. This is essential because
** they must be read in the same order they were created, so "000" must be
** read first, etc.
*/
ini.Put_Int(INI_Name(), "Count", Nodes.Count());
/*
** Write each entry into the INI
*/
for (int i = 0; i < Nodes.Count(); i++) {
char buf[128];
char uname[10];
sprintf(uname,"%03d",i);
sprintf(buf,"%s,%d",
BuildingTypeClass::As_Reference(Nodes[i].Type).IniName,
Nodes[i].Cell);
ini.Put_String(INI_Name(), uname, buf);
}
}
}

130
CODE/BASE.H Normal file
View file

@ -0,0 +1,130 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/BASE.H 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : BASE.H *
* *
* Programmer : Bill Randolph *
* *
* Start Date : 03/27/95 *
* *
* Last Update : March 27, 1995 *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef BASE_H
#define BASE_H
/****************************************************************************
** This class defines one "node" in the pre-built base list. Each node
** contains a type of building to build, and the COORDINATE to build it at.
*/
class BaseNodeClass
{
public:
BaseNodeClass(void) {};
BaseNodeClass(StructType building, CELL cell) : Type(building), Cell(cell) {};
int operator == (BaseNodeClass const & node);
int operator != (BaseNodeClass const & node);
int operator > (BaseNodeClass const & node);
StructType Type;
CELL Cell;
};
/****************************************************************************
** This is the class that defines a pre-built base for the computer AI.
** (Despite its name, this is NOT the "base" class for C&C's class hierarchy!)
*/
class BaseClass
{
public:
/*
** Constructor/Destructor
*/
BaseClass(void) {};
virtual ~BaseClass() {Nodes.Clear();}
/*
** Initialization
*/
void Init(void) {House = HOUSE_NONE; Nodes.Clear();}
/*
** The standard suite of load/save support routines
*/
void Read_INI(CCINIClass & ini);
void Write_INI(CCINIClass & ini);
static char *INI_Name(void) {return "Base";}
bool Load(Straw & file);
bool Save(Pipe & file) const;
virtual void Code_Pointers(void) {};
virtual void Decode_Pointers(void) {};
/*
** Tells if the given node has been built or not
*/
bool Is_Built(int index) const;
/*
** Returns a pointer to the object for the given node
*/
BuildingClass * Get_Building(int index) const;
/*
** Tells if the given building ptr is a node in this base's list.
*/
bool Is_Node(BuildingClass const * obj);
/*
** Returns a pointer to the requested node.
*/
BaseNodeClass * Get_Node(BuildingClass const * obj);
BaseNodeClass * Get_Node(int index) { return (&Nodes[index]); }
BaseNodeClass * Get_Node(CELL cell);
/*
** Returns a pointer to the next "hole" in the Nodes list.
*/
BaseNodeClass * Next_Buildable(StructType type = STRUCT_NONE);
/*
** This is the list of "nodes" that define the base. Portions of this
** list can be pre-built by simply saving those buildings in the INI
** along with non-base buildings, so Is_Built will return true for them.
*/
DynamicVectorClass<BaseNodeClass> Nodes;
/*
** This is the house this base belongs to.
*/
HousesType House;
};
#endif

437
CODE/BASE64.CPP Normal file
View file

@ -0,0 +1,437 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/BASE64.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : BASE64.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 06/29/96 *
* *
* Last Update : July 6, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* Base64_Decode -- Decodes Base 64 data into its original data form. *
* Base64_Encode -- Encode data into Base 64 format. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "base64.h"
#include <stddef.h>
/*
** This is the magic padding character used to fill out the encoded data to a multiple of
** 4 characters even though the source data is less than necessary to accomplish this.
** The pad character lets the decoder know of this condition and it will compensate
** accordingly.
*/
static char const * const _pad = "=";
/*
** This encoder translation table will convert a 6 bit number into an ASCII character.
*/
static char const * const _encoder = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/*
** The decoder translation table takes an ASCII character and converts it into a
** 6 bit number.
*/
#define BAD 0xFE // Ignore this character in source data.
#define END 0xFF // Signifies premature end of input data.
static unsigned char const _decoder[256] = {
BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,
BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,
BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,62,BAD,BAD,BAD,63,
52,53,54,55,56,57,58,59,60,61,BAD,BAD,BAD,END,BAD,BAD,
BAD,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,
15,16,17,18,19,20,21,22,23,24,25,BAD,BAD,BAD,BAD,BAD,
BAD,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
41,42,43,44,45,46,47,48,49,50,51,BAD,BAD,BAD,BAD,BAD,
BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,
BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,
BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,
BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,
BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,
BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,
BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,
BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD,BAD
};
int const PacketChars = 4;
/*
** The packet type is used to construct and disect the Base64 data blocks. The data
** consists of three source data bytes mapped onto four 6 bit Base64 code elements.
*/
typedef union {
struct {
#ifdef BIG_ENDIAN
unsigned char C1;
unsigned char C2;
unsigned char C3;
#else
unsigned char C3;
unsigned char C2;
unsigned char C1;
#endif
unsigned char pad;
} Char;
struct {
#ifdef BIG_ENDIAN
unsigned O1:6;
unsigned O2:6;
unsigned O3:6;
unsigned O4:6;
#else
unsigned O4:6;
unsigned O3:6;
unsigned O2:6;
unsigned O1:6;
#endif
unsigned pad:8;
} SubCode;
unsigned int Raw;
} PacketType;
/***********************************************************************************************
* Base64_Encode -- Encode data into Base 64 format. *
* *
* This will take an arbitrary length of source data and transform it into base 64 format *
* data. Base 64 format has the property of being very portable across text editors and *
* country character encoding schemes. As such it is ideal for e-mail. Note that the output *
* data will be about 33% larger than the source. *
* *
* INPUT: source -- Pointer to the source data to convert. *
* *
* slen -- The number of bytes to encode. *
* *
* dest -- Pointer to the destination buffer that will hold the encoded data. *
* *
* dlen -- The size of the destination buffer. *
* *
* OUTPUT: Returns with the number of bytes stored into the destination buffer. *
* *
* WARNINGS: Be sure that the destination buffer is big enough to hold the encoded output. *
* *
* HISTORY: *
* 07/06/1996 JLB : Created. *
*=============================================================================================*/
int Base64_Encode(void const * source, int slen, void * dest, int dlen)
{
/*
** Check the parameters for legality.
*/
if (source == NULL || slen == 0 || dest == NULL || dlen == 0) {
return(0);
}
/*
** Process the source data in blocks of three bytes. Fewer than three bytes
** results in special padding output characters (automatically discarded
** during the decode process).
*/
int total = 0;
unsigned char const * sptr = (unsigned char const *)source;
unsigned char * dptr = (unsigned char *)dest;
while (slen > 0 && dlen >= PacketChars) {
/*
** Fetch 24 bits of source data.
*/
PacketType packet;
int pad = 0;
packet.Raw = 0;
packet.Char.C1 = *sptr++;
slen--;
if (slen) {
packet.Char.C2 = *sptr++;
slen--;
} else {
pad++;
}
if (slen) {
packet.Char.C3 = *sptr++;
slen--;
} else {
pad++;
}
/*
** Translate and write 4 characters of Base64 data. Pad with pad
** characters if there is insufficient source data for a full packet.
*/
*dptr++ = _encoder[packet.SubCode.O1];
*dptr++ = _encoder[packet.SubCode.O2];
if (pad < 2) {
*dptr++ = _encoder[packet.SubCode.O3];
} else {
*dptr++ = _pad[0];
}
if (pad < 1) {
*dptr++ = _encoder[packet.SubCode.O4];
} else {
*dptr++ = _pad[0];
}
dlen -= PacketChars;
total += PacketChars;
}
/*
** Add a trailing null as a courtesy measure.
*/
if (dlen > 0) {
*dptr = '\0';
}
/*
** Return with the total number of characters in the output buffer.
*/
return(total);
}
/***********************************************************************************************
* Base64_Decode -- Decodes Base 64 data into its original data form. *
* *
* Use this routine to decode base 64 data back into the original data. A property of this *
* decode process is that unrecognized input characters are ignored. This allows mangled *
* source (filled with line breaks or spaces) to be correctly decoded. The decode process *
* terminates when the end of the source data has been reached or the special end of data *
* marker is encountered. *
* *
* INPUT: source -- Pointer to the source data to decode. *
* *
* slen -- The number of bytes in the source data buffer. *
* *
* dest -- Pointer to the destination buffer to be filled with the decoded data. *
* *
* dlen -- The maximum size of the destination buffer. *
* *
* OUTPUT: Returns with the number of bytes stored into the destination buffer. This will *
* always be less than the number of source bytes (usually by about 33%). *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/06/1996 JLB : Created. *
*=============================================================================================*/
int Base64_Decode(void const * source, int slen, void * dest, int dlen)
{
/*
** Check the parameters for legality.
*/
if (source == NULL || slen == 0 || dest == NULL || dlen == 0) {
return(0);
}
int total = 0;
unsigned char const * sptr = (unsigned char const *)source;
unsigned char * dptr = (unsigned char *)dest;
while (slen > 0 && dlen > 0) {
PacketType packet;
packet.Raw = 0;
/*
** Process input until a full packet has been accumulated or the
** source is exhausted.
*/
int pcount = 0;
while (pcount < PacketChars && slen > 0) {
unsigned char c = *sptr++;
slen--;
unsigned char code = _decoder[c];
/*
** An unrecognized character is skipped.
*/
if (code == BAD) continue;
/*
** The "=" character signifies the end of data regardless of what
** the source buffer length value may be.
*/
if (code == END) {
slen = 0;
break;
}
/*
** A valid Base64 character was found so add it to the packet
** data.
*/
switch (pcount) {
case 0:
packet.SubCode.O1 = code;
break;
case 1:
packet.SubCode.O2 = code;
break;
case 2:
packet.SubCode.O3 = code;
break;
case 3:
packet.SubCode.O4 = code;
break;
}
pcount++;
}
/*
** A packet block is ready for output into the destination buffer.
*/
*dptr++ = packet.Char.C1;
dlen--;
total++;
if (dlen > 0 && pcount > 2) {
*dptr++ = packet.Char.C2;
dlen--;
total++;
}
if (dlen > 0 && pcount > 3) {
*dptr++ = packet.Char.C3;
dlen--;
total++;
}
}
/*
** Return with the total number of characters decoded into the
** output buffer.
*/
return(total);
}
/*
Base64 Content-Transfer-Encoding
The Base64 Content-Transfer-Encoding is designed to represent arbitrary
sequences of octets in a form that need not be humanly readable. The encoding
and decoding algorithms are simple, but the encoded data are consistently
only about 33 percent larger than the unencoded data. This encoding is
virtually identical to the one used in Privacy Enhanced Mail (PEM)
applications, as defined in RFC 1421. The base64 encoding is adapted from
RFC 1421, with one change: base64 eliminates the "*" mechanism for embedded
clear text.
A 65-character subset of US-ASCII is used, enabling 6 bits to be represented
per printable character. (The extra 65th character, "=", is used to signify a
special processing function.)
NOTE:
This subset has the important property that it is represented identically
in all versions of ISO 646, including US ASCII, and all characters in the
subset are also represented identically in all versions of EBCDIC. Other
popular encodings, such as the encoding used by the uuencode utility and
the base85 encoding specified as part of Level 2 PostScript, do not share
these properties, and thus do not fulfill the portability requirements a
binary transport encoding for mail must meet.
The encoding process represents 24-bit groups of input bits as output strings
of 4 encoded characters. Proceeding from left to right, a 24-bit input group is
formed by concatenating 3 8-bit input groups. These 24 bits are then treated as
4 concatenated 6-bit groups, each of which is translated into a single digit in
the base64 alphabet. When encoding a bit stream via the base64 encoding, the
bit stream must be presumed to be ordered with the most-significant-bit first.
That is, the first bit in the stream will be the high-order bit in the first
byte, and the eighth bit will be the low-order bit in the first byte, and so on.
Each 6-bit group is used as an index into an array of 64 printable characters.
The character referenced by the index is placed in the output string. These
characters, identified in Table 1, below, are selected so as to be universally
representable, and the set excludes characters with particular significance to
SMTP (e.g., ".", CR, LF) and to the encapsulation boundaries defined in this
document (e.g., "-").
Table 1: The Base64 Alphabet
Value Encoding Value Encoding Value Encoding Value Encoding
0 A 17 R 34 i 51 z
1 B 18 S 35 j 52 0
2 C 19 T 36 k 53 1
3 D 20 U 37 l 54 2
4 E 21 V 38 m 55 3
5 F 22 W 39 n 56 4
6 G 23 X 40 o 57 5
7 H 24 Y 41 p 58 6
8 I 25 Z 42 q 59 7
9 J 26 a 43 r 60 8
10 K 27 b 44 s 61 9
11 L 28 c 45 t 62 +
12 M 29 d 46 u 63 /
13 N 30 e 47 v
14 O 31 f 48 w (pad) =
15 P 32 g 49 x
16 Q 33 h 50 y
The output stream (encoded bytes) must be represented in lines of no more than
76 characters each. All line breaks or other characters not found in Table 1
must be ignored by decoding software. In base64 data, characters other than
those in Table 1, line breaks, and other white space probably indicate a
transmission error, about which a warning message or even a message rejection
might be appropriate under some circumstances.
Special processing is performed if fewer than 24 bits are available at the end
of the data being encoded. A full encoding quantum is always completed at the
end of a body. When fewer than 24 input bits are available in an input group,
zero bits are added (on the right) to form an integral number of 6-bit groups.
Padding at the end of the data is performed using the '=' character. Since all
base64 input is an integral number of octets, only the following cases can
arise: (1) the final quantum of encoding input is an integral multiple of 24
bits; here, the final unit of encoded output will be an integral multiple of 4
characters with no "=" padding, (2) the final quantum of encoding input is
exactly 8 bits; here, the final unit of encoded output will be two characters
followed by two "=" padding characters, or (3) the final quantum of encoding
input is exactly 16 bits; here, the final unit of encoded output will be three
characters followed by one "=" padding character.
Because it is used only for padding at the end of the data, the occurrence of
any '=' characters may be taken as evidence that the end of the data has been
reached (without truncation in transit). No such assurance is possible,
however, when the number of octets transmitted was a multiple of three.
Any characters outside of the base64 alphabet are to be ignored in
base64-encoded data. The same applies to any illegal sequence of characters in
the base64 encoding, such as "====="
Care must be taken to use the proper octets for line breaks if base64 encoding
is applied directly to text material that has not been converted to canonical
form. In particular, text line breaks must be converted into CRLF sequences
prior to base64 encoding. The important thing to note is that this may be done
directly by the encoder rather than in a prior canonicalization step in some
implementations.
NOTE:
There is no need to worry about quoting apparent encapsulation boundaries
within base64-encoded parts of multipart entities because no hyphen
characters are used in the base64 encoding.
*/

40
CODE/BASE64.H Normal file
View file

@ -0,0 +1,40 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/BASE64.H 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : BASE64.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 06/29/96 *
* *
* Last Update : June 29, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int Base64_Encode(void const * source, int slen, void * dest, int dlen);
int Base64_Decode(void const * source, int slen, void * dest, int dlen);

300
CODE/BBDATA.CPP Normal file
View file

@ -0,0 +1,300 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/BBDATA.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : BBDATA.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : May 23, 1994 *
* *
* Last Update : July 19, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* BulletTypeClass::As_Reference -- Returns with a reference to the bullet type object specif*
* BulletTypeClass::BulletTypeClass -- Constructor for bullet type objects. *
* BulletTypeClass::Init_Heap -- Initialize the heap objects for the bullet type. *
* BulletTypeClass::Load_Shapes -- Load shape data for bullet types. *
* BulletTypeClass::One_Time -- Performs the one time processing for bullets. *
* BulletTypeClass::Read_INI -- Fetch the bullet type data from the INI database. *
* BulletTypeClass::operator delete -- Deletes a bullet type object from the special heap. *
* BulletTypeClass::operator new -- Allocates a bullet type object from the special heap. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
/***********************************************************************************************
* BulletTypeClass::BulletTypeClass -- Constructor for bullet type objects. *
* *
* This is basically a constructor for static type objects used by bullets. All bullets *
* are of a type constructed by this routine at game initialization time. *
* *
* INPUT: see below... *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 10/17/1994 JLB : Created. *
* 07/17/1996 JLB : Uses correct default values. *
*=============================================================================================*/
BulletTypeClass::BulletTypeClass(char const * name) :
ObjectTypeClass( RTTI_BULLETTYPE,
BulletTypes.ID(this),
true,
true,
false,
false,
true,
true,
false,
TXT_NONE,
name
),
IsHigh(false),
IsShadow(true),
IsArcing(false),
IsDropping(false),
IsInvisible(false),
IsProximityArmed(false),
IsFlameEquipped(false),
IsFueled(false),
IsFaceless(true),
IsInaccurate(false),
IsTranslucent(false),
IsAntiAircraft(false),
IsAntiGround(true),
IsAntiSub(false),
IsDegenerate(false),
IsSubSurface(false),
IsParachuted(false),
IsGigundo(false),
Type(BulletType(ID)),
ROT(0),
Arming(0),
Tumble(0)
{
}
/***********************************************************************************************
* BulletTypeClass::operator new -- Allocates a bullet type object from the special heap. *
* *
* This allocates a bullet type object from a special heap that is used just for *
* objects of this type. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with a pointer to an allocated block or NULL if the allocation could not *
* occur. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/06/1996 JLB : Created. *
*=============================================================================================*/
void * BulletTypeClass::operator new(size_t)
{
return(BulletTypes.Alloc());
}
/***********************************************************************************************
* BulletTypeClass::operator delete -- Deletes a bullet type object from the special heap. *
* *
* This is the counterpart to the operator new function for bullet type objects. It will *
* return the bullet type object back to the special heap used for bullet type object *
* allocation. *
* *
* INPUT: ptr -- Pointer to the bullet type object to free. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/06/1996 JLB : Created. *
*=============================================================================================*/
void BulletTypeClass::operator delete(void * ptr)
{
BulletTypes.Free((BulletTypeClass *)ptr);
}
/***********************************************************************************************
* BulletTypeClass::Init_Heap -- Initialize the heap objects for the bullet type. *
* *
* This performs any necessary initialization for the bullet types. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/06/1996 JLB : Created. *
*=============================================================================================*/
void BulletTypeClass::Init_Heap(void)
{
/*
** These bullet type class objects must be allocated in the exact order that they
** are specified in the BulletType enumeration. This is necessary because the heap
** allocation block index serves double duty as the type number index.
*/
new BulletTypeClass("Invisible"); // BULLET_INVISIBLE
new BulletTypeClass("Cannon"); // BULLET_CANNON
new BulletTypeClass("Ack"); // BULLET_ACK
new BulletTypeClass("Torpedo"); // BULLET_TORPEDO
new BulletTypeClass("FROG"); // BULLET_FROG
new BulletTypeClass("HeatSeeker"); // BULLET_HEAT_SEEKER
new BulletTypeClass("LaserGuided"); // BULLET_LASER_GUIDED
new BulletTypeClass("Lobbed"); // BULLET_LOBBED
new BulletTypeClass("Bomblet"); // BULLET_BOMBLET
new BulletTypeClass("Ballistic"); // BULLET_BALLISTIC
new BulletTypeClass("Parachute"); // BULLET_PARACHUTE
new BulletTypeClass("Fireball"); // BULLET_FIREBALL
new BulletTypeClass("LeapDog"); // BULLET_DOG
new BulletTypeClass("Catapult"); // BULLET_CATAPULT
new BulletTypeClass("AAMissile"); // BULLET_AAMISSILE
new BulletTypeClass("GPSSatellite");// BULLET_GPS_SATELLITE
new BulletTypeClass("NukeUp"); // BULLET_NUKE_UP
new BulletTypeClass("NukeDown"); // BULLET_NUKE_DOWN
}
/***********************************************************************************************
* BulletTypeClass::One_Time -- Performs the one time processing for bullets. *
* *
* This routine is used to perform any one time processing for the bullet type class. It *
* handles loading of the shape files. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: This routine must be called before any rendering of bullets occurs and should *
* only be called once. *
* *
* HISTORY: *
* 05/28/1994 JLB : Created. *
*=============================================================================================*/
void BulletTypeClass::One_Time(void)
{
/*
** Load the bullet shapes.
*/
for (BulletType index = BULLET_FIRST; index < BULLET_COUNT; index++) {
BulletTypeClass const & bullet = As_Reference(index);
char fullname[_MAX_FNAME+_MAX_EXT];
if (!bullet.IsInvisible) {
_makepath(fullname, NULL, NULL, bullet.GraphicName, ".SHP");
#ifdef NDEBUG
((void const *&)bullet.ImageData) = MFCD::Retrieve(fullname);
#else
RawFileClass file(fullname);
if (file.Is_Available()) {
((void const *&)bullet.ImageData) = Load_Alloc_Data(file);
} else {
((void const *&)bullet.ImageData) = MFCD::Retrieve(fullname);
}
#endif
}
}
}
/***********************************************************************************************
* BulletTypeClass::As_Reference -- Returns with a reference to the bullet type object specifi *
* *
* Given a bullet type identifier, this routine will return a reference to the bullet type *
* object it refers to. *
* *
* INPUT: type -- The bullet type identifier to convert to a reference. *
* *
* OUTPUT: Returns with a reference to the bullet type object. *
* *
* WARNINGS: Make sure that the type parameter specified is a valid bullet type. If not, *
* then the results are undefined. *
* *
* HISTORY: *
* 07/06/1996 JLB : Created. *
*=============================================================================================*/
BulletTypeClass & BulletTypeClass::As_Reference(BulletType type)
{
return(*BulletTypes.Ptr(type));
}
/***********************************************************************************************
* BulletTypeClass::Read_INI -- Fetch the bullet type data from the INI database. *
* *
* Use this routine to fetch override information about this bullet type class object *
* from the INI database specified. *
* *
* INPUT: ini -- Reference to the INI database to examine. *
* *
* OUTPUT: bool; Was the section for this bullet found and the data extracted? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/19/1996 JLB : Created. *
*=============================================================================================*/
bool BulletTypeClass::Read_INI(CCINIClass & ini)
{
if (ini.Is_Present(Name())) {
Arming = ini.Get_Int(Name(), "Arm", Arming);
ROT = ini.Get_Int(Name(), "ROT", ROT);
Tumble = ini.Get_Int(Name(), "Frames", Tumble);
IsHigh = ini.Get_Bool(Name(), "High", IsHigh);
IsShadow = ini.Get_Bool(Name(), "Shadow", IsShadow);
IsArcing = ini.Get_Bool(Name(), "Arcing", IsArcing);
IsDropping = ini.Get_Bool(Name(), "Dropping", IsDropping);
IsInvisible = ini.Get_Bool(Name(), "Inviso", IsInvisible);
IsProximityArmed = ini.Get_Bool(Name(), "Proximity", IsProximityArmed);
IsFlameEquipped = ini.Get_Bool(Name(), "Animates", IsFlameEquipped);
IsFueled = ini.Get_Bool(Name(), "Ranged", IsFueled);
IsInaccurate = ini.Get_Bool(Name(), "Inaccuate", IsInaccurate);
IsAntiAircraft = ini.Get_Bool(Name(), "AA", IsAntiAircraft);
IsAntiGround = ini.Get_Bool(Name(), "AG", IsAntiGround);
IsAntiSub = ini.Get_Bool(Name(), "ASW", IsAntiSub);
IsDegenerate = ini.Get_Bool(Name(), "Degenerates", IsDegenerate);
IsSubSurface = ini.Get_Bool(Name(), "UnderWater", IsSubSurface);
IsParachuted = ini.Get_Bool(Name(), "Parachuted", IsParachuted);
IsFaceless = !ini.Get_Bool(Name(), "Rotates", !IsFaceless);
IsTranslucent = ini.Get_Bool(Name(), "Translucent", IsTranslucent);
IsGigundo = ini.Get_Bool(Name(), "Gigundo", IsGigundo);
ini.Get_String(Name(), "Image", "none", GraphicName, sizeof(GraphicName));
return(true);
}
return(false);
}

3834
CODE/BDATA.CPP Normal file

File diff suppressed because it is too large Load diff

167
CODE/BENCH.CPP Normal file
View file

@ -0,0 +1,167 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/BENCH.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : BENCH.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 07/17/96 *
* *
* Last Update : July 18, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* Benchmark::Begin -- Start the benchmark operation. *
* Benchmark::Benchmark -- Constructor for the benchmark object. *
* Benchmark::End -- Mark the end of a benchmarked operation *
* Benchmark::Reset -- Clear out the benchmark statistics. *
* Benchmark::Value -- Fetch the current average benchmark time. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "bench.h"
#include "mpu.h"
/***********************************************************************************************
* Benchmark::Benchmark -- Constructor for the benchmark object. *
* *
* This will construct the benchmark object. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/18/1996 JLB : Created. *
*=============================================================================================*/
Benchmark::Benchmark(void) :
Average(0),
Counter(0),
TotalCount(0)
{
}
/***********************************************************************************************
* Benchmark::Reset -- Clear out the benchmark statistics. *
* *
* Use this routine to clear out all the accumulated statistics within this benchmark *
* object. The object is set just as if it was freshly constructed. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/18/1996 JLB : Created. *
*=============================================================================================*/
void Benchmark::Reset(void)
{
Average = 0;
Counter = 0;
TotalCount = 0;
}
/***********************************************************************************************
* Benchmark::Begin -- Start the benchmark operation. *
* *
* Call this routine before the operation to be benchmarked is begun. The corresponding *
* End() function must be called after the operation has completed. *
* *
* INPUT: reset -- Should the entire benchmark object be reset at this time as well? *
* *
* OUTPUT: none *
* *
* WARNINGS: The Begin() and End() functions are NOT nestable. *
* *
* HISTORY: *
* 07/18/1996 JLB : Created. *
*=============================================================================================*/
void Benchmark::Begin(bool reset)
{
if (reset) Reset();
Clock = 0;
}
/***********************************************************************************************
* Benchmark::End -- Mark the end of a benchmarked operation *
* *
* This routine is called at the end of the operation that is being benchmarked. It is *
* important to call this routine as soon as possible after the event being benchmarked *
* has completed. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: The Being() and End() functions are NOT nestable. *
* *
* HISTORY: *
* 07/18/1996 JLB : Created. *
*=============================================================================================*/
void Benchmark::End(void)
{
unsigned long value = Clock;
if (Counter == MAXIMUM_EVENT_COUNT) {
Average -= Average / MAXIMUM_EVENT_COUNT;
Average += value;
} else {
Average += value;
Counter++;
}
TotalCount++;
}
/***********************************************************************************************
* Benchmark::Value -- Fetch the current average benchmark time. *
* *
* This routine will take the statistics already accumulated and determine the average *
* time recorded. This value will be returned. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the average time that all events tracked by this object. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/18/1996 JLB : Created. *
*=============================================================================================*/
unsigned long Benchmark::Value(void) const
{
if (Counter) {
return(Average / Counter);
}
return(0);
}

122
CODE/BENCH.H Normal file
View file

@ -0,0 +1,122 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/BENCH.H 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : BENCH.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 07/17/96 *
* *
* Last Update : July 17, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef BENCH_H
#define BENCH_H
#include "mpu.h"
#include "ftimer.h"
/*
** The "bool" integral type was defined by the C++ committee in
** November of '94. Until the compiler supports this, use the following
** definition.
*/
#ifndef __BORLANDC__
#ifndef TRUE_FALSE_DEFINED
#define TRUE_FALSE_DEFINED
enum {false=0,true=1};
typedef int bool;
#endif
#endif
/*
** This is a timer access object that will fetch the internal Pentium
** clock value.
*/
class PentiumTimerClass
{
public:
unsigned long operator () (void) const {unsigned long h;unsigned long l = Get_CPU_Clock(h);return((l >> 4) | (h << 28));}
operator unsigned long (void) const {unsigned long h;unsigned long l = Get_CPU_Clock(h);return((l >> 4) | (h << 28));}
};
/*
** A performance tracking tool object. It is used to track elapsed time. Unlike a simple clock, this
** class will keep a running average of the duration. Typical use of this would be to benchmark some
** process that occurs multiple times. By benchmarking an average time, inconsistencies in a particular
** run can be overcome.
*/
class Benchmark
{
public:
Benchmark(void);
void Begin(bool reset=false);
void End(void);
void Reset(void);
unsigned long Value(void) const;
unsigned long Count(void) const {return(TotalCount);}
private:
/*
** The maximum number of events to keep running average of. If
** events exceed this number, then older events drop off the
** accumulated time. This number needs to be as small as
** is reasonable. The larger this number gets, the less magnitude
** that the benchmark timer can handle. Example; At a value of
** 256, the magnitude of the timer can only be 24 bits.
*/
enum {MAXIMUM_EVENT_COUNT=256};
/*
** This is the timer the is used to clock the events.
*/
BasicTimerClass<PentiumTimerClass> Clock;
/*
** The total time off all events tracked so far.
*/
unsigned long Average;
/*
** The total number of events tracked so far.
*/
unsigned long Counter;
/*
** Absolute total number of events (possibly greater than the
** number of events tracked in the average).
*/
unsigned long TotalCount;
};
#endif

2122
CODE/BFILE.MAK Normal file

File diff suppressed because it is too large Load diff

2098
CODE/BFILE2.MAK Normal file

File diff suppressed because it is too large Load diff

987
CODE/BFIOFILE.CPP Normal file
View file

@ -0,0 +1,987 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/BFIOFILE.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Westwood Library *
* *
* File Name : RAMFILE.CPP *
* *
* Programmer : David R. Dettmer *
* *
* Start Date : November 10, 1995 *
* *
* Last Update : November 10, 1995 [DRD] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* BufferIOFileClass::BufferIOFileClass -- Filename based constructor for a file object. *
* BufferIOFileClass::BufferIOFileClass -- default constructor for a file object. *
* BufferIOFileClass::Cache -- Load part or all of a file data into RAM. *
* BufferIOFileClass::Close -- Perform a closure of the file. *
* BufferIOFileClass::Commit -- Writes the cache to the file if it has changed. *
* BufferIOFileClass::Free -- Frees the allocated buffer. *
* BufferIOFileClass::Is_Available -- Checks for existence of file cached or on disk. *
* BufferIOFileClass::Is_Open -- Determines if the file is open. *
* BufferIOFileClass::Open -- Assigns name and opens file in one operation. *
* BufferIOFileClass::Open -- Opens the file object with the rights specified. *
* BufferIOFileClass::Read -- Reads data from the file cache. *
* BufferIOFileClass::Seek -- Moves the current file pointer in the file. *
* BufferIOFileClass::Set_Name -- Checks for name changed for a cached file. *
* BufferIOFileClass::Size -- Determines size of file (in bytes). *
* BufferIOFileClass::Write -- Writes data to the file cache. *
* BufferIOFileClass::~BufferIOFileClass -- Destructor for the file object. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "bfiofile.h"
#include <string.h>
/***********************************************************************************************
* BufferIOFileClass::BufferIOFileClass -- Filename based constructor for a file object. *
* *
* This constructor is called when a file object is created with a supplied filename, but *
* not opened at the same time. In this case, an assumption is made that the supplied *
* filename is a constant string. A duplicate of the filename string is not created since *
* it would be wasteful in that case. *
* *
* INPUT: filename -- The filename to assign to this file object. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/10/1995 DRD : Created. *
*=============================================================================================*/
BufferIOFileClass::BufferIOFileClass(char const * filename) :
IsAllocated(false),
IsOpen(false),
IsDiskOpen(false),
IsCached(false),
IsChanged(false),
UseBuffer(false),
BufferRights(0),
Buffer(0),
BufferSize(0),
BufferPos(0),
BufferFilePos(0),
BufferChangeBeg(-1),
BufferChangeEnd(-1),
FileSize(0),
FilePos(0),
TrueFileStart(0)
{
BufferIOFileClass::Set_Name(filename);
}
/***********************************************************************************************
* BufferIOFileClass::BufferIOFileClass -- default constructor for a file object. *
* *
* This is the default constructor for a file object. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/10/1995 DRD : Created. *
*=============================================================================================*/
BufferIOFileClass::BufferIOFileClass(void) :
IsAllocated(false),
IsOpen(false),
IsDiskOpen(false),
IsCached(false),
IsChanged(false),
UseBuffer(false),
BufferRights(0),
Buffer(0),
BufferSize(0),
BufferPos(0),
BufferFilePos(0),
BufferChangeBeg(-1),
BufferChangeEnd(-1),
FileSize(0),
FilePos(0),
TrueFileStart(0)
{
}
/***********************************************************************************************
* BufferIOFileClass::~BufferIOFileClass -- Destructor for the file object. *
* *
* This destructor will free all memory allocated thru using Cache routines. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/10/1995 DRD : Created. *
*=============================================================================================*/
BufferIOFileClass::~BufferIOFileClass(void)
{
Free();
}
/***********************************************************************************************
* BufferIOFileClass::Cache -- Load part or all of a file data into RAM. *
* *
* INPUT: none *
* *
* OUTPUT: bool; Was the file load successful? It could fail if there wasn't enough room *
* to allocate the raw data block. *
* *
* WARNINGS: This routine goes to disk for a potentially very long time. *
* *
* HISTORY: *
* 11/10/1995 DRD : Created. *
*=============================================================================================*/
bool BufferIOFileClass::Cache( long size, void * ptr )
{
if (Buffer) {
//
// if trying to cache again with size or ptr fail
//
if (size || ptr) {
return( false );
} else {
return( true );
}
}
if ( Is_Available() ) {
FileSize = Size();
} else {
FileSize = 0;
}
if (size) {
//
// minimum buffer size for performance
//
if (size < MINIMUM_BUFFER_SIZE) {
size = MINIMUM_BUFFER_SIZE;
/*
** Specifying a size smaller than the minimum is an error
** IF a buffer pointer was also specified. In such a case the
** system cannot use the buffer.
*/
if (ptr) {
Error(EINVAL);
}
}
BufferSize = size;
} else {
BufferSize = FileSize;
}
//
// if size == 0 and a ptr to a buffer is specified then that is invalid.
// if the BufferSize is 0 then this must be a new file and no size was
// specified so exit.
//
if ( (size == 0 && ptr) || !BufferSize) {
return( false );
}
if (ptr) {
Buffer = ptr;
} else {
Buffer = new char [BufferSize];
}
if (Buffer) {
IsAllocated = true;
IsDiskOpen = false;
BufferPos = 0;
BufferFilePos = 0;
BufferChangeBeg = -1;
BufferChangeEnd = -1;
FilePos = 0;
TrueFileStart = 0;
//
// the file was checked for availability then set the FileSize
//
if (FileSize) {
long readsize;
int opened = false;
long prevpos = 0;
if (FileSize <= BufferSize) {
readsize = FileSize;
} else {
readsize = BufferSize;
}
if ( Is_Open() ) {
//
// get previous file position
//
prevpos = Seek(0);
//
// get true file position
//
if ( RawFileClass::Is_Open() ) {
TrueFileStart = RawFileClass::Seek(0);
} else {
TrueFileStart = prevpos;
}
if (FileSize <= BufferSize) {
//
// if previous position is non-zero seek to the beginning
//
if (prevpos) {
Seek(0, SEEK_SET);
}
//
// set the buffer position for future reads/writes
//
BufferPos = prevpos;
} else {
BufferFilePos = prevpos;
}
FilePos = prevpos;
} else {
if ( Open() ) {
TrueFileStart = RawFileClass::Seek(0);
opened = true;
}
}
long actual = Read(Buffer, readsize);
if (actual != readsize) {
Error(EIO);
}
if (opened) {
Close();
} else {
//
// seek to the previous position in the file
//
Seek(prevpos, SEEK_SET);
}
IsCached = true;
}
UseBuffer = true;
return(true);
}
Error(ENOMEM);
return(false);
}
/***********************************************************************************************
* BufferIOFileClass::Free -- Frees the allocated buffer. *
* *
* This routine will free the buffer. By using this in conjunction with the *
* Cache() function, one can maintain tight control of memory usage. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/10/1995 DRD : Created. *
*=============================================================================================*/
void BufferIOFileClass::Free(void)
{
if (Buffer) {
if (IsAllocated) {
delete [] Buffer;
IsAllocated = false;
}
Buffer = 0;
}
BufferSize = 0;
IsOpen = false;
IsCached = false;
IsChanged = false;
UseBuffer = false;
}
/***********************************************************************************************
* BufferIOFileClass::Commit -- Writes the cache to the file if it has changed. *
* *
* *
* INPUT: none *
* *
* OUTPUT: false, did not need to write the buffer. *
* true, wrote the buffer. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/15/1995 DRD : Created. *
*=============================================================================================*/
bool BufferIOFileClass::Commit( void )
{
long size;
if (UseBuffer) {
if (IsChanged) {
size = BufferChangeEnd - BufferChangeBeg;
if (IsDiskOpen) {
RawFileClass::Seek( TrueFileStart + BufferFilePos +
BufferChangeBeg, SEEK_SET );
RawFileClass::Write( Buffer, size );
RawFileClass::Seek( TrueFileStart + FilePos, SEEK_SET );
} else {
RawFileClass::Open();
RawFileClass::Seek( TrueFileStart + BufferFilePos +
BufferChangeBeg, SEEK_SET );
RawFileClass::Write( Buffer, size );
RawFileClass::Close();
}
IsChanged = false;
return( true );
} else {
return( false );
}
} else {
return( false );
}
}
/***********************************************************************************************
* BufferIOFileClass::Set_Name -- Checks for name changed for a cached file. *
* *
* Checks for a previous filename and that it is cached. If so, then check the *
* new filename against the old. If they are the same then return that filename. *
* Otherwise, the file object's name is set with just the raw filename as passed *
* to this routine. *
* *
* INPUT: filename -- Pointer to the filename to set as the name of this file object. *
* *
* OUTPUT: Returns a pointer to the final and complete filename of this file object. This *
* may have a path attached to the file. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/15/1995 DRD : Created. *
*=============================================================================================*/
char const * BufferIOFileClass::Set_Name(char const * filename)
{
if ( File_Name() && UseBuffer) {
if ( strcmp(filename, File_Name() ) == 0) {
return( File_Name() );
} else {
Commit();
IsCached = false;
}
}
RawFileClass::Set_Name(filename);
return( File_Name() );
}
/***********************************************************************************************
* BufferIOFileClass::Is_Available -- Checks for existence of file cached or on disk. *
* *
* *
* INPUT: none *
* *
* OUTPUT: bool; Is the file available for opening? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/16/1995 DRD : Created. *
*=============================================================================================*/
int BufferIOFileClass::Is_Available(int )
{
if (UseBuffer) {
return(true);
}
return( RawFileClass::Is_Available() );
}
/***********************************************************************************************
* BufferIOFileClass::Is_Open -- Determines if the file is open. *
* *
* If part or all of the file is cached, then return that it is opened. A closed file *
* doesn't have a valid pointer. *
* *
* INPUT: none *
* *
* OUTPUT: bool; Is the file open? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/14/1995 DRD : Created. *
*=============================================================================================*/
int BufferIOFileClass::Is_Open(void) const
{
if (IsOpen && UseBuffer) {
return( true );
}
return( RawFileClass::Is_Open() );
}
/***********************************************************************************************
* BufferIOFileClass::Open -- Assigns name and opens file in one operation. *
* *
* This routine will assign the specified filename to the file object and open it at the *
* same time. If the file object was already open, then it will be closed first. If the *
* file object was previously assigned a filename, then it will be replaced with the new *
* name. Typically, this routine is used when an anonymous file object has been crated and *
* now it needs to be assigned a name and opened. *
* *
* INPUT: filename -- The filename to assign to this file object. *
* *
* rights -- The open file access rights to use. *
* *
* OUTPUT: bool; Was the file opened? The return value of this is moot, since the open file *
* is designed to never return unless it succeeded. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/14/1995 DRD : Created. *
*=============================================================================================*/
int BufferIOFileClass::Open(char const * filename, int rights)
{
Set_Name(filename);
return( BufferIOFileClass::Open( rights ) );
}
/***********************************************************************************************
* BufferIOFileClass::Open -- Opens the file object with the rights specified. *
* *
* This routine is used to open the specified file object with the access rights indicated. *
* This only works if the file has already been assigned a filename. It is guaranteed, by *
* the error handler, that this routine will always return with success. *
* *
* INPUT: rights -- The file access rights to use when opening this file. This is a *
* combination of READ and/or WRITE bit flags. *
* *
* OUTPUT: bool; Was the file opened successfully? This will always return true by reason of *
* the error handler. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/14/1995 DRD : Created. *
*=============================================================================================*/
int BufferIOFileClass::Open(int rights)
{
BufferIOFileClass::Close();
if (UseBuffer) {
BufferRights = rights; // save rights requested for checks later
if (rights != READ ||
(rights == READ && FileSize > BufferSize) ) {
if (rights == WRITE) {
RawFileClass::Open( rights );
RawFileClass::Close();
rights = READ | WRITE;
TrueFileStart = 0; // now writing to single file
}
if (TrueFileStart) {
UseBuffer = false;
Open( rights );
UseBuffer = true;
} else {
RawFileClass::Open( rights );
}
IsDiskOpen = true;
if (BufferRights == WRITE) {
FileSize = 0;
}
} else {
IsDiskOpen = false;
}
BufferPos = 0;
BufferFilePos = 0;
BufferChangeBeg = -1;
BufferChangeEnd = -1;
FilePos = 0;
IsOpen = true;
} else {
RawFileClass::Open( rights );
}
return( true );
}
/***********************************************************************************************
* BufferIOFileClass::Write -- Writes data to the file cache. *
* *
* *
* INPUT: buffer -- Pointer to the buffer that holds the data to be written. *
* *
* size -- The number of bytes to write. *
* *
* OUTPUT: Returns the number of bytes actually written. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/15/1995 DRD : Created. *
*=============================================================================================*/
long BufferIOFileClass::Write(void const * buffer, long size)
{
int opened = false;
if ( !Is_Open() ) {
if (!Open(WRITE)) {
return(0);
}
TrueFileStart = RawFileClass::Seek(0);
opened = true;
}
if (UseBuffer) {
long sizewritten = 0;
if (BufferRights != READ) {
while (size) {
long sizetowrite;
if (size >= (BufferSize - BufferPos) ) {
sizetowrite = (BufferSize - BufferPos);
} else {
sizetowrite = size;
}
if (sizetowrite != BufferSize) {
if ( !IsCached ) {
long readsize;
if (FileSize < BufferSize) {
readsize = FileSize;
BufferFilePos = 0;
} else {
readsize = BufferSize;
BufferFilePos = FilePos;
}
if (TrueFileStart) {
UseBuffer = false;
Seek( FilePos, SEEK_SET );
Read( Buffer, BufferSize );
Seek( FilePos, SEEK_SET );
UseBuffer = true;
} else {
RawFileClass::Seek( BufferFilePos, SEEK_SET );
RawFileClass::Read( Buffer, readsize );
}
BufferPos = 0;
BufferChangeBeg = -1;
BufferChangeEnd = -1;
IsCached = true;
}
}
memmove((char *)Buffer + BufferPos, (char *)buffer + sizewritten, sizetowrite);
IsChanged = true;
sizewritten += sizetowrite;
size -= sizetowrite;
if (BufferChangeBeg == -1) {
BufferChangeBeg = BufferPos;
BufferChangeEnd = BufferPos;
} else {
if (BufferChangeBeg > BufferPos) {
BufferChangeBeg = BufferPos;
}
}
BufferPos += sizetowrite;
if (BufferChangeEnd < BufferPos) {
BufferChangeEnd = BufferPos;
}
FilePos = BufferFilePos + BufferPos;
if (FileSize < FilePos) {
FileSize = FilePos;
}
//
// end of buffer reached?
//
if (BufferPos == BufferSize) {
Commit();
BufferPos = 0;
BufferFilePos = FilePos;
BufferChangeBeg = -1;
BufferChangeEnd = -1;
if (size && FileSize > FilePos) {
if (TrueFileStart) {
UseBuffer = false;
Seek( FilePos, SEEK_SET );
Read( Buffer, BufferSize );
Seek( FilePos, SEEK_SET );
UseBuffer = true;
} else {
RawFileClass::Seek( FilePos, SEEK_SET );
RawFileClass::Read( Buffer, BufferSize );
}
} else {
IsCached = false;
}
}
}
} else {
Error(EACCES);
}
size = sizewritten;
} else {
size = RawFileClass::Write(buffer, size);
}
if (opened) {
Close();
}
return( size );
}
/***********************************************************************************************
* BufferIOFileClass::Read -- Reads data from the file cache. *
* *
* *
* INPUT: buffer -- Pointer to the buffer to place the read data. *
* *
* size -- The number of bytes to read. *
* *
* OUTPUT: Returns the actual number of bytes read (this could be less than requested). *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/15/1995 DRD : Created. *
*=============================================================================================*/
long BufferIOFileClass::Read(void * buffer, long size)
{
int opened = false;
if ( !Is_Open() ) {
if ( Open() ) {
TrueFileStart = RawFileClass::Seek(0);
opened = true;
}
}
if (UseBuffer) {
long sizeread = 0;
if (BufferRights != WRITE) {
while (size) {
long sizetoread;
if (size >= (BufferSize - BufferPos) ) {
sizetoread = (BufferSize - BufferPos);
} else {
sizetoread = size;
}
if ( !IsCached ) {
long readsize;
if (FileSize < BufferSize) {
readsize = FileSize;
BufferFilePos = 0;
} else {
readsize = BufferSize;
BufferFilePos = FilePos;
}
if (TrueFileStart) {
UseBuffer = false;
Seek( FilePos, SEEK_SET );
Read( Buffer, BufferSize );
Seek( FilePos, SEEK_SET );
UseBuffer = true;
} else {
RawFileClass::Seek( BufferFilePos, SEEK_SET );
RawFileClass::Read( Buffer, readsize );
}
BufferPos = 0;
BufferChangeBeg = -1;
BufferChangeEnd = -1;
IsCached = true;
}
memmove((char *)buffer + sizeread, (char *)Buffer + BufferPos, sizetoread);
sizeread += sizetoread;
size -= sizetoread;
BufferPos += sizetoread;
FilePos = BufferFilePos + BufferPos;
//
// end of buffer reached?
//
if (BufferPos == BufferSize) {
Commit();
BufferPos = 0;
BufferFilePos = FilePos;
BufferChangeBeg = -1;
BufferChangeEnd = -1;
if (size && FileSize > FilePos) {
if (TrueFileStart) {
UseBuffer = false;
Seek( FilePos, SEEK_SET );
Read( Buffer, BufferSize );
Seek( FilePos, SEEK_SET );
UseBuffer = true;
} else {
RawFileClass::Seek( FilePos, SEEK_SET );
RawFileClass::Read( Buffer, BufferSize );
}
} else {
IsCached = false;
}
}
}
} else {
Error(EACCES);
}
size = sizeread;
} else {
size = RawFileClass::Read(buffer, size);
}
if (opened) {
Close();
}
return( size );
}
/***********************************************************************************************
* BufferIOFileClass::Seek -- Moves the current file pointer in the file. *
* *
* This routine will change the current file pointer to the position specified. It follows *
* the same rules the a normal Seek() does, but if the file is part of the mixfile system, *
* then only the position value needs to be updated. *
* *
* INPUT: pos -- The position to move the file to relative to the position indicated *
* by the "dir" parameter. *
* *
* dir -- The direction to affect the position change against. This can be *
* either SEEK_CUR, SEEK_END, or SEEK_SET. *
* *
* OUTPUT: Returns with the position of the new location. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/15/1995 DRD : Created. *
*=============================================================================================*/
long BufferIOFileClass::Seek(long pos, int dir)
{
if (UseBuffer) {
bool adjusted = false;
switch (dir) {
case SEEK_END:
FilePos = FileSize;
break;
case SEEK_SET:
FilePos = 0;
break;
case SEEK_CUR:
default:
break;
}
if (TrueFileStart) {
if (pos >= TrueFileStart) {
pos -= TrueFileStart;
adjusted = true;
}
}
FilePos += pos;
if (FilePos < 0) {
FilePos = 0;
}
if (FilePos > FileSize ) {
FilePos = FileSize;
}
if (FileSize <= BufferSize) {
BufferPos = FilePos;
} else {
if (FilePos >= BufferFilePos &&
FilePos < (BufferFilePos + BufferSize) ) {
BufferPos = FilePos - BufferFilePos;
} else {
Commit();
// check!!
if (TrueFileStart) {
UseBuffer = false;
Seek(FilePos, SEEK_SET);
UseBuffer = true;
} else {
RawFileClass::Seek(FilePos, SEEK_SET);
}
IsCached = false;
}
}
if (TrueFileStart && adjusted) {
return( FilePos + TrueFileStart );
}
return( FilePos );
}
return( RawFileClass::Seek(pos, dir) );
}
/***********************************************************************************************
* BufferIOFileClass::Size -- Determines size of file (in bytes). *
* *
* If part or all of the file is cached, then the size of the file is already *
* determined and available. Otherwise, go to the low level system to find the file *
* size. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the number of bytes in the file. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/14/1995 DRD : Created. *
*=============================================================================================*/
long BufferIOFileClass::Size(void)
{
if (IsOpen && UseBuffer) {
return( FileSize );
}
return( RawFileClass::Size() );
}
/***********************************************************************************************
* BufferIOFileClass::Close -- Perform a closure of the file. *
* *
* Call Commit() to write the buffer if the file is cached and the buffer has changed, *
* then call lower level Close(). *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/14/1995 DRD : Created. *
*=============================================================================================*/
void BufferIOFileClass::Close(void)
{
if (UseBuffer) {
Commit();
if (IsDiskOpen) {
if (TrueFileStart) {
UseBuffer = false;
Close();
UseBuffer = true;
} else {
RawFileClass::Close();
}
IsDiskOpen = false;
}
IsOpen = false;
} else {
RawFileClass::Close();
}
}

95
CODE/BFIOFILE.H Normal file
View file

@ -0,0 +1,95 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/BFIOFILE.H 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Westwood Library *
* *
* File Name : BFIOFILE.H *
* *
* Programmer : David R. Dettmer *
* *
* Start Date : November 10, 1995 *
* *
* Last Update : November 10, 1995 [DRD] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef BFIOFILE_H
#define BFIOFILE_H
#include "rawfile.h"
/*
** This derivation of the raw file class handles buffering the input/output in order to
** achieve greater speed. The buffering is not active by default. It must be activated
** by setting the appropriate buffer through the Cache() function.
*/
class BufferIOFileClass : public RawFileClass
{
public:
BufferIOFileClass(char const *filename);
BufferIOFileClass(void);
virtual ~BufferIOFileClass(void);
bool Cache( long size=0, void *ptr=NULL );
void Free( void );
bool Commit( void );
virtual char const * Set_Name(char const *filename);
virtual int Is_Available(int forced=false);
virtual int Is_Open(void) const;
virtual int Open(char const *filename, int rights=READ);
virtual int Open(int rights=READ);
virtual long Read(void *buffer, long size);
virtual long Seek(long pos, int dir=SEEK_CUR);
virtual long Size(void);
virtual long Write(void const *buffer, long size);
virtual void Close(void);
enum {MINIMUM_BUFFER_SIZE=1024};
private:
unsigned IsAllocated:1;
unsigned IsOpen:1;
unsigned IsDiskOpen:1;
unsigned IsCached:1;
unsigned IsChanged:1;
unsigned UseBuffer:1;
int BufferRights;
void *Buffer;
long BufferSize;
long BufferPos;
long BufferFilePos;
long BufferChangeBeg;
long BufferChangeEnd;
long FileSize;
long FilePos;
long TrueFileStart;
};
#endif

84
CODE/BIGCHECK.CPP Normal file
View file

@ -0,0 +1,84 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// BigCheck.cpp
// ajw 9/14/98
#ifdef WOLAPI_INTEGRATION
#include "function.h"
#include "bigcheck.h"
//***********************************************************************************************
int BigCheckBoxClass::Draw_Me( int forced )
{
if (ToggleClass::Draw_Me(forced))
{
Hide_Mouse();
if( !IsOn )
{
if( !IsDisabled )
CC_Draw_Shape( MFCD::Retrieve( "bigcheck.shp" ), 0, X, Y, WINDOW_MAIN, SHAPE_NORMAL );
else
CC_Draw_Shape( MFCD::Retrieve( "bigcheck.shp" ), 2, X, Y, WINDOW_MAIN, SHAPE_NORMAL );
}
else
{
if( !IsDisabled )
CC_Draw_Shape( MFCD::Retrieve( "bigcheck.shp" ), 1, X, Y, WINDOW_MAIN, SHAPE_NORMAL );
else
CC_Draw_Shape( MFCD::Retrieve( "bigcheck.shp" ), 3, X, Y, WINDOW_MAIN, SHAPE_NORMAL );
}
TextPrintType flags = TextFlags;
RemapControlType* pScheme;
// if( !IsDisabled )
pScheme = GadgetClass::Get_Color_Scheme();
// else
// {
// pScheme = &GreyScheme;
// flags = flags | TPF_MEDIUM_COLOR;
// }
Conquer_Clip_Text_Print( szCaption, X + BIGCHECK_OFFSETX, Y + BIGCHECK_OFFSETY, pScheme, TBLACK, flags, Width, 0 );
Show_Mouse();
return true;
}
return false;
}
//***********************************************************************************************
int BigCheckBoxClass::Action(unsigned flags, KeyNumType & key)
{
/* if( flags & LEFTPRESS )
{
if (IsOn) {
Turn_Off();
} else {
Turn_On();
}
}
*/
return(ToggleClass::Action(flags, key));
}
#endif

74
CODE/BIGCHECK.H Normal file
View file

@ -0,0 +1,74 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Bigcheck.h
// ajw 9/14/98
#ifdef WOLAPI_INTEGRATION
#ifndef BIGCHECKBOX_H
#define BIGCHECKBOX_H
#include "toggle.h"
#define BIGCHECK_OFFSETX 20
#define BIGCHECK_OFFSETY 0
//***********************************************************************************************
class BigCheckBoxClass : public ToggleClass
{
public:
BigCheckBoxClass( unsigned id, int x, int y, int w, int h, const char* szCaptionIn, TextPrintType TextFlags,
bool bInitiallyChecked = false ) :
ToggleClass( id, x, y, w, h ),
TextFlags( TextFlags )
{
szCaption = new char[ strlen( szCaptionIn ) + 1 ];
strcpy( szCaption, szCaptionIn );
if( bInitiallyChecked )
Turn_On();
IsToggleType = 1;
}
virtual ~BigCheckBoxClass()
{
delete [] szCaption;
}
virtual int Draw_Me(int forced=false);
virtual int Action(unsigned flags, KeyNumType & key);
bool Toggle()
{
if( IsOn )
{
Turn_Off();
return false;
}
Turn_On();
return true;
}
protected:
TextPrintType TextFlags;
char* szCaption;
};
#endif
#endif

598
CODE/BLOWFISH.CPP Normal file
View file

@ -0,0 +1,598 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/BLOWFISH.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : BLOWFISH.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 04/14/96 *
* *
* Last Update : July 8, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* BlowfishEngine::Decrypt -- Decrypts data using blowfish algorithm. *
* BlowfishEngine::Encrypt -- Encrypt an arbitrary block of data. *
* BlowfishEngine::Process_Block -- Process a block of data using Blowfish algorithm. *
* BlowfishEngine::Sub_Key_Encrypt -- Encrypts a block for use in S-Box processing. *
* BlowfishEngine::Submit_Key -- Submit a key that will allow data processing. *
* BlowfishEngine::~BlowfishEngine -- Destructor for the Blowfish engine. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "blowfish.h"
#include <string.h>
#include <assert.h>
/*
** Byte order controlled long integer. This integer is constructed
** so that character 0 (C0) is the most significant byte of the
** integer. This is biased toward big endian architecture, but that
** just happens to be how the Blowfish algorithm was designed.
*/
typedef union {
unsigned long Long;
struct {
unsigned char C3;
unsigned char C2;
unsigned char C1;
unsigned char C0;
} Char;
} Int;
/***********************************************************************************************
* BlowfishEngine::~BlowfishEngine -- Destructor for the Blowfish engine. *
* *
* This destructor will clear out the s-box tables so that even if the memory for the *
* class remains, it will contain no compromising data. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/08/1996 JLB : Created. *
*=============================================================================================*/
BlowfishEngine::~BlowfishEngine(void)
{
if (IsKeyed) {
Submit_Key(NULL, 0);
}
}
/***********************************************************************************************
* BlowfishEngine::Submit_Key -- Submit a key that will allow data processing. *
* *
* This routine must be called before any data can be encrypted or decrypted. This routine *
* need only be called when the key is to be changed or set for the first time. Once the *
* key has been set, the engine may be used to encrypt, decrypt, or both operations *
* indefinitely. The key must be 56 bytes or less in length. This is necessary because *
* any keys longer than that will not correctly affect the encryption process. *
* *
* If the key pointer is NULL, then the S-Box tables are reset to identity. This will *
* mask the previous key setting. Use this method to clear the engine after processing in *
* order to gain a measure of security. *
* *
* INPUT: key -- Pointer to the key data block. *
* *
* length -- The length of the submitted key. *
* *
* OUTPUT: none *
* *
* WARNINGS: This is a time consuming process. *
* *
* HISTORY: *
* 04/14/1996 JLB : Created. *
*=============================================================================================*/
void BlowfishEngine::Submit_Key(void const * key, int length)
{
assert(length <= MAX_KEY_LENGTH);
/*
** Initialize the permutation and S-Box tables to a known
** constant value.
*/
memcpy(P_Encrypt, P_Init, sizeof(P_Init));
memcpy(P_Decrypt, P_Init, sizeof(P_Init));
memcpy(bf_S, S_Init, sizeof(S_Init));
/*
** Validate parameters.
*/
if (key == 0 || length == 0) {
IsKeyed = false;
return;
}
/*
** Combine the key with the permutation table. Wrap the key
** as many times as necessary to ensure that the entire
** permutation table has been modified. The key is lifted
** into a long by using endian independent means.
*/
int j = 0;
unsigned char const * key_ptr = (unsigned char const *)key;
unsigned long * p_ptr = &P_Encrypt[0];
for (int index = 0; index < ROUNDS+2; index++) {
unsigned long data = 0;
data = (data << CHAR_BIT) | key_ptr[j++ % length];
data = (data << CHAR_BIT) | key_ptr[j++ % length];
data = (data << CHAR_BIT) | key_ptr[j++ % length];
data = (data << CHAR_BIT) | key_ptr[j++ % length];
*p_ptr++ ^= data;
}
/*
** The permutation table must be scrambled by means of the key. This
** is how the key is factored into the encryption -- by merely altering
** the permutation (and S-Box) tables. Because this transformation alters
** the table data WHILE it is using the table data, the tables are
** thoroughly obfuscated by this process.
*/
unsigned long left = 0x00000000L;
unsigned long right = 0x00000000L;
unsigned long * p_en = &P_Encrypt[0]; // Encryption table.
unsigned long * p_de = &P_Decrypt[ROUNDS+1]; // Decryption table.
for (int p_index = 0; p_index < ROUNDS+2; p_index += 2) {
Sub_Key_Encrypt(left, right);
*p_en++ = left;
*p_en++ = right;
*p_de-- = left;
*p_de-- = right;
}
/*
** Perform a similar transmutation to the S-Box tables. Also notice that the
** working 64 bit number is carried into this process from the previous
** operation.
*/
for (int sbox_index = 0; sbox_index < 4; sbox_index++) {
for (int ss_index = 0; ss_index < UCHAR_MAX+1; ss_index += 2) {
Sub_Key_Encrypt(left, right);
bf_S[sbox_index][ss_index] = left;
bf_S[sbox_index][ss_index + 1] = right;
}
}
IsKeyed = true;
}
/***********************************************************************************************
* BlowfishEngine::Encrypt -- Encrypt an arbitrary block of data. *
* *
* Use this routine to encrypt an arbitrary block of data. The block must be an even *
* multiple of 8 bytes. Any bytes left over will not be encrypted. The 8 byte requirement *
* is necessary because the underlying algorithm processes blocks in 8 byte chunks. *
* Partial blocks are unrecoverable and useless. *
* *
* INPUT: plaintext-- Pointer to the data block to be encrypted. *
* *
* length -- The length of the data block. *
* *
* cyphertext- Pointer to the output buffer that will hold the encrypted data. *
* *
* OUTPUT: Returns with the actual number of bytes encrypted. *
* *
* WARNINGS: You must submit the key before calling this routine. This will only encrypt *
* the plaintext in 8 byte increments. Modulo bytes left over are not processed. *
* *
* HISTORY: *
* 04/14/1996 JLB : Created. *
*=============================================================================================*/
int BlowfishEngine::Encrypt(void const * plaintext, int length, void * cyphertext)
{
if (plaintext == 0 || length == 0) {
return(0);
}
if (cyphertext == 0) cyphertext = (void *)plaintext;
if (IsKeyed) {
/*
** Validate parameters.
*/
int blocks = length / BYTES_PER_BLOCK;
/*
** Process the buffer in 64 bit chunks.
*/
for (int index = 0; index < blocks; index++) {
Process_Block(plaintext, cyphertext, P_Encrypt);
plaintext = ((char *)plaintext) + BYTES_PER_BLOCK;
cyphertext = ((char *)cyphertext) + BYTES_PER_BLOCK;
}
int encrypted = blocks * BYTES_PER_BLOCK;
/*
** Copy over any trailing left over appendix bytes.
*/
if (encrypted < length) {
memmove(cyphertext, plaintext, length - encrypted);
}
return(encrypted);
}
/*
** Non-keyed processing merely copies the data.
*/
if (plaintext != cyphertext) {
memmove(cyphertext, plaintext, length);
}
return(length);
}
/***********************************************************************************************
* BlowfishEngine::Decrypt -- Decrypt an arbitrary block of data. *
* *
* Use this routine to decrypt an arbitrary block of data. The block must be an even *
* multiple of 8 bytes. Any bytes left over will not be decrypted. The 8 byte requirement *
* is necessary because the underlying algorithm processes blocks in 8 byte chunks. *
* Partial blocks are unrecoverable and useless. *
* *
* INPUT: cyphertext- Pointer to the data block to be decrypted. *
* *
* length -- The length of the data block. *
* *
* plaintext-- Pointer to the output buffer that will hold the decrypted data. *
* *
* OUTPUT: Returns with the actual number of bytes decrypted. *
* *
* WARNINGS: You must submit the key before calling this routine. This will only decrypt *
* the cyphertext in 8 byte increments. Modulo bytes left over are not processed. *
* *
* HISTORY: *
* 04/14/1996 JLB : Created. *
*=============================================================================================*/
int BlowfishEngine::Decrypt(void const * cyphertext, int length, void * plaintext)
{
if (cyphertext == 0 || length == 0) {
return(0);
}
if (plaintext == 0) plaintext = (void *)cyphertext;
if (IsKeyed) {
/*
** Validate parameters.
*/
int blocks = length / BYTES_PER_BLOCK;
/*
** Process the buffer in 64 bit chunks.
*/
for (int index = 0; index < blocks; index++) {
Process_Block(cyphertext, plaintext, P_Decrypt);
cyphertext = ((char *)cyphertext) + BYTES_PER_BLOCK;
plaintext = ((char *)plaintext) + BYTES_PER_BLOCK;
}
int encrypted = blocks * BYTES_PER_BLOCK;
/*
** Copy over any trailing left over appendix bytes.
*/
if (encrypted < length) {
memmove(plaintext, cyphertext, length - encrypted);
}
return(encrypted);
}
/*
** Non-keyed processing merely copies the data.
*/
if (plaintext != cyphertext) {
memmove(plaintext, cyphertext, length);
}
return(length);
}
/***********************************************************************************************
* BlowfishEngine::Process_Block -- Process a block of data using Blowfish algorithm. *
* *
* This is the main processing routine for encryption and decryption. The algorithm *
* consists of a 16 round Feistal network and uses mathematics from different algebraic *
* groups (strengthens against differential cryptanalysis). The large S-Boxes and the *
* rounds strengthen it against linear cryptanalysis. *
* *
* INPUT: plaintext -- Pointer to the source text (it actually might be a pointer to *
* the cyphertext if this is called as a decryption process). *
* *
* cyphertext -- Pointer to the output buffer that will hold the processed block. *
* *
* ptable -- Pointer to the permutation table. This algorithm will encrypt *
* and decrypt using the same S-Box tables. The encryption control *
* is handled by the permutation table. *
* *
* OUTPUT: none *
* *
* WARNINGS: The source and destination buffers must be 8 bytes long. *
* *
* HISTORY: *
* 04/19/1996 JLB : Created. *
*=============================================================================================*/
void BlowfishEngine::Process_Block(void const * plaintext, void * cyphertext, unsigned long const * ptable)
{
/*
** Input the left and right halves of the source block such that
** the byte order is constant regardless of the endian
** persuasion of the current processor. The blowfish algorithm is
** biased toward "big endian" architecture and some optimizations
** could be done for big endian processors in that case.
*/
unsigned char const * source = (unsigned char const *)plaintext;
Int left;
left.Char.C0 = *source++;
left.Char.C1 = *source++;
left.Char.C2 = *source++;
left.Char.C3 = *source++;
Int right;
right.Char.C0 = *source++;
right.Char.C1 = *source++;
right.Char.C2 = *source++;
right.Char.C3 = *source;
/*
** Perform all Feistal rounds on the block. This is the encryption/decryption
** process. Since there is an exchange that occurs after each round, two
** rounds are combined in this loop to avoid unnecessary exchanging.
*/
for (int index = 0; index < ROUNDS/2; index++) {
left.Long ^= *ptable++;
right.Long ^= ((( bf_S[0][left.Char.C0] + bf_S[1][left.Char.C1]) ^ bf_S[2][left.Char.C2]) + bf_S[3][left.Char.C3]);
right.Long ^= *ptable++;
left.Long ^= ((( bf_S[0][right.Char.C0] + bf_S[1][right.Char.C1]) ^ bf_S[2][right.Char.C2]) + bf_S[3][right.Char.C3]);
}
/*
** The final two longs in the permutation table are processed into the block.
** The left and right halves are still reversed as a side effect of the last
** round.
*/
left.Long ^= *ptable++;
right.Long ^= *ptable;
/*
** The final block data is output in endian architecture
** independent format. Notice that the blocks are output as
** right first and left second. This is to counteract the final
** superfluous exchange that occurs as a side effect of the
** encryption rounds.
*/
unsigned char * out = (unsigned char *)cyphertext;
*out++ = right.Char.C0;
*out++ = right.Char.C1;
*out++ = right.Char.C2;
*out++ = right.Char.C3;
*out++ = left.Char.C0;
*out++ = left.Char.C1;
*out++ = left.Char.C2;
*out = left.Char.C3;
}
/***********************************************************************************************
* BlowfishEngine::Sub_Key_Encrypt -- Encrypts a block for use in S-Box processing. *
* *
* This is the same as the normal process block function but it doesn't have the endian *
* fixup logic. Since this routine is only called for S-Box table generation and it is *
* known that the S-Box initial data is already in local machine endian format, the *
* byte order fixups are not needed. This also has a tendency to speed up S-Box generation *
* as well. *
* *
* INPUT: left -- The left half of the data block. *
* *
* right -- The right half of the data block. *
* *
* OUTPUT: none, but the processed block is stored back into the left and right half *
* integers. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 04/19/1996 JLB : Created. *
*=============================================================================================*/
void BlowfishEngine::Sub_Key_Encrypt(unsigned long & left, unsigned long & right)
{
Int l;
l.Long = left;
Int r;
r.Long = right;
for (int index = 0; index < ROUNDS; index += 2) {
l.Long ^= P_Encrypt[index];
r.Long ^= ((( bf_S[0][l.Char.C0] + bf_S[1][l.Char.C1]) ^ bf_S[2][l.Char.C2]) + bf_S[3][l.Char.C3]);
r.Long ^= P_Encrypt[index+1];
l.Long ^= ((( bf_S[0][r.Char.C0] + bf_S[1][r.Char.C1]) ^ bf_S[2][r.Char.C2]) + bf_S[3][r.Char.C3]);
}
left = r.Long ^ P_Encrypt[ROUNDS+1];
right = l.Long ^ P_Encrypt[ROUNDS];
}
/*
** These tables have the bytes stored in machine endian format. Because of this,
** a special block cypher routine is needed when the sub-keys are generated.
** This is kludgier than it otherwise should be. However, storing these
** integers in machine independent format would be even more painful.
*/
unsigned long const BlowfishEngine::P_Init[BlowfishEngine::ROUNDS+2] = {
0x243F6A88U,0x85A308D3U,0x13198A2EU,0x03707344U,0xA4093822U,0x299F31D0U,0x082EFA98U,0xEC4E6C89U,
0x452821E6U,0x38D01377U,0xBE5466CFU,0x34E90C6CU,0xC0AC29B7U,0xC97C50DDU,0x3F84D5B5U,0xB5470917U,
0x9216D5D9U,0x8979FB1BU
} ;
unsigned long const BlowfishEngine::S_Init[4][UCHAR_MAX+1] = {
{
0xD1310BA6U,0x98DFB5ACU,0x2FFD72DBU,0xD01ADFB7U,0xB8E1AFEDU,0x6A267E96U,0xBA7C9045U,0xF12C7F99U,
0x24A19947U,0xB3916CF7U,0x0801F2E2U,0x858EFC16U,0x636920D8U,0x71574E69U,0xA458FEA3U,0xF4933D7EU,
0x0D95748FU,0x728EB658U,0x718BCD58U,0x82154AEEU,0x7B54A41DU,0xC25A59B5U,0x9C30D539U,0x2AF26013U,
0xC5D1B023U,0x286085F0U,0xCA417918U,0xB8DB38EFU,0x8E79DCB0U,0x603A180EU,0x6C9E0E8BU,0xB01E8A3EU,
0xD71577C1U,0xBD314B27U,0x78AF2FDAU,0x55605C60U,0xE65525F3U,0xAA55AB94U,0x57489862U,0x63E81440U,
0x55CA396AU,0x2AAB10B6U,0xB4CC5C34U,0x1141E8CEU,0xA15486AFU,0x7C72E993U,0xB3EE1411U,0x636FBC2AU,
0x2BA9C55DU,0x741831F6U,0xCE5C3E16U,0x9B87931EU,0xAFD6BA33U,0x6C24CF5CU,0x7A325381U,0x28958677U,
0x3B8F4898U,0x6B4BB9AFU,0xC4BFE81BU,0x66282193U,0x61D809CCU,0xFB21A991U,0x487CAC60U,0x5DEC8032U,
0xEF845D5DU,0xE98575B1U,0xDC262302U,0xEB651B88U,0x23893E81U,0xD396ACC5U,0x0F6D6FF3U,0x83F44239U,
0x2E0B4482U,0xA4842004U,0x69C8F04AU,0x9E1F9B5EU,0x21C66842U,0xF6E96C9AU,0x670C9C61U,0xABD388F0U,
0x6A51A0D2U,0xD8542F68U,0x960FA728U,0xAB5133A3U,0x6EEF0B6CU,0x137A3BE4U,0xBA3BF050U,0x7EFB2A98U,
0xA1F1651DU,0x39AF0176U,0x66CA593EU,0x82430E88U,0x8CEE8619U,0x456F9FB4U,0x7D84A5C3U,0x3B8B5EBEU,
0xE06F75D8U,0x85C12073U,0x401A449FU,0x56C16AA6U,0x4ED3AA62U,0x363F7706U,0x1BFEDF72U,0x429B023DU,
0x37D0D724U,0xD00A1248U,0xDB0FEAD3U,0x49F1C09BU,0x075372C9U,0x80991B7BU,0x25D479D8U,0xF6E8DEF7U,
0xE3FE501AU,0xB6794C3BU,0x976CE0BDU,0x04C006BAU,0xC1A94FB6U,0x409F60C4U,0x5E5C9EC2U,0x196A2463U,
0x68FB6FAFU,0x3E6C53B5U,0x1339B2EBU,0x3B52EC6FU,0x6DFC511FU,0x9B30952CU,0xCC814544U,0xAF5EBD09U,
0xBEE3D004U,0xDE334AFDU,0x660F2807U,0x192E4BB3U,0xC0CBA857U,0x45C8740FU,0xD20B5F39U,0xB9D3FBDBU,
0x5579C0BDU,0x1A60320AU,0xD6A100C6U,0x402C7279U,0x679F25FEU,0xFB1FA3CCU,0x8EA5E9F8U,0xDB3222F8U,
0x3C7516DFU,0xFD616B15U,0x2F501EC8U,0xAD0552ABU,0x323DB5FAU,0xFD238760U,0x53317B48U,0x3E00DF82U,
0x9E5C57BBU,0xCA6F8CA0U,0x1A87562EU,0xDF1769DBU,0xD542A8F6U,0x287EFFC3U,0xAC6732C6U,0x8C4F5573U,
0x695B27B0U,0xBBCA58C8U,0xE1FFA35DU,0xB8F011A0U,0x10FA3D98U,0xFD2183B8U,0x4AFCB56CU,0x2DD1D35BU,
0x9A53E479U,0xB6F84565U,0xD28E49BCU,0x4BFB9790U,0xE1DDF2DAU,0xA4CB7E33U,0x62FB1341U,0xCEE4C6E8U,
0xEF20CADAU,0x36774C01U,0xD07E9EFEU,0x2BF11FB4U,0x95DBDA4DU,0xAE909198U,0xEAAD8E71U,0x6B93D5A0U,
0xD08ED1D0U,0xAFC725E0U,0x8E3C5B2FU,0x8E7594B7U,0x8FF6E2FBU,0xF2122B64U,0x8888B812U,0x900DF01CU,
0x4FAD5EA0U,0x688FC31CU,0xD1CFF191U,0xB3A8C1ADU,0x2F2F2218U,0xBE0E1777U,0xEA752DFEU,0x8B021FA1U,
0xE5A0CC0FU,0xB56F74E8U,0x18ACF3D6U,0xCE89E299U,0xB4A84FE0U,0xFD13E0B7U,0x7CC43B81U,0xD2ADA8D9U,
0x165FA266U,0x80957705U,0x93CC7314U,0x211A1477U,0xE6AD2065U,0x77B5FA86U,0xC75442F5U,0xFB9D35CFU,
0xEBCDAF0CU,0x7B3E89A0U,0xD6411BD3U,0xAE1E7E49U,0x00250E2DU,0x2071B35EU,0x226800BBU,0x57B8E0AFU,
0x2464369BU,0xF009B91EU,0x5563911DU,0x59DFA6AAU,0x78C14389U,0xD95A537FU,0x207D5BA2U,0x02E5B9C5U,
0x83260376U,0x6295CFA9U,0x11C81968U,0x4E734A41U,0xB3472DCAU,0x7B14A94AU,0x1B510052U,0x9A532915U,
0xD60F573FU,0xBC9BC6E4U,0x2B60A476U,0x81E67400U,0x08BA6FB5U,0x571BE91FU,0xF296EC6BU,0x2A0DD915U,
0xB6636521U,0xE7B9F9B6U,0xFF34052EU,0xC5855664U,0x53B02D5DU,0xA99F8FA1U,0x08BA4799U,0x6E85076AU,
},{
0x4B7A70E9U,0xB5B32944U,0xDB75092EU,0xC4192623U,0xAD6EA6B0U,0x49A7DF7DU,0x9CEE60B8U,0x8FEDB266U,
0xECAA8C71U,0x699A17FFU,0x5664526CU,0xC2B19EE1U,0x193602A5U,0x75094C29U,0xA0591340U,0xE4183A3EU,
0x3F54989AU,0x5B429D65U,0x6B8FE4D6U,0x99F73FD6U,0xA1D29C07U,0xEFE830F5U,0x4D2D38E6U,0xF0255DC1U,
0x4CDD2086U,0x8470EB26U,0x6382E9C6U,0x021ECC5EU,0x09686B3FU,0x3EBAEFC9U,0x3C971814U,0x6B6A70A1U,
0x687F3584U,0x52A0E286U,0xB79C5305U,0xAA500737U,0x3E07841CU,0x7FDEAE5CU,0x8E7D44ECU,0x5716F2B8U,
0xB03ADA37U,0xF0500C0DU,0xF01C1F04U,0x0200B3FFU,0xAE0CF51AU,0x3CB574B2U,0x25837A58U,0xDC0921BDU,
0xD19113F9U,0x7CA92FF6U,0x94324773U,0x22F54701U,0x3AE5E581U,0x37C2DADCU,0xC8B57634U,0x9AF3DDA7U,
0xA9446146U,0x0FD0030EU,0xECC8C73EU,0xA4751E41U,0xE238CD99U,0x3BEA0E2FU,0x3280BBA1U,0x183EB331U,
0x4E548B38U,0x4F6DB908U,0x6F420D03U,0xF60A04BFU,0x2CB81290U,0x24977C79U,0x5679B072U,0xBCAF89AFU,
0xDE9A771FU,0xD9930810U,0xB38BAE12U,0xDCCF3F2EU,0x5512721FU,0x2E6B7124U,0x501ADDE6U,0x9F84CD87U,
0x7A584718U,0x7408DA17U,0xBC9F9ABCU,0xE94B7D8CU,0xEC7AEC3AU,0xDB851DFAU,0x63094366U,0xC464C3D2U,
0xEF1C1847U,0x3215D908U,0xDD433B37U,0x24C2BA16U,0x12A14D43U,0x2A65C451U,0x50940002U,0x133AE4DDU,
0x71DFF89EU,0x10314E55U,0x81AC77D6U,0x5F11199BU,0x043556F1U,0xD7A3C76BU,0x3C11183BU,0x5924A509U,
0xF28FE6EDU,0x97F1FBFAU,0x9EBABF2CU,0x1E153C6EU,0x86E34570U,0xEAE96FB1U,0x860E5E0AU,0x5A3E2AB3U,
0x771FE71CU,0x4E3D06FAU,0x2965DCB9U,0x99E71D0FU,0x803E89D6U,0x5266C825U,0x2E4CC978U,0x9C10B36AU,
0xC6150EBAU,0x94E2EA78U,0xA5FC3C53U,0x1E0A2DF4U,0xF2F74EA7U,0x361D2B3DU,0x1939260FU,0x19C27960U,
0x5223A708U,0xF71312B6U,0xEBADFE6EU,0xEAC31F66U,0xE3BC4595U,0xA67BC883U,0xB17F37D1U,0x018CFF28U,
0xC332DDEFU,0xBE6C5AA5U,0x65582185U,0x68AB9802U,0xEECEA50FU,0xDB2F953BU,0x2AEF7DADU,0x5B6E2F84U,
0x1521B628U,0x29076170U,0xECDD4775U,0x619F1510U,0x13CCA830U,0xEB61BD96U,0x0334FE1EU,0xAA0363CFU,
0xB5735C90U,0x4C70A239U,0xD59E9E0BU,0xCBAADE14U,0xEECC86BCU,0x60622CA7U,0x9CAB5CABU,0xB2F3846EU,
0x648B1EAFU,0x19BDF0CAU,0xA02369B9U,0x655ABB50U,0x40685A32U,0x3C2AB4B3U,0x319EE9D5U,0xC021B8F7U,
0x9B540B19U,0x875FA099U,0x95F7997EU,0x623D7DA8U,0xF837889AU,0x97E32D77U,0x11ED935FU,0x16681281U,
0x0E358829U,0xC7E61FD6U,0x96DEDFA1U,0x7858BA99U,0x57F584A5U,0x1B227263U,0x9B83C3FFU,0x1AC24696U,
0xCDB30AEBU,0x532E3054U,0x8FD948E4U,0x6DBC3128U,0x58EBF2EFU,0x34C6FFEAU,0xFE28ED61U,0xEE7C3C73U,
0x5D4A14D9U,0xE864B7E3U,0x42105D14U,0x203E13E0U,0x45EEE2B6U,0xA3AAABEAU,0xDB6C4F15U,0xFACB4FD0U,
0xC742F442U,0xEF6ABBB5U,0x654F3B1DU,0x41CD2105U,0xD81E799EU,0x86854DC7U,0xE44B476AU,0x3D816250U,
0xCF62A1F2U,0x5B8D2646U,0xFC8883A0U,0xC1C7B6A3U,0x7F1524C3U,0x69CB7492U,0x47848A0BU,0x5692B285U,
0x095BBF00U,0xAD19489DU,0x1462B174U,0x23820E00U,0x58428D2AU,0x0C55F5EAU,0x1DADF43EU,0x233F7061U,
0x3372F092U,0x8D937E41U,0xD65FECF1U,0x6C223BDBU,0x7CDE3759U,0xCBEE7460U,0x4085F2A7U,0xCE77326EU,
0xA6078084U,0x19F8509EU,0xE8EFD855U,0x61D99735U,0xA969A7AAU,0xC50C06C2U,0x5A04ABFCU,0x800BCADCU,
0x9E447A2EU,0xC3453484U,0xFDD56705U,0x0E1E9EC9U,0xDB73DBD3U,0x105588CDU,0x675FDA79U,0xE3674340U,
0xC5C43465U,0x713E38D8U,0x3D28F89EU,0xF16DFF20U,0x153E21E7U,0x8FB03D4AU,0xE6E39F2BU,0xDB83ADF7U,
},{
0xE93D5A68U,0x948140F7U,0xF64C261CU,0x94692934U,0x411520F7U,0x7602D4F7U,0xBCF46B2EU,0xD4A20068U,
0xD4082471U,0x3320F46AU,0x43B7D4B7U,0x500061AFU,0x1E39F62EU,0x97244546U,0x14214F74U,0xBF8B8840U,
0x4D95FC1DU,0x96B591AFU,0x70F4DDD3U,0x66A02F45U,0xBFBC09ECU,0x03BD9785U,0x7FAC6DD0U,0x31CB8504U,
0x96EB27B3U,0x55FD3941U,0xDA2547E6U,0xABCA0A9AU,0x28507825U,0x530429F4U,0x0A2C86DAU,0xE9B66DFBU,
0x68DC1462U,0xD7486900U,0x680EC0A4U,0x27A18DEEU,0x4F3FFEA2U,0xE887AD8CU,0xB58CE006U,0x7AF4D6B6U,
0xAACE1E7CU,0xD3375FECU,0xCE78A399U,0x406B2A42U,0x20FE9E35U,0xD9F385B9U,0xEE39D7ABU,0x3B124E8BU,
0x1DC9FAF7U,0x4B6D1856U,0x26A36631U,0xEAE397B2U,0x3A6EFA74U,0xDD5B4332U,0x6841E7F7U,0xCA7820FBU,
0xFB0AF54EU,0xD8FEB397U,0x454056ACU,0xBA489527U,0x55533A3AU,0x20838D87U,0xFE6BA9B7U,0xD096954BU,
0x55A867BCU,0xA1159A58U,0xCCA92963U,0x99E1DB33U,0xA62A4A56U,0x3F3125F9U,0x5EF47E1CU,0x9029317CU,
0xFDF8E802U,0x04272F70U,0x80BB155CU,0x05282CE3U,0x95C11548U,0xE4C66D22U,0x48C1133FU,0xC70F86DCU,
0x07F9C9EEU,0x41041F0FU,0x404779A4U,0x5D886E17U,0x325F51EBU,0xD59BC0D1U,0xF2BCC18FU,0x41113564U,
0x257B7834U,0x602A9C60U,0xDFF8E8A3U,0x1F636C1BU,0x0E12B4C2U,0x02E1329EU,0xAF664FD1U,0xCAD18115U,
0x6B2395E0U,0x333E92E1U,0x3B240B62U,0xEEBEB922U,0x85B2A20EU,0xE6BA0D99U,0xDE720C8CU,0x2DA2F728U,
0xD0127845U,0x95B794FDU,0x647D0862U,0xE7CCF5F0U,0x5449A36FU,0x877D48FAU,0xC39DFD27U,0xF33E8D1EU,
0x0A476341U,0x992EFF74U,0x3A6F6EABU,0xF4F8FD37U,0xA812DC60U,0xA1EBDDF8U,0x991BE14CU,0xDB6E6B0DU,
0xC67B5510U,0x6D672C37U,0x2765D43BU,0xDCD0E804U,0xF1290DC7U,0xCC00FFA3U,0xB5390F92U,0x690FED0BU,
0x667B9FFBU,0xCEDB7D9CU,0xA091CF0BU,0xD9155EA3U,0xBB132F88U,0x515BAD24U,0x7B9479BFU,0x763BD6EBU,
0x37392EB3U,0xCC115979U,0x8026E297U,0xF42E312DU,0x6842ADA7U,0xC66A2B3BU,0x12754CCCU,0x782EF11CU,
0x6A124237U,0xB79251E7U,0x06A1BBE6U,0x4BFB6350U,0x1A6B1018U,0x11CAEDFAU,0x3D25BDD8U,0xE2E1C3C9U,
0x44421659U,0x0A121386U,0xD90CEC6EU,0xD5ABEA2AU,0x64AF674EU,0xDA86A85FU,0xBEBFE988U,0x64E4C3FEU,
0x9DBC8057U,0xF0F7C086U,0x60787BF8U,0x6003604DU,0xD1FD8346U,0xF6381FB0U,0x7745AE04U,0xD736FCCCU,
0x83426B33U,0xF01EAB71U,0xB0804187U,0x3C005E5FU,0x77A057BEU,0xBDE8AE24U,0x55464299U,0xBF582E61U,
0x4E58F48FU,0xF2DDFDA2U,0xF474EF38U,0x8789BDC2U,0x5366F9C3U,0xC8B38E74U,0xB475F255U,0x46FCD9B9U,
0x7AEB2661U,0x8B1DDF84U,0x846A0E79U,0x915F95E2U,0x466E598EU,0x20B45770U,0x8CD55591U,0xC902DE4CU,
0xB90BACE1U,0xBB8205D0U,0x11A86248U,0x7574A99EU,0xB77F19B6U,0xE0A9DC09U,0x662D09A1U,0xC4324633U,
0xE85A1F02U,0x09F0BE8CU,0x4A99A025U,0x1D6EFE10U,0x1AB93D1DU,0x0BA5A4DFU,0xA186F20FU,0x2868F169U,
0xDCB7DA83U,0x573906FEU,0xA1E2CE9BU,0x4FCD7F52U,0x50115E01U,0xA70683FAU,0xA002B5C4U,0x0DE6D027U,
0x9AF88C27U,0x773F8641U,0xC3604C06U,0x61A806B5U,0xF0177A28U,0xC0F586E0U,0x006058AAU,0x30DC7D62U,
0x11E69ED7U,0x2338EA63U,0x53C2DD94U,0xC2C21634U,0xBBCBEE56U,0x90BCB6DEU,0xEBFC7DA1U,0xCE591D76U,
0x6F05E409U,0x4B7C0188U,0x39720A3DU,0x7C927C24U,0x86E3725FU,0x724D9DB9U,0x1AC15BB4U,0xD39EB8FCU,
0xED545578U,0x08FCA5B5U,0xD83D7CD3U,0x4DAD0FC4U,0x1E50EF5EU,0xB161E6F8U,0xA28514D9U,0x6C51133CU,
0x6FD5C7E7U,0x56E14EC4U,0x362ABFCEU,0xDDC6C837U,0xD79A3234U,0x92638212U,0x670EFA8EU,0x406000E0U,
},{
0x3A39CE37U,0xD3FAF5CFU,0xABC27737U,0x5AC52D1BU,0x5CB0679EU,0x4FA33742U,0xD3822740U,0x99BC9BBEU,
0xD5118E9DU,0xBF0F7315U,0xD62D1C7EU,0xC700C47BU,0xB78C1B6BU,0x21A19045U,0xB26EB1BEU,0x6A366EB4U,
0x5748AB2FU,0xBC946E79U,0xC6A376D2U,0x6549C2C8U,0x530FF8EEU,0x468DDE7DU,0xD5730A1DU,0x4CD04DC6U,
0x2939BBDBU,0xA9BA4650U,0xAC9526E8U,0xBE5EE304U,0xA1FAD5F0U,0x6A2D519AU,0x63EF8CE2U,0x9A86EE22U,
0xC089C2B8U,0x43242EF6U,0xA51E03AAU,0x9CF2D0A4U,0x83C061BAU,0x9BE96A4DU,0x8FE51550U,0xBA645BD6U,
0x2826A2F9U,0xA73A3AE1U,0x4BA99586U,0xEF5562E9U,0xC72FEFD3U,0xF752F7DAU,0x3F046F69U,0x77FA0A59U,
0x80E4A915U,0x87B08601U,0x9B09E6ADU,0x3B3EE593U,0xE990FD5AU,0x9E34D797U,0x2CF0B7D9U,0x022B8B51U,
0x96D5AC3AU,0x017DA67DU,0xD1CF3ED6U,0x7C7D2D28U,0x1F9F25CFU,0xADF2B89BU,0x5AD6B472U,0x5A88F54CU,
0xE029AC71U,0xE019A5E6U,0x47B0ACFDU,0xED93FA9BU,0xE8D3C48DU,0x283B57CCU,0xF8D56629U,0x79132E28U,
0x785F0191U,0xED756055U,0xF7960E44U,0xE3D35E8CU,0x15056DD4U,0x88F46DBAU,0x03A16125U,0x0564F0BDU,
0xC3EB9E15U,0x3C9057A2U,0x97271AECU,0xA93A072AU,0x1B3F6D9BU,0x1E6321F5U,0xF59C66FBU,0x26DCF319U,
0x7533D928U,0xB155FDF5U,0x03563482U,0x8ABA3CBBU,0x28517711U,0xC20AD9F8U,0xABCC5167U,0xCCAD925FU,
0x4DE81751U,0x3830DC8EU,0x379D5862U,0x9320F991U,0xEA7A90C2U,0xFB3E7BCEU,0x5121CE64U,0x774FBE32U,
0xA8B6E37EU,0xC3293D46U,0x48DE5369U,0x6413E680U,0xA2AE0810U,0xDD6DB224U,0x69852DFDU,0x09072166U,
0xB39A460AU,0x6445C0DDU,0x586CDECFU,0x1C20C8AEU,0x5BBEF7DDU,0x1B588D40U,0xCCD2017FU,0x6BB4E3BBU,
0xDDA26A7EU,0x3A59FF45U,0x3E350A44U,0xBCB4CDD5U,0x72EACEA8U,0xFA6484BBU,0x8D6612AEU,0xBF3C6F47U,
0xD29BE463U,0x542F5D9EU,0xAEC2771BU,0xF64E6370U,0x740E0D8DU,0xE75B1357U,0xF8721671U,0xAF537D5DU,
0x4040CB08U,0x4EB4E2CCU,0x34D2466AU,0x0115AF84U,0xE1B00428U,0x95983A1DU,0x06B89FB4U,0xCE6EA048U,
0x6F3F3B82U,0x3520AB82U,0x011A1D4BU,0x277227F8U,0x611560B1U,0xE7933FDCU,0xBB3A792BU,0x344525BDU,
0xA08839E1U,0x51CE794BU,0x2F32C9B7U,0xA01FBAC9U,0xE01CC87EU,0xBCC7D1F6U,0xCF0111C3U,0xA1E8AAC7U,
0x1A908749U,0xD44FBD9AU,0xD0DADECBU,0xD50ADA38U,0x0339C32AU,0xC6913667U,0x8DF9317CU,0xE0B12B4FU,
0xF79E59B7U,0x43F5BB3AU,0xF2D519FFU,0x27D9459CU,0xBF97222CU,0x15E6FC2AU,0x0F91FC71U,0x9B941525U,
0xFAE59361U,0xCEB69CEBU,0xC2A86459U,0x12BAA8D1U,0xB6C1075EU,0xE3056A0CU,0x10D25065U,0xCB03A442U,
0xE0EC6E0EU,0x1698DB3BU,0x4C98A0BEU,0x3278E964U,0x9F1F9532U,0xE0D392DFU,0xD3A0342BU,0x8971F21EU,
0x1B0A7441U,0x4BA3348CU,0xC5BE7120U,0xC37632D8U,0xDF359F8DU,0x9B992F2EU,0xE60B6F47U,0x0FE3F11DU,
0xE54CDA54U,0x1EDAD891U,0xCE6279CFU,0xCD3E7E6FU,0x1618B166U,0xFD2C1D05U,0x848FD2C5U,0xF6FB2299U,
0xF523F357U,0xA6327623U,0x93A83531U,0x56CCCD02U,0xACF08162U,0x5A75EBB5U,0x6E163697U,0x88D273CCU,
0xDE966292U,0x81B949D0U,0x4C50901BU,0x71C65614U,0xE6C6C7BDU,0x327A140AU,0x45E1D006U,0xC3F27B9AU,
0xC9AA53FDU,0x62A80F00U,0xBB25BFE2U,0x35BDD2F6U,0x71126905U,0xB2040222U,0xB6CBCF7CU,0xCD769C2BU,
0x53113EC0U,0x1640E3D3U,0x38ABBD60U,0x2547ADF0U,0xBA38209CU,0xF746CE76U,0x77AFA1C5U,0x20756060U,
0x85CBFE4EU,0x8AE88DD8U,0x7AAAF9B0U,0x4CF9AA7EU,0x1948C25CU,0x02FB8A8CU,0x01C36AE4U,0xD6EBE1F9U,
0x90D4F869U,0xA65CDEA0U,0x3F09252DU,0xC208E69FU,0xB74E6132U,0xCE77E25BU,0x578FDFE3U,0x3AC372E6U
}
};

117
CODE/BLOWFISH.H Normal file
View file

@ -0,0 +1,117 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/BLOWFISH.H 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : BLOWFISH.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 04/14/96 *
* *
* Last Update : April 14, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef BLOWFISH_H
#define BLOWFISH_H
#include <limits.h>
/*
** The "bool" integral type was defined by the C++ committee in
** November of '94. Until the compiler supports this, use the following
** definition.
*/
#ifndef __BORLANDC__
#ifndef TRUE_FALSE_DEFINED
#define TRUE_FALSE_DEFINED
enum {false=0,true=1};
typedef int bool;
#endif
#endif
/*
** This engine will process data blocks by encryption and decryption.
** The "Blowfish" algorithm is in the public domain. It uses
** a Feistal network (similar to IDEA). It has no known
** weaknesses, but is still relatively new. Blowfish is particularly strong
** against brute force attacks. It is also quite strong against linear and
** differential cryptanalysis. Its weakness is that it takes a relatively
** long time to set up with a new key (1/100th of a second on a P6-200).
** The time to set up a key is equivalent to encrypting 4240 bytes.
*/
class BlowfishEngine {
public:
BlowfishEngine(void) : IsKeyed(false) {}
~BlowfishEngine(void);
void Submit_Key(void const * key, int length);
int Encrypt(void const * plaintext, int length, void * cyphertext);
int Decrypt(void const * cyphertext, int length, void * plaintext);
/*
** This is the maximum key length supported.
*/
enum {MAX_KEY_LENGTH=56};
private:
bool IsKeyed;
void Sub_Key_Encrypt(unsigned long & left, unsigned long & right);
void Process_Block(void const * plaintext, void * cyphertext, unsigned long const * ptable);
void Initialize_Tables(void);
enum {
ROUNDS = 16, // Feistal round count (16 is standard).
BYTES_PER_BLOCK=8 // The number of bytes in each cypher block (don't change).
};
/*
** Initialization data for sub keys. The initial values are constant and
** filled with a number generated from pi. Thus they are not random but
** they don't hold a weak pattern either.
*/
static unsigned long const P_Init[(int)ROUNDS+2];
static unsigned long const S_Init[4][UCHAR_MAX+1];
/*
** Permutation tables for encryption and decryption.
*/
unsigned long P_Encrypt[(int)ROUNDS+2];
unsigned long P_Decrypt[(int)ROUNDS+2];
/*
** S-Box tables (four).
*/
unsigned long bf_S[4][UCHAR_MAX+1];
};
#endif

202
CODE/BLOWPIPE.CPP Normal file
View file

@ -0,0 +1,202 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/BLOWPIPE.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : BLOWPIPE.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 06/30/96 *
* *
* Last Update : July 3, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* BlowPipe::Flush -- Flushes any pending data out the pipe. *
* BlowPipe::Key -- Submit a key to the blowfish pipe handler. *
* BlowPipe::Put -- Submit a block of data for encrypt/decrypt. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "blowpipe.h"
#include <string.h>
#include <assert.h>
/***********************************************************************************************
* BlowPipe::Flush -- Flushes any pending data out the pipe. *
* *
* If there is any pending data in the holding buffer, then this routine will force it to *
* be flushed out the end of the pipe. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the actual number of bytes output at the end final distant pipe *
* segment in the chain. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/03/1996 JLB : Created. *
*=============================================================================================*/
int BlowPipe::Flush(void)
{
int total = 0;
if (Counter > 0 && BF != NULL) {
total += Pipe::Put(Buffer, Counter);
}
Counter = 0;
total += Pipe::Flush();
return(total);
}
/***********************************************************************************************
* BlowPipe::Put -- Submit a block of data for encrypt/decrypt. *
* *
* This will take the data block specified and process it before passing it on to the next *
* link in the pipe chain. A key must be submitted before this routine will actually perform*
* any processing. Prior to key submission, the data is passed through unchanged. *
* *
* INPUT: source -- Pointer to the buffer that contains the data to pass through. *
* *
* length -- The length of the data in the buffer. *
* *
* OUTPUT: Returns with then actual number of bytes output at the final distant end link in *
* the pipe chain. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/03/1996 JLB : Created. *
*=============================================================================================*/
int BlowPipe::Put(void const * source, int slen)
{
if (source == NULL || slen < 1) {
return(Pipe::Put(source, slen));
}
/*
** If there is no blowfish engine present, then merely pass the data through
** unchanged in any way.
*/
if (BF == NULL) {
return(Pipe::Put(source, slen));
}
int total = 0;
/*
** If there is a partial block accumulated, then tag on the new data to
** this block and process it if the block is full. Proceed with the bulk
** processing if there are any left over bytes from this step. This step
** can be skipped if there are no pending bytes in the buffer.
*/
if (Counter) {
int sublen = (sizeof(Buffer)-Counter < slen) ? (sizeof(Buffer)-Counter) : slen;
memmove(&Buffer[Counter], source, sublen);
Counter += sublen;
source = ((char *)source) + sublen;
slen -= sublen;
if (Counter == sizeof(Buffer)) {
if (Control == DECRYPT) {
BF->Decrypt(Buffer, sizeof(Buffer), Buffer);
} else {
BF->Encrypt(Buffer, sizeof(Buffer), Buffer);
}
total += Pipe::Put(Buffer, sizeof(Buffer));
Counter = 0;
}
}
/*
** Process the input data in blocks until there is not enough
** source data to fill a full block of data.
*/
while (slen >= sizeof(Buffer)) {
if (Control == DECRYPT) {
BF->Decrypt(source, sizeof(Buffer), Buffer);
} else {
BF->Encrypt(source, sizeof(Buffer), Buffer);
}
total += Pipe::Put(Buffer, sizeof(Buffer));
source = ((char *)source) + sizeof(Buffer);
slen -= sizeof(Buffer);
}
/*
** If there are any left over bytes, then they must be less than the size of
** the staging buffer. Store the bytes in the staging buffer for later
** processing.
*/
if (slen > 0) {
memmove(Buffer, source, slen);
Counter = slen;
}
/*
** Return with the total number of bytes flushed out to the final end of the
** pipe chain.
*/
return(total);
}
/***********************************************************************************************
* BlowPipe::Key -- Submit a key to the blowfish pipe handler. *
* *
* This routine will take the key provided and use it to process the data that passes *
* through this pipe. Prior to a key being submitted, the data passes through the pipe *
* unchanged. *
* *
* INPUT: key -- Pointer to the key data to use. *
* *
* length-- The length of the key. The key length must not be greater than 56 bytes. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/03/1996 JLB : Created. *
*=============================================================================================*/
void BlowPipe::Key(void const * key, int length)
{
/*
** Create the blowfish engine if one isn't already present.
*/
if (BF == NULL) {
BF = new BlowfishEngine;
}
assert(BF != NULL);
if (BF != NULL) {
BF->Submit_Key(key, length);
}
}

85
CODE/BLOWPIPE.H Normal file
View file

@ -0,0 +1,85 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/BLOWPIPE.H 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : BLOWPIPE.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 06/30/96 *
* *
* Last Update : June 30, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef BLOWPIPE_H
#define BLOWPIPE_H
#include "pipe.h"
#include "blowfish.h"
/*
** Performs Blowfish encryption/decryption on the data stream that is piped
** through this class.
*/
class BlowPipe : public Pipe
{
public:
typedef enum CryptControl {
ENCRYPT,
DECRYPT
} CryptControl;
BlowPipe(CryptControl control) : BF(NULL), Counter(0), Control(control) {}
virtual ~BlowPipe(void) {delete BF;BF = NULL;}
virtual int Flush(void);
virtual int Put(void const * source, int slen);
// Submit key for blowfish engine.
void Key(void const * key, int length);
protected:
/*
** The Blowfish engine used for encryption/decryption. If this pointer is
** NULL, then this indicates that the blowfish engine is not active and no
** key has been submitted. All data would pass through this pipe unchanged
** in that case.
*/
BlowfishEngine * BF;
private:
char Buffer[8];
int Counter;
CryptControl Control;
BlowPipe(BlowPipe & rvalue);
BlowPipe & operator = (BlowPipe const & pipe);
};
#endif

161
CODE/BLWSTRAW.CPP Normal file
View file

@ -0,0 +1,161 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/BLWSTRAW.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : BLWSTRAW.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 07/02/96 *
* *
* Last Update : July 3, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* BlowStraw::Get -- Fetch a block of data from the straw. *
* BlowStraw::Key -- Submit a key to the Blowfish straw. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "blwstraw.h"
#include <string.h>
#include <assert.h>
/***********************************************************************************************
* BlowStraw::Get -- Fetch a block of data from the straw. *
* *
* This routine will take a block of data from the straw and process it according to the *
* encrypt/decrypt flag and the key supplied. Prior to a key be supplied, the data passes *
* through this straw unchanged. *
* *
* INPUT: source -- Pointer to the buffer to hold the data being requested. *
* *
* length -- The length of the data being requested. *
* *
* OUTPUT: Returns with the actual number of bytes stored into the buffer. If the number *
* returned is less than the number requested, then this indicates that the data *
* source has been exhausted. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/03/1996 JLB : Created. *
*=============================================================================================*/
int BlowStraw::Get(void * source, int slen)
{
/*
** Verify the parameter for legality.
*/
if (source == NULL || slen <= 0) {
return(0);
}
/*
** If there is no blowfish engine present, then merely pass the data through
** unchanged.
*/
if (BF == NULL) {
return(Straw::Get(source, slen));
}
int total = 0;
while (slen > 0) {
/*
** If there are any left over bytes in the buffer, pass them
** through first.
*/
if (Counter > 0) {
int sublen = (slen < Counter) ? slen : Counter;
memmove(source, &Buffer[sizeof(Buffer)-Counter], sublen);
Counter -= sublen;
source = ((char *)source) + sublen;
slen -= sublen;
total += sublen;
}
if (slen == 0) break;
/*
** Fetch and encrypt/decrypt the next block.
*/
int incount = Straw::Get(Buffer, sizeof(Buffer));
if (incount == 0) break;
/*
** Only full blocks are processed. Partial blocks are
** merely passed through unchanged.
*/
if (incount == sizeof(Buffer)) {
if (Control == DECRYPT) {
BF->Decrypt(Buffer, incount, Buffer);
} else {
BF->Encrypt(Buffer, incount, Buffer);
}
} else {
memmove(&Buffer[sizeof(Buffer)-incount], Buffer, incount);
}
Counter = incount;
}
/*
** Return with the total number of bytes placed into the buffer.
*/
return(total);
}
/***********************************************************************************************
* BlowStraw::Key -- Submit a key to the Blowfish straw. *
* *
* This will take the key specified and use it to process the data that flows through this *
* straw segment. Prior to a key being submitted, the data will flow through unchanged. *
* *
* INPUT: key -- Pointer to the key to submit. *
* *
* length-- The length of the key. The length must not exceed 56 bytes. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/03/1996 JLB : Created. *
*=============================================================================================*/
void BlowStraw::Key(void const * key, int length)
{
/*
** Create the blowfish engine if one isn't already present.
*/
if (BF == NULL) {
BF = new BlowfishEngine;
}
assert(BF != NULL);
if (BF != NULL) {
BF->Submit_Key(key, length);
}
}

87
CODE/BLWSTRAW.H Normal file
View file

@ -0,0 +1,87 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/BLWSTRAW.H 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : BLWSTRAW.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 07/02/96 *
* *
* Last Update : July 2, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef BLWSTRAW_H
#define BLWSTRAW_H
#include "straw.h"
#include "blowfish.h"
/*
** Performs Blowfish encryption/decryption to the data that is drawn through this straw. The
** process is controlled by the key which must be submitted to the class before any data
** manipulation will occur. The Blowfish algorithm is symmetric, thus the same key is used
** for encryption as is for decryption.
*/
class BlowStraw : public Straw
{
public:
typedef enum CryptControl {
ENCRYPT,
DECRYPT
} CryptControl;
BlowStraw(CryptControl control) : BF(NULL), Counter(0), Control(control) {}
virtual ~BlowStraw(void) {delete BF;BF = NULL;}
virtual int Get(void * source, int slen);
// Submit key for blowfish engine.
void Key(void const * key, int length);
protected:
/*
** The Blowfish engine used for encryption/decryption. If this pointer is
** NULL, then this indicates that the blowfish engine is not active and no
** key has been submitted. All data would pass through this straw unchanged
** in that case.
*/
BlowfishEngine * BF;
private:
char Buffer[8];
int Counter;
CryptControl Control;
BlowStraw(BlowStraw & rvalue);
BlowStraw & operator = (BlowStraw const & straw);
};
#endif

189
CODE/BMP8.CPP Normal file
View file

@ -0,0 +1,189 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "bmp8.h"
//***********************************************************************************************
BMP8::~BMP8()
{
// free resources
if( hBitmap )
::DeleteObject( hBitmap );
if( hPal )
::DeleteObject( hPal );
}
//***********************************************************************************************
bool BMP8::Init( const char* szFile, HWND hWnd )
{
int i;
char string[128];
DWORD dwRead;
BITMAPFILEHEADER bitmapHeader;
BITMAPINFOHEADER bitmapInfoHeader;
LPLOGPALETTE lpLogPalette;
char *palData;
HGLOBAL hmem2;
LPVOID lpvBits;
PAINTSTRUCT ps;
HDC hdc;
HPALETTE select;
UINT realize;
RECT rect;
// Remember window handle for use later.
this->hWnd = hWnd;
// Retrieve a handle identifying the file.
HANDLE hFile = ::CreateFile(
szFile,
GENERIC_READ,
FILE_SHARE_READ,
(LPSECURITY_ATTRIBUTES)NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_READONLY,
(HANDLE)NULL );
if( !hFile )
return false;
// Retrieve the BITMAPFILEHEADER structure.
::ReadFile( hFile, &bitmapHeader, sizeof(BITMAPFILEHEADER), &dwRead, (LPOVERLAPPED)NULL );
// Retrieve the BITMAPFILEHEADER structure.
::ReadFile( hFile, &bitmapInfoHeader, sizeof(BITMAPINFOHEADER), &dwRead, (LPOVERLAPPED)NULL );
// Allocate memory for the BITMAPINFO structure.
HGLOBAL infoHeaderMem = ::GlobalAlloc( GHND, sizeof(BITMAPINFOHEADER) + ((1<<bitmapInfoHeader.biBitCount) * sizeof(RGBQUAD)) );
LPBITMAPINFO lpHeaderMem = (LPBITMAPINFO)::GlobalLock( infoHeaderMem );
// Load BITMAPINFOHEADER into the BITMAPINFO structure.
lpHeaderMem->bmiHeader.biSize = bitmapInfoHeader.biSize;
lpHeaderMem->bmiHeader.biWidth = bitmapInfoHeader.biWidth;
lpHeaderMem->bmiHeader.biHeight = bitmapInfoHeader.biHeight;
lpHeaderMem->bmiHeader.biPlanes = bitmapInfoHeader.biPlanes;
lpHeaderMem->bmiHeader.biBitCount = bitmapInfoHeader.biBitCount;
lpHeaderMem->bmiHeader.biCompression = bitmapInfoHeader.biCompression;
lpHeaderMem->bmiHeader.biSizeImage = bitmapInfoHeader.biSizeImage;
lpHeaderMem->bmiHeader.biXPelsPerMeter = bitmapInfoHeader.biXPelsPerMeter;
lpHeaderMem->bmiHeader.biYPelsPerMeter = bitmapInfoHeader.biYPelsPerMeter;
lpHeaderMem->bmiHeader.biClrUsed = bitmapInfoHeader.biClrUsed;
lpHeaderMem->bmiHeader.biClrImportant = bitmapInfoHeader.biClrImportant;
// Retrieve the color table.
// 1 << bitmapInfoHeader.biBitCount == 2 ^ bitmapInfoHeader.biBitCount
::ReadFile( hFile, lpHeaderMem->bmiColors, ((1<<bitmapInfoHeader.biBitCount) * sizeof(RGBQUAD)),
&dwRead, (LPOVERLAPPED)NULL );
lpLogPalette = (LPLOGPALETTE)new char[ (sizeof(LOGPALETTE) + sizeof(PALETTEENTRY)*256) ];
lpLogPalette->palVersion=0x300;
lpLogPalette->palNumEntries=256;
palData = (char*)lpHeaderMem->bmiColors;
for( i = 0; i < 256; i++ )
{
lpLogPalette->palPalEntry[i].peRed = *palData++;
lpLogPalette->palPalEntry[i].peGreen = *palData++;
lpLogPalette->palPalEntry[i].peBlue = *palData++;
lpLogPalette->palPalEntry[i].peFlags = *palData++;
}
hPal = ::CreatePalette( lpLogPalette );
delete [] lpLogPalette;
// Allocate memory for the required number of bytes.
hmem2 = ::GlobalAlloc( GHND, (bitmapHeader.bfSize - bitmapHeader.bfOffBits) );
lpvBits = ::GlobalLock( hmem2 );
// Retrieve the bitmap data.
::ReadFile( hFile, lpvBits, (bitmapHeader.bfSize - bitmapHeader.bfOffBits), &dwRead, (LPOVERLAPPED)NULL );
// Create a bitmap from the data stored in the .BMP file.
hdc = ::GetDC( hWnd );
select = ::SelectPalette( hdc, hPal, 0 );
if( !select )
return false;
realize = ::RealizePalette( hdc );
if( realize == GDI_ERROR )
return false;
hBMP = ::CreateDIBitmap( hdc, &bitmapInfoHeader, CBM_INIT, lpvBits, lpHeaderMem, DIB_RGB_COLORS );
::ReleaseDC( hWnd, hdc );
// Unlock the global memory objects and close the .BMP file.
::GlobalUnlock( infoHeaderMem );
::GlobalUnlock( hmem2 );
::CloseHandle( hFile );
if( !hBMP )
return false;
return true;
}
bit8 BMP8::drawBmp(void)
{
// Paint the window (and draw the bitmap).
PAINTSTRUCT ps;
HDC hdc;
char string[128];
InvalidateRect(WindowHandle_,NULL,FALSE); // keep windows from screwing up the
// redrawing (as much).
hdc=BeginPaint(WindowHandle_,&ps);
//Do palette stuff
HPALETTE select=SelectPalette(ps.hdc,PalHandle_,0);
if (select==NULL)
{
sprintf(string,"Select Pal Fail: %d",GetLastError());
MessageBox(NULL,string,"OK",MB_OK);
}
UINT realize=RealizePalette(ps.hdc);
if (realize==GDI_ERROR)
{
sprintf(string,"Realize Pal Fail: %d",GetLastError());
MessageBox(NULL,string,"OK",MB_OK);
}
HDC hdcMem = CreateCompatibleDC(ps.hdc);
SelectObject(hdcMem, BitmapHandle_);
BITMAP bm;
GetObject(BitmapHandle_, sizeof(BITMAP), (LPSTR) &bm);
/// for non-stretching version
///////BitBlt(ps.hdc, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);
RECT clientRect;
GetClientRect(WindowHandle_,&clientRect);
SetStretchBltMode(ps.hdc,COLORONCOLOR);
StretchBlt(ps.hdc,0,0,clientRect.right,clientRect.bottom,hdcMem,0,0,bm.bmWidth,
bm.bmHeight,SRCCOPY);
DeleteDC(hdcMem);
EndPaint(WindowHandle_,&ps);
return(TRUE);
}

43
CODE/BMP8.H Normal file
View file

@ -0,0 +1,43 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef BMP8_H
#define BMP8_H
//#include<stdlib.h>
//#include<stdio.h>
//#include "wstypes.h"
//#include "winblows.h"
class BMP8
{
public:
BMP8() : hBMP( NULL ), hPal( NULL ), hWnd( NULL ) {}
~BMP8();
bool Init( const char* szFile, HWND hWnd );
bool Draw(void); // call this from your WM_PAINT message
private:
HBITMAP hBMP;
HPALETTE hPal;
HWND hWnd;
};
#endif

220
CODE/BUFF.CPP Normal file
View file

@ -0,0 +1,220 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/BUFF.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : BUFF.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 07/29/96 *
* *
* Last Update : September 7, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* Buffer::Buffer -- Constructor for buffer object. *
* Buffer::Buffer -- Copy constructor for buffer object. *
* Buffer::Buffer -- Self-allocating constructor for buffer object. *
* Buffer::Reset -- Clears the buffer object to null state. *
* Buffer::operator = -- Assignment operator for the buffer object. *
* Buffer::~Buffer -- Destructor for buffer object. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "buff.h"
#include <stddef.h>
/***********************************************************************************************
* Buffer::Buffer -- Constructor for buffer object. *
* *
* This is the normal constructor for a buffer object. The buffer pointer and size are *
* specified as parameters. *
* *
* INPUT: buffer -- Pointer to the buffer. *
* *
* size -- The size of the buffer. *
* *
* OUTPUT: none *
* *
* WARNINGS: It is possible to construct a Buffer object that has a pointer but a size *
* value of zero. The Buffer object can still be used for its pointer, but it *
* any function that requires a size will fail. *
* *
* HISTORY: *
* 07/29/1996 JLB : Created. *
*=============================================================================================*/
Buffer::Buffer(void * buffer, long size) :
BufferPtr(buffer),
Size(size),
IsAllocated(false)
{
}
// Alternate constructor for char * pointer.
Buffer::Buffer(char * buffer, long size) :
BufferPtr(buffer),
Size(size),
IsAllocated(false)
{
}
// Alternate constructor for void const * pointer.
Buffer::Buffer(void const * buffer, long size) :
BufferPtr((void*)buffer),
Size(size),
IsAllocated(false)
{
}
/***********************************************************************************************
* Buffer::Buffer -- Self-allocating constructor for buffer object. *
* *
* This construtor for a buffer object will automatically allocate the bytes necessary *
* to fulfill the size requested. This object is also responsible for deleting the buffer *
* it allocated. *
* *
* INPUT: size -- The size of the buffer to allocated. *
* *
* OUTPUT: none *
* *
* WARNINGS: There is no way to tell if the allocation failed. To verify, call Get_Buffer *
* and compare with NULL. *
* *
* HISTORY: *
* 07/29/1996 JLB : Created. *
*=============================================================================================*/
Buffer::Buffer(long size) :
BufferPtr(NULL),
Size(size),
IsAllocated(false)
{
if (size > 0) {
BufferPtr = new char[size];
IsAllocated = true;
}
}
/***********************************************************************************************
* Buffer::Buffer -- Copy constructor for buffer object. *
* *
* This will make a duplicate of the specified buffer object. The ownership of the pointer *
* remains with the original object. This prevents multiple deletion of the same pointer. *
* *
* INPUT: buffer -- Reference to the buffer object to be dupilcated. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/02/1996 JLB : Created. *
*=============================================================================================*/
Buffer::Buffer(Buffer const & buffer) :
IsAllocated(false)
{
BufferPtr = buffer.BufferPtr;
Size = buffer.Size;
}
/***********************************************************************************************
* Buffer::operator = -- Assignment operator for the buffer object. *
* *
* This will make a duplicate of the buffer object specified. Any buffer pointed to by the *
* left hand buffer will be lost (possibley freed as a result). *
* *
* INPUT: buffer -- Reference to the right hand buffer object. *
* *
* OUTPUT: Returns with a reference to the copied buffer object. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/02/1996 JLB : Created. *
*=============================================================================================*/
Buffer & Buffer::operator = (Buffer const & buffer)
{
if (buffer != this) {
if (IsAllocated) {
delete [] BufferPtr;
}
IsAllocated = false;
BufferPtr = buffer.BufferPtr;
Size = buffer.Size;
}
return(*this);
}
/***********************************************************************************************
* Buffer::~Buffer -- Destructor for buffer object. *
* *
* This destructor will free any buffer it is responsible for. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/29/1996 JLB : Created. *
*=============================================================================================*/
Buffer::~Buffer(void)
{
Reset();
}
/***********************************************************************************************
* Buffer::Reset -- Clears the buffer object to null state. *
* *
* This routine will bring the buffer object into a null (newly constructed) state. If *
* there was any buffer allocated or referred to by this object, it will be freed or *
* dereferenced as necessary. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: This routine will free the buffer if it is responsible for doing so when *
* it is no longer referenced. *
* *
* HISTORY: *
* 09/07/1996 JLB : Created. *
*=============================================================================================*/
void Buffer::Reset(void)
{
if (IsAllocated) {
delete [] BufferPtr;
}
BufferPtr = NULL;
Size = 0;
IsAllocated = false;
}

99
CODE/BUFF.H Normal file
View file

@ -0,0 +1,99 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/BUFF.H 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : BUFF.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 07/29/96 *
* *
* Last Update : July 29, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef CCBUFF_H
#define CCBUFF_H
/*
** The "bool" integral type was defined by the C++ committee in
** November of '94. Until the compiler supports this, use the following
** definition.
*/
#ifndef __BORLANDC__
#ifndef TRUE_FALSE_DEFINED
#define TRUE_FALSE_DEFINED
enum {false=0,true=1};
typedef int bool;
#endif
#endif
/*
** A general purpose buffer pointer handler object. It holds not only the pointer to the
** buffer, but its size as well. By using this class instead of separate pointer and size
** values, function interfaces and algorithms become simpler to manage and understand.
*/
class Buffer {
public:
Buffer(char * ptr, long size=0);
Buffer(void * ptr=0, long size=0);
Buffer(void const * ptr, long size=0);
Buffer(long size);
Buffer(Buffer const & buffer);
~Buffer(void);
Buffer & operator = (Buffer const & buffer);
operator void * (void) const {return(BufferPtr);}
operator char * (void) const {return((char *)BufferPtr);}
void Reset(void);
void * Get_Buffer(void) const {return(BufferPtr);}
long Get_Size(void) const {return(Size);}
bool Is_Valid(void) const {return(BufferPtr != 0);}
protected:
/*
** Pointer to the buffer memory.
*/
void * BufferPtr;
/*
** The size of the buffer memory.
*/
long Size;
/*
** Was the buffer allocated by this class? If so, then this class
** will be responsible for freeing the buffer.
*/
bool IsAllocated;
};
#endif

101
CODE/BUFFERX.H Normal file
View file

@ -0,0 +1,101 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/BUFFERX.H 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : BUFFER.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 05/04/96 *
* *
* Last Update : May 4, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef BUFFERx_H
#define BUFFERx_H
#include "wwfile.h"
/*
** This is a transmuter interface designed to aid implementation of compression, encryption, or
** data analysis classes. The Transmuter should be derived into a class that performs the necessary
** processing.
*/
class Transmuter {
public:
Transmuter(void) : Output(0) {}
virtual ~Transmuter(void) {}
/*
** These are the interface function that are used to pass data to the transmuter. The
** default implementation of these functions do nothing other than pass the data onto
** the subsequent transmuter. For practical use, these functions should be overloaded to
** do something more useful.
*/
virtual void Attach(Transmuter * transmuter) {Output = transmuter;}
virtual void Flush(void) {if (Output) Output->Flush();}
virtual void Put(const void * input, unsigned length) {if (Output) Output->Put(input, length);}
protected:
/*
** Pointer to the output transmuter.
*/
Transmuter * Output;
};
class FileTransmuter {
public:
FileTransmuter(FileClass * file = NULL) : OutputFile(file) {}
virtual void Attach(FileClass * file) {OutputFile = file;}
virtual void Flush(void) {}
virtual void Put(const void * input, unsigned length) {if (OutputFile) OutputFile->Write(input, length);}
protected:
FileClass * OutputFile;
};
class BufferTransmuter {
public:
BufferTransmuter(void * buffer = NULL) : BufferPtr(buffer) {}
virtual void Attach(void * buffer) {BufferPtr = buffer;}
virtual void Flush(void) {}
virtual void Put(const void * input, unsigned length) {if (BufferPtr) {memcpy(BufferPtr, input, length);((char *&)BufferPtr) += length;}}
protected:
void * BufferPtr;
};
#endif

64
CODE/BUGS.TXT Normal file
View file

@ -0,0 +1,64 @@
Fixed:
A415,A436,A437,A446,A447,A453,A466,A475,A488,
B171,B326,B407,B443,B530,B550,B566,B578,B600,
B609,B626,B628,B632,B637,B641,B644,B655,B658,
B675,B678,B684,B685,B688,B690,B698,B711,B715,
B726,B730,B731,B729,B732,B733,B738,B743,B744,
B747,B748,B750,B753,B759,B762,B766,B767,B768,
B770,B774,B775,B777,B778,B780,B781,B786,B795,
B797,B798,B805,C1001,C1007,C1011,C1012,C1014,
C1017,C1018,C1020,C1024,C1031,C1037,C1042,C1045,
C1052,C1061,C1054,C288,C487,C543,C546,
C666,C671,C697,C702,C773,C841,C856,C869,C871,
C887,C888,C904,C919,C922,C923,C925,C926
C927,C930,C932,C936,C938,C939,C942,C945,C947,
C953,C954,C962,C966,C967,C968,C975,C976,C977
C981,C982
Unsolved:
A035,A248,A352,A383,A417,A419,A420,A427,A445,A449,
A450,A455,A456,A457,A469,A470,A477,A478,A480,B005,
B042,B206,B207,B247,B284,B356,B418,B430,B467,B536,
B548,B549,B559,B633,B674,B686,B703,B714,B725,B740,
B745,B785,B787,B794,B796,B799,B802,B809,B817,B823,
C033,C072,C1000,C1002,C1004,C1006,C1008,C1009,C1013,C1016,
C1022,C1026,C1028,C1029,C1030,C1047,C1053,C1054,C1056,C1057,
C1059,C197,C318,C407,C409,C453,C502,C527,C530,C551,
C554,C573,C606,C676,C682,C694,C750,C776,C793,C811,
C821,C834,C867,C872,C877,C881,C896,C898,C901,C921,
C928,C929,C931,C933,C934,C940,C941,C943,C944,C946,
C952,C961,C964,C965,C969,C971,C794,C987,C988,C992,
C997
Old / Need more info / non-repeatable (maybe it's fixed now?):
A380,A388,A401,A414,A482,B445,B791,
A342,A402,A413,A434,A443,A460,A461,A462,A463,A468,
A472,A473,A476,A485,A489,A490,B1044,B513,B524,B608
B721,B773,B789,B807,B812,C570,C633,C654,C744,C778,
C853,C913,C963,C991,C998
Modem/Net Bug (for Bill):
A431,A452,A454,A464,A471,A481,A483,A486,A487,
B742,B760,B761,B764,B765,B772,B792,C1025,C1036,C1038
C883,C886,C895,C950,C951,C956,C993,C995
Design Bug (for Erik):
A432,A433,A448,A479,B041,B414,B659,B717,B719,B720,
B722,B723,B727,B728,B735,B736,B737,B741,
B756,B757,B758,B784,B802,B803,B808,B810,B815,
B816,B818,B822,C1010,C1023,C1027,C1035,C1044,
C1062,C534,C568,C637,C663,C918,C920,C924,C948,
C949,C986,C996,C999
Setup/Install/README.TXT Bug:
A458,A467,A484,B395,C957,C958,C959
Not Bug, repeated bug, suggestion, can't fix, or huh?:
A459,B1024,B218,B507,B522,B541,B546,B592,B593,B596,
B687,B724,B739,B746,B749,B763,B776,B779,B782,B783,
B790,B793,B806,B819,B820,B821,C1003,C1005,C1015,C1019,
C1032,C1033,C1034,C1039,C1040,C1043,C1048,
C1050,C1051,C1055,C1058,C1060,C1063,C336,C377,
C491,C537,C541,C578,C691,C703,C716,C781,C792,C838,
C854,C860,C879,C912,C915,C935,C937,C955,C970,C978,
C979,C980,C983,C984,C985,C990

5712
CODE/BUILDING.CPP Normal file

File diff suppressed because it is too large Load diff

356
CODE/BUILDING.H Normal file
View file

@ -0,0 +1,356 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/BUILDING.H 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : BUILDING.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : April 14, 1994 *
* *
* Last Update : April 14, 1994 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef BUILDING_H
#define BUILDING_H
#include "radio.h"
#include "cargo.h"
#include "mission.h"
#include "bullet.h"
#include "target.h"
#include "factory.h"
#include "techno.h"
#define MAX_DOOR_STAGE 18 // # of frames of door opening on weapons factory
#define DOOR_OPEN_STAGE 9 // frame on which the door is entirely open
#define MAX_REPAIR_ANIM_STAGE 5 // # of stages of anim for repair center cycling
/****************************************************************************
** For each instance of a building in the game, there is one of
** these structures. This structure holds information that is specific
** and dynamic for a particular building.
*/
class BuildingClass : public TechnoClass
{
public:
/*
** This points to the control data that gives this building its characteristics.
*/
CCPtr<BuildingTypeClass> Class;
/*
** If this building is in the process of producing something, then this
** will point to the factory manager.
*/
CCPtr<FactoryClass> Factory;
/*
** This is the house that originally owned this factory. Objects buildable
** by this house type will be produced from this factory regardless of who
** the current owner is.
*/
HousesType ActLike;
/*
** This building should be rebuilt if it is destroyed. This is in spite
** of the condition of the prebuilt base list.
*/
unsigned IsToRebuild:1;
/*
** Is the building allowed to repair itself?
*/
unsigned IsToRepair:1;
/*
** If the computer owns this building, then it is allowed to sell it if
** the situation warrants it. In the other case, it cannot sell the
** building regardless of conditions.
*/
unsigned IsAllowedToSell:1;
/*
** If the building is at a good point to change orders, then this
** flag will be set to true.
*/
unsigned IsReadyToCommence:1;
/*
** If this building is currently spending money to repair itself, then
** this flag is true. It will automatically be set to false when the building
** has reached full strength, when money is exhausted, or if the player
** specifically stops the repair process.
*/
unsigned IsRepairing:1;
/*
** If repair is currently in progress and this flag is true, then a wrench graphic
** will be overlaid on the building to give visual feedback for the repair process.
*/
unsigned IsWrenchVisible:1;
/*
** This flag is set when a commando has raided the building and planted
** plastic explosives. When the CommandoCountDown timer expires, the
** building takes massive damage.
*/
unsigned IsGoingToBlow:1;
/*
** If this building was destroyed by some method that would prevent
** survivors, then this flag will be true.
*/
unsigned IsSurvivorless:1;
/*
** These state control variables are used by the obelisk for the charging
** animation.
*/
unsigned IsCharging:1;
unsigned IsCharged:1;
/*
** A building that has been captured will not contain the full compliment
** of crew. This is true even if it subsequently gets captured back.
*/
unsigned IsCaptured:1;
/*
** Used by the gap generator to decide if it should jam or unjam
*/
unsigned IsJamming:1;
/*
** Used by radar facilities to know if they're being jammed by a mobile
** radar jammer
*/
unsigned IsJammed:1;
/*
** Used only by advanced tech center, this keeps track of whether the
** GPS satellite has been fired or not.
*/
unsigned HasFired:1;
/*
** If Grand_Opening was already called for this building, then this
** flag will be true. By utilizing this flag, multiple inadvertant
** calls to Grand_Opening won't cause problems.
*/
unsigned HasOpened:1;
/*
** Special countdown to destruction value. If the building is destroyed,
** it won't actually be removed from the map until this value reaches
** zero. This delay is for cosmetic reasons.
*/
CDTimerClass<FrameTimerClass> CountDown;
/*
** This is the current animation processing state that the building is
** in.
*/
BStateType BState;
BStateType QueueBState;
/*
** For multiplayer games, this keeps track of the last house to damage
** this building, so if it burns to death or otherwise gradually dies,
** proper credit can be given for the kill.
*/
HousesType WhoLastHurtMe;
/*
** This is the saboteur responsible for this building's destruction.
*/
TARGET WhomToRepay;
/*
** This is a record of the last strength of the building. Every so often,
** it will compare this strength to the current strength. If there is a
** discrepancy, then the owner power is adjusted accordingly.
*/
int LastStrength;
/*
** This is a target id of an animation we're keeping track of. Examples
** of this usage are the advanced tech center, which needs to know
** when the sputdoor animation has reached a certain stage.
*/
TARGET AnimToTrack;
/*
** This is the countdown timer that regulates placement retry logic
** for factory type buildings.
*/
CDTimerClass<FrameTimerClass> PlacementDelay;
/*---------------------------------------------------------------------
** Constructors, Destructors, and overloaded operators.
*/
static void * operator new(size_t size);
static void * operator new(size_t , void * ptr) {return(ptr);};
static void operator delete(void *ptr);
BuildingClass(StructType type, HousesType house);
#ifdef FIXIT_MULTI_SAVE
BuildingClass(NoInitClass const & x) : TechnoClass(x), Class(x), Factory(x), CountDown(x), PlacementDelay(x) {};
#else
BuildingClass(NoInitClass const & x) : TechnoClass(x), Class(x), CountDown(x), PlacementDelay(x) {};
#endif
virtual ~BuildingClass(void);
operator StructType(void) const {return Class->Type;};
/*---------------------------------------------------------------------
** Member function prototypes.
*/
static void Init(void);
TARGET Target_Scan(void);
BuildingTypeClass::AnimControlType const * Fetch_Anim_Control(void) {return (&Class->Anims[BState]);};
/*
** Query functions.
*/
virtual int Value(void) const;
virtual void const * Get_Image_Data(void) const;
virtual int How_Many_Survivors(void) const;
virtual DirType Turret_Facing(void) const;
virtual CELL Find_Exit_Cell(TechnoClass const * techno) const;
virtual InfantryType Crew_Type(void) const;
virtual int Pip_Count(void) const;
virtual bool Can_Player_Move(void) const;
virtual ActionType What_Action(ObjectClass const * target) const;
virtual ActionType What_Action(CELL cell) const;
virtual bool Can_Demolish(void) const;
virtual ObjectTypeClass const & Class_Of(void) const {return *Class;};
virtual DirType Fire_Direction(void) const;
virtual short const * Overlap_List(bool redraw=false) const;
int Shape_Number(void) const;
int Power_Output(void) const;
CELL Check_Point(CheckPointType cp) const;
/*
** Coordinate inquiry functions. These are used for both display and
** combat purposes.
*/
virtual COORDINATE Target_Coord(void) const;
virtual COORDINATE Docking_Coord(void) const;
virtual COORDINATE Center_Coord(void) const;
virtual COORDINATE Sort_Y(void) const;
virtual COORDINATE Exit_Coord(void) const;
/*
** Object entry and exit from the game system.
*/
virtual void Detach(TARGET target, bool all);
virtual void Detach_All(bool all=true);
virtual void Grand_Opening(bool captured = false);
virtual void Update_Buildables(void);
virtual MoveType Can_Enter_Cell(CELL cell, FacingType = FACING_NONE) const;
virtual bool Unlimbo(COORDINATE , DirType dir = DIR_N);
virtual bool Limbo(void);
/*
** Display and rendering support functionality. Supports imagery and how
** object interacts with the map and thus indirectly controls rendering.
*/
virtual void const * Remap_Table(void);
virtual int Exit_Object(TechnoClass * base);
virtual void Draw_It(int x, int y, WindowNumberType window) const;
virtual bool Mark(MarkType mark=MARK_CHANGE);
virtual void Fire_Out(void);
void Begin_Mode(BStateType bstate);
/*
** User I/O.
*/
virtual void Active_Click_With(ActionType action, ObjectClass * object);
virtual void Active_Click_With(ActionType action, CELL cell);
/*
** Combat related.
*/
virtual void Death_Announcement(TechnoClass const * source=0) const;
virtual FireErrorType Can_Fire(TARGET, int which) const;
virtual TARGET Greatest_Threat(ThreatType threat) const;
virtual ResultType Take_Damage(int & damage, int distance, WarheadType warhead, TechnoClass * source=0, bool forced=false);
virtual bool Captured(HouseClass * newowner);
void Update_Radar_Spied(void);
/*
** AI.
*/
void Charging_AI(void);
void Rotation_AI(void);
void Factory_AI(void);
void Repair_AI(void);
void Animation_AI(void);
virtual bool Revealed(HouseClass * house);
virtual void Repair(int control);
virtual void Sell_Back(int control);
virtual RadioMessageType Receive_Message(RadioClass * from, RadioMessageType message, long & param);
virtual void AI(void);
virtual void Assign_Target(TARGET target);
virtual bool Toggle_Primary(void);
bool Flush_For_Placement(TechnoClass * techno, CELL cell);
virtual int Mission_Unload(void);
virtual int Mission_Repair(void);
virtual int Mission_Attack(void);
virtual int Mission_Harvest(void);
virtual int Mission_Guard(void);
virtual int Mission_Construction(void);
virtual int Mission_Deconstruction(void);
virtual int Mission_Missile(void);
virtual void Enter_Idle_Mode(bool initial=false);
void Remove_Gap_Effect(void);
/*
** Scenario and debug support.
*/
#ifdef CHEAT_KEYS
virtual void Debug_Dump(MonoClass *mono) const;
#endif
/*
** File I/O.
*/
static void Read_INI(CCINIClass & ini);
static void Write_INI(CCINIClass & ini);
static char *INI_Name(void) {return "STRUCTURES";};
bool Load(Straw & file);
bool Save(Pipe & file) const;
private:
void Drop_Debris(TARGET source = TARGET_NONE);
static COORDINATE const CenterOffset[BSIZE_COUNT];
};
#endif

1070
CODE/BULLET.CPP Normal file

File diff suppressed because it is too large Load diff

149
CODE/BULLET.H Normal file
View file

@ -0,0 +1,149 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/BULLET.H 2 3/06/97 1:46p Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : BULLET.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : April 23, 1994 *
* *
* Last Update : April 23, 1994 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef BULLET_H
#define BULLET_H
#include "object.h"
#include "fly.h"
#include "fuse.h"
class BulletClass : public ObjectClass,
public FlyClass,
public FuseClass
{
public:
/*
** This specifies exactly what kind of bullet this is. All of the static attributes
** for this bullet is located in the BulletTypeClass pointed to by this variable.
*/
CCPtr<BulletTypeClass> Class;
private:
/*
** Records who sent this "present" so that an appropriate "thank you" can
** be returned.
*/
TechnoClass * Payback;
/*
** This is the facing that the projectile is travelling.
*/
FacingClass PrimaryFacing;
public:
/*---------------------------------------------------------------------
** Constructors, Destructors, and overloaded operators.
*/
static void * operator new(size_t size);
static void * operator new(size_t , void * ptr) {return(ptr);};
static void operator delete(void *ptr);
BulletClass(BulletType id, TARGET target, TechnoClass * Payback, int strength, WarheadType warhead, int speed);
#ifdef FIXIT_MULTI_SAVE
BulletClass(NoInitClass const & x) : ObjectClass(x), Class(x), FlyClass(x), FuseClass(x), PrimaryFacing(x) {};
#else
BulletClass(NoInitClass const & x) : ObjectClass(x), Class(x), FlyClass(x), FuseClass(x) {};
#endif
virtual ~BulletClass(void);
operator BulletType(void) const {return Class->Type;};
/*---------------------------------------------------------------------
** Member function prototypes.
*/
static void Init(void);
bool Is_Forced_To_Explode(COORDINATE & coord) const;
void Bullet_Explodes(bool forced);
int Shape_Number(void) const;
virtual LayerType In_Which_Layer(void) const;
virtual COORDINATE Sort_Y(void) const;
virtual void Assign_Target(TARGET target) {TarCom = target;};
virtual bool Unlimbo(COORDINATE , DirType facing = DIR_N);
virtual ObjectTypeClass const & Class_Of(void) const {return *Class;};
virtual void Detach(TARGET target, bool all);
virtual void Draw_It(int x, int y, WindowNumberType window) const;
virtual bool Mark(MarkType mark=MARK_CHANGE);
virtual void AI(void);
virtual short const * Occupy_List(bool = false) const;
virtual short const * Overlap_List(void) const {return Occupy_List(false);};
virtual COORDINATE Target_Coord(void) const;
/*
** File I/O.
*/
bool Load(Straw & file);
bool Save(Pipe & file) const;
virtual void Code_Pointers(void);
virtual void Decode_Pointers(void);
/*
** If this bullet is forced to be inaccurate because of some outside means. A tank
** firing while moving is a good example.
*/
unsigned IsInaccurate:1;
private:
// Crude animation flag.
unsigned IsToAnimate:1;
/*
** Is this missile allowed to come in from out of bounds?
*/
unsigned IsLocked:1;
/*
** This is the target of the projectile. It is especially significant for those projectiles
** that home in on a target.
*/
TARGET TarCom;
/*
** The speed of this projectile.
*/
int MaxSpeed;
/*
** The warhead of this projectile.
*/
WarheadType Warhead;
};
#endif

410
CODE/C&CZERO.PJT Normal file
View file

@ -0,0 +1,410 @@
;Codewright Project File (do not remove or modify this line)
[ProjInit]
ProjSetConfigFlags=0x00010140
[Files]
c:\projects\c&c\code\aadata.cpp
c:\projects\c&czero\code\aadata.cpp
c:\projects\c&czero\code\abstract.cpp
c:\projects\c&czero\code\abstract.h
c:\projects\c&czero\code\adata.cpp
c:\projects\c&czero\code\ADPCM.CPP
c:\projects\c&czero\code\aircraft.cpp
c:\projects\c&czero\code\aircraft.h
c:\projects\c&czero\code\alloc.cpp
c:\projects\c&czero\code\anim.cpp
c:\projects\c&czero\code\anim.h
c:\projects\c&czero\code\audio.cpp
c:\projects\c&czero\code\audio.h
c:\projects\c&czero\code\base.cpp
c:\projects\c&czero\code\base.h
c:\projects\c&czero\code\bbdata.cpp
c:\projects\c&czero\code\bdata.cpp
c:\projects\c&czero\code\BFIOFILE.CPP
c:\projects\c&czero\code\BFIOFILE.H
c:\projects\c&czero\code\building.cpp
c:\projects\c&czero\code\building.h
c:\projects\c&czero\code\bullet.cpp
c:\projects\c&czero\code\bullet.h
c:\projects\c&czero\code\cargo.cpp
c:\projects\c&czero\code\cargo.h
c:\projects\c&czero\code\CARRY.CPP
c:\projects\c&czero\code\CARRY.H
c:\projects\c&czero\code\ccfile.cpp
c:\projects\c&czero\code\ccfile.h
c:\projects\c&czero\code\cdata.cpp
c:\projects\c&czero\code\cdfile.cpp
c:\projects\c&czero\code\cdfile.h
c:\projects\c&czero\code\cell.cpp
c:\projects\c&czero\code\cell.h
c:\projects\c&czero\code\checkbox.cpp
c:\projects\c&czero\code\checkbox.h
c:\projects\c&czero\code\cheklist.cpp
c:\projects\c&czero\code\cheklist.h
c:\projects\c&czero\code\colrlist.cpp
c:\projects\c&czero\code\colrlist.h
c:\projects\c&czero\code\combat.cpp
c:\projects\c&czero\code\combuf.cpp
c:\projects\c&czero\code\combuf.h
c:\projects\c&czero\code\compat.h
c:\projects\c&czero\code\comqueue.cpp
c:\projects\c&czero\code\comqueue.h
c:\projects\c&czero\code\confdlg.cpp
c:\projects\c&czero\code\confdlg.h
c:\projects\c&czero\code\connect.cpp
c:\projects\c&czero\code\connect.h
c:\projects\c&czero\code\connmgr.h
c:\projects\c&czero\code\conquer.cpp
c:\projects\c&czero\code\conquer.h
c:\projects\c&czero\code\const.cpp
c:\projects\c&czero\code\control.cpp
c:\projects\c&czero\code\control.h
c:\projects\c&czero\code\coord.cpp
c:\projects\c&czero\code\crc.cpp
c:\projects\c&czero\code\crc.h
c:\projects\c&czero\code\credits.cpp
c:\projects\c&czero\code\credits.h
c:\projects\c&czero\code\crew.cpp
c:\projects\c&czero\code\crew.h
c:\projects\c&czero\code\cwstub.c
c:\projects\c&czero\code\debug.cpp
c:\projects\c&czero\code\debug.h
c:\projects\c&czero\code\defines.h
c:\projects\c&czero\code\descdlg.cpp
c:\projects\c&czero\code\descdlg.h
c:\projects\c&czero\code\dial8.cpp
c:\projects\c&czero\code\dial8.h
c:\projects\c&czero\code\dialog.cpp
c:\projects\c&czero\code\display.cpp
c:\projects\c&czero\code\display.h
c:\projects\c&czero\code\door.cpp
c:\projects\c&czero\code\door.h
c:\projects\c&czero\code\dpmi.cpp
c:\projects\c&czero\code\dpmi.h
c:\projects\c&czero\code\drive.cpp
c:\projects\c&czero\code\drive.h
c:\projects\c&czero\code\drop.cpp
c:\projects\c&czero\code\drop.h
c:\projects\c&czero\code\DTABLE.CPP
c:\projects\c&czero\code\edit.cpp
c:\projects\c&czero\code\edit.h
c:\projects\c&czero\code\ending.cpp
c:\projects\c&czero\code\ending.h
c:\projects\c&czero\code\event.cpp
c:\projects\c&czero\code\event.h
c:\projects\c&czero\code\expand.cpp
c:\projects\c&czero\code\externs.h
c:\projects\c&czero\code\FACE.CPP
c:\projects\c&czero\code\FACE.H
c:\projects\c&czero\code\facing.cpp
c:\projects\c&czero\code\facing.h
c:\projects\c&czero\code\factory.cpp
c:\projects\c&czero\code\factory.h
c:\projects\c&czero\code\findpath.cpp
c:\projects\c&czero\code\flasher.cpp
c:\projects\c&czero\code\flasher.h
c:\projects\c&czero\code\fly.cpp
c:\projects\c&czero\code\fly.h
c:\projects\c&czero\code\foot.cpp
c:\projects\c&czero\code\foot.h
c:\projects\c&czero\code\ftimer.h
c:\projects\c&czero\code\function.h
c:\projects\c&czero\code\fuse.cpp
c:\projects\c&czero\code\fuse.h
c:\projects\c&czero\code\gadget.cpp
c:\projects\c&czero\code\gadget.h
c:\projects\c&czero\code\gamedlg.cpp
c:\projects\c&czero\code\gamedlg.h
c:\projects\c&czero\code\gauge.cpp
c:\projects\c&czero\code\gauge.h
c:\projects\c&czero\code\globals.cpp
c:\projects\c&czero\code\goptions.cpp
c:\projects\c&czero\code\goptions.h
c:\projects\c&czero\code\gscreen.cpp
c:\projects\c&czero\code\gscreen.h
c:\projects\c&czero\code\hdata.cpp
c:\projects\c&czero\code\heap.cpp
c:\projects\c&czero\code\heap.h
c:\projects\c&czero\code\help.cpp
c:\projects\c&czero\code\help.h
c:\projects\c&czero\code\house.cpp
c:\projects\c&czero\code\house.h
c:\projects\c&czero\code\HSV.CPP
c:\projects\c&czero\code\HSV.H
c:\projects\c&czero\code\idata.cpp
c:\projects\c&czero\code\infantry.cpp
c:\projects\c&czero\code\infantry.h
c:\projects\c&czero\code\ini.cpp
c:\projects\c&czero\code\inibin.cpp
c:\projects\c&czero\code\inicode.cpp
c:\projects\c&czero\code\init.cpp
c:\projects\c&czero\code\intro.cpp
c:\projects\c&czero\code\intro.h
c:\projects\c&czero\code\iomap.cpp
c:\projects\c&czero\code\ioobj.cpp
c:\projects\c&czero\code\ipx.cpp
c:\projects\c&czero\code\ipx.h
c:\projects\c&czero\code\ipxaddr.cpp
c:\projects\c&czero\code\ipxaddr.h
c:\projects\c&czero\code\ipxconn.cpp
c:\projects\c&czero\code\ipxconn.h
c:\projects\c&czero\code\ipxgconn.cpp
c:\projects\c&czero\code\ipxgconn.h
c:\projects\c&czero\code\ipxmgr.cpp
c:\projects\c&czero\code\ipxmgr.h
c:\projects\c&czero\code\itable.cpp
c:\projects\c&czero\code\jshell.cpp
c:\projects\c&czero\code\jshell.h
c:\projects\c&czero\code\keyframe.cpp
c:\projects\c&czero\code\layer.cpp
c:\projects\c&czero\code\layer.h
c:\projects\c&czero\code\lcwuncmp.cpp
c:\projects\c&czero\code\led.h
c:\projects\c&czero\code\link.cpp
c:\projects\c&czero\code\link.h
c:\projects\c&czero\code\lint.h
c:\projects\c&czero\code\list.cpp
c:\projects\c&czero\code\list.h
c:\projects\c&czero\code\loaddlg.cpp
c:\projects\c&czero\code\loaddlg.h
c:\projects\c&czero\code\logic.cpp
c:\projects\c&czero\code\logic.h
c:\projects\c&czero\code\map.cpp
c:\projects\c&czero\code\map.h
c:\projects\c&czero\code\mapeddlg.cpp
c:\projects\c&czero\code\mapedit.cpp
c:\projects\c&czero\code\mapedit.h
c:\projects\c&czero\code\mapedplc.cpp
c:\projects\c&czero\code\mapedsel.cpp
c:\projects\c&czero\code\mapedtm.cpp
c:\projects\c&czero\code\mapsel.cpp
c:\projects\c&czero\code\menus.cpp
c:\projects\c&czero\code\message.h
c:\projects\c&czero\code\mission.cpp
c:\projects\c&czero\code\mission.h
c:\projects\c&czero\code\mixfile.cpp
c:\projects\c&czero\code\mixfile.h
c:\projects\c&czero\code\monoc.cpp
c:\projects\c&czero\code\monoc.h
c:\projects\c&czero\code\mouse.cpp
c:\projects\c&czero\code\mouse.h
c:\projects\c&czero\code\mplayer.cpp
c:\projects\c&czero\code\msgbox.cpp
c:\projects\c&czero\code\msgbox.h
c:\projects\c&czero\code\msglist.cpp
c:\projects\c&czero\code\msglist.h
c:\projects\c&czero\code\netdlg.cpp
c:\projects\c&czero\code\nullconn.cpp
c:\projects\c&czero\code\nullconn.h
c:\projects\c&czero\code\nulldlg.cpp
c:\projects\c&czero\code\nullmgr.cpp
c:\projects\c&czero\code\nullmgr.h
c:\projects\c&czero\code\object.cpp
c:\projects\c&czero\code\object.h
c:\projects\c&czero\code\odata.cpp
c:\projects\c&czero\code\options.cpp
c:\projects\c&czero\code\options.h
c:\projects\c&czero\code\overlay.cpp
c:\projects\c&czero\code\overlay.h
c:\projects\c&czero\code\PALETTE.CPP
c:\projects\c&czero\code\PALETTE.H
c:\projects\c&czero\code\phone.h
c:\projects\c&czero\code\power.cpp
c:\projects\c&czero\code\power.h
c:\projects\c&czero\code\profile.cpp
c:\projects\c&czero\code\queue.cpp
c:\projects\c&czero\code\queue.h
c:\projects\c&czero\code\radar.cpp
c:\projects\c&czero\code\radar.h
c:\projects\c&czero\code\radio.cpp
c:\projects\c&czero\code\radio.h
c:\projects\c&czero\code\rand.cpp
c:\projects\c&czero\code\RANDOM.CPP
c:\projects\c&czero\code\RANDOM.H
c:\projects\c&czero\code\rawfile.cpp
c:\projects\c&czero\code\rawfile.h
c:\projects\c&czero\code\region.h
c:\projects\c&czero\code\reinf.cpp
c:\projects\c&czero\code\RGB.CPP
c:\projects\c&czero\code\RGB.H
c:\projects\c&czero\code\ROTBMP.CPP
c:\projects\c&czero\code\ROTBMP.H
c:\projects\c&czero\code\savedlg.h
c:\projects\c&czero\code\saveload.cpp
c:\projects\c&czero\code\scenario.cpp
c:\projects\c&czero\code\SCENARIO.H
c:\projects\c&czero\code\score.cpp
c:\projects\c&czero\code\score.h
c:\projects\c&czero\code\screen.h
c:\projects\c&czero\code\scroll.cpp
c:\projects\c&czero\code\scroll.h
c:\projects\c&czero\code\sdata.cpp
c:\projects\c&czero\code\SESSION.CPP
c:\projects\c&czero\code\SESSION.H
c:\projects\c&czero\code\shapebtn.cpp
c:\projects\c&czero\code\shapebtn.h
c:\projects\c&czero\code\sidebar.cpp
c:\projects\c&czero\code\sidebar.h
c:\projects\c&czero\code\slider.cpp
c:\projects\c&czero\code\slider.h
c:\projects\c&czero\code\smudge.cpp
c:\projects\c&czero\code\smudge.h
c:\projects\c&czero\code\sounddlg.cpp
c:\projects\c&czero\code\sounddlg.h
c:\projects\c&czero\code\special.cpp
c:\projects\c&czero\code\special.h
c:\projects\c&czero\code\SPRITE.CPP
c:\projects\c&czero\code\stage.h
c:\projects\c&czero\code\startup.cpp
c:\projects\c&czero\code\super.cpp
c:\projects\c&czero\code\super.h
c:\projects\c&czero\code\tab.cpp
c:\projects\c&czero\code\tab.h
c:\projects\c&czero\code\TACTION.CPP
c:\projects\c&czero\code\TACTION.H
c:\projects\c&czero\code\target.cpp
c:\projects\c&czero\code\target.h
c:\projects\c&czero\code\tdata.cpp
c:\projects\c&czero\code\team.cpp
c:\projects\c&czero\code\team.h
c:\projects\c&czero\code\teamtype.cpp
c:\projects\c&czero\code\teamtype.h
c:\projects\c&czero\code\techno.cpp
c:\projects\c&czero\code\techno.h
c:\projects\c&czero\code\template.cpp
c:\projects\c&czero\code\template.h
c:\projects\c&czero\code\terrain.cpp
c:\projects\c&czero\code\terrain.h
c:\projects\c&czero\code\TEVENT.CPP
c:\projects\c&czero\code\TEVENT.H
c:\projects\c&czero\code\textbtn.cpp
c:\projects\c&czero\code\textbtn.h
c:\projects\c&czero\code\theme.cpp
c:\projects\c&czero\code\theme.h
c:\projects\c&czero\code\toggle.cpp
c:\projects\c&czero\code\toggle.h
c:\projects\c&czero\code\trigger.cpp
c:\projects\c&czero\code\trigger.h
c:\projects\c&czero\code\txtlabel.cpp
c:\projects\c&czero\code\txtlabel.h
c:\projects\c&czero\code\type.h
c:\projects\c&czero\code\udata.cpp
c:\projects\c&czero\code\unit.cpp
c:\projects\c&czero\code\unit.h
c:\projects\c&czero\code\vdata.cpp
c:\projects\c&czero\code\vector.cpp
c:\projects\c&czero\code\vector.h
c:\projects\c&czero\code\VERSION.CPP
c:\projects\c&czero\code\VERSION.H
c:\projects\c&czero\code\vessel.cpp
c:\projects\c&czero\code\vessel.h
c:\projects\c&czero\code\visudlg.cpp
c:\projects\c&czero\code\visudlg.h
c:\projects\c&czero\code\watcom.h
c:\projects\c&czero\code\wwalloc.h
c:\projects\c&czero\code\wwfile.h
C:\projects\c&czero\code\2KEYFRAM.CPP
C:\projects\c&czero\code\BLOWFISH.CPP
C:\projects\c&czero\code\BLOWFISH.H
C:\projects\c&czero\code\FILEPCX.H
C:\projects\c&czero\code\INT.CPP
C:\projects\c&czero\code\INT.H
C:\projects\c&czero\code\interpal.cpp
C:\projects\c&czero\code\language.h
C:\projects\c&czero\code\MP.CPP
C:\projects\c&czero\code\MP.H
C:\projects\c&czero\code\RNG.H
C:\projects\c&czero\code\SHA.CPP
C:\projects\c&czero\code\SHA.H
C:\projects\c&czero\code\tarcom.cpp
C:\projects\c&czero\code\tcpip.h
C:\projects\c&czero\code\winstub.cpp
c:\projects\c&czero\code\BUFFERX.H
c:\projects\c&czero\code\ini.h
c:\projects\c&czero\code\listnode.h
c:\projects\c&czero\code\rules.cpp
c:\projects\c&czero\code\rules.h
c:\projects\c&czero\code\tarcom.h
c:\projects\c&czero\code\turret.cpp
c:\projects\c&czero\code\turret.h
c:\projects\c&czero\code\warhead.h
c:\projects\c&czero\code\weapon.h
[State]
SysSetCwd='C:\projects\c&czero\code'
SrchSetFlags=0x000320aa
FileSortMode=0x0
StateWindowFrame=37,16,923,511,0x62c9f5fa
_StateWindow=0,0,990,647,0x00100018,'C:\projects\c&czero\code\palette.cpp',240,15,244,32,32,0,32,32,32,32,8,4294967295,4294967295,1,10,'',12,255,48,0,7,243,252,253,247,249,247,93,1,400,0,246,252,248,244,247,15,15,15,15,0,0
_StateBuffer='C:\projects\c&czero\code\palette.cpp',0x0400048e,93,1,25,'4 7','',0x0,''
_StateBuffer='C:\projects\c&czero\code\jshell.h',0x0400048e,1,2,25,'4 7','',0x0,''
_StateBuffer='C:\projects\c&czero\code\sprite.cpp',0x0400048e,35,1,25,'4 7','',0x0,''
_StateBuffer='C:\projects\c&czero\code\wwfile.h',0x0400048e,21,1,25,'4 7','',0x0,''
_StateBuffer='C:\projects\c&czero\win32lib\INCLUDE\RAWFILE.H',0x0400048e,1,1,25,'4 7','',0x0,''
_StateBuffer='C:\projects\c&czero\code\ROTBMP.H',0x0400048e,9,1,25,'4 7','',0x0,''
_StateBuffer='C:\projects\c&czero\code\rotbmp.cpp',0x0400048e,6,1,25,'4 7','',0x0,''
_StateBuffer='C:\projects\c&czero\code\function.h',0x0400048e,157,1,25,'4 7','',0x0,''
_StateBuffer='C:\projects\c&czero\wwflat32\INCLUDE\gbuffer.h',0x0400048e,265,26,25,'4 7','',0x0,''
_StateBuffer='C:\projects\c&czero\code\anim.cpp',0x0400048e,682,1,25,'4 7','',0x0,''
_StateBuffer='C:\projects\c&czero\code\makefile',0x0400048e,420,1,25,'5 9','',0x0,''
_StateBuffer='C:\projects\c&czero\code\crc.cpp',0x0400048e,1,1,25,'4 7','',0x0,''
_StateBuffer='C:\projects\c&czero\code\PALETTE.H',0x0400048e,1,1,25,'4 7','',0x0,''
_StateHistory=SEARCH,'::Mission_U','Force_','MOUSE_','jshell','WindowsTim','LINKFILE','game.dat','wwflat','wwlib','Bitmap'
_StateHistory=REPLACE,'building','bindex','vindex','iindex','AIRCRAFT','AircraftType','aircraft','aindex','_Scale_To_256','tech'
_StateHistory=XMACRO,'small','sort','SORT','sort','SORT','sort','SORT','sort','SORT','sort'
_StateHistory=FILELIST,'C:\projects\c&czero\wwflat32\INCLUDE\gbuffer.h','C:\projects\c&czero\code\function.h','C:\projects\c&czero\code\rotbmp.cpp','C:\projects\c&czero\code\ROTBMP.H','C:\projects\c&czero\code\jshell.h','C:\projects\c&czero\code\palette.cpp','C:\projects\c&czero\code\crc.cpp','C:\projects\c&czero\code\makefile','C:\projects\c&czero\code\PALETTE.H','C:\projects\c&czero\code\anim.cpp'
_StateHistory=EDITFILE,'palette.cpp','crc.cpp','makefile','palette.cpp','palette.h','makefile','anim.cpp','palette.cpp','function.h','jshell.h'
_StateHistory=DIRECTORY,'c:\\','c:\projects\c&c\code','e:\c&czero\code','e:','c:\projects\c&czero\code','c:','C:\PROJECTS\C&Czero\code','c:\projects\C&Czero\code'
_StateHistory=GOTOMARK,'2','1','2','1','2','3','1','2','3','1'
_StateHistory=OUTNAME,'tab.cpp','power.cpp','2txtprnt.asm','display.cpp','scroll.cpp','sidebar.cpp','power.cpp','help.cpp','tab.cpp','mapeddlg.cpp'
_StateHistory=GOTOLINE,'1665','410','93','375','590','231','246','616','384','686'
_StateHistory=WBLOCK,'c:\temp\face.cpp','c:\temp\face.h'
_StateHistory=FILTER,'sort'
_StateHistory=DOSHISTORY,'eset path','ndos','eset path','set path=%PATH%;c:\utils','ts *.cpp Interpolated','n','d:','exit','ts *.cpp Interpolated','exit'
_StateMark=MARK_POSITION,1,'C:\projects\c&czero\wwflat32\INCLUDE\gbuffer.h',265,25,0
_StateMark=MARK_POSITION,1,'C:\projects\c&czero\code\jshell.h',1,1,0
[Editor]
ClipboardSetTermStr='\r\n',0
ClipboardEnableTermStr=1
ClipboardSetSepStr='\r\n',0
ClipboardEnableSepStr=1
ScrapSetCount=1
VCSProject=''
VCSProjectPath=''
VCSProjectLocalPath=''
_RestoreSysFlags=0x6249f5fa, 0xfffffffc
[Compiler]
TagSetCmd='${HOME}${WTAGS} -oc -d -t${TAGFILE}.tag -p${TAGFILE}.ptg',0x8000060
BrowseSetFile='c:\projects\c&czero\code\c&czero.ptg'
TagSetFile='c:\projects\c&czero\code\c&czero.tag'
CompilerAddCmd='Microsoft Assembler','ftee masm -w2 -zi %r%e;',1073741824,'',0,'',16,'',16,'',0,'',0,'_MicrosoftErrorInfo','','','','%v%p'
CompilerAddResponse='Microsoft Assembler',
CompilerAddCmd='Borland C++','ftee bcc -S %r.c',1073741824,'',0,'ftee make %r.obj',16,'ftee make %r.obj',16,'',0,'',0,'_BorlandCppErrorInfo','','','','%v%p'
CompilerAddResponse='Borland C++',
CompilerAddCmd='Borland Turbo Assembler','ftee make %r.obj',1073741824,'',0,'ftee make %r.obj',16,'',16,'',0,'',0,'_TasmErrorInfo','','','','%v%p'
CompilerAddResponse='Borland Turbo Assembler',
CompilerAddCmd='$_cw_proj_hash_$','',1073741825,'',1,'ftee watcom\binw\wmake %r.obj',209,'ftee m.bat',209,'ftee joemake',209,'g.bat -hansolo cheater -xm -editor',224,'_MSLinkErrorInfo','_MicrosoftErrorInfo','_NMakeErrorInfo','proj.err','c:\projects\c&czero\code'
CompilerAddResponse='$_cw_proj_hash_$',
CompilerAddCmd='Default Project','',1073741824,'',0,'ftee make',16,'ftee make',16,'',0,'',0,'_ErrorInfoDefault','','','proj.err','%v%p'
CompilerAddResponse='Default Project',
CompilerAddCmd='Microsoft C','ftee cl -c -AL -Gsw -Ow -Zpe %r%e',1073741824,'',0,'',16,'',16,'',0,'',0,'_MicrosoftErrorInfo','','','','%v%p'
CompilerAddResponse='Microsoft C',
CompilerAddCmd='Script','ftee make %r.inf',1073741824,'',0,'ftee make',16,'ftee make',16,'',0,'',0,'_BorlandCppErrorInfo','','','',''
CompilerAddResponse='Script',
CompilerAddCmd='Zortech C++','ftee ztc -a -b -c -g -ml -W %r%e',1073741824,'',0,'',16,'',16,'',0,'',0,'_ZortechCppErrorInfo','','','','%v%p'
CompilerAddResponse='Zortech C++',
CompilerAddCmd='Microsoft C(NT-i386)','${FTEE} cl -DSTRICT -c -W3 -G3 -D_X86_=1 -DWIN32 %r%e',1073741936,'${FTEE} cl -DSTRICT -c -W3 -G3 -D_X86_=1 -DWIN32 %r%e',112,'',144,'',144,'',0,'',0,'_MicrosoftErrorInfo','','','',''
CompilerAddResponse='Microsoft C(NT-i386)',
CompilerAssign='Borland C++','.scr'
CompilerNewExt=.bas
CompilerAssign='Borland C++','.int'
CompilerAssign='Borland C++','.c'
CompilerNewExt=.prg
CompilerAssign='Microsoft C','.h'
CompilerAssign='Borland C++','.cpp'
CompilerAssign='Default Project','.*'
CompilerAssign='Microsoft C(NT-i386)','.cxx'
CompilerAssign='Borland Turbo Assembler','.asm'
CompilerAssign='Microsoft C(NT-i386)','.hpp'

183
CODE/CARGO.CPP Normal file
View file

@ -0,0 +1,183 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/CARGO.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : CARGO.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : April 23, 1994 *
* *
* Last Update : 10/31/94 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* CargoClass::Attach -- Add unit to cargo hold. *
* CargoClass::Attached_Object -- Determine attached unit pointer. *
* CargoClass::Debug_Dump -- Displays the cargo value to the monochrome screen. *
* CargoClass::Detach_Object -- Removes a unit from the cargo hold. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
#ifdef CHEAT_KEYS
/***********************************************************************************************
* CargoClass::Debug_Dump -- Displays the cargo value to the monochrome screen. *
* *
* This routine is used to dump the current cargo value to the monochrome monitor. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/02/1994 JLB : Created. *
*=============================================================================================*/
void CargoClass::Debug_Dump(MonoClass * mono) const
{
if (How_Many()) {
mono->Set_Cursor(63, 3);
mono->Printf("(%d)%04X", How_Many(), Attached_Object());
}
}
#endif
/***********************************************************************************************
* CargoClass::Attach -- Add unit to cargo hold. *
* *
* This routine will add the specified unit to the cargo hold. The *
* unit will chain to any existing units in the hold. The chaining is *
* in a LIFO order. *
* *
* INPUT: object-- Pointer to the object to attach to the cargo hold. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 04/23/1994 JLB : Created. *
* 10/31/94 JLB : Handles chained objects. *
*=============================================================================================*/
void CargoClass::Attach(FootClass * object)
{
/*
** If there is no object, then no action is necessary.
*/
if (object == NULL) return;
object->Limbo();
/*
** Attach any existing cargo hold object to the end of the list as indicated by the
** object pointer passed into this routine. This is necessary because several objects may
** be attached at one time or several objects may be attached as a result of several calls
** to this routine. Either case must be handled properly.
*/
ObjectClass * o = object->Next;
while (o != NULL) {
if (o->Next == (void*)NULL) break;
o = o->Next;
}
if (o != NULL) {
o->Next = CargoHold;
} else {
object->Next = CargoHold;
}
/*
** Finally, assign the object pointer as the first object attached to this cargo hold.
*/
CargoHold = object;
Quantity = 0;
object = CargoHold;
while (object != NULL) {
Quantity++;
object = (FootClass *)(ObjectClass *)object->Next;
}
}
/***********************************************************************************************
* CargoClass::Detach_Object -- Removes a unit from the cargo hold. *
* *
* This routine will take a unit from the cargo hold and extract it. *
* The unit extracted is the last unit added to the hold. If there *
* is no unit in the hold or the occupant is not a unit, then NULL is *
* returned. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with a pointer to the unit that has been extracted. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 04/23/1994 JLB : Created. *
* 06/07/1994 JLB : Handles generic object types. *
*=============================================================================================*/
FootClass * CargoClass::Detach_Object(void)
{
TechnoClass * unit = Attached_Object();
if (unit != NULL) {
CargoHold = (FootClass *)(ObjectClass *)unit->Next;
unit->Next = 0;
Quantity--;
}
return((FootClass *)unit);
}
/***********************************************************************************************
* CargoClass::Attached_Object -- Determine attached unit pointer. *
* *
* This routine will return with a pointer to the attached unit if one *
* is present. One would need to know this if this is a transport *
* unit and it needs to unload. *
* *
* INPUT: none *
* *
* OUTPUT: Returns a pointer to the attached unit. If there is no *
* attached unit, then return NULL. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/07/1992 JLB : Created. *
* 06/07/1994 JLB : Handles generic object types. *
*=============================================================================================*/
FootClass * CargoClass::Attached_Object(void) const
{
if (Is_Something_Attached()) {
return(CargoHold);
}
return(NULL);
}

93
CODE/CARGO.H Normal file
View file

@ -0,0 +1,93 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/CARGO.H 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : CARGO.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : April 23, 1994 *
* *
* Last Update : April 23, 1994 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef CARGO_H
#define CARGO_H
class FootClass;
/****************************************************************************
** This class handles the basic cargo logic.
*/
class CargoClass {
public:
/*---------------------------------------------------------------------
** Constructors, Destructors, and overloaded operators.
*/
CargoClass(void) : Quantity(0), CargoHold(0) {};
CargoClass(NoInitClass const & ) {};
~CargoClass(void) {CargoHold=0;};
/*---------------------------------------------------------------------
** Member function prototypes.
*/
#ifdef CHEAT_KEYS
void Debug_Dump(MonoClass *mono) const;
#endif
void AI(void) {};
int How_Many(void) const {return Quantity;};
bool Is_Something_Attached(void) const {return (CargoHold != 0);};
FootClass * Attached_Object(void) const;
FootClass * Detach_Object(void);
void Attach(FootClass * object);
/*
** File I/O.
*/
void Code_Pointers(void);
void Decode_Pointers(void);
private:
/*
** This is the number of objects attached to this cargo hold. For transporter
** objects, they might contain more than one object.
*/
unsigned char Quantity;
/*
** This is the target value of any attached object. A value of zero indicates
** that no object is attached.
*/
FootClass * CargoHold;
};
#endif

153
CODE/CARRY.CPP Normal file
View file

@ -0,0 +1,153 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/CARRY.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : CARRY.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 02/26/96 *
* *
* Last Update : May 10, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* CarryoverClass::CarryoverClass -- Constructor for carry over objects. *
* CarryoverClass::Create -- Creates a carried over object. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
/***********************************************************************************************
* CarryoverClass::CarryoverClass -- Constructor for carry over objects. *
* *
* This is the constructor for a carry over object. Such an object is used to record the *
* object that will be "carried over" into a new scenario at some future time. *
* *
* INPUT: techno -- Pointer to the object that will be carried over. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/10/1996 JLB : Created. *
*=============================================================================================*/
CarryoverClass::CarryoverClass(TechnoClass * techno) :
RTTI(RTTI_NONE),
Cell(0),
Strength(0),
House(HOUSE_NONE)
{
if (techno) {
RTTI = techno->What_Am_I();
switch (RTTI) {
case RTTI_UNIT:
Type.Unit = ((UnitClass *)techno)->Class->Type;
break;
case RTTI_BUILDING:
Type.Building = ((BuildingClass *)techno)->Class->Type;
break;
case RTTI_INFANTRY:
Type.Infantry = ((InfantryClass *)techno)->Class->Type;
break;
case RTTI_VESSEL:
Type.Vessel = ((VesselClass *)techno)->Class->Type;
break;
default:
break;
}
House = techno->Owner();
Strength = techno->Strength;
Cell = Coord_Cell(techno->Coord);
}
}
/***********************************************************************************************
* CarryoverClass::Create -- Creates a carried over object. *
* *
* Use this routine to convert a carried over object into an actual object that will be *
* placed on the map. *
* *
* INPUT: none *
* *
* OUTPUT: bool; Was the object successfully created and placed on the map? *
* *
* WARNINGS: This routine might not place the object if the old map location was invalid *
* or there are other barriers to the object's creation and placement. *
* *
* HISTORY: *
* 05/10/1996 JLB : Created. *
*=============================================================================================*/
bool CarryoverClass::Create(void) const
{
TechnoClass * techno = 0;
TechnoTypeClass const * ttype = 0;
switch (RTTI) {
case RTTI_UNIT:
ttype = &UnitTypeClass::As_Reference(Type.Unit);
techno = new UnitClass(Type.Unit, House);
break;
case RTTI_INFANTRY:
ttype = &InfantryTypeClass::As_Reference(Type.Infantry);
techno = new InfantryClass(Type.Infantry, House);
break;
case RTTI_BUILDING:
ttype = &BuildingTypeClass::As_Reference(Type.Building);
techno = new BuildingClass(Type.Building, House);
break;
case RTTI_VESSEL:
ttype = &VesselTypeClass::As_Reference(Type.Vessel);
techno = new VesselClass(Type.Vessel, House);
break;
}
if (techno) {
bool oldscen = ScenarioInit;
techno->Strength = Strength;
if (RTTI == RTTI_INFANTRY) {
ScenarioInit = 0;
}
techno->Unlimbo(Cell_Coord(Cell));
if (RTTI == RTTI_INFANTRY) {
ScenarioInit = oldscen;
}
}
return(false);
}

84
CODE/CARRY.H Normal file
View file

@ -0,0 +1,84 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/CARRY.H 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : CARRY.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 02/26/96 *
* *
* Last Update : February 26, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef CARRY_H
#define CARRY_H
class CarryoverClass : public LinkClass {
public:
CarryoverClass(TechnoClass * techno = 0);
CarryoverClass(NoInitClass const & x) : LinkClass(x) {}
bool Create(void) const;
protected:
/*
** What type of object this is.
*/
RTTIType RTTI;
/*
** This is the object type that is to be carried over. The exact nature of
** this type depends on the RTTI value. Only certain object types are
** recorded.
*/
union {
StructType Building;
UnitType Unit;
InfantryType Infantry;
VesselType Vessel;
} Type;
/*
** The location of the object.
*/
CELL Cell;
/*
** The strength of the object at the time is was recorded.
*/
int Strength;
/*
** This is the owner of the object.
*/
HousesType House;
};
#endif

431
CODE/CCDDE.CPP Normal file
View file

@ -0,0 +1,431 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer - Red Alert *
* *
* File Name : CCDDE.CPP *
* *
* Programmer : Steve Tall *
* *
* Start Date : 10/04/95 *
* *
* Last Update : August 5th, 1996 [ST] *
* *
*---------------------------------------------------------------------------------------------*
* Overview: *
* C&C's interface to the DDE class *
* *
*---------------------------------------------------------------------------------------------*
* *
* Functions: *
* DDE_Callback -- DDE server callback function *
* DDEServerClass::DDEServerClass -- class constructor *
* DDEServerClass::Enable -- Enables the DDE callback *
* DDEServerClass::Disable -- Disables the DDE callback *
* DDEServerClass::~DDEServerClass -- class destructor *
* DDESC::Callback -- callback function. Called from the DDE_Callback wrapper function *
* DDESC::Get_MPlayer_Game_Info -- returns a pointer to the multiplayer setup info from wchat *
* DDESC::Delete_MPlayer_Game_Info -- clears out multi player game setup info *
* DDESC::Time_Since_Heartbeat -- returns the time in ticks since the last heartbeat from wchat*
* *
* Send_Data_To_DDE_Server -- sends a packet to WChat *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifdef WIN32
#include <WINDOWS.H>
#include "ccdde.h"
#include <stdio.h>
#include <timer.h>
DDEServerClass DDEServer; //Instance of the DDE Server class
Instance_Class *DDE_Class = NULL; // pointer for client callback
// this *must* be called DDE_Class
BOOL RA95AlreadyRunning = FALSE; //Was there an instance of Red Alert 95 already running when we started?
/*
** Misc externs so we dont have to include FUNCTION.H
*/
extern HWND MainWindow;
extern TimerClass GameTimer;
extern BOOL GameTimerInUse;
extern void WWDebugString (char *string);
/***********************************************************************************************
* DDE_Callback -- DDE server callback function *
* *
* Just acts as a wrapper for the DDEServerClass callback function *
* *
* INPUT: ptr to data from client *
* length of data *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 6/8/96 3:19PM ST : Created *
*=============================================================================================*/
BOOL CALLBACK DDE_Callback (unsigned char *data, long length)
{
return (DDEServer.Callback(data, length));
}
/***********************************************************************************************
* DDEServerClass::DDEServerClass -- class constructor *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 6/8/96 3:20PM ST : Created *
*=============================================================================================*/
DDEServerClass::DDEServerClass(void)
{
MPlayerGameInfo = NULL; //Flag that we havnt received a start game info packet yet
//DDE_Class = new Instance_Class ("CONQUER", "WCHAT");
DDE_Class = new Instance_Class ("REDALERT", "WCHAT");
DDE_Class->Enable_Callback( TRUE );
IsEnabled = TRUE;
if (DDE_Class->Test_Server_Running(DDE_Class->local_name)){
RA95AlreadyRunning = TRUE;
}else{
DDE_Class->Register_Server( DDE_Callback );
}
}
/***********************************************************************************************
* DDEServerClass::Enable -- Enables the DDE callback *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 8/5/96 9:44PM ST : Created *
*=============================================================================================*/
void DDEServerClass::Enable(void)
{
if (!IsEnabled){
DDE_Class->Enable_Callback( TRUE );
IsEnabled = TRUE;
}
}
/***********************************************************************************************
* DDEServerClass::Disable -- Disables the DDE callback *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 8/5/96 9:44PM ST : Created *
*=============================================================================================*/
void DDEServerClass::Disable(void)
{
if (IsEnabled){
DDE_Class->Enable_Callback( FALSE );
IsEnabled = FALSE;
}
}
/***********************************************************************************************
* DDEServerClass::~DDEServerClass -- class destructor *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 6/8/96 3:20PM ST : Created *
*=============================================================================================*/
DDEServerClass::~DDEServerClass(void)
{
Delete_MPlayer_Game_Info();
delete( DDE_Class );
}
/***********************************************************************************************
* DDESC::Callback -- callback function. Called from the DDE_Callback wrapper function *
* *
* *
* *
* INPUT: data from DDE client *
* length of data *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: Data has length and type as first 2 ints *
* *
* HISTORY: *
* 6/8/96 3:21PM ST : Created *
*=============================================================================================*/
BOOL DDEServerClass::Callback(unsigned char *data, long length)
{
/*
** If the packet length < 0 then this is a special advisory packet
*/
if ( length<0 ) {
switch( length ) {
case DDE_ADVISE_CONNECT:
WWDebugString("RA95 - DDE advisory: client connect detected.");
return TRUE;
case DDE_ADVISE_DISCONNECT:
WWDebugString("RA95 - DDE advisory: client disconnect detected.");
return TRUE;
default:
WWDebugString("RA95 - DDE advisory: Unknown DDE advise type.");
return FALSE;
}
}else{
/*
** Packet must be at least the length of the packet type & size fields to be valid
*/
if (length < 2*sizeof(int)) {
WWDebugString ("RA95 - Received invalid packet.");
return (FALSE);
}
/*
** Find out what kind of packet this is and its length.
*/
int *packet_pointer = (int *)data;
int actual_length = ntohl(*packet_pointer++);
int packet_type = ntohl(*packet_pointer++);
/*
** Strip the ID int from the start of the packet
*/
data += 2*sizeof (int);
length -= 2*sizeof (int);
actual_length -= 2*sizeof (int);
/*
** Take the appropriate action for the packet type
*/
switch ( packet_type ){
/*
** This is a packet with the info required for starting a new internet game. This is really
* just C&CSPAWN.INI sent from WChat instead of read from disk.
*/
case DDE_PACKET_START_MPLAYER_GAME:
WWDebugString("RA95 - Received start game packet.");
Delete_MPlayer_Game_Info();
MPlayerGameInfo = new char [actual_length + 1];
memcpy (MPlayerGameInfo, data, actual_length);
*(MPlayerGameInfo + actual_length) = 0; //Terminator in case we treat it as a string
MPlayerGameInfoLength = actual_length;
LastHeartbeat = 0;
break;
case DDE_TICKLE:
WWDebugString("RA95 - Received 'tickle' packet.");
//SetForegroundWindow ( MainWindow );
//ShowWindow ( MainWindow, SW_SHOWMAXIMIZED );
break;
case DDE_PACKET_HEART_BEAT:
WWDebugString("RA95 - Received heart beat packet.");
if (GameTimerInUse){
LastHeartbeat = GameTimer.Time();
}else{
LastHeartbeat = 0;
}
break;
default:
WWDebugString("RA95 - Received unrecognised packet.");
break;
}
}
return (TRUE);
}
/***********************************************************************************************
* DDESC::Get_MPlayer_Game_Info -- returns a pointer to the multiplayer setup info from wchat *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: ptr to data in .INI file format *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 6/8/96 3:23PM ST : Created *
*=============================================================================================*/
char *DDEServerClass::Get_MPlayer_Game_Info (void)
{
return (MPlayerGameInfo);
}
/***********************************************************************************************
* DDESC::Delete_MPlayer_Game_Info -- clears out multi player game setup info *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 6/8/96 3:24PM ST : Created *
*=============================================================================================*/
void DDEServerClass::Delete_MPlayer_Game_Info(void)
{
if (MPlayerGameInfo){
delete [] MPlayerGameInfo;
MPlayerGameInfo = NULL;
}
}
/***********************************************************************************************
* DDESC::Time_Since_Heartbeat -- returns the time in ticks since the last heartbeat from wchat*
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: time since heartbeat *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 6/9/96 11:05PM ST : Created *
*=============================================================================================*/
int DDEServerClass::Time_Since_Heartbeat(void)
{
return (GameTimer.Time() - LastHeartbeat);
}
/***********************************************************************************************
* Send_Data_To_DDE_Server -- sends a packet to WChat *
* *
* *
* *
* INPUT: ptr to the data to send *
* length of data *
* packet type identifier *
* *
* OUTPUT: true if packet successfully sent *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 6/9/96 11:07PM ST : Created *
*=============================================================================================*/
BOOL Send_Data_To_DDE_Server (char *data, int length, int packet_type)
{
if( DDE_Class->Open_Poke_Connection(DDE_Class->remote_name) == FALSE) {
WWDebugString("RA95 - Failed to connect for POKE!");
return (FALSE);
}
char *poke_data = new char [length + 2*sizeof(int)];
int *poke_data_int = (int*)poke_data;
*poke_data_int = htonl (length + 2*sizeof(int));
*(poke_data_int+1)= htonl (packet_type);
memcpy (poke_data + 8, data, length);
if(DDE_Class->Poke_Server( (LPBYTE) poke_data, ntohl(*poke_data_int) ) == FALSE) {
WWDebugString("RA95 - POKE failed!\n");
DDE_Class->Close_Poke_Connection(); // close down the link
delete poke_data;
return (FALSE);
}
DDE_Class->Close_Poke_Connection(); // close down the link
delete poke_data;
return (TRUE);
}
#endif //WIN32

89
CODE/CCDDE.H Normal file
View file

@ -0,0 +1,89 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer - Red Alert *
* *
* File Name : CCDDE.H *
* *
* Programmer : Steve Tall *
* *
* Start Date : 10/04/95 *
* *
* Last Update : August 5th, 1996 [ST] *
* *
*---------------------------------------------------------------------------------------------*
* Overview: *
* C&C's interface to the DDE class *
* *
*---------------------------------------------------------------------------------------------*
* *
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifdef WIN32
#include "dde.h"
class DDEServerClass {
public:
DDEServerClass (void);
~DDEServerClass (void);
char *Get_MPlayer_Game_Info (void); //Returns pointer to game info
int Get_MPlayer_Game_Info_Length(){return(MPlayerGameInfoLength);}; //Len of game info
BOOL Callback(unsigned char *data, long length); //DDE callback function
void Delete_MPlayer_Game_Info(void); //release the game info memory
void Enable(void); //Enable the DDE callback
void Disable(void); //Disable the DDE callback
int Time_Since_Heartbeat(void); //Returns the time since the last hearbeat from WChat
/*
** Enumeration for DDE packet types from WChat
*/
enum {
DDE_PACKET_START_MPLAYER_GAME, //Start game packet. This includes game options
DDE_PACKET_GAME_RESULTS, //Game results packet. The game statistics.
DDE_PACKET_HEART_BEAT, //Heart beat packet so we know WChat is still there.
DDE_TICKLE, //Message to prompt other app to take focus.
DDE_CONNECTION_FAILED
};
private:
char *MPlayerGameInfo; //Pointer to game start packet
int MPlayerGameInfoLength; //Length of game start packet.
BOOL IsEnabled; //Flag for DDE callback enable
int LastHeartbeat; // Time since last heartbeat packet was received from WChat
};
extern DDEServerClass DDEServer;
extern BOOL Send_Data_To_DDE_Server (char *data, int length, int packet_type);
#endif //WIN32

693
CODE/CCFILE.CPP Normal file
View file

@ -0,0 +1,693 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/CCFILE.CPP 2 3/13/97 2:05p Steve_tall $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : CCFILE.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : August 8, 1994 *
* *
* Last Update : August 5, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* CCFileClass::CCFileClass -- Default constructor for file object. *
* CCFileClass::CCFileClass -- Filename based constructor for C&C file. *
* CCFileClass::Close -- Closes the file. *
* CCFileClass::Error -- Handles displaying a file error message. *
* CCFileClass::Is_Available -- Checks for existence of file on disk or in mixfile. *
* CCFileClass::Is_Open -- Determines if the file is open. *
* CCFileClass::Open -- Opens a file from either the mixfile system or the rawfile system. *
* CCFileClass::Read -- Reads data from the file. *
* CCFileClass::Seek -- Moves the current file pointer in the file. *
* CCFileClass::Size -- Determines the size of the file. *
* CCFileClass::Write -- Writes data to the file (non mixfile files only). *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
#include <errno.h>
#include "ccfile.h"
/***********************************************************************************************
* CCFileClass::CCFileClass -- Filename based constructor for C&C file. *
* *
* Use this constructor for a file when the filename is known at construction time. *
* *
* INPUT: filename -- Pointer to the filename to use for this file object. *
* *
* OUTPUT: none *
* *
* WARNINGS: The filename pointer is presumed to be inviolate throughout the duration of *
* the file object. If this is not guaranteed, then use the default constructor *
* and then set the name manually. *
* *
* HISTORY: *
* 03/20/1995 JLB : Created. *
*=============================================================================================*/
CCFileClass::CCFileClass(char const * filename) :
Position(0)
{
CCFileClass::Set_Name(filename);
}
/***********************************************************************************************
* CCFileClass::CCFileClass -- Default constructor for file object. *
* *
* This is the default constructor for a C&C file object. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 03/20/1995 JLB : Created. *
*=============================================================================================*/
CCFileClass::CCFileClass(void) :
Position(0)
{
}
/***********************************************************************************************
* CCFileClass::Error -- Handles displaying a file error message. *
* *
* Display an error message as indicated. If it is allowed to retry, then pressing a key *
* will return from this function. Otherwise, it will exit the program with "exit()". *
* *
* INPUT: error -- The error number (same as the DOSERR.H error numbers). *
* *
* canretry -- Can this routine exit normally so that retrying can occur? If this is *
* false, then the program WILL exit in this routine. *
* *
* filename -- Optional filename to report with this error. If no filename is *
* supplied, then no filename is listed in the error message. *
* *
* OUTPUT: none, but this routine might not return at all if the "canretry" parameter is *
* false or the player pressed ESC. *
* *
* WARNINGS: This routine may not return at all. It handles being in text mode as well as *
* if in a graphic mode. *
* *
* HISTORY: *
* 10/17/1994 JLB : Created. *
*=============================================================================================*/
void CCFileClass::Error(int , int , char const * )
{
if (!Force_CD_Available(RequiredCD)) {
//Prog_End();
Emergency_Exit(EXIT_FAILURE);
}
}
/***********************************************************************************************
* CCFileClass::Write -- Writes data to the file (non mixfile files only). *
* *
* This routine will write data to the file, but NOT to a file that is part of a mixfile. *
* *
* INPUT: buffer -- Pointer to the buffer that holds the data to be written. *
* *
* size -- The number of bytes to write. *
* *
* OUTPUT: Returns the number of bytes actually written. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/08/1994 JLB : Created. *
*=============================================================================================*/
long CCFileClass::Write(void const * buffer, long size)
{
/*
** If this is part of a mixfile, then writing is not allowed. Error out with a fatal
** message.
*/
if (Is_Resident()) {
Error(EACCES, false, File_Name());
}
return(CDFileClass::Write(buffer, size));
}
/***********************************************************************************************
* CCFileClass::Read -- Reads data from the file. *
* *
* This routine determines if the file is part of the mixfile system. If it is, then *
* the file is copied from RAM if it is located there. Otherwise it is read from disk *
* according to the correct position of the file within the parent mixfile. *
* *
* INPUT: buffer -- Pointer to the buffer to place the read data. *
* *
* size -- The number of bytes to read. *
* *
* OUTPUT: Returns the actual number of bytes read (this could be less than requested). *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/08/1994 JLB : Created. *
*=============================================================================================*/
long CCFileClass::Read(void * buffer, long size)
{
bool opened = false;
/*
** If the file isn't currently open, then open it.
*/
if (!Is_Open()) {
if (Open()) {
opened = true;
}
}
/*
** If the file is part of a loaded mixfile, then a mere copy is
** all that is required for the read.
*/
if (Is_Resident()) {
long maximum = Data.Get_Size() - Position;
size = maximum < size ? maximum : size;
// size = MIN(maximum, size);
if (size) {
memmove(buffer, (char *)Data + Position, size);
// Mem_Copy((char *)Pointer + Position, buffer, size);
Position += size;
}
if (opened) Close();
return(size);
}
long s = CDFileClass::Read(buffer, size);
/*
** If the file was opened by this routine, then close it at this time.
*/
if (opened) Close();
/*
** Return with the number of bytes read.
*/
return(s);
}
/***********************************************************************************************
* CCFileClass::Seek -- Moves the current file pointer in the file. *
* *
* This routine will change the current file pointer to the position specified. It follows *
* the same rules the a normal Seek() does, but if the file is part of the mixfile system, *
* then only the position value needs to be updated. *
* *
* INPUT: pos -- The position to move the file to relative to the position indicated *
* by the "dir" parameter. *
* *
* dir -- The direction to affect the position change against. This can be *
* either SEEK_CUR, SEEK_END, or SEEK_SET. *
* *
* OUTPUT: Returns with the position of the new location. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/08/1994 JLB : Created. *
*=============================================================================================*/
long CCFileClass::Seek(long pos, int dir)
{
/*
** When the file is resident, a mere adjustment of the virtual file position is
** all that is required of a seek.
*/
if (Is_Resident()) {
switch (dir) {
case SEEK_END:
Position = Data.Get_Size();
break;
case SEEK_SET:
Position = 0;
break;
case SEEK_CUR:
default:
break;
}
Position += pos;
Position = Position < 0 ? 0 : Position;
Position = Position > Data.Get_Size() ? Data.Get_Size() : Position;
// Position = Bound(Position+pos, 0L, Length);
return(Position);
}
return(CDFileClass::Seek(pos, dir));
}
/***********************************************************************************************
* CCFileClass::Size -- Determines the size of the file. *
* *
* If the file is part of the mixfile system, then the size of the file is already *
* determined and available. Otherwise, go to the low level system to find the file *
* size. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the size of the file in bytes. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/08/1994 JLB : Created. *
* 08/05/1996 JLB : Handles returning size of embedded file. *
*=============================================================================================*/
long CCFileClass::Size(void)
{
/*
** If the file is resident, the the size is already known. Just return the size in this
** case.
*/
if (Is_Resident()) return(Data.Get_Size());
/*
** If the file is not available as a stand alone file, then search for it in the
** mixfiles in order to get its size.
*/
if (!CDFileClass::Is_Available()) {
long length = 0;
MFCD::Offset(File_Name(), NULL, NULL, NULL, &length);
return(length);
}
return(CDFileClass::Size());
}
/***********************************************************************************************
* CCFileClass::Is_Available -- Checks for existence of file on disk or in mixfile. *
* *
* This routine will examine the mixfile system looking for the file. If the file could *
* not be found there, then the disk is examined directly. *
* *
* INPUT: none *
* *
* OUTPUT: bool; Is the file available for opening? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/08/1994 JLB : Created. *
*=============================================================================================*/
int CCFileClass::Is_Available(int )
{
/*
** A file that is open is presumed available.
*/
if (Is_Open()) return(true);
/*
** A file that is part of a mixfile is also presumed available.
*/
if (MFCD::Offset(File_Name())) {
return(true);
}
/*
** Otherwise a manual check of the file system is required to
** determine if the file is actually available.
*/
return(CDFileClass::Is_Available());
}
/***********************************************************************************************
* CCFileClass::Is_Open -- Determines if the file is open. *
* *
* A mixfile is open if there is a pointer to the mixfile data. In absence of this, *
* the the file is open if the file handle is valid. *
* *
* INPUT: none *
* *
* OUTPUT: bool; Is the file open? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/08/1994 JLB : Created. *
*=============================================================================================*/
int CCFileClass::Is_Open(void) const
{
/*
** If the file is part of a cached file, then return that it is opened. A closed file
** doesn't have a valid pointer.
*/
if (Is_Resident()) return(true);
/*
** Otherwise, go to a lower level to determine if the file is open.
*/
return(CDFileClass::Is_Open());
}
/***********************************************************************************************
* CCFileClass::Close -- Closes the file. *
* *
* If this is a mixfile file, then only the pointers need to be adjusted. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/08/1994 JLB : Created. *
*=============================================================================================*/
void CCFileClass::Close(void)
{
new(&Data) ::Buffer;
Position = 0; // Starts at beginning offset.
CDFileClass::Close();
}
/***********************************************************************************************
* CCFileClass::Open -- Opens a file from either the mixfile system or the rawfile system. *
* *
* This routine will open the specified file. It examines the mixfile system to find a *
* match. If one is found then the file is "opened" in a special cached way. Otherwise *
* it is opened as a standard DOS file. *
* *
* INPUT: rights -- The access rights desired. *
* *
* OUTPUT: bool; Was the file opened successfully? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/08/1994 JLB : Created. *
*=============================================================================================*/
int CCFileClass::Open(int rights)
{
/*
** Always close the file if it was open.
*/
Close();
/*
** Perform a preliminary check to see if the specified file
** exists on the disk. If it does, then open this file regardless
** of whether it also exists in RAM. This is slower, but allows
** upgrade files to work.
*/
if ((rights & WRITE) || CDFileClass::Is_Available()) {
return(CDFileClass::Open(rights));
}
/*
** Check to see if file is part of a mixfile and that mixfile is currently loaded
** into RAM.
*/
MFCD * mixfile = NULL;
void * pointer = NULL;
long length = 0;
long start = 0;
if (MFCD::Offset(File_Name(), &pointer, &mixfile, &start, &length)) {
assert(mixfile != NULL);
/*
** If the mixfile is located on disk, then fake out the file system to read from
** the mixfile, but think it is reading from a solitary file.
*/
if (pointer == NULL && mixfile != NULL) {
/*
** This is a legitimate open to the file. All access to the file through this
** file object will be appropriately adjusted for mixfile support however. Also
** note that the filename attached to this object is NOT the same as the file
** attached to the file handle.
*/
char * dupfile = strdup(File_Name());
Open(mixfile->Filename, READ);
Searching(false); // Disable multi-drive search.
Set_Name(dupfile);
Searching(true);
free(dupfile);
Bias(0);
Bias(start, length);
Seek(0, SEEK_SET);
} else {
new (&Data) ::Buffer(pointer, length);
Position = 0;
}
} else {
/*
** The file cannot be found in any mixfile, so it must reside as
** an individual file on the disk. Or else it is just plain missing.
*/
return(CDFileClass::Open(rights));
}
return(true);
}
/***********************************************************************************************
* CCFileClass::Get_Date_Time -- Gets the date and time the file was last modified. *
* *
* Use this routine to get the date and time of the file. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the file date and time as a long. *
* Use the YEAR(long), MONTH(),.... *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/14/1995 DRD : Created. *
*=============================================================================================*/
unsigned long CCFileClass::Get_Date_Time(void)
{
unsigned long datetime;
MFCD * mixfile;
datetime = CDFileClass::Get_Date_Time();
if ( !datetime ) {
if (MFCD::Offset(File_Name(), NULL, &mixfile, NULL, NULL)) {
//
// check for nested MIX files
//
return( CCFileClass(mixfile->Filename).Get_Date_Time() );
}
// else return 0 indicating no file
}
return( datetime );
}
/***********************************************************************************************
* CCFileClass::Set_Date_Time -- Sets the date and time the file was last modified. *
* *
* Use this routine to set the date and time of the file. *
* *
* INPUT: the file date and time as a long *
* *
* OUTPUT: successful or not if the file date and time was changed. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/14/1995 DRD : Created. *
*=============================================================================================*/
bool CCFileClass::Set_Date_Time( unsigned long datetime )
{
bool status;
MFCD * mixfile;
status = CDFileClass::Set_Date_Time( datetime );
if ( !status ) {
if (MFCD::Offset(File_Name(), NULL, &mixfile, NULL, NULL)) {
//
// check for nested MIX files
//
return( CCFileClass(mixfile->Filename).Set_Date_Time( datetime ) );
}
// else return 0 indicating no file
}
return( status );
}
/***********************************************************************************
** Backward compatibility section.
*/
//extern "C" {
static CCFileClass Handles[10];
int __cdecl Open_File(char const * file_name, int mode)
{
for (int index = 0; index < ARRAY_SIZE(Handles); index++) {
if (!Handles[index].Is_Open()) {
if (Handles[index].Open(file_name, mode)) {
return(index);
}
break;
}
}
return(WWERROR);
}
void __cdecl Close_File(int handle)
{
if (handle != WWERROR && Handles[handle].Is_Open()) {
Handles[handle].Close();
}
}
long __cdecl Read_File(int handle, void * buf, unsigned long bytes)
{
if (handle != WWERROR && Handles[handle].Is_Open()) {
return(Handles[handle].Read(buf, bytes));
}
return(0);
}
long __cdecl Write_File(int handle, void const * buf, unsigned long bytes)
{
if (handle != WWERROR && Handles[handle].Is_Open()) {
return(Handles[handle].Write(buf, bytes));
}
return(0);
}
int __cdecl Find_File(char const * file_name)
{
CCFileClass file(file_name);
return(file.Is_Available());
}
#ifdef NEVER
int __cdecl Delete_File(char const * file_name)
{
return(CCFileClass(file_name).Delete());
}
int __cdecl Create_File(char const * file_name)
{
return(CCFileClass(file_name).Create());
}
unsigned long __cdecl Load_Data(char const * name, void * ptr, unsigned long size)
{
return(CCFileClass(name).Read(ptr, size));
}
#endif
void * __cdecl Load_Alloc_Data(char const * name, int )
{
CCFileClass file(name);
return(Load_Alloc_Data(file));
}
unsigned long __cdecl File_Size(int handle)
{
if (handle != WWERROR && Handles[handle].Is_Open()) {
return(Handles[handle].Size());
}
return(0);
}
#ifdef NEVER
unsigned long __cdecl Write_Data(char const * name, void const * ptr, unsigned long size)
{
return(CCFileClass(name).Write(ptr, size));
}
#endif
unsigned long __cdecl Seek_File(int handle, long offset, int starting)
{
if (handle != WWERROR && Handles[handle].Is_Open()) {
return(Handles[handle].Seek(offset, starting));
}
return(0);
}
#ifdef NEVER
bool __cdecl Multi_Drive_Search(bool on)
{
// return(CCFileClass::Multi_Drive_Search(on));
return(on);
}
void __cdecl WWDOS_Init(void)
{
}
void __cdecl WWDOS_Shutdown(void)
{
}
int __cdecl Find_Disk_Number(char const *)
{
return(0);
}
#endif
//unsigned long __cdecl Load_Uncompress(char const * file, BuffType uncomp_buff, BuffType dest_buff, void * reserved_data)
//{
// return(Load_Uncompress(CCFileClass(file), uncomp_buff, dest_buff, reserved_data));
// return(CCFileClass(file).Load_Uncompress(uncomp_buff, dest_buff, reserved_data));
//}
#ifdef WIN32
extern "C" {
int MaxDevice;
int DefaultDrive;
char CallingDOSInt;
}
#endif
void Unfragment_File_Cache(void)
{
}

107
CODE/CCFILE.H Normal file
View file

@ -0,0 +1,107 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/CCFILE.H 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : CCFILE.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : October 17, 1994 *
* *
* Last Update : October 17, 1994 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef CCFILE_H
#define CCFILE_H
//#include <wwlib32.h>
#include <limits.h>
#include "mixfile.h"
#include "cdfile.h"
#include "buff.h"
/*
** This derived class for file access knows about mixfiles (packed files). It can handle opening
** a file that is embedded within a mixfile. This is true if the mixfile is cached or resides on
** disk. It is functionally similar to pakfiles, except much faster and less RAM intensive.
*/
class CCFileClass : public CDFileClass
{
public:
CCFileClass(char const * filename);
CCFileClass(void);
virtual ~CCFileClass(void) {Position = 0;};
// Delete should be overloaded here as well. Don't allow deletes of mixfiles.
bool Is_Resident(void) const {return(Data.Get_Buffer() != NULL);}
virtual int Is_Available(int forced=false);
virtual int Is_Open(void) const;
virtual int Open(char const * filename, int rights=READ) {Set_Name(filename);return Open(rights);};
virtual int Open(int rights=READ);
virtual long Read(void * buffer, long size);
virtual long Seek(long pos, int dir=SEEK_CUR);
virtual long Size(void);
virtual long Write(void const * buffer, long size);
virtual void Close(void);
virtual unsigned long Get_Date_Time(void);
virtual bool Set_Date_Time(unsigned long datetime);
virtual void Error(int error, int canretry = false, char const * filename=NULL);
private:
/*
** This indicates the file is actually part of a resident image of the mixfile
** itself. In this case, the embedded file handle is invalid. All file access actually
** gets routed through the cached version of the file. This is a pointer to the start
** of the RAM image of the file.
*/
::Buffer Data;
// void * Pointer;
/*
** This is the size of the file if it was embedded in a mixfile. The size must be manually
** kept track of because the DOS file size is invalid.
*/
// long Length;
/*
** This is the current seek position of the file. It is duplicated here if the file is
** part of a mixfile since the DOS seek position is not accurate. This value will
** range from zero to the size of the file in bytes.
*/
long Position;
// Force these to never be invoked.
CCFileClass const & operator = (CCFileClass const & c);
CCFileClass (CCFileClass const & );
};
class MixFileClass<CDFileClass>;
#endif

1487
CODE/CCINI.CPP Normal file

File diff suppressed because it is too large Load diff

120
CODE/CCINI.H Normal file
View file

@ -0,0 +1,120 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/CCINI.H 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : CCINI.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 05/24/96 *
* *
* Last Update : May 24, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef CCINI_H
#define CCINI_H
#include "ini.h"
#include "fixed.h"
#include "pk.h"
class TriggerTypeClass;
/*
** The advanced version of the INI database manager. It handles the C&C expansion types and
** identifiers. In addition, it automatically stores a message digest with the INI data
** so that verification can occur.
*/
class CCINIClass : public INIClass
{
public:
CCINIClass(void) : IsDigestPresent(false) {}
bool Load(FileClass & file, bool withdigest);
bool Load(Straw & file, bool withdigest);
int Save(FileClass & file, bool withdigest) const;
int Save(Pipe & pipe, bool withdigest) const;
long Get_Buildings(char const * section, char const * entry, long defvalue) const;
UnitType Get_UnitType(char const * section, char const * entry, UnitType defvalue) const;
AnimType Get_AnimType(char const * section, char const * entry, AnimType defvalue) const;
ArmorType Get_ArmorType(char const * section, char const * entry, ArmorType defvalue) const;
BulletType Get_BulletType(char const * section, char const * entry, BulletType defvalue) const;
HousesType Get_HousesType(char const * section, char const * entry, HousesType defvalue) const;
LEPTON Get_Lepton(char const * section, char const * entry, LEPTON defvalue) const;
MPHType Get_MPHType(char const * section, char const * entry, MPHType defvalue) const;
OverlayType Get_OverlayType(char const * section, char const * entry, OverlayType defvalue) const;
SourceType Get_SourceType(char const * section, char const * entry, SourceType defvalue) const;
TerrainType Get_TerrainType(char const * section, char const * entry, TerrainType defvalue) const;
TheaterType Get_TheaterType(char const * section, char const * entry, TheaterType defvalue) const;
ThemeType Get_ThemeType(char const * section, char const * entry, ThemeType defvalue) const;
TriggerTypeClass * Get_TriggerType(char const * section, char const * entry) const;
VQType Get_VQType(char const * section, char const * entry, VQType defvalue) const;
VocType Get_VocType(char const * section, char const * entry, VocType defvalue) const;
WarheadType Get_WarheadType(char const * section, char const * entry, WarheadType defvalue) const;
WeaponType Get_WeaponType(char const * section, char const * entry, WeaponType defvalue) const;
long Get_Owners(char const * section, char const * entry, long defvalue) const;
CrateType Get_CrateType(char const * section, char const * entry, CrateType defvalue) const;
bool Put_Buildings(char const * section, char const * entry, long value);
bool Put_AnimType(char const * section, char const * entry, AnimType value);
bool Put_UnitType(char const * section, char const * entry, UnitType value);
bool Put_ArmorType(char const * section, char const * entry, ArmorType value);
bool Put_BulletType(char const * section, char const * entry, BulletType value);
bool Put_HousesType(char const * section, char const * entry, HousesType value);
bool Put_Lepton(char const * section, char const * entry, LEPTON value);
bool Put_MPHType(char const * section, char const * entry, MPHType value);
bool Put_VQType(char const * section, char const * entry, VQType value);
bool Put_OverlayType(char const * section, char const * entry, OverlayType value);
bool Put_Owners(char const * section, char const * entry, long value);
bool Put_SourceType(char const * section, char const * entry, SourceType value);
bool Put_TerrainType(char const * section, char const * entry, TerrainType value);
bool Put_TheaterType(char const * section, char const * entry, TheaterType value);
bool Put_ThemeType(char const * section, char const * entry, ThemeType value);
bool Put_TriggerType(char const * section, char const * entry, TriggerTypeClass * value);
bool Put_VocType(char const * section, char const * entry, VocType value);
bool Put_WarheadType(char const * section, char const * entry, WarheadType value);
bool Put_WeaponType(char const * section, char const * entry, WeaponType value);
bool Put_CrateType(char const * section, char const * entry, CrateType value);
int Get_Unique_ID(void) const;
private:
void Calculate_Message_Digest(void);
void Invalidate_Message_Digest(void);
bool IsDigestPresent:1;
/*
** This is the message digest (SHA) of the INI database that was embedded as part of
** the INI file.
*/
unsigned char Digest[20];
};
#endif

421
CODE/CCMPATH.CPP Normal file
View file

@ -0,0 +1,421 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/***************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : CCMPATH.CPP *
* *
* Programmer : Bill R. Randolph *
* *
* Start Date : 01/09/96 *
* *
* Last Update : January 11, 1996 [BRR] *
* *
*-------------------------------------------------------------------------*
* Functions: *
* Init_MPATH -- Performs MPATH-specific initialization *
* Shutdown_MPATH -- Shuts down MPATH connections *
* Connect_MPATH -- Waits for connections to other players *
* Destroy_MPATH_Connection -- Destroys the given connection *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
/***************************************************************************
* Init_MPATH -- Performs MPATH-specific initialization *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* 1 = OK, 0 = error *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 01/09/1996 BRR : Created. *
*=========================================================================*/
int Init_MPATH(void)
{
#if(MPATH)
//------------------------------------------------------------------------
// Allocate a packet buffer for MPATH's use
//------------------------------------------------------------------------
Session.MPathPacket = new char[Session.MPathSize];
//------------------------------------------------------------------------
// Read the multiplayer settings from the CONQUER.INI file, and the game
// options from the options file.
//------------------------------------------------------------------------
Session.Read_MultiPlayer_Settings();
if (!Read_MPATH_Game_Options()) {
WWMessageBox().Process("Unable to load game settings!");
//Prog_End();
Emergency_Exit(0);
}
//------------------------------------------------------------------------
// Flush all incoming packets
//------------------------------------------------------------------------
MPath->Flush_All();
//------------------------------------------------------------------------
// Form connections to all other players
//------------------------------------------------------------------------
Connect_MPATH();
//------------------------------------------------------------------------
// Set multiplayer values for the local system, and timing values.
//------------------------------------------------------------------------
Session.CommProtocol = COMM_PROTOCOL_MULTI_E_COMP;
return (1);
#else
return (1);
#endif
} // end of Init_MPATH
/***************************************************************************
* Shutdown_MPATH -- Shuts down MPATH connections *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 01/09/1996 BRR : Created. *
*=========================================================================*/
void Shutdown_MPATH(void)
{
#if(MPATH)
CDTimerClass<SystemTimerClass> timer;
//------------------------------------------------------------------------
// Wait a full second before exiting, to ensure all packets get sent.
//------------------------------------------------------------------------
timer = 60;
while (timer) ;
//------------------------------------------------------------------------
// Free memory
//------------------------------------------------------------------------
if (Session.MPathPacket) {
delete [] Session.MPathPacket;
Session.MPathPacket = NULL;
}
if (MPath) {
delete MPath;
MPath = NULL;
}
return;
#endif
} // end of Shutdown_MPATH
/***************************************************************************
* Connect_MPATH -- Waits for connections to other players *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 01/10/1996 BRR : Created. *
*=========================================================================*/
void Connect_MPATH(void)
{
#if(MPATH)
typedef struct ConnectPacketTag {
NetCommandType Dummy; // packet type; set to PING
char Name[MPLAYER_NAME_MAX]; // player's name
HousesType House; // player's ActLike
unsigned char Color; // player's Color
} ConnectPacketType;
int num_players;
int num_found;
ConnectPacketType send_packet;
ConnectPacketType receive_packet;
int address;
int found;
int size;
int i;
CDTimerClass<SystemTimerClass> send_timer;
NodeNameType *who;
enum {
D_TXT6_H = 7,
D_MARGIN = 5,
};
static int x,y,w,h;
char const *buf1;
char const *buf2;
int display = 0;
RemapControlType * scheme = GadgetClass::Get_Color_Scheme();
//
// Clear the Players list
//
while (Session.Players.Count() > 0) {
delete Session.Players[0];
Session.Players.Delete(Session.Players[0]);
}
//
// Add myself to the list first thing
//
who = new NodeNameType;
strcpy(who->Name, Session.Handle);
who->Player.House = Session.House;
who->Player.Color = Session.ColorIdx;
Session.Players.Add (who);
//
// Find out how many players to wait for
//
num_players = MPath->Find_Num_Connections();
num_found = 0;
Session.NumPlayers = num_players + 1;
//
// Send out a packet announcing my presence
//
send_packet.Dummy = NET_PING;
strcpy(send_packet.Name, Session.Handle);
send_packet.House = Session.House;
send_packet.Color = Session.ColorIdx;
MPath->Send_Global_Message(&send_packet, sizeof(send_packet), 0, 0);
//
// Start our packet-sending timer
//
send_timer = 240;
//
// Wait for all players to enter the game
//
display = 1;
while (num_found < num_players) {
#ifdef WIN32
/*
** If we have just received input focus again after running in the background then
** we need to redraw.
*/
if (AllSurfaces.SurfacesRestored) {
AllSurfaces.SurfacesRestored=FALSE;
display = 1;
}
#endif
if (display) {
Fancy_Text_Print("", 0, 0, 0, 0, TPF_TEXT);
buf1 = Text_String(TXT_WAITING_FOR_CONNECTIONS);
buf2 = Text_String(TXT_PRESS_ESC);
w = MAX(String_Pixel_Width(buf1),String_Pixel_Width(buf2));
w += (D_MARGIN * 2);
h = (D_TXT6_H * 2) + (D_MARGIN * 7);
x = 160 - (w / 2);
y = 100 - (h / 2);
Hide_Mouse();
//Set_Logic_Page(SeenBuff);
Dialog_Box(x * RESFACTOR, y * RESFACTOR, w * RESFACTOR, h * RESFACTOR);
Fancy_Text_Print(buf1,
160 * RESFACTOR,
(y + (D_MARGIN * 2)) * RESFACTOR,
scheme, TBLACK, TPF_CENTER | TPF_TEXT);
Fancy_Text_Print(buf2,
160 * RESFACTOR,
(y + (D_MARGIN * 2) + D_TXT6_H + D_MARGIN) * RESFACTOR,
scheme, TBLACK, TPF_CENTER | TPF_TEXT);
Show_Mouse();
display = 0;
}
MPath->Service();
//
// Check for an incoming packet; if a PING comes in, see if we already
// have this player in our Players list. If not, add him.
//
if (MPath->Get_Global_Message (&receive_packet, &size, &address) &&
receive_packet.Dummy == NET_PING) {
found = 0;
for (i = 1; i < Session.Players.Count(); i++) {
if (Session.Players[i]->MPathAddress == address) {
found = 1;
break;
}
}
//
// Create a new connection and a new node in the list.
//
if (!found) {
who = new NodeNameType;
strcpy(who->Name, receive_packet.Name);
who->MPathAddress = address;
who->Player.House = receive_packet.House;
who->Player.Color = (PlayerColorType)receive_packet.Color;
Session.Players.Add (who);
num_found++;
MPath->Send_Global_Message(&send_packet, sizeof(send_packet), 1,
address);
}
}
//
// If the user hits ESC, bail out.
//
if (Keyboard->Check()) {
if (Keyboard->Get() == KN_ESC) {
//Prog_End();
Emergency_Exit(0);
}
}
//
// When our timer expires, re-send the packet.
//
if (!send_timer) {
send_packet.Dummy = NET_PING;
MPath->Send_Global_Message(&send_packet, sizeof(send_packet), 0, 0);
send_timer = 240;
}
}
#else
return;
#endif
}
/***************************************************************************
* Destroy_MPATH_Connection -- Destroys the given connection *
* *
* INPUT: *
* id connection ID to destroy *
* error 0 = user signed off; 1 = connection error; otherwise, *
* no error is shown. *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 01/11/1996 BRR : Created. *
*=========================================================================*/
void Destroy_MPATH_Connection(int id, int error)
{
#if(MPATH)
int i;
HouseClass *housep;
char txt[80];
//------------------------------------------------------------------------
// Do nothing if the house isn't human.
//------------------------------------------------------------------------
housep = HouseClass::As_Pointer((HousesType)id);
if (!housep || !housep->IsHuman)
return;
/*------------------------------------------------------------------------
Create a message to display to the user
------------------------------------------------------------------------*/
txt[0] = '\0';
if (error==1) {
sprintf(txt,Text_String(TXT_CONNECTION_LOST),MPath->Connection_Name(id));
} else if (error==0) {
sprintf(txt,Text_String(TXT_LEFT_GAME),MPath->Connection_Name(id));
}
if (strlen(txt)) {
Session.Messages.Add_Message (NULL,0, txt, housep->RemapColor,
TPF_TEXT, Rule.MessageDelay * TICKS_PER_MINUTE);
Map.Flag_To_Redraw(false);
}
//------------------------------------------------------------------------
// Remove this player from the Players vector
//------------------------------------------------------------------------
for (i = 0; i < Session.Players.Count(); i++) {
if (!stricmp(Session.Players[i]->Name,housep->IniName)) {
delete Session.Players[i];
Session.Players.Delete(Session.Players[i]);
break;
}
}
/*------------------------------------------------------------------------
Delete the MPATH connection
------------------------------------------------------------------------*/
MPath->Delete_Connection(id);
//------------------------------------------------------------------------
// Turn the player's house over to the computer's AI
//------------------------------------------------------------------------
housep->IsHuman = false;
housep->IQ = Rule.MaxIQ;
strcpy (housep->IniName,Text_String(TXT_COMPUTER));
Session.NumPlayers--;
/*------------------------------------------------------------------------
If we're the last player left, tell the user.
------------------------------------------------------------------------*/
if (Session.NumPlayers == 1) {
sprintf(txt,"%s",Text_String(TXT_JUST_YOU_AND_ME));
Session.Messages.Add_Message (NULL, 0, txt, housep->RemapColor,
TPF_TEXT, Rule.MessageDelay * TICKS_PER_MINUTE);
Map.Flag_To_Redraw(false);
}
#else
id = id;
error = error;
#endif
} // end of Destroy_MPATH_Connection
/***************************** end of ccmpath.cpp **************************/

76
CODE/CCPTR.CPP Normal file
View file

@ -0,0 +1,76 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/CCPTR.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : CCPTR.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 06/07/96 *
* *
* Last Update : July 6, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* CCPtr<T>::operator > -- Greater than comparison operator. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
/*
** These member functions for the CCPtr class cannot be declared inside the
** class definition since they could refer to other objects that themselves
** contain CCPtr objects. The recursive nature of this type of declaration
** is not handled by Watcom, hence the body declaration is dislocated here.
*/
template<class T>
CCPtr<T>::CCPtr(T * ptr) : ID(-1)
{
if (ptr != NULL) {
ID = ptr->ID;
}
}
/***********************************************************************************************
* CCPtr<T>::operator > -- Greater than comparison operator. *
* *
* This will compare two pointer value to see if the left hand value is greater than the *
* right hand. The values are compared by comparing based on their Name() functions. *
* *
* INPUT: rvalue -- The right handle CCPtr value. *
* *
* OUTPUT: Is the left hand value greater than the right hand value? *
* *
* WARNINGS: The values pointed to by CCPtr must have a Name() function defined. *
* *
* HISTORY: *
* 07/06/1996 JLB : Created. *
*=============================================================================================*/
template<class T>
bool CCPtr<T>::operator > (CCPtr<T> const & rvalue) const
{
return (stricmp((*this)->Name(), rvalue->Name()) > 0);
}

115
CODE/CCPTR.H Normal file
View file

@ -0,0 +1,115 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/CCPTR.H 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : CCPTR.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 06/07/96 *
* *
* Last Update : June 7, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef CCPTR_H
#define CCPTR_H
/*
** The CCPtr class is designed for a specific purpose. It functions like a pointer except that
** it requires no fixups for saving and loading. If pointer fixups are not an issue, than using
** regular pointers would be more efficient.
*/
template<class T>
class CCPtr
{
public:
CCPtr(void) : ID(-1) {};
CCPtr(NoInitClass const & ) {};
CCPtr(T * ptr);
operator T * (void) const {
if (ID == -1) return(NULL);
assert(Heap != NULL && (unsigned)ID < Heap->Length());
return((T*) (*Heap)[ID]);
}
T & operator * (void) const {
assert(Heap != NULL && (unsigned)ID < Heap->Length());
return(*(T*)(*Heap)[ID]);
}
T * operator -> (void) const {
if (ID == -1) return(NULL);
assert(Heap != NULL && (unsigned)ID < Heap->Length());
return((T*) (*Heap)[ID]);
}
bool Is_Valid(void) const {return(ID != -1);}
bool operator == (CCPtr<T> const & rvalue) const {return(ID == rvalue.ID);}
bool operator != (CCPtr<T> const & rvalue) const {return(ID != rvalue.ID);}
bool operator > (CCPtr<T> const & rvalue) const;
bool operator <= (CCPtr<T> const & rvalue) const {return (rvalue > *this);}
bool operator < (CCPtr<T> const & rvalue) const {return (*this != rvalue && rvalue > *this);}
bool operator >= (CCPtr<T> const & rvalue) const {return (*this == rvalue || rvalue > *this);}
long Raw(void) const {return(ID);}
void Set_Raw(long value) {ID = value;}
private:
static FixedIHeapClass * Heap;
/*
** This is the ID number of the object it refers to. By using an ID number, this class can
** be saved and loaded without pointer fixups.
*/
int ID;
};
/*
** These template helper functions tell the compiler what to do in the
** ambiguous case of a CCPtr on one side and a regular type pointer on the
** other side. In such a case the compiler could create a temp CCPtr object
** OR call the conversion operator on the existing CCPtr object. Either way
** is technically valid, but the compiler doesn't know which is better so it
** generates an error. These routines force the conversion operator rather than
** creating a temporary object. This presumes that the conversion operator is
** cheaper than constructing a temporary and that cheaper solutions are desirable.
*/
template<class T>
int operator == (CCPtr<T> & lvalue, T * rvalue)
{
return((T*)lvalue == rvalue);
}
template<class T>
int operator == (T * lvalue, CCPtr<T> & rvalue)
{
return(lvalue == (T*)rvalue);
}
#endif

603
CODE/CCTEN.CPP Normal file
View file

@ -0,0 +1,603 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/***************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : CCTEN.CPP *
* *
* Programmer : Bill R. Randolph *
* *
* Start Date : 01/09/96 *
* *
* Last Update : November 27, 1996 [BRR] *
* *
*-------------------------------------------------------------------------*
* Functions: *
* Init_TEN -- Performs TEN-specific initialization *
* Shutdown_TEN -- Shuts down TEN connections *
* Connect_TEN -- Waits for connections to other players *
* Destroy_TEN_Connection -- Destroys the given connection *
* Debug_Mono -- Custom mono prints *
* Send_TEN_Win_Packet -- Sends a win packet to server *
* Send_TEN_Alliance -- Sends an ally/enemy packet to server *
* Send_TEN_Out_Of_Sync -- Announces this game out of sync *
* Send_TEN_Packet_Too_Late -- Announces packet-received-too-late *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
#if(TEN)
#ifdef WIN32
#define WINDOWS
#endif
#include "ten.h"
#endif
void Connect_TEN(void);
void Debug_Mono(void);
/***************************************************************************
* Init_TEN -- Performs TEN-specific initialization *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* 1 = OK, 0 = error *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 01/09/1996 BRR : Created. *
*=========================================================================*/
int Init_TEN(void)
{
#if(TEN)
//------------------------------------------------------------------------
// Allocate a packet buffer for TEN's use
//------------------------------------------------------------------------
Session.TenPacket = new char[Session.TenSize];
//------------------------------------------------------------------------
// Read the multiplayer settings from the CONQUER.INI file, and the game
// options from the options file.
//------------------------------------------------------------------------
Session.Read_MultiPlayer_Settings();
if (!Read_TEN_Game_Options()) {
WWMessageBox().Process("Unable to load game settings!");
//Prog_End();
Emergency_Exit(0);
}
//------------------------------------------------------------------------
// Flush all incoming packets
//------------------------------------------------------------------------
Ten->Flush_All();
//------------------------------------------------------------------------
// Form connections to all other players
//------------------------------------------------------------------------
Connect_TEN();
//------------------------------------------------------------------------
// Set multiplayer values for the local system, and timing values.
//------------------------------------------------------------------------
Session.CommProtocol = COMM_PROTOCOL_MULTI_E_COMP;
return (1);
#else
return (1);
#endif
} // end of Init_TEN
/***************************************************************************
* Shutdown_TEN -- Shuts down TEN connections *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 01/09/1996 BRR : Created. *
*=========================================================================*/
void Shutdown_TEN(void)
{
#if(TEN)
CDTimerClass<SystemTimerClass> timer;
//------------------------------------------------------------------------
// Wait a full second before exiting, to ensure all packets get sent.
//------------------------------------------------------------------------
timer = 60;
while (timer) ;
//------------------------------------------------------------------------
// Free memory
//------------------------------------------------------------------------
if (Session.TenPacket) {
delete [] Session.TenPacket;
Session.TenPacket = NULL;
}
if (Ten) {
delete Ten;
Ten = NULL;
}
return;
#endif
} // end of Shutdown_TEN
/***************************************************************************
* Connect_TEN -- Waits for connections to other players *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* MPlayerCount must have been initialized at this point. *
* *
* HISTORY: *
* 01/10/1996 BRR : Created. *
*=========================================================================*/
void Connect_TEN(void)
{
#if(TEN)
typedef struct ConnectPacketTag {
NetCommandType Dummy; // packet type; set to PING
char Name[MPLAYER_NAME_MAX]; // player's name
HousesType House; // player's ActLike
unsigned char Color; // player's Color
} ConnectPacketType;
int num_players;
int num_found;
ConnectPacketType send_packet;
ConnectPacketType receive_packet;
int address;
int found;
int size;
int i;
CDTimerClass<SystemTimerClass> send_timer;
NodeNameType *who;
enum {
D_TXT6_H = 7,
D_MARGIN = 5,
};
static int x,y,w,h;
char const *buf1;
char const *buf2;
int display = 0;
RemapControlType * scheme = GadgetClass::Get_Color_Scheme();
//
// Clear the Players list
//
while (Session.Players.Count() > 0) {
delete Session.Players[0];
Session.Players.Delete(Session.Players[0]);
}
//
// Add myself to the list first thing
//
who = new NodeNameType;
strcpy(who->Name, Session.Handle);
who->Player.House = Session.House;
who->Player.Color = Session.ColorIdx;
Session.Players.Add (who);
//
// Find out how many players to wait for
//
num_players = Session.NumPlayers - 1;
num_found = 0;
//
// Send out a packet announcing my presence
//
send_packet.Dummy = NET_PING;
strcpy(send_packet.Name, Session.Handle);
send_packet.House = Session.House;
send_packet.Color = Session.ColorIdx;
Ten->Send_Global_Message(&send_packet, sizeof(send_packet), 0, -1);
//
// Start our packet-sending timer
//
send_timer = 240;
//
// Wait for all players to enter the game
//
display = 1;
while (num_found < num_players) {
#ifdef WIN32
/*
** If we have just received input focus again after running in the background then
** we need to redraw.
*/
if (AllSurfaces.SurfacesRestored) {
AllSurfaces.SurfacesRestored=FALSE;
display = 1;
}
#endif
if (display) {
Fancy_Text_Print("", 0, 0, 0, 0, TPF_TEXT);
buf1 = Text_String(TXT_WAITING_FOR_CONNECTIONS);
buf2 = Text_String(TXT_PRESS_ESC);
w = MAX(String_Pixel_Width(buf1),String_Pixel_Width(buf2));
w += (D_MARGIN * 2);
h = (D_TXT6_H * 2) + (D_MARGIN * 7);
x = 160 - (w / 2);
y = 100 - (h / 2);
Hide_Mouse();
//Set_Logic_Page(SeenBuff);
Dialog_Box(x * RESFACTOR, y * RESFACTOR, w * RESFACTOR, h * RESFACTOR);
Fancy_Text_Print(buf1,
160 * RESFACTOR,
(y + (D_MARGIN * 2)) * RESFACTOR,
scheme, TBLACK, TPF_CENTER | TPF_TEXT);
Fancy_Text_Print(buf2,
160 * RESFACTOR,
(y + (D_MARGIN * 2) + D_TXT6_H + D_MARGIN) * RESFACTOR,
scheme, TBLACK, TPF_CENTER | TPF_TEXT);
Show_Mouse();
display = 0;
}
Ten->Service();
//
// Check for an incoming packet; if a PING comes in, see if we already
// have this player in our Players list. If not, add him.
//
if (Ten->Get_Global_Message (&receive_packet, &size, &address) &&
receive_packet.Dummy == NET_PING) {
found = 0;
for (i = 1; i < Session.Players.Count(); i++) {
if (Session.Players[i]->TenAddress == address) {
found = 1;
break;
}
}
//
// Create a new connection and a new node in the list.
//
if (!found) {
who = new NodeNameType;
strcpy(who->Name, receive_packet.Name);
who->TenAddress = address;
who->Player.House = receive_packet.House;
who->Player.Color = (PlayerColorType)receive_packet.Color;
Session.Players.Add (who);
num_found++;
Ten->Send_Global_Message(&send_packet, sizeof(send_packet), 1,
address);
}
}
//
// If the user hits ESC, bail out.
//
if (Keyboard->Check()) {
if (Keyboard->Get() == KN_ESC) {
//Prog_End();
Emergency_Exit(0);
}
}
//
// When our timer expires, re-send the packet.
//
if (!send_timer) {
send_packet.Dummy = NET_PING;
Ten->Send_Global_Message(&send_packet, sizeof(send_packet), 0, -1);
send_timer = 240;
}
}
#else
return;
#endif
}
/***************************************************************************
* Destroy_TEN_Connection -- Destroys the given connection *
* *
* INPUT: *
* id connection ID to destroy (must be a HousesType) *
* error 0 = user signed off; 1 = connection error; otherwise, *
* no error is shown. *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 01/11/1996 BRR : Created. *
*=========================================================================*/
void Destroy_TEN_Connection(int id, int error)
{
#if(TEN)
int i;
HouseClass *housep;
char txt[80];
//------------------------------------------------------------------------
// Do nothing if the house isn't human.
//------------------------------------------------------------------------
housep = HouseClass::As_Pointer((HousesType)id);
if (!housep || !housep->IsHuman)
return;
/*------------------------------------------------------------------------
Create a message to display to the user
------------------------------------------------------------------------*/
txt[0] = '\0';
if (error==1) {
sprintf(txt,Text_String(TXT_CONNECTION_LOST),Ten->Connection_Name(id));
} else if (error==0) {
sprintf(txt,Text_String(TXT_LEFT_GAME),Ten->Connection_Name(id));
}
if (strlen(txt)) {
Session.Messages.Add_Message (NULL,0, txt, housep->RemapColor,
TPF_TEXT, Rule.MessageDelay * TICKS_PER_MINUTE);
Map.Flag_To_Redraw(false);
}
//------------------------------------------------------------------------
// Remove this player from the Players vector
//------------------------------------------------------------------------
for (i = 0; i < Session.Players.Count(); i++) {
if (!stricmp(Session.Players[i]->Name,housep->IniName)) {
delete Session.Players[i];
Session.Players.Delete(Session.Players[i]);
break;
}
}
/*------------------------------------------------------------------------
Delete the TEN connection
------------------------------------------------------------------------*/
Ten->Delete_Connection(id);
//------------------------------------------------------------------------
// Turn the player's house over to the computer's AI
//------------------------------------------------------------------------
housep->IsHuman = false;
housep->IQ = Rule.MaxIQ;
strcpy (housep->IniName,Text_String(TXT_COMPUTER));
Session.NumPlayers--;
/*------------------------------------------------------------------------
If we're the last player left, tell the user.
------------------------------------------------------------------------*/
if (Session.NumPlayers == 1) {
sprintf(txt,"%s",Text_String(TXT_JUST_YOU_AND_ME));
Session.Messages.Add_Message (NULL, 0, txt, housep->RemapColor,
TPF_TEXT, Rule.MessageDelay * TICKS_PER_MINUTE);
Map.Flag_To_Redraw(false);
}
#else
id = id;
error = error;
#endif
} // end of Destroy_TEN_Connection
/***************************************************************************
* Debug_Mono -- Custom mono prints *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 11/27/1996 BRR : Created. *
*=========================================================================*/
void Debug_Mono(void)
{
#if(TEN)
int i;
int id;
Mono_Printf("STATE: # Connections:%d\n",Ten->Num_Connections());
for (i=0;i<Ten->Num_Connections();i++) {
id = Ten->Connection_ID(i);
Mono_Printf("Connection %d: Name:%s, ID:%d, Address:%d\n",
i,
Ten->Connection_Name(id),
Ten->Connection_ID(i),
Ten->Connection_Address(id));
}
#endif
}
/***************************************************************************
* Send_TEN_Win_Packet -- Sends a win packet to server *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 11/27/1996 BRR : Created. *
*=========================================================================*/
void Send_TEN_Win_Packet(void)
{
#if(TEN)
char winbuf[80];
char idbuf[20];
int first = 1;
HouseClass *hptr;
int i;
//
// Build a special text buffer to send to the TEN server. Format:
// "winner 'id id'", where 'id' is the Ten Player ID of each player
// on the winning team. (For TEN, the color index is the player ID.)
//
sprintf(winbuf,"winner '");
for (i = 0; i < Session.Players.Count(); i++) {
hptr = HouseClass::As_Pointer(Session.Players[i]->Player.ID);
if (!hptr->IsDefeated) {
if (!first) {
strcat(winbuf," ");
} else {
first = 0;
}
sprintf(idbuf,"%d", Session.Players[i]->Player.Color);
strcat (winbuf, idbuf);
}
}
strcat (winbuf,"' ");
tenArSetPlayerState(winbuf);
#endif // TEN
} // end of Send_TEN_Win_Packet
/***************************************************************************
* Send_TEN_Alliance -- Sends an ally/enemy packet to server *
* *
* INPUT: *
* whom name of player we're allying / enemying with *
* ally 1 = we're allying; 0 = we're breaking the alliance *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 11/27/1996 BRR : Created. *
*=========================================================================*/
void Send_TEN_Alliance(char *whom, int ally)
{
#if(TEN)
char buf[80];
if (ally) {
sprintf(buf,"ally '%s' ",whom);
} else {
sprintf(buf,"enemy '%s' ",whom);
}
tenArSetPlayerState(buf);
#else
whom = whom;
ally = ally;
#endif // TEN
} // end of Send_TEN_Alliance
/***************************************************************************
* Send_TEN_Out_Of_Sync -- Announces this game out of sync *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 11/27/1996 BRR : Created. *
*=========================================================================*/
void Send_TEN_Out_Of_Sync(void)
{
#if(TEN)
tenArSetPlayerState("sync '1' ");
#endif // TEN
} // end of Send_TEN_Out_Of_Sync
/***************************************************************************
* Send_TEN_Packet_Too_Late -- Announces packet-received-too-late *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 11/27/1996 BRR : Created. *
*=========================================================================*/
void Send_TEN_Packet_Too_Late(void)
{
#if(TEN)
tenArSetPlayerState("toolate '1' ");
#endif // TEN
} // end of Send_TEN_Packet_Too_Late
/***************************** end of ccten.cpp *****************************/

6
CODE/CC_ICON.RC Normal file
View file

@ -0,0 +1,6 @@
#define ICON_1 1
ICON_1 ICON "redalert.ico"

1
CODE/CC_ICON.RH Normal file
View file

@ -0,0 +1 @@
#define ICON_1 1

3324
CODE/CDATA.CPP Normal file

File diff suppressed because it is too large Load diff

720
CODE/CDFILE.CPP Normal file
View file

@ -0,0 +1,720 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/CDFILE.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Westwood Library *
* *
* File Name : CDFILE.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : October 18, 1994 *
* *
* Last Update : September 22, 1995 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* CDFileClass::Clear_Search_Drives -- Removes all record of a search path. *
* CDFileClass::Open -- Opens the file object -- with path search. *
* CDFileClass::Open -- Opens the file wherever it can be found. *
* CDFileClass::Set_Name -- Performs a multiple directory scan to set the filename. *
* CDFileClass::Set_Search_Drives -- Sets a list of search paths for file access. *
* Is_Disk_Inserted -- Checks to see if a disk is inserted in specified drive. *
* harderr_handler -- Handles hard DOS errors. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "cdfile.h"
#include <stdio.h>
#include <string.h>
#ifndef WIN32
#include <wwstd.h>
#include <playcd.h>
#endif
/*
** Pointer to the first search path record.
*/
CDFileClass::SearchDriveType * CDFileClass::First = 0;
int CDFileClass::CurrentCDDrive = 0;
int CDFileClass::LastCDDrive = 0;
char CDFileClass::RawPath[512] = {0};
CDFileClass::CDFileClass(char const *filename) :
IsDisabled(false)
{
CDFileClass::Set_Name(filename);
// memset (RawPath, 0, sizeof(RawPath));
}
CDFileClass::CDFileClass(void) :
IsDisabled(false)
{
}
extern int Get_CD_Index (int cd_drive, int timeout);
/***********************************************************************************************
* harderr_handler -- Handles hard DOS errors. *
* *
* This routine will handle the low level DOS error trapper. Instead of displaying the *
* typical "Abort, Retry, Ignore" message, it simply returns with the failure code. The *
* cause of the error will fail. The likely case would be with disk I/O. *
* *
* INPUT: *
* *
* OUTPUT: Return the failure code. *
* *
* WARNINGS: Do no processing in this routine that could possibly generate another *
* hard error condition. *
* *
* HISTORY: *
* 09/22/1995 JLB : Created. *
*=============================================================================================*/
#ifdef WIN32
int harderr_handler(unsigned int , unsigned int , unsigned int *)
#else
int harderr_handler(unsigned int , unsigned int , unsigned int __far *)
#endif
{
return(_HARDERR_FAIL);
}
/***********************************************************************************************
* Is_Disk_Inserted -- Checks to see if a disk is inserted in specified drive. *
* *
* This routine will examine the drive specified to see if there is a disk inserted. It *
* can be used for floppy drives as well as for the CD-ROM. *
* *
* INPUT: disk -- The drive number to examine. 0=A, 1=B, etc. *
* *
* OUTPUT: bool; Is a disk inserted into the specified drive? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/20/1995 JLB : Created. *
*=============================================================================================*/
int cdecl Is_Disk_Inserted(int disk)
{
#ifndef OBSOLETE
struct find_t fb;
char scan[] = "?:\\*.*";
#ifndef WIN32
_harderr(harderr_handler); // BG: Install hard error handler
#endif
scan[0] = (char)('A' + disk);
return(_dos_findfirst(scan, _A_SUBDIR, &fb) == 0);
#else
struct {
struct {
char Length;
char Unit;
char Function;
char Status;
char Reserved[8];
} ReqHdr;
char MediaDescriptor; // Media descriptor byte from BPB.
void *Transfer; // Pointer to transfer address block.
short Length; // Number of bytes to transfer.
short Sector; // Starting sector number.
void *Volume; // Pointer to requested volume.
} IOCTLI;
char status[5];
memset(IOCTLI, 0, sizeof(IOCTLI));
IOCTLI.ReqHdr.Length = 26;
IOCTLI.ReqHdr.Unit = 0; // First CD-ROM controlled by this driver.
//IOCTLI.ReqHdr.Unit = 11; // Hard coded for K:
IOCTLI.ReqHdr.Function = 3; // IOCTL read
IOCTLI.Transfer = &status[0];
IOCTLI.Length = sizeof(status);
status[0] = 6; // Fetch device status code.
_AX = 0x440D;
_CX = 0x0003;
geninterrupt(0x21);
return(!(_AX & (1<<11)));
#endif
}
/***********************************************************************************************
* CDFileClass::Open -- Opens the file object -- with path search. *
* *
* This will open the file object, but since the file object could have been constructed *
* with a pathname, this routine will try to find the file first. For files opened for *
* writing, then use the existing filename without performing a path search. *
* *
* INPUT: rights -- The access rights to use when opening the file *
* *
* OUTPUT: bool; Was the open successful? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 10/18/1994 JLB : Created. *
*=============================================================================================*/
int CDFileClass::Open(int rights)
{
return(BufferIOFileClass::Open(rights));
}
/***********************************************************************************************
* CDFC::Refresh_Search_Drives -- Updates the search path when a CD changes or is added *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 5/22/96 9:01AM ST : Created *
*=============================================================================================*/
void CDFileClass::Refresh_Search_Drives (void)
{
Clear_Search_Drives();
Set_Search_Drives(RawPath);
}
#if 0
/***********************************************************************************************
* CDFileClass::Set_Search_Drives -- Sets a list of search paths for file access. *
* *
* This routine sets up a list of search paths to use when accessing files. The path list *
* is scanned if the file could not be found in the current directory. This is the primary *
* method of supporting CD-ROM drives, but is also useful for scanning network and other *
* directories. The pathlist as passed to this routine is of the same format as the path *
* list used by DOS -- paths are separated by semicolons and need not end in an antivirgule.*
* *
* If a path entry begins with "?:" then the question mark will be replaced with the first *
* CD-ROM drive letter available. If there is no CD-ROM driver detected, then this path *
* entry will be ignored. By using this feature, you can always pass the CD-ROM path *
* specification to this routine and it will not break if the CD-ROM is not loaded (as in *
* the case during development). *
* *
* Here is an example path specification: *
* *
* Set_Search_Drives("DATA;?:\DATA;F:\PROJECT\DATA"); *
* *
* In this example, the current directory will be searched first, followed by a the *
* subdirectory "DATA" located off of the current directory. If not found, then the CD-ROM *
* will be searched in a directory called "\DATA". If not found or the CD-ROM is not *
* present, then it will look to the hard coded path of "F:\PROJECTS\DATA" (maybe a *
* network?). If all of these searches fail, the file system will default to the current *
* directory and let the normal file error system take over. *
* *
* INPUT: pathlist -- Pointer to string of path specifications (separated by semicolons) *
* that will be used to search for files. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 10/18/1994 JLB : Created. *
*=============================================================================================*/
int CDFileClass::Set_Search_Drives(char * pathlist)
{
int found = false;
int empty = false;
/*
** If there is no pathlist to add, then just return.
*/
if (!pathlist) return(0);
char const * ptr = strtok(pathlist, ";");
while (ptr) {
char path[PATH_MAX]; // Working path buffer.
SearchDriveType *srch; // Working pointer to path object.
/*
** Fixup the path to be legal. Legal is defined as all that is necessary to
** create a pathname is to append the actual filename submitted to the
** file system. This means that it must have either a trailing ':' or '\'
** character.
*/
strcpy(path, ptr);
switch (path[strlen(path)-1]) {
case ':':
case '\\':
break;
default:
strcat(path, "\\");
break;
}
/*
** If there is a drive letter specified, and this drive letter is '?', then it should
** be substituted with the CD-ROM drive letter. In the case of no CD-ROM attached, then
** merely ignore this path entry.
*/
if (strncmp(path, "?:", 2) == 0) {
#ifndef WIN32
GetCDClass temp;
int cd = temp.GetCDDrive();
#else
int cd = 10;
#endif
found = cd;
empty = !Is_Disk_Inserted(cd);
if (!found || empty) goto nextpath;
path[0] = (char)('A' + cd);
}
/*
** Allocate a record structure.
*/
srch = new SearchDriveType;
if (srch) {
found = true;
/*
** Attach the path to this structure.
*/
srch->Path = strdup(path);
srch->Next = NULL;
/*
** Attach this path record to the end of the path chain.
*/
if (!First) {
First = srch;
} else {
SearchDriveType * chain = First;
while (chain->Next) {
chain = (SearchDriveType *)chain->Next;
}
chain->Next = srch;
}
}
/*
** Find the next path string and resubmit.
*/
nextpath:
ptr = strtok(NULL, ";");
}
if (!found) return(1);
if (empty) return(2);
return(0);
}
#endif
/***********************************************************************************************
* CDFileClass::Set_Search_Drives -- Sets a list of search paths for file access. *
* *
* This routine sets up a list of search paths to use when accessing files. The path list *
* is scanned if the file could not be found in the current directory. This is the primary *
* method of supporting CD-ROM drives, but is also useful for scanning network and other *
* directories. The pathlist as passed to this routine is of the same format as the path *
* list used by DOS -- paths are separated by semicolons and need not end in an antivirgule.*
* *
* If a path entry begins with "?:" then the question mark will be replaced with the first *
* CD-ROM drive letter available. If there is no CD-ROM driver detected, then this path *
* entry will be ignored. By using this feature, you can always pass the CD-ROM path *
* specification to this routine and it will not break if the CD-ROM is not loaded (as in *
* the case during development). *
* *
* Here is an example path specification: *
* *
* Set_Search_Drives("DATA;?:\DATA;F:\PROJECT\DATA"); *
* *
* In this example, the current directory will be searched first, followed by a the *
* subdirectory "DATA" located off of the current directory. If not found, then the CD-ROM *
* will be searched in a directory called "\DATA". If not found or the CD-ROM is not *
* present, then it will look to the hard coded path of "F:\PROJECTS\DATA" (maybe a *
* network?). If all of these searches fail, the file system will default to the current *
* directory and let the normal file error system take over. *
* *
* INPUT: pathlist -- Pointer to string of path specifications (separated by semicolons) *
* that will be used to search for files. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 10/18/1994 JLB : Created. *
* 05/21/1996 ST : Modified to recognise multiple CD drives *
*=============================================================================================*/
int CDFileClass::Set_Search_Drives(char * pathlist)
{
int found = FALSE;
int empty = FALSE;
/*
** If there is no pathlist to add, then just return.
*/
if (!pathlist) return(0);
/*
** Save the path as it was passed in so we can parse it again later.
** Check for the case where RawPath was passed in.
*/
if (pathlist != RawPath) {
strcat (RawPath, ";");
strcat (RawPath, pathlist);
}
char const * ptr = strtok(pathlist, ";");
while (ptr != NULL) {
if (strlen(ptr) > 0) {
char path[PATH_MAX]; // Working path buffer.
/*
** Fixup the path to be legal. Legal is defined as all that is necessary to
** create a pathname is to append the actual filename submitted to the
** file system. This means that it must have either a trailing ':' or '\'
** character.
*/
strcpy(path, ptr);
switch (path[strlen(path)-1]) {
case ':':
case '\\':
break;
default:
strcat(path, "\\");
break;
}
/*
** If there is a drive letter specified, and this drive letter is '?', then it should
** be substituted with the CD-ROM drive letter. In the case of no CD-ROM attached, then
** merely ignore this path entry.
** Adds an extra entry for each CD drive in the system that has a C&C disc inserted.
** ST - 5/21/96 4:40PM
*/
if (strncmp(path, "?:", 2) == 0) {
if (CurrentCDDrive) {
found = true;
/*
** If the drive has a C&C CD in it then add it to the path
*/
if (Get_CD_Index(CurrentCDDrive, 2*60) >= 0) {
path[0] = (char)(CurrentCDDrive + 'A');
Add_Search_Drive(path);
}
}
/*
** Find the next path string and resubmit.
*/
ptr = strtok(NULL, ";");
continue;
}
found = true;
Add_Search_Drive(path);
}
/*
** Find the next path string and resubmit.
*/
ptr = strtok(NULL, ";");
}
if (!found) return(1);
if (empty) return(2);
return(0);
}
/***********************************************************************************************
* CDFC::Add_Search_Drive -- Add a new path to the search path list *
* *
* *
* *
* INPUT: path *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 5/22/96 10:12AM ST : Created *
*=============================================================================================*/
void CDFileClass::Add_Search_Drive(char *path)
{
SearchDriveType *srch; // Working pointer to path object.
/*
** Allocate a record structure.
*/
srch = new SearchDriveType;
/*
** Attach the path to this structure.
*/
srch->Path = strdup(path);
srch->Next = NULL;
/*
** Attach this path record to the end of the path chain.
*/
if (!First) {
First = srch;
} else {
SearchDriveType * chain = First;
while (chain->Next) {
chain = (SearchDriveType *)chain->Next;
}
chain->Next = srch;
}
}
/***********************************************************************************************
* CDFC::Set_CD_Drive -- sets the current CD drive letter *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 5/22/96 9:39AM ST : Created *
*=============================================================================================*/
void CDFileClass::Set_CD_Drive (int drive)
{
LastCDDrive = CurrentCDDrive;
CurrentCDDrive = drive;
}
/***********************************************************************************************
* CDFileClass::Clear_Search_Drives -- Removes all record of a search path. *
* *
* Use this routine to clear out any previous path(s) set with Set_Search_Drives() *
* function. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 10/18/1994 JLB : Created. *
*=============================================================================================*/
void CDFileClass::Clear_Search_Drives(void)
{
SearchDriveType * chain; // Working pointer to path chain.
chain = First;
while (chain) {
SearchDriveType *next;
next = (SearchDriveType *)chain->Next;
if (chain->Path) {
free((char *)chain->Path);
}
delete chain;
chain = next;
}
First = 0;
}
/***********************************************************************************************
* CDFileClass::Set_Name -- Performs a multiple directory scan to set the filename. *
* *
* This routine will scan all the directories specified in the path list and if the file *
* was found in one of the directories, it will set the filename to a composite of the *
* correct directory and the filename. It is used to allow path searching when searching *
* for files. Typical use is to support CD-ROM drives. This routine examines the current *
* directory first before scanning through the path list. If after scanning the entire *
* path list, the file still could not be found, then the file object's name is set with *
* just the raw filename as passed to this routine. *
* *
* INPUT: filename -- Pointer to the filename to set as the name of this file object. *
* *
* OUTPUT: Returns a pointer to the final and complete filename of this file object. This *
* may have a path attached to the file. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 10/18/1994 JLB : Created. *
*=============================================================================================*/
char const * CDFileClass::Set_Name(char const *filename)
{
/*
** Try to find the file in the current directory first. If it can be found, then
** just return with the normal file name setting process. Do the same if there is
** no multi-drive search path.
*/
BufferIOFileClass::Set_Name(filename);
if (IsDisabled || !First || BufferIOFileClass::Is_Available()) return(File_Name());
/*
** Attempt to find the file first. Check the current directory. If not found there, then
** search all the path specifications available. If it still can't be found, then just
** fall into the normal raw file filename setting system.
*/
SearchDriveType * srch = First;
while (srch) {
char path[_MAX_PATH];
/*
** Build a pathname to search for.
*/
strcpy(path, srch->Path);
strcat(path, filename);
/*
** Check to see if the file could be found. The low level Is_Available logic will
** prompt if necessary when the CD-ROM drive has been removed. In all other cases,
** it will return false and the search process will continue.
*/
BufferIOFileClass::Set_Name(path);
if (BufferIOFileClass::Is_Available()) {
return(File_Name());
}
/*
** It wasn't found, so try the next path entry.
*/
srch = (SearchDriveType *)srch->Next;
}
/*
** At this point, all path searching has failed. Just set the file name to the
** plain text passed to this routine and be done with it.
*/
BufferIOFileClass::Set_Name(filename);
return(File_Name());
}
/***********************************************************************************************
* CDFileClass::Open -- Opens the file wherever it can be found. *
* *
* This routine is similar to the RawFileClass open except that if the file is being *
* opened only for READ access, it will search all specified directories looking for the *
* file. If after a complete search the file still couldn't be found, then it is opened *
* using the normal BufferIOFileClass system -- resulting in normal error procedures. *
* *
* INPUT: filename -- Pointer to the override filename to supply for this file object. It *
* would be the base filename (sans any directory specification). *
* *
* rights -- The access rights to use when opening the file. *
* *
* OUTPUT: bool; Was the file opened successfully? If so then the filename may be different *
* than requested. The location of the file can be determined by examining the *
* filename of this file object. The filename will contain the complete *
* pathname used to open the file. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 10/18/1994 JLB : Created. *
*=============================================================================================*/
int CDFileClass::Open(char const *filename, int rights)
{
CDFileClass::Close();
/*
** Verify that there is a filename associated with this file object. If not, then this is a
** big error condition.
*/
if (!filename) {
Error(ENOENT, false);
}
/*
** If writing is requested, then multiple drive searching is not performed.
*/
if (IsDisabled || rights == WRITE) {
BufferIOFileClass::Set_Name( filename );
return( BufferIOFileClass::Open( rights ) );
}
/*
** Perform normal multiple drive searching for the filename and open
** using the normal procedure.
*/
Set_Name(filename);
return(BufferIOFileClass::Open(rights));
}
#ifdef NEVER
/*
** Get the drive letters if the CD's online */
*/
WORD cdecl GetCDDrive(VOID)
{
_ES = FP_SEG(&cdDrive[0]);
_BX = FP_OFF(&cdDrive[0]);
_AX = 0x150d;
geninterrupt(0x2F);
return((WORD)(*cdDrive));
}
#endif
#if 0
int Get_CD_Drive(void)
{
#ifdef WIN32
return(10);
#else
#ifdef NEVER
for (int index = 0; index < 26; index++) {
union REGS regs;
regs.w.ax = 0x150B;
regs.w.bx = 0;
regs.w.cx = index;
int386(0x2F, &regs, &regs);
if (regs.w.bx == 0xADAD) {
return(index);
}
}
return(0);
#else
GetCDClass temp;
return(temp.GetCDDrive());
#endif
#endif
}
#endif

113
CODE/CDFILE.H Normal file
View file

@ -0,0 +1,113 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/CDFILE.H 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Westwood LIbrary *
* *
* File Name : CDFILE.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : October 18, 1994 *
* *
* Last Update : October 18, 1994 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef CDFILE_H
#define CDFILE_H
#include <dos.h>
#include "bfiofile.h"
/*
** This class is derived from the BufferIOFileClass. This class adds the functionality of searching
** across multiple directories or drives. It is designed for the typical case of a CD-ROM game
** were some data exists in the current directory (hard drive) and the rest exists on the CD-ROM.
** Searching for the file occurs by first examining the current directory. If the file does not
** exist there, then all the paths available are examined in turn until the file can be found.
** For opening files to write, only the current directory is examined. The directory search order
** is controlled by the path list as submitted to Set_Search_Drives(). The format of the path
** string is the same as the DOS path string.
*/
class CDFileClass : public BufferIOFileClass
{
public:
CDFileClass(char const *filename);
CDFileClass(void);
virtual ~CDFileClass(void) {};
virtual char const * Set_Name(char const *filename);
virtual int Open(char const *filename, int rights=READ);
virtual int Open(int rights=READ);
void Searching(int on) {IsDisabled = !on;};
static bool Is_There_Search_Drives(void) {return(First != NULL);};
static int Set_Search_Drives(char * pathlist);
static void Add_Search_Drive(char *path);
static void Clear_Search_Drives(void);
static void Refresh_Search_Drives(void);
static void Set_CD_Drive(int drive);
static int Get_CD_Drive(void) {return(CurrentCDDrive);};
static int Get_Last_CD_Drive(void) {return(LastCDDrive);};
private:
/*
** Is multi-drive searching disabled for this file object?
*/
unsigned IsDisabled:1;
/*
** This is the control record for each of the drives specified in the search
** path. There can be many such search paths available.
*/
typedef struct {
void * Next; // Pointer to next search record.
char const * Path; // Pointer to path string.
} SearchDriveType;
/*
** This points to the first path record.
*/
static SearchDriveType * First;
/*
** This is a copy of the unparsed search path list
*/
static char RawPath[512];
/*
** The drive letter of the current cd drive
*/
static int CurrentCDDrive;
/*
** The drive letter of the last used CD drive
*/
static int LastCDDrive;
};
#endif

3014
CODE/CELL.CPP Normal file

File diff suppressed because it is too large Load diff

295
CODE/CELL.H Normal file
View file

@ -0,0 +1,295 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/CELL.H 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : CELL.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : April 29, 1994 *
* *
* Last Update : April 29, 1994 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef CELL_H
#define CELL_H
#include "building.h"
#include "unit.h"
#include "template.h"
/****************************************************************************
** Each cell on the map is controlled by the following structure.
*/
class CellClass
{
public:
/*
** This is the ID number of this cell. By placing the ID number here, it doesn't have
** be calculated. Calculating this number requires a divide and would occur about
** 5.72031 bijillion times per second.
*/
short ID;
/*
** Does this cell need to be updated on the radar map? If something changes in the cell
** that might change the radar map imagery, then this flag will be set. It gets cleared
** when the cell graphic is updated to the radar map.
*/
unsigned IsPlot:1;
/*
** Does this cell contain the special placement cursor graphic? This graphic is
** present when selecting a site for building placement.
*/
unsigned IsCursorHere:1;
/*
** A mapped cell has some portion of it visible. Maybe it has a shroud piece
** over it and maybe not.
*/
unsigned IsMapped:1;
/*
** A visible cell means that it is completely visible with no shroud over
** it at all.
*/
unsigned IsVisible:1;
/*
** Every cell can be assigned a waypoint. A waypoint can only be assigned
** to one cell, and vice-versa. This bit simply indicates whether this
** cell is assigned a waypoint or not.
*/
unsigned IsWaypoint:1;
/*
** Is this cell currently under the radar map cursor? If so then it
** needs to be updated whenever the map is updated.
*/
unsigned IsRadarCursor:1;
/*
** If this cell contains a house flag, then this will be true. The actual house
** flag it contains is specified by the Owner field.
*/
unsigned IsFlagged:1;
/*
** This is a working flag used to help keep track of what cells should be
** shrouded. By using this flag it allows a single pass through the map
** cells for determining shadow regrowth logic.
*/
unsigned IsToShroud:1;
/*
** This records the movement zone for this map. Movement zones share the
** same number if they are contiguous (terrain consideration only). There
** are basically two kinds of zones. The difference being determined by
** walls that can be crushed by movement. A vehicle that can crush walls
** will only consider the CrushZone. All other terrestrial travellers will
** use the normal Zone.
*/
unsigned char Zones[MZONE_COUNT];
/*
** This field controls whether an area is being jammed by a gap
** generator.
*/
unsigned short Jammed;
/*
** This is the trigger ID for any trigger that might be attached to
** this cell.
*/
CCPtr<TriggerClass> Trigger;
/*
** This contains the icon number and set to use for the base
** of the terrain. All rendering on an icon occurs AFTER the icon
** specified by this element is rendered. It is the lowest of the low.
*/
TemplateType TType;
unsigned char TIcon;
/*
** The second layer of 'terrain' icons is represented by a simple
** type number and a value byte. This is sufficient for handling
** concrete and walls.
*/
OverlayType Overlay;
unsigned char OverlayData;
/*
** This is used to specify any special 'stain' overlay icon. This
** typically includes infantry bodies or other temporary marks.
*/
SmudgeType Smudge;
unsigned char SmudgeData;
/*
** Smudges and walls need to record ownership values. For walls, this
** allows adjacent building placement logic to work. For smudges, it
** allows building over smudges that are no longer attached to buildings
** in addition to fixing the adjacent placement logic.
*/
HousesType Owner;
/*
** This flag tells you what type of infantry currently occupy the
** cell or are moving into it.
*/
HousesType InfType;
/*
** These point to the object(s) that are located in this cell or overlap
** this cell.
*/
private:
ObjectClass * OccupierPtr;
public:
#ifdef SORTDRAW
ObjectClass * Overlapper[10];
#else
ObjectClass * Overlapper[6];
#endif
/*
** This array of bit flags is used to indicate which sub positions
** within the cell are either occupied or are soon going to be
** occupied. For vehicles, the cells that the vehicle is passing over
** will be flagged with the vehicle bit. For infantry, the the sub
** position the infantry is stopped at or headed toward will be marked.
** The sub positions it passes over will NOT be marked.
*/
union {
struct {
unsigned Center:1;
unsigned NW:1;
unsigned NE:1;
unsigned SW:1;
unsigned SE:1;
unsigned Vehicle:1; // Reserved for vehicle occupation.
unsigned Monolith:1; // Some immovable blockage is in cell.
unsigned Building:1; // A building of some time (usually blocks movement).
} Occupy;
unsigned char Composite;
} Flag;
//----------------------------------------------------------------
CellClass(void);
CellClass(NoInitClass const & x) : Trigger(x) {}
~CellClass(void) {OccupierPtr=0;}
int operator == (CellClass const & cell) const {return &cell == this;}
/*
** Query functions.
*/
bool Can_Tiberium_Germinate(void) const;
bool Can_Tiberium_Grow(void) const;
bool Can_Tiberium_Spread(void) const;
bool Is_Bridge_Here(void) const;
RTTIType What_Am_I(void) const {return(RTTI_CELL);}
BuildingClass * Cell_Building(void) const;
CELL Cell_Number(void) const {return(ID);}
COORDINATE Cell_Coord(void) const;
COORDINATE Closest_Free_Spot(COORDINATE coord, bool any=false) const;
COORDINATE Free_Spot(void) const {return Closest_Free_Spot(Cell_Coord());}
CellClass & Adjacent_Cell(FacingType face) {return (CellClass &)((*((CellClass const *)this)).Adjacent_Cell(face));}
CellClass const & Adjacent_Cell(FacingType face) const;
InfantryClass * Cell_Infantry(void) const;
LandType Land_Type(void) const {return(Land);}
ObjectClass * Cell_Find_Object(RTTIType rtti) const;
ObjectClass * Cell_Object(int x=0, int y=0) const;
ObjectClass * Cell_Occupier(void) const {return(OccupierPtr);}
ObjectClass * Fetch_Occupier(void) const;
TARGET As_Target(void) const {return ::As_Target(Cell_Number());}
TechnoClass * Cell_Techno(int x=0, int y=0) const;
TerrainClass * Cell_Terrain(void) const;
UnitClass * Cell_Unit(void) const;
VesselClass * Cell_Vessel(void) const;
bool Goodie_Check(FootClass * object);
bool Is_Clear_To_Build(SpeedType loco = SPEED_TRACK) const;
bool Is_Clear_To_Move(SpeedType loco, bool ignoreinfantry, bool ignorevehicles, int zone=-1, MZoneType check=MZONE_NORMAL) const;
bool Is_Spot_Free(int spot_index) const {return (! (Flag.Composite & (1 << spot_index)) ); }
int Cell_Color(bool override=false) const;
int Clear_Icon(void) const;
static int Spot_Index(COORDINATE coord);
/*
** Object placement and removal flag operations.
*/
void Occupy_Down(ObjectClass * object);
void Occupy_Up(ObjectClass * object);
void Overlap_Down(ObjectClass * object);
void Overlap_Up(ObjectClass * object);
bool Flag_Place(HousesType house);
bool Flag_Remove(void);
/*
** File I/O.
*/
bool Should_Save(void) const;
bool Save(Pipe & file) const;
bool Load(Straw & file);
void Code_Pointers(void);
void Decode_Pointers(void);
/*
** Display and rendering controls.
*/
void Draw_It(int x, int y, bool objects=false) const;
void Redraw_Objects(bool forced=false);
void Shimmer(void);
/*
** Maintenance calculation support.
*/
bool Grow_Tiberium(void);
bool Spread_Tiberium(bool forced=false);
long Tiberium_Adjust(bool pregame=false);
void Wall_Update(void);
void Concrete_Calc(void);
void Recalc_Attributes(void);
int Reduce_Tiberium(int levels);
int Reduce_Wall(int damage);
void Incoming(COORDINATE threat=0, bool forced=false, bool nokidding=false);
void Adjust_Threat(HousesType house, int threat_value);
int operator != (CellClass const &) const {return 0;}
private:
CellClass (CellClass const &) ;
LandType Land; // The land type of this cell.
};
#endif

102
CODE/CHECKBOX.CPP Normal file
View file

@ -0,0 +1,102 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/CHECKBOX.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : CHECKBOX.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 05/26/95 *
* *
* Last Update : July 6, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* CheckBoxClass::Action -- Handles a button action on a checkbox object. *
* CheckBoxClass::Draw_Me -- Draws the checkbox imagery. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
#include "checkbox.h"
/***********************************************************************************************
* CheckBoxClass::Draw_Me -- Draws the checkbox imagery. *
* *
* This routine will draw the checkbox either filled or empty as necessary. *
* *
* INPUT: forced -- Should the check box be drawn even if it doesn't think it needs to? *
* *
* OUTPUT: Was the check box rendered? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/01/1995 JLB : Created. *
*=============================================================================================*/
int CheckBoxClass::Draw_Me(int forced)
{
if (ToggleClass::Draw_Me(forced)) {
Hide_Mouse();
Draw_Box(X, Y, Width, Height, BOXSTYLE_DOWN, false);
LogicPage->Fill_Rect(X+1, Y+1, X+Width-2, Y+Height-2, DKGREY);
if (IsOn) {
LogicPage->Fill_Rect(X+1, Y+1, X+Width-2, Y+Height-2, LTGREEN);
}
Show_Mouse();
return(true);
}
return(false);
}
/***********************************************************************************************
* CheckBoxClass::Action -- Handles a button action on a checkbox object. *
* *
* This routine will detect if the mouse has been clicked on the checkbox object. If so, *
* the check box state will be toggled. *
* *
* INPUT: flags -- The event flags that resulted in this routine being called. *
* *
* key -- The key that resulted in this routine being called. *
* *
* OUTPUT: bool; Should normal processing occur? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/06/1996 JLB : Created. *
*=============================================================================================*/
int CheckBoxClass::Action(unsigned flags, KeyNumType & key)
{
if (flags & LEFTRELEASE) {
if (IsOn) {
Turn_Off();
} else {
Turn_On();
}
}
return(ToggleClass::Action(flags, key));
}

56
CODE/CHECKBOX.H Normal file
View file

@ -0,0 +1,56 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/CHECKBOX.H 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : CHECKBOX.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 05/26/95 *
* *
* Last Update : May 26, 1995 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef CHECKBOX_H
#define CHECKBOX_H
#include "toggle.h"
class CheckBoxClass : public ToggleClass
{
public:
CheckBoxClass(unsigned id, int x, int y) :
ToggleClass(id, x, y, 7, 7)
{};
virtual int Draw_Me(int forced=false);
virtual int Action(unsigned flags, KeyNumType & key);
protected:
};
#endif

365
CODE/CHEKLIST.CPP Normal file
View file

@ -0,0 +1,365 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/CHEKLIST.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : CHEKLIST.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 07/05/96 *
* *
* Last Update : July 6, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* CheckListClass::Action -- action function for this class *
* CheckListClass::Add_Item -- Adds specifies text to check list box. *
* CheckListClass::CheckListClass -- constructor *
* CheckListClass::Check_Item -- [un]checks an items *
* CheckListClass::Draw_Entry -- draws a list box entry *
* CheckListClass::Get_Item -- Fetches a pointer to the text associated with the index. *
* CheckListClass::Remove_Item -- Remove the item that matches the text pointer specified. *
* CheckListClass::Set_Selected_Index -- Set the selected index to match the text pointer spe*
* CheckListClass::~CheckListClass -- Destructor for check list object. *
* CheckListClass::~CheckListClass -- destructor *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
/***************************************************************************
* CheckListClass::CheckListClass -- constructor *
* *
* INPUT: *
* id control ID for this list box *
* x x-coord *
* y y-coord *
* w width *
* h height *
* flags mouse event flags *
* up ptr to Up-arrow shape *
* down ptr to Down-arrow shape *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 02/16/1995 BR : Created. *
*=========================================================================*/
CheckListClass::CheckListClass(int id, int x, int y, int w, int h, TextPrintType flags,
void const * up, void const * down) :
ListClass (id, x, y, w, h, flags, up, down),
IsReadOnly(false)
{
}
/***********************************************************************************************
* CheckListClass::~CheckListClass -- Destructor for check list object. *
* *
* This destructor will delete all entries attached to it. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/06/1996 JLB : Created. *
*=============================================================================================*/
CheckListClass::~CheckListClass(void)
{
while (CheckListClass::Count()) {
CheckObject * obj = (CheckObject *)ListClass::Get_Item(0);
ListClass::Remove_Item(0);
delete obj;
}
}
/***********************************************************************************************
* CheckListClass::Add_Item -- Adds specifies text to check list box. *
* *
* This routine will add the specified text string to the check list. *
* *
* INPUT: text -- Pointer to the text string to add to the list box. *
* *
* OUTPUT: Returns the index number where the text object was added. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 02/14/1996 JLB : Created. *
*=============================================================================================*/
int CheckListClass::Add_Item(char const * text)
{
CheckObject * obj = new CheckObject(text, false);
return(ListClass::Add_Item((char const *)obj));
}
char const * CheckListClass::Current_Item(void) const
{
CheckObject * obj = (CheckObject *)ListClass::Current_Item();
if (obj) {
return(obj->Text);
}
return(0);
}
/***********************************************************************************************
* CheckListClass::Get_Item -- Fetches a pointer to the text associated with the index. *
* *
* This routine will find the text associated with the entry specified and return a pointer *
* to that text. *
* *
* INPUT: index -- The entry (index) to fetch a pointer to. *
* *
* OUTPUT: Returns with the text pointer associated with the index specified. *
* *
* WARNINGS: If the index is out of range, then NULL is returned. *
* *
* HISTORY: *
* 07/06/1996 JLB : Created. *
*=============================================================================================*/
char const * CheckListClass::Get_Item(int index) const
{
CheckObject * obj = (CheckObject *)ListClass::Get_Item(index);
if (obj) {
return(obj->Text);
}
return(0);
}
/***********************************************************************************************
* CheckListClass::Remove_Item -- Remove the item that matches the text pointer specified. *
* *
* This routine will find the entry that matches the text pointer specified and then *
* delete that entry. *
* *
* INPUT: text -- The text pointer to use to find the exact match in the list. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/06/1996 JLB : Created. *
*=============================================================================================*/
void CheckListClass::Remove_Item(char const * text)
{
for (int index = 0; index < Count(); index++) {
CheckObject * obj = (CheckObject *)ListClass::Get_Item(index);
if (obj && stricmp(obj->Text, text) == 0) {
ListClass::Remove_Item(index);
delete obj;
break;
}
}
}
/***********************************************************************************************
* CheckListClass::Set_Selected_Index -- Set the selected index to match the text pointer spec *
* *
* This routine will find the entry that exactly matches the text pointer specified. If *
* found, then that entry will be set as the currently selected index. *
* *
* INPUT: text -- Pointer to the text string to find the match for. *
* *
* OUTPUT: none *
* *
* WARNINGS: If an exact match to the specified text string could not be found, then the *
* currently selected index is not changed. *
* *
* HISTORY: *
* 07/06/1996 JLB : Created. *
*=============================================================================================*/
void CheckListClass::Set_Selected_Index(char const * text)
{
for (int index = 0; index < Count(); index++) {
CheckObject * obj = (CheckObject *)ListClass::Get_Item(index);
if (obj && stricmp(obj->Text, text) == 0) {
Set_Selected_Index(index);
break;
}
}
}
/***************************************************************************
* CheckListClass::Check_Item -- [un]checks an items *
* *
* INPUT: *
* index index of item to check or uncheck *
* checked 0 = uncheck, non-zero = check *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 02/16/1995 BR : Created. *
* 02/14/1996 JLB : Revamped. *
*=========================================================================*/
void CheckListClass::Check_Item(int index, bool checked)
{
CheckObject * obj = (CheckObject *)ListClass::Get_Item(index);
if (obj && obj->IsChecked != checked) {
obj->IsChecked = checked;
Flag_To_Redraw();
}
}
/***************************************************************************
* CheckListClass::Is_Checked -- returns checked state of an item *
* *
* INPUT: *
* index index of item to query *
* *
* OUTPUT: *
* 0 = item is unchecked, 1 = item is checked *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 02/16/1995 BR : Created. *
* 02/14/1996 JLB : Revamped. *
*=========================================================================*/
bool CheckListClass::Is_Checked(int index) const
{
CheckObject * obj = (CheckObject *)ListClass::Get_Item(index);
if (obj) {
return(obj->IsChecked);
}
return(false);
}
/***************************************************************************
* CheckListClass::Action -- action function for this class *
* *
* INPUT: *
* flags the reason we're being called *
* key the KN_number that was pressed *
* *
* OUTPUT: *
* true = event was processed, false = event not processed *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 02/16/1995 BR : Created. *
*=========================================================================*/
int CheckListClass::Action(unsigned flags, KeyNumType &key)
{
int rc;
/*
** If this is a read-only list, it's a display-only device
*/
if (IsReadOnly) {
return(false);
}
/*
** Invoke parents Action first, so it can set the SelectedIndex if needed.
*/
rc = ListClass::Action(flags, key);
/*
** Now, if this event was a left-press, toggle the checked state of the
** current item.
*/
if (flags & LEFTPRESS) {
Check_Item(SelectedIndex, !Is_Checked(SelectedIndex));
}
return(rc);
}
/***************************************************************************
* CheckListClass::Draw_Entry -- draws a list box entry *
* *
* INPUT: *
* index index into List of item to draw *
* x,y x,y coords to draw at *
* width maximum width allowed for text *
* selected true = this item is selected *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/14/1995 BRR : Created. *
*=========================================================================*/
void CheckListClass::Draw_Entry(int index, int x, int y, int width, int selected)
{
if (index >= Count()) return;
CheckObject * obj = (CheckObject *)ListClass::Get_Item(index);
if (obj) {
char buffer[100] = "";
if (obj->IsChecked) {
buffer[0] = CHECK_CHAR;
} else {
buffer[0] = UNCHECK_CHAR;
}
buffer[1] = ' ';
sprintf(&buffer[2], obj->Text);
TextPrintType flags = TextFlags;
RemapControlType * scheme = GadgetClass::Get_Color_Scheme();
if (selected) {
flags = flags | TPF_BRIGHT_COLOR;
LogicPage->Fill_Rect (x, y, x + width - 1, y + LineHeight - 1, scheme->Shadow);
} else {
if (!(flags & TPF_USE_GRAD_PAL)) {
flags = flags | TPF_MEDIUM_COLOR;
}
}
Conquer_Clip_Text_Print(buffer, x, y, scheme, TBLACK, flags, width, Tabs);
}
}

105
CODE/CHEKLIST.H Normal file
View file

@ -0,0 +1,105 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/CHEKLIST.H 1 3/03/97 10:24a Joe_bostic $ */
/***************************************************************************
** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S **
***************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : CHEKLIST.H *
* *
* Programmer : Bill Randolph *
* *
* Start Date : February 16, 1995 *
* *
* Last Update : February 16, 1995 [BR] *
* *
*-------------------------------------------------------------------------*
* This class behaves just like the standard list box, except that if the *
* first character of a list entry is a space, clicking on it toggles the *
* space with a check-mark ('\3'). This makes each entry in the list box *
* "toggle-able". *
*-------------------------------------------------------------------------*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef CHEKLIST_H
#define CHEKLIST_H
#include "list.h"
class CheckObject
{
public:
CheckObject(char const * text = 0, bool checked=false) :
Text(text),
IsChecked(checked)
{};
char const * Text;
bool IsChecked;
};
class CheckListClass : public ListClass
{
public:
/*
** Constructor/Destructor
*/
CheckListClass(int id, int x, int y, int w, int h, TextPrintType flags,
void const * up, void const * down);
~CheckListClass(void);
virtual int Add_Item(int text) {return ListClass::Add_Item(text);}
virtual int Add_Item(char const * text);
virtual char const * Current_Item(void) const;
virtual char const * Get_Item(int index) const;
virtual void Remove_Item(char const * text);
virtual void Remove_Item(int text) {ListClass::Remove_Item(text);}
virtual void Set_Selected_Index(char const * text);
virtual void Set_Selected_Index(int index) {ListClass::Set_Selected_Index(index);};
/*
** Checkmark utility functions
*/
void Check_Item(int index, bool checked); // sets checked state of item
bool Is_Checked(int index) const; // gets checked state of item
void Set_Read_Only(int rdonly) {IsReadOnly = rdonly;}
/*
** This defines the ASCII value of the checkmark character & non-checkmark
** character.
*/
typedef enum CheckListClassEnum {
CHECK_CHAR = '\3',
UNCHECK_CHAR = ' '
} CheckListClassEnum;
protected:
virtual int Action(unsigned flags, KeyNumType &key);
virtual void Draw_Entry(int index, int x, int y, int width, int selected);
private:
bool IsReadOnly;
};
#endif

19
CODE/CLASS.CPP Normal file
View file

@ -0,0 +1,19 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

67
CODE/CO-WC32.LNT Normal file
View file

@ -0,0 +1,67 @@
// Compiler Options for Watcom C, C++ 32 bit
-cwc
// This file contains options to allow PC-lint to process source
// files for your compiler. It is used as follows:
//
// lint co-wc32.lnt source-file(s)
//
-d_M_IX86=200 // assume Intel 80286 architecture -- modify to suit
-d__declspec()= // ignore this construct
// additional reserve words needed
+rw(_loadds,_export)
+rw(__interrupt,__near,__far,__huge,__fortran,__pascal,__cdecl)
+rw(__export,__loadds,__saveregs,__asm,__fastcall,__stdcall)
+rw(_export)
+fcd // makes cdecl significant -- used for proto generation
+fcu // chars are by default unsigned
+fsu // so are strings
-d__386__ // pre-defined macro for 386 version, not set by -cwc
-d__FLAT__ // not set by -cwc
-si4 // sizeof(int) is 4
-spN4 // sizeof(near pointer) is 4
-spF6 // sizeof( far pointer) is 6
-sld10 // sizeof(long double) is 10.
-function(exit,_exit) // _exit() is like exit()
-emacro(734,putc) // don't complain about items being too large.
-emacro(506,putc) // don't complain about constant Boolean
-emacro(???,va_arg) // the va_arg() macro can yield 415, 416, 661, 662
// 796 and 797 (out-of-bounds errors).
// While processing compiler (library) header files ...
-elib(46) // an unsigned short bit field is used as __FILLER__
-elib(522) // function return value ignored
-elib(537) // repeated include file (ios.h)
-elib(641) // converting enum to int
-elib(652) // suppress message about #define of earlier declared symbols
-elib(655) // ORing enum's
-elib(726) // extraneous comma in enumeration
-elib(760) // suppress message about multiple identical macro defs
-elib(762) // suppress message about multiple identical declarations and
-elib(806) // small bit field is signed
-elib(1053) // prototypes cannot be distinguished
-elib(1511) // member (rdbuf) hides nonvirtual member
-elib(1704) // private copy constructor
-elib(1712) // default constructor missing
-elib(1717) // empty prototypes
-elib(1720) // strange argument to assignment operator
-elib(1721) // unusual operator =() declaration
-elib(1722) // assignment operator does not return ref to class
-elib(1724) // strange argument to copy constructor
-esym(1702,operator<<,operator>>)
// The following functions exhibit variable return modes.
// That is, they may equally-usefully be called for a value
// as called just for their effects. Accordingly we inhibit
// Warning 534 for these functions.
// Feel free to add to or subtract from this list.
-esym(534,close,creat,fclose,fflush,fprintf,fputc)
-esym(534,fputs,fscanf,fseek,fwrite,lseek,memcpy,memmove,memset)
-esym(534,printf,puts,scanf,sprintf,sscanf,strcat,strcpy)
-esym(534,strncat,strncpy,unlink,write)

278
CODE/COLRLIST.CPP Normal file
View file

@ -0,0 +1,278 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/COLRLIST.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : COLRLIST.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 01/15/95 *
* *
* Last Update : April 19, 1995 [BRR] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* ColorListClass::Add_Item -- Adds an item to the list *
* ColorListClass::ColorListClass -- Class constructor *
* ColorListClass::Draw_Entry -- Draws one text line *
* ColorListClass::Remove_Item -- Removes an item from the list *
* ColorListClass::Set_Selected_Style -- tells how to draw selected item *
* ColorListClass::~ColorListClass -- Class destructor *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
/***************************************************************************
* ColorListClass::ColorListClass -- class constructor *
* *
* INPUT: *
* id button ID *
* x,y upper-left corner, in pixels *
* w,h width, height, in pixels *
* list ptr to array of char strings to list *
* flags flags for mouse, style of listbox *
* up,down pointers to shapes for up/down buttons *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: 01/05/1995 MML : Created. *
*=========================================================================*/
ColorListClass::ColorListClass (int id, int x, int y, int w, int h,
TextPrintType flags, void const * up, void const * down) :
ListClass (id, x, y, w, h, flags, up, down),
Style(SELECT_HIGHLIGHT),
SelectColor(NULL)
{
}
/***************************************************************************
* ColorListClass::~ColorListClass -- Class destructor *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 04/19/1995 BRR : Created. *
*=========================================================================*/
ColorListClass::~ColorListClass(void)
{
Colors.Clear();
SelectColor = 0;
}
/***************************************************************************
* ColorListClass::Add_Item -- Adds an item to the list *
* *
* INPUT: *
* text text to add to list *
* color color for item *
* *
* OUTPUT: *
* position of item in the list *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 04/19/1995 BRR : Created. *
*=========================================================================*/
int ColorListClass::Add_Item(char const * text, RemapControlType * color)
{
Colors.Add(color);
return(ListClass::Add_Item(text));
}
/***************************************************************************
* ColorListClass::Add_Item -- Adds an item to the list *
* *
* INPUT: *
* text text to add to list *
* color color for item *
* *
* OUTPUT: *
* position of item in the list *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 04/19/1995 BRR : Created. *
*=========================================================================*/
int ColorListClass::Add_Item(int text, RemapControlType * color)
{
Colors.Add(color);
return(ListClass::Add_Item(text));
}
/***************************************************************************
* ColorListClass::Remove_Item -- Removes an item from the list *
* *
* INPUT: *
* text ptr to item to remove *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* *
* HISTORY: *
* 04/19/1995 BRR : Created. *
*=========================================================================*/
void ColorListClass::Remove_Item(char const * text)
{
int index = List.ID(text);
if (index != -1) {
Colors.Delete(index);
ListClass::Remove_Item(text);
}
}
/***************************************************************************
* ColorListClass::Set_Selected_Style -- tells how to draw selected item *
* *
* INPUT: *
* style style to draw *
* color color to draw the special style in; -1 = use item's color *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 04/19/1995 BRR : Created. *
*=========================================================================*/
void ColorListClass::Set_Selected_Style(SelectStyleType style, RemapControlType * color)
{
Style = style;
SelectColor = color;
}
/***************************************************************************
* ColorListClass::Draw_Entry -- Draws one text line *
* *
* INPUT: *
* index index into List of item to draw *
* x,y x,y coords to draw at *
* width maximum width allowed for text *
* selected true = this item is selected *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 04/19/1995 BRR : Created. *
*=========================================================================*/
void ColorListClass::Draw_Entry(int index, int x, int y, int width, int selected)
{
RemapControlType * color;
/*
** Draw a non-selected item in its color
*/
if (!selected) {
Conquer_Clip_Text_Print(List[index], x, y, Colors[index], TBLACK, TextFlags, width, Tabs);
return;
}
/*
** For selected items, choose the right color & style:
*/
if (SelectColor == NULL) {
color = Colors[index];
} else {
color = SelectColor;
}
switch (Style) {
/*
** NONE: Just print the string in its native color
*/
case SELECT_NORMAL:
Conquer_Clip_Text_Print(List[index], x, y, Colors[index], TBLACK,
TextFlags, width, Tabs);
break;
/*
** HIGHLIGHT: Draw the string in the highlight color (SelectColor must
** be set)
*/
case SELECT_HIGHLIGHT:
if (TextFlags & TPF_6PT_GRAD) {
Conquer_Clip_Text_Print(List[index], x, y, color, TBLACK, TextFlags | TPF_BRIGHT_COLOR, width, Tabs);
} else {
Conquer_Clip_Text_Print(List[index], x, y, color, TBLACK, TextFlags, width, Tabs);
}
break;
/*
** BOX: Draw a box around the item in the current select color
*/
case SELECT_BOX:
LogicPage->Draw_Rect (x, y, x + width - 2, y + LineHeight - 2, color->Color);
Conquer_Clip_Text_Print(List[index], x, y, Colors[index], TBLACK, TextFlags, width, Tabs);
break;
/*
** BAR: draw a color bar under the text
*/
case SELECT_BAR:
if (TextFlags & TPF_6PT_GRAD) {
LogicPage->Fill_Rect(x, y, x + width - 1, y + LineHeight - 1, color->Color);
Conquer_Clip_Text_Print(List[index], x, y, Colors[index], TBLACK, TextFlags | TPF_BRIGHT_COLOR, width, Tabs);
} else {
LogicPage->Fill_Rect(x, y, x + width - 2, y + LineHeight - 2, color->Color);
Conquer_Clip_Text_Print(List[index], x, y, Colors[index], TBLACK, TextFlags, width, Tabs);
}
break;
/*
** INVERT: Draw text as the background color on foreground color
*/
case SELECT_INVERT:
LogicPage->Fill_Rect (x, y, x + width - 1, y + LineHeight - 1, Colors[index]->Color);
break;
}
}

87
CODE/COLRLIST.H Normal file
View file

@ -0,0 +1,87 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/COLRLIST.H 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : COLRLIST.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 01/15/95 *
* *
* Last Update : January 15, 1995 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef COLORLIST_H
#define COLORLIST_H
#include "list.h"
/***************************************************************************
** This class adds the ability for every list item to have a different color.
*/
class ColorListClass : public ListClass
{
public:
/*********************************************************************
** These enums are the ways a selected item can be drawn
*/
//lint -esym(578,SELECT_NONE)
typedef enum SelectEnum {
SELECT_NORMAL, // selected items aren't drawn differently
SELECT_HIGHLIGHT, // item is highlighted
SELECT_BOX, // draw a box around the item
SELECT_BAR, // draw a bar behind the item
SELECT_INVERT // draw the string inverted
} SelectStyleType;
ColorListClass(int id, int x, int y, int w, int h, TextPrintType flags, void const * up, void const * down);
virtual ~ColorListClass(void);
virtual int Add_Item(char const * text, RemapControlType * color = NULL);
virtual int Add_Item(int text, RemapControlType * color = NULL);
virtual void Remove_Item(char const * text);
virtual void Set_Selected_Style(SelectStyleType style, RemapControlType * color = NULL);
/*
** This is the list of colors for each item.
*/
DynamicVectorClass<RemapControlType *> Colors;
protected:
virtual void Draw_Entry(int index, int x, int y, int width, int selected);
/*
** This tells how to draw the selected item.
*/
SelectStyleType Style;
RemapControlType * SelectColor;
};
#endif

425
CODE/COMBAT.CPP Normal file
View file

@ -0,0 +1,425 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/COMBAT.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : COMBAT.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : September 19, 1994 *
* *
* Last Update : July 26, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* Combat_Anim -- Determines explosion animation to play. *
* Explosion_Damage -- Inflict an explosion damage affect. *
* Modify_Damage -- Adjusts damage to reflect the nature of the target. *
* Wide_Area_Damage -- Apply wide area damage to the map. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
/***********************************************************************************************
* Modify_Damage -- Adjusts damage to reflect the nature of the target. *
* *
* This routine is the core of combat tactics. It implements the *
* affect various armor types have against various weapon types. By *
* careful exploitation of this table, tactical advantage can be *
* obtained. *
* *
* INPUT: damage -- The damage points to process. *
* *
* warhead -- The source of the damage points. *
* *
* armor -- The type of armor defending against the damage. *
* *
* distance -- The distance (in leptons) from the source of the damage. *
* *
* OUTPUT: Returns with the adjusted damage points to inflict upon the *
* target. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 04/16/1994 JLB : Created. *
* 04/17/1994 JLB : Always does a minimum of damage. *
* 01/01/1995 JLB : Takes into account distance from damage source. *
* 04/11/1996 JLB : Changed damage fall-off formula for less damage fall-off. *
*=============================================================================================*/
int Modify_Damage(int damage, WarheadType warhead, ArmorType armor, int distance)
{
if (!damage) return(damage);
/*
** If there is no raw damage value to start with, then
** there can be no modified damage either.
*/
if (Special.IsInert || !damage || warhead == WARHEAD_NONE) return(0);
/*
** Negative damage (i.e., heal) is always applied full strength, but only if the heal
** effect is close enough.
*/
if (damage < 0) {
#ifdef FIXIT_CSII // checked - ajw 9/28/98
if (distance < 0x008) {
if(warhead != WARHEAD_MECHANICAL && armor == ARMOR_NONE) return(damage);
if(warhead == WARHEAD_MECHANICAL && armor != ARMOR_NONE) return(damage);
}
#else
if (distance < 0x008 && armor == ARMOR_NONE) return(damage);
#endif
return(0);
}
WarheadTypeClass const * whead = WarheadTypeClass::As_Pointer(warhead);
// WarheadTypeClass const * whead = &Warheads[warhead];
damage = damage * whead->Modifier[armor];
/*
** Reduce damage according to the distance from the impact point.
*/
if (damage) {
if (!whead->SpreadFactor) {
distance /= PIXEL_LEPTON_W/4;
} else {
distance /= whead->SpreadFactor * (PIXEL_LEPTON_W/2);
}
distance = Bound(distance, 0, 16);
if (distance) {
damage = damage / distance;
}
/*
** Allow damage to drop to zero only if the distance would have
** reduced damage to less than 1/4 full damage. Otherwise, ensure
** that at least one damage point is done.
*/
if (distance < 4) {
damage = max(damage, Rule.MinDamage);
}
}
damage = min(damage, Rule.MaxDamage);
return(damage);
}
/***********************************************************************************************
* Explosion_Damage -- Inflict an explosion damage affect. *
* *
* Processes the collateral damage affects typically caused by an *
* explosion. *
* *
* INPUT: coord -- The coordinate of ground zero. *
* *
* strength -- Raw damage points at ground zero. *
* *
* source -- Source of the explosion (who is responsible). *
* *
* warhead -- The kind of explosion to process. *
* *
* OUTPUT: none *
* *
* WARNINGS: This routine can consume some time and will affect the AI *
* of nearby enemy units (possibly). *
* *
* HISTORY: *
* 08/16/1991 JLB : Created. *
* 11/30/1991 JLB : Uses coordinate system. *
* 12/27/1991 JLB : Radius of explosion damage effect. *
* 04/13/1994 JLB : Streamlined. *
* 04/16/1994 JLB : Warhead damage type modifier. *
* 04/17/1994 JLB : Cleaned up. *
* 06/20/1994 JLB : Uses object pointers to distribute damage. *
* 06/20/1994 JLB : Source is a pointer. *
* 06/18/1996 JLB : Strength could be negative for healing effects. *
*=============================================================================================*/
void Explosion_Damage(COORDINATE coord, int strength, TechnoClass * source, WarheadType warhead)
{
CELL cell; // Cell number under explosion.
ObjectClass * object; // Working object pointer.
ObjectClass * objects[32]; // Maximum number of objects that can be damaged.
int distance; // Distance to unit.
int range; // Damage effect radius.
int count; // Number of vehicle IDs in list.
if (!strength || Special.IsInert || warhead == WARHEAD_NONE) return;
WarheadTypeClass const * whead = WarheadTypeClass::As_Pointer(warhead);
// WarheadTypeClass const * whead = &Warheads[warhead];
// range = ICON_LEPTON_W*2;
range = ICON_LEPTON_W + (ICON_LEPTON_W >> 1);
cell = Coord_Cell(coord);
if ((unsigned)cell >= MAP_CELL_TOTAL) return;
CellClass * cellptr = &Map[cell];
ObjectClass * impacto = cellptr->Cell_Occupier();
/*
** Fill the list of unit IDs that will have damage
** assessed upon them. The units can be lifted from
** the cell data directly.
*/
count = 0;
for (FacingType i = FACING_NONE; i < FACING_COUNT; i++) {
/*
** Fetch a pointer to the cell to examine. This is either
** an adjacent cell or the center cell. Damage never spills
** further than one cell away.
*/
if (i != FACING_NONE) {
cellptr = &Map[cell].Adjacent_Cell(i);
}
/*
** Add all objects in this cell to the list of objects to possibly apply
** damage to. The list stops building when the object pointer list becomes
** full. Do not include overlapping objects; selection state can affect
** the overlappers, and this causes multiplayer games to go out of sync.
*/
object = cellptr->Cell_Occupier();
while (object) {
if (!object->IsToDamage && object != source) {
object->IsToDamage = true;
objects[count++] = object;
if (count >= ARRAY_SIZE(objects)) break;
}
object = object->Next;
}
if (count >= ARRAY_SIZE(objects)) break;
}
/*
** Sweep through the units to be damaged and damage them. When damaging
** buildings, consider a hit on any cell the building occupies as if it
** were a direct hit on the building's center.
*/
for (int index = 0; index < count; index++) {
object = objects[index];
object->IsToDamage = false;
if (object->IsActive) {
if (object->What_Am_I() == RTTI_BUILDING && impacto == object) {
distance = 0;
} else {
distance = Distance(coord, object->Center_Coord());
}
if (object->IsDown && !object->IsInLimbo && distance < range) {
int damage = strength;
object->Take_Damage(damage, distance, warhead, source);
}
}
}
/*
** If there is a wall present at this location, it may be destroyed. Check to
** make sure that the warhead is of the kind that can destroy walls.
*/
cellptr = &Map[cell];
if (cellptr->Overlay != OVERLAY_NONE) {
OverlayTypeClass const * optr = &OverlayTypeClass::As_Reference(cellptr->Overlay);
if (optr->IsTiberium && whead->IsTiberiumDestroyer) {
cellptr->Reduce_Tiberium(strength / 10);
}
if (optr->IsWall) {
if (whead->IsWallDestroyer || (whead->IsWoodDestroyer && optr->IsWooden)) {
Map[cell].Reduce_Wall(strength);
}
}
}
/*
** If there is a bridge at this location, then it may be destroyed by the
** combat damage.
*/
if (cellptr->TType == TEMPLATE_BRIDGE1 || cellptr->TType == TEMPLATE_BRIDGE2 ||
cellptr->TType == TEMPLATE_BRIDGE1H || cellptr->TType == TEMPLATE_BRIDGE2H ||
cellptr->TType == TEMPLATE_BRIDGE_1A || cellptr->TType == TEMPLATE_BRIDGE_1B ||
cellptr->TType == TEMPLATE_BRIDGE_2A || cellptr->TType == TEMPLATE_BRIDGE_2B ||
cellptr->TType == TEMPLATE_BRIDGE_3A || cellptr->TType == TEMPLATE_BRIDGE_3B ) {
if (((warhead == WARHEAD_AP || warhead == WARHEAD_HE) && Random_Pick(1, Rule.BridgeStrength) < strength)) {
Map.Destroy_Bridge_At(cell);
}
}
}
/***********************************************************************************************
* Combat_Anim -- Determines explosion animation to play. *
* *
* This routine is called when a projectile impacts. This routine will determine what *
* animation should be played. *
* *
* INPUT: damage -- The amount of damage this warhead possess (warhead size). *
* *
* warhead -- The type of warhead. *
* *
* land -- The land type that this explosion is over. Sometimes, this makes *
* a difference (especially over water). *
* *
* OUTPUT: Returns with the animation to play. If no animation is to be played, then *
* ANIM_NONE is returned. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/19/1996 JLB : Created. *
*=============================================================================================*/
AnimType Combat_Anim(int damage, WarheadType warhead, LandType land)
{
/*
** For cases of no damage or invalid warhead, don't have any
** animation effect at all.
*/
if (damage == 0 || warhead == WARHEAD_NONE) {
return(ANIM_NONE);
}
static AnimType _aplist[] = {
ANIM_VEH_HIT3, // Small fragment throwing explosion -- burn/exp mix.
ANIM_VEH_HIT2, // Small fragment throwing explosion -- pop & sparkles.
ANIM_FRAG1, // Medium fragment throwing explosion -- short decay.
ANIM_FBALL1, // Large fireball explosion (bulges rightward).
};
static AnimType _helist[] = {
ANIM_VEH_HIT1, // Small fireball explosion (bulges rightward).
ANIM_VEH_HIT2, // Small fragment throwing explosion -- pop & sparkles.
ANIM_ART_EXP1, // Large fragment throwing explosion -- many sparkles.
ANIM_FBALL1, // Large fireball explosion (bulges rightward).
};
static AnimType _firelist[] = {
ANIM_NAPALM1, // Small napalm burn.
ANIM_NAPALM2, // Medium napalm burn.
ANIM_NAPALM3, // Large napalm burn.
};
static AnimType _waterlist[] = {
ANIM_WATER_EXP3,
ANIM_WATER_EXP2,
ANIM_WATER_EXP1,
};
WarheadTypeClass const * wptr = WarheadTypeClass::As_Pointer(warhead);
// WarheadTypeClass const * wptr = &Warheads[warhead];
switch (wptr->ExplosionSet) {
case 6:
return(ANIM_ATOM_BLAST);
case 2:
if (damage > 15) {
return(ANIM_PIFFPIFF);
}
return(ANIM_PIFF);
case 4:
if (land == LAND_NONE) return(ANIM_FLAK);
// Fixed math error
if (land == LAND_WATER) return(_waterlist[(ARRAY_SIZE(_waterlist)-1) * fixed(min(damage, 90), 90)]);
return(_aplist[(ARRAY_SIZE(_aplist)-1) * fixed(min(damage, 90), 90)]);
case 5:
if (land == LAND_NONE) return(ANIM_FLAK);
if (land == LAND_WATER) return(_waterlist[(ARRAY_SIZE(_waterlist)-1) * fixed(min(damage, 130), 130)]);
return(_helist[(ARRAY_SIZE(_helist)-1) * fixed(min(damage, 130), 130)]);
case 3:
if (land == LAND_NONE) return(ANIM_FLAK);
if (land == LAND_WATER) return(_waterlist[(ARRAY_SIZE(_waterlist)-1) * fixed(min(damage, 150), 150)]);
return(_firelist[(ARRAY_SIZE(_firelist)-1) * fixed(min(damage, 150), 150)]);
case 1:
return(ANIM_PIFF);
default:
break;
}
return(ANIM_NONE);
}
/***********************************************************************************************
* Wide_Area_Damage -- Apply wide area damage to the map. *
* *
* This routine will apply damage to a very wide area on the map. The damage will be *
* spread out from the coordinate specified by the radius specified. The amount of damage *
* will attenuate according to the distance from center. *
* *
* INPUT: coord -- The coordinate that the explosion damage will center about. *
* *
* radius -- The radius of the explosion. *
* *
* damage -- The amount of damage to apply at the center location. *
* *
* source -- Pointer to the purpetrator of the damage (if any). *
* *
* warhead -- The type of warhead that is causing the damage. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/26/1996 JLB : Created. *
*=============================================================================================*/
void Wide_Area_Damage(COORDINATE coord, LEPTON radius, int rawdamage, TechnoClass * source, WarheadType warhead)
{
int cell_radius = (radius + CELL_LEPTON_W-1) / CELL_LEPTON_W;
CELL cell = Coord_Cell(coord);
for (int x = -cell_radius; x <= cell_radius; x++) {
for (int y = -cell_radius; y <= cell_radius; y++) {
int xpos = Cell_X(cell) + x;
int ypos = Cell_Y(cell) + y;
/*
** If the potential damage cell is outside of the map bounds,
** then don't process it. This unusual check method ensures that
** damage won't wrap from one side of the map to the other.
*/
if ((unsigned)xpos > MAP_CELL_W) {
continue;
}
if ((unsigned)ypos > MAP_CELL_H) {
continue;
}
CELL tcell = XY_Cell(xpos, ypos);
if (!Map.In_Radar(tcell)) continue;
int dist_from_center = Distance(XY_Coord(x+cell_radius, y+cell_radius), XY_Coord(cell_radius, cell_radius));
int damage = rawdamage * Inverse(fixed(cell_radius, dist_from_center));
Explosion_Damage(Cell_Coord(tcell), damage, source, warhead);
if (warhead == WARHEAD_FIRE && damage > 100) {
new SmudgeClass(Random_Pick(SMUDGE_SCORCH1, SMUDGE_SCORCH6), Cell_Coord(tcell));
}
}
}
}

1164
CODE/COMBUF.CPP Normal file

File diff suppressed because it is too large Load diff

193
CODE/COMBUF.H Normal file
View file

@ -0,0 +1,193 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/COMBUF.H 1 3/03/97 10:24a Joe_bostic $ */
/***************************************************************************
** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S **
***************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : COMBUF.H *
* *
* Programmer : Bill Randolph *
* *
* Start Date : December 19, 1994 *
* *
* Last Update : April 1, 1995 [BR] *
* *
*-------------------------------------------------------------------------*
* *
* This class's job is to store outgoing messages & incoming messages, *
* and serves as a storage area for various flags for ACK & Retry logic. *
* *
* This class stores buffers in a non-sequenced order; it allows freeing *
* any entry, so the buffers can be kept clear, even if packets come in *
* out of order. *
* *
* The class also contains routines to maintain a cumulative response time *
* for this queue. It's up to the caller to call Add_Delay() whenever *
* it detects that an outgoing message has been ACK'd; this class adds *
* that delay into a computed average delay over the last few message *
* delays. *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef COMBUF_H
#define COMBUF_H
/*
********************************** Defines **********************************
*/
/*---------------------------------------------------------------------------
This is one output queue entry
---------------------------------------------------------------------------*/
typedef struct {
unsigned int IsActive : 1; // 1 = this entry is ready to be processed
unsigned int IsACK : 1; // 1 = ACK received for this packet
unsigned long FirstTime; // time this packet was first sent
unsigned long LastTime; // time this packet was last sent
unsigned long SendCount; // # of times this packet has been sent
int BufLen; // size of the packet stored in this entry
char *Buffer; // the data packet
int ExtraLen; // size of extra data
char *ExtraBuffer; // extra data buffer
} SendQueueType;
/*---------------------------------------------------------------------------
This is one input queue entry
---------------------------------------------------------------------------*/
typedef struct {
unsigned int IsActive : 1; // 1 = this entry is ready to be processed
unsigned int IsRead : 1; // 1 = caller has read this entry
unsigned int IsACK : 1; // 1 = ACK sent for this packet
int BufLen; // size of the packet stored in this entry
char *Buffer; // the data packet
int ExtraLen; // size of extra data
char *ExtraBuffer; // extra data buffer
} ReceiveQueueType;
/*
***************************** Class Declaration *****************************
*/
class CommBufferClass
{
/*
---------------------------- Public Interface ----------------------------
*/
public:
/*
....................... Constructor/Destructor ........................
*/
CommBufferClass(int numsend, int numrecieve, int maxlen,
int extralen = 0);
virtual ~CommBufferClass();
void Init(void);
void Init_Send_Queue(void);
/*
......................... Send Queue routines .........................
*/
int Queue_Send(void *buf, int buflen, void *extrabuf = NULL,
int extralen = 0);
int UnQueue_Send(void *buf, int *buflen, int index,
void *extrabuf = NULL, int *extralen = NULL);
int Num_Send(void) {return (SendCount);} // # entries in queue
int Max_Send(void) { return (MaxSend);} // max # send queue entries
SendQueueType * Get_Send(int index); // random access to queue
unsigned long Send_Total(void) {return (SendTotal);}
/*
....................... Receive Queue routines ........................
*/
int Queue_Receive(void *buf, int buflen, void *extrabuf = NULL,
int extralen = 0);
int UnQueue_Receive(void *buf, int *buflen, int index,
void *extrabuf = NULL, int *extralen = NULL);
int Num_Receive(void) {return (ReceiveCount);} // # entries in queue
int Max_Receive(void) { return (MaxReceive); } // max # recv queue entries
ReceiveQueueType * Get_Receive(int index); // random access to queue
unsigned long Receive_Total(void) {return (ReceiveTotal);}
/*
....................... Response time routines ........................
*/
void Add_Delay(unsigned long delay); // accumulates response time
unsigned long Avg_Response_Time(void); // gets mean response time
unsigned long Max_Response_Time(void); // gets max response time
void Reset_Response_Time(void); // resets computations
/*
........................ Debug output routines ........................
*/
void Configure_Debug(int type_offset, int type_size, char **names,
int namestart, int namecount);
void Mono_Debug_Print(int refresh = 0);
void Mono_Debug_Print2(int refresh = 0);
/*
--------------------------- Private Interface ----------------------------
*/
private:
/*
.......................... Limiting variables .........................
*/
int MaxSend; // max # send queue entries
int MaxReceive; // max # receive queue entries
int MaxPacketSize; // max size of a packet, in bytes
int MaxExtraSize; // max size of extra bytes
/*
....................... Response time variables .......................
*/
unsigned long DelaySum; // sum of last 4 delay times
unsigned long NumDelay; // current # delay times summed
unsigned long MeanDelay; // current average delay time
unsigned long MaxDelay; // max delay ever for this queue
/*
........................ Send Queue variables .........................
*/
SendQueueType * SendQueue; // incoming packets
int SendCount; // # packets in the queue
unsigned long SendTotal; // total # added to send queue
int *SendIndex; // array of Send entry indices
/*
....................... Receive Queue variables .......................
*/
ReceiveQueueType * ReceiveQueue; // outgoing packets
int ReceiveCount; // # packets in the queue
unsigned long ReceiveTotal; // total # added to receive queue
int *ReceiveIndex; // array of Receive entry indices
/*
......................... Debugging Variables .........................
*/
int DebugOffset; // offset into app's packet for ID
int DebugSize; // size of app's ID
char **DebugNames; // ptr to array of app-specific names
int DebugNameStart; // number of 1st ID
int DebugNameCount; // # of names in array
};
#endif
/**************************** end of combuf.h ******************************/

51
CODE/COMINIT.CPP Normal file
View file

@ -0,0 +1,51 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//
// If you link with this it will automatically call the COM initialization stuff
//
#include "cominit.h"
//#include <stdlib.h>
//#include <stdio.h>
//#include <windows.h>
#include <objbase.h>
//#include "externs.h"
//#include "text.rh"
//#include "WolDebug.h"
ComInit::ComInit()
{
//HRESULT hRes = CoInitialize(NULL);
// if (SUCCEEDED(hRes)==FALSE)
// exit(0);
HRESULT hRes = OleInitialize(NULL);
}
ComInit::~ComInit()
{
// CoUninitialize();
// debugprint( "pre OleUninitialize\n" );
OleUninitialize();
// debugprint( "post OleUninitialize\n" );
}
// Creating this instance will setup all COM stuff & do cleanup on program exit
ComInit Global_COM_Initializer;

34
CODE/COMINIT.H Normal file
View file

@ -0,0 +1,34 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef COMINIT_HEADER
#define COMINIT_HEADER
//
// Link with this to automatically initialize COM at startup
// - See cominit.cpp for more info
//
class ComInit
{
public:
ComInit();
~ComInit();
};
#endif

217
CODE/COMPAT.H Normal file
View file

@ -0,0 +1,217 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/COMPAT.H 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : COMPAT.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 03/02/95 *
* *
* Last Update : March 2, 1995 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef COMPAT_H
#define COMPAT_H
#define BuffType BufferClass
//#define movmem(a,b,c) memmove(b,a,c)
#define ShapeBufferSize _ShapeBufferSize
/*=========================================================================*/
/* Define some equates for the different graphic routines we will install */
/* later. */
/*=========================================================================*/
#define HIDBUFF ((void *)(0xA0000))
#define Size_Of_Region(a, b) ((a)*(b))
/*=========================================================================*/
/* Define some Graphic Routines which will only be fixed by these defines */
/*=========================================================================*/
#define Set_Font_Palette(a) Set_Font_Palette_Range(a, 0, 15)
/*
** These are the Open_File, Read_File, and Seek_File constants.
*/
#define READ 1 // Read access.
#define WRITE 2 // Write access.
#ifndef SEEK_SET
#define SEEK_SET 0 // Seek from start of file.
#define SEEK_CUR 1 // Seek relative from current location.
#define SEEK_END 2 // Seek from end of file.
#endif
#define ERROR_WINDOW 1
#define ErrorWindow 1
//extern unsigned char *Palette;
extern unsigned char MDisabled; // Is mouse disabled?
extern WORD Hard_Error_Occured;
/*
** This is the menu control structures.
*/
typedef enum MenuIndexType {
MENUX,
MENUY,
ITEMWIDTH,
ITEMSHIGH,
MSELECTED,
NORMCOL,
HILITE,
MENUPADDING=0x1000
} MenuIndexType;
#ifdef NEVER
#define BITSPERBYTE 8
#define MAXSHORT 0x7FFF
#define HIBITS 0x8000
#define MAXLONG 0x7FFFFFFFL
#define HIBITL 0x80000000
#define MAXINT MAXLONG
#define HIBITI HIBITL
#define DMAXEXP 308
#define FMAXEXP 38
#define DMINEXP -307
#define FMINEXP -37
#define MAXDOUBLE 1.797693E+308
#define MAXFLOAT 3.37E+38F
#define MINDOUBLE 2.225074E-308
#define MINFLOAT 8.43E-37F
#define DSIGNIF 53
#define FSIGNIF 24
#define DMAXPOWTWO 0x3FF
#define FMAXPOWTWO 0x7F
#define DEXPLEN 11
#define FEXPLEN 8
#define EXPBASE 2
#define IEEE 1
#define LENBASE 1
#define HIDDENBIT 1
#define LN_MAXDOUBLE 7.0978E+2
#define LN_MINDOUBLE -7.0840E+2
#endif
/* These defines handle the various names given to the same color. */
#define DKGREEN GREEN
#define DKBLUE BLUE
#define GRAY GREY
#define DKGREY GREY
#define DKGRAY GREY
#define LTGRAY LTGREY
class IconsetClass;
#ifndef WIN32
typedef struct {
short Width; // Width of icons (pixels).
short Height; // Height of icons (pixels).
short Count; // Number of (logical) icons in this set.
short Allocated; // Was this iconset allocated?
short MapWidth; // Width of map (in icons).
short MapHeight; // Height of map (in icons).
long Size; // Size of entire iconset memory block.
long Icons; // Offset from buffer start to icon data.
// unsigned char * Icons; // Offset from buffer start to icon data.
long Palettes; // Offset from buffer start to palette data.
long Remaps; // Offset from buffer start to remap index data.
long TransFlag; // Offset for transparency flag table.
long ColorMap; // Offset for color control value table.
long Map; // Icon map offset (if present).
// unsigned char * Map; // Icon map offset (if present).
} IControl_Type;
#endif
inline int Get_IconSet_MapWidth(void const * data)
{
if (data) {
return(((IControl_Type *)data)->MapWidth);
}
return(0);
}
inline int Get_IconSet_MapHeight(void const * data)
{
if (data) {
return(((IControl_Type *)data)->MapHeight);
}
return(0);
}
inline unsigned char const * Get_IconSet_ControlMap(void const * data)
{
if (data) {
return((unsigned char const *)((char *)data + ((IControl_Type *)data)->ColorMap));
}
return(0);
}
class IconsetClass : protected IControl_Type
{
public:
/*
** Query functions.
*/
int Map_Width(void) const {return(MapWidth);};
int Map_Height(void) const {return(MapHeight);};
unsigned char * Control_Map(void) {return((unsigned char *)this + ColorMap);};
unsigned char const * Control_Map(void) const {return((unsigned char const *)this + ColorMap);};
int Icon_Count(void) const {return(Count);};
int Pixel_Width(void) const {return(Width);};
int Pixel_Height(void) const {return(Height);};
int Total_Size(void) const {return(Size);};
unsigned char const * Palette_Data(void) const {return((unsigned char const *)this + Palettes);};
unsigned char * Palette_Data(void) {return((unsigned char *)this + Palettes);};
unsigned char const * Icon_Data(void) const {return((unsigned char const *)this + Icons);};
unsigned char * Icon_Data(void) {return((unsigned char *)this + Icons);};
unsigned char const * Map_Data(void) const {return((unsigned char const *)this + Map);};
unsigned char * Map_Data(void) {return((unsigned char *)this + Map);};
unsigned char const * Remap_Data(void) const {return((unsigned char const *)this + Remaps);};
unsigned char * Remap_Data(void) {return((unsigned char *)this + Remaps);};
unsigned char const * Trans_Data(void) const {return((unsigned char const *)this + TransFlag);};
unsigned char * Trans_Data(void) {return((unsigned char *)this + TransFlag);};
/*
** Disallow these operations with an IconsetClass object.
*/
private:
IconsetClass & operator = (IconsetClass const &);
IconsetClass(void);
static void * operator new(size_t);
};
#endif

1003
CODE/COMQUEUE.CPP Normal file

File diff suppressed because it is too large Load diff

193
CODE/COMQUEUE.H Normal file
View file

@ -0,0 +1,193 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: F:\projects\c&c0\vcs\code\comqueue.h_v 4.1 11 Apr 1996 18:26:02 JOE_BOSTIC $ */
/***************************************************************************
** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S **
***************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : COMQUEUE.H *
* *
* Programmer : Bill Randolph *
* *
* Start Date : December 19, 1994 *
* *
* Last Update : April 1, 1995 [BR] *
* *
*-------------------------------------------------------------------------*
* *
* This class's job is to queue up outgoing messages & incoming messages, *
* and serves as a storage area for various flags for ACK & Retry logic. *
* It allows the application to keep track of how many messages have *
* passed through this queue, in & out, so packets can use this as a *
* unique ID. (If packets have a unique ID, the application can use this *
* to detect re-sends.) *
* *
* The queues act as FIFO buffers (First-In, First-Out). The first entry *
* placed in a queue is the first one read from it, and so on. The *
* controlling application must ensure it places the entries on the queue *
* in the order it wants to access them. *
* *
* The queue is implemented as an array of Queue Entries. Index 0 is the *
* first element placed on the queue, and is the first retrieved. Index *
* 1 is the next, and so on. When Index 0 is retrieved, the next-available*
* entry becomes Index 1. The array is circular; when the end is reached, *
* the indices wrap around to the beginning. *
* *
* The class also contains routines to maintain a cumulative response time *
* for this queue. It's up to the caller to call Add_Delay() whenever *
* it detects that an outgoing message has been ACK'd; this class adds *
* that delay into a computed average delay over the last few message *
* delays. *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef COMQUEUE_H
#define COMQUEUE_H
/*---------------------------------------------------------------------------
This is one output queue entry
---------------------------------------------------------------------------*/
typedef struct {
unsigned int IsActive : 1; // 1 = this entry is ready to be processed
unsigned int IsACK : 1; // 1 = ACK received for this packet
unsigned long FirstTime; // time this packet was first sent
unsigned long LastTime; // time this packet was last sent
unsigned long SendCount; // # of times this packet has been sent
int BufLen; // size of the packet stored in this entry
char *Buffer; // the data packet
} SendQueueType;
/*---------------------------------------------------------------------------
This is one input queue entry
---------------------------------------------------------------------------*/
typedef struct {
unsigned int IsActive : 1; // 1 = this entry is ready to be processed
unsigned int IsRead : 1; // 1 = caller has read this entry
unsigned int IsACK : 1; // 1 = ACK sent for this packet
int BufLen; // size of the packet stored in this entry
char *Buffer; // the data packet
} ReceiveQueueType;
/*
***************************** Class Declaration *****************************
*/
class CommQueueClass
{
/*
---------------------------- Public Interface ----------------------------
*/
public:
/*
....................... Constructor/Destructor ........................
*/
CommQueueClass(int numsend, int numrecieve, int maxlen);
virtual ~CommQueueClass();
void Init(void);
/*
......................... Send Queue routines .........................
*/
int Queue_Send(void *buf, int buflen); // add to Send queue
int UnQueue_Send(void *buf, int *buflen); // remove from Send queue
SendQueueType * Next_Send(void); // ptr to next avail entry
int Num_Send(void) {return (SendCount);} // # entries in queue
int Max_Send(void) { return (MaxSend);} // max # send queue entries
SendQueueType * Get_Send(int index); // random access to queue
unsigned long Send_Total(void) {return (SendTotal);}
/*
....................... Receive Queue routines ........................
*/
int Queue_Receive(void *buf, int buflen); // add to Receive queue
int UnQueue_Receive(void *buf, int *buflen); // remove from Receive queue
ReceiveQueueType * Next_Receive(void); // ptr to next avail entry
int Num_Receive(void) {return (ReceiveCount);} // # entries in queue
int Max_Receive(void) { return (MaxReceive); } // max # recv queue entries
ReceiveQueueType * Get_Receive(int index); // random access to queue
unsigned long Receive_Total(void) {return (ReceiveTotal);}
/*
....................... Response time routines ........................
*/
void Add_Delay(unsigned long delay); // accumulates response time
unsigned long Avg_Response_Time(void); // gets mean response time
unsigned long Max_Response_Time(void); // gets max response time
void Reset_Response_Time(void); // resets computations
/*
........................ Debug output routines ........................
*/
void Configure_Debug(int offset, int size, char **names, int maxnames);
void Mono_Debug_Print(int refresh = 0);
void Mono_Debug_Print2(int refresh = 0);
/*
--------------------------- Private Interface ----------------------------
*/
private:
/*
.......................... Limiting variables .........................
*/
int MaxSend; // max # send queue entries
int MaxReceive; // max # receive queue entries
int MaxPacketSize; // max size of a packet, in bytes
/*
....................... Response time variables .......................
*/
unsigned long DelaySum; // sum of last 4 delay times
unsigned long NumDelay; // current # delay times summed
unsigned long MeanDelay; // current average delay time
unsigned long MaxDelay; // max delay ever for this queue
/*
........................ Send Queue variables .........................
*/
SendQueueType * SendQueue; // incoming packets
int SendCount; // # packets in the queue
int SendNext; // next entry read from queue
int SendEmpty; // next empty spot in queue
unsigned long SendTotal; // total # added to send queue
/*
....................... Receive Queue variables .......................
*/
ReceiveQueueType * ReceiveQueue; // outgoing packets
int ReceiveCount; // # packets in the queue
int ReceiveNext; // next entry read from queue
int ReceiveEmpty; // next empty spot in queue
unsigned long ReceiveTotal; // total # added to receive queue
/*
......................... Debugging Variables .........................
*/
int DebugOffset; // offset into app's packet for ID
int DebugSize; // size of app's ID
char **DebugNames; // ptr to array of app-specific names
int DebugMaxNames; // max # of names in array
};
#endif
/*************************** end of comqueue.h *****************************/

244
CODE/CONFDLG.CPP Normal file
View file

@ -0,0 +1,244 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: F:\projects\c&c0\vcs\code\confdlg.cpv 4.67 27 Aug 1996 15:46:52 JOE_BOSTIC $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : CONFDLG.CPP *
* *
* Programmer : Maria del Mar McCready Legg *
* Joe L. Bostic *
* *
* Start Date : Jan 30, 1995 *
* *
* Last Update : Jan 30, 1995 [MML] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* ConfirmationClass::Process -- Handles all the options graphic interface. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
#include "confdlg.h"
bool ConfirmationClass::Process(int text)
{
return(Process(Text_String(text)));
}
/***********************************************************************************************
* ConfirmationClass::Process -- Handles all the options graphic interface. *
* *
* This dialog uses an edit box to confirm a deletion. *
* *
* INPUT: char * string - display in edit box. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: 12/31/1994 MML : Created. *
*=============================================================================================*/
bool ConfirmationClass::Process(char const * string)
{
enum {
NUM_OF_BUTTONS = 2
};
char buffer[80*3];
int result = true;
int width;
int bwidth, bheight; // button width and height
int height;
int selection = 0;
bool pressed;
int curbutton;
TextButtonClass * buttons[NUM_OF_BUTTONS];
/*
** Set up the window. Window x-coords are in bytes not pixels.
*/
strcpy(buffer, string);
Fancy_Text_Print(TXT_NONE, 0, 0, TBLACK, TBLACK, TPF_6PT_GRAD | TPF_NOSHADOW);
Format_Window_String(buffer, 200, width, height);
width += 60;
height += 60;
int x = (320 - width) / 2;
int y = (200 - height) / 2;
Set_Logic_Page(SeenBuff);
/*
** Create Buttons. Button coords are in pixels, but are window-relative.
*/
bheight = FontHeight + FontYSpacing + 2;
bwidth = max( (String_Pixel_Width( Text_String( TXT_YES ) ) + 8), 30);
TextButtonClass yesbtn(BUTTON_YES, TXT_YES,
TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
x + 10, y + height - (bheight + 5), bwidth );
TextButtonClass nobtn(BUTTON_NO, TXT_NO,
TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
x + width - (bwidth + 10),
y + height - (bheight + 5), bwidth );
nobtn.Add_Tail(yesbtn);
curbutton = 1;
buttons[0] = &yesbtn;
buttons[1] = &nobtn;
buttons[curbutton]->Turn_On();
/*
** This causes left mouse button clicking within the confines of the dialog to
** be ignored if it wasn't recognized by any other button or slider.
*/
GadgetClass dialog(x, y, width, height, GadgetClass::LEFTPRESS);
dialog.Add_Tail(yesbtn);
/*
** This causes a right click anywhere or a left click outside the dialog region
** to be equivalent to clicking on the return to options dialog.
*/
ControlClass background(BUTTON_NO, 0, 0, 320, 200, GadgetClass::LEFTPRESS|GadgetClass::RIGHTPRESS);
background.Add_Tail(yesbtn);
/*
** Main Processing Loop.
*/
bool display = true;
bool process = true;
pressed = false;
while (process) {
/*
** Invoke game callback.
*/
if (Session.Type == GAME_NORMAL) {
Call_Back();
} else {
if (Main_Loop()) {
process = false;
result = false;
}
}
/*
** Refresh display if needed.
*/
if (display) {
Hide_Mouse();
/*
** Draw the background.
*/
Dialog_Box(x, y, width, height);
Draw_Caption(TXT_CONFIRMATION, x, y, width);
Fancy_Text_Print(buffer, x+20, y+30, GadgetClass::Get_Color_Scheme(), TBLACK, TPF_6PT_GRAD|TPF_USE_GRAD_PAL|TPF_NOSHADOW);
/*
** Draw the titles.
*/
yesbtn.Draw_All();
Show_Mouse();
display = false;
}
/*
** Get user input.
*/
KeyNumType input = yesbtn.Input();
/*
** Process Input.
*/
switch (input) {
case KeyNumType(BUTTON_YES | KN_BUTTON):
selection = BUTTON_YES;
pressed = true;
break;
case (KN_ESC):
case KeyNumType(BUTTON_NO | KN_BUTTON):
selection = BUTTON_NO;
pressed = true;
break;
case (KN_LEFT):
buttons[curbutton]->Turn_Off();
buttons[curbutton]->Flag_To_Redraw();
curbutton--;
if (curbutton < 0) {
curbutton = NUM_OF_BUTTONS - 1;
}
buttons[curbutton]->Turn_On();
buttons[curbutton]->Flag_To_Redraw();
break;
case (KN_RIGHT):
buttons[curbutton]->Turn_Off();
buttons[curbutton]->Flag_To_Redraw();
curbutton++;
if (curbutton > (NUM_OF_BUTTONS - 1) ) {
curbutton = 0;
}
buttons[curbutton]->Turn_On();
buttons[curbutton]->Flag_To_Redraw();
break;
case (KN_RETURN):
selection = curbutton + BUTTON_YES;
pressed = true;
break;
default:
break;
}
if (pressed) {
switch (selection) {
case (BUTTON_YES):
result = true;
process = false;
break;
case (BUTTON_NO):
result = false;
process = false;
break;
default:
break;
}
pressed = false;
}
}
return(result);
}

56
CODE/CONFDLG.H Normal file
View file

@ -0,0 +1,56 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: F:\projects\c&c0\vcs\code\confdlg.h_v 4.69 27 Aug 1996 15:43:36 JOE_BOSTIC $ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : CONFDLG.H *
* *
* Programmer : Maria del Mar McCready Legg *
* Joe L. Bostic *
* *
* Start Date : Jan 30, 1995 *
* *
* Last Update : Jan 30, 1995 [MML] *
* *
*---------------------------------------------------------------------------------------------*/
#ifndef CONFDLG_H
#define CONFDLG_H
#include "gadget.h"
class ConfirmationClass
{
private:
enum ConfirmationClassEnum {
BUTTON_YES=1, // Button number for "Options menu"
BUTTON_NO // Button number for "Options menu"
};
public:
ConfirmationClass(void) { };
bool Process(char const * string);
bool Process(int text);
};
#endif

838
CODE/CONNECT.CPP Normal file
View file

@ -0,0 +1,838 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/CONNECT.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***************************************************************************
** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S **
***************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : CONNECT.CPP *
* *
* Programmer : Bill Randolph *
* *
* Start Date : December 20, 1994 *
* *
* Last Update : May 31, 1995 [BRR] *
*-------------------------------------------------------------------------*
* Functions: *
* ConnectionClass::ConnectionClass -- class constructor *
* ConnectionClass::~ConnectionClass -- class destructor *
* ConnectionClass::Init -- Initializes connection queue to empty *
* ConnectionClass::Send_Packet -- adds a packet to the send queue *
* ConnectionClass::Receive_Packet -- adds packet to receive queue *
* ConnectionClass::Get_Packet -- gets a packet from receive queue *
* ConnectionClass::Service -- main polling routine; services packets *
* ConnectionClass::Service_Send_Queue -- services the send queue *
* ConnectionClass::Service_Receive_Queue -- services receive queue *
* ConnectionClass::Time -- gets current time *
* ConnectionClass::Command_Name -- returns name for a packet command *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
#include <stdio.h>
#include <mem.h>
#include <sys\timeb.h>
#include "connect.h"
#include "WolDebug.h"
/*
********************************* Globals ***********************************
*/
static char *ConnectionClass::Commands[PACKET_COUNT] = {
"ADATA",
"NDATA",
"ACK"
};
/***************************************************************************
* ConnectionClass::ConnectionClass -- class constructor *
* *
* INPUT: *
* numsend desired # of entries for the send queue *
* numreceive desired # of entries for the receive queue *
* maxlen max length of an application packet *
* magicnum the packet "magic number" for this connection *
* retry_delta the time to wait between sends *
* max_retries the max # of retries allowed for a packet *
* (-1 means retry forever, based on this parameter) *
* timeout the max amount of time before we give up on a packet *
* (-1 means retry forever, based on this parameter) *
* extralen max size of app-specific extra bytes (optional) *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/20/1994 BR : Created. *
*=========================================================================*/
ConnectionClass::ConnectionClass (int numsend, int numreceive,
int maxlen, unsigned short magicnum, unsigned long retry_delta,
unsigned long max_retries, unsigned long timeout, int extralen)
{
/*------------------------------------------------------------------------
Compute our maximum packet length
------------------------------------------------------------------------*/
MaxPacketLen = maxlen + sizeof(CommHeaderType);
/*------------------------------------------------------------------------
Assign the magic number
------------------------------------------------------------------------*/
MagicNum = magicnum;
/*------------------------------------------------------------------------
Initialize the retry time. This is the time that t2 - t1 must be greater
than before a retry will occur.
------------------------------------------------------------------------*/
RetryDelta = retry_delta;
/*------------------------------------------------------------------------
Set the maximum allowable retries.
------------------------------------------------------------------------*/
MaxRetries = max_retries;
/*------------------------------------------------------------------------
Set the timeout for this connection.
------------------------------------------------------------------------*/
Timeout = timeout;
/*------------------------------------------------------------------------
Allocate the packet staging buffer. This will be used to
------------------------------------------------------------------------*/
PacketBuf = new char[ MaxPacketLen ];
/*------------------------------------------------------------------------
Allocate the packet Queue. This will store incoming packets (placed there
by Receive_Packet), and outgoing packets (placed there by Send_Packet).
It can optionally store "extra" bytes, which are stored along with each
packet, but aren't transmitted as part of the packet. If 'extralen'
is 0, the CommBufferClass ignores this parameter.
------------------------------------------------------------------------*/
Queue = new CommBufferClass (numsend, numreceive, MaxPacketLen, extralen);
} /* end of ConnectionClass */
/***************************************************************************
* ConnectionClass::~ConnectionClass -- class destructor *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/20/1994 BR : Created. *
*=========================================================================*/
ConnectionClass::~ConnectionClass ()
{
/*------------------------------------------------------------------------
Free memory.
------------------------------------------------------------------------*/
delete [] PacketBuf;
delete Queue;
} /* end of ~ConnectionClass */
/***************************************************************************
* ConnectionClass::Init -- Initializes connection queue to empty *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/20/1994 BR : Created. *
*=========================================================================*/
void ConnectionClass::Init (void)
{
NumRecNoAck = 0;
NumRecAck = 0;
NumSendNoAck = 0;
NumSendAck = 0;
LastSeqID = 0xffffffff;
LastReadID = 0xffffffff;
Queue->Init();
} /* end of Init */
/***************************************************************************
* ConnectionClass::Send_Packet -- adds a packet to the send queue *
* *
* This routine prefixes the given buffer with a CommHeaderType and *
* queues the resulting packet into the Send Queue. (It's actually the *
* Service() routine that handles the hardware-dependent Send of the data).*
* The packet's MagicNumber, Code, and PacketID are set here. *
* *
* INPUT: *
* buf buffer to send *
* buflen length of buffer *
* ack_req 1 = ACK is required for this packet; 0 = isn't *
* *
* OUTPUT: *
* 1 = packet was queue'd OK, 0 = wasn't *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/20/1994 BR : Created. *
*=========================================================================*/
int ConnectionClass::Send_Packet (void * buf, int buflen, int ack_req)
{
/*------------------------------------------------------------------------
Set the magic # for the packet
------------------------------------------------------------------------*/
((CommHeaderType *)PacketBuf)->MagicNumber = MagicNum;
/*------------------------------------------------------------------------
Set the packet Code: DATA_ACK if it requires an ACK, NOACK if it doesn't
Set the packet ID to the appropriate counter value.
------------------------------------------------------------------------*/
if (ack_req) {
((CommHeaderType *)PacketBuf)->Code = PACKET_DATA_ACK;
((CommHeaderType *)PacketBuf)->PacketID = NumSendAck;
}
else {
((CommHeaderType *)PacketBuf)->Code = PACKET_DATA_NOACK;
((CommHeaderType *)PacketBuf)->PacketID = NumSendNoAck;
}
/*------------------------------------------------------------------------
Now build the packet
------------------------------------------------------------------------*/
memcpy(PacketBuf + sizeof(CommHeaderType), buf, buflen);
/*------------------------------------------------------------------------
Add it to the queue; don't add any extra data with it.
------------------------------------------------------------------------*/
if (Queue->Queue_Send(PacketBuf,buflen + sizeof(CommHeaderType), NULL, 0)) {
if (ack_req) {
NumSendAck++;
}
else {
NumSendNoAck++;
}
return(1);
}
else {
return(0);
}
} /* end of Send_Packet */
/***************************************************************************
* ConnectionClass::Receive_Packet -- adds packet to receive queue *
* *
* INPUT: *
* buf buffer to process (already includes CommHeaderType) *
* buflen length of buffer to process *
* *
* OUTPUT: *
* 1 = packet was processed OK, 0 = error *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/20/1994 BR : Created. *
*=========================================================================*/
int ConnectionClass::Receive_Packet (void * buf, int buflen)
{
CommHeaderType *packet; // ptr to packet header
SendQueueType *send_entry; // ptr to send entry header
ReceiveQueueType *rec_entry; // ptr to recv entry header
CommHeaderType *entry_data; // ptr to queue entry data
CommHeaderType ackpacket; // ACK packet to send
int i;
int save_packet = 1; // 0 = this is a resend
int found;
/*------------------------------------------------------------------------
Check the magic #
------------------------------------------------------------------------*/
packet = (CommHeaderType *)buf;
if (packet->MagicNumber != MagicNum) {
return(0);
}
/*------------------------------------------------------------------------
Handle an incoming ACK
------------------------------------------------------------------------*/
if (packet->Code == PACKET_ACK) {
for (i = 0; i < Queue->Num_Send(); i++) {
/*..................................................................
Get queue entry ptr
..................................................................*/
send_entry = Queue->Get_Send(i);
/*..................................................................
If ptr is valid, get ptr to its data
..................................................................*/
if (send_entry != NULL) {
entry_data = (CommHeaderType *)send_entry->Buffer;
/*...............................................................
If ACK is for this entry, mark it
...............................................................*/
if (packet->PacketID==entry_data->PacketID &&
entry_data->Code == PACKET_DATA_ACK) {
send_entry->IsACK = 1;
break;
}
}
}
return(1);
}
/*------------------------------------------------------------------------
Handle an incoming PACKET_DATA_NOACK packet
------------------------------------------------------------------------*/
else if (packet->Code == PACKET_DATA_NOACK) {
/*.....................................................................
If there's only one slot left, don't tie up the queue with this packet
.....................................................................*/
if (Queue->Max_Receive() - Queue->Num_Receive() <= 1) {
return(0);
}
/*.....................................................................
Error if we can't queue the packet
.....................................................................*/
if (!Queue->Queue_Receive (buf, buflen, NULL, 0)) {
return(0);
}
NumRecNoAck++;
return(1);
}
/*------------------------------------------------------------------------
Handle an incoming PACKET_DATA_ACK packet
------------------------------------------------------------------------*/
else if (packet->Code == PACKET_DATA_ACK) {
/*.....................................................................
If this is a packet requires an ACK, and it's ID is older than our
"oldest" ID, we know it's a resend; send an ACK, but don't queue it
.....................................................................*/
if (packet->PacketID <= LastSeqID && LastSeqID != 0xffffffff) {
save_packet = 0;
}
/*.....................................................................
Otherwise, scan the queue for this entry; if it's found, it's a
resend, so don't save it.
.....................................................................*/
else {
save_packet = 1;
for (i = 0; i < Queue->Num_Receive(); i++) {
rec_entry = Queue->Get_Receive(i);
if (rec_entry) {
entry_data = (CommHeaderType *)rec_entry->Buffer;
/*...........................................................
Packet is found; it's a resend
...........................................................*/
if (entry_data->Code == PACKET_DATA_ACK &&
entry_data->PacketID == packet->PacketID) {
save_packet = 0;
break;
}
}
}
} /* end of scan for resend */
/*.....................................................................
Queue the packet & update our LastSeqID value.
.....................................................................*/
if (save_packet) {
/*..................................................................
If there's only one slot left, make sure we only put a packet in it
if this packet will let us increment our LastSeqID; otherwise, we'll
get stuck, forever unable to increment LastSeqID.
..................................................................*/
if (Queue->Max_Receive() - Queue->Num_Receive() <= 1) {
if (packet->PacketID != (LastSeqID + 1) ) {
return(0);
}
}
/*..................................................................
If we can't queue the packet, return; don't send an ACK.
..................................................................*/
if (!Queue->Queue_Receive (buf, buflen, NULL, 0)) {
return(0);
}
NumRecAck++;
/*..................................................................
Update our LastSeqID value if we can. Anything less than LastSeqID
we'll know is a resend.
..................................................................*/
if (packet->PacketID == (LastSeqID + 1)) {
LastSeqID = packet->PacketID;
/*...............................................................
Now that we have a new 'LastSeqID', search our Queue to see if
the next ID is there; if so, keep checking for the next one;
break only when the next one isn't found. This forces
LastSeqID to be the largest possible value.
...............................................................*/
do {
found = 0;
for (i = 0; i < Queue->Num_Receive(); i++) {
rec_entry = Queue->Get_Receive(i);
if (rec_entry) {
entry_data = (CommHeaderType *)rec_entry->Buffer;
/*......................................................
Entry is found
......................................................*/
if (entry_data->Code == PACKET_DATA_ACK &&
entry_data->PacketID == (LastSeqID + 1)) {
LastSeqID = entry_data->PacketID;
found = 1;
break;
}
}
}
} while (found);
}
} /* end of save packet */
/*.....................................................................
Send an ACK, regardless of whether this was a resend or not.
.....................................................................*/
ackpacket.MagicNumber = Magic_Num();
ackpacket.Code = PACKET_ACK;
ackpacket.PacketID = packet->PacketID;
Send ((char *)&ackpacket, sizeof(CommHeaderType), NULL, 0);
return(1);
}
return(0);
} /* end of Receive_Packet */
/***************************************************************************
* ConnectionClass::Get_Packet -- gets a packet from receive queue *
* *
* INPUT: *
* buf location to store buffer *
* buflen filled in with length of 'buf' *
* *
* OUTPUT: *
* 1 = packet was read, 0 = wasn't *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/20/1994 BR : Created. *
*=========================================================================*/
int ConnectionClass::Get_Packet (void * buf, int *buflen)
{
ReceiveQueueType *rec_entry; // ptr to receive entry header
int packetlen; // size of received packet
CommHeaderType *entry_data;
int i;
/*------------------------------------------------------------------------
Ensure that we read the packets in order. LastReadID is the ID of the
last PACKET_DATA_ACK packet we read.
------------------------------------------------------------------------*/
for (i = 0; i < Queue->Num_Receive(); i++) {
rec_entry = Queue->Get_Receive(i);
/*.....................................................................
Only read this entry if it hasn't been yet
.....................................................................*/
if (rec_entry && rec_entry->IsRead==0) {
entry_data = (CommHeaderType *)rec_entry->Buffer;
/*..................................................................
If this is a DATA_ACK packet, its ID must be one greater than
the last one we read.
..................................................................*/
if ( (entry_data->Code == PACKET_DATA_ACK) &&
(entry_data->PacketID == (LastReadID + 1))) {
LastReadID = entry_data->PacketID;
rec_entry->IsRead = 1;
packetlen = rec_entry->BufLen - sizeof(CommHeaderType);
if (packetlen > 0) {
memcpy(buf, rec_entry->Buffer + sizeof(CommHeaderType),
packetlen);
}
(*buflen) = packetlen;
return(1);
}
/*..................................................................
If this is a DATA_NOACK packet, who cares what the ID is?
..................................................................*/
else if (entry_data->Code == PACKET_DATA_NOACK) {
rec_entry->IsRead = 1;
packetlen = rec_entry->BufLen - sizeof(CommHeaderType);
if (packetlen > 0) {
memcpy(buf, rec_entry->Buffer + sizeof(CommHeaderType),
packetlen);
}
(*buflen) = packetlen;
return(1);
}
}
}
return(0);
} /* end of Get_Packet */
/***************************************************************************
* ConnectionClass::Service -- main polling routine; services packets *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* 1 = OK, 0 = error (connection is broken!) *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/20/1994 BR : Created. *
*=========================================================================*/
int ConnectionClass::Service (void)
{
/*------------------------------------------------------------------------
Service the Send Queue: This [re]sends packets in the Send Queue which
haven't been ACK'd yet, and if their retry timeout has expired, and
updates the FirstTime, LastTime & SendCount values in the Queue entry.
Entries that have been ACK'd should be removed.
Service the Receive Queue: This sends ACKs for packets that haven't
been ACK'd yet. Entries that the app has read, and have been ACK'd,
should be removed.
------------------------------------------------------------------------*/
if ( Service_Send_Queue() && Service_Receive_Queue() ) {
return(1);
}
else {
return(0);
}
} /* end of Service */
/***************************************************************************
* ConnectionClass::Service_Send_Queue -- services the send queue *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* 1 = OK, 0 = error *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/20/1994 BR : Created. *
*=========================================================================*/
int ConnectionClass::Service_Send_Queue (void)
{
int i;
int num_entries;
SendQueueType *send_entry; // ptr to send queue entry
CommHeaderType *packet_hdr; // packet header
unsigned long curtime; // current time
int bad_conn = 0;
/*------------------------------------------------------------------------
Remove any ACK'd packets from the queue
------------------------------------------------------------------------*/
for (i = 0; i < Queue->Num_Send(); i++) {
/*.....................................................................
Get this queue entry
.....................................................................*/
send_entry = Queue->Get_Send(i);
/*.....................................................................
If ACK has been received, unqueue it
.....................................................................*/
if (send_entry->IsACK) {
/*..................................................................
Update this queue's response time
..................................................................*/
packet_hdr = (CommHeaderType *)send_entry->Buffer;
if (packet_hdr->Code == PACKET_DATA_ACK) {
Queue->Add_Delay(Time() - send_entry->FirstTime);
}
/*..................................................................
Unqueue the packet
..................................................................*/
Queue->UnQueue_Send(NULL,NULL,i,NULL,NULL);
i--;
}
}
/*------------------------------------------------------------------------
Loop through all entries in the Send queue. [Re]Send any entries that
need it.
------------------------------------------------------------------------*/
num_entries = Queue->Num_Send();
for (i = 0; i < num_entries; i++) {
send_entry = Queue->Get_Send(i);
if (send_entry->IsACK) {
continue;
}
/*.....................................................................
Only send the message if time has elapsed. (The message's Time
fields are init'd to 0 when a message is queue'd or unqueue'd, so the
first time through, the delta time will appear large.)
.....................................................................*/
curtime = Time();
if (curtime - send_entry->LastTime > RetryDelta) {
/*..................................................................
Send the message
..................................................................*/
Send (send_entry->Buffer, send_entry->BufLen, send_entry->ExtraBuffer,
send_entry->ExtraLen);
/*..................................................................
Fill in Time fields
..................................................................*/
send_entry->LastTime = curtime;
if (send_entry->SendCount==0) {
send_entry->FirstTime = curtime;
/*...............................................................
If this is the 1st time we're sending this packet, and it doesn't
require an ACK, mark it as ACK'd; then, the next time through,
it will just be removed from the queue.
...............................................................*/
packet_hdr = (CommHeaderType *)send_entry->Buffer;
if (packet_hdr->Code == PACKET_DATA_NOACK) {
send_entry->IsACK = 1;
}
}
/*..................................................................
Update SendCount
..................................................................*/
send_entry->SendCount++;
/*..................................................................
Perform error detection, based on either MaxRetries or Timeout
..................................................................*/
if (MaxRetries != -1 && send_entry->SendCount > MaxRetries) {
bad_conn = 1;
}
if (Timeout != -1 &&
(send_entry->LastTime - send_entry->FirstTime) > Timeout) {
bad_conn = 1;
}
}
}
/*------------------------------------------------------------------------
If the connection is going bad, return an error
------------------------------------------------------------------------*/
if (bad_conn) {
return(0);
}
else {
return(1);
}
} /* end of Service_Send_Queue */
/***************************************************************************
* ConnectionClass::Service_Receive_Queue -- services receive queue *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* 1 = OK, 0 = error *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/20/1994 BR : Created. *
*=========================================================================*/
int ConnectionClass::Service_Receive_Queue (void)
{
ReceiveQueueType *rec_entry; // ptr to receive entry header
CommHeaderType *packet_hdr; // packet header
int i;
/*------------------------------------------------------------------------
Remove all dead packets.
PACKET_DATA_NOACK: if it's been read, throw it away.
PACKET_DATA_ACK: if it's been read, and its ID is older than LastSeqID,
throw it away.
------------------------------------------------------------------------*/
for (i = 0; i < Queue->Num_Receive(); i++) {
rec_entry = Queue->Get_Receive(i);
if (rec_entry->IsRead) {
packet_hdr = (CommHeaderType *)(rec_entry->Buffer);
if (packet_hdr->Code == PACKET_DATA_NOACK) {
Queue->UnQueue_Receive(NULL,NULL,i,NULL,NULL);
i--;
}
else if (packet_hdr->PacketID < LastSeqID) {
Queue->UnQueue_Receive(NULL,NULL,i,NULL,NULL);
i--;
}
}
}
return(1);
} /* end of Service_Receive_Queue */
/***************************************************************************
* ConnectionClass::Time -- gets current time *
* *
* INPUT: *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/20/1994 BR : Created. *
*=========================================================================*/
unsigned long ConnectionClass::Time (void)
{
static struct timeb mytime; // DOS time
unsigned long msec;
#ifdef WWLIB32_H
/*------------------------------------------------------------------------
If the Westwood timer system has been activated, use TickCount's value
------------------------------------------------------------------------*/
if (TimerSystemOn) {
return(TickCount); // Westwood Library time
}
/*------------------------------------------------------------------------
Otherwise, use the DOS timer
------------------------------------------------------------------------*/
else {
ftime(&mytime);
msec = (unsigned long)mytime.time * 1000L + (unsigned long)mytime.millitm;
return((msec / 100) * 6);
}
#else
/*------------------------------------------------------------------------
If the Westwood library isn't being used, use the DOS timer.
------------------------------------------------------------------------*/
ftime(&mytime);
msec = (unsigned long)mytime.time * 1000L + (unsigned long)mytime.millitm;
return((msec / 100) * 6);
#endif
} /* end of Time */
/***************************************************************************
* ConnectionClass::Command_Name -- returns name for given packet command *
* *
* INPUT: *
* command packet Command value to get name for *
* *
* OUTPUT: *
* ptr to command name, NULL if invalid *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 05/31/1995 BRR : Created. *
*=========================================================================*/
char *ConnectionClass::Command_Name(int command)
{
if (command >= 0 && command < PACKET_COUNT) {
return(Commands[command]);
}
else {
return(NULL);
}
} /* end of Command_Name */
/************************** end of connect.cpp *****************************/

833
CODE/CONNECT.CPP.BAK Normal file
View file

@ -0,0 +1,833 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: F:\projects\c&c0\vcs\code\connect.cpv 4.76 03 Oct 1996 09:20:28 JOE_BOSTIC $ */
/***************************************************************************
** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S **
***************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : CONNECT.CPP *
* *
* Programmer : Bill Randolph *
* *
* Start Date : December 20, 1994 *
* *
* Last Update : May 31, 1995 [BRR] *
*-------------------------------------------------------------------------*
* Functions: *
* ConnectionClass::ConnectionClass -- class constructor *
* ConnectionClass::~ConnectionClass -- class destructor *
* ConnectionClass::Init -- Initializes connection queue to empty *
* ConnectionClass::Send_Packet -- adds a packet to the send queue *
* ConnectionClass::Receive_Packet -- adds packet to receive queue *
* ConnectionClass::Get_Packet -- gets a packet from receive queue *
* ConnectionClass::Service -- main polling routine; services packets *
* ConnectionClass::Service_Send_Queue -- services the send queue *
* ConnectionClass::Service_Receive_Queue -- services receive queue *
* ConnectionClass::Time -- gets current time *
* ConnectionClass::Command_Name -- returns name for a packet command *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
#include <stdio.h>
#include <mem.h>
#include <sys\timeb.h>
#include "connect.h"
/*
********************************* Globals ***********************************
*/
static char *ConnectionClass::Commands[PACKET_COUNT] = {
"ADATA",
"NDATA",
"ACK"
};
/***************************************************************************
* ConnectionClass::ConnectionClass -- class constructor *
* *
* INPUT: *
* numsend desired # of entries for the send queue *
* numreceive desired # of entries for the receive queue *
* maxlen max length of an application packet *
* magicnum the packet "magic number" for this connection *
* retry_delta the time to wait between sends *
* max_retries the max # of retries allowed for a packet *
* (-1 means retry forever, based on this parameter) *
* timeout the max amount of time before we give up on a packet *
* (-1 means retry forever, based on this parameter) *
* extralen max size of app-specific extra bytes (optional) *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/20/1994 BR : Created. *
*=========================================================================*/
ConnectionClass::ConnectionClass (int numsend, int numreceive,
int maxlen, unsigned short magicnum, unsigned long retry_delta,
unsigned long max_retries, unsigned long timeout, int extralen)
{
/*------------------------------------------------------------------------
Compute our maximum packet length
------------------------------------------------------------------------*/
MaxPacketLen = maxlen + sizeof(CommHeaderType);
/*------------------------------------------------------------------------
Assign the magic number
------------------------------------------------------------------------*/
MagicNum = magicnum;
/*------------------------------------------------------------------------
Initialize the retry time. This is the time that t2 - t1 must be greater
than before a retry will occur.
------------------------------------------------------------------------*/
RetryDelta = retry_delta;
/*------------------------------------------------------------------------
Set the maximum allowable retries.
------------------------------------------------------------------------*/
MaxRetries = max_retries;
/*------------------------------------------------------------------------
Set the timeout for this connection.
------------------------------------------------------------------------*/
Timeout = timeout;
/*------------------------------------------------------------------------
Allocate the packet staging buffer. This will be used to
------------------------------------------------------------------------*/
PacketBuf = new char[ MaxPacketLen ];
/*------------------------------------------------------------------------
Allocate the packet Queue. This will store incoming packets (placed there
by Receive_Packet), and outgoing packets (placed there by Send_Packet).
It can optionally store "extra" bytes, which are stored along with each
packet, but aren't transmitted as part of the packet. If 'extralen'
is 0, the CommBufferClass ignores this parameter.
------------------------------------------------------------------------*/
Queue = new CommBufferClass (numsend, numreceive, MaxPacketLen, extralen);
} /* end of ConnectionClass */
/***************************************************************************
* ConnectionClass::~ConnectionClass -- class destructor *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/20/1994 BR : Created. *
*=========================================================================*/
ConnectionClass::~ConnectionClass ()
{
/*------------------------------------------------------------------------
Free memory.
------------------------------------------------------------------------*/
delete [] PacketBuf;
delete Queue;
} /* end of ~ConnectionClass */
/***************************************************************************
* ConnectionClass::Init -- Initializes connection queue to empty *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/20/1994 BR : Created. *
*=========================================================================*/
void ConnectionClass::Init (void)
{
NumRecNoAck = 0;
NumRecAck = 0;
NumSendNoAck = 0;
NumSendAck = 0;
LastSeqID = 0xffffffff;
LastReadID = 0xffffffff;
Queue->Init();
} /* end of Init */
/***************************************************************************
* ConnectionClass::Send_Packet -- adds a packet to the send queue *
* *
* This routine prefixes the given buffer with a CommHeaderType and *
* queues the resulting packet into the Send Queue. (It's actually the *
* Service() routine that handles the hardware-dependent Send of the data).*
* The packet's MagicNumber, Code, and PacketID are set here. *
* *
* INPUT: *
* buf buffer to send *
* buflen length of buffer *
* ack_req 1 = ACK is required for this packet; 0 = isn't *
* *
* OUTPUT: *
* 1 = packet was queue'd OK, 0 = wasn't *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/20/1994 BR : Created. *
*=========================================================================*/
int ConnectionClass::Send_Packet (void * buf, int buflen, int ack_req)
{
/*------------------------------------------------------------------------
Set the magic # for the packet
------------------------------------------------------------------------*/
((CommHeaderType *)PacketBuf)->MagicNumber = MagicNum;
/*------------------------------------------------------------------------
Set the packet Code: DATA_ACK if it requires an ACK, NOACK if it doesn't
Set the packet ID to the appropriate counter value.
------------------------------------------------------------------------*/
if (ack_req) {
((CommHeaderType *)PacketBuf)->Code = PACKET_DATA_ACK;
((CommHeaderType *)PacketBuf)->PacketID = NumSendAck;
}
else {
((CommHeaderType *)PacketBuf)->Code = PACKET_DATA_NOACK;
((CommHeaderType *)PacketBuf)->PacketID = NumSendNoAck;
}
/*------------------------------------------------------------------------
Now build the packet
------------------------------------------------------------------------*/
memcpy(PacketBuf + sizeof(CommHeaderType), buf, buflen);
/*------------------------------------------------------------------------
Add it to the queue; don't add any extra data with it.
------------------------------------------------------------------------*/
if (Queue->Queue_Send(PacketBuf,buflen + sizeof(CommHeaderType), NULL, 0)) {
if (ack_req) {
NumSendAck++;
}
else {
NumSendNoAck++;
}
return(1);
}
else {
return(0);
}
} /* end of Send_Packet */
/***************************************************************************
* ConnectionClass::Receive_Packet -- adds packet to receive queue *
* *
* INPUT: *
* buf buffer to process (already includes CommHeaderType) *
* buflen length of buffer to process *
* *
* OUTPUT: *
* 1 = packet was processed OK, 0 = error *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/20/1994 BR : Created. *
*=========================================================================*/
int ConnectionClass::Receive_Packet (void * buf, int buflen)
{
CommHeaderType *packet; // ptr to packet header
SendQueueType *send_entry; // ptr to send entry header
ReceiveQueueType *rec_entry; // ptr to recv entry header
CommHeaderType *entry_data; // ptr to queue entry data
CommHeaderType ackpacket; // ACK packet to send
int i;
int save_packet = 1; // 0 = this is a resend
int found;
/*------------------------------------------------------------------------
Check the magic #
------------------------------------------------------------------------*/
packet = (CommHeaderType *)buf;
if (packet->MagicNumber != MagicNum) {
return(0);
}
/*------------------------------------------------------------------------
Handle an incoming ACK
------------------------------------------------------------------------*/
if (packet->Code == PACKET_ACK) {
for (i = 0; i < Queue->Num_Send(); i++) {
/*..................................................................
Get queue entry ptr
..................................................................*/
send_entry = Queue->Get_Send(i);
/*..................................................................
If ptr is valid, get ptr to its data
..................................................................*/
if (send_entry != NULL) {
entry_data = (CommHeaderType *)send_entry->Buffer;
/*...............................................................
If ACK is for this entry, mark it
...............................................................*/
if (packet->PacketID==entry_data->PacketID &&
entry_data->Code == PACKET_DATA_ACK) {
send_entry->IsACK = 1;
break;
}
}
}
return(1);
}
/*------------------------------------------------------------------------
Handle an incoming PACKET_DATA_NOACK packet
------------------------------------------------------------------------*/
else if (packet->Code == PACKET_DATA_NOACK) {
/*.....................................................................
If there's only one slot left, don't tie up the queue with this packet
.....................................................................*/
if (Queue->Max_Receive() - Queue->Num_Receive() <= 1) {
return(0);
}
/*.....................................................................
Error if we can't queue the packet
.....................................................................*/
if (!Queue->Queue_Receive (buf, buflen, NULL, 0)) {
return(0);
}
NumRecNoAck++;
return(1);
}
/*------------------------------------------------------------------------
Handle an incoming PACKET_DATA_ACK packet
------------------------------------------------------------------------*/
else if (packet->Code == PACKET_DATA_ACK) {
/*.....................................................................
If this is a packet requires an ACK, and it's ID is older than our
"oldest" ID, we know it's a resend; send an ACK, but don't queue it
.....................................................................*/
if (packet->PacketID <= LastSeqID && LastSeqID != 0xffffffff) {
save_packet = 0;
}
/*.....................................................................
Otherwise, scan the queue for this entry; if it's found, it's a
resend, so don't save it.
.....................................................................*/
else {
save_packet = 1;
for (i = 0; i < Queue->Num_Receive(); i++) {
rec_entry = Queue->Get_Receive(i);
if (rec_entry) {
entry_data = (CommHeaderType *)rec_entry->Buffer;
/*...........................................................
Packet is found; it's a resend
...........................................................*/
if (entry_data->Code == PACKET_DATA_ACK &&
entry_data->PacketID == packet->PacketID) {
save_packet = 0;
break;
}
}
}
} /* end of scan for resend */
/*.....................................................................
Queue the packet & update our LastSeqID value.
.....................................................................*/
if (save_packet) {
/*..................................................................
If there's only one slot left, make sure we only put a packet in it
if this packet will let us increment our LastSeqID; otherwise, we'll
get stuck, forever unable to increment LastSeqID.
..................................................................*/
if (Queue->Max_Receive() - Queue->Num_Receive() <= 1) {
if (packet->PacketID != (LastSeqID + 1) ) {
return(0);
}
}
/*..................................................................
If we can't queue the packet, return; don't send an ACK.
..................................................................*/
if (!Queue->Queue_Receive (buf, buflen, NULL, 0)) {
return(0);
}
NumRecAck++;
/*..................................................................
Update our LastSeqID value if we can. Anything less than LastSeqID
we'll know is a resend.
..................................................................*/
if (packet->PacketID == (LastSeqID + 1)) {
LastSeqID = packet->PacketID;
/*...............................................................
Now that we have a new 'LastSeqID', search our Queue to see if
the next ID is there; if so, keep checking for the next one;
break only when the next one isn't found. This forces
LastSeqID to be the largest possible value.
...............................................................*/
do {
found = 0;
for (i = 0; i < Queue->Num_Receive(); i++) {
rec_entry = Queue->Get_Receive(i);
if (rec_entry) {
entry_data = (CommHeaderType *)rec_entry->Buffer;
/*......................................................
Entry is found
......................................................*/
if (entry_data->Code == PACKET_DATA_ACK &&
entry_data->PacketID == (LastSeqID + 1)) {
LastSeqID = entry_data->PacketID;
found = 1;
break;
}
}
}
} while (found);
}
} /* end of save packet */
/*.....................................................................
Send an ACK, regardless of whether this was a resend or not.
.....................................................................*/
ackpacket.MagicNumber = Magic_Num();
ackpacket.Code = PACKET_ACK;
ackpacket.PacketID = packet->PacketID;
Send ((char *)&ackpacket, sizeof(CommHeaderType), NULL, 0);
return(1);
}
return(0);
} /* end of Receive_Packet */
/***************************************************************************
* ConnectionClass::Get_Packet -- gets a packet from receive queue *
* *
* INPUT: *
* buf location to store buffer *
* buflen filled in with length of 'buf' *
* *
* OUTPUT: *
* 1 = packet was read, 0 = wasn't *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/20/1994 BR : Created. *
*=========================================================================*/
int ConnectionClass::Get_Packet (void * buf, int *buflen)
{
ReceiveQueueType *rec_entry; // ptr to receive entry header
int packetlen; // size of received packet
CommHeaderType *entry_data;
int i;
/*------------------------------------------------------------------------
Ensure that we read the packets in order. LastReadID is the ID of the
last PACKET_DATA_ACK packet we read.
------------------------------------------------------------------------*/
for (i = 0; i < Queue->Num_Receive(); i++) {
rec_entry = Queue->Get_Receive(i);
/*.....................................................................
Only read this entry if it hasn't been yet
.....................................................................*/
if (rec_entry && rec_entry->IsRead==0) {
entry_data = (CommHeaderType *)rec_entry->Buffer;
/*..................................................................
If this is a DATA_ACK packet, its ID must be one greater than
the last one we read.
..................................................................*/
if ( (entry_data->Code == PACKET_DATA_ACK) &&
(entry_data->PacketID == (LastReadID + 1))) {
LastReadID = entry_data->PacketID;
rec_entry->IsRead = 1;
packetlen = rec_entry->BufLen - sizeof(CommHeaderType);
if (packetlen > 0) {
memcpy(buf, rec_entry->Buffer + sizeof(CommHeaderType),
packetlen);
}
(*buflen) = packetlen;
return(1);
}
/*..................................................................
If this is a DATA_NOACK packet, who cares what the ID is?
..................................................................*/
else if (entry_data->Code == PACKET_DATA_NOACK) {
rec_entry->IsRead = 1;
packetlen = rec_entry->BufLen - sizeof(CommHeaderType);
if (packetlen > 0) {
memcpy(buf, rec_entry->Buffer + sizeof(CommHeaderType),
packetlen);
}
(*buflen) = packetlen;
return(1);
}
}
}
return(0);
} /* end of Get_Packet */
/***************************************************************************
* ConnectionClass::Service -- main polling routine; services packets *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* 1 = OK, 0 = error (connection is broken!) *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/20/1994 BR : Created. *
*=========================================================================*/
int ConnectionClass::Service (void)
{
/*------------------------------------------------------------------------
Service the Send Queue: This [re]sends packets in the Send Queue which
haven't been ACK'd yet, and if their retry timeout has expired, and
updates the FirstTime, LastTime & SendCount values in the Queue entry.
Entries that have been ACK'd should be removed.
Service the Receive Queue: This sends ACKs for packets that haven't
been ACK'd yet. Entries that the app has read, and have been ACK'd,
should be removed.
------------------------------------------------------------------------*/
if ( Service_Send_Queue() && Service_Receive_Queue() ) {
return(1);
}
else {
return(0);
}
} /* end of Service */
/***************************************************************************
* ConnectionClass::Service_Send_Queue -- services the send queue *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* 1 = OK, 0 = error *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/20/1994 BR : Created. *
*=========================================================================*/
int ConnectionClass::Service_Send_Queue (void)
{
int i;
int num_entries;
SendQueueType *send_entry; // ptr to send queue entry
CommHeaderType *packet_hdr; // packet header
unsigned long curtime; // current time
int bad_conn = 0;
/*------------------------------------------------------------------------
Remove any ACK'd packets from the queue
------------------------------------------------------------------------*/
for (i = 0; i < Queue->Num_Send(); i++) {
/*.....................................................................
Get this queue entry
.....................................................................*/
send_entry = Queue->Get_Send(i);
/*.....................................................................
If ACK has been received, unqueue it
.....................................................................*/
if (send_entry->IsACK) {
/*..................................................................
Update this queue's response time
..................................................................*/
packet_hdr = (CommHeaderType *)send_entry->Buffer;
if (packet_hdr->Code == PACKET_DATA_ACK) {
Queue->Add_Delay(Time() - send_entry->FirstTime);
}
/*..................................................................
Unqueue the packet
..................................................................*/
Queue->UnQueue_Send(NULL,NULL,i,NULL,NULL);
i--;
}
}
/*------------------------------------------------------------------------
Loop through all entries in the Send queue. [Re]Send any entries that
need it.
------------------------------------------------------------------------*/
num_entries = Queue->Num_Send();
for (i = 0; i < num_entries; i++) {
send_entry = Queue->Get_Send(i);
if (send_entry->IsACK) {
continue;
}
/*.....................................................................
Only send the message if time has elapsed. (The message's Time
fields are init'd to 0 when a message is queue'd or unqueue'd, so the
first time through, the delta time will appear large.)
.....................................................................*/
curtime = Time();
if (curtime - send_entry->LastTime > RetryDelta) {
/*..................................................................
Send the message
..................................................................*/
Send (send_entry->Buffer, send_entry->BufLen, send_entry->ExtraBuffer,
send_entry->ExtraLen);
/*..................................................................
Fill in Time fields
..................................................................*/
send_entry->LastTime = curtime;
if (send_entry->SendCount==0) {
send_entry->FirstTime = curtime;
/*...............................................................
If this is the 1st time we're sending this packet, and it doesn't
require an ACK, mark it as ACK'd; then, the next time through,
it will just be removed from the queue.
...............................................................*/
packet_hdr = (CommHeaderType *)send_entry->Buffer;
if (packet_hdr->Code == PACKET_DATA_NOACK) {
send_entry->IsACK = 1;
}
}
/*..................................................................
Update SendCount
..................................................................*/
send_entry->SendCount++;
/*..................................................................
Perform error detection, based on either MaxRetries or Timeout
..................................................................*/
if (MaxRetries != -1 && send_entry->SendCount > MaxRetries) {
bad_conn = 1;
}
if (Timeout != -1 &&
(send_entry->LastTime - send_entry->FirstTime) > Timeout) {
bad_conn = 1;
}
}
}
/*------------------------------------------------------------------------
If the connection is going bad, return an error
------------------------------------------------------------------------*/
if (bad_conn) {
return(0);
}
else {
return(1);
}
} /* end of Service_Send_Queue */
/***************************************************************************
* ConnectionClass::Service_Receive_Queue -- services receive queue *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* 1 = OK, 0 = error *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/20/1994 BR : Created. *
*=========================================================================*/
int ConnectionClass::Service_Receive_Queue (void)
{
ReceiveQueueType *rec_entry; // ptr to receive entry header
CommHeaderType *packet_hdr; // packet header
int i;
/*------------------------------------------------------------------------
Remove all dead packets.
PACKET_DATA_NOACK: if it's been read, throw it away.
PACKET_DATA_ACK: if it's been read, and its ID is older than LastSeqID,
throw it away.
------------------------------------------------------------------------*/
for (i = 0; i < Queue->Num_Receive(); i++) {
rec_entry = Queue->Get_Receive(i);
if (rec_entry->IsRead) {
packet_hdr = (CommHeaderType *)(rec_entry->Buffer);
if (packet_hdr->Code == PACKET_DATA_NOACK) {
Queue->UnQueue_Receive(NULL,NULL,i,NULL,NULL);
i--;
}
else if (packet_hdr->PacketID < LastSeqID) {
Queue->UnQueue_Receive(NULL,NULL,i,NULL,NULL);
i--;
}
}
}
return(1);
} /* end of Service_Receive_Queue */
/***************************************************************************
* ConnectionClass::Time -- gets current time *
* *
* INPUT: *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/20/1994 BR : Created. *
*=========================================================================*/
unsigned long ConnectionClass::Time (void)
{
static struct timeb mytime; // DOS time
unsigned long msec;
#ifdef WWLIB32_H
/*------------------------------------------------------------------------
If the Westwood timer system has been activated, use TickCount's value
------------------------------------------------------------------------*/
if (TimerSystemOn) {
return(TickCount); // Westwood Library time
}
/*------------------------------------------------------------------------
Otherwise, use the DOS timer
------------------------------------------------------------------------*/
else {
ftime(&mytime);
msec = (unsigned long)mytime.time * 1000L + (unsigned long)mytime.millitm;
return((msec / 100) * 6);
}
#else
/*------------------------------------------------------------------------
If the Westwood library isn't being used, use the DOS timer.
------------------------------------------------------------------------*/
ftime(&mytime);
msec = (unsigned long)mytime.time * 1000L + (unsigned long)mytime.millitm;
return((msec / 100) * 6);
#endif
} /* end of Time */
/***************************************************************************
* ConnectionClass::Command_Name -- returns name for given packet command *
* *
* INPUT: *
* command packet Command value to get name for *
* *
* OUTPUT: *
* ptr to command name, NULL if invalid *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 05/31/1995 BRR : Created. *
*=========================================================================*/
char *ConnectionClass::Command_Name(int command)
{
if (command >= 0 && command < PACKET_COUNT) {
return(Commands[command]);
}
else {
return(NULL);
}
} /* end of Command_Name */
/************************** end of connect.cpp *****************************/

281
CODE/CONNECT.H Normal file
View file

@ -0,0 +1,281 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/CONNECT.H 1 3/03/97 10:24a Joe_bostic $ */
/***************************************************************************
** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S **
***************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : CONNECT.H *
* *
* Programmer : Bill Randolph *
* *
* Start Date : December 19, 1994 *
* *
* Last Update : April 1, 1995 [BR] *
* *
*-------------------------------------------------------------------------*
* *
* DESCRIPTION: *
* This class represents a single "connection" with another system. It's *
* a pure virtual base class that acts as a framework for other classes. *
* *
* This class contains a CommBufferClass member, which stores received *
* & transmitted packets. The ConnectionClass has virtual functions to *
* handle adding packets to the queue, reading them from the queue, *
* a Send routine for actually sending data, and a Receive_Packet function *
* which is used to tell the connection that a new packet has come in. *
* *
* The virtual Service routines handle all ACK & Retry logic for *
* communicating between this system & another. Thus, any class derived *
* from this class may overload the basic ACK/Retry logic. *
* *
* THE PACKET HEADER: *
* The Connection Classes prefix every packet sent with a header that's *
* local to this class. The header contains a "Magic Number" which should *
* be unique for each product, and Packet "Code", which will tell the *
* receiving end if this is DATA, or an ACK packet, and a packet ID, which *
* is a unique numerical ID for this packet (useful for detecting resends).*
* The header is stored with each packet in the send & receive Queues; *
* it's removed before it's passed back to the application, via *
* Get_Packet() *
* *
* THE CONNECTION MANAGER: *
* It is assumed that there will be a "Connection Manager" class which *
* will handle parsing incoming packets; it will then tell the connection *
* that new packets have come in, and the connection will process them in *
* whatever way it needs to for its protocol (check for resends, handle *
* ACK packets, etc). The job of the connection manager is to parse *
* incoming packets & distribute them to the connections that need to *
* store them (for multi-connection protocols). *
* *
* NOTES ON ACK/RETRY: *
* This class provides a "non-sequenced" ACK/Retry approach to packet *
* transmission. It sends out as many packets as are in the queue, whose *
* resend delta times have expired; and it ACK's any packets its received *
* who haven't been ACK'd yet. Thus, order of delivery is NOT guaranteed; *
* but, the performance is better than a "sequenced" approach. Also, the *
* Packet ID scheme (see below) ensures that the application will read *
* the packets in the proper order. Thus, this class guarantees delivery *
* and order of deliver. *
* *
* Each packet has a unique numerical ID; the ID is set to a count of the *
* number of packets sent. Different count values are provided, for both *
* DATA_ACK & DATA_NOACK packets. This ensures that the counter can be *
* used to detect resends of DATA_ACK packets; the counters for DATA_NOACK *
* packets aren't currently used. Other counters keep track of the *
* last-sequentially-received packet ID (for DATA_ACK packets), so we *
* can check for resends & missed packets, and the last-sequentially-read *
* packet ID, so we can ensure the app reads the packets in order. *
* *
* If the protocol being used already guarantees delivery of packets, *
* no ACK is required for the packets. In this case, the connection *
* class for this protocol can overload the Service routine to avoid *
* sending ACK packets, or the Connection Manager can just mark the *
* packet as ACK'd when it adds it to the Receive Queue for the connection.*
* *
* Derived classes must provide: *
* - Init: Initialization of any hardware-specific values. *
* - Send: a hardware-dependent send routine. *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef CONNECTION_H
#define CONNECTION_H
/*
********************************* Includes **********************************
*/
#include "combuf.h"
/*
********************************** Defines **********************************
*/
#define CONN_DEBUG 0
/*---------------------------------------------------------------------------
This structure is the header prefixed to any packet sent by the application.
MagicNumber: This is a number unique to the application; it's up to the
Receive_Packet routine to check this value, to be sure we're
not getting data from some other product. This value should
be unique for each application.
Code: This will be one of the below-defined codes.
PacketID: This is a unique numerical ID for this packet. The Connection
sets this ID on all packets sent out.
---------------------------------------------------------------------------*/
typedef struct {
unsigned short MagicNumber;
unsigned char Code;
unsigned long PacketID;
} CommHeaderType;
/*
***************************** Class Declaration *****************************
*/
class ConnectionClass
{
/*
---------------------------- Public Interface ----------------------------
*/
public:
/*.....................................................................
These are the possible values for the Code field of the CommHeaderType:
.....................................................................*/
enum ConnectionEnum {
PACKET_DATA_ACK, // this is a data packet requiring an ACK
PACKET_DATA_NOACK, // this is a data packet not requiring an ACK
PACKET_ACK, // this is an ACK for a packet
PACKET_COUNT // for computational purposes
};
/*.....................................................................
Constructor/destructor.
.....................................................................*/
ConnectionClass (int numsend, int numrecieve, int maxlen,
unsigned short magicnum, unsigned long retry_delta,
unsigned long max_retries, unsigned long timeout, int extralen = 0);
virtual ~ConnectionClass ();
/*.....................................................................
Initialization.
.....................................................................*/
virtual void Init (void);
/*.....................................................................
Send/Receive routines.
.....................................................................*/
virtual int Send_Packet (void * buf, int buflen, int ack_req);
virtual int Receive_Packet (void * buf, int buflen);
virtual int Get_Packet (void * buf, int * buflen);
/*.....................................................................
The main polling routine for the connection. Should be called as often
as possible.
.....................................................................*/
virtual int Service (void);
/*.....................................................................
This routine is used by the retry logic; returns the current time in
60ths of a second.
.....................................................................*/
static unsigned long Time (void);
/*.....................................................................
Utility routines.
.....................................................................*/
unsigned short Magic_Num (void) { return (MagicNum); }
unsigned long Retry_Delta (void) { return (RetryDelta); }
void Set_Retry_Delta (unsigned long delta) { RetryDelta = delta;}
unsigned long Max_Retries (void) { return (MaxRetries); }
void Set_Max_Retries (unsigned long retries) { MaxRetries = retries;}
unsigned long Time_Out (void) { return (Timeout); }
void Set_TimeOut (unsigned long t) { Timeout = t;}
unsigned long Max_Packet_Len (void) { return (MaxPacketLen); }
static char * Command_Name(int command);
/*.....................................................................
The packet "queue"; this non-sequenced version isn't really much of
a queue, but more of a repository.
.....................................................................*/
CommBufferClass *Queue;
/*
-------------------------- Protected Interface ---------------------------
*/
protected:
/*.....................................................................
Routines to service the Send & Receive queues.
.....................................................................*/
virtual int Service_Send_Queue(void);
virtual int Service_Receive_Queue(void);
/*.....................................................................
This routine actually performs a hardware-dependent data send. It's
pure virtual, so it must be defined by a derived class. The routine
is protected; it's only called by the ACK/Retry logic, not the
application.
.....................................................................*/
virtual int Send(char *buf, int buflen, void *extrabuf,
int extralen) = 0;
/*.....................................................................
This is the maximum packet length, including our own internal header.
.....................................................................*/
int MaxPacketLen;
/*.....................................................................
Packet staging area; this is where the CommHeaderType gets tacked onto
the application's packet before it's sent.
.....................................................................*/
char *PacketBuf;
/*.....................................................................
This is the magic number assigned to this connection. It is the first
few bytes of any transmission.
.....................................................................*/
unsigned short MagicNum;
/*.....................................................................
This value determines the time delay before a packet is re-sent.
.....................................................................*/
unsigned long RetryDelta;
/*.....................................................................
This is the maximum number of retries allowed for a packet; if this
value is exceeded, the connection is probably broken.
.....................................................................*/
unsigned long MaxRetries;
/*.....................................................................
This is the total timeout for this connection; if this time is exceeded
on a packet, the connection is probably broken.
.....................................................................*/
unsigned long Timeout;
/*.....................................................................
Running totals of # of packets we send & receive which require an ACK,
and those that don't.
.....................................................................*/
unsigned long NumRecNoAck;
unsigned long NumRecAck;
unsigned long NumSendNoAck;
unsigned long NumSendAck;
/*.....................................................................
This is the ID of the last consecutively-received packet; anything older
than this, we know is a resend. Anything newer than this MUST be lying
around in the Queue for us to detect it as a resend.
.....................................................................*/
unsigned long LastSeqID;
/*.....................................................................
This is the ID of the PACKET_DATA_ACK packet we read last; it ensures
that the application reads that type of packet in order.
.....................................................................*/
unsigned long LastReadID;
/*.....................................................................
Names of all packet commands
.....................................................................*/
static char * Commands[PACKET_COUNT];
};
#endif
/**************************** end of connect.h *****************************/

154
CODE/CONNMGR.H Normal file
View file

@ -0,0 +1,154 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header: /CounterStrike/CONNMGR.H 1 3/03/97 10:24a Joe_bostic $ */
/***************************************************************************
** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S **
***************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : CONNMGR.H *
* *
* Programmer : Bill Randolph *
* *
* Start Date : December 19, 1994 *
* *
* Last Update : April 3, 1995 [BR] *
* *
*-------------------------------------------------------------------------*
* *
* This is the Connection Manager base class. This is an abstract base *
* class that's just a shell for more functional derived classes. *
* The main job of the Connection Manager classes is to parse a "pool" of *
* incoming packets, which may be from different computers, and distribute *
* those packets to Connection Classes via their Receive_Packet function. *
* *
* This class should be the only access to the network/modem for the *
* application, so if the app needs any functions to access the *
* connections or the queue's, the derived versions of this class should *
* provide them. *
* *
* It's up to the derived class to define: *
* - Service: polling routine; should Service each connection *
* - Init: initialization; should perform hardware-dependent *
* initialization, then Init each connection; this function *
* isn't defined in this class, since the parameters will *
* be highly protocol-dependent) *
* - Send_Message:sends a packet across the connection (this function *
* isn't defined in this class, since the parameters will *
* be highly protocol-dependent) *
* - Get_Message: gets a message from the connection (this function *
* isn't defined in this class, since the parameters will *
* be highly protocol-dependent) *
* *
* If the derived class supports multiple connections, it should provide *
* functions for creating the connections, associating them with a name *
* or ID or both, destroying them, and sending data through all or any *
* connection. *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef CONNMGR_H
#define CONNMGR_H
/*
***************************** Class Declaration *****************************
*/
class ConnManClass
{
/*
---------------------------- Public Interface ----------------------------
*/
public:
/*.....................................................................
Various useful enums:
.....................................................................*/
enum IPXConnTag {
CONNECTION_NONE = -1 // value of an invalid connection ID
};
/*.....................................................................
Constructor/Destructor. These currently do nothing.
.....................................................................*/
ConnManClass (void) {};
virtual ~ConnManClass () {};
/*.....................................................................
The Service routine:
- Parses incoming packets, and adds them to the Receive Queue for the
Connection Class(s) for this protocol
- Invokes each connection's Service routine; returns an error if the
connection's Service routine indicates an error.
.....................................................................*/
virtual int Service (void) = 0;
/*.....................................................................
Sending & receiving data
.....................................................................*/
virtual int Send_Private_Message (void *buf, int buflen,
int ack_req = 1, int conn_id = CONNECTION_NONE) = 0;
virtual int Get_Private_Message (void *buf, int *buflen,
int *conn_id) = 0;
/*.....................................................................
Connection management
.....................................................................*/
virtual int Num_Connections(void) = 0;
virtual int Connection_ID(int index) = 0;
virtual int Connection_Index(int id) = 0;
/*.....................................................................
Queue utility routines
.....................................................................*/
virtual int Global_Num_Send(void) = 0;
virtual int Global_Num_Receive(void) = 0;
virtual int Private_Num_Send(int id = CONNECTION_NONE) = 0;
virtual int Private_Num_Receive(int id = CONNECTION_NONE) = 0;
/*.....................................................................
Timing management
.....................................................................*/
virtual void Reset_Response_Time(void) = 0;
virtual unsigned long Response_Time(void) = 0;
virtual void Set_Timing (unsigned long retrydelta,
unsigned long maxretries, unsigned long timeout) = 0;
/*.....................................................................
Debugging
.....................................................................*/
virtual void Configure_Debug(int index, int type_offset, int type_size,
char **names, int namestart, int namecount) = 0;
#ifdef CHEAT_KEYS
virtual void Mono_Debug_Print(int index, int refresh) = 0;
#endif
/*
--------------------------- Private Interface ----------------------------
*/
private:
/*.....................................................................
This abstract class contains no data members; but a derived class
will contain:
- An instance of one or more derived Connection Classes
- A buffer to store incoming packets
.....................................................................*/
};
#endif

5558
CODE/CONQUER.CPP Normal file

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more