Browse Source

Initial commit of Command & Conquer Red Alert source code.

LFeenanEA 6 months ago
parent
commit
5e733d5dcc
100 changed files with 66823 additions and 0 deletions
  1. 4848 0
      CODE/2KEYFBUF.ASM
  2. 583 0
      CODE/2KEYFRAM.CPP
  3. 564 0
      CODE/2SUPPORT.ASM
  4. 507 0
      CODE/2TXTPRNT.ASM
  5. 655 0
      CODE/AADATA.CPP
  6. 216 0
      CODE/ABSTRACT.CPP
  7. 135 0
      CODE/ABSTRACT.H
  8. 1847 0
      CODE/ADAMTEMP.MAK
  9. 2361 0
      CODE/ADATA.CPP
  10. 83 0
      CODE/ADPCM.CPP
  11. 4375 0
      CODE/AIRCRAFT.CPP
  12. 248 0
      CODE/AIRCRAFT.H
  13. 590 0
      CODE/ALLOC.CPP
  14. 1108 0
      CODE/ANIM.CPP
  15. 1062 0
      CODE/ANIM.CPP.BAK
  16. 156 0
      CODE/ANIM.H
  17. 763 0
      CODE/AUDIO.CPP
  18. 656 0
      CODE/AUDIO.CPP.BAK
  19. 99 0
      CODE/AUDIO.H
  20. 165 0
      CODE/B64PIPE.CPP
  21. 92 0
      CODE/B64PIPE.H
  22. 117 0
      CODE/B64STRAW.CPP
  23. 91 0
      CODE/B64STRAW.H
  24. 239 0
      CODE/BAR.CPP
  25. 111 0
      CODE/BAR.H
  26. 548 0
      CODE/BASE.CPP
  27. 130 0
      CODE/BASE.H
  28. 437 0
      CODE/BASE64.CPP
  29. 40 0
      CODE/BASE64.H
  30. 300 0
      CODE/BBDATA.CPP
  31. 3834 0
      CODE/BDATA.CPP
  32. 167 0
      CODE/BENCH.CPP
  33. 122 0
      CODE/BENCH.H
  34. 2122 0
      CODE/BFILE.MAK
  35. 2098 0
      CODE/BFILE2.MAK
  36. 987 0
      CODE/BFIOFILE.CPP
  37. 95 0
      CODE/BFIOFILE.H
  38. 84 0
      CODE/BIGCHECK.CPP
  39. 74 0
      CODE/BIGCHECK.H
  40. 598 0
      CODE/BLOWFISH.CPP
  41. 117 0
      CODE/BLOWFISH.H
  42. 202 0
      CODE/BLOWPIPE.CPP
  43. 85 0
      CODE/BLOWPIPE.H
  44. 161 0
      CODE/BLWSTRAW.CPP
  45. 87 0
      CODE/BLWSTRAW.H
  46. 189 0
      CODE/BMP8.CPP
  47. 43 0
      CODE/BMP8.H
  48. 220 0
      CODE/BUFF.CPP
  49. 99 0
      CODE/BUFF.H
  50. 101 0
      CODE/BUFFERX.H
  51. 64 0
      CODE/BUGS.TXT
  52. 5712 0
      CODE/BUILDING.CPP
  53. 356 0
      CODE/BUILDING.H
  54. 1070 0
      CODE/BULLET.CPP
  55. 149 0
      CODE/BULLET.H
  56. 410 0
      CODE/C&CZERO.PJT
  57. 183 0
      CODE/CARGO.CPP
  58. 93 0
      CODE/CARGO.H
  59. 153 0
      CODE/CARRY.CPP
  60. 84 0
      CODE/CARRY.H
  61. 431 0
      CODE/CCDDE.CPP
  62. 89 0
      CODE/CCDDE.H
  63. 693 0
      CODE/CCFILE.CPP
  64. 107 0
      CODE/CCFILE.H
  65. 1487 0
      CODE/CCINI.CPP
  66. 120 0
      CODE/CCINI.H
  67. 421 0
      CODE/CCMPATH.CPP
  68. 76 0
      CODE/CCPTR.CPP
  69. 115 0
      CODE/CCPTR.H
  70. 603 0
      CODE/CCTEN.CPP
  71. 6 0
      CODE/CC_ICON.RC
  72. 1 0
      CODE/CC_ICON.RH
  73. 3324 0
      CODE/CDATA.CPP
  74. 720 0
      CODE/CDFILE.CPP
  75. 113 0
      CODE/CDFILE.H
  76. 3014 0
      CODE/CELL.CPP
  77. 295 0
      CODE/CELL.H
  78. 102 0
      CODE/CHECKBOX.CPP
  79. 56 0
      CODE/CHECKBOX.H
  80. 365 0
      CODE/CHEKLIST.CPP
  81. 105 0
      CODE/CHEKLIST.H
  82. 19 0
      CODE/CLASS.CPP
  83. 67 0
      CODE/CO-WC32.LNT
  84. 278 0
      CODE/COLRLIST.CPP
  85. 87 0
      CODE/COLRLIST.H
  86. 425 0
      CODE/COMBAT.CPP
  87. 1164 0
      CODE/COMBUF.CPP
  88. 193 0
      CODE/COMBUF.H
  89. 51 0
      CODE/COMINIT.CPP
  90. 34 0
      CODE/COMINIT.H
  91. 217 0
      CODE/COMPAT.H
  92. 1003 0
      CODE/COMQUEUE.CPP
  93. 193 0
      CODE/COMQUEUE.H
  94. 244 0
      CODE/CONFDLG.CPP
  95. 56 0
      CODE/CONFDLG.H
  96. 838 0
      CODE/CONNECT.CPP
  97. 833 0
      CODE/CONNECT.CPP.BAK
  98. 281 0
      CODE/CONNECT.H
  99. 154 0
      CODE/CONNMGR.H
  100. 5558 0
      CODE/CONQUER.CPP

+ 4848 - 0
CODE/2KEYFBUF.ASM

@@ -0,0 +1,4848 @@
+;
+;	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 : Command & Conquer                        *
+;*                                                                         *
+;*                    File Name : KEYFBUFF.ASM                             *
+;*                                                                         *
+;*                   Programmer : David R. Dettmer                         *
+;*                                                                         *
+;*                   Start Date : March 3, 1995                            *
+;*                                                                         *
+;*                  Last Update :                                          *
+;*                                                                         *
+;*-------------------------------------------------------------------------*
+;* Functions:                                                              *
+;*   Buffer_Frame_To_Page -- Copies a linear buffer to a virtual viewport  *
+;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *
+
+;********************** Model & Processor Directives ***********************
+IDEAL
+P386
+MODEL USE32 FLAT
+jumps
+
+;******************************** Includes *********************************
+INCLUDE "gbuffer.inc"
+include	"profile.inc"
+
+
+;******************************** Equates **********************************
+
+TRUE	equ	1			; Boolean 'true' value
+FALSE	equ	0			; Boolean 'false' value
+
+;*=========================================================================*/
+;* The following are defines used to control what functions are linked	   *
+;* in for Buffer_Frame_To_Page.						   *
+;*=========================================================================*/
+;USE_NORMAL		EQU	TRUE
+;USE_HORZ_REV 		EQU	TRUE
+;USE_VERT_REV 		EQU	TRUE
+;USE_SCALING 		EQU	TRUE
+
+
+FLAG_NORMAL		EQU	0
+FLAG_TRANS		EQU	1
+FLAG_GHOST		EQU	2
+FLAG_FADING		EQU	4
+FLAG_PREDATOR		EQU	8
+
+FLAG_MASK		EQU	0Fh
+
+
+SHAPE_NORMAL 		EQU	0000h		; Standard shape
+;SHAPE_HORZ_REV 		EQU	0001h		; Flipped horizontally
+;SHAPE_VERT_REV 		EQU	0002h		; Flipped vertically
+;SHAPE_SCALING 		EQU	0004h		; Scaled (WORD scale_x, WORD scale_y)
+;SHAPE_VIEWPORT_REL 	EQU	0010h		; Coords are window-relative
+;SHAPE_WIN_REL 		EQU	0010h		; Coordinates are window relative instead of absolute.
+SHAPE_CENTER 		EQU	0020h		; Coords are based on shape's center pt
+SHAPE_TRANS		EQU	0040h		; has transparency
+
+SHAPE_FADING 		EQU	0100h		; Fading effect (VOID * fading_table,
+						;   WORD fading_num)
+SHAPE_PREDATOR 		EQU	0200h		; Transparent warping effect
+;SHAPE_COMPACT 		EQU	0400h		; Never use this bit
+;SHAPE_PRIORITY 		EQU	0800h		; Use priority system when drawing
+SHAPE_GHOST		EQU	1000h		; Shape is drawn ghosted
+;SHAPE_SHADOW		EQU	2000h
+SHAPE_PARTIAL  		EQU	4000h
+;SHAPE_COLOR 		EQU	8000h		; Remap the shape's colors
+						;   (VOID * color_table)
+
+
+;
+;.......................... Shadow Effect ..................................
+;
+SHADOW_COL		EQU	00FFh	; magic number for shadows
+
+;......................... Priority System .................................
+;
+CLEAR_UNUSED_BITS  	EQU	0007h	; and with 0000-0111 to clear
+					;  non-walkable high bit and
+					;  scaling id bits
+NON_WALKABLE_BIT  	EQU	0080h	; and with 1000-0000 to clear all
+					;  but non-walkable bit
+;
+;......................... Predator Effect .................................
+;
+;PRED_MASK		EQU	0007h	; mask used for predator pixel puts
+PRED_MASK		EQU	000Eh	; mask used for predator pixel puts
+
+
+;---------------------------------------------------------------------------
+;
+; Use a macro to make code a little cleaner.
+; The parameter varname is optional.
+; Syntax to use macro is :
+;  WANT equ expression
+;  USE func [,varname]
+; If the 'varname' is defined, a table declaration is created like:
+;	GLOBAL	TableName:DWORD
+; Then, the table entry is created:
+;  If WANT is true, the table entry is created for the given function:
+;	varname	DD	func
+;  If WANT is not TRUE, a Not_Supported entry is put in the table:
+;	varname	DD	Not_Supported
+; The resulting tables look like:
+;
+;	GLOBAL	ExampTable:DWORD
+;	ExampTable	DD	routine1
+;			DD	routine2
+;			DD	routine3
+;			...
+; Thus, each table is an array of function pointers.
+;
+;---------------------------------------------------------------------------
+MACRO USE func, varname
+ IF WANT
+  varname 	DD	func
+ ELSE
+  varname	DD	Not_Supported
+ ENDIF
+ENDM
+
+; IFNB <varname>
+;	GLOBAL	varname:DWORD
+; ENDIF
+
+;---------------------------------------------------------------------------
+
+
+DATASEG
+
+;---------------------------------------------------------------------------
+; Predator effect variables
+;---------------------------------------------------------------------------
+; make table for negative offset and use the used space for other variables
+
+BFPredNegTable	DW	-1, -3, -2, -5, -2, -4, -3, -1
+	; 8 words below calculated
+		DW	0, 0, 0, 0, 0, 0, 0, 0	; index ffffff00
+		DD	0, 0, 0, 0		; index ffffff10
+BFPredOffset	DD	0, 0, 0, 0		; index ffffff20
+		DD	0, 0, 0, 0		; index ffffff30
+	; partially faded predator effect value
+BFPartialPred	DD	0, 0, 0, 0		; index ffffff40
+BFPartialCount	DD	0, 0, 0, 0		; index ffffff50
+		DD	0, 0, 0, 0		; index ffffff60
+		DD	0, 0, 0, 0		; index ffffff70
+		DD	0, 0, 0, 0		; index ffffff80
+		DD	0, 0, 0, 0		; index ffffff90
+		DD	0, 0, 0, 0		; index ffffffa0
+		DD	0, 0, 0, 0		; index ffffffb0
+		DD	0, 0, 0, 0		; index ffffffc0
+		DD	0, 0, 0, 0		; index ffffffd0
+		DD	0, 0, 0, 0		; index ffffffe0
+		DD	0, 0, 0, 0		; index fffffff0
+BFPredTable	DW	1, 3, 2, 5, 2, 3, 4, 1
+;BFPredTable	DB	1, 3, 2, 5, 4, 3, 2, 1
+
+
+
+
+
+
+		global	C BigShapeBufferStart:dword
+		global	C UseBigShapeBuffer:dword
+		global	C UseOldShapeDraw:dword
+		global	C TheaterShapeBufferStart:dword
+		global	C IsTheaterShape:dword
+		global	C Single_Line_Trans_Entry:near
+		global	C Next_Line:near
+		global	C MMX_Done:near
+		global	C MMXAvailable:dword
+		global	EndNewShapeJumpTable:byte
+		global	NewShapeJumpTable:dword
+
+
+;**********************************************************************************
+;
+; Jump tables for new line header system
+;
+; Each line of shape data now has a header byte which describes the data on the line.
+;
+
+;
+; Header byte control bits
+;
+BLIT_TRANSPARENT	=1
+BLIT_GHOST		=2
+BLIT_FADING		=4
+BLIT_PREDATOR		=8
+BLIT_SKIP		=16
+BLIT_ALL		=BLIT_TRANSPARENT or BLIT_GHOST or BLIT_FADING or BLIT_PREDATOR or BLIT_SKIP
+
+
+		struc		ShapeHeaderType
+
+		draw_flags	dd	?
+		shape_data	dd	?
+		shape_buffer	dd	?
+
+		ends
+
+;
+; Global definitions for routines that draw a single line of a shape
+;
+		global	Short_Single_Line_Copy:near
+		global	Single_Line_Trans:near
+		global	Single_Line_Ghost:near
+		global	Single_Line_Ghost_Trans:near
+		global	Single_Line_Fading:near
+		global	Single_Line_Fading_Trans:near
+		global	Single_Line_Ghost_Fading:near
+		global	Single_Line_Ghost_Fading_Trans:near
+		global	Single_Line_Predator:near
+		global	Single_Line_Predator_Trans:near
+		global	Single_Line_Predator_Ghost:near
+		global	Single_Line_Predator_Ghost_Trans:near
+		global	Single_Line_Predator_Fading:near
+		global	Single_Line_Predator_Fading_Trans:near
+		global	Single_Line_Predator_Ghost_Fading:near
+		global	Single_Line_Predator_Ghost_Fading_Trans:near
+		global	Single_Line_Skip:near
+
+		global	Single_Line_Single_Fade:near
+		global	Single_Line_Single_Fade_Trans:near
+
+
+
+label		NewShapeJumpTable	dword
+
+;
+; Jumptable for shape line drawing with no flags set
+;
+
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+label		CriticalFadeRedirections dword
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+
+
+;
+; Jumptable for shape line drawing routines with transparent flags set
+;
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Trans
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Trans
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Trans
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Trans
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Trans
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Trans
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Trans
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Trans
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+
+
+;
+; Jumptable for shape line drawing routines with ghost flags set
+;
+
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Ghost
+		dd	Single_Line_Ghost
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Ghost
+		dd	Single_Line_Ghost
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Ghost
+		dd	Single_Line_Ghost
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Ghost
+		dd	Single_Line_Ghost
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+
+
+;
+; Jumptable for shape line drawing routines with ghost and transparent flags set
+;
+
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Trans
+		dd	Single_Line_Ghost
+		dd	Single_Line_Ghost_Trans
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Trans
+		dd	Single_Line_Ghost
+		dd	Single_Line_Ghost_Trans
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Trans
+		dd	Single_Line_Ghost
+		dd	Single_Line_Ghost_Trans
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Trans
+		dd	Single_Line_Ghost
+		dd	Single_Line_Ghost_Trans
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+
+
+
+
+
+;
+; Jumptable for shape line drawing routines with fading flag set
+;
+
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Single_Fade
+		dd	Single_Line_Single_Fade
+		dd	Single_Line_Fading
+		dd	Single_Line_Fading
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Fading
+		dd	Single_Line_Fading
+		dd	Single_Line_Fading
+		dd	Single_Line_Fading
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+
+
+;
+; Jumptable for shape line drawing routines with fading and transparent flags set
+;
+
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Trans
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Trans
+		dd	Single_Line_Single_Fade
+		dd	Single_Line_Single_Fade_Trans
+		dd	Single_Line_Fading
+		dd	Single_Line_Fading_Trans
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Trans
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Trans
+		dd	Single_Line_Fading
+		dd	Single_Line_Fading_Trans
+		dd	Single_Line_Fading
+		dd	Single_Line_Fading_Trans
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+
+
+;
+; Jumptable for shape line drawing routines with fading and ghost flags set
+;
+
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Ghost
+		dd	Single_Line_Ghost
+		dd	Single_Line_Single_Fade
+		dd	Single_Line_Single_Fade
+		dd	Single_Line_Ghost_Fading
+		dd	Single_Line_Ghost_Fading
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Ghost
+		dd	Single_Line_Ghost
+		dd	Single_Line_Fading
+		dd	Single_Line_Fading
+		dd	Single_Line_Ghost_Fading
+		dd	Single_Line_Ghost_Fading
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+
+
+
+;
+; Jumptable for shape line drawing routines with fading, transparent and ghost flags set
+;
+
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Trans
+		dd	Single_Line_Ghost
+		dd	Single_Line_Ghost_Trans
+		dd	Single_Line_Single_Fade
+		dd	Single_Line_Single_Fade_Trans
+		dd	Single_Line_Ghost_Fading
+		dd	Single_Line_Ghost_Fading_Trans
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Trans
+		dd	Single_Line_Ghost
+		dd	Single_Line_Ghost_Trans
+		dd	Single_Line_Fading
+		dd	Single_Line_Fading_Trans
+		dd	Single_Line_Ghost_Fading
+		dd	Single_Line_Ghost_Fading_Trans
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+
+
+
+
+
+
+;
+; Jumptable for shape line drawing with predator flag set
+;
+
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Predator
+		dd	Single_Line_Predator
+		dd	Single_Line_Predator
+		dd	Single_Line_Predator
+		dd	Single_Line_Predator
+		dd	Single_Line_Predator
+		dd	Single_Line_Predator
+		dd	Single_Line_Predator
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+
+
+;
+; Jumptable for shape line drawing routines with transparent and predator flags set
+;
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Trans
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Trans
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Trans
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Trans
+		dd	Single_Line_Predator
+		dd	Single_Line_Predator_Trans
+		dd	Single_Line_Predator
+		dd	Single_Line_Predator_Trans
+		dd	Single_Line_Predator
+		dd	Single_Line_Predator_Trans
+		dd	Single_Line_Predator
+		dd	Single_Line_Predator_Trans
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+
+
+;
+; Jumptable for shape line drawing routines with ghost and predator flags set
+;
+
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Ghost
+		dd	Single_Line_Ghost
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Ghost
+		dd	Single_Line_Ghost
+		dd	Single_Line_Predator
+		dd	Single_Line_Predator
+		dd	Single_Line_Predator_Ghost
+		dd	Single_Line_Predator_Ghost
+		dd	Single_Line_Predator
+		dd	Single_Line_Predator
+		dd	Single_Line_Predator_Ghost
+		dd	Single_Line_Predator_Ghost
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+
+
+;
+; Jumptable for shape line drawing routines with ghost and transparent and predator flags set
+;
+
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Trans
+		dd	Single_Line_Ghost
+		dd	Single_Line_Ghost_Trans
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Trans
+		dd	Single_Line_Ghost
+		dd	Single_Line_Ghost_Trans
+		dd	Single_Line_Predator
+		dd	Single_Line_Predator_Trans
+		dd	Single_Line_Predator_Ghost
+		dd	Single_Line_Predator_Ghost_Trans
+		dd	Single_Line_Predator
+		dd	Single_Line_Predator_Trans
+		dd	Single_Line_Predator_Ghost
+		dd	Single_Line_Predator_Ghost_Trans
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+
+
+
+
+
+;
+; Jumptable for shape line drawing routines with fading and predator flags set
+;
+
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Single_Fade
+		dd	Single_Line_Single_Fade
+		dd	Single_Line_Fading
+		dd	Single_Line_Fading
+		dd	Single_Line_Predator
+		dd	Single_Line_Predator
+		dd	Single_Line_Predator
+		dd	Single_Line_Predator
+		dd	Single_Line_Predator_Fading
+		dd	Single_Line_Predator_Fading
+		dd	Single_Line_Predator_Fading
+		dd	Single_Line_Predator_Fading
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+
+
+;
+; Jumptable for shape line drawing routines with fading and transparent and predator flags set
+;
+
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Trans
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Trans
+		dd	Single_Line_Single_Fade
+		dd	Single_Line_Single_Fade_Trans
+		dd	Single_Line_Fading
+		dd	Single_Line_Fading_Trans
+		dd	Single_Line_Predator
+		dd	Single_Line_Predator_Trans
+		dd	Single_Line_Predator
+		dd	Single_Line_Predator_Trans
+		dd	Single_Line_Predator_Fading
+		dd	Single_Line_Predator_Fading_Trans
+		dd	Single_Line_Predator_Fading
+		dd	Single_Line_Predator_Fading_Trans
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+
+
+;
+; Jumptable for shape line drawing routines with fading and ghost and predator flags set
+;
+
+		dd	Short_Single_Line_Copy
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Ghost
+		dd	Single_Line_Ghost
+		dd	Single_Line_Single_Fade
+		dd	Single_Line_Single_Fade
+		dd	Single_Line_Ghost_Fading
+		dd	Single_Line_Ghost_Fading
+		dd	Single_Line_Predator
+		dd	Single_Line_Predator
+		dd	Single_Line_Predator_Ghost
+		dd	Single_Line_Predator_Ghost
+		dd	Single_Line_Predator_Fading
+		dd	Single_Line_Predator_Fading
+		dd	Single_Line_Predator_Ghost_Fading
+		dd	Single_Line_Predator_Ghost_Fading
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+
+
+
+
+
+
+
+;
+; Jumptable for shape line drawing routines with all flags set
+;
+
+label		AllFlagsJumpTable	dword
+		dd	Short_Single_Line_Copy
+		dd	Single_Line_Trans
+		dd	Single_Line_Ghost
+		dd	Single_Line_Ghost_Trans
+		dd	Single_Line_Single_Fade
+		dd	Single_Line_Single_Fade_Trans
+		dd	Single_Line_Ghost_Fading
+		dd	Single_Line_Ghost_Fading_Trans
+		dd	Single_Line_Predator
+		dd	Single_Line_Predator_Trans
+		dd	Single_Line_Predator_Ghost
+		dd	Single_Line_Predator_Ghost_Trans
+		dd	Single_Line_Predator_Fading
+		dd	Single_Line_Predator_Fading_Trans
+		dd	Single_Line_Predator_Ghost_Fading
+		dd	Single_Line_Predator_Ghost_Fading_Trans
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+		dd	Single_Line_Skip
+
+
+
+label		EndNewShapeJumpTable	byte
+
+CODESEG
+
+;---------------------------------------------------------------------------
+; Code Segment Tables:
+; This code uses the USE macro to set up tables of function addresses.
+; The tables have the following format:
+; Tables defined are:
+;	BufferFrameTable
+;---------------------------------------------------------------------------
+
+WANT	equ 	<TRUE>
+USE	BF_Copy, BufferFrameTable
+
+WANT	equ 	<TRUE>
+USE	BF_Trans
+
+WANT	equ 	<TRUE>
+USE	BF_Ghost
+
+WANT	equ 	<TRUE>
+USE	BF_Ghost_Trans
+
+WANT	equ 	<TRUE>
+USE	BF_Fading
+
+WANT	equ 	<TRUE>
+USE	BF_Fading_Trans
+
+WANT	equ 	<TRUE>
+USE	BF_Ghost_Fading
+
+WANT	equ 	<TRUE>
+USE	BF_Ghost_Fading_Trans
+
+WANT	equ 	<TRUE>
+USE	BF_Predator
+
+WANT	equ 	<TRUE>
+USE	BF_Predator_Trans
+
+WANT	equ 	<TRUE>
+USE	BF_Predator_Ghost
+
+WANT	equ 	<TRUE>
+USE	BF_Predator_Ghost_Trans
+
+WANT	equ 	<TRUE>
+USE	BF_Predator_Fading
+
+WANT	equ 	<TRUE>
+USE	BF_Predator_Fading_Trans
+
+WANT	equ 	<TRUE>
+USE	BF_Predator_Ghost_Fading
+
+WANT	equ 	<TRUE>
+USE	BF_Predator_Ghost_Fading_Trans
+
+
+
+
+
+;---------------------------------------------------------------------------
+
+
+
+
+;*********************************************************************************************
+;* Set_Shape_Header -- create the line header bytes for a shape                              *
+;*                                                                                           *
+;* INPUT:	Shape width                                                                  *
+;*              Shape height                                                                 *
+;*              ptr to raw shape data                                                        *
+;*              ptr to shape headers                                                         *
+;*              shape flags                                                                  *
+;*              ptr to translucency table                                                    *
+;*              IsTranslucent                                                                *
+;*                                                                                           *
+;* OUTPUT:      none                                                                         *
+;*                                                                                           *
+;* Warnings:                                                                                 *
+;*                                                                                           *
+;* HISTORY:                                                                                  *
+;*   11/29/95 10:09AM ST : Created.                                                          *
+;*===========================================================================================*
+
+		proc	Setup_Shape_Header C near
+
+		ARG	pixel_width 	:DWORD		; width of rectangle to blit
+		ARG	pixel_height	:DWORD		; height of rectangle to blit
+		ARG  	src         	:DWORD		; this is a member function
+		ARG	headers	    	:DWORD
+		ARG	flags		:DWORD
+		ARG	Translucent	:DWORD
+		ARG	IsTranslucent	:DWORD
+		LOCAL	trans_count	:DWORD
+
+		pushad
+
+
+		mov	esi,[src]		;ptr to raw shape data
+		mov	edi,[headers]		;ptr to headers we are going to set up
+		mov	eax,[flags]
+		and	eax,SHAPE_TRANS or SHAPE_FADING or SHAPE_PREDATOR or SHAPE_GHOST
+		mov	[(ShapeHeaderType edi).draw_flags],eax 	;save old flags in header
+		add	edi,size ShapeHeaderType
+		mov	edx,[pixel_height]	;number of shape lines to scan
+
+??outer_loop:	mov	ecx,[pixel_width]	;number of pixels in shape line
+		xor	bl,bl			;flag the we dont know anything about this line yet
+		mov	[trans_count],0		;we havnt scanned any transparent pixels yet
+
+;
+; Scan one shape line to see what kind of data it contains
+;
+??inner_loop:	xor	eax,eax
+		mov	al,[esi]
+		inc	esi
+
+;
+; Check for transparent pixel
+;
+		test	al,al
+		jnz	??not_transp
+		test	[flags],SHAPE_TRANS
+		jz	??not_transp
+		or	bl,BLIT_TRANSPARENT	;flag that pixel is transparent
+		inc	[trans_count]		;keep count of the number of transparent pixels on the line
+		jmp	??end_lp
+
+;
+; Check for predator effect on this line
+;
+??not_transp:	test	[flags],SHAPE_PREDATOR
+		jz	??not_pred
+		or	bl,BLIT_PREDATOR
+
+;
+; Check for ghost effects
+;
+??not_pred:	test	[flags],SHAPE_GHOST
+		jz	??not_ghost
+		push	edi
+		mov	edi,[IsTranslucent]
+		cmp	[byte edi+eax],-1
+		pop	edi
+		jz	??not_ghost
+		or	bl,BLIT_GHOST
+
+;
+; Check if fading is required
+;
+??not_ghost:	test	[flags],SHAPE_FADING
+		jz	??end_lp
+		or	bl,BLIT_FADING
+
+??end_lp:       dec	ecx
+		jnz	??inner_loop
+
+
+;
+; Interpret the info we have collected and decide which routine will be
+; used to draw this line
+;
+		xor	bh,bh
+
+		test	bl,BLIT_TRANSPARENT
+		jz	??no_transparencies
+		or	bh,BLIT_TRANSPARENT
+		mov	ecx,[pixel_width]
+		cmp	ecx,[trans_count]
+		jnz	??not_all_trans
+
+; all pixels in the line were transparent so we dont need to draw it at all
+		mov	bh,BLIT_SKIP
+		jmp	??got_line_type
+
+??not_all_trans:
+??no_transparencies:
+		mov	al,bl
+		and	al,BLIT_PREDATOR
+		or	bh,al
+		mov	al,bl
+		and	al,BLIT_GHOST
+		or	bh,al
+		mov	al,bl
+		and	al,BLIT_FADING
+		or	bh,al
+
+;
+; Save the line header and do the next line
+;
+??got_line_type:mov	[edi],bh
+		inc	edi
+
+		dec	edx
+		jnz	??outer_loop
+
+
+		popad
+		ret
+
+		endp	Setup_Shape_Header
+
+
+
+
+;**************************************************************
+;
+; Macro to fetch the header of the next line and jump to the appropriate routine
+;
+		macro	next_line
+
+		add	edi , [ dest_adjust_width ]	;add in dest modulo
+		dec	edx				;line counter
+		jz	??real_out			;return
+		mov	ecx,[save_ecx]			;ecx is pixel count
+		mov	eax,[header_pointer]		;ptr to next header byte
+		mov	al,[eax]
+		inc	[header_pointer]
+		and	eax,BLIT_ALL			;Make sure we dont jump to some spurious address
+							; if the header is wrong then its better to draw with the wrong
+							; shape routine than to die
+		shl	eax,2
+		add	eax,[ShapeJumpTableAddress]	;get the address to jump to
+		jmp	[dword eax]			;do the jump
+
+		endm
+
+
+
+
+
+
+;***************************************************************************
+;* VVC::TOPAGE -- Copies a linear buffer to a virtual viewport		   *
+;*                                                                         *
+;* INPUT:	WORD	x_pixel		- x pixel on viewport to copy from *
+;*		WORD	y_pixel 	- y pixel on viewport to copy from *
+;*		WORD	pixel_width	- the width of copy region	   *
+;*		WORD	pixel_height	- the height of copy region	   *
+;*		BYTE *	src		- buffer to copy from		   *
+;*		VVPC *  dest		- virtual viewport to copy to	   *
+;*                                                                         *
+;* OUTPUT:      none                                                       *
+;*                                                                         *
+;* WARNINGS:    Coordinates and dimensions will be adjusted if they exceed *
+;*	        the boundaries.  In the event that no adjustment is 	   *
+;*	        possible this routine will abort.  If the size of the 	   *
+;*		region to copy exceeds the size passed in for the buffer   *
+;*		the routine will automatically abort.			   *
+;*									   *
+;* HISTORY:                                                                *
+;*   06/15/1994 PWG : Created.                                             *
+;*=========================================================================*
+	GLOBAL	C Buffer_Frame_To_Page:NEAR
+	PROC	Buffer_Frame_To_Page C near
+	USES	eax,ebx,ecx,edx,esi,edi
+
+	;*===================================================================
+	;* define the arguements that our function takes.
+	;*===================================================================
+	ARG	x_pixel     :DWORD		; x pixel position in source
+	ARG	y_pixel     :DWORD		; y pixel position in source
+	ARG	pixel_width :DWORD		; width of rectangle to blit
+	ARG	pixel_height:DWORD		; height of rectangle to blit
+	ARG    	src         :DWORD		; this is a member function
+	ARG	dest        :DWORD		; what are we blitting to
+
+	ARG	flags       :DWORD		; flags passed
+
+	;*===================================================================
+	; Define some locals so that we can handle things quickly
+	;*===================================================================
+	LOCAL	IsTranslucent		:DWORD	; ptr to the is_translucent table
+	LOCAL	Translucent		:DWORD	; ptr to the actual translucent table
+	LOCAL	FadingTable		:DWORD	; extracted fading table pointer
+	LOCAL	FadingNum		:DWORD	; get the number of times to fade
+
+	LOCAL	StashECX		:DWORD	; temp variable for ECX register
+
+	LOCAL	jflags			:DWORD	; flags used to goto correct buff frame routine
+	LOCAL	BufferFrameRout		:DWORD	; ptr to the buffer frame routine
+
+	LOCAL	jmp_loc			:DWORD	; calculated jump location
+	LOCAL	loop_cnt		:DWORD
+
+	LOCAL 	x1_pixel		:DWORD
+	LOCAL	y1_pixel		:DWORD
+	LOCAL	scr_x			:DWORD
+	LOCAL	scr_y			:DWORD
+	LOCAL	dest_adjust_width	:DWORD
+	LOCAL	scr_adjust_width	:DWORD
+	LOCAL	header_pointer		:DWORD
+	LOCAL	use_old_draw		:DWORD
+	LOCAL	save_ecx		:DWORD
+	LOCAL	ShapeJumpTableAddress	:DWORD
+	LOCAL	shape_buffer_start	:DWORD
+
+
+	prologue
+	cmp	[ src ] , 0
+	jz	??real_out
+
+	cmp	[UseOldShapeDraw],0
+	jz	??new_system
+
+	mov	[use_old_draw],1
+	jmp	??do_args
+
+??new_system:
+	;
+	; Save the line attributes pointers and
+	; Modify the src pointer to point to the actual image
+	;
+	cmp	[UseBigShapeBuffer],0
+	jz	??do_args			;just use the old shape drawing system
+	mov	edi,[src]
+	mov	[header_pointer],edi
+
+	mov	eax,[BigShapeBufferStart]
+	cmp	[(ShapeHeaderType edi).shape_buffer],0
+	jz	??is_ordinary_shape
+	mov	eax,[TheaterShapeBufferStart]
+??is_ordinary_shape:
+	mov	[shape_buffer_start],eax
+
+	mov	edi,[(ShapeHeaderType edi).shape_data]
+	add	edi,[shape_buffer_start]
+	mov	[src],edi
+	mov	[use_old_draw],0
+
+
+	;====================================================================
+	; Pull off optional arguments:
+	; EDI is used as an offset from the 'flags' parameter, to point
+	; to the optional argument currently being processed.
+	;====================================================================
+??do_args:
+	mov	edi , 4	 			; optional params start past flags
+	mov	[ jflags ] , 0			; clear jump flags
+
+??check_centering:
+	;-------------------------------------------------------------------
+	; See if we need to center the frame
+	;-------------------------------------------------------------------
+	test	[ flags ] , SHAPE_CENTER	; does this need to be centered?
+	je	??check_trans			; if not the skip over this stuff
+
+	mov	eax , [ pixel_width ]
+	mov	ebx , [ pixel_height ]
+	sar	eax , 1
+	sar	ebx , 1
+	sub	[ x_pixel ] , eax
+	sub	[ y_pixel ] , ebx
+
+??check_trans:
+	test	[ flags ] , SHAPE_TRANS
+	jz	??check_ghost
+
+	or	[ jflags ] , FLAG_TRANS
+
+	;--------------------------------------------------------------------
+	; SHAPE_GHOST: DWORD is_translucent tbl
+	;--------------------------------------------------------------------
+??check_ghost:
+	test	[ flags ] , SHAPE_GHOST		; are we ghosting this shape
+	jz	??check_fading
+
+	mov	eax , [ flags + edi ]
+	or	[ jflags ] , FLAG_GHOST
+	mov	[ IsTranslucent ] , eax		; save ptr to is_trans. tbl
+	add	eax , 0100h			; add 256 for first table
+	add	edi , 4				; next argument
+	mov	[ Translucent ] , eax		; save ptr to translucent tbl
+
+
+
+??check_fading:
+	;______________________________________________________________________
+	; If this is the first time through for this shape then
+	; set up the shape header
+	;______________________________________________________________________
+	pushad
+
+	cmp	[UseBigShapeBuffer],0		;no big shape buffer so use old system
+	jz	??new_shape
+	cmp	[UseOldShapeDraw],0		;use old shape system flag
+	jnz	??new_shape
+
+	mov	edi,[header_pointer]
+	cmp	[(ShapeHeaderType edi).draw_flags],-1
+	jz	??setup_headers
+	mov	eax,[flags]							 ;Redo the shape headers if this shape was
+	and	eax,SHAPE_TRANS or SHAPE_FADING or SHAPE_PREDATOR or SHAPE_GHOST ;initially set up with different flags
+	cmp	eax,[(ShapeHeaderType edi).draw_flags]
+	jz	??no_header_setup
+??new_shape:
+	mov	[use_old_draw],1
+	jmp	??no_header_setup
+
+??setup_headers:
+	push	[IsTranslucent]
+	push	[Translucent]
+	push	[flags]
+	push	[header_pointer]
+	push	[src]
+	push	[pixel_height]
+	push	[pixel_width]
+	call	Setup_Shape_Header
+	add	esp,7*4
+	mov	[ShapeJumpTableAddress],offset AllFlagsJumpTable
+	jmp	??headers_set
+??no_header_setup:
+
+	xor	eax,eax
+	test	[flags],SHAPE_PREDATOR
+	jz	??not_shape_predator
+	or	al,BLIT_PREDATOR
+
+??not_shape_predator:
+	test	[flags],SHAPE_FADING
+	jz	??not_shape_fading
+	or	al,BLIT_FADING
+
+??not_shape_fading:
+
+	test	[flags],SHAPE_TRANS
+	jz	??not_shape_transparent
+	or	al,BLIT_TRANSPARENT
+
+??not_shape_transparent:
+
+	test	[flags],SHAPE_GHOST
+	jz	??not_shape_ghost
+	or	al,BLIT_GHOST
+
+??not_shape_ghost:
+
+	shl	eax,7
+	add	eax,offset NewShapeJumpTable
+	mov	[ShapeJumpTableAddress],eax
+
+
+??headers_set:
+	popad
+
+	;--------------------------------------------------------------------
+	; SHAPE_FADING: DWORD fade_table[256], DWORD fade_count
+	;--------------------------------------------------------------------
+	test	[ flags ] , SHAPE_FADING	; are we fading this shape
+	jz	??check_predator
+
+	mov	eax , [ flags + edi ]
+	mov	[ FadingTable ] , eax		; save address of fading tbl
+	mov	eax , [ flags + edi + 4 ]	; get fade num
+	or	[ jflags ] , FLAG_FADING
+	and	eax , 03fh			; no need for more than 63
+	add	edi , 8				; next argument
+	cmp	eax , 0				; check if it's 0
+	jnz	??set_fading			; if not, store fade num
+
+	and	[ flags ] , NOT SHAPE_FADING	; otherwise, don't fade
+
+??set_fading:
+	mov	[ FadingNum ] , eax
+
+	mov	ebx,[ShapeJumpTableAddress]
+	mov	[dword ebx+CriticalFadeRedirections-NewShapeJumpTable],offset Single_Line_Single_Fade
+	mov	[dword ebx+CriticalFadeRedirections-NewShapeJumpTable+4],offset Single_Line_Single_Fade_Trans
+	cmp	eax,1
+	jz	??single_fade
+	mov	[dword ebx+CriticalFadeRedirections-NewShapeJumpTable],offset Single_Line_Fading
+	mov	[dword ebx+CriticalFadeRedirections-NewShapeJumpTable+4],offset Single_Line_Fading_Trans
+
+??single_fade:
+
+	;--------------------------------------------------------------------
+	; SHAPE_PREDATOR: DWORD init_pred_lookup_offset (0-7)
+	;--------------------------------------------------------------------
+??check_predator:
+	test	[ flags ] , SHAPE_PREDATOR	; is predator effect on
+	jz	??check_partial
+
+	mov	eax , [ flags + edi ]		; pull the partial value
+	or	[ jflags ] , FLAG_PREDATOR
+	shl	eax , 1
+	cmp	eax , 0
+	jge	??check_range
+
+	neg	eax
+	mov	ebx , -1
+	and	eax , PRED_MASK			; keep entries within bounds
+	mov	bl , al
+	mov	eax , ebx			; will be ffffff00-ffffff07
+	jmp	??pred_cont
+
+??check_range:
+	and	eax , PRED_MASK			; keep entries within bounds
+
+??pred_cont:
+	add	edi , 4				; next argument
+	mov	[ BFPredOffset ] , eax
+	mov	[ BFPartialCount ] , 0		; clear the partial count
+	mov	[ BFPartialPred ] , 100h	; init partial to off
+
+??pred_neg_init:
+	mov  	esi , [ dest ]	    ; get ptr to dest
+	mov	ebx, 7 * 2
+
+??pred_loop:
+	movzx	eax , [ WORD PTR BFPredNegTable + ebx ]
+	add	eax , [ (GraphicViewPort esi) . GVPWidth ]	; add width
+	add	eax , [ (GraphicViewPort esi) . GVPXAdd ]	; add x add
+	add	eax , [ (GraphicViewPort esi) . GVPPitch ]	; extra pitch of DD surface	ST - 9/29/95 1:08PM
+	mov	[ WORD PTR BFPredNegTable + 16 + ebx ] , ax
+	dec	ebx
+	dec	ebx
+	jge	??pred_loop
+
+	;--------------------------------------------------------------------
+	; SHAPE_PARTIAL: DWORD partial_pred_value (0-255)
+	;--------------------------------------------------------------------
+??check_partial:
+	test	[ flags ] , SHAPE_PARTIAL		; is this a partial pred?
+	jz	??setupfunc
+
+	mov	eax , [ flags + edi ]		; pull the partial value
+	add	edi , 4				; next argument
+	and	eax , 0ffh			; make sure 0-255
+	mov	[ BFPartialPred ] , eax		; store it off
+
+??setupfunc:
+	mov	ebx , [ jflags ]		; load flags value
+	and	ebx , FLAG_MASK			; clip high bits
+	add	ebx , ebx			; mult by 4 to get DWORD offset
+	add	ebx , ebx
+	mov	ebx , [ BufferFrameTable + ebx ]	; get table value
+	mov	[ BufferFrameRout ] , ebx		; store it in the function pointer
+
+; Clip dest Rectangle against source Window boundaries.
+
+	mov	[ scr_x ] , 0
+	mov	[ scr_y ] , 0
+	mov  	esi , [ dest ]	    ; get ptr to dest
+	xor 	ecx , ecx
+	xor 	edx , edx
+	mov	edi , [ (GraphicViewPort esi) . GVPWidth ]  ; get width into register
+	mov	ebx , [ x_pixel ]
+	mov	eax , [ x_pixel ]
+	add	ebx , [ pixel_width ]
+	shld	ecx , eax , 1
+	mov	[ x1_pixel ] , ebx
+	inc	edi
+	shld	edx , ebx , 1
+	sub	eax , edi
+	sub	ebx , edi
+	shld	ecx , eax , 1
+	shld	edx , ebx , 1
+
+	mov	edi,[ ( GraphicViewPort esi) . GVPHeight ] ; get height into register
+	mov	ebx , [ y_pixel ]
+	mov	eax , [ y_pixel ]
+	add	ebx , [ pixel_height ]
+	shld	ecx , eax , 1
+	mov	[ y1_pixel ] , ebx
+	inc	edi
+	shld	edx , ebx , 1
+	sub	eax , edi
+	sub	ebx , edi
+	shld	ecx , eax , 1
+	shld	edx , ebx , 1
+
+	xor	cl , 5
+	xor	dl , 5
+	mov	al , cl
+	test	dl , cl
+	jnz	??real_out
+
+	or	al , dl
+	jz	??do_blit
+
+	mov	[use_old_draw],1
+	test	cl , 1000b
+	jz	??dest_left_ok
+
+	mov	eax , [ x_pixel ]
+	neg	eax
+	mov	[ x_pixel ] , 0
+	mov	[ scr_x ] , eax
+
+??dest_left_ok:
+	test	cl , 0010b
+	jz	??dest_bottom_ok
+
+	mov	eax , [ y_pixel ]
+	neg	eax
+	mov	[ y_pixel ] , 0
+	mov	[ scr_y ] , eax
+
+??dest_bottom_ok:
+	test	dl , 0100b
+	jz	??dest_right_ok
+
+	mov	eax , [ (GraphicViewPort esi) . GVPWidth ]  ; get width into register
+	mov	[ x1_pixel ] , eax
+
+??dest_right_ok:
+	test	dl , 0001b
+	jz	??do_blit
+
+	mov	eax , [ (GraphicViewPort esi) . GVPHeight ]  ; get width into register
+	mov	[ y1_pixel ] , eax
+
+??do_blit:
+	cld
+	mov	eax , [ (GraphicViewPort esi) . GVPXAdd ]
+	add	eax , [ (GraphicViewPort esi) . GVPPitch ]
+	add	eax , [ (GraphicViewPort esi) . GVPWidth ]
+	mov	edi , [ (GraphicViewPort esi) . GVPOffset ]
+
+	mov	ecx , eax
+	mul	[ y_pixel ]
+	add	edi , [ x_pixel ]
+	add	edi , eax
+
+	add	ecx , [ x_pixel ]
+	sub	ecx , [ x1_pixel ]
+	mov	[ dest_adjust_width ] , ecx
+
+	mov	esi , [ src ]
+	mov	eax , [ pixel_width ]
+	sub	eax , [ x1_pixel ]
+	add	eax , [ x_pixel ]
+	mov	[ scr_adjust_width ] , eax
+
+	mov	eax , [ scr_y ]
+	mul	[ pixel_width ]
+	add	eax , [ scr_x ]
+	add	esi , eax
+
+;
+; If the shape needs to be clipped then we cant handle it with the new header systen
+; so draw it with the old shape drawer
+;
+	cmp	[use_old_draw],0
+	jnz	??use_old_stuff
+
+	add	[header_pointer],size ShapeHeaderType
+	mov	edx,[pixel_height]
+	mov	ecx,[pixel_width]
+	mov	eax,[header_pointer]
+	mov	al,[eax]
+	mov	[save_ecx],ecx
+	inc	[header_pointer]
+	and	eax,BLIT_ALL
+	shl	eax,2
+	add	eax,[ShapeJumpTableAddress]
+	jmp	[dword eax]
+
+
+??use_old_stuff:
+	mov	edx , [ y1_pixel ]
+	mov	eax , [ x1_pixel ]
+
+	sub	edx , [ y_pixel ]
+	jle	??real_out
+
+	sub	eax , [ x_pixel ]
+	jle	??real_out
+
+	jmp	[ BufferFrameRout ]	; buffer frame to viewport routine
+
+??real_out:
+	epilogue
+
+	ret
+
+
+; ********************************************************************
+; Forward bitblit only
+; the inner loop is so efficient that
+; the optimal consept no longer apply because
+; the optimal byte have to by a number greather than 9 bytes
+; ********************************************************************
+global	BF_Copy:near
+
+BF_Copy:
+	prologue
+	cmp	eax , 10
+	jl	??forward_loop_bytes
+
+??forward_loop_dword:
+	mov	ecx , edi
+	mov	ebx , eax
+	neg	ecx
+	and	ecx , 3
+	sub	ebx , ecx
+	rep	movsb
+	mov	ecx , ebx
+	shr	ecx , 2
+	rep	movsd
+	mov	ecx , ebx
+	and	ecx , 3
+	rep	movsb
+
+	add	esi , [ scr_adjust_width ]
+	add	edi , [ dest_adjust_width ]
+	dec	edx
+	jnz	??forward_loop_dword
+
+	ret
+
+??forward_loop_bytes:
+	mov	ecx , eax
+	rep	movsb
+	add	esi , [ scr_adjust_width ]
+	add	edi , [ dest_adjust_width ]
+	dec	edx					; decrement the height
+	jnz	??forward_loop_bytes
+	epilogue
+
+	ret
+
+
+;********************************************************************
+;********************************************************************
+
+		segment code page public use32 'code'	; Need stricter segment alignment
+							; for pentium optimisations
+
+
+;*****************************************************************************
+; Draw a single line with transparent pixels
+;
+; 11/29/95 10:21AM - ST
+;
+		align	32
+
+Single_Line_Trans:
+		prologue
+??slt_mask_map_lp:				; Pentium pipeline usage
+						;Pipe	Cycles
+		mov	al,[esi]		;U	1
+		inc	esi			;Vee	1
+
+		test	al,al			;U	1
+		jz	??slt_skip		;Vee	1/5
+
+??slt_not_trans:mov	[edi],al		;u 	1
+
+		inc	edi			;vee	1
+		dec	ecx			;u	1
+
+		jnz	??slt_mask_map_lp	;vee  (maybe)	1
+
+??slt_end_line:	epilogue
+		next_line
+
+		align	32
+
+??slt_skip:	inc	edi
+		dec	ecx
+		jz	??slt_skip_end_line
+
+		mov	al,[esi]
+		inc	esi
+		test	al,al
+		jz	??slt_skip2
+		mov	[edi],al
+		inc	edi
+		dec	ecx
+		jnz	??slt_mask_map_lp
+
+		epilogue
+		next_line
+
+		align	32
+
+??slt_skip2:	inc	edi
+		dec	ecx
+		jz	??slt_end_line
+
+;
+; If we have hit two transparent pixels in a row then we go into
+; the transparent optimised bit
+;
+??slt_round_again:
+	rept	64
+		mov	al,[esi]   ;	;pipe 1
+		inc	esi	   ;1	;pipe 2
+		test	al,al	   ;	;pipe 1
+		jnz	??slt_not_trans;pipe 2 (not pairable in 1)
+				   ;2
+		inc	edi	   ;	;pipe 1
+		dec	ecx	   ;3	;pipe 2
+		jz	??slt_end_line ;4	;pipe 1 (not pairable)
+	endm			   ; best case is 4 cycles per iteration
+		jmp	??slt_round_again
+
+
+
+??slt_skip_end_line:
+		epilogue
+		next_line
+
+
+
+;*****************************************************************************
+; Draw a single line with no transparent pixels
+;
+; 11/29/95 10:21AM - ST
+;
+; We have to align the destination for cards that dont bankswitch correctly
+; when you write non-aligned data.
+;
+		align	32
+Long_Single_Line_Copy:
+		prologue
+
+ rept 3
+		test	edi,3
+		jz	??LSLC_aligned
+		movsb
+		dec	ecx
+ endm
+
+??LSLC_aligned:
+		mov	ebx,ecx
+
+		shr	ecx,2
+		rep	movsd
+		and	ebx,3
+		jz	??out
+		movsb
+		dec	bl
+		jz	??out
+		movsb
+		dec	bl
+		jz	??out
+		movsb
+??out:		epilogue
+		next_line
+
+
+
+;*****************************************************************************
+; Draw a single short line with no transparent pixels
+;
+; 11/29/95 10:21AM - ST
+;
+		align	32
+Short_Single_Line_Copy:
+		prologue
+		cmp	ecx,16
+		jge	Long_Single_Line_Copy
+		mov	ebx,ecx
+		rep	movsb
+		mov	ecx,ebx
+		epilogue
+		next_line
+
+
+;*****************************************************************************
+; Skip a line of source that is all transparent
+;
+; 11/29/95 10:21AM - ST
+;
+
+		align	32
+Single_Line_Skip:
+		prologue
+		add	esi,ecx
+		add	edi,ecx
+		epilogue
+		next_line
+
+
+
+;*****************************************************************************
+; Draw a single line with ghosting
+;
+; 11/29/95 10:21AM - ST
+;
+		align	32
+Single_Line_Ghost:
+
+		prologue
+		xor	eax,eax
+??slg_loop:	mov	al,[esi]
+		mov	ebx,[IsTranslucent]
+		inc	esi
+		mov	bh,[eax+ebx]
+		cmp	bh,-1
+		jz	??slg_store_pixel
+
+		and	ebx,0ff00h
+		mov	al,[edi]
+		add	ebx,[Translucent]
+		mov	al,[eax+ebx]
+
+??slg_store_pixel:
+		mov	[edi],al
+
+		inc	edi
+		dec	ecx
+		jnz	??slg_loop
+		epilogue
+		next_line
+
+
+
+;*****************************************************************************
+; Draw a single line with transparent pixels and ghosting
+;
+; 11/29/95 10:21AM - ST
+;
+		align	32
+Single_Line_Ghost_Trans:
+		prologue
+		xor	eax,eax
+;		cmp	ecx,3
+;		ja	??slgt4
+
+??slgt_loop:	mov	al,[esi]
+		inc	esi
+		test	al,al
+		jz	??slgt_transparent
+
+??slgt_not_transparent:
+		mov	ebx,[IsTranslucent]
+		mov	bh,[eax+ebx]
+		cmp	bh,-1
+		jz	??slgt_store_pixel
+
+		and	ebx,0ff00h
+		mov	al,[edi]
+		add	ebx,[Translucent]
+		mov	al,[eax+ebx]
+
+??slgt_store_pixel:
+		mov	[edi],al
+		inc	edi
+		dec	ecx
+		jnz	??slgt_loop
+		epilogue
+		next_line
+
+
+		align	32
+
+??slgt_transparent:
+		inc	edi		;1
+		dec	ecx		;2
+		jz	??slgt_out	;1 (not pairable)
+
+??slgt_round_again:
+	rept	64
+		mov	al,[esi]   ;	;pipe 1
+		inc	esi	   ;1	;pipe 2
+		test	al,al	   ;	;pipe 1
+		jnz	??slgt_not_transparent	;pipe 2 (not pairable in 1)
+				   ;2
+		inc	edi	   ;	;pipe 1
+		dec	ecx	   ;3	;pipe 2
+		jz	??slgt_out ;4	;pipe 1 (not pairable)
+	endm			   ; best case is 4 cycles per iteration
+		jmp	??slgt_round_again
+
+??slgt_out:	epilogue
+		next_line
+
+
+
+;
+; Optimised video memory access version
+;
+		align 	32
+
+??slgt4:        push	edx
+		mov	edx,[edi]
+
+	rept	4
+	local	slgt4_store1
+	local	slgt4_trans1
+		mov	al,[esi]
+		inc	esi
+		test	al,al
+		jz	slgt4_trans1
+
+		mov	ebx,[IsTranslucent]
+		mov	bh,[eax+ebx]
+		cmp	bh,-1
+		jz	slgt4_store1
+
+		and	ebx,0ff00h
+		mov	al,dl
+		add	ebx,[Translucent]
+		mov	al,[eax+ebx]
+
+slgt4_store1:	mov	dl,al
+
+slgt4_trans1:	ror	edx,8
+	endm
+		mov	[edi],edx
+		pop	edx
+		lea	edi,[edi+4]
+		lea	ecx,[ecx+0fffffffch]
+		cmp	ecx,3
+		ja	??slgt4
+		test	ecx,ecx
+		jnz	??slgt_loop
+
+		epilogue
+		next_line
+
+
+
+
+
+
+
+
+
+
+;*****************************************************************************
+; Draw a single line with fading (colour remapping)
+;
+; 11/29/95 10:21AM - ST
+;
+		align	32
+
+Single_Line_Fading:
+		prologue
+		xor	eax,eax
+		mov	ebx,[FadingTable]
+		push	ebp
+		mov	ebp,[FadingNum]
+		push	ebp
+
+??slf_loop:	mov	al,[esi]
+		inc	esi
+
+		mov	ebp,[esp]
+
+??slf_fade_loop:mov	al,[ebx+eax]
+		dec	ebp
+		jnz	??slf_fade_loop
+
+		mov	[edi],al
+		inc	edi
+
+		dec	ecx
+		jnz	??slf_loop
+		add	esp,4
+		pop	ebp
+		epilogue
+		next_line
+
+
+;*****************************************************************************
+; Draw a single line with transparent pixels and fading (colour remapping)
+;
+; 11/29/95 10:21AM - ST
+;
+		align	32
+
+Single_Line_Fading_Trans:
+		prologue
+		xor	eax,eax
+		mov	ebx,[FadingTable]
+		push	ebp
+		mov	ebp,[FadingNum]
+		push	ebp
+
+??slft_loop:	mov	al,[esi]
+		inc	esi
+		test	al,al
+		jz	??slft_transparent
+
+		mov	ebp,[esp]
+
+??slft_fade_loop:
+		mov	al,[ebx+eax]
+		dec	ebp
+		jnz	??slft_fade_loop
+
+		mov	[edi],al
+??slft_transparent:
+		inc	edi
+
+		dec	ecx
+		jnz	??slft_loop
+		add	esp,4
+		pop	ebp
+		epilogue
+		next_line
+
+
+
+
+
+;*****************************************************************************
+; Draw a single line with a single fade level (colour remap)
+;
+; 11/29/95 10:21AM - ST
+;
+		align	32
+
+Single_Line_Single_Fade:
+		prologue
+		xor	eax,eax
+		mov	ebx,[FadingTable]
+
+??slsf_loop:	mov	al,[esi]
+		mov	al,[ebx+eax]
+		mov	[edi],al
+		inc	esi
+		inc	edi
+
+		dec	ecx
+		jnz	??slsf_loop
+		epilogue
+		next_line
+
+
+
+;*****************************************************************************
+; Draw a single line with transparent pixels and a single fade level (colour remap)
+;
+; 11/29/95 10:21AM - ST
+;
+		align	32
+
+Single_Line_Single_Fade_Trans:
+		prologue
+		xor	eax,eax
+		mov	ebx,[FadingTable]
+
+??slsft_loop:	mov	al,[esi]
+		inc	esi
+		test	al,al
+		jz	??slsft_transparent
+		mov	al,[ebx+eax]
+		mov	[edi],al
+		inc	edi
+		dec	ecx
+		jnz	??slsft_loop
+		epilogue
+		next_line
+
+		align	32
+
+??slsft_transparent:
+		inc	edi
+
+		dec	ecx
+		jz	??slsft_next_line
+		mov	al,[esi]
+		inc	esi
+		test	al,al
+		jz	??slsft_transparent
+		mov	al,[ebx+eax]
+		mov	[edi],al
+		inc	edi
+		dec	ecx
+		jnz	??slsft_loop
+
+??slsft_next_line:
+		epilogue
+		next_line
+
+
+
+
+
+;*****************************************************************************
+; Draw a single line with ghosting and fading (colour remapping)
+;
+; 11/29/95 10:21AM - ST
+;
+		align	32
+
+Single_Line_Ghost_Fading:
+
+		prologue
+		mov	[StashECX],ecx
+
+??SLGF_loop:	xor	eax,eax
+		mov	al,[esi]
+		mov	ebx,[IsTranslucent]
+		mov	bh,[eax+ebx]
+		cmp	bh,-1
+		jz	??slgf_do_fading
+
+		and	ebx,0ff00h
+
+		mov	al,[edi]
+		add	ebx,[Translucent]
+		mov	al,[ebx+eax]
+
+??slgf_do_fading:
+		mov	ebx,[FadingTable]
+		mov	ecx,[FadingNum]
+
+??slgf_fade_loop:
+		mov	al,[eax+ebx]
+		dec	ecx
+		jnz	??slgf_fade_loop
+
+		mov	[edi],al
+		inc	esi
+		inc	edi
+
+		dec	[StashECX]
+		jnz	??SLGF_loop
+		epilogue
+		next_line
+
+
+;*****************************************************************************
+; Draw a single line with transparent pixels, ghosting and fading
+;
+; 11/29/95 10:21AM - ST
+;
+		align	32
+
+Single_Line_Ghost_Fading_Trans:
+		prologue
+		mov	[StashECX],ecx
+		xor	eax,eax
+
+;		cmp	ecx,3
+;		ja	??slgft4
+
+??SLGFT_loop:	mov	al,[esi]
+		inc	esi
+		test	al,al
+		jz	??slgft_trans_pixel
+		mov	ebx,[IsTranslucent]
+		mov	bh,[eax+ebx]
+		cmp	bh,-1
+		jz	??slgft_do_fading
+
+		and	ebx,0ff00h
+
+		mov	al,[edi]
+		add	ebx,[Translucent]
+		mov	al,[ebx+eax]
+
+??slgft_do_fading:
+		mov	ebx,[FadingTable]
+		mov	ecx,[FadingNum]
+
+??slgft_fade_loop:
+		mov	al,[eax+ebx]
+		dec	ecx
+		jnz	??slgft_fade_loop
+
+		mov	[edi],al
+??slgft_trans_pixel:
+		inc	edi
+
+		dec	[StashECX]
+		jnz	??SLGFT_loop
+		epilogue
+		next_line
+
+
+		align	32
+
+??slgft4:	push	edx
+		mov	edx,[edi]
+
+	rept	4
+	local	slgft4_fade
+	local	slgft4_fade_lp
+	local	slgft4_trans
+		mov	al,[esi]
+		inc	esi
+		test	al,al
+		jz	slgft4_trans
+		mov	ebx,[IsTranslucent]
+		mov	bh,[eax+ebx]
+		cmp	bh,-1
+		jz	slgft4_fade
+
+		and	ebx,0ff00h
+
+		mov	al,dl
+		add	ebx,[Translucent]
+		mov	al,[ebx+eax]
+
+slgft4_fade:	mov	ebx,[FadingTable]
+		mov	ecx,[FadingNum]
+
+slgft4_fade_lp:	mov	al,[eax+ebx]
+		dec	ecx
+		jnz	slgft4_fade_lp
+
+		mov	dl,al
+
+slgft4_trans:	ror	edx,8
+	endm
+		mov	[edi],edx
+		pop	edx
+		lea	edi,[edi+4]
+		sub	[StashECX],4
+		jz	??slgft4_out
+		cmp	[StashECX],3
+		ja	??slgft4
+		jmp	??SLGFT_loop
+
+??slgft4_out:	epilogue
+		next_line
+
+
+;*****************************************************************************
+; Draw a single line with predator effect
+;
+; 11/29/95 10:21AM - ST
+;
+		align	32
+
+Single_Line_Predator:
+
+		prologue
+
+??slp_loop:	mov	al,[esi]
+
+		mov	ebx,[BFPartialCount]
+		add	ebx,[BFPartialPred]
+		or	bh,bh
+		jnz	??slp_get_pred
+
+		mov	[BFPartialCount] , ebx
+		jmp	??slp_skip_pixel
+
+??slp_get_pred:	xor	bh , bh
+		mov	eax,[BFPredOffset]
+		mov	[BFPartialCount] , ebx
+		add	[BYTE BFPredOffset],2
+		mov	eax,[DWORD BFPredTable+eax]
+		and	[BYTE BFPredOffset],PRED_MASK
+		and	eax,0ffffh
+
+		mov	al,[edi+eax]
+		mov	[edi],al
+
+??slp_skip_pixel:
+		inc	esi
+		inc	edi
+
+		dec	ecx
+		jnz	??slp_loop
+
+		epilogue
+		next_line
+
+
+
+
+;*****************************************************************************
+; Draw a single line with transparent pixels and predator effect
+;
+; 11/29/95 10:21AM - ST
+;
+		align	32
+
+Single_Line_Predator_Trans:
+
+		prologue
+
+??slpt_loop:	mov	al,[esi]
+		inc	esi
+		test	al,al
+		jz	??slpt_skip_pixel
+
+		mov	ebx,[BFPartialCount]
+		add	ebx,[BFPartialPred]
+		or	bh,bh
+		jnz	??slpt_get_pred
+
+		mov	[BFPartialCount] , ebx
+		jmp	??slpt_skip_pixel
+
+??slpt_get_pred:xor	bh , bh
+		mov	eax,[BFPredOffset]
+		mov	[BFPartialCount] , ebx
+		add	[BYTE BFPredOffset],2
+		mov	eax,[DWORD BFPredTable+eax]
+		and	[BYTE PTR BFPredOffset ] , PRED_MASK
+		and	eax,0ffffh
+
+		mov	al,[edi+eax]
+		mov	[edi],al
+
+??slpt_skip_pixel:
+		inc	edi
+
+		dec	ecx
+		jnz	??slpt_loop
+
+		epilogue
+		next_line
+
+
+;*****************************************************************************
+; Draw a single line with predator and ghosting
+;
+; 11/29/95 10:21AM - ST
+;
+		align	32
+
+Single_Line_Predator_Ghost:
+
+		prologue
+
+??slpg_loop:	mov	al,[esi]
+		mov	ebx,[BFPartialCount]
+		add	ebx,[BFPartialPred]
+		test	bh,bh
+		jnz	??slpg_get_pred		; is this a predator pixel?
+
+		mov	[BFPartialCount],ebx
+		jmp	??slpg_check_ghost
+
+??slpg_get_pred:
+		xor	bh,bh
+		mov	eax,[BFPredOffset]
+		mov	[BFPartialCount],ebx
+		add	[BYTE BFPredOffset],2
+		mov	eax,[DWORD BFPredTable+eax ]
+		and	[BYTE BFPredOffset],PRED_MASK
+		and	eax,0ffffh
+		mov	al,[edi+eax]
+
+??slpg_check_ghost:
+		mov	ebx,[IsTranslucent]
+		mov	bh,[ebx+eax]
+		cmp	bh,0ffh
+		je	??slpg_store_pixel
+
+		xor	eax,eax
+		and	ebx,0FF00h
+
+		mov	al,[edi]
+		add	ebx,[Translucent]
+
+		mov	al,[ebx+eax]
+
+??slpg_store_pixel:
+		mov	[edi],al
+		inc	esi
+		inc	edi
+
+		dec	ecx
+		jnz	??slpg_loop
+
+		epilogue
+		next_line
+
+
+
+;*****************************************************************************
+; Draw a single line with transparent pixels, predator and ghosting
+;
+; 11/29/95 10:21AM - ST
+;
+		align	32
+
+Single_Line_Predator_Ghost_Trans:
+		prologue
+
+??slpgt_loop:	mov	al,[esi]
+		inc	esi
+		test	al,al
+		jz	??slpgt_transparent
+
+		mov	ebx,[BFPartialCount]
+		add	ebx,[BFPartialPred]
+		test	bh,bh
+		jnz	??slpgt_get_pred		; is this a predator pixel?
+
+		mov	[BFPartialCount],ebx
+		jmp	??slpgt_check_ghost
+
+??slpgt_get_pred:
+		xor	bh,bh
+		mov	eax,[BFPredOffset]
+		mov	[BFPartialCount],ebx
+		add	[BYTE BFPredOffset],2
+		mov	eax,[DWORD BFPredTable+eax ]
+		and	[BYTE BFPredOffset],PRED_MASK
+		and	eax,0ffffh
+		mov	al,[edi+eax]
+
+??slpgt_check_ghost:
+		mov	ebx,[IsTranslucent]
+		mov	bh,[ebx+eax]
+		cmp	bh,0ffh
+		je	??slpgt_store_pixel
+
+		xor	eax,eax
+		and	ebx,0FF00h
+
+		mov	al,[edi]
+		add	ebx,[Translucent]
+
+		mov	al,[ebx+eax]
+
+??slpgt_store_pixel:
+		mov	[edi],al
+??slpgt_transparent:
+		inc	edi
+
+		dec	ecx
+		jnz	??slpgt_loop
+
+		pop	ecx
+		epilogue
+		next_line
+
+
+;*****************************************************************************
+; Draw a single line with predator and fading
+;
+; 11/29/95 10:21AM - ST
+;
+		align	32
+
+Single_Line_Predator_Fading:
+
+		prologue
+		mov	[StashECX],ecx
+
+??slpf_loop:	mov	al,[esi]
+		mov	ebx,[BFPartialCount]
+		inc	esi
+		add	ebx,[BFPartialPred]
+		test	bh,bh
+		jnz	??slpf_get_pred
+
+		mov	[BFPartialCount],ebx
+		jmp	??slpf_do_fading
+
+??slpf_get_pred:xor	bh,bh
+		mov	eax,[BFPredOffset]
+		mov	[BFPartialCount],ebx
+		and	[BYTE BFPredOffset],2
+		mov	eax,[DWORD BFPredTable+eax]
+		and	[BYTE BFPredOffset],PRED_MASK
+
+		and	eax,0ffffh
+		mov	al,[eax+edi]
+
+??slpf_do_fading:
+		and	eax,255
+		mov	ebx,[FadingTable]
+		mov	ecx,[FadingNum]
+
+??slpf_fade_loop:
+		mov	al,[eax+ebx]
+		dec	ecx
+		jnz	??slpf_fade_loop
+
+		mov	[edi],al
+		inc	edi
+
+		dec	[StashECX]
+		jnz	??slpf_loop
+
+		epilogue
+		next_line
+
+
+
+;*****************************************************************************
+; Draw a single line with transparent pixels, fading and predator
+;
+; 11/29/95 10:21AM - ST
+;
+		align	32
+
+Single_Line_Predator_Fading_Trans:
+		prologue
+		mov	[StashECX],ecx
+
+??slpft_loop:	mov	al,[esi]
+		inc	esi
+		test	al,al
+		jz	??slpft_transparent
+		mov	ebx,[BFPartialCount]
+		add	ebx,[BFPartialPred]
+		test	bh,bh
+		jnz	??slpft_get_pred
+
+		mov	[BFPartialCount],ebx
+		jmp	??slpft_do_fading
+
+??slpft_get_pred:
+		xor	bh,bh
+		mov	eax,[BFPredOffset]
+		mov	[BFPartialCount],ebx
+		and	[BYTE BFPredOffset],2
+		mov	eax,[DWORD BFPredTable+eax]
+		and	[BYTE BFPredOffset],PRED_MASK
+
+		and	eax,0ffffh
+		mov	al,[eax+edi]
+
+??slpft_do_fading:
+		and	eax,255
+		mov	ebx,[FadingTable]
+		mov	ecx,[FadingNum]
+
+??slpft_fade_loop:
+		mov	al,[eax+ebx]
+		dec	ecx
+		jnz	??slpft_fade_loop
+
+		mov	[edi],al
+??slpft_transparent:
+		inc	edi
+
+		dec	[StashECX]
+		jnz	??slpft_loop
+
+		epilogue
+		next_line
+
+
+
+;*****************************************************************************
+; Draw a single line with predator, ghosting and fading
+;
+; 11/29/95 10:21AM - ST
+;
+		align	32
+
+Single_Line_Predator_Ghost_Fading:
+
+		prologue
+		mov	[StashECX],ecx
+
+??slpgf_loop:	mov	al,[esi]
+		mov	ebx,[BFPartialCount]
+		inc	esi
+		add	ebx,[BFPartialPred]
+		test	bh , bh
+		jnz	??slpgf_get_pred		; is this a predator pixel?
+
+		mov	[BFPartialCount],ebx
+		jmp	??slpgf_check_ghost
+
+??slpgf_get_pred:
+		xor	bh,bh
+		mov	eax,[BFPredOffset]
+		mov	[BFPartialCount],ebx
+		add	[BYTE BFPredOffset],2
+		mov	eax,[DWORD BFPredTable+eax]
+		and	[BYTE BFPredOffset],PRED_MASK
+		and	eax,0ffffh
+
+		mov	al,[edi+eax]
+
+??slpgf_check_ghost:
+		and	eax,255
+		mov	ebx,[IsTranslucent]
+		mov	bh,[ebx+eax]
+		cmp	bh,0ffh
+		je	??slpgf_do_fading
+
+		and	ebx , 0FF00h
+
+		mov	al,[edi]
+		add	ebx,[Translucent]
+
+		mov	al,[ebx+eax]
+
+??slpgf_do_fading:
+		xor	eax,eax
+		mov	ebx,[FadingTable]
+		mov	ecx,[FadingNum]
+
+??slpgf_fade_loop:
+		mov	al,[ebx+eax]
+		dec	ecx
+		jnz	??slpgf_fade_loop
+
+??slpgf_store_pixel:
+		mov	[edi],al
+		inc	edi
+
+		dec	[StashECX]
+		jnz	??slpgf_loop
+
+		epilogue
+		next_line
+
+
+
+;*****************************************************************************
+; Draw a single line with transparent pixels, predator, ghosting and fading
+;
+; 11/29/95 10:21AM - ST
+;
+		align	32
+
+Single_Line_Predator_Ghost_Fading_Trans:
+
+		prologue
+		mov	[StashECX],ecx
+
+??slpgft_loop:	mov	al,[esi]
+		inc	esi
+		test	al,al
+		jz	??slpgft_transparent
+
+		mov	ebx,[BFPartialCount]
+		add	ebx,[BFPartialPred]
+		test	bh , bh
+		jnz	??slpgft_get_pred		; is this a predator pixel?
+
+		mov	[BFPartialCount],ebx
+		jmp	??slpgft_check_ghost
+
+??slpgft_get_pred:
+		xor	bh,bh
+		mov	eax,[BFPredOffset]
+		mov	[BFPartialCount],ebx
+		add	[BYTE BFPredOffset],2
+		mov	eax,[DWORD BFPredTable+eax]
+		and	[BYTE BFPredOffset],PRED_MASK
+		and	eax,0ffffh
+
+		mov	al,[edi+eax]
+
+??slpgft_check_ghost:
+		and	eax,255
+		mov	ebx,[IsTranslucent]
+		mov	bh,[ebx+eax]
+		cmp	bh,0ffh
+		je	??slpgft_do_fading
+
+		and	ebx , 0FF00h
+
+		mov	al,[edi]
+		add	ebx,[Translucent]
+
+		mov	al,[ebx+eax]
+
+??slpgft_do_fading:
+		xor	eax,eax
+		mov	ebx,[FadingTable]
+		mov	ecx,[FadingNum]
+
+??slpgft_fade_loop:
+		mov	al,[ebx+eax]
+		dec	ecx
+		jnz	??slpgft_fade_loop
+
+??slpgft_store_pixel:
+		mov	[edi],al
+??slpgft_transparent:
+		inc	edi
+
+		dec	[StashECX]
+		jnz	??slpgft_loop
+
+		epilogue
+		next_line
+
+
+
+
+		ends		;end of strict alignment segment
+
+	       	codeseg
+
+
+
+global	BF_Trans:near
+
+BF_Trans:
+
+	prologue
+; calc the code location to skip to 10 bytes per REPT below!!!!
+	mov	ecx , eax
+	and	ecx , 01fh
+	lea	ecx , [ ecx + ecx * 4 ]		; quick multiply by 5
+	neg	ecx
+	shr	eax , 5
+	lea	ecx , [ ??trans_reference + ecx * 2 ] ; next multiply by 2
+	mov	[ loop_cnt ] , eax
+	mov	[ jmp_loc ] , ecx
+
+??trans_loop:
+	mov	ecx , [ loop_cnt ]
+	jmp	[ jmp_loc ]
+
+; the following code should NOT be changed without changing the calculation
+; above!!!!!!
+
+??trans_line:
+
+	REPT	32
+	local	trans_pixel
+		mov	bl , [ esi ]
+		inc	esi
+		test	bl , bl
+		jz	trans_pixel
+
+		mov	[ edi ] , bl
+
+	trans_pixel:
+		inc	edi
+	ENDM
+
+??trans_reference:
+	dec	ecx
+	jge	??trans_line
+
+	add	esi , [ scr_adjust_width ]
+	add	edi , [ dest_adjust_width ]
+	dec	edx
+	jnz	??trans_loop
+	epilogue
+
+	ret
+
+;********************************************************************
+;********************************************************************
+
+global	BF_Ghost:near
+BF_Ghost:
+
+	prologue
+	mov	ebx , eax			; width
+
+	; NOTE: the below calculation assumes a group of instructions is
+	;	less than 256 bytes
+
+	; get length of the 32 groups of instructions
+
+	lea	ecx , [ ??ghost_reference - ??ghost_line ]
+
+	shr	ebx , 5				; width / 32
+	shr	ecx , 5				; length of instructions / 32
+	and	eax , 01fh			; mod of width / 32
+	mul	cl				; calc offset to start of group
+	neg	eax				; inverse of width
+	mov	[ loop_cnt ] , ebx		; save width / 32
+	lea	ecx , [ ??ghost_reference + eax ]
+	mov	eax , 0
+	mov	[ jmp_loc ] , ecx
+
+??ghost_loop:
+	mov	ecx , [ loop_cnt ]
+	jmp	[ jmp_loc ]
+
+??ghost_line:
+
+	REPT	32
+	local	store_pixel
+		mov	al , [ esi ]
+		inc	esi
+		mov	ebx , [ IsTranslucent ]		; is it a translucent color?
+		mov	bh , [ BYTE PTR ebx + eax ]
+		cmp	bh , 0ffh
+		je	store_pixel
+
+		and	ebx , 0FF00h			; clear all of ebx except bh
+							; we have the index to the translation table
+							; ((trans_colour * 256) + dest colour)
+		mov	al , [ edi ]			; mov pixel at destination to al
+		add	ebx , [ Translucent ]		; get the ptr to it!
+							; Add the (trans_color * 256) of the translation equ.
+		mov	al , [ BYTE PTR ebx + eax ]	; get new pixel in al
+
+	store_pixel:
+		mov	[ edi ] , al
+		inc	edi
+
+	ENDM
+
+??ghost_reference:
+	dec	ecx
+	jge	??ghost_line
+
+	add	esi , [ scr_adjust_width ]
+	add	edi , [ dest_adjust_width ]
+	dec	edx
+	jnz	??ghost_loop
+
+	epilogue
+	ret
+
+
+;********************************************************************
+;********************************************************************
+
+global	BF_Ghost_Trans:near
+BF_Ghost_Trans:
+
+	prologue
+	mov	ebx , eax			; width
+
+	; NOTE: the below calculation assumes a group of instructions is
+	;	less than 256 bytes
+
+	; get length of the 32 groups of instructions
+
+	lea	ecx , [ ??ghost_t_reference - ??ghost_t_line ]
+
+	shr	ebx , 5				; width / 32
+	shr	ecx , 5				; length of instructions / 32
+	and	eax , 01fh			; mod of width / 32
+	mul	cl				; calc offset to start of group
+	neg	eax				; inverse of width
+	mov	[ loop_cnt ] , ebx		; save width / 32
+	lea	ecx , [ ??ghost_t_reference + eax ]
+	mov	eax , 0
+	mov	[ jmp_loc ] , ecx
+
+??ghost_t_loop:
+	mov	ecx , [ loop_cnt ]
+	jmp	[ jmp_loc ]
+
+??ghost_t_line:
+
+	REPT	32
+	local	transp_pixel
+	local	store_pixel
+		mov	al , [ esi ]
+		inc	esi
+		test	al , al
+		jz	transp_pixel
+
+		mov	ebx , [ IsTranslucent ]		; is it a translucent color?
+		mov	bh , [ BYTE PTR ebx + eax ]
+		cmp	bh , 0ffh
+		je	store_pixel
+
+		and	ebx , 0FF00h			; clear all of ebx except bh
+							; we have the index to the translation table
+							; ((trans_colour * 256) + dest colour)
+		mov	al , [ edi ]			; mov pixel at destination to al
+		add	ebx , [ Translucent ]		; get the ptr to it!
+							; Add the (trans_color * 256) of the translation equ.
+		mov	al , [ BYTE PTR ebx + eax ]	; get new pixel in al
+
+	store_pixel:
+		mov	[ edi ] , al
+
+	transp_pixel:
+		inc	edi
+
+	ENDM
+
+??ghost_t_reference:
+	dec	ecx
+	jge	??ghost_t_line
+
+	add	esi , [ scr_adjust_width ]
+	add	edi , [ dest_adjust_width ]
+	dec	edx
+	jnz	??ghost_t_loop
+
+	epilogue
+	ret
+
+
+;********************************************************************
+;********************************************************************
+
+global	BF_Fading:near
+BF_Fading:
+
+	prologue
+	mov	ebx , eax			; width
+
+	; NOTE: the below calculation assumes a group of instructions is
+	;	less than 256 bytes
+
+	; get length of the 32 groups of instructions
+
+	lea	ecx , [ ??fading_reference - ??fading_line ]
+
+	shr	ebx , 5				; width / 32
+	shr	ecx , 5				; length of instructions / 32
+	and	eax , 01fh			; mod of width / 32
+	mul	cl				; calc offset to start of group
+	neg	eax				; inverse of width
+	mov	[ loop_cnt ] , ebx		; save width / 32
+	lea	ecx , [ ??fading_reference + eax ]
+	mov	eax , 0
+	mov	[ jmp_loc ] , ecx
+
+??fading_loop:
+	mov	ecx , [ loop_cnt ]
+	mov	[ StashECX ] , ecx		; preserve ecx for later
+	mov	ebx , [ FadingTable ]		; run color through fading table
+	jmp	[ jmp_loc ]
+
+??fading_line_begin:
+	mov	[ StashECX ] , ecx		; preserve ecx for later
+
+??fading_line:
+
+	REPT	32
+	local	fade_loop
+		mov	al , [ esi ]
+		inc	esi
+		mov	ecx , [ FadingNum ]
+
+	fade_loop:
+		mov	al, [BYTE PTR ebx + eax]
+		dec	ecx
+		jnz	fade_loop
+
+		mov	[ edi ] , al
+		inc	edi
+
+	ENDM
+
+??fading_reference:
+	mov	ecx , [ StashECX ]		; restore ecx for main draw loop
+	dec	ecx
+	jge	??fading_line_begin
+
+	add	esi , [ scr_adjust_width ]
+	add	edi , [ dest_adjust_width ]
+	dec	edx
+	jnz	??fading_loop
+
+	epilogue
+	ret
+
+
+;********************************************************************
+;********************************************************************
+
+global	BF_Fading_Trans:near
+BF_Fading_Trans:
+
+	prologue
+	mov	ebx , eax			; width
+
+	; NOTE: the below calculation assumes a group of instructions is
+	;	less than 256 bytes
+
+	; get length of the 32 groups of instructions
+
+	lea	ecx , [ ??fading_t_reference - ??fading_t_line ]
+
+	shr	ebx , 5				; width / 32
+	shr	ecx , 5				; length of instructions / 32
+	and	eax , 01fh			; mod of width / 32
+	mul	cl				; calc offset to start of group
+	neg	eax				; inverse of width
+	mov	[ loop_cnt ] , ebx		; save width / 32
+	lea	ecx , [ ??fading_t_reference + eax ]
+	mov	eax , 0
+	mov	[ jmp_loc ] , ecx
+
+??fading_t_loop:
+	mov	ecx , [ loop_cnt ]
+	mov	[ StashECX ] , ecx		; preserve ecx for later
+	mov	ebx , [ FadingTable ]		; run color through fading table
+	jmp	[ jmp_loc ]
+
+??fading_t_line_begin:
+	mov	[ StashECX ] , ecx		; preserve ecx for later
+
+??fading_t_line:
+
+	REPT	32
+	local	transp_pixel
+	local	fade_loop
+		mov	al , [ esi ]
+		inc	esi
+		test	al , al
+		jz	transp_pixel
+
+		mov	ecx , [ FadingNum ]
+
+	fade_loop:
+		mov	al, [BYTE PTR ebx + eax]
+		dec	ecx
+		jnz	fade_loop
+
+		mov	[ edi ] , al
+
+	transp_pixel:
+		inc	edi
+
+	ENDM
+
+??fading_t_reference:
+	mov	ecx , [ StashECX ]		; restore ecx for main draw loop
+	dec	ecx
+	jge	??fading_t_line_begin
+
+	add	esi , [ scr_adjust_width ]
+	add	edi , [ dest_adjust_width ]
+	dec	edx
+	jnz	??fading_t_loop
+
+	epilogue
+	ret
+
+
+;********************************************************************
+;********************************************************************
+
+global	BF_Ghost_Fading:near
+BF_Ghost_Fading:
+
+	prologue
+	mov	ebx , eax			; width
+
+	; NOTE: the below calculation assumes a group of instructions is
+	;	less than 256 bytes
+
+	; get length of the 32 groups of instructions
+
+	lea	ecx , [ ??ghost_f_reference - ??ghost_f_line ]
+
+	shr	ebx , 5				; width / 32
+	shr	ecx , 5				; length of instructions / 32
+	and	eax , 01fh			; mod of width / 32
+	mul	cl				; calc offset to start of group
+	neg	eax				; inverse of width
+	mov	[ loop_cnt ] , ebx		; save width / 32
+	lea	ecx , [ ??ghost_f_reference + eax ]
+	mov	eax , 0
+	mov	[ jmp_loc ] , ecx
+
+??ghost_f_loop:
+	mov	ecx , [ loop_cnt ]
+	mov	[ StashECX ] , ecx		; preserve ecx for later
+	jmp	[ jmp_loc ]
+
+??ghost_f_line_begin:
+	mov	[ StashECX ] , ecx		; preserve ecx for later
+
+??ghost_f_line:
+
+	REPT	32
+	local	store_pixel
+	local	do_fading
+	local	fade_loop
+		mov	al , [ esi ]
+		inc	esi
+		mov	ebx , [ IsTranslucent ]		; is it a lucent color?
+		mov	bh , [ BYTE PTR ebx + eax ]
+		cmp	bh , 0ffh
+		je	do_fading
+
+		and	ebx , 0FF00h			; clear all of ebx except bh
+							; we have the index to the lation table
+							; ((_colour * 256) + dest colour)
+		mov	al , [ edi ]			; mov pixel at destination to al
+		add	ebx , [ Translucent ]		; get the ptr to it!
+							; Add the (_color * 256) of the lation equ.
+		mov	al , [ BYTE PTR ebx + eax ]	; get new pixel in al
+; DRD		jmp	store_pixel
+
+	do_fading:
+		mov	ebx , [ FadingTable ]		; run color through fading table
+		mov	ecx , [ FadingNum ]
+
+	fade_loop:
+		mov	al, [BYTE PTR ebx + eax]
+		dec	ecx
+		jnz	fade_loop
+
+	store_pixel:
+		mov	[ edi ] , al
+		inc	edi
+
+	ENDM
+
+??ghost_f_reference:
+	mov	ecx , [ StashECX ]		; restore ecx for main draw loop
+	dec	ecx
+	jge	??ghost_f_line_begin
+
+	add	esi , [ scr_adjust_width ]
+	add	edi , [ dest_adjust_width ]
+	dec	edx
+	jnz	??ghost_f_loop
+
+	epilogue
+	ret
+
+
+;********************************************************************
+;********************************************************************
+
+global	BF_Ghost_Fading_Trans:near
+BF_Ghost_Fading_Trans:
+
+	prologue
+	mov	ebx , eax			; width
+
+	; NOTE: the below calculation assumes a group of instructions is
+	;	less than 256 bytes
+
+	; get length of the 32 groups of instructions
+
+	lea	ecx , [ ??ghost_f_t_reference - ??ghost_f_t_line ]
+
+	shr	ebx , 5				; width / 32
+	shr	ecx , 5				; length of instructions / 32
+	and	eax , 01fh			; mod of width / 32
+	mul	cl				; calc offset to start of group
+	neg	eax				; inverse of width
+	mov	[ loop_cnt ] , ebx		; save width / 32
+	lea	ecx , [ ??ghost_f_t_reference + eax ]
+	mov	eax , 0
+	mov	[ jmp_loc ] , ecx
+
+??ghost_f_t_loop:
+	mov	ecx , [ loop_cnt ]
+	mov	[ StashECX ] , ecx		; preserve ecx for later
+	jmp	[ jmp_loc ]
+
+??ghost_f_t_line_begin:
+	mov	[ StashECX ] , ecx		; preserve ecx for later
+
+??ghost_f_t_line:
+
+	REPT	32
+	local	transp_pixel
+	local	store_pixel
+	local	do_fading
+	local	fade_loop
+		mov	al , [ esi ]
+		inc	esi
+		test	al , al
+		jz	transp_pixel
+
+		mov	ebx , [ IsTranslucent ]		; is it a translucent color?
+		mov	bh , [ BYTE PTR ebx + eax ]
+		cmp	bh , 0ffh
+		je	do_fading
+
+		and	ebx , 0FF00h			; clear all of ebx except bh
+							; we have the index to the translation table
+							; ((trans_colour * 256) + dest colour)
+		mov	al , [ edi ]			; mov pixel at destination to al
+		add	ebx , [ Translucent ]		; get the ptr to it!
+							; Add the (trans_color * 256) of the translation equ.
+		mov	al , [ BYTE PTR ebx + eax ]	; get new pixel in al
+; DRD		jmp	store_pixel
+
+	do_fading:
+		mov	ebx , [ FadingTable ]		; run color through fading table
+		mov	ecx , [ FadingNum ]
+
+	fade_loop:
+		mov	al, [BYTE PTR ebx + eax]
+		dec	ecx
+		jnz	fade_loop
+
+	store_pixel:
+		mov	[ edi ] , al
+
+	transp_pixel:
+		inc	edi
+
+	ENDM
+
+??ghost_f_t_reference:
+	mov	ecx , [ StashECX ]		; restore ecx for main draw loop
+	dec	ecx
+	jge	??ghost_f_t_line_begin
+
+	add	esi , [ scr_adjust_width ]
+	add	edi , [ dest_adjust_width ]
+	dec	edx
+	jnz	??ghost_f_t_loop
+
+	epilogue
+	ret
+
+
+;********************************************************************
+;********************************************************************
+
+global	BF_Predator:near
+BF_Predator:
+
+	prologue
+	mov	ebx , eax			; width
+
+	; NOTE: the below calculation assumes a group of instructions is
+	;	less than 256 bytes
+
+	; get length of the 32 groups of instructions
+
+	lea	ecx , [ ??predator_reference - ??predator_line ]
+
+	shr	ebx , 5				; width / 32
+	shr	ecx , 5				; length of instructions / 32
+	and	eax , 01fh			; mod of width / 32
+	mul	cl				; calc offset to start of group
+	neg	eax				; inverse of width
+	mov	[ loop_cnt ] , ebx		; save width / 32
+	lea	ecx , [ ??predator_reference + eax ]
+	mov	eax , 0
+	mov	[ jmp_loc ] , ecx
+
+??predator_loop:
+	mov	ecx , [ loop_cnt ]
+	jmp	[ jmp_loc ]
+
+??predator_line:
+
+	REPT	32
+	local	get_pred
+	local	skip_pixel
+		mov	al , [ esi ]
+		inc	esi
+		mov	ebx , [ BFPartialCount ]
+		add	ebx , [ BFPartialPred ]
+		or	bh , bh
+		jnz	get_pred		; is this a predator pixel?
+
+		mov	[ BFPartialCount ] , ebx
+		jmp	skip_pixel
+
+	get_pred:
+		xor	bh , bh
+		mov	eax, [ BFPredOffset ]
+		mov	[ BFPartialCount ] , ebx
+		add	[ BYTE PTR BFPredOffset ] , 2
+		movzx	eax , [ WORD PTR BFPredTable + eax ]
+		and	[ BYTE PTR BFPredOffset ] , PRED_MASK
+						; pick up a color offset a pseudo-
+						;  random amount from the current
+		movzx	eax , [ BYTE PTR edi + eax ]	;  viewport address
+
+;		xor	bh , bh
+;		mov	eax , [ BFPredValue ]	; pick up a color offset a pseudo-
+;						;  random amount from the current
+;		mov	[ BFPartialCount ] , ebx
+;		mov	al , [ edi + eax ]	;  viewport address
+
+		mov	[ edi ] , al
+
+	skip_pixel:
+		inc	edi
+
+	ENDM
+
+??predator_reference:
+	dec	ecx
+	jge	??predator_line
+
+	add	esi , [ scr_adjust_width ]
+	add	edi , [ dest_adjust_width ]
+	dec	edx
+	jnz	??predator_loop
+
+	epilogue
+	ret
+
+
+;********************************************************************
+;********************************************************************
+
+global	BF_Predator_Trans:near
+BF_Predator_Trans:
+
+	prologue
+	mov	ebx , eax			; width
+
+	; NOTE: the below calculation assumes a group of instructions is
+	;	less than 256 bytes
+
+	; get length of the 32 groups of instructions
+
+	lea	ecx , [ ??predator_t_reference - ??predator_t_line ]
+
+	shr	ebx , 5				; width / 32
+	shr	ecx , 5				; length of instructions / 32
+	and	eax , 01fh			; mod of width / 32
+	mul	cl				; calc offset to start of group
+	neg	eax				; inverse of width
+	mov	[ loop_cnt ] , ebx		; save width / 32
+	lea	ecx , [ ??predator_t_reference + eax ]
+	mov	eax , 0
+	mov	[ jmp_loc ] , ecx
+
+??predator_t_loop:
+	mov	ecx , [ loop_cnt ]
+	jmp	[ jmp_loc ]
+
+??predator_t_line:
+
+	REPT	32
+	local	trans_pixel
+	local	get_pred
+	local	store_pixel
+		mov	al , [ esi ]
+		inc	esi
+		test	al , al
+		jz	trans_pixel
+
+		mov	ebx , [ BFPartialCount ]
+		add	ebx , [ BFPartialPred ]
+		or	bh , bh
+		jnz	get_pred		; is this a predator pixel?
+
+		mov	[ BFPartialCount ] , ebx
+		jmp	store_pixel
+
+	get_pred:
+		xor	bh , bh
+		mov	eax, [ BFPredOffset ]
+		mov	[ BFPartialCount ] , ebx
+		add	[ BYTE PTR BFPredOffset ] , 2
+		movzx	eax , [ WORD PTR BFPredTable + eax ]
+		and	[ BYTE PTR BFPredOffset ] , PRED_MASK
+						; pick up a color offset a pseudo-
+						;  random amount from the current
+		movzx	eax , [ BYTE PTR edi + eax ]	;  viewport address
+
+	store_pixel:
+		mov	[ edi ] , al
+
+	trans_pixel:
+		inc	edi
+
+	ENDM
+
+??predator_t_reference:
+	dec	ecx
+	jge	??predator_t_line
+
+	add	esi , [ scr_adjust_width ]
+	add	edi , [ dest_adjust_width ]
+	dec	edx
+	jnz	??predator_t_loop
+
+	epilogue
+	ret
+
+
+;********************************************************************
+;********************************************************************
+
+global	BF_Predator_Ghost:near
+BF_Predator_Ghost:
+
+	prologue
+	mov	ebx , eax			; width
+
+	; NOTE: the below calculation assumes a group of instructions is
+	;	less than 256 bytes
+
+	; get length of the 32 groups of instructions
+
+	lea	ecx , [ ??predator_g_reference - ??predator_g_line ]
+
+	shr	ebx , 5				; width / 32
+	shr	ecx , 5				; length of instructions / 32
+	and	eax , 01fh			; mod of width / 32
+	mul	cl				; calc offset to start of group
+	neg	eax				; inverse of width
+	mov	[ loop_cnt ] , ebx		; save width / 32
+	lea	ecx , [ ??predator_g_reference + eax ]
+	mov	eax , 0
+	mov	[ jmp_loc ] , ecx
+
+??predator_g_loop:
+	mov	ecx , [ loop_cnt ]
+	jmp	[ jmp_loc ]
+
+??predator_g_line:
+
+	REPT	32
+	local	get_pred
+	local	check_ghost
+	local	store_pixel
+		mov	al , [ esi ]
+		mov	ebx , [ BFPartialCount ]
+		inc	esi
+		add	ebx , [ BFPartialPred ]
+		or	bh , bh
+		jnz	get_pred		; is this a predator pixel?
+
+		mov	[ BFPartialCount ] , ebx
+		jmp	check_ghost
+
+	get_pred:
+		xor	bh , bh
+		mov	eax, [ BFPredOffset ]
+		mov	[ BFPartialCount ] , ebx
+		add	[ BYTE PTR BFPredOffset ] , 2
+		movzx	eax , [ WORD PTR BFPredTable + eax ]
+		and	[ BYTE PTR BFPredOffset ] , PRED_MASK
+						; pick up a color offset a pseudo-
+						;  random amount from the current
+		movzx	eax , [ BYTE PTR edi + eax ]	;  viewport address
+
+	check_ghost:
+		mov	ebx , [ IsTranslucent ]		; is it a translucent color?
+		mov	bh , [ BYTE PTR ebx + eax ]
+		cmp	bh , 0ffh
+		je	store_pixel
+
+		and	ebx , 0FF00h			; clear all of ebx except bh
+							; we have the index to the translation table
+							; ((trans_colour * 256) + dest colour)
+		mov	al , [ edi ]			; mov pixel at destination to al
+		add	ebx , [ Translucent ]		; get the ptr to it!
+							; Add the (trans_color * 256) of the translation equ.
+		mov	al , [ BYTE PTR ebx + eax ]	; get new pixel in al
+
+	store_pixel:
+		mov	[ edi ] , al
+		inc	edi
+
+	ENDM
+
+??predator_g_reference:
+	dec	ecx
+	jge	??predator_g_line
+
+	add	esi , [ scr_adjust_width ]
+	add	edi , [ dest_adjust_width ]
+	dec	edx
+	jnz	??predator_g_loop
+
+	epilogue
+	ret
+
+
+;********************************************************************
+;********************************************************************
+
+global	BF_Predator_Ghost_Trans:near
+BF_Predator_Ghost_Trans:
+
+	prologue
+	mov	ebx , eax			; width
+
+	; NOTE: the below calculation assumes a group of instructions is
+	;	less than 256 bytes
+
+	; get length of the 32 groups of instructions
+
+	lea	ecx , [ ??predator_g_t_reference - ??predator_g_t_line ]
+
+	shr	ebx , 5				; width / 32
+	shr	ecx , 5				; length of instructions / 32
+	and	eax , 01fh			; mod of width / 32
+	mul	cl				; calc offset to start of group
+	neg	eax				; inverse of width
+	mov	[ loop_cnt ] , ebx		; save width / 32
+	lea	ecx , [ ??predator_g_t_reference + eax ]
+	mov	eax , 0
+	mov	[ jmp_loc ] , ecx
+
+??predator_g_t_loop:
+	mov	ecx , [ loop_cnt ]
+	jmp	[ jmp_loc ]
+
+??predator_g_t_line:
+
+	REPT	32
+	local	trans_pixel
+	local	get_pred
+	local	check_ghost
+	local	store_pixel
+		mov	al , [ esi ]
+		inc	esi
+		test	al , al
+		jz	trans_pixel
+
+		mov	ebx , [ BFPartialCount ]
+		add	ebx , [ BFPartialPred ]
+		or	bh , bh
+		jnz	get_pred		; is this a predator pixel?
+
+		mov	[ BFPartialCount ] , ebx
+		jmp	check_ghost
+
+	get_pred:
+		xor	bh , bh
+		mov	eax, [ BFPredOffset ]
+		mov	[ BFPartialCount ] , ebx
+		add	[ BYTE PTR BFPredOffset ] , 2
+		movzx	eax , [ WORD PTR BFPredTable + eax ]
+		and	[ BYTE PTR BFPredOffset ] , PRED_MASK
+						; pick up a color offset a pseudo-
+						;  random amount from the current
+		movzx	eax , [ BYTE PTR edi + eax ]	;  viewport address
+
+	check_ghost:
+		mov	ebx , [ IsTranslucent ]		; is it a translucent color?
+		mov	bh , [ BYTE PTR ebx + eax ]
+		cmp	bh , 0ffh
+		je	store_pixel
+
+		and	ebx , 0FF00h			; clear all of ebx except bh
+							; we have the index to the translation table
+							; ((trans_colour * 256) + dest colour)
+		mov	al , [ edi ]			; mov pixel at destination to al
+		add	ebx , [ Translucent ]		; get the ptr to it!
+							; Add the (trans_color * 256) of the translation equ.
+		mov	al , [ BYTE PTR ebx + eax ]	; get new pixel in al
+
+	store_pixel:
+		mov	[ edi ] , al
+
+	trans_pixel:
+		inc	edi
+
+	ENDM
+
+??predator_g_t_reference:
+	dec	ecx
+	jge	??predator_g_t_line
+
+	add	esi , [ scr_adjust_width ]
+	add	edi , [ dest_adjust_width ]
+	dec	edx
+	jnz	??predator_g_t_loop
+
+	epilogue
+	ret
+
+
+;********************************************************************
+;********************************************************************
+
+global	BF_Predator_Fading:near
+BF_Predator_Fading:
+
+	prologue
+	mov	ebx , eax			; width
+
+	; NOTE: the below calculation assumes a group of instructions is
+	;	less than 256 bytes
+
+	; get length of the 32 groups of instructions
+
+	lea	ecx , [ ??predator_f_reference - ??predator_f_line ]
+
+	shr	ebx , 5				; width / 32
+	shr	ecx , 5				; length of instructions / 32
+	and	eax , 01fh			; mod of width / 32
+	mul	cl				; calc offset to start of group
+	neg	eax				; inverse of width
+	mov	[ loop_cnt ] , ebx		; save width / 32
+	lea	ecx , [ ??predator_f_reference + eax ]
+	mov	eax , 0
+	mov	[ jmp_loc ] , ecx
+
+??predator_f_loop:
+	mov	ecx , [ loop_cnt ]
+	mov	[ StashECX ] , ecx		; preserve ecx for later
+	jmp	[ jmp_loc ]
+
+??predator_f_line_begin:
+	mov	[ StashECX ] , ecx		; preserve ecx for later
+
+??predator_f_line:
+
+	REPT	32
+	local	get_pred
+	local	do_fading
+	local	fade_loop
+		mov	al , [ esi ]
+		mov	ebx , [ BFPartialCount ]
+		inc	esi
+		add	ebx , [ BFPartialPred ]
+		or	bh , bh
+		jnz	get_pred		; is this a predator pixel?
+
+		mov	[ BFPartialCount ] , ebx
+		jmp	do_fading
+
+	get_pred:
+		xor	bh , bh
+		mov	eax, [ BFPredOffset ]
+		mov	[ BFPartialCount ] , ebx
+		add	[ BYTE PTR BFPredOffset ] , 2
+		movzx	eax , [ WORD PTR BFPredTable + eax ]
+		and	[ BYTE PTR BFPredOffset ] , PRED_MASK
+						; pick up a color offset a pseudo-
+						;  random amount from the current
+		movzx	eax , [ BYTE PTR edi + eax ]	;  viewport address
+
+	do_fading:
+		mov	ebx , [ FadingTable ]		; run color through fading table
+		mov	ecx , [ FadingNum ]
+
+	fade_loop:
+		mov	al, [BYTE PTR ebx + eax]
+		dec	ecx
+		jnz	fade_loop
+
+		mov	[ edi ] , al
+		inc	edi
+
+	ENDM
+
+??predator_f_reference:
+	mov	ecx , [ StashECX ]		; restore ecx for main draw loop
+	dec	ecx
+	jge	??predator_f_line_begin
+
+	add	esi , [ scr_adjust_width ]
+	add	edi , [ dest_adjust_width ]
+	dec	edx
+	jnz	??predator_f_loop
+
+	epilogue
+	ret
+
+
+;********************************************************************
+;********************************************************************
+
+global	BF_Predator_Fading_Trans:near
+BF_Predator_Fading_Trans:
+
+	prologue
+	mov	ebx , eax			; width
+
+	; NOTE: the below calculation assumes a group of instructions is
+	;	less than 256 bytes
+
+	; get length of the 32 groups of instructions
+
+	lea	ecx , [ ??predator_f_t_reference - ??predator_f_t_line ]
+
+	shr	ebx , 5				; width / 32
+	shr	ecx , 5				; length of instructions / 32
+	and	eax , 01fh			; mod of width / 32
+	mul	cl				; calc offset to start of group
+	neg	eax				; inverse of width
+	mov	[ loop_cnt ] , ebx		; save width / 32
+	lea	ecx , [ ??predator_f_t_reference + eax ]
+	mov	eax , 0
+	mov	[ jmp_loc ] , ecx
+
+??predator_f_t_loop:
+	mov	ecx , [ loop_cnt ]
+	mov	[ StashECX ] , ecx		; preserve ecx for later
+	jmp	[ jmp_loc ]
+
+??predator_f_t_line_begin:
+	mov	[ StashECX ] , ecx		; preserve ecx for later
+
+??predator_f_t_line:
+
+	REPT	32
+	local	trans_pixel
+	local	get_pred
+	local	do_fading
+	local	fade_loop
+		mov	al , [ esi ]
+		inc	esi
+		test	al , al
+		jz	trans_pixel
+
+		mov	ebx , [ BFPartialCount ]
+		add	ebx , [ BFPartialPred ]
+		or	bh , bh
+		jnz	get_pred		; is this a predator pixel?
+
+		mov	[ BFPartialCount ] , ebx
+		jmp	do_fading
+
+	get_pred:
+		xor	bh , bh
+		mov	eax, [ BFPredOffset ]
+		mov	[ BFPartialCount ] , ebx
+		add	[ BYTE PTR BFPredOffset ] , 2
+		movzx	eax , [ WORD PTR BFPredTable + eax ]
+		and	[ BYTE PTR BFPredOffset ] , PRED_MASK
+						; pick up a color offset a pseudo-
+						;  random amount from the current
+		movzx	eax , [ BYTE PTR edi + eax ]	;  viewport address
+
+	do_fading:
+		mov	ebx , [ FadingTable ]		; run color through fading table
+		mov	ecx , [ FadingNum ]
+
+	fade_loop:
+		mov	al, [BYTE PTR ebx + eax]
+		dec	ecx
+		jnz	fade_loop
+
+		mov	[ edi ] , al
+
+	trans_pixel:
+		inc	edi
+
+	ENDM
+
+??predator_f_t_reference:
+	mov	ecx , [ StashECX ]		; restore ecx for main draw loop
+	dec	ecx
+	jge	??predator_f_t_line_begin
+
+	add	esi , [ scr_adjust_width ]
+	add	edi , [ dest_adjust_width ]
+	dec	edx
+	jnz	??predator_f_t_loop
+
+	epilogue
+	ret
+
+
+;********************************************************************
+;********************************************************************
+
+global	BF_Predator_Ghost_Fading:near
+BF_Predator_Ghost_Fading:
+
+	prologue
+	mov	ebx , eax			; width
+
+	; NOTE: the below calculation assumes a group of instructions is
+	;	less than 256 bytes
+
+	; get length of the 32 groups of instructions
+
+	lea	ecx , [ ??predator_g_f_reference - ??predator_g_f_line ]
+
+	shr	ebx , 5				; width / 32
+	shr	ecx , 5				; length of instructions / 32
+	and	eax , 01fh			; mod of width / 32
+	mul	cl				; calc offset to start of group
+	neg	eax				; inverse of width
+	mov	[ loop_cnt ] , ebx		; save width / 32
+	lea	ecx , [ ??predator_g_f_reference + eax ]
+	mov	eax , 0
+	mov	[ jmp_loc ] , ecx
+
+??predator_g_f_loop:
+	mov	ecx , [ loop_cnt ]
+	mov	[ StashECX ] , ecx		; preserve ecx for later
+	jmp	[ jmp_loc ]
+
+??predator_g_f_line_begin:
+	mov	[ StashECX ] , ecx		; preserve ecx for later
+
+??predator_g_f_line:
+
+	REPT	32
+	local	get_pred
+	local	check_ghost
+	local	store_pixel
+	local	do_fading
+	local	fade_loop
+		mov	al , [ esi ]
+		mov	ebx , [ BFPartialCount ]
+		inc	esi
+		add	ebx , [ BFPartialPred ]
+		or	bh , bh
+		jnz	get_pred		; is this a predator pixel?
+
+		mov	[ BFPartialCount ] , ebx
+		jmp	check_ghost
+
+	get_pred:
+		xor	bh , bh
+		mov	eax, [ BFPredOffset ]
+		mov	[ BFPartialCount ] , ebx
+		add	[ BYTE PTR BFPredOffset ] , 2
+		movzx	eax , [ WORD PTR BFPredTable + eax ]
+		and	[ BYTE PTR BFPredOffset ] , PRED_MASK
+						; pick up a color offset a pseudo-
+						;  random amount from the current
+		movzx	eax , [ BYTE PTR edi + eax ]	;  viewport address
+
+	check_ghost:
+		mov	ebx , [ IsTranslucent ]		; is it a translucent color?
+		mov	bh , [ BYTE PTR ebx + eax ]
+		cmp	bh , 0ffh
+		je	do_fading
+
+		and	ebx , 0FF00h			; clear all of ebx except bh
+							; we have the index to the translation table
+							; ((trans_colour * 256) + dest colour)
+		mov	al , [ edi ]			; mov pixel at destination to al
+		add	ebx , [ Translucent ]		; get the ptr to it!
+							; Add the (trans_color * 256) of the translation equ.
+		mov	al , [ BYTE PTR ebx + eax ]	; get new pixel in al
+; DRD		jmp	store_pixel
+
+	do_fading:
+		mov	ebx , [ FadingTable ]		; run color through fading table
+		mov	ecx , [ FadingNum ]
+
+	fade_loop:
+		mov	al, [BYTE PTR ebx + eax]
+		dec	ecx
+		jnz	fade_loop
+
+	store_pixel:
+		mov	[ edi ] , al
+		inc	edi
+
+	ENDM
+
+??predator_g_f_reference:
+	mov	ecx , [ StashECX ]		; restore ecx for main draw loop
+	dec	ecx
+	jge	??predator_g_f_line_begin
+
+	add	esi , [ scr_adjust_width ]
+	add	edi , [ dest_adjust_width ]
+	dec	edx
+	jnz	??predator_g_f_loop
+
+	epilogue
+	ret
+
+
+;********************************************************************
+;********************************************************************
+
+global	BF_Predator_Ghost_Fading_Trans:near
+BF_Predator_Ghost_Fading_Trans:
+
+	prologue
+	mov	ebx , eax			; width
+
+	; NOTE: the below calculation assumes a group of instructions is
+	;	less than 256 bytes
+
+	; get length of the 32 groups of instructions
+
+	lea	ecx , [ ??predator_g_f_t_reference - ??predator_g_f_t_line ]
+
+	shr	ebx , 5				; width / 32
+	shr	ecx , 5				; length of instructions / 32
+	and	eax , 01fh			; mod of width / 32
+	mul	cl				; calc offset to start of group
+	neg	eax				; inverse of width
+	mov	[ loop_cnt ] , ebx		; save width / 32
+	lea	ecx , [ ??predator_g_f_t_reference + eax ]
+	mov	eax , 0
+	mov	[ jmp_loc ] , ecx
+
+??predator_g_f_t_loop:
+	mov	ecx , [ loop_cnt ]
+	mov	[ StashECX ] , ecx		; preserve ecx for later
+	jmp	[ jmp_loc ]
+
+??predator_g_f_t_line_begin:
+	mov	[ StashECX ] , ecx		; preserve ecx for later
+
+??predator_g_f_t_line:
+
+	REPT	32
+	local	trans_pixel
+	local	get_pred
+	local	check_ghost
+	local	store_pixel
+	local	do_fading
+	local	fade_loop
+		mov	al , [ esi ]
+		inc	esi
+		test	al , al
+		jz	trans_pixel
+
+		mov	ebx , [ BFPartialCount ]
+		add	ebx , [ BFPartialPred ]
+		or	bh , bh
+		jnz	get_pred		; is this a predator pixel?
+
+		mov	[ BFPartialCount ] , ebx
+		jmp	check_ghost
+
+	get_pred:
+		xor	bh , bh
+		mov	eax, [ BFPredOffset ]
+		mov	[ BFPartialCount ] , ebx
+		add	[ BYTE PTR BFPredOffset ] , 2
+		movzx	eax , [ WORD PTR BFPredTable + eax ]
+		and	[ BYTE PTR BFPredOffset ] , PRED_MASK
+						; pick up a color offset a pseudo-
+						;  random amount from the current
+		movzx	eax , [ BYTE PTR edi + eax ]	;  viewport address
+
+	check_ghost:
+		mov	ebx , [ IsTranslucent ]		; is it a translucent color?
+		mov	bh , [ BYTE PTR ebx + eax ]
+		cmp	bh , 0ffh
+		je	do_fading
+
+		and	ebx , 0FF00h			; clear all of ebx except bh
+							; we have the index to the translation table
+							; ((trans_colour * 256) + dest colour)
+		mov	al , [ edi ]			; mov pixel at destination to al
+		add	ebx , [ Translucent ]		; get the ptr to it!
+							; Add the (trans_color * 256) of the translation equ.
+		mov	al , [ BYTE PTR ebx + eax ]	; get new pixel in al
+; DRD		jmp	store_pixel
+
+	do_fading:
+		mov	ebx , [ FadingTable ]		; run color through fading table
+		mov	ecx , [ FadingNum ]
+
+	fade_loop:
+		mov	al, [BYTE PTR ebx + eax]
+		dec	ecx
+		jnz	fade_loop
+
+	store_pixel:
+		mov	[ edi ] , al
+
+	trans_pixel:
+		inc	edi
+
+	ENDM
+
+??predator_g_f_t_reference:
+	mov	ecx , [ StashECX ]		; restore ecx for main draw loop
+	dec	ecx
+	jge	??predator_g_f_t_line_begin
+
+	add	esi , [ scr_adjust_width ]
+	add	edi , [ dest_adjust_width ]
+	dec	edx
+	jnz	??predator_g_f_t_loop
+
+	epilogue
+	ret
+
+
+;********************************************************************
+;********************************************************************
+
+Not_Supported:
+	ret
+
+	ENDP	Buffer_Frame_To_Page
+END
+
+;***************************************************************************
+;**   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 : KEYFBUFF.ASM                             *
+;*                                                                         *
+;*                   Programmer : Phil W. Gorrow                           *
+;*                                                                         *
+;*                   Start Date : July 16, 1992                            *
+;*                                                                         *
+;*                  Last Update : October 2, 1994   [JLB]                  *
+;*                                                                         *
+;*-------------------------------------------------------------------------*
+;* Functions:                                                              *
+;*   BUFFER_FRAME_TO_LOGICPAGE --                                          *
+;*   Normal_Draw -- Function that writes a normal pixel line               *
+;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *
+
+	IDEAL
+	P386
+IDEAL_MODE	EQU	1
+	INCLUDE "wwlib.i"
+
+	;-------------------------------------------------------------------
+	; Extern all the library variables that this module requires
+	;-------------------------------------------------------------------
+
+	EXTRN	C MaskPage:WORD
+	EXTRN	C BackGroundPage:WORD
+
+	;-------------------------------------------------------------------
+	; Define all the equates that this module requires
+	;-------------------------------------------------------------------
+
+WIN_X		EQU	0		; offset for the x coordinate
+WIN_Y		EQU	2		; offset for the y coordinate
+WIN_WIDTH	EQU	4		; offset for the window width
+WIN_HEIGHT	EQU	6		; offset for the window height
+BYTESPERROW	EQU	320		; number of bytes per row
+
+FLAG_NORMAL		EQU	0		; flag for normal draw
+
+FLAG_GHOST		EQU	1		; This flag enables the ghost
+FLAG_PRIORITY_TRANS	EQU	2		; flag for priority and transparent
+FLAG_TRANS		EQU	4		; flag for transparent draw
+FLAG_PRIORITY		EQU	8		; flag for priority draw
+
+						; fx on the above flags
+
+FLAG_MASK		EQU	15		; used to and of uneeded bits
+
+SHAPE_NORMAL		EQU	0000h		; Standard shape.
+;SHAPE_HORZ_REV		EQU	0001h		; Flipped horizontally.
+;SHAPE_VERT_REV		EQU	0002h		; Flipped vertically.
+;SHAPE_SCALING		EQU	0004h		; Scaled (WORD scale_x, WORD scale_y)
+
+SHAPE_WIN_REL		EQU	0010h		; Coordinates are window relative instead of absolute.
+SHAPE_CENTER		EQU	0020h		; Coordinates are based on shape's center point.
+SHAPE_TRANS		EQU	0040h		; has transparency
+
+
+;SHAPE_FADING		EQU	0100h		; Fading effect active (VOID * fading_table, WORD fading_num).
+;SHAPE_PREDATOR		EQU	0200h		; Transparent warping effect.
+;SHAPE_COMPACT		EQU	0400h		; Never use this bit.
+SHAPE_PRIORITY		EQU	0800h		; Use priority system when drawing.
+
+SHAPE_GHOST		EQU	1000h		; Transluscent table process.
+;SHAPE_SHADOW		EQU	2000h		; ????
+;SHAPE_PARTIAL 		EQU	4000h		; ????
+;SHAPE_COLOR		EQU	8000h		; Remap the shape's colors (VOID * color_table).
+
+
+; MBL MOD 12.1.92
+
+CLEAR_NON_WALK_BIT_AND_SCALE_BITS	EQU	7	; Makes it one AND per pixel in Priority_Trans display
+CLEAR_NON_WALK_BIT    	EQU	7fh	; and with 0111-1111 to clear non-walkable high bit
+CLEAR_SCALE_BITS  	EQU	87h	; and with 1000-0111 to clear scaling id bits
+NON_WALKABLE_BIT  	EQU	80h	; and with 1000-0000 to clear all but non-walkable bit
+
+; END MBL MOD
+
+
+	CODESEG
+
+	;   1 = GHOST (all odd entrys are prefixed with Ghost_)
+	;   2 = BLAAAH
+	;   4 = Trans (prfx)
+	;   8 = Prior (prfx)
+
+
+;---------------------------------------------------------------------------
+; Define the table of different line draw types
+;---------------------------------------------------------------------------
+
+LineTable	DW	WSA_Normal_Draw			;0
+		DW	Ghost_Normal_Draw		;1
+		DW	0				;2
+		DW	0				;3
+
+		DW	Transparent_Draw		;4
+		DW	Ghost_Transparent_Draw		;5
+		DW	0				;6
+		DW	0				;7
+
+		DW	Priority_Draw			;8
+		DW	Ghost_Priority_Draw		;9
+		DW	0				;10
+		DW	0				;11
+
+		DW	Priority_Transparent_Draw	;12
+		DW	Ghost_Priority_Transparent_Draw	;13
+		DW	0				;14
+		DW	0				;15
+
+
+
+;***************************************************************************
+;* BUFFER_FRAME_TO_LOGICPAGE --                                            *
+;*                                                                         *
+;*                                                                         *
+;*                                                                         *
+;* INPUT:                                                                  *
+;*                                                                         *
+;* OUTPUT:                                                                 *
+;*                                                                         *
+;* WARNINGS:                                                               *
+;*                                                                         *
+;* HISTORY:                                                                *
+;*   07/16/1992 PWG : Created.                                             *
+;*=========================================================================*
+	PUBLIC	C Buffer_Frame_To_LogicPage
+	PROC	C Buffer_Frame_To_LogicPage FAR USES ax bx ecx dx ds esi es edi
+
+	;-------------------------------------------------------------------
+	; Define the arguements that our program takes.
+	;-------------------------------------------------------------------
+
+	ARG	x_pixel:WORD		; x pixel position to draw at
+	ARG	y_pixel:WORD		; y pixel position to draw at
+	ARG	pixel_w:WORD		; pixel width of draw region
+	ARG	pixel_h:WORD		; pixel height of draw region
+	ARG	win:WORD		; window to clip around
+	ARG	flags:WORD		; flags that this routine will take
+	ARG	buffer:DWORD		; pointer to the buffer with data
+	ARG	args:WORD
+
+	;-------------------------------------------------------------------
+	; Define the local variables that our program uses
+	;-------------------------------------------------------------------
+
+	LOCAL	IsTranslucent:DWORD	; ptr to the is_translucent table
+	LOCAL	Translucent:DWORD	; ptr to the actual translucent table
+
+	LOCAL	win_x1:WORD		; clip window left x pixel position
+	LOCAL	win_x2:WORD		; clip window right x pixel position
+	LOCAL	win_y1:WORD		; clip window top y pixel position
+	LOCAL	win_y2:WORD		; clip window bottom y pixel position
+	LOCAL	clipleft:WORD		; number of pixels to clip on left
+	LOCAL	clipright:WORD		; number of pixels to clip on right
+	LOCAL	nextline:WORD		; offset to the next line
+	LOCAL	putmiddle:WORD 		; routine to call to put the middle
+	LOCAL	maskpage:WORD		; location of the depth masks
+	LOCAL   background:WORD		; location of the background data
+	LOCAL   jflags:WORD		; location of the background data
+
+	LOCAL	priority:BYTE		; the priority level of the back
+
+	push	fs
+
+	xor	ecx,ecx
+
+	;--------------------------------------------------------------------
+	; Check to see if we have supplied any GHOST tables.
+	;--------------------------------------------------------------------
+	push	di
+
+	mov	di,6
+	mov	[jflags],0
+
+??ghost:
+	test	[flags],SHAPE_GHOST	; are we ghosting this shape
+	jz	short ??no_ghost	; if not then skip and do more
+
+	or	[jflags],FLAG_GHOST
+
+	les	ax,[DWORD PTR buffer + di]
+
+	; get the "are we really translucent?" table
+	mov	[WORD PTR IsTranslucent],ax
+	mov	[WORD PTR IsTranslucent + 2],es
+	add	ax,0100h		; add to offset for tables
+
+	; get the "ok we are translucent!!" table
+	mov	[WORD PTR Translucent],ax
+	mov	[WORD PTR Translucent + 2],es
+
+	add	di,4
+
+??no_ghost:
+
+	pop	di
+
+	;-------------------------------------------------------------------
+	; See if we need to center the frame
+	;-------------------------------------------------------------------
+	test	[flags],SHAPE_CENTER	; does this need to be centered?
+	je	short ??no_centering	; if not the skip over this stuff
+
+	mov	ax,[pixel_w]
+	mov	bx,[pixel_h]
+	sar	ax,1
+	sar	bx,1
+	sub	[x_pixel],ax
+	sub	[y_pixel],bx
+
+??no_centering:
+	mov	ax,[flags]
+	and	ax,SHAPE_PRIORITY+SHAPE_TRANS
+	cmp	ax,SHAPE_PRIORITY+SHAPE_TRANS
+	jne	short ??test_trans
+
+	or	[jflags],FLAG_PRIORITY_TRANS
+	jmp	short ??priority
+
+	;-------------------------------------------------------------------
+	; Get the trans information if we need to get it
+	;-------------------------------------------------------------------
+??test_trans:
+	test	[flags],SHAPE_TRANS	; does this draw use transparencies?
+	je	short ??test_priority	; if not the skip over this junk
+
+	or	[jflags],FLAG_TRANS
+
+??test_priority:
+	;-------------------------------------------------------------------
+	; Get the priority information if we need to get it
+	;-------------------------------------------------------------------
+	test	[flags],SHAPE_PRIORITY	; does this draw use priorities?
+	je	short ??no_priority	; if not the skip over this junk
+
+	or	[jflags],FLAG_PRIORITY
+
+??priority:
+	mov	ax,[BackGroundPage]	; get the background page from ds
+	mov	[background],ax		;    and store it on the stack
+	mov	ax,[MaskPage]		; get the mask page from ds
+	mov	[maskpage],ax		;    and store it on the stack
+	mov	ax,[WORD PTR buffer + 4]; get the priority level from args
+	mov	[priority],al		;    and store it in a local
+
+	;-------------------------------------------------------------------
+	; Get the draw routine that we are going to draw with
+	;-------------------------------------------------------------------
+??no_priority:
+;	mov	bx,[flags]		; load in the current flags byte
+;	and	bx,FLAG_MASK		; prevent lockup on bad value
+	mov	bx,[jflags]		; load in the jump table flags
+	shl	bx,1
+	mov	ax,[WORD PTR LineTable + bx]	; get the offset of the skip table
+	mov	[putmiddle],ax		; store off the new offset
+
+	;-------------------------------------------------------------------
+	; Get a pointer to the logic page to where we will draw our buffer
+	;-------------------------------------------------------------------
+	push	[LogicPage]		; push the current logic page
+	call	FAR PTR Get_Page	; get the physical page address
+	add	sp,2			; pull the parameter from the stack
+	mov	es,dx			; store the address in the dest
+
+	;--------------------------------------------------------------------
+	; Point DI to the beginning of the window that we need to look at.
+	;   that way we can access all of the info through di.
+	;--------------------------------------------------------------------
+	mov	si,OFFSET WindowList	; get the offset of the window list
+	mov	cl,4			; shift 3 times = multiply by 16
+	mov	ax,[win]		; get the window number we are using
+	shl	ax,cl			; each window is 8 words long
+	add	si,ax			; add that into the offset of window
+
+	;--------------------------------------------------------------------
+	; Place all the clipping values on the stack so our function will
+	; be truly re-entrant and will not need to shadow these values.
+	;--------------------------------------------------------------------
+	mov	cl,3			; to convert x to pixel mult by 8
+	mov	ax,[si + WIN_X]		; get the left clip position
+	shl	ax,cl			; convert to a pixel x position
+	mov	[win_x1],ax		; store the left edge of window
+	mov	[win_x2],ax
+
+	mov	ax,[si + WIN_WIDTH]	; get the width of the window
+	shl	ax,cl			; convert to a pixel width
+	add	[win_x2],ax		; add to get the right window edge
+
+	mov	ax,[si + WIN_Y]		; get the win y coordinate to clip
+	mov	[win_y1],ax		; and save it onto the stack
+
+	add	ax,[si + WIN_HEIGHT]	; calculate the bottom win y coord
+	mov	[win_y2],ax		; and save it onto the stack
+
+	test	[flags],SHAPE_WIN_REL	; is this window relative?
+	je	short ??get_buffer	; if not the skip over
+
+	mov	ax,[win_x1]		; get left edge of window
+	add	[x_pixel],ax		; add to x pixel position
+	mov	ax,[win_y1]		; get top edge of window
+	add	[y_pixel],ax		; add to y pixel position
+
+	;--------------------------------------------------------------------
+	; Get a pointer to the source buffer so we can handle the clipping
+	;--------------------------------------------------------------------
+??get_buffer:
+	lds	si,[buffer]		; get a pointer to the buffer
+
+	;--------------------------------------------------------------------
+	; Check the top of our shape and clip any lines that are necessary
+	;--------------------------------------------------------------------
+	mov	ax,[y_pixel]		; get the y_pixel draw position
+	sub	ax,[win_y1]		; subtract out the window y top
+	jns	short ??check_bottom		;   skip if y below window top
+	add	ax,[pixel_h]		; add in the height of the region
+	jg	short ??clip_top		; if positive then clip top lines
+
+??jump_exit:
+	jmp	??exit			; otherwise completely clipped
+
+??clip_top:
+	xchg	[pixel_h],ax
+	sub	ax,[pixel_h]
+	add	[y_pixel],ax
+	mul	[pixel_w]		; convert to number of bytes to skip
+	add	si,ax			; skip past the necessary bytes
+
+	;--------------------------------------------------------------------
+	; Check the bottom of our shape and clip it if necessary
+	;--------------------------------------------------------------------
+??check_bottom:
+	mov	ax,[win_y2]		; get the bottom y of the window
+	sub	ax,[y_pixel]		; subtract of the y to draw at
+	js	??jump_exit		; if its signed then nothing to draw
+	jz	??jump_exit		; if its zero then nothing to draw
+
+	cmp	ax,[pixel_h]		; if more room to draw then height
+	jae	short ??clip_x_left		;   then go check the left clip
+	mov	[pixel_h],ax		; clip all but amount that will fit
+
+??clip_x_left:
+	mov	[clipleft],0		; clear clip on left of region
+	mov	ax,[x_pixel]		; get the pixel x of draw region
+	sub	ax,[win_x1]		; pull out the window coordinate
+	jns	short ??clip_x_right
+	neg	ax			; negate to get amnt to skip in buf
+	mov	[clipleft],ax		; store it in the left clip info
+	add	[x_pixel],ax		; move to the edge of the window
+	sub	[pixel_w],ax		; pull it out of the pixel width
+
+??clip_x_right:
+	mov	[clipright],0		; clear clip on right of region
+	mov	ax,[win_x2]		; get the window x of clip region
+	sub	ax,[x_pixel]		; subtract the draw edge of region
+	js	??jump_exit		; if its negative then get out
+	jz	??jump_exit		; if its zero then get out
+
+	cmp	ax,[pixel_w]		; is space available larger than w
+	jae	short ??draw_prep		;   if so then go get drawing
+
+
+	xchg	[pixel_w],ax		; amt to draw in pixel_w (wid in ax)
+	sub	ax,[pixel_w]		; pull out the amount to draw
+	mov	[clipright],ax		; this is the amount to clip on right
+
+??draw_prep:
+	push	si			; save off source pos in buffer
+	push	ds			;   both offset and segment
+	mov	ax,@data
+	mov	ds,ax
+	mov	bx,[y_pixel]
+	shl	bx,1			; shift left by 1 for word table look
+	lds	si,[YTable]	; get the address of the ytable
+	mov	di,[ds:si+bx]		; look up the multiplied value
+	pop	ds			; restore source pos in buffer
+	pop	si			;   both offset and segment
+
+	add	di,[x_pixel]		; add in the x pixel position
+	mov	[nextline],di		; save it off in the next line
+
+ 	;--------------------------------------------------------------------
+	; Now determine the type of the shape and process it in the proper
+	;   way.
+	;--------------------------------------------------------------------
+	mov	dx,[pixel_h]
+
+	; Check to see if the WSA is the screen width and there is no
+	; clipping. In this case, then a special single call to the
+	; line processing routine is possible.
+	mov	ax,[clipleft]
+	add	ax,[clipright]
+	jne	short ??top_of_loop
+	cmp	[pixel_w],BYTESPERROW
+	jne	short ??top_of_loop
+
+	;------------------------------------
+	; The width of the WSA is the screen width, so just process as
+	; one large WSA line.
+	mov	ax,BYTESPERROW
+	imul	dx
+	mov	cx,ax
+	call	[putmiddle]
+	jmp	short ??exit
+
+	;------------------------------------
+	; Process line by line.
+??top_of_loop:
+	add	si,[clipleft]		; skip whats necessary on left edge
+	mov	cx,[pixel_w]		; get the width we need to draw
+
+	; Copy the source to the destination as appropriate. This routine can
+	; trash AX, BX, CX, and DI. It must properly modify SI to point one byte past
+	; the end of the data.
+	call	[putmiddle]
+
+	add	si,[clipright]		; skip past the left clip
+	add	[nextline],BYTESPERROW
+	mov	di,[nextline]
+
+	dec	dx
+	jnz	??top_of_loop
+
+??exit:
+	pop	fs
+	ret
+	ENDP
+
+
+;***************************************************************************
+;* NORMAL_DRAW -- Function that writes a normal pixel line                 *
+;*                                                                         *
+;* INPUT:	cx    - number of pixels to write                          *
+;*		ds:si - buffer which holds the pixels to write		   *
+;*		es:di - place to put the pixels we are writing		   *
+;*                                                                         *
+;* OUTPUT:      ds:si - points to next pixel past last pixel read          *
+;*		es:di - points to next pixel past last pixel written	   *
+;*                                                                         *
+;* WARNINGS:    none                                                       *
+;*                                                                         *
+;* HISTORY:                                                                *
+;*   07/17/1992 PWG : Created.                                             *
+;*=========================================================================*
+
+	PROC	NOLANGUAGE WSA_Normal_Draw NEAR
+
+ IF 1
+ 	; This version is marginally faster than the later version.
+ 	mov	ax,cx
+	shr	cx,2
+	rep movsd
+	and	ax,011b
+	mov	cx,ax
+	shr	cx,1
+	rep movsw
+	adc	cx,cx
+	rep movsb
+	ret
+
+ ELSE
+
+	shr	cx,1			; convert to words (odd pix in carry)
+	rep	movsw			; write out the needed words
+	adc	cx,0			; add the carry into cx
+	rep	movsb			; write out the odd byte if any
+	ret
+ ENDIF
+
+	ENDP
+
+
+;***************************************************************************
+;* TRANSPARENT_DRAW -- Function that writes a transparent pixel line       *
+;*                                                                         *
+;* INPUT:	cx    - number of pixels to write                          *
+;*		ds:si - buffer which holds the pixels to write		   *
+;*		es:di - place to put the pixels we are writing		   *
+;*                                                                         *
+;* OUTPUT:      ds:si - points to next pixel past last pixel read          *
+;*		es:di - points to next pixel past last pixel written	   *
+;*                                                                         *
+;* WARNINGS:    none                                                       *
+;*                                                                         *
+;* HISTORY:                                                                *
+;*   07/17/1992 PWG : Created.                                             *
+;*   10/02/1994 JLB : Optimized for 250% speed improvement.                *
+;*=========================================================================*
+	PROC	NOLANGUAGE Transparent_Draw NEAR
+
+ IF 1
+	; Preserve DX since it is used as a scratch register.
+	push	dx
+
+??loop:
+	; Swap DS:SI and ES:DI back in preparation for the REP SCASB
+	; instruction.
+	xchg	di,si
+	mov	dx,es
+	mov	ax,ds
+	mov	ds,dx
+	mov	es,ax
+
+	; Remember the bytes remaining in order to calculate the position
+	; of the scan when it stops.
+	mov	bx,cx
+
+	; Scan looking for a non-zero value in the source buffer.
+	xor	al,al
+	repe scasb
+
+	; When the loop ends, if the EQ flag is set then the scanning is
+	; complete. Jump to the end of the routine in order to fixup the
+	; pointers.
+	je	short ??fini
+
+	; Advance the destination pointer by the amount necessary to match
+	; the source movement. DS:SI points to where data should be written.
+	add	si,bx
+	inc	cx		; SCASB leaves CX one too low, fix it.
+	dec	di		; SCASB leaves DI one byte too far, fix it.
+	sub	si,cx
+
+	; Scan for the duration of non-zero pixels. This yields a count which
+	; is used to copy the source data to the destination. Preserve DI.
+	mov	dx,di
+	mov	bx,cx
+	repne scasb
+	mov	di,dx
+
+	; Set BX to equal the number of bytes to copy from source to dest.
+	inc	cx		; SCASB leaves CX one too low, fix it.
+	sub	bx,cx
+
+	; Move the data from ES:DI to DS:SI for BX bytes.
+	xchg	cx,bx		; Make CX=bytes to move, BX=bytes remaining.
+
+	; Swap DS:SI and ES:DI in preparation for the REP MOV instruction.
+	xchg	di,si
+	mov	dx,es
+	mov	ax,ds
+	mov	ds,dx
+	mov	es,ax
+
+	; Move the data from source to dest. First try to move double
+	; words. Then copy the remainder bytes (if any). Putting jumps in
+	; this section doesn't result in any savings -- oh well.
+	mov	ax,cx
+	shr	cx,2
+	rep movsd
+	and	ax,0011b
+	mov	cx,ax
+	shr	cx,1
+	rep movsw
+	adc	cx,cx
+	rep movsb
+
+	; Restore CX with the remaining bytes to process.
+	mov	cx,bx
+
+	; If there are more bytes to process, then loop back.
+	or	cx,cx
+	jne	short ??loop
+
+??fini:
+	; Swap ES:DI and DS:SI back to original orientation.
+	mov	ax,ds
+	mov	bx,es
+	mov	es,ax
+	mov	ds,bx
+	xchg	di,si
+
+	; Restore DX and return.
+	pop	dx
+	ret
+
+ ELSE
+
+??loop_top:
+	lodsb
+	or	al,al
+	jz	short ??skip
+
+	mov	[es:di],al		; store the pixel to the screen
+??skip:
+	inc	di
+	loop	??loop_top
+	ret
+
+ ENDIF
+
+	ENDP
+
+
+;***************************************************************************
+;* PRIORITY_DRAW -- Function that writes a pixels if they are in front of  *
+;*		    the given plate.					   *
+;*                                                                         *
+;* INPUT:	cx    - number of pixels to write                          *
+;*		ds:si - buffer which holds the pixels to write		   *
+;*		es:di - place to put the pixels we are writing		   *
+;*                                                                         *
+;* OUTPUT:      ds:si - points to next pixel past last pixel read          *
+;*		es:di - points to next pixel past last pixel written	   *
+;*                                                                         *
+;* WARNINGS:    none                                                       *
+;*                                                                         *
+;* HISTORY:                                                                *
+;*   07/17/1992 PWG : Created.                                             *
+;*   12/01/1992 MBL : Updated to work with latest mask data encoding.      *
+;*   17/01/1993 MCC : Updated for 386, and optimized			   *
+;*=========================================================================*
+
+	PROC	NOLANGUAGE Priority_Draw NEAR
+
+	mov	fs,[background]		; get the SEG of the background page
+	mov	gs,[maskpage]		; get the SEG of the mask info
+	mov	ah,[priority]		; keep a copy of priority varible for faster cmp
+
+
+??loop_top:
+	lodsb				; get the pixel to draw on the screen
+
+					; get the mask byte for our pixel
+	mov	bl,[ds:di]
+					; get rid of non-walkable bit and
+					; get rid of scaling id bits
+	and	bl,CLEAR_NON_WALK_BIT_AND_SCALE_BITS
+
+	cmp	ah,bl			; are we more toward the front?
+	jge	short ??out_pixel	; if so then write the pixel
+
+	mov	al,[fs:di]		; get the pixel to write
+??out_pixel:
+	stosb				; write the pixel and inc the DI
+	loop	??loop_top
+	ret
+
+	ENDP
+
+
+;***************************************************************************
+;* PRIORITY_TRANSPARENT_DRAW -- Function that writes a pixels if they are  *
+;*		    in front of the given plate.  It also deals with	   *
+;*		    transparent pixels.					   *
+;*                                                                         *
+;* INPUT:	cx    - number of pixels to write                          *
+;*		ds:si - buffer which holds the pixels to write		   *
+;*		es:di - place to put the pixels we are writing		   *
+;*                                                                         *
+;* OUTPUT:      ds:si - points to next pixel past last pixel read          *
+;*		es:di - points to next pixel past last pixel written	   *
+;*                                                                         *
+;* WARNINGS:    none                                                       *
+;*                                                                         *
+;* HISTORY:                                                                *
+;*   07/17/1992 PWG : Created.                                             *
+;*   12/01/1992 MBL : Updated to work with latest mask data encoding.      *
+;*   17/01/1993 MCC : Updated for 386, and optimized			   *
+;*=========================================================================*
+
+	PROC	NOLANGUAGE Priority_Transparent_Draw NEAR
+
+	mov	fs,[background]		; get the SEG of the background page
+	mov	gs,[maskpage]		; get the SEG of the mask info
+	mov	ah,[priority]		; keep a copy of priority varible for faster cmp
+
+??loop_top:
+	lodsb				; get the pixel on the screen
+	or	al,al			; check to see if al is transparent
+	je	short ??write_back	; if it is go write background
+
+	mov	bl,[gs:di]		; get the mask byte for our pixel
+
+					; get rid of non-walkable bit and
+					; get rid of scaling id bits
+	and	bl,CLEAR_NON_WALK_BIT_AND_SCALE_BITS
+
+	cmp	ah,bl			; are we more toward the front?
+	jge	short ??out_pixel	; if so then write the pixel
+
+??write_back:
+	mov	al,[fs:di]		; get the pixel to write
+??out_pixel:
+	stosb				; write the pixel
+	loop	??loop_top
+	ret
+
+	ENDP
+
+
+;***************************************************************************
+;* GHOST_NORMAL_DRAW -- Function that writes a normal pixel line           *
+;*                                                                         *
+;* INPUT:	cx    - number of pixels to write                          *
+;*		ds:si - buffer which holds the pixels to write		   *
+;*		es:di - place to put the pixels we are writing		   *
+;*                                                                         *
+;* OUTPUT:      ds:si - points to next pixel past last pixel read          *
+;*		es:di - points to next pixel past last pixel written	   *
+;*                                                                         *
+;* WARNINGS:    none                                                       *
+;*                                                                         *
+;* HISTORY:                                                                *
+;*   05/27/1993 MCC : Created.                                             *
+;*=========================================================================*
+
+	PROC	NOLANGUAGE Ghost_Normal_Draw NEAR
+
+??loop_top:
+	lodsb
+
+;---
+	; Ok, find out if the colour is a Translucent colour
+	push	ax
+	push 	ds
+
+	lds	bx,[IsTranslucent]
+	mov	ah,al			; preserve real pixel
+	xlat				; get new al (transluecent pixel
+	xchg	ah,al			; get real pixel back into AL just in case
+	cmp	ah,255
+	je	short ??normal_pixel		; is it a translucent ?
+					; if we get passed here value in
+					; AH should be 0-15
+
+	; yes, it is a translucent colour so goto our translucent translation
+	; table and set up a ptr to the correct table
+
+	mov	al,[es:di]
+					; mov pixel at destination to al and we have
+					; the index to the translation table
+					; ((trans_colour * 256) + dest colour)
+	lds	bx,[Translucent]	; get the ptr to it!
+	add	bh,ah			; Add the (trans_color * 256) of the translation equ.
+					; XLAT only uses AL so no need to clear AH
+	xlat				; get new pixel in AL
+
+??normal_pixel:
+	pop	ds
+	pop	bx
+	mov	ah,bh
+;---
+
+	mov	[es:di],al		; store the pixel to the screen
+
+??skip:
+	inc	di
+	loop	??loop_top
+
+	ret
+
+	ENDP
+
+
+;***************************************************************************
+;* GHOST_TRANSPARENT_DRAW -- Function that writes a transparent pixel line *
+;*                                                                         *
+;* INPUT:	cx    - number of pixels to write                          *
+;*		ds:si - buffer which holds the pixels to write		   *
+;*		es:di - place to put the pixels we are writing		   *
+;*                                                                         *
+;* OUTPUT:      ds:si - points to next pixel past last pixel read          *
+;*		es:di - points to next pixel past last pixel written	   *
+;*                                                                         *
+;* WARNINGS:    none                                                       *
+;*                                                                         *
+;* HISTORY:                                                                *
+;*   05/27/1993 MCC : Created.                                             *
+;*=========================================================================*
+	PROC	NOLANGUAGE Ghost_Transparent_Draw NEAR
+
+??loop_top:
+	lodsb
+	or	al,al
+	jz	short ??skip
+
+;---
+	; Ok, find out if the colour is a Translucent colour
+	push	ax
+	push 	ds
+
+	lds	bx,[IsTranslucent]
+	mov	ah,al			; preserve real pixel
+	xlat				; get new al (transluecent pixel
+	xchg	ah,al			; get real pixel back into AL just in case
+	cmp	ah,255
+	je	short ??normal_pixel		; is it a translucent ?
+					; if we get passed here value in
+					; AH should be 0-15
+
+	; yes, it is a translucent colour so goto our translucent translation
+	; table and set up a ptr to the correct table
+
+	mov	al,[es:di]
+					; mov pixel at destination to al and we have
+					; the index to the translation table
+					; ((trans_colour * 256) + dest colour)
+	lds	bx,[Translucent]	; get the ptr to it!
+	add	bh,ah			; Add the (trans_color * 256) of the translation equ.
+					; XLAT only uses AL so no need to clear AH
+	xlat				; get new pixel in AL
+
+??normal_pixel:
+	pop	ds
+	pop	bx
+	mov	ah,bh
+;---
+
+	mov	[es:di],al		; store the pixel to the screen
+
+??skip:
+	inc	di
+	loop	??loop_top
+	ret
+
+	ENDP
+
+
+;***************************************************************************
+;* GHOST_PRIORITY_DRAW -- Function that writes a pixels if they are in fron*
+;*		    the given plate.					   *
+;*                                                                         *
+;* INPUT:	cx    - number of pixels to write                          *
+;*		ds:si - buffer which holds the pixels to write		   *
+;*		es:di - place to put the pixels we are writing		   *
+;*                                                                         *
+;* OUTPUT:      ds:si - points to next pixel past last pixel read          *
+;*		es:di - points to next pixel past last pixel written	   *
+;*                                                                         *
+;* WARNINGS:    none                                                       *
+;*                                                                         *
+;* HISTORY:                                                                *
+;*   07/17/1992 PWG : Created.                                             *
+;*   12/01/1992 MBL : Updated to work with latest mask data encoding.      *
+;*   05/27/1993 MCC : Updated to use the new Ghosting fx		   *
+;*   17/01/1993 MCC : Updated for 386, and optimized			   *
+;*=========================================================================*
+	PROC	NOLANGUAGE Ghost_Priority_Draw NEAR
+
+	mov	fs,[background]		; get the SEG of the background page
+	mov	gs,[maskpage]		; get the SEG of the mask info
+	mov	ah,[priority]		; keep a copy of priority varible for faster cmp
+
+
+??loop_top:
+	lodsb				; get the pixel to draw on the screen
+					; get the mask byte for our pixel
+	mov	bl,[ds:di]
+					; get rid of non-walkable bit and
+					; get rid of scaling id bits
+	and	bl,CLEAR_NON_WALK_BIT_AND_SCALE_BITS
+	cmp	ah,bl			; are we more toward the front?
+	jge	short ??out_pixel	; if so then write the pixel
+
+	mov	al,[fs:di]		; get the pixel to write
+??out_pixel:
+	stosb				; write the pixel and inc the DI
+	loop	??loop_top
+
+	ret
+
+	ENDP
+
+
+;***************************************************************************
+;* GHOST_PRIORITY_TRANSPARENT_DRAW -- Function that writes a pixels if they*
+;*		    in front of the given plate.  It also deals with	   *
+;*		    transparent pixels.					   *
+;*                                                                         *
+;* INPUT:	cx    - number of pixels to write                          *
+;*		ds:si - buffer which holds the pixels to write		   *
+;*		es:di - place to put the pixels we are writing		   *
+;*                                                                         *
+;* OUTPUT:      ds:si - points to next pixel past last pixel read          *
+;*		es:di - points to next pixel past last pixel written	   *
+;*                                                                         *
+;* WARNINGS:    none                                                       *
+;*                                                                         *
+;* HISTORY:                                                                *
+;*   07/17/1992 PWG : Created.                                             *
+;*   12/01/1992 MBL : Updated to work with latest mask data encoding.      *
+;*   05/27/1993 MCC : Updated to use the new Ghosting fx		   *
+;*   17/01/1993 MCC : Updated for 386, and optimized			   *
+;*=========================================================================*
+	PROC	NOLANGUAGE Ghost_Priority_Transparent_Draw NEAR
+
+	mov	fs,[background]		; get the SEG of the background page
+	mov	gs,[maskpage]		; get the SEG of the mask info
+	mov	ah,[priority]		; keep a copy of priority varible for faster cmp
+
+??loop_top:
+	lodsb				; get the pixel on the screen
+	or	al,al			; check to see if al is transparent
+	je	short ??write_back	;   if it is go write background
+	mov	bl,[gs:di]		; get the mask byte for our pixel
+					; get rid of non-walkable bit and
+					; get rid of scaling id bits
+	and	bl,CLEAR_NON_WALK_BIT_AND_SCALE_BITS
+	cmp	ah,bl			; are we more toward the front?
+	jge	short ??out_pixel	; if so then write the pixel
+??write_back:
+	mov	al,[fs:di]		; get the pixel to write
+??out_pixel:
+	stosb				; write the pixel
+	loop	??loop_top
+
+	ret
+
+	ENDP
+
+	END

+ 583 - 0
CODE/2KEYFRAM.CPP

@@ -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 - 0
CODE/2SUPPORT.ASM

@@ -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 - 0
CODE/2TXTPRNT.ASM

@@ -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 - 0
CODE/AADATA.CPP

@@ -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 - 0
CODE/ABSTRACT.CPP

@@ -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 - 0
CODE/ABSTRACT.H

@@ -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 - 0
CODE/ADAMTEMP.MAK

@@ -0,0 +1,1847 @@
+#
+#	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\bfile.mav   5.0   11 Nov 1996 09:40:38   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 : MAKEFILE                                 *
+#*                                                                         *
+#*                   Programmer : Joe L. Bostic                            *
+#*                                                                         *
+#*                   Start Date : March 25, 1993                           *
+#*                                                                         *
+#*                  Last Update : March 25, 1993   [JLB]                   *
+#*                                                                         *
+#*-------------------------------------------------------------------------*
+
+
+# Comment out the following line to disable "include file autodependency".
+.AUTODEPEND
+#.SWAP
+
+!include	"rules.mak"
+
+
+##########################################################################
+
+MAPFILES = \
+
+CACHEMAP = \
+	BRIEFING.AUD \
+
+LOCALFILES = \
+	PROLOG.CPS \
+	MAP.AUD \
+	TITLE.CPS \
+	PALETTE.CPS \
+	INTRO.AUD \
+	EGOPAL.PAL \
+	RULES.INI \
+	CREDITS.TXT \
+	ALIPAPER.CPS \
+	3POINT.FNT \
+	8POINT.FNT \
+	EDITFNT.FNT \
+	CONQUER.ENG \
+	DEBUG.ENG \
+	LED.FNT \
+	SNOW.PAL \
+	TEMPERAT.PAL \
+	INTERIOR.PAL \
+	VCR.FNT \
+	HOLE0000.LUT \
+	HOLE0001.LUT \
+	HOLE0002.LUT \
+	HOLE0003.LUT \
+	HOLE0004.LUT \
+	HOLE0005.LUT \
+	HOLE0006.LUT \
+	HOLE0007.LUT \
+	HOLE0008.LUT \
+	HOLE0009.LUT \
+	HOLE0010.LUT \
+	HOLE0011.LUT \
+	HOLE0012.LUT \
+	HOLE0013.LUT \
+	HOLE0014.LUT \
+	HOLE0015.LUT \
+	HOLE0016.LUT \
+	HOLE0017.LUT \
+	HOLE0018.LUT \
+	HOLE0019.LUT \
+	HOLE0020.LUT \
+	HOLE0021.LUT \
+	HOLE0022.LUT \
+	HOLE0023.LUT \
+	HOLE0024.LUT \
+	HOLE0025.LUT \
+	HOLE0026.LUT \
+	HOLE0027.LUT \
+	HOLE0028.LUT \
+	HOLE0029.LUT \
+	HOLE0030.LUT \
+	HOLE0031.LUT \
+	HOLE0032.LUT \
+	HOLE0033.LUT \
+	HOLE0034.LUT \
+	HOLE0035.LUT \
+	HOLE0036.LUT \
+	HOLE0037.LUT \
+	HOLE0038.LUT \
+	HOLE0039.LUT \
+	HOLE0040.LUT \
+	HOLE0041.LUT \
+	HOLE0042.LUT \
+	HOLE0043.LUT \
+	HOLE0044.LUT \
+	HOLE0045.LUT \
+	HOLE0046.LUT \
+	HOLE0047.LUT \
+#	TEMPSCOR.FNT \
+#	6POINT.FNT \
+#	GRAD6FNT.FNT \
+#	SCOREFNT.FNT \
+
+
+# Files that have counterparts in both high and low resolutions.
+# These files will be built into the HIRES.MIX and LORES.MIX files.
+HILORES = \
+	TRANICON.SHP \
+	PIPS.SHP \
+	PULSE.SHP \
+	ATOMICON.SHP \
+	WARPICON.SHP \
+	C1.SHP \
+	C2.SHP \
+	CHAN.SHP \
+	DELPHI.SHP \
+	E1.SHP \
+	E2.SHP \
+	E3.SHP \
+	E4.SHP \
+	E5.SHP \
+	E6.SHP \
+	E7.SHP \
+	EINSTEIN.SHP \
+	GNRL.SHP \
+	MEDI.SHP \
+	SPY.SHP \
+	THF.SHP \
+	DD-BKGND.SHP \
+	DD-BOTM.SHP \
+	DD-CRNR.SHP \
+	DD-EDGE.SHP \
+	DD-LEFT.SHP \
+	DD-RIGHT.SHP \
+	DD-TOP.SHP \
+	12METFNT.FNT \
+	GRAD6FNT.FNT \
+	HELP.FNT \
+	6POINT.FNT \
+	TYPE.FNT \
+	SCOREFNT.FNT \
+	1TNKICON.SHP \
+	2TNKICON.SHP \
+	3TNKICON.SHP \
+	4TNKICON.SHP \
+	AFLDICON.SHP \
+	AGUNICON.SHP \
+	APCICON.SHP \
+	APWRICON.SHP \
+	ARTYICON.SHP \
+	ATEKICON.SHP \
+	BADRICON.SHP \
+	BARRICON.SHP \
+	BRIKICON.SHP \
+	BTN-DN.SHP \
+	BTN-PL.SHP \
+	BTN-ST.SHP \
+	BTN-UP.SHP \
+	CAICON.SHP \
+	CAMICON.SHP \
+	CLOCK.SHP \
+	DDICON.SHP \
+	DOGICON.SHP \
+	DOMEICON.SHP \
+	DOMFICON.SHP \
+	E1ICON.SHP \
+	E2ICON.SHP \
+	E3ICON.SHP \
+	E4ICON.SHP \
+	E6ICON.SHP \
+	E7ICON.SHP \
+	FACFICON.SHP \
+	FACTICON.SHP \
+	FENCICON.SHP \
+	FIXICON.SHP \
+	FTURICON.SHP \
+	GAPICON.SHP \
+	GPSSICON.SHP \
+	GUNICON.SHP \
+	HARVICON.SHP \
+	HBOXICON.SHP \
+	HELIICON.SHP \
+	HINDICON.SHP \
+	HPADICON.SHP \
+	INFXICON.SHP \
+	IRONICON.SHP \
+	JEEPICON.SHP \
+	KENNICON.SHP \
+	LSTICON.SHP \
+	MAP.SHP \
+	MCVICON.SHP \
+	MEDIICON.SHP \
+	MGGICON.SHP \
+	MIGICON.SHP \
+	MNLYICON.SHP \
+	MOUSE.SHP \
+	MRJICON.SHP \
+	MSLOICON.SHP \
+	NATORADR.SHP \
+	PBMBICON.SHP \
+	PBOXICON.SHP \
+	PDOXICON.SHP \
+	PINFICON.SHP \
+	POWER.SHP \
+	POWERBAR.SHP \
+	POWRICON.SHP \
+	PROCICON.SHP \
+	PTICON.SHP \
+	REPAIR.SHP \
+	SAMICON.SHP \
+	SBAGICON.SHP \
+	SELL.SHP \
+	SIDEBAR.SHP \
+	SILOICON.SHP \
+	SMIGICON.SHP \
+	SONRICON.SHP \
+	SOVPAPER.CPS \
+	SPEFICON.SHP \
+	SPENICON.SHP \
+	SPYICON.SHP \
+	SSICON.SHP \
+	STEKICON.SHP \
+	STRIP.SHP \
+	STRIPDN.SHP \
+	STRIPUP.SHP \
+	SYRDICON.SHP \
+	SYRFICON.SHP \
+	TABS.SHP \
+	TENTICON.SHP \
+	THFICON.SHP \
+	TRUKICON.SHP \
+	TSLAICON.SHP \
+	U2ICON.SHP \
+	USSRRADR.SHP \
+	V2RLICON.SHP \
+	WEAFICON.SHP \
+	WEAPICON.SHP \
+	YAKICON.SHP \
+	NRADRFRM.SHP \
+	URADRFRM.SHP \
+	SIDE1NA.SHP \
+	SIDE1US.SHP \
+	SIDE2NA.SHP \
+	SIDE2US.SHP \
+	SIDE3NA.SHP \
+	SIDE3US.SHP \
+	STRIPNA.SHP \
+	STRIPUS.SHP \
+
+#	MOEBICON.SHP \
+
+HILORES1 = \
+	MECH.SHP \
+	SHOK.SHP \
+	CARRICON.SHP \
+	CTNKICON.SHP \
+	DTRKICON.SHP \
+	MECHICON.SHP \
+	MSUBICON.SHP \
+	QTNKICON.SHP \
+	SHOKICON.SHP \
+	STNKICON.SHP \
+	TTNKICON.SHP \
+
+# These helper macros substitute the extension so that
+# the appropriate art build rule will be invoked.
+xLOHILORES = $(HILORES:.SHP=.LOW)
+LOHILORES = $(xLOHILORES:.FNT=.LNT)
+xHIHILORES = $(HILORES:.SHP=.HI)
+HIHILORES = $(xHIHILORES:.FNT=.HNT)
+
+xLOHILORES1 = $(HILORES1:.SHP=.LOW)
+LOHILORES1 = $(xLOHILORES1:.FNT=.LNT)
+xHIHILORES1 = $(HILORES1:.SHP=.HI)
+HIHILORES1 = $(xHIHILORES1:.FNT=.HNT)
+
+#
+# Files required for hires/Win95 version only
+#
+# This mix file is cached
+#
+HIRESFILES = \
+	ALIPAPER.PCX \
+      	PROLOG.PCX \
+	SOVPAPER.PCX \
+	AFTR_HI.PCX \
+	ALY1.PCX \
+	APC_HI.PCX \
+	APHI0049.PCX \
+	BNHI0020.PCX \
+	DCHI0040.PCX \
+	FRHI0166.PCX \
+	LAB.PCX \
+	LANDSBRG.PCX \
+	MAHI0107.PCX \
+	MIG_HI.PCX \
+	MTFACTHI.PCX \
+	NEEDLE.PCX \
+	SOV2.PCX \
+	SPY.PCX \
+	STALIN.PCX \
+	TENT.PCX \
+#	ENG_HI.PCX \
+
+
+CONQUERFILES = \
+	PARABOMB.SHP \
+
+GENERALMAPFILES = \
+	MISSIONS.PKT \
+	CSTRIKE.PKT \
+	TUTORIAL.INI \
+        SCG01EA.INI \     
+        SCG40EA.INI \     
+        SCG41EA.INI \     
+        SCG42EA.INI \     
+        SCG43EA.INI \     
+        SCG44EA.INI \     
+        SCG45EA.INI \     
+        SCG46EA.INI \     
+        SCG47EA.INI \     
+        SCG48EA.INI \     
+        SCU40EA.INI \     
+        SCU41EA.INI \     
+        SCU42EA.INI \     
+        SCU43EA.INI \     
+        SCU44EA.INI \     
+        SCU45EA.INI \     
+        SCU46EA.INI \     
+        SCU47EA.INI \     
+        SCU48EA.INI \     
+	SCU01EA.INI \     
+	SCM01EA.INI \      
+	SCM02EA.INI \ 
+	SCM03EA.INI \ 
+	SCM04EA.INI \ 
+	SCM05EA.INI \ 
+	SCM06EA.INI \ 
+	SCM07EA.INI \ 
+	SCM08EA.INI \ 
+	SCM09EA.INI \ 
+	SCM10EA.INI \ 
+	SCM11EA.INI \ 
+	SCM12EA.INI \ 
+	SCM13EA.INI \ 
+	SCM14EA.INI \ 
+	SCM15EA.INI \ 
+	SCM16EA.INI \ 
+	SCM17EA.INI \ 
+	SCM18EA.INI \ 
+	SCM19EA.INI \ 
+	SCM20EA.INI \ 
+	SCM21EA.INI \ 
+	SCM22EA.INI \ 
+	SCM23EA.INI \ 
+	SCM24EA.INI \ 
+	SCMD0EA.INI \
+	SCMD1EA.INI \
+	SCMD2EA.INI \
+	SCMD3EA.INI \
+	SCMD4EA.INI \
+	SCMD5EA.INI \
+	SCMD6EA.INI \
+	SCMD7EA.INI \
+	SCMD8EA.INI \
+	SCMD9EA.INI \
+	SCME0EA.INI \
+	SCME1EA.INI \
+	SCME2EA.INI \
+	SCME3EA.INI \
+	SCME4EA.INI \
+	SCME5EA.INI \
+	SCME6EA.INI \
+	SCME7EA.INI \
+	SCME8EA.INI \
+	SCME9EA.INI \
+	SCMF0EA.INI \
+	SCMF1EA.INI \
+	SCMF2EA.INI \
+	SCMF3EA.INI \
+	SCMF4EA.INI \
+	SCMF5EA.INI \
+	SCMF6EA.INI \
+	SCMF7EA.INI \
+	SCMF8EA.INI \
+	SCMF9EA.INI \
+	SCMG0EA.INI \
+	SCMG1EA.INI \
+	SCMG2EA.INI \
+	SCMG3EA.INI \
+	SCMG4EA.INI \
+	SCMG5EA.INI \
+	SCMG6EA.INI \
+	SCMG7EA.INI \
+	SCMG8EA.INI \
+	SCMG9EA.INI \
+	SCMH0EA.INI \
+	SCMH1EA.INI \
+	SCMH2EA.INI \
+	SCMH3EA.INI \
+	SCMH4EA.INI \
+	SCMH5EA.INI \
+	SCMH6EA.INI \
+	SCMH7EA.INI \
+	SCMH8EA.INI \
+	SCMH9EA.INI \
+	SCMI0EA.INI \
+	SCMI1EA.INI \
+	SCMI2EA.INI \
+	SCMI3EA.INI \
+	SCMI4EA.INI \
+	SCMI5EA.INI \
+	SCMI6EA.INI \
+	SCMI7EA.INI \
+	SCMI8EA.INI \
+	SCMI9EA.INI \
+	SCMJ0EA.INI \
+	SCMJ1EA.INI \
+	SCMJ2EA.INI \
+	SCMJ3EA.INI \
+	SCMJ4EA.INI \
+	SCMJ5EA.INI \
+	SCMJ6EA.INI \
+	SCMJ7EA.INI \
+	SCMJ8EA.INI \
+	SCMJ9EA.INI \
+	SCMK0EA.INI \
+	SCMK1EA.INI \
+	SCMK2EA.INI \
+	SCMK3EA.INI \
+	SCMK4EA.INI \
+	SCMK5EA.INI \
+	SCMK6EA.INI \
+	SCMK7EA.INI \
+	SCMK8EA.INI \
+	SCMK9EA.INI \
+	SCML0EA.INI \
+	SCML1EA.INI \
+	SCML2EA.INI \
+	SCML3EA.INI \
+	SCML4EA.INI \
+	SCML5EA.INI \
+	SCML6EA.INI \
+	SCML7EA.INI \
+	SCML8EA.INI \
+	SCML9EA.INI \
+	SCMM0EA.INI \
+	SCMM1EA.INI \
+	SCMM2EA.INI \
+	SCMM3EA.INI \
+	SCMM4EA.INI \
+	SCMM5EA.INI \
+	SCMM6EA.INI \
+	SCMM7EA.INI \
+	SCMM8EA.INI \
+	SCMM9EA.INI \
+      	SCM25EA.INI \
+	SCM26EA.INI \
+	SCM27EA.INI \
+	SCM28EA.INI \
+	SCM29EA.INI \
+	SCM30EA.INI \
+	SCM31EA.INI \ 
+	SCM32EA.INI \ 
+	SCM33EA.INI \
+	SCM34EA.INI \
+     	SCM35EA.INI \
+	SCM36EA.INI \
+	SCM37EA.INI \
+	SCM38EA.INI \
+	SCM39EA.INI \
+	SCM40EA.INI \
+	SCM41EA.INI \
+	SCM42EA.INI \
+	SCM43EA.INI \
+	SCM44EA.INI \
+	SCM45EA.INI \
+	SCM46EA.INI \
+	SCM47EA.INI \
+	SCM48EA.INI \
+	SCM49EA.INI \
+	SCM50EA.INI \
+	SCM51EA.INI \
+	SCM52EA.INI \
+	SCM53EA.INI \
+	SCM54EA.INI \
+	SCM55EA.INI \
+	SCM56EA.INI \
+	SCM57EA.INI \
+	SCM58EA.INI \
+	SCM59EA.INI \
+	SCM60EA.INI \
+	SCM61EA.INI \
+	SCM62EA.INI \
+	SCM63EA.INI \
+	SCM64EA.INI \
+	SCM65EA.INI \
+	SCM66EA.INI \
+	SCM67EA.INI \
+	SCM68EA.INI \
+	SCM69EA.INI \
+	SCM70EA.INI \
+	SCM71EA.INI \
+	SCM72EA.INI \
+	SCM73EA.INI \
+	SCM74EA.INI \
+	SCM75EA.INI \
+	SCM76EA.INI \
+	SCM77EA.INI \
+	SCM78EA.INI \
+	SCM79EA.INI \
+	SCM80EA.INI \
+	SCM81EA.INI \
+	SCM82EA.INI \
+	SCM83EA.INI \
+	SCM84EA.INI \
+	SCM85EA.INI \
+	SCM86EA.INI \
+	SCM87EA.INI \
+	SCM88EA.INI \
+	SCM89EA.INI \	
+	SCM90EA.INI \
+	SCM91EA.INI \
+	SCM92EA.INI \
+	SCM93EA.INI \
+	SCM94EA.INI \
+	SCM95EA.INI \
+	SCM96EA.INI \
+	SCM97EA.INI \
+	SCM98EA.INI \
+	SCM99EA.INI \
+	SCM100EA.INI \
+	SCM101EA.INI \
+	SCM102EA.INI \
+	SCM103EA.INI \
+	SCM104EA.INI \
+	SCM105EA.INI \
+	SCM106EA.INI \
+	SCM107EA.INI \
+	SCM108EA.INI \
+	SCM109EA.INI \
+	SCM110EA.INI \
+	SCM111EA.INI \
+	SCM112EA.INI \
+	SCM113EA.INI \
+	SCM114EA.INI \
+	SCM115EA.INI \
+	SCM116EA.INI \
+	SCM117EA.INI \
+	SCM118EA.INI \
+ 	SCM119EA.INI \    
+	SCM120EA.INI \     
+	SCM121EA.INI \    
+	SCM122EA.INI \     
+	SCM123EA.INI \    
+	SCM124EA.INI \    
+	SCM125EA.INI \    
+	SCM126EA.INI \    
+	SCM127EA.INI \    
+	SCM128EA.INI \    
+	SCM129EA.INI \ 
+	SCM130EA.INI \   
+
+NETMAPFILES = \
+
+# Files that aren't cached.
+GENERALFILES = \
+	AFTR_LO.CPS \
+	ALY1-LO.CPS \
+	APC_LO.CPS \
+	APLO0049.CPS \
+	BNLO0020.CPS \
+	DCLO0040.CPS \
+	FRLO0166.CPS \
+	LAB-LO.CPS \
+	LANDS-LO.CPS \
+	MALO0107.CPS \
+	MIG_LO.CPS \
+	MTFACTLO.CPS \
+	NEEDL-LO.CPS \
+	SOV2-LO.CPS \
+	SPY-LO.CPS \
+	STALN-LO.CPS \
+	TENT-LO.CPS \
+	TITLE.CPS \
+	PPAPER.CPS \
+	MSAA.WSA \
+	MSAB.WSA \
+	MSAC.WSA \
+	MSAD.WSA \
+	MSAE.WSA \
+	MSAF.WSA \
+	MSAG.WSA \
+	MSAH.WSA \
+	MSAI.WSA \
+	MSAJ.WSA \
+	MSAK.WSA \
+	MSAL.WSA \
+	MSAM.WSA \
+	MSAN.WSA \
+	MSSA.WSA \
+	MSSB.WSA \
+	MSSC.WSA \
+	MSSD.WSA \
+	MSSE.WSA \
+	MSSF.WSA \
+	MSSG.WSA \
+	MSSH.WSA \
+	MSSI.WSA \
+	MSSJ.WSA \
+	MSSK.WSA \
+	MSSL.WSA \
+	MSSM.WSA \
+	MSSN.WSA \
+
+INTERIORFILES = \
+	BOXES01.INT \
+	BOXES02.INT \
+	BOXES03.INT \
+	BOXES04.INT \
+	BOXES05.INT \
+	BOXES06.INT \
+	BOXES07.INT \
+	BOXES08.INT \
+	BOXES09.INT \
+	XTRA0001.INT \
+	XTRA0002.INT \
+	XTRA0003.INT \
+	XTRA0004.INT \
+	XTRA0005.INT \
+	XTRA0006.INT \
+	XTRA0007.INT \
+	XTRA0008.INT \
+	XTRA0009.INT \
+	XTRA0010.INT \
+	XTRA0011.INT \
+	XTRA0012.INT \
+	XTRA0013.INT \
+	XTRA0014.INT \
+	XTRA0015.INT \
+	XTRA0016.INT \
+	CLEAR1.INT \
+	MOVEFLSH.INT \
+	ARRO0001.INT \
+	ARRO0002.INT \
+	ARRO0003.INT \
+	ARRO0004.INT \
+	ARRO0005.INT \
+	ARRO0006.INT \
+	ARRO0007.INT \
+	ARRO0008.INT \
+	ARRO0009.INT \
+	ARRO0010.INT \
+	ARRO0011.INT \
+	ARRO0012.INT \
+	ARRO0013.INT \
+	ARRO0014.INT \
+	ARRO0015.INT \
+	FLOR0001.INT \
+	FLOR0002.INT \
+	FLOR0003.INT \
+	FLOR0004.INT \
+	FLOR0005.INT \
+	FLOR0006.INT \
+	FLOR0007.INT \
+	GFLR0001.INT \
+	GFLR0002.INT \
+	GFLR0003.INT \
+	GFLR0004.INT \
+	GFLR0005.INT \
+	GSTR0001.INT \
+	GSTR0002.INT \
+	GSTR0003.INT \
+	GSTR0004.INT \
+	GSTR0005.INT \
+	GSTR0006.INT \
+	GSTR0007.INT \
+	GSTR0008.INT \
+	GSTR0009.INT \
+	GSTR0010.INT \
+	GSTR0011.INT \
+	LWAL0001.INT \
+	LWAL0002.INT \
+	LWAL0003.INT \
+	LWAL0004.INT \
+	LWAL0005.INT \
+	LWAL0006.INT \
+	LWAL0007.INT \
+	LWAL0008.INT \
+	LWAL0009.INT \
+	LWAL0010.INT \
+	LWAL0011.INT \
+	LWAL0012.INT \
+	LWAL0013.INT \
+	LWAL0014.INT \
+	LWAL0015.INT \
+	LWAL0016.INT \
+	LWAL0017.INT \
+	LWAL0018.INT \
+	LWAL0019.INT \
+	LWAL0020.INT \
+	LWAL0021.INT \
+	LWAL0022.INT \
+	LWAL0023.INT \
+	LWAL0024.INT \
+	LWAL0025.INT \
+	LWAL0026.INT \
+	LWAL0027.INT \
+	STRP0001.INT \
+	STRP0002.INT \
+	STRP0003.INT \
+	STRP0004.INT \
+	STRP0005.INT \
+	STRP0006.INT \
+	STRP0007.INT \
+	STRP0008.INT \
+	STRP0009.INT \
+	STRP0010.INT \
+	STRP0011.INT \
+	WALL0001.INT \
+	WALL0002.INT \
+	WALL0003.INT \
+	WALL0004.INT \
+	WALL0005.INT \
+	WALL0006.INT \
+	WALL0007.INT \
+	WALL0008.INT \
+	WALL0009.INT \
+	WALL0010.INT \
+	WALL0011.INT \
+	WALL0012.INT \
+	WALL0013.INT \
+	WALL0014.INT \
+	WALL0015.INT \
+	WALL0016.INT \
+	WALL0017.INT \
+	WALL0018.INT \
+	WALL0019.INT \
+	WALL0020.INT \
+	WALL0021.INT \
+	WALL0022.INT \
+	WALL0023.INT \
+	WALL0024.INT \
+	WALL0025.INT \
+	WALL0026.INT \
+	WALL0027.INT \
+	WALL0028.INT \
+	WALL0029.INT \
+	WALL0030.INT \
+	WALL0031.INT \
+	WALL0032.INT \
+	WALL0033.INT \
+	WALL0034.INT \
+	WALL0035.INT \
+	WALL0036.INT \
+	WALL0037.INT \
+	WALL0038.INT \
+	WALL0039.INT \
+	WALL0040.INT \
+	WALL0041.INT \
+	WALL0042.INT \
+	WALL0043.INT \
+	WALL0044.INT \
+	WALL0045.INT \
+	WALL0046.INT \
+	WALL0047.INT \
+	WALL0048.INT \
+	WALL0049.INT \
+
+# Both the temperate and snow sets have identical template entries.
+TEMPERATEFILES = \
+	MINE.TEM \
+	ICE01.TEM \
+	ICE02.TEM \
+	ICE03.TEM \
+	ICE04.TEM \
+	ICE05.TEM \
+	MOVEFLSH.TEM \
+	BR1X.TEM \
+	BR2X.TEM \
+	BRIDGE1X.TEM \
+	BRIDGE2X.TEM \
+	BRIDGE1H.TEM \
+	BRIDGE2H.TEM \
+	F01.TEM \
+	F02.TEM \
+	F03.TEM \
+	F04.TEM \
+	F05.TEM \
+	F06.TEM \
+	ELECTRO.TEM \
+	B1.TEM \
+	B2.TEM \
+	B3.TEM \
+	BIB1.TEM \
+	BIB2.TEM \
+	BIB3.TEM \
+	BR1A.TEM \
+	BR1B.TEM \
+	BR1C.TEM \
+	BR2A.TEM \
+	BR2B.TEM \
+	BR2C.TEM \
+	BR3A.TEM \
+	BR3B.TEM \
+	BR3C.TEM \
+	BR3D.TEM \
+	BR3E.TEM \
+	BR3F.TEM \
+	BRIDGE1.TEM \
+	BRIDGE1D.TEM \
+	BRIDGE2.TEM \
+	BRIDGE2D.TEM \
+	CLEAR1.TEM \
+	CORPSE1.TEM \
+	CORPSE2.TEM \
+	CORPSE3.TEM \
+	CR1.TEM \
+	CR2.TEM \
+	CR3.TEM \
+	CR4.TEM \
+	CR5.TEM \
+	CR6.TEM \
+	D01.TEM \
+	D02.TEM \
+	D03.TEM \
+	D04.TEM \
+	D05.TEM \
+	D06.TEM \
+	D07.TEM \
+	D08.TEM \
+	D09.TEM \
+	D10.TEM \
+	D11.TEM \
+	D12.TEM \
+	D13.TEM \
+	D14.TEM \
+	D15.TEM \
+	D16.TEM \
+	D17.TEM \
+	D18.TEM \
+	D19.TEM \
+	D20.TEM \
+	D21.TEM \
+	D22.TEM \
+	D23.TEM \
+	D24.TEM \
+	D25.TEM \
+	D26.TEM \
+	D27.TEM \
+	D28.TEM \
+	D29.TEM \
+	D30.TEM \
+	D31.TEM \
+	D32.TEM \
+	D33.TEM \
+	D34.TEM \
+	D35.TEM \
+	D36.TEM \
+	D37.TEM \
+	D38.TEM \
+	D39.TEM \
+	D40.TEM \
+	D41.TEM \
+	D42.TEM \
+	D43.TEM \
+	D44.TEM \
+	D45.TEM \
+	FALLS1.TEM \
+	FALLS1A.TEM \
+	FALLS2.TEM \
+	FALLS2A.TEM \
+	FORD1.TEM \
+	FORD2.TEM \
+	GEM01.TEM \
+	GEM02.TEM \
+	GEM03.TEM \
+	GEM04.TEM \
+	GOLD01.TEM \
+	GOLD02.TEM \
+	GOLD03.TEM \
+	GOLD04.TEM \
+	HBOX.TEM \
+	MSLOMAKE.TEM \
+	HBOXMAKE.TEM \
+	MSLO.TEM \
+	P01.TEM \
+	P02.TEM \
+	P03.TEM \
+	P04.TEM \
+	P07.TEM \
+	P08.TEM \
+	P13.TEM \
+	P14.TEM \
+	RC01.TEM \
+	RC02.TEM \
+	RC03.TEM \
+	RC04.TEM \
+	RF01.TEM \
+	RF02.TEM \
+	RF03.TEM \
+	RF04.TEM \
+	RF05.TEM \
+	RF06.TEM \
+	RF07.TEM \
+	RF08.TEM \
+	RF09.TEM \
+	RF10.TEM \
+	RF11.TEM \
+	RV01.TEM \
+	RV02.TEM \
+	RV03.TEM \
+	RV04.TEM \
+	RV05.TEM \
+	RV06.TEM \
+	RV07.TEM \
+	RV08.TEM \
+	RV09.TEM \
+	RV10.TEM \
+	RV11.TEM \
+	RV12.TEM \
+	RV13.TEM \
+	RV14.TEM \
+	RV15.TEM \
+	S01.TEM \
+	S02.TEM \
+	S03.TEM \
+	S04.TEM \
+	S05.TEM \
+	S06.TEM \
+	S07.TEM \
+	S08.TEM \
+	S09.TEM \
+	S10.TEM \
+	S11.TEM \
+	S12.TEM \
+	S13.TEM \
+	S14.TEM \
+	S15.TEM \
+	S16.TEM \
+	S17.TEM \
+	S18.TEM \
+	S19.TEM \
+	S20.TEM \
+	S21.TEM \
+	S22.TEM \
+	S23.TEM \
+	S24.TEM \
+	S25.TEM \
+	S26.TEM \
+	S27.TEM \
+	S28.TEM \
+	S29.TEM \
+	S30.TEM \
+	S31.TEM \
+	S32.TEM \
+	S33.TEM \
+	S34.TEM \
+	S35.TEM \
+	S36.TEM \
+	S37.TEM \
+	S38.TEM \
+	SC1.TEM \
+	SC2.TEM \
+	SC3.TEM \
+	SC4.TEM \
+	SC5.TEM \
+	SC6.TEM \
+	SH01.TEM \
+	SH02.TEM \
+	SH03.TEM \
+	SH04.TEM \
+	SH05.TEM \
+	SH06.TEM \
+	SH07.TEM \
+	SH08.TEM \
+	SH09.TEM \
+	SH10.TEM \
+	SH11.TEM \
+	SH12.TEM \
+	SH13.TEM \
+	SH14.TEM \
+	SH15.TEM \
+	SH16.TEM \
+	SH17.TEM \
+	SH18.TEM \
+	SH19.TEM \
+	SH20.TEM \
+	SH21.TEM \
+	SH22.TEM \
+	SH23.TEM \
+	SH24.TEM \
+	SH25.TEM \
+	SH26.TEM \
+	SH27.TEM \
+	SH28.TEM \
+	SH29.TEM \
+	SH30.TEM \
+	SH31.TEM \
+	SH32.TEM \
+	SH33.TEM \
+	SH34.TEM \
+	SH35.TEM \
+	SH36.TEM \
+	SH37.TEM \
+	SH38.TEM \
+	SH39.TEM \
+	SH40.TEM \
+	SH41.TEM \
+	SH42.TEM \
+	SH43.TEM \
+	SH44.TEM \
+	SH45.TEM \
+	SH46.TEM \
+	SH47.TEM \
+	SH48.TEM \
+	SH49.TEM \
+	SH50.TEM \
+	SH51.TEM \
+	SH52.TEM \
+	SH53.TEM \
+	SH54.TEM \
+	SH55.TEM \
+	SH56.TEM \
+	T01.TEM \
+	T02.TEM \
+	T03.TEM \
+	T05.TEM \
+	T06.TEM \
+	T07.TEM \
+	T08.TEM \
+	T10.TEM \
+	T11.TEM \
+	T12.TEM \
+	T13.TEM \
+	T14.TEM \
+	T15.TEM \
+	T16.TEM \
+	T17.TEM \
+	TC01.TEM \
+	TC02.TEM \
+	TC03.TEM \
+	TC04.TEM \
+	TC05.TEM \
+	V01.TEM \
+	V02.TEM \
+	V03.TEM \
+	V04.TEM \
+	V05.TEM \
+	V06.TEM \
+	V07.TEM \
+	V08.TEM \
+	V09.TEM \
+	V10.TEM \
+	V11.TEM \
+	V12.TEM \
+	V13.TEM \
+	V14.TEM \
+	V15.TEM \
+	V16.TEM \
+	V17.TEM \
+	V18.TEM \
+	W1.TEM \
+	W2.TEM \
+	WC01.TEM \
+	WC02.TEM \
+	WC03.TEM \
+	WC04.TEM \
+	WC05.TEM \
+	WC06.TEM \
+	WC07.TEM \
+	WC08.TEM \
+	WC09.TEM \
+	WC10.TEM \
+	WC11.TEM \
+	WC12.TEM \
+	WC13.TEM \
+	WC14.TEM \
+	WC15.TEM \
+	WC16.TEM \
+	WC17.TEM \
+	WC18.TEM \
+	WC19.TEM \
+	WC20.TEM \
+	WC21.TEM \
+	WC22.TEM \
+	WC23.TEM \
+	WC24.TEM \
+	WC25.TEM \
+	WC26.TEM \
+	WC27.TEM \
+	WC28.TEM \
+	WC29.TEM \
+	WC30.TEM \
+	WC31.TEM \
+	WC32.TEM \
+	WC33.TEM \
+	WC34.TEM \
+	WC35.TEM \
+	WC36.TEM \
+	WC37.TEM \
+	WC38.TEM \
+
+# Every temperate theater terrain file has a snow theater counterpart.
+SNOWFILES = $(TEMPERATEFILES:.TEM=.SNO)
+
+# Sound effects (Juvenile or Adult)
+SFX = \
+
+# Generic wave files (never changes).
+WAVFILES = \
+	AACANON3.AUD \
+	BEEPSLCT.AUD \
+	BLEEP11.AUD \
+	BLEEP12.AUD \
+	BLEEP13.AUD \
+	BLEEP17.AUD \
+	BLEEP5.AUD \
+	BLEEP6.AUD \
+	BLEEP9.AUD \
+	BOMBIT1.AUD \
+	BUILD5.AUD \
+	BUZZY1.AUD \       
+	CANNON1.AUD \
+	CANNON2.AUD \
+	CASHDN1.AUD \
+	CASHTURN.AUD \
+	CASHUP1.AUD \
+	CHRONO2.AUD \
+	CHROTNK1.AUD \
+	CHUTE1.AUD \
+	CMON1.AUD \
+	CRMBLE2.AUD \
+	DEDMAN1.AUD \
+	DEDMAN10.AUD \
+	DEDMAN2.AUD \
+	DEDMAN3.AUD \
+	DEDMAN4.AUD \
+	DEDMAN5.AUD \
+	DEDMAN6.AUD \
+	DEDMAN7.AUD \
+	DEDMAN8.AUD \
+	DOGG5P.AUD \
+	DOGW3PX.AUD \
+	DOGW5.AUD \
+	DOGW6.AUD \
+	DOGW7.AUD \
+	DOGY1.AUD \
+	EAFFIRM1.AUD \
+	EENGIN1.AUD \
+	EINAH1.AUD \
+	EINOK1.AUD \
+	EINYES1.AUD \
+	EMOVOUT1.AUD \
+	EYESSIR1.AUD \
+	FIREBL3.AUD \
+	FIRETRT1.AUD \
+	FIXIT1.AUD \
+	GIRLOKAY.AUD \
+	GIRLYEAH.AUD \
+	GOTIT1.AUD \
+	GRENADE1.AUD \
+	GUN11.AUD \
+	GUN13.AUD \
+	GUN27.AUD \
+	GUN5.AUD \
+	GUYOKAY1.AUD \
+	GUYYEAH1.AUD \
+	H2OBOMB2.AUD \
+	HEAL2.AUD \
+	HYDROD1.AUD \
+	INVUL2.AUD \
+	IRONCUR9.AUD \
+	JBURN1.AUD \
+	JCHRGE1.AUD \
+	JCRISP1.AUD \
+	JDANCE1.AUD \
+	JJUICE1.AUD \
+	JJUMP1.AUD \
+	JLIGHT1.AUD \
+	JPOWER1.AUD \
+	JSHOCK1.AUD \
+	JYES1.AUD \
+	KABOOM1.AUD \
+	KABOOM12.AUD \
+	KABOOM15.AUD \
+	KABOOM22.AUD \
+	KABOOM25.AUD \
+	KABOOM30.AUD \
+	KEEPEM1.AUD \
+	LAUGH1.AUD \
+	LEFTY1.AUD \
+	MADCHRG2.AUD \
+	MADEXPLO.AUD \
+	MAFFIRM1.AUD \
+	MBOSS1.AUD \
+	MHEAR1.AUD \
+	MHOTDIG1.AUD \
+	MHOWDY1.AUD \
+	MHUH1.AUD \
+	MGUNINF1.AUD \
+	MINE1.AUD \
+	MINEBLO1.AUD \
+	MINELAY1.AUD \
+	MISSILE1.AUD \
+	MISSILE6.AUD \
+	MISSILE7.AUD \
+	MLAFF1.AUD \
+	MMOVOUT1.AUD \
+	MRESPON1.AUD \
+	MRISE1.AUD \
+	MWRENCH1.AUD \
+	MYEEHAW1.AUD \
+	MYES1.AUD \
+	MYESSIR1.AUD \
+	ONIT1.AUD \
+	PILLBOX1.AUD \
+	PLACBLDG.AUD \
+	RABEEP1.AUD \
+	RADARDN1.AUD \
+	RADARON2.AUD \
+	RAMENU1.AUD \
+	ROKROLL1.AUD \
+	SAFFIRM1.AUD \
+	SANDBAG2.AUD \
+	SCOLDY1.AUD \
+	SCOMND1.AUD \
+	SHKTROP1.AUD \
+	SILENCER.AUD \
+	SINDEED1.AUD \
+	SKING1.AUD \
+	SMOUT1.AUD \
+	SOKAY1.AUD \
+	SONPULSE.AUD \
+	SONWAY1.AUD \
+	SPLASH9.AUD \
+	SQUISHY2.AUD \
+	SUBSHOW1.AUD \
+	SWHAT1.AUD \
+	SYEAH1.AUD \
+	SYESSIR1.AUD \
+	TANDETH1.AUD \
+	TANK5.AUD \
+	TANK6.AUD \
+	TESLA1.AUD \
+	TORPEDO1.AUD \
+	TSLACHG2.AUD \
+	TUFFGUY1.AUD \
+	TURRET1.AUD \
+	WALLKIL2.AUD \
+	YEAH1.AUD \
+	YES1.AUD \
+	YO1.AUD \
+
+# Vehicle responses
+RESPONSE1 = \
+	ACKNO.AUD \
+	AFFIRM1.AUD \
+	AWAIT1.AUD \
+	REPORT1.AUD \
+	VEHIC1.AUD \
+	YESSIR1.AUD \
+
+# Infantry responses
+RESPONSE2 = \
+	ACKNO.AUD \
+	AFFIRM1.AUD \
+	AWAIT1.AUD \
+	NOPROB.AUD \
+	OVEROUT.AUD \
+	READY.AUD \
+	REPORT1.AUD \
+	RITAWAY.AUD \
+	ROGER.AUD \
+	UGOTIT.AUD \
+	YESSIR1.AUD \
+
+#TSCOREFILES = \
+#	cps\record.bin \
+#	WIN1.AUD \
+#	MAP1.AUD \
+
+VARFILES = \
+
+SCOREFILES = \
+	CREDITS.AUD  \
+	AWAIT.AUD    \
+	BIGF226M.AUD \
+	CRUS226M.AUD \
+	DENSE_R.AUD  \
+	FAC1226M.AUD \
+	FAC2226M.AUD \
+	FOGGER1A.AUD \
+	HELL226M.AUD \
+	MUD1A.AUD \
+	RADIO2.AUD \
+	ROLLOUT.AUD \
+	RUN1226M.AUD \
+	SCORE.AUD \
+	SMSH226M.AUD \
+	SNAKE.AUD \
+	TERMINAT.AUD \
+	TREN226M.AUD \
+	TWIN.AUD \
+	VECTOR1A.AUD \
+	WORK226M.AUD \
+	2ND_HAND.AUD \   
+	ARAZIOD.AUD \   
+	BACKSTAB.AUD \
+	CHAOS2.AUD \ 
+	SHUT_IT.AUD \   
+	TWINMIX1.AUD \   
+	UNDER3.AUD \   
+	VR2.AUD \
+	BOG.AUD \
+	FLOAT_V2.AUD \
+	GLOOM.AUD \
+	GRNDWIRE.AUD \
+	RPT.AUD \
+	SEARCH.AUD \
+	TRACTION.AUD \
+	WASTELND.AUD \
+
+SPEECHFILES = \
+	STRCKIL1.AUD \
+	NOPOWR1.AUD \
+	SAVE1.AUD \
+	LOAD1.AUD \
+	10MINR.AUD \
+	1MINR.AUD \
+	1OBJMET1.AUD \
+	20MINR.AUD \
+	2MINR.AUD \
+	2OBJMET1.AUD \
+	30MINR.AUD \
+	3MINR.AUD \
+	3OBJMET1.AUD \
+	40MINR.AUD \
+	4MINR.AUD \
+	5MINR.AUD \
+	AAPPRO1.AUD \
+	AARIVE1.AUD \
+	AARIVE1.AUD \
+	AARRIVE1.AUD \
+	AARRIVN1.AUD \
+	AARRIVS1.AUD \
+	AARRIVW1.AUD \
+	AAVAIL1.AUD \
+	ABLDGIN1.AUD \
+	AFALLEN1.AUD \
+	ALAUNCH1.AUD \
+	APREP1.AUD \
+	AREADY1.AUD \
+	ARMORUP1.AUD \
+	ASELECT1.AUD \
+	ATLNCH1.AUD \
+	ATPREP1.AUD \
+	AUNITL1.AUD \
+	BASEATK1.AUD \
+	BCT1.AUD \
+	BLDGINF1.AUD \
+	BLDGPRG1.AUD \
+	CANCLD1.AUD \
+	CHROCHR1.AUD \
+	CHRORDY1.AUD \
+	CHROYES1.AUD \
+	CMDCNTR1.AUD \
+	CNTLDED1.AUD \
+	COMNDOF1.AUD \
+	COMNDOR1.AUD \
+	CONSCMP1.AUD \
+	CONVLST1.AUD \
+	CONVYAP1.AUD \
+	CREDIT1.AUD \
+	ENMYAPP1.AUD \
+	FIREPO1.AUD \
+	FLARE1.AUD \
+	FLAREE1.AUD \
+	FLAREN1.AUD \
+	FLARES1.AUD \
+	FLAREW1.AUD \
+	IRONCHG1.AUD \
+	IRONRDY1.AUD \
+	KOSYFRE1.AUD \
+	KOSYRES1.AUD \
+	LOPOWER1.AUD \
+	MERCF1.AUD \
+	MERCR1.AUD \
+	MISNLST1.AUD \
+	MISNWON1.AUD \
+	MTIMEIN1.AUD \
+	NAVYLST1.AUD \
+	NEWOPT1.AUD \
+	NOBUILD1.AUD \
+	NODEPLY1.AUD \
+	NOFUNDS1.AUD \
+	NOFUNDS1.AUD \
+	OBJMET1.AUD \
+	OBJNMET1.AUD \
+	OBJNRCH1.AUD \
+	OBJRCH1.AUD \
+	ONHOLD1.AUD \
+	OPTERM1.AUD \
+	PRIBLDG1.AUD \
+	PROGRES1.AUD \
+	PULSE1.AUD \
+	REINFOR1.AUD \
+	REPAIR1.AUD \
+	REPAIR1.AUD \
+	SATLNCH1.AUD \
+	SILOND1.AUD \
+	SLCTTGT1.AUD \
+	SOVEFAL1.AUD \
+	SOVEMP1.AUD \
+	SOVFAPP1.AUD \
+	SOVFORC1.AUD \
+	SOVREIN1.AUD \
+	SPYPLN1.AUD \
+	STRUCAP1.AUD \
+	STRUSLD1.AUD \
+	TANYAF1.AUD \
+	TANYAR1.AUD \
+	TARGFRE1.AUD \
+	TARGRES1.AUD \
+	TIMERGO1.AUD \
+	TIMERNO1.AUD \
+	TRAIN1.AUD \
+	UNITFUL1.AUD \
+	UNITLST1.AUD \
+	UNITRDY1.AUD \
+	UNITREP1.AUD \
+	UNITSLD1.AUD \
+	UNITSPD1.AUD \
+	XPLOPLC1.AUD \
+#	ABLDGC1.AUD \
+#	SOVBLDG1.AUD \
+#	SOVSTRC1.AUD \
+#	SOVUNTD1.AUD \
+#	AUNITD1.AUD \
+#	ASTRUCD1.AUD \
+
+#ALLIESVQ = \
+DUMMYVQ = \
+	AAGUN.VQA \
+	AFTRMATH.VQA \
+	ALLY1.VQA \
+	ALLY10.VQA \
+	ALLY10B.VQA \
+	ALLY11.VQA \
+	ALLY12.VQA \
+	ALLY14.VQA \
+	ALLY2.VQA \
+	ALLY4.VQA \
+	ALLY5.VQA \
+	ALLY6.VQA \
+	ALLY8.VQA \
+	ALLY9.VQA \
+	ALLYEND.VQA \
+	ALLYMORF.VQA \
+	APCESCPE.VQA \
+	ASSESS.VQA \
+	BATTLE.VQA \
+	1BINOC.VQA \
+	BMAP.VQA \
+	BRDGTILT.VQA \
+	CRONTEST.VQA \
+	CRONFAIL.VQA \
+	DESTROYR.VQA \
+	DUD.VQA \
+	ELEVATOR.VQA \
+	FLARE.VQA \
+	FROZEN.VQA \
+	GRVESTNE.VQA \
+	LANDING.VQA \
+	MASASSLT.VQA \
+	MCV.VQA \
+	MCV_LAND.VQA \
+	MONTPASS.VQA \
+	OILDRUM.VQA \
+	OVERRUN.VQA \
+	PROLOG.VQA \
+	REDINTRO.VQA \
+	SHIPSINK.VQA \
+	SHORBOM1.VQA \
+	SHORBOM2.VQA \
+	SHORBOMB.VQA \
+	SNOWBOMB.VQA \
+	SOVIET1.VQA \
+	SOVTSTAR.VQA \
+	SPY.VQA \
+	TANYA1.VQA \
+	TANYA2.VQA \
+	TOOFAR.VQA \
+	TRINITY.VQA \
+#	TRAILER.VQA \
+
+SOVIETVQ = \
+       	AAGUN.VQA \
+	CRONFAIL.VQA \
+	AIRFIELD.VQA \
+	ALLY1.VQA \
+	ALLYMORF.VQA \
+	AVERTED.VQA \
+	BEACHEAD.VQA \
+	BMAP.VQA \
+	BOMBRUN.VQA \
+	COUNTDWN.VQA \
+	DOUBLE.VQA \
+	DPTHCHRG.VQA \
+	EXECUTE.VQA \
+	FLARE.VQA \
+	LANDING.VQA \
+	MCVBRDGE.VQA \
+	MIG.VQA \
+	MOVINGIN.VQA \
+	MTNKFACT.VQA \
+	NUKESTOK.VQA \
+	ONTHPRWL.VQA \
+	PERISCOP.VQA \
+	PROLOG.VQA \
+	RADRRAID.VQA \
+	REDINTRO.VQA \
+	SEARCH.VQA \
+	SFROZEN.VQA \
+	SITDUCK.VQA \
+	SLNTSRVC.VQA \
+	SNOWBOMB.VQA \
+	SNSTRAFE.VQA \
+	SOVBATL.VQA \
+	SOVCEMET.VQA \
+	SOVFINAL.VQA \
+	SOVIET1.VQA \
+	SOVIET10.VQA \
+	SOVIET11.VQA \
+	SOVIET12.VQA \
+	SOVIET13.VQA \
+	SOVIET14.VQA \
+	SOVIET2.VQA \
+	SOVIET3.VQA \
+	SOVIET4.VQA \
+	SOVIET5.VQA \
+	SOVIET6.VQA \
+	SOVIET7.VQA \
+	SOVIET8.VQA \
+	SOVIET9.VQA \
+	SOVMCV.VQA \
+	SOVTSTAR.VQA \
+	SPOTTER.VQA \
+	STRAFE.VQA \
+	TAKE_OFF.VQA \
+	TESLA.VQA \
+	V2ROCKET.VQA \
+#	TRAILER.VQA \
+
+ALLIESVQ = \
+	AFTRMATH.VQA \
+	ALLY1.VQA \
+	ALLYMORF.VQA \
+	APCESCPE.VQA \
+ BATTLE.VQA \
+	BMAP.VQA \	
+	CRONFAIL.VQA \
+ DPTHCHRG.VQA \
+	EXECUTE.VQA \
+	FLARE.VQA \	
+	FROZEN.VQA \
+	GRVESTNE.VQA \
+	LANDING.VQA \
+	MASASSLT.VQA \
+ NUKESTOK.VQA \
+ ONTHPRWL.VQA \
+	OVERRUN.VQA \
+	PROLOG.VQA \
+	REDINTRO.VQA \
+	SFROZEN.VQA \
+ SLNTSRVC.VQA \
+	SNOWBOMB.VQA \
+ SNOWBASE.VQA \
+ SOVMCV.VQA \
+	SNSTRAFE.VQA \
+	SOVBATL.VQA \
+	SOVCEMET.VQA \
+	SOVIET1.VQA \
+	SOVTSTAR.VQA \
+	SPY.VQA \
+ STRAFE.VQA \
+	TESLA.VQA \
+	TOOFAR.VQA \
+	TRINITY.VQA \
+	V2ROCKET.VQA \		
+#	ANTEND.VQA \
+#	ANTINTRO.VQA \
+	
+
+
+# Files required for hires/Win95 version only
+#
+# This mix file is not cached
+#
+NOCACHEHIRESFILES= \
+	ENGLISH.VQA \
+	$(ALLIESVQ:.VQA=.VQP) \
+	$(SOVIETVQ:.VQA=.VQP) \
+       
+
+LINTOBJECTS1 = $(OBJECTS:,=)
+LINTOBJECTS = $(LINTOBJECTS1:.OBJ=.LOB)
+
+# Mixfiles that should reside on the CD-ROM drive.
+CD1MIXFILES = \
+	CONQUER.MIX \
+	
+
+
+# Mixfiles that should reside on the hard drive.
+LOCALMIXFILES = \
+	EDITOR.MIX \
+	HIRES.MIX \
+	LOCAL.MIX \
+	LORES.MIX \
+	NCHIRES.MIX \
+	SPEECH.MIX \
+	
+
+# Mixfiles as they appear on the CD and hard drive.
+
+
+
+# Ant assets SOME ASSETS ARE HERE FOR OVERRIDING
+EXPANDFILES= \
+	ANT1.SHP \
+	ANT2.SHP \
+	ANT3.SHP \
+	QUEE.SHP \
+	CREDITS.ENG \
+	HILL01.TEM \
+	ANTBITE.AUD \
+	ANTDIE.AUD \
+	ANTDIE.SHP \
+	LAR1.SHP \
+	LAR2.SHP \
+	TITLE.PCX \							  
+	MISSION.INI \
+	BUZZY1.AUD \       
+	STAVCMDR.AUD \     
+	STAVCRSE.AUD \     
+	STAVYES.AUD \      
+	STAVMOV.AUD \
+	CONQUER.ENG \   
+	RAMBO1.AUD \
+	RAMBO2.AUD \
+	RAMBO3.AUD \
+	TITLE.CPS \
+	TUTORIAL.INI \
+	BMAP.VQP \
+	ANTEND.VQP \
+	ANTINTRO.VQP \
+
+# Aftermath expansion files
+EXPAND2FILES= \
+	CARR.SHP \
+
+
+
+#############################################################
+# Rebuilds all the mixfiles.				  
+packfiles:	always $(PACKFILES)
+
+always:
+	copy f:\projects\c&c0\editor\english\*.mix $(.path.mix) /u
+
+
+####################################################################
+# All mixfiles that exist on the CD-ROM are embedded within this mega-mixfile.
+$(.path.cd1)MAIN.MIX: $(CD1MIXFILES)
+	UTILS\MIXFILE -k -I$(.path.mix) &&!
+	$**
+! $(.path.cd1)$&.mix
+
+
+
+
+####################################################################
+# These are the various sub-mixfiles.
+CONQUER.MIX: $(CONQUERFILES) $(CACHEMAP) .\key.ini
+	UTILS\MIXFILE -k -h -I$(.path.cps) &&!
+	$(CONQUERFILES) $(CACHEMAP)
+! $(.path.mix)$&.mix
+
+TEMPERAT.MIX: $(TEMPERATEFILES) .\key.ini
+	UTILS\MIXFILE -h -k -I$(.path.cps) &&!
+	$(TEMPERATEFILES)
+! $(.path.mix)$&.mix
+
+SNOW.MIX: $(SNOWFILES) .\key.ini
+	UTILS\MIXFILE -h -k -I$(.path.cps) &&!
+	$(SNOWFILES)
+! $(.path.mix)$&.mix
+
+INTERIOR.MIX: $(INTERIORFILES) .\key.ini
+	UTILS\MIXFILE -h -k -I$(.path.cps) &&!
+	$(INTERIORFILES)
+! $(.path.mix)$&.mix
+
+GENERAL.MIX: $(GENERALFILES) $(GENERALMAPFILES) $(NETMAPFILES) $(MAPFILES) .\key.ini
+	UTILS\MIXFILE -k -I$(.path.cps) -I$(.path.ini) &&!
+	$(GENERALFILES) $(GENERALMAPFILES) $(NETMAPFILES) $(MAPFILES)
+! $(.path.mix)$&.mix
+
+SCORES.MIX: $(SCOREFILES)
+	UTILS\MIXFILE -k -I$(.path.cps) -I$(.path.ini) &&!
+	$**
+! $(.path.mix)$&.mix
+
+SOUNDS.MIX: $(WAVFILES) $(SFX)
+	UTILS\MIXFILE -h -k -EA60=V00 -EA61=V01 -EA62=V02 -EA63=V03 -I$(.path.aud) &&!
+	$**
+! $(.path.mix)$&.mix
+
+RUSSIAN.MIX: $(RESPONSE1:.AUD=.R00) $(RESPONSE2:.AUD=.R01) $(RESPONSE1:.AUD=.R02) $(RESPONSE2:.AUD=.R03)
+	UTILS\MIXFILE -h -k -I$(.path.aud) &&!
+	$**
+! $(.path.mix)$&.mix
+
+LIMITED.MIX: BLEEP11.AUD
+	UTILS\MIXFILE -h -k -I$(.path.aud) &&!
+	$**
+! $(.path.mix)$&.mix
+
+ALLIES.MIX: $(RESPONSE1:.AUD=.V00) $(RESPONSE2:.AUD=.V01) $(RESPONSE1:.AUD=.V02) $(RESPONSE2:.AUD=.V03)
+	UTILS\MIXFILE -h -k -I$(.path.aud) &&!
+	$**
+! $(.path.mix)$&.mix
+
+MOVIES1.MIX: $(ALLIESVQ)
+	UTILS\MIXFILE -k -I$(.path.vqa) &&!
+	$**
+! $(.path.mix)$&.mix
+
+
+
+
+
+NCHIRES.MIX: $(NOCACHEHIRESFILES:.SHP=.HI)
+	UTILS\MIXFILE -k -I$(.path.vqp) -I$(.path.cps) &&!
+	$(NOCACHEHIRESFILES)
+! $(.path.mix)$&.mix
+
+LOCAL.MIX: $(LOCALFILES) .\key.ini
+	UTILS\MIXFILE -h -k -E.A6=.AUD -I$(.path.ini) -I$(.path.txt) -I$(.path.cps) &&!
+	$(LOCALFILES)
+! $(.path.mix)$&.mix
+
+LORES.MIX: $(LOHILORES) .\key.ini
+	UTILS\MIXFILE -h -k -E.LOW=.SHP -E.LNT=.FNT -I$(.path.cps) &&!
+	$(LOHILORES)
+! $(.path.mix)$&.mix
+
+HIRES.MIX: $(HIRESFILES:.SHP=.HI) $(HIHILORES) .\key.ini
+	UTILS\MIXFILE -h -k -E.HI=.SHP -E.HNT=.FNT -I$(.path.cps) &&!
+	$(HIRESFILES:.SHP=.HI) $(HIHILORES)
+! $(.path.mix)$&.mix
+
+LORES1.MIX: $(LOHILORES1) .\key.ini
+	UTILS\MIXFILE -h -k -E.LOW=.SHP -E.LNT=.FNT -I$(.path.cps) &&!
+	$(LOHILORES1)
+! $(.path.mix)$&.mix
+
+HIRES1.MIX: $(HIHILORES1) .\key.ini
+	UTILS\MIXFILE -h -k -E.HI=.SHP -E.HNT=.FNT -I$(.path.cps) &&!
+	$(HIHILORES1)
+! $(.path.mix)$&.mix
+
+SPEECH.MIX: $(SPEECHFILES)
+	UTILS\MIXFILE -k -I$(.path.aud) &&!
+	$**
+! $(.path.mix)$&.mix
+
+
+EXPAND.MIX: $(EXPANDFILES)			   
+	UTILS\MIXFILE -k  -I$(.path.mix)  &&!
+	$**
+! $(.path.mix)$&.mix
+
+EXPAND2.MIX: $(EXPAND2FILES)			   
+	UTILS\MIXFILE -k  -I$(.path.mix)  &&!
+	$**
+! $(.path.mix)$&.mix
+
+#############################################################
+# Special rule to create the mouse shape (which must be a shape file)
+mouse.hi:	$(.path.anm)hires\mouse.anm
+	-utils\makeshps $(.path.lbm)palettes\temperat.lbm &&!
+ &$(.path.anm)hires\mouse.anm;
+ end;
+! $(.path.hi)$&.hi $(SHAPEBUFFSIZE)
+
+# Special rule to create the mouse shape (which must be a shape file)
+mouse.low:	$(.path.anm)lores\mouse.anm
+	-utils\makeshps $(.path.lbm)palettes\temperat.lbm &&!
+ &$(.path.anm)lores\mouse.anm;
+ end;
+! $(.path.low)$&.low $(SHAPEBUFFSIZE)
+
+
+#############################################################
+# Special build rule for radar animations so that they won't.
+#
+NATORADR.HI: $(.path.anm)hires\NATORADR.ANM
+	utils\newkeyf $** $(.path.hi)$&.hi -l -k
+
+USSRRADR.HI: $(.path.anm)hires\USSRRADR.ANM
+	utils\newkeyf $** $(.path.hi)$&.hi -l -k
+
+NATORADR.LOW: $(.path.anm)lores\NATORADR.ANM
+	utils\newkeyf $** $(.path.low)$&.low -l -k
+
+USSRRADR.LOW: $(.path.anm)lores\USSRRADR.ANM
+	utils\newkeyf $** $(.path.low)$&.low -l -k
+
+
+#############################################################
+# Debug text file creation.
+debug.eng:	debug.txt
+	utils\textmake -b1000 eng\$&.txt $(.path.eng)$&.eng $&.h
+
+

+ 2361 - 0
CODE/ADATA.CPP

@@ -0,0 +1,2361 @@
+/*
+**	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/ADATA.CPP 3     3/07/97 4:27p 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 : ADATA.CPP                                                    *
+ *                                                                                             *
+ *                   Programmer : Joe L. Bostic                                                *
+ *                                                                                             *
+ *                   Start Date : May 30, 1994                                                 *
+ *                                                                                             *
+ *                  Last Update : July 9, 1996 [JLB]                                           *
+ *                                                                                             *
+ *---------------------------------------------------------------------------------------------*
+ * Functions:                                                                                  *
+ *   AnimTypeClass::AnimTypeClass -- Constructor for animation types.                          *
+ *   AnimTypeClass::One_Time -- Performs one time action for animation types.                  *
+ *   AnimTypeClass::Init -- Load any animation artwork that is theater specific.               *
+ *   Anim_Name -- Fetches the ASCII name of the animation type specified.                      *
+ *   AnimTypeClass::As_Reference -- Fetch a reference to the animation type specified.         *
+ *   AnimTypeClass::Init_Heap -- Initialize the animation type system.                         *
+ *   AnimTypeClass::operator new -- Allocate an animation type object from private pool.       *
+ *   AnimTypeClass::operator delete -- Returns an anim type class object back to the pool.     *
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+#include	"function.h"
+
+static AnimTypeClass const AtomBomb(
+	ANIM_ATOM_BLAST,						// Animation number.
+	"ATOMSFX",								// Data name of animation.
+	72,										// Maximum dimension of animation.
+	19,										// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	true,										// Scorches the ground?
+	true,										// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+
+static AnimTypeClass const SputDoor(
+	ANIM_SPUTDOOR,							// Animation number.
+	"SPUTDOOR",								// Data name of animation.
+	42,										// Maximum dimension of animation.
+	1,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	-1,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	1,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+
+// Electrocution death anim from Tesla coil
+static AnimTypeClass const ElectricDie(
+	ANIM_ELECT_DIE,						// Animation number.
+	"ELECTRO",									// Data name of animation.
+	16,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	true,										// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	true,										// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	true,										// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	3,											// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	5,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_FIRE_MED
+);
+
+// Electrocution death anim from Tesla coil for dog
+static AnimTypeClass const DogElectricDie(
+	ANIM_DOG_ELECT_DIE,					// Animation number.
+	"ELECTDOG",								// Data name of animation.
+	17,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	true,										// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	true,										// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	3,											// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	5,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_FIRE_MED
+);
+
+static AnimTypeClass const SAMN(
+	ANIM_SAM_N,								// Animation number.
+	"SAMFIRE",								// Data name of animation.
+	55,										// Maximum dimension of animation.
+	4,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	18*0,										// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	18,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+static AnimTypeClass const SAMNW(
+	ANIM_SAM_NW,							// Animation number.
+	"SAMFIRE",								// Data name of animation.
+	55,										// Maximum dimension of animation.
+	22,										// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	18*1,										// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	18,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+static AnimTypeClass const SAMW(
+	ANIM_SAM_W,								// Animation number.
+	"SAMFIRE",								// Data name of animation.
+	55,										// Maximum dimension of animation.
+	40,										// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	18*2,										// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	18,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+static AnimTypeClass const SAMSW(
+	ANIM_SAM_SW,							// Animation number.
+	"SAMFIRE",								// Data name of animation.
+	55,										// Maximum dimension of animation.
+	58,										// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	18*3,										// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	18,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+static AnimTypeClass const SAMS(
+	ANIM_SAM_S,								// Animation number.
+	"SAMFIRE",								// Data name of animation.
+	55,										// Maximum dimension of animation.
+	76,										// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	18*4,										// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	18,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+static AnimTypeClass const SAMSE(
+	ANIM_SAM_SE,							// Animation number.
+	"SAMFIRE",								// Data name of animation.
+	55,										// Maximum dimension of animation.
+	94,										// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	18*5,										// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	18,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+static AnimTypeClass const SAME(
+	ANIM_SAM_E,								// Animation number.
+	"SAMFIRE",								// Data name of animation.
+	55,										// Maximum dimension of animation.
+	112,										// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	18*6,										// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	18,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+static AnimTypeClass const SAMNE(
+	ANIM_SAM_NE,							// Animation number.
+	"SAMFIRE",								// Data name of animation.
+	55,										// Maximum dimension of animation.
+	130,										// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	18*7,										// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	18,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+
+static AnimTypeClass const LZSmoke(
+	ANIM_LZ_SMOKE,						// Animation number.
+	"SMOKLAND",								// Data name of animation.
+	32,										// Maximum dimension of animation.
+	72,										// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	true,										// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	2,											// Delay between frames.
+	0,											// Starting frame number.
+	72,										// Loop start frame number.
+	91,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	255,										// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+
+/*
+**	Flammable object burning animations. Primarily used on trees and buildings.
+*/
+static AnimTypeClass const BurnSmall(
+	ANIM_BURN_SMALL,						// Animation number.
+	"BURN-S",								// Data name of animation.
+	11,										// Maximum dimension of animation.
+	13,										// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	true,										// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	fixed(1, 32),							// Damage to apply per tick (fixed point).
+	2,											// Delay between frames.
+	0,											// Starting frame number.
+	30,										// Loop start frame number.
+	62,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	4,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+static AnimTypeClass const BurnMed(
+	ANIM_BURN_MED,							// Animation number.
+	"BURN-M",								// Data name of animation.
+	14,										// Maximum dimension of animation.
+	13,										// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	true,										// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	fixed(1, 16),							// Damage to apply per tick (fixed point).
+	2,											// Delay between frames.
+	0,											// Starting frame number.
+	30,										// Loop start frame number.
+	62,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	4,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+static AnimTypeClass const BurnBig(
+	ANIM_BURN_BIG,							// Animation number.
+	"BURN-L",								// Data name of animation.
+	23,										// Maximum dimension of animation.
+	13,										// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	true,										// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	true,										// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	fixed(1, 10),							// Damage to apply per tick (fixed point).
+	2,											// Delay between frames.
+	0,											// Starting frame number.
+	30,										// Loop start frame number.
+	62,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	4,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+
+/*
+**	Flammable object burning animations that trail into smoke. Used for
+**	buildings and the gunboat.
+*/
+static AnimTypeClass const OnFireSmall(
+	ANIM_ON_FIRE_SMALL,					// Animation number.
+	"BURN-S",								// Data name of animation.
+	11,										// Maximum dimension of animation.
+	13,										// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	true,										// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	fixed(1, 32),							// Damage to apply per tick (fixed point).
+	2,											// Delay between frames.
+	0,											// Starting frame number.
+	30,										// Loop start frame number.
+	62,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	4,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_SMOKE_M
+);
+static AnimTypeClass const OnFireMed(
+	ANIM_ON_FIRE_MED,						// Animation number.
+	"BURN-M",								// Data name of animation.
+	14,										// Maximum dimension of animation.
+	13,										// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	true,										// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	fixed(1, 16),							// Damage to apply per tick (fixed point).
+	2,											// Delay between frames.
+	0,											// Starting frame number.
+	30,										// Loop start frame number.
+	62,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	4,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_ON_FIRE_SMALL
+);
+static AnimTypeClass const OnFireBig(
+	ANIM_ON_FIRE_BIG,						// Animation number.
+	"BURN-L",								// Data name of animation.
+	23,										// Maximum dimension of animation.
+	13,										// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	true,										// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	true,										// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	fixed(1, 10),							// Damage to apply per tick (fixed point).
+	2,											// Delay between frames.
+	0,											// Starting frame number.
+	30,										// Loop start frame number.
+	62,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	4,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_ON_FIRE_MED
+);
+static AnimTypeClass const Parachute(
+	ANIM_PARACHUTE,						// Animation number.
+	"PARACH",								// Data name of animation.
+	32,										// Maximum dimension of animation.
+	15,										// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	4,											// Delay between frames.
+	0,											// Starting frame number.
+	7,											// Loop start frame number.
+	-1,										// Loopback frame number.
+	-1,										// Number of animation stages.
+	15,										// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+static AnimTypeClass const ParaBomb(
+	ANIM_PARA_BOMB,						// Animation number.
+	"PARABOMB",								// Data name of animation.
+	32,										// Maximum dimension of animation.
+	8,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	4,											// Delay between frames.
+	0,											// Starting frame number.
+	7,											// Loop start frame number.
+	-1,										// Loopback frame number.
+	-1,										// Number of animation stages.
+	15,										// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+
+static AnimTypeClass const FBall1(
+	ANIM_FBALL1,							// Animation number.
+	"FBALL1",								// Data name of animation.
+	67,										// Maximum dimension of animation.
+	6,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	true,										// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	-1,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	1,											// Number of times the animation loops.
+	VOC_KABOOM25,							// Sound effect to play.
+	ANIM_NONE
+);
+
+static AnimTypeClass const Frag1(
+	ANIM_FRAG1,								// Animation number.
+	"FRAG1",									// Data name of animation.
+	45,										// Maximum dimension of animation.
+	3,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	true,										// Forms a crater?
+	true,										// Sticks to unit in square?
+	true,										// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	-1,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	1,											// Number of times the animation loops.
+	VOC_KABOOM30,							// Sound effect to play.
+	ANIM_NONE
+);
+
+static AnimTypeClass const VehHit1(
+	ANIM_VEH_HIT1,							// Animation number.
+	"VEH-HIT1",								// Data name of animation.
+	30,										// Maximum dimension of animation.
+	4,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	true,										// Forms a crater?
+	true,										// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	-1,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	1,											// Number of times the animation loops.
+	VOC_KABOOM25,							// Sound effect to play.
+	ANIM_NONE
+);
+
+static AnimTypeClass const VehHit2(
+	ANIM_VEH_HIT2,							// Animation number.
+	"VEH-HIT2",								// Data name of animation.
+	21,										// Maximum dimension of animation.
+	1,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	true,										// Forms a crater?
+	true,										// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	-1,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	1,											// Number of times the animation loops.
+	VOC_KABOOM12,								// Sound effect to play.
+	ANIM_NONE
+);
+
+static AnimTypeClass const VehHit3(
+	ANIM_VEH_HIT3,							// Animation number.
+	"VEH-HIT3",								// Data name of animation.
+	19,										// Maximum dimension of animation.
+	3,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	true,										// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	-1,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	1,											// Number of times the animation loops.
+	VOC_KABOOM12,								// Sound effect to play.
+	ANIM_NONE
+);
+
+static AnimTypeClass const ArtExp1(
+	ANIM_ART_EXP1,							// Animation number.
+	"ART-EXP1",								// Data name of animation.
+	41,										// Maximum dimension of animation.
+	1,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	true,										// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	-1,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	1,											// Number of times the animation loops.
+	VOC_KABOOM22,							// Sound effect to play.
+	ANIM_NONE
+);
+
+static AnimTypeClass const Napalm1(
+	ANIM_NAPALM1,							// Animation number.
+	"NAPALM1",								// Data name of animation.
+	21,										// Maximum dimension of animation.
+	5,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	true,										// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	-1,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	1,											// Number of times the animation loops.
+	VOC_FIRE_EXPLODE,						// Sound effect to play.
+	ANIM_NONE
+);
+
+static AnimTypeClass const Napalm2(
+	ANIM_NAPALM2,							// Animation number.
+	"NAPALM2",								// Data name of animation.
+	41,										// Maximum dimension of animation.
+	5,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	true,										// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	-1,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	1,											// Number of times the animation loops.
+	VOC_FIRE_EXPLODE,						// Sound effect to play.
+	ANIM_NONE
+);
+
+static AnimTypeClass const Napalm3(
+	ANIM_NAPALM3,							// Animation number.
+	"NAPALM3",								// Data name of animation.
+	78,										// Maximum dimension of animation.
+	5,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	true,										// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	-1,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	1,											// Number of times the animation loops.
+	VOC_FIRE_LAUNCH,							// Sound effect to play.
+	ANIM_NONE
+);
+
+static AnimTypeClass const SmokePuff(
+	ANIM_SMOKE_PUFF,						// Animation number.
+	"SMOKEY",								// Data name of animation.
+	24,										// Maximum dimension of animation.
+	2,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	true,										// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	-1,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	1,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+
+static AnimTypeClass const FireBallFade(
+	ANIM_FBALL_FADE,						// Animation number.
+	"FB2",									// Data name of animation.
+	24,										// Maximum dimension of animation.
+	1,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	-1,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	1,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+
+static AnimTypeClass const Piff(
+	ANIM_PIFF,								// Animation number.
+	"PIFF",									// Data name of animation.
+	13,										// Maximum dimension of animation.
+	1,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	-1,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	1,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+
+static AnimTypeClass const PiffPiff(
+	ANIM_PIFFPIFF,							// Animation number.
+	"PIFFPIFF",								// Data name of animation.
+	20,										// Maximum dimension of animation.
+	2,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	-1,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	1,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+
+static AnimTypeClass const Fire3(
+	ANIM_FIRE_SMALL,						// Animation number.
+	"FIRE3",									// Data name of animation.
+	23,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	true,										// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	fixed(1, 32),							// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	-1,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	2,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+
+static AnimTypeClass const Fire1(
+	ANIM_FIRE_MED2,		 				// Animation number.
+	"FIRE1",									// Data name of animation.
+	23,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	true,										// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	true,										// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	fixed(1, 16),							// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	-1,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	3,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+
+static AnimTypeClass const Fire4(
+	ANIM_FIRE_TINY,		 				// Animation number.
+	"FIRE4",									// Data name of animation.
+	7,											// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	true,										// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	fixed(1, 32),							// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	-1,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	3,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+
+static AnimTypeClass const Fire2(
+	ANIM_FIRE_MED,							// Animation number.
+	"FIRE2",									// Data name of animation.
+	23,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	true,										// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	true,										// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	fixed(1, 16),							// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	-1,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	3,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+
+static AnimTypeClass const OilFieldBurn(
+	ANIM_OILFIELD_BURN,					// Animation number.
+	"FLMSPT",								// Data name of animation.
+	42,										// Maximum dimension of animation.
+	58,										// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	true,										// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	33,										// Loop start frame number.
+	99,										// Ending frame of loop back.
+	66,										// Number of animation stages.
+	65535,									// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+
+static AnimTypeClass const Gunfire(
+	ANIM_MUZZLE_FLASH,					// Animation number.
+	"GUNFIRE",								// Data name of animation.
+	16,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	true,										// Ground level animation?
+	true,										// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Number of times the animation loops.
+	1,											// Number of animation stages.
+	1,											// Ending frame of loop back.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+
+static AnimTypeClass const SmokeM(
+	ANIM_SMOKE_M,							// Animation number.
+	"SMOKE_M",								// Data name of animation.
+	28,										// Maximum dimension of animation.
+	30,										// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	true,										// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	67,										// Loop start frame number.
+	-1,										// Loopback frame number.
+	-1,										// Number of animation stages.
+	6,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+
+/*
+**	Mini-gun fire effect -- used by guard towers.
+*/
+static AnimTypeClass const GUNN(
+	ANIM_GUN_N,								// Animation number.
+	"MINIGUN",								// Data name of animation.
+	18,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Number of times the animation loops.
+	6,											// Number of animation stages.
+	0,											// Ending frame of loop back.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+static AnimTypeClass const GUNNW(
+	ANIM_GUN_NW,							// Animation number.
+	"MINIGUN",								// Data name of animation.
+	18,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	6,											// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Number of times the animation loops.
+	6,											// Number of animation stages.
+	0,											// Ending frame of loop back.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+static AnimTypeClass const GUNW(
+	ANIM_GUN_W,								// Animation number.
+	"MINIGUN",								// Data name of animation.
+	18,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	12,										// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Number of times the animation loops.
+	6,											// Number of animation stages.
+	0,											// Ending frame of loop back.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+static AnimTypeClass const GUNSW(
+	ANIM_GUN_SW,							// Animation number.
+	"MINIGUN",								// Data name of animation.
+	18,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	18,										// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Number of times the animation loops.
+	6,											// Number of animation stages.
+	0,											// Ending frame of loop back.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+static AnimTypeClass const GUNS(
+	ANIM_GUN_S,								// Animation number.
+	"MINIGUN",								// Data name of animation.
+	18,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	24,										// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Number of times the animation loops.
+	6,											// Number of animation stages.
+	0,											// Ending frame of loop back.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+static AnimTypeClass const GUNSE(
+	ANIM_GUN_SE,							// Animation number.
+	"MINIGUN",								// Data name of animation.
+	18,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	30,										// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Number of times the animation loops.
+	6,											// Number of animation stages.
+	0,											// Ending frame of loop back.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+static AnimTypeClass const GUNE(
+	ANIM_GUN_E,								// Animation number.
+	"MINIGUN",								// Data name of animation.
+	18,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	36,										// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Number of times the animation loops.
+	6,											// Number of animation stages.
+	0,											// Ending frame of loop back.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+static AnimTypeClass const GUNNE(
+	ANIM_GUN_NE,							// Animation number.
+	"MINIGUN",								// Data name of animation.
+	18,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	false,									// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	42,										// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Number of times the animation loops.
+	6,											// Number of animation stages.
+	0,											// Ending frame of loop back.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+static AnimTypeClass const CDeviator(
+	ANIM_CRATE_DEVIATOR,					// Animation number.
+	"DEVIATOR",								// Data name of animation.
+	48,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	2,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE								// Follow up animation.
+);
+
+static AnimTypeClass const CrateArmor(
+	ANIM_CRATE_ARMOR,						// Animation number.
+	"ARMOR",									// Data name of animation.
+	48,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	2,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE								// Follow up animation.
+);
+static AnimTypeClass const CrateSpeed(
+	ANIM_CRATE_SPEED,						// Animation number.
+	"SPEED",									// Data name of animation.
+	48,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	2,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE								// Follow up animation.
+);
+
+static AnimTypeClass const CrateFPower(
+	ANIM_CRATE_FPOWER,					// Animation number.
+	"FPOWER",								// Data name of animation.
+	48,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	2,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE								// Follow up animation.
+);
+static AnimTypeClass const CrateTQuake(
+	ANIM_CRATE_TQUAKE,					// Animation number.
+	"TQUAKE",								// Data name of animation.
+	48,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	2,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE								// Follow up animation.
+);
+
+static AnimTypeClass const CDollar(
+	ANIM_CRATE_DOLLAR,					// Animation number.
+	"DOLLAR",								// Data name of animation.
+	48,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	2,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE								// Follow up animation.
+);
+static AnimTypeClass const CEarth(
+	ANIM_CRATE_EARTH,						// Animation number.
+	"EARTH",									// Data name of animation.
+	48,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	2,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE								// Follow up animation.
+);
+static AnimTypeClass const CEmpulse(
+	ANIM_CRATE_EMPULSE,					// Animation number.
+	"EMPULSE",								// Data name of animation.
+	48,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	2,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE								// Follow up animation.
+);
+static AnimTypeClass const CInvun(
+	ANIM_CRATE_INVUN,						// Animation number.
+	"INVUN",									// Data name of animation.
+	48,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	2,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE								// Follow up animation.
+);
+static AnimTypeClass const CMine(
+	ANIM_CRATE_MINE,						// Animation number.
+	"MINE",									// Data name of animation.
+	48,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	2,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE								// Follow up animation.
+);
+static AnimTypeClass const CRapid(
+	ANIM_CRATE_RAPID,						// Animation number.
+	"RAPID",									// Data name of animation.
+	48,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	2,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE								// Follow up animation.
+);
+static AnimTypeClass const CStealth(
+	ANIM_CRATE_STEALTH,					// Animation number.
+	"STEALTH2",								// Data name of animation.
+	48,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	2,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE								// Follow up animation.
+);
+static AnimTypeClass const ChronoBox(
+	ANIM_CHRONO_BOX,						// Animation number.
+	"CHRONBOX",								// Data name of animation.
+	48,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	2,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE								// Follow up animation.
+);
+static AnimTypeClass const GPSBox(
+	ANIM_GPS_BOX,							// Animation number.
+	"GPSBOX",								// Data name of animation.
+	48,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	2,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE								// Follow up animation.
+);
+static AnimTypeClass const InvulBox(
+	ANIM_INVUL_BOX,						// Animation number.
+	"INVULBOX",								// Data name of animation.
+	48,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	2,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE								// Follow up animation.
+);
+static AnimTypeClass const ParaBox(
+	ANIM_PARA_BOX,							// Animation number.
+	"PARABOX",								// Data name of animation.
+	48,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	2,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE								// Follow up animation.
+);
+static AnimTypeClass const SonarBox(
+	ANIM_SONAR_BOX,						// Animation number.
+	"SONARBOX",								// Data name of animation.
+	48,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	2,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE								// Follow up animation.
+);
+
+static AnimTypeClass const CMissile(
+	ANIM_CRATE_MISSILE,					// Animation number.
+	"MISSILE2",								// Data name of animation.
+	48,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	2,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE								// Follow up animation.
+);
+
+static AnimTypeClass const MoveFlash(
+	ANIM_MOVE_FLASH,							// Animation number.
+	"MOVEFLSH",								// Data name of animation.
+	24,										// Maximum dimension of animation.
+	0,											// Biggest animation stage.
+	true,										// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	true,										// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	true,										// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE								// Follow up animation.
+);
+
+static AnimTypeClass const Corpse1(
+	ANIM_CORPSE1,							// Animation number.
+	"CORPSE1",								// Data name of animation.
+	24,										// Maximum dimension of animation.
+	1,											// Biggest animation stage.
+	true,										// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	true,										// Ground level animation?
+	true,										// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	15,										// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+
+static AnimTypeClass const Corpse2(
+	ANIM_CORPSE2,							// Animation number.
+	"CORPSE2",								// Data name of animation.
+	24,										// Maximum dimension of animation.
+	1,											// Biggest animation stage.
+	true,										// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	true,										// Ground level animation?
+	true,										// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	15,										// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+
+static AnimTypeClass const Corpse3(
+	ANIM_CORPSE3,							// Animation number.
+	"CORPSE3",								// Data name of animation.
+	24,										// Maximum dimension of animation.
+	1,											// Biggest animation stage.
+	true,										// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	true,										// Ground level animation?
+	true,										// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	15,										// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	0,											// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	0,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+
+static AnimTypeClass const Twinkle1(
+	ANIM_TWINKLE1,							// Animation number.
+	"TWINKLE1",								// Data name of animation.
+	8,											// Maximum dimension of animation.
+	1,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	-1,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	1,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+static AnimTypeClass const Twinkle2(
+	ANIM_TWINKLE2,							// Animation number.
+	"TWINKLE2",								// Data name of animation.
+	8,											// Maximum dimension of animation.
+	1,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	-1,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	1,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+static AnimTypeClass const Twinkle3(
+	ANIM_TWINKLE3,							// Animation number.
+	"TWINKLE3",								// Data name of animation.
+	8,											// Maximum dimension of animation.
+	1,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	-1,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	1,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+static AnimTypeClass const Flak(
+	ANIM_FLAK,								// Animation number.
+	"FLAK",									// Data name of animation.
+	8,											// Maximum dimension of animation.
+	7,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	-1,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	1,											// Number of times the animation loops.
+	VOC_NONE,								// Sound effect to play.
+	ANIM_NONE
+);
+static AnimTypeClass const WaterExp1(
+	ANIM_WATER_EXP1,						// Animation number.
+	"H2O_EXP1",								// Data name of animation.
+	64,										// Maximum dimension of animation.
+	3,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	true,										// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	-1,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	1,											// Number of times the animation loops.
+	VOC_SPLASH,								// Sound effect to play.
+	ANIM_NONE
+);
+static AnimTypeClass const WaterExp2(
+	ANIM_WATER_EXP2,						// Animation number.
+	"H2O_EXP2",								// Data name of animation.
+	40,										// Maximum dimension of animation.
+	3,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	true,										// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	-1,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	1,											// Number of times the animation loops.
+	VOC_SPLASH,								// Sound effect to play.
+	ANIM_NONE
+);
+static AnimTypeClass const WaterExp3(
+	ANIM_WATER_EXP3,						// Animation number.
+	"H2O_EXP3",								// Data name of animation.
+	32,										// Maximum dimension of animation.
+	3,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	true,										// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	-1,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	1,											// Number of times the animation loops.
+	VOC_SPLASH,								// Sound effect to play.
+	ANIM_NONE
+);
+
+
+static AnimTypeClass const MineExp1(
+	ANIM_MINE_EXP1,						// Animation number.
+	"VEH-HIT2",								// Data name of animation.
+	21,										// Maximum dimension of animation.
+	1,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	true,										// Forms a crater?
+	false,									// Sticks to unit in square?
+	false,									// Ground level animation?
+	false,									// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	1,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	-1,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	1,											// Number of times the animation loops.
+	VOC_MINEBLOW,							// Sound effect to play.
+	ANIM_NONE
+);
+
+#ifdef FIXIT_ANTS
+static AnimTypeClass const AntDeath(
+	ANIM_ANT_DEATH,						// Animation number.
+	"ANTDIE",								// Data name of animation.
+	28,										// Maximum dimension of animation.
+	1,											// Biggest animation stage.
+	false,									// Theater specific art imagery?
+	true,										// Normalized animation rate?
+	false,									// Uses white translucent table?
+	false,									// Scorches the ground?
+	false,									// Forms a crater?
+	false,									// Sticks to unit in square?
+	true,										// Ground level animation?
+	true,										// Translucent colors in this animation?
+	false,									// Is this a flame thrower animation?
+	0,											// Damage to apply per tick (fixed point).
+	4,											// Delay between frames.
+	0,											// Starting frame number.
+	0,											// Loop start frame number.
+	-1,										// Ending frame of loop back.
+	-1,										// Number of animation stages.
+	1,											// Number of times the animation loops.
+	VOC_ANTDIE,								// Sound effect to play.
+	ANIM_NONE
+);
+#endif
+
+/***********************************************************************************************
+ * AnimTypeClass::AnimTypeClass -- Constructor for animation types.                            *
+ *                                                                                             *
+ *    This is the constructor for static objects that elaborate the various animation types    *
+ *    allowed in the game. Each animation in the game is of one of these types.                *
+ *                                                                                             *
+ * INPUT:   see below...                                                                       *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/23/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+AnimTypeClass::AnimTypeClass(
+		AnimType anim,
+		char const * name,
+		int size,
+		int biggest,
+		bool istheater,
+		bool isnormal,
+		bool iswhitetrans,
+		bool isscorcher,
+		bool iscrater,
+		bool issticky,
+		bool ground,
+		bool istrans,
+		bool isflame,
+		fixed damage,
+		int delaytime,
+		int start,
+		int loopstart,
+		int loopend,
+		int stages,
+		int loops,
+		VocType soundid,
+		AnimType chainto) :
+	ObjectTypeClass(RTTI_ANIMTYPE,
+			int(anim),
+			true,
+			true,
+			false,
+			false,
+			true,
+			true,
+			false,
+			TXT_NONE,
+			name
+			),
+	IsNormalized(isnormal),
+	IsGroundLayer(ground),
+	IsTranslucent(istrans),
+	IsWhiteTrans(iswhitetrans),
+	IsFlameThrower(isflame),
+	IsScorcher(isscorcher),
+	IsCraterForming(iscrater),
+	IsSticky(issticky),
+	IsTheater(istheater),
+	Type(anim),
+	Size(size),
+	Biggest(biggest),
+	Damage(damage),
+	Delay(delaytime),
+	Start(start),
+	LoopStart(loopstart),
+	LoopEnd(loopend),
+	Stages(stages),
+	Loops(loops),
+	Sound(soundid),
+	ChainTo(chainto)
+{
+}
+
+
+/***********************************************************************************************
+ * AnimTypeClass::operator new -- Allocate an animation type object from private pool.         *
+ *                                                                                             *
+ *    This routine will allocate an animation type class object.                               *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with a pointer to the newly allocated anim type object. If no anim type    *
+ *          could be allocated, then NULL is returned.                                         *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/09/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void * AnimTypeClass::operator new(size_t)
+{
+	return(AnimTypes.Alloc());
+}
+
+
+/***********************************************************************************************
+ * AnimTypeClass::operator delete -- Returns an anim type class object back to the pool.       *
+ *                                                                                             *
+ *    This will return the anim type class object back to the memory pool from whence it was   *
+ *    previously allocated.                                                                    *
+ *                                                                                             *
+ * INPUT:   pointer  -- Pointer to the anim type class object to return to the memory pool.    *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/09/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AnimTypeClass::operator delete(void * pointer)
+{
+	AnimTypes.Free((AnimTypeClass *)pointer);
+}
+
+
+/***********************************************************************************************
+ * AnimTypeClass::Init_Heap -- Initialize the animation type system.                           *
+ *                                                                                             *
+ *    This routine is called to initialize the animation type class heap. It allocates all     *
+ *    known animation types.                                                                   *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/09/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AnimTypeClass::Init_Heap(void)
+{
+	/*
+	**	These anim type class objects must be allocated in the exact order that they
+	**	are specified in the AnimType enumeration. This is necessary because the heap
+	**	allocation block index serves double duty as the type number index.
+	*/
+	new AnimTypeClass(FBall1);
+	new AnimTypeClass(FireBallFade);
+	new AnimTypeClass(Frag1);
+	new AnimTypeClass(VehHit1);
+	new AnimTypeClass(VehHit2);
+	new AnimTypeClass(VehHit3);
+	new AnimTypeClass(ArtExp1);
+	new AnimTypeClass(Napalm1);
+	new AnimTypeClass(Napalm2);
+	new AnimTypeClass(Napalm3);
+	new AnimTypeClass(SmokePuff);
+	new AnimTypeClass(Piff);
+	new AnimTypeClass(PiffPiff);
+	new AnimTypeClass(Fire3);
+	new AnimTypeClass(Fire2);
+	new AnimTypeClass(Fire1);
+	new AnimTypeClass(Fire4);
+	new AnimTypeClass(Gunfire);
+	new AnimTypeClass(SmokeM);
+	new AnimTypeClass(BurnSmall);
+	new AnimTypeClass(BurnMed);
+	new AnimTypeClass(BurnBig);
+	new AnimTypeClass(OnFireSmall);
+	new AnimTypeClass(OnFireMed);
+	new AnimTypeClass(OnFireBig);
+	new AnimTypeClass(SAMN);
+	new AnimTypeClass(SAMNE);
+	new AnimTypeClass(SAME);
+	new AnimTypeClass(SAMSE);
+	new AnimTypeClass(SAMS);
+	new AnimTypeClass(SAMSW);
+	new AnimTypeClass(SAMW);
+	new AnimTypeClass(SAMNW);
+	new AnimTypeClass(GUNN);
+	new AnimTypeClass(GUNNE);
+	new AnimTypeClass(GUNE);
+	new AnimTypeClass(GUNSE);
+	new AnimTypeClass(GUNS);
+	new AnimTypeClass(GUNSW);
+	new AnimTypeClass(GUNW);
+	new AnimTypeClass(GUNNW);
+	new AnimTypeClass(LZSmoke);
+	new AnimTypeClass(CDeviator);
+	new AnimTypeClass(CDollar);
+	new AnimTypeClass(CEarth);
+	new AnimTypeClass(CEmpulse);
+	new AnimTypeClass(CInvun);
+	new AnimTypeClass(CMine);
+	new AnimTypeClass(CRapid);
+	new AnimTypeClass(CStealth);
+	new AnimTypeClass(CMissile);
+	new AnimTypeClass(MoveFlash);
+	new AnimTypeClass(OilFieldBurn);
+	new AnimTypeClass(ElectricDie);
+	new AnimTypeClass(Parachute);
+	new AnimTypeClass(DogElectricDie);
+	new AnimTypeClass(Corpse1);
+	new AnimTypeClass(Corpse2);
+	new AnimTypeClass(Corpse3);
+	new AnimTypeClass(SputDoor);
+	new AnimTypeClass(AtomBomb);
+	new AnimTypeClass(ChronoBox);
+	new AnimTypeClass(GPSBox);
+	new AnimTypeClass(InvulBox);
+	new AnimTypeClass(ParaBox);
+	new AnimTypeClass(SonarBox);
+	new AnimTypeClass(Twinkle1);
+	new AnimTypeClass(Twinkle2);
+	new AnimTypeClass(Twinkle3);
+	new AnimTypeClass(Flak);
+	new AnimTypeClass(WaterExp1);
+	new AnimTypeClass(WaterExp2);
+	new AnimTypeClass(WaterExp3);
+	new AnimTypeClass(CrateArmor);
+	new AnimTypeClass(CrateSpeed);
+	new AnimTypeClass(CrateFPower);
+	new AnimTypeClass(CrateTQuake);
+	new AnimTypeClass(ParaBomb);
+	new AnimTypeClass(MineExp1);
+#ifdef FIXIT_ANTS
+	new AnimTypeClass(AntDeath);
+#endif
+}
+
+/***********************************************************************************************
+ * AnimTypeClass::One_Time -- Performs one time action for animation types.                    *
+ *                                                                                             *
+ *    This will load the animation shape data. It is called by the game initialization         *
+ *    process.                                                                                 *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   This routine should be called ONLY once.                                        *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/02/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AnimTypeClass::One_Time(void)
+{
+	for (AnimType index = ANIM_FIRST; index < ANIM_COUNT; index++) {
+		char fullname[_MAX_FNAME+_MAX_EXT];
+
+		AnimTypeClass const & anim = As_Reference(index);
+
+		if (!anim.IsTheater) {
+
+			_makepath(fullname, NULL, NULL, As_Reference(index).IniName, ".SHP");
+
+			#ifndef NDEBUG
+				RawFileClass file(fullname);
+				if (file.Is_Available()) {
+					((void const *&)As_Reference(index).ImageData) = Load_Alloc_Data(file);
+				} else {
+					((void const *&)As_Reference(index).ImageData) = MFCD::Retrieve(fullname);
+				}
+			#else
+				((void const *&)As_Reference(index).ImageData) = MFCD::Retrieve(fullname);
+			#endif
+		}
+	}
+}
+
+
+/***********************************************************************************************
+ * AnimTypeClass::Init -- Load any animation artwork that is theater specific.                 *
+ *                                                                                             *
+ *    This routine will examine all the animation types and for any that are theater           *
+ *    specific, it will fetch a pointer to the artwork appropriate for the theater specified.  *
+ *                                                                                             *
+ * INPUT:   theater  -- The theater to align the animation artwork with.                       *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   Call this routine when the theater changes.                                     *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/06/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AnimTypeClass::Init(TheaterType theater)
+{
+	if (theater != LastTheater) {
+		for (AnimType index = ANIM_FIRST; index < ANIM_COUNT; index++) {
+			AnimTypeClass const & anim = As_Reference(index);
+
+			if (anim.IsTheater) {
+				char fullname[_MAX_FNAME+_MAX_EXT];	// Fully constructed iconset name.
+				_makepath(fullname, NULL, NULL, anim.IniName, Theaters[theater].Suffix);
+				((void const *&)anim.ImageData) = MFCD::Retrieve(fullname);
+			}
+		}
+	}
+}
+
+
+/***********************************************************************************************
+ * Anim_Name -- Fetches the ASCII name of the animation type specified.                        *
+ *                                                                                             *
+ *    This will convert the animation type specified into a text name. This name can be used   *
+ *    for uniquely identifying the animation.                                                  *
+ *                                                                                             *
+ * INPUT:   anim  -- The anim type to convert to a text string.                                *
+ *                                                                                             *
+ * OUTPUT:  Returns with a pointer to the ASCII string that identifies this animation.         *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/06/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+char const * Anim_Name(AnimType anim)
+{
+	if (anim == ANIM_NONE) return("");
+
+	return(AnimTypeClass::As_Reference(anim).IniName);
+}
+
+
+/***********************************************************************************************
+ * AnimTypeClass::As_Reference -- Fetch a reference to the animation type specified.           *
+ *                                                                                             *
+ *    This routine will convert the animation type specified into a reference to the           *
+ *    animation type class object.                                                             *
+ *                                                                                             *
+ * INPUT:   type  -- The animation type to convert into a reference.                           *
+ *                                                                                             *
+ * OUTPUT:  Returns with a reference to the animation type class object.                       *
+ *                                                                                             *
+ * WARNINGS:   Be sure that the animation type specified is legal. If it isn't then the        *
+ *             results of this routine are undefined.                                          *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/06/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+AnimTypeClass & AnimTypeClass::As_Reference(AnimType type)
+{
+	return(* AnimTypes.Ptr(type));
+}
+

+ 83 - 0
CODE/ADPCM.CPP

@@ -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 - 0
CODE/AIRCRAFT.CPP

@@ -0,0 +1,4375 @@
+/*
+**	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.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 : AIRCRAFT.CPP                                                 *
+ *                                                                                             *
+ *                   Programmer : Joe L. Bostic                                                *
+ *                                                                                             *
+ *                   Start Date : July 22, 1994                                                *
+ *                                                                                             *
+ *                  Last Update : November 2, 1996 [JLB]                                       *
+ *                                                                                             *
+ *---------------------------------------------------------------------------------------------*
+ * Functions:                                                                                  *
+ *   AircraftClass::AI -- Processes the normal non-graphic AI for the aircraft.                *
+ *   AircraftClass::Active_Click_With -- Handles clicking over specified cell.                 *
+ *   AircraftClass::Active_Click_With -- Handles clicking over specified object.               *
+ *   AircraftClass::AircraftClass -- The constructor for aircraft objects.                     *
+ *   AircraftClass::Can_Enter_Cell -- Determines if the aircraft can land at this location.    *
+ *   AircraftClass::Can_Fire -- Checks to see if the aircraft can fire.                        *
+ *   AircraftClass::Cell_Seems_Ok -- Checks to see if a cell is good to enter.                 *
+ *   AircraftClass::Desired_Load_Dir -- Determines where passengers should line up.            *
+ *   AircraftClass::Draw_It -- Renders an aircraft object at the location specified.           *
+ *   AircraftClass::Draw_Rotors -- Draw rotor blades on the aircraft.                          *
+ *   AircraftClass::Edge_Of_World_AI -- Detect if aircraft has exited the map.                 *
+ *   AircraftClass::Enter_Idle_Mode -- Gives the aircraft an appropriate mission.              *
+ *   AircraftClass::Exit_Object -- Unloads passenger from aircraft.                            *
+ *   AircraftClass::Fire_At -- Handles firing a projectile from an aircraft.                   *
+ *   AircraftClass::Fire_Direction -- Determines the direction of fire.                        *
+ *   AircraftClass::Good_Fire_Location -- Searches for and finds a good spot to fire from.     *
+ *   AircraftClass::Good_LZ -- Locates a good spot ot land.                                    *
+ *   AircraftClass::In_Which_Layer -- Calculates the display layer of the aircraft.            *
+ *   AircraftClass::Init -- Initialize the aircraft system to an empty state.                  *
+ *   AircraftClass::Is_LZ_Clear -- Determines if landing zone is free for landing.             *
+ *   AircraftClass::Landing_Takeoff_AI -- Handle aircraft take off and landing processing.     *
+ *   AircraftClass::Look -- Aircraft will look if they are on the ground always.               *
+ *   AircraftClass::Mission_Attack -- Handles the attack mission for aircraft.                 *
+ *   AircraftClass::Mission_Enter -- Control aircraft to fly to the helipad or repair center.  *
+ *   AircraftClass::Mission_Guard -- Handles aircraft in guard mode.                           *
+ *   AircraftClass::Mission_Guard_Area -- Handles the aircraft guard area logic.               *
+ *   AircraftClass::Mission_Hunt -- Maintains hunt AI for the aircraft.                        *
+ *   AircraftClass::Mission_Move -- Handles movement mission.                                  *
+ *   AircraftClass::Mission_Retreat -- Handles the aircraft logic for leaving the battlefield. *
+ *   AircraftClass::Mission_Unload -- Handles unloading cargo.                                 *
+ *   AircraftClass::Movement_AI -- Handles aircraft physical movement logic.                   *
+ *   AircraftClass::New_LZ -- Find a good landing zone.                                        *
+ *   AircraftClass::Overlap_List -- Returns with list of cells the aircraft overlaps.          *
+ *   AircraftClass::Paradrop_Cargo -- Drop a passenger by parachute.                           *
+ *   AircraftClass::Per_Cell_Process -- Handle the aircraft per cell process.                  *
+ *   AircraftClass::Pip_Count -- Returns the number of "objects" in aircraft.                  *
+ *   AircraftClass::Player_Assign_Mission -- Handles player input to assign a mission.         *
+ *   AircraftClass::Pose_Dir -- Fetches the natural landing facing.                            *
+ *   AircraftClass::Process_Fly_To -- Handles state machine for flying to destination.         *
+ *   AircraftClass::Process_Landing -- Landing process state machine handler.                  *
+ *   AircraftClass::Process_Take_Off -- State machine support for taking off.                  *
+ *   AircraftClass::Read_INI -- Reads aircraft object data from an INI file.                   *
+ *   AircraftClass::Receive_Message -- Handles receipt of radio messages.                      *
+ *   AircraftClass::Response_Attack -- Gives audio response to attack order.                   *
+ *   AircraftClass::Response_Move -- Gives audio response to move request.                     *
+ *   AircraftClass::Response_Select -- Gives audio response when selected.                     *
+ *   AircraftClass::Rotation_AI -- Handle aircraft body and flight rotation.                   *
+ *   AircraftClass::Scatter -- Causes the aircraft to move away a bit.                         *
+ *   AircraftClass::Set_Speed -- Sets the speed for the aircraft.                              *
+ *   AircraftClass::Shape_Number -- Fetch the shape number to use for the aircraft.            *
+ *   AircraftClass::Sort_Y -- Figures the sorting coordinate.                                  *
+ *   AircraftClass::Take_Damage -- Applies damage to the aircraft.                             *
+ *   AircraftClass::Unlimbo -- Removes an aircraft from the limbo state.                       *
+ *   AircraftClass::What_Action -- Determines what action to perform.                          *
+ *   AircraftClass::What_Action -- Determines what action to perform.                          *
+ *   AircraftClass::operator delete -- Deletes the aircraft object.                            *
+ *   AircraftClass::operator new -- Allocates a new aircraft object from the pool              *
+ *   AircraftClass::~AircraftClass -- Destructor for aircraft object.                          *
+ *   _Counts_As_Civ_Evac -- Is the specified object a candidate for civilian evac logic?       *
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+#include	"function.h"
+
+
+/***********************************************************************************************
+ * _Counts_As_Civ_Evac -- Is the specified object a candidate for civilian evac logic?         *
+ *                                                                                             *
+ *    Examines the specified object to see if it qualifies to be a civilian evacuation. This   *
+ *    can only occur if it is a civilian (or Tanya) and the special evacuation flag has been   *
+ *    set in the scenario control structure.                                                   *
+ *                                                                                             *
+ * INPUT:   candidate   -- Candidate object to examine for civilian evacuation legality.       *
+ *                                                                                             *
+ * OUTPUT:  bool; Is the specified object considered a civilian that must be auto-evacuated?   *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/24/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+static bool _Counts_As_Civ_Evac(ObjectClass const * candidate)
+{
+	/*
+	**	If the candidate pointer is missing, then return with failure code.
+	*/
+	if (candidate == NULL) return(false);
+
+	/*
+	**	Only infantry objects can be considered for civilian evacuation action.
+	*/
+	if (candidate->What_Am_I() != RTTI_INFANTRY) return(false);
+
+	/*
+	**	Working infantry object pointer.
+	*/
+	InfantryClass const * inf = (InfantryClass const *)candidate;
+
+	/*
+	**	Certain infantry types will always be considered a civilian evacuation candidate. These
+	**	include the special one-time infantry that appear in some missions.
+	*/
+	if (*inf == INFANTRY_EINSTEIN || *inf == INFANTRY_GENERAL || *inf == INFANTRY_DELPHI || *inf == INFANTRY_CHAN) return(true);
+
+	/*
+	**	Consider Tanya to be part of the civilian evacuation logic if the scenario is
+	**	specially flagged for this.
+	*/
+	if (Scen.IsTanyaEvac && *inf == INFANTRY_TANYA) return(true);
+
+	/*
+	**	If the infantry is not a civilian, then it isn't allowed to be a civilian evacuation.
+	*/
+	if (!inf->Class->IsCivilian) return(false);
+
+	/*
+	**	Technicians look like civilians, but are not considered a legal evacuation candidate.
+	*/
+	if (inf->IsTechnician) return(false);
+
+	/*
+	**	All tests pass, so return the success of the infantry as a civilian evacuation candidate.
+	*/
+	return(true);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::operator new -- Allocates a new aircraft object from the pool                *
+ *                                                                                             *
+ *    This routine will allocate an aircraft object from the free aircraft object pool. If     *
+ *    there are no free object available, then this routine will fail (return NULL).           *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with a pointer to the allocate aircraft object or NULL if none were        *
+ *          available.                                                                         *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/26/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void * AircraftClass::operator new(size_t)
+{
+	void * ptr = Aircraft.Allocate();
+	if (ptr) {
+		((AircraftClass *)ptr)->IsActive = true;
+	}
+	return(ptr);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::operator delete -- Deletes the aircraft object.                              *
+ *                                                                                             *
+ *    This routine will return the aircraft object back to the free aircraft object pool.      *
+ *                                                                                             *
+ * INPUT:   ptr   -- Pointer to the aircraft object to delete.                                 *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/26/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AircraftClass::operator delete(void * ptr)
+{
+	if (ptr) {
+		((AircraftClass *)ptr)->IsActive = false;
+	}
+	Aircraft.Free((AircraftClass *)ptr);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::AircraftClass -- The constructor for aircraft objects.                       *
+ *                                                                                             *
+ *    This routine is the constructor for aircraft objects. An aircraft object can be          *
+ *    created and possibly placed into the game system by this routine.                        *
+ *                                                                                             *
+ * INPUT:   classid  -- The type of aircraft to create.                                        *
+ *                                                                                             *
+ *          house    -- The owner of this aircraft.                                            *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/26/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+AircraftClass::AircraftClass(AircraftType classid, HousesType house) :
+	FootClass(RTTI_AIRCRAFT, Aircraft.ID(this), house),
+	Class(AircraftTypes.Ptr((int)classid)),
+	SecondaryFacing(PrimaryFacing),
+	Passenger(false),
+	IsLanding(false),
+	IsTakingOff(false),
+	IsHovering(false),
+	Jitter(0),
+	SightTimer(0),
+	AttacksRemaining(1)
+{
+	/*
+	**	For two shooters, clear out the second shot flag -- it will be set the first time
+	**	the object fires. For non two shooters, set the flag since it will never be cleared
+	**	and the second shot flag tells the system that normal rearm times apply -- this is
+	**	what is desired for non two shooters.
+	*/
+	IsSecondShot = !Class->Is_Two_Shooter();
+	House->Tracking_Add(this);
+	Ammo = Class->MaxAmmo;
+	Height = FLIGHT_LEVEL;
+	Strength = Class->MaxStrength;
+	NavCom = TARGET_NONE;
+
+	/*
+	** Keep count of the number of units created. Dont track cargo planes as they are created
+	** automatically, not bought.
+	*/
+//	if (/*classid != AIRCRAFT_CARGO && */ Session.Type == GAME_INTERNET) {
+//		House->AircraftTotals->Increment_Unit_Total((int)classid);
+//	}
+
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Unlimbo -- Removes an aircraft from the limbo state.                         *
+ *                                                                                             *
+ *    This routine is used to transition the aircraft from the limbo to the non limbo state.   *
+ *    It occurs when the aircraft is placed on the map for whatever reason. When it is         *
+ *    unlimboed, only then will normal game processing recognize it.                           *
+ *                                                                                             *
+ * INPUT:   coord -- The coordinate that the aircraft should appear at.                        *
+ *                                                                                             *
+ *          dir   -- The direction it should start facing.                                     *
+ *                                                                                             *
+ *				strength (optional) -- sets initial strength													  *
+ *                                                                                             *
+ *				mission (optional) -- sets initial mission													  *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the aircraft unlimboed successfully?                                     *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/26/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool AircraftClass::Unlimbo(COORDINATE coord, DirType dir)
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	if (FootClass::Unlimbo(coord, dir)) {
+
+		if (*this == AIRCRAFT_BADGER || (Class->PrimaryWeapon != NULL && Class->PrimaryWeapon->IsCamera)) {
+			IsALoaner = true;
+		}
+
+		/*
+		**	Ensure that the owning house knows about the
+		**	new object.
+		*/
+		House->AScan |= (1L << Class->Type);
+		House->ActiveAScan |= (1L << Class->Type);
+
+		/*
+		**	Hack it so that aircraft that are both passenger and cargo carrying
+		**	will carry passengers at the expense of ammo.
+		*/
+		if (Is_Something_Attached()) {
+			Ammo = 0;
+			Passenger = true;
+		}
+
+		/*
+		**	Forces the body of the helicopter to face the correct direction.
+		*/
+		SecondaryFacing = dir;
+
+		/*
+		**	Start rotor animation.
+		*/
+		if (!Class->IsFixedWing) {
+			Set_Rate(1);
+			Set_Stage(0);
+		}
+
+		/*
+		**	When starting at flight level, then give it speed. When landed
+		**	then it must be stationary.
+		*/
+		if (Height == FLIGHT_LEVEL) {
+			Set_Speed(0xFF);
+		} else {
+			Set_Speed(0);
+		}
+		return(true);
+	}
+	return(false);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Shape_Number -- Fetch the shape number to use for the aircraft.              *
+ *                                                                                             *
+ *    This will determine what shape number to use for the aircraft in its current state.      *
+ *    The shape number can be used for drawing or determine shape rectangle size.              *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the shape number to use for the aircraft body.                        *
+ *                                                                                             *
+ * WARNINGS:   Some aircraft, particularly helicopters, require other shapes attached to it.   *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/26/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+int AircraftClass::Shape_Number(void) const
+{
+	int shapenum = 0;
+
+	switch (Class->Rotation) {
+		case 32:
+			shapenum = UnitClass::BodyShape[Dir_To_32(SecondaryFacing)];
+			break;
+
+		case 16:
+			shapenum = UnitClass::BodyShape[Dir_To_16(SecondaryFacing)*2]/2;
+			break;
+
+		case 8:
+			shapenum = UnitClass::BodyShape[Dir_To_8(SecondaryFacing)*4]/4;
+			break;
+
+		default:
+			break;
+	}
+
+	/*
+	**	If there is a door on this aircraft (Chinook), then adjust the
+	**	shape number to match the door open state.
+	*/
+	if (!Is_Door_Closed()) {
+		shapenum = Class->Rotation + Door_Stage();
+	}
+
+	return(shapenum);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Draw_It -- Renders an aircraft object at the location specified.             *
+ *                                                                                             *
+ *    This routine is used to display the aircraft object at the coordinates specified.        *
+ *    The tactical map display uses this routine for all aircraft rendering.                   *
+ *                                                                                             *
+ * INPUT:   x,y      -- The coordinates to render the aircraft at.                             *
+ *                                                                                             *
+ *          window   -- The window that the coordinates are based upon.                        *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/26/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AircraftClass::Draw_It(int x, int y, WindowNumberType window) const
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	/*
+	**	Verify the legality of the unit class.
+	*/
+	void const * shapefile = Get_Image_Data();
+	if (!shapefile) return;
+
+	int shapenum = Shape_Number();
+
+	/*
+	**	Certain aircraft use algorithmic rotation for some stages. Set the
+	**	rotation value accordingly. A rotation of DIR_N means no rotation at all.
+	*/
+	DirType rotation = DIR_N;
+	if (Class->Rotation == 16) {
+		rotation = DirType(Rotation16[SecondaryFacing]);
+	}
+
+#ifdef TOFIX
+	/*
+	**	The orca attack helicopter uses a special shape set when it is travelling
+	**	forward above a certain speed.
+	*/
+	if (*this == AIRCRAFT_HIND && Get_Speed() >= MPH_MEDIUM_FAST) {
+		shapenum += Class->Rotation;
+	}
+#endif
+
+	/*
+	**	Helicopters that are flying have a "bobbing" effect.
+	*/
+	int jitter = 0;
+	if (Height == FLIGHT_LEVEL && Get_Speed() < 3) {
+		static int _jitter[] = {0,0,0,0,1,1,1,0,0,0,0,0,-1,-1,-1,0};
+		jitter = _jitter[::Frame % 16];
+	}
+
+	/*
+	**	Special manual shadow draw code.
+	*/
+	if (Visual_Character() <= VISUAL_DARKEN) {
+		CC_Draw_Shape(shapefile, shapenum, x+1, y+2, window, SHAPE_PREDATOR|SHAPE_CENTER|SHAPE_WIN_REL|SHAPE_FADING, DisplayClass::FadingShade, NULL);
+	}
+
+	/*
+	**	Actually draw the root body of the unit.
+	*/
+	Techno_Draw_Object(shapefile, shapenum, x, y+jitter, window, rotation);
+
+	/*
+	**	If this aircraft is equipped with rotor blades, then draw them at this time.
+	*/
+	if (Class->IsRotorEquipped) {
+		Draw_Rotors(x, y+jitter, window);
+	}
+
+	/*
+	**	This draws any overlay graphics on the aircraft.
+	*/
+	FootClass::Draw_It(x, y-Lepton_To_Pixel(Height), window);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Draw_Rotors -- Draw rotor blades on the aircraft.                            *
+ *                                                                                             *
+ *    This routine will draw rotor blades on the aircraft. It is presumed that the aircraft    *
+ *    has already been drawn at the X and Y pixel coordinates specified.                       *
+ *                                                                                             *
+ * INPUT:   x,y   -- The X and Y pixel coordinates to draw the rotor blades.                   *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/26/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AircraftClass::Draw_Rotors(int x, int y, WindowNumberType window) const
+{
+	ShapeFlags_Type flags = SHAPE_CENTER|SHAPE_WIN_REL;
+	int shapenum;
+
+	/*
+	**	The rotor shape number depends on whether the helicopter is idling
+	**	or not. A landed helicopter uses slow moving "idling" blades.
+	*/
+	if (Height == 0) {
+		shapenum = (Fetch_Stage()%8)+4;
+		flags = flags | SHAPE_GHOST;
+	} else {
+		shapenum = Fetch_Stage()%4;
+		flags = flags | SHAPE_FADING|SHAPE_PREDATOR;
+	}
+
+	if (*this == AIRCRAFT_TRANSPORT) {
+		int _stretch[FACING_COUNT] = {8, 9, 10, 9, 8, 9, 10, 9};
+
+		/*
+		**	Dual rotors offset along flight axis.
+		*/
+		short xx = x;
+		short yy = y-Lepton_To_Pixel(Height);
+		FacingType face = Dir_Facing(SecondaryFacing);
+		Move_Point(xx, yy, SecondaryFacing.Current(), _stretch[face]);
+		CC_Draw_Shape(AircraftTypeClass::RRotorData, shapenum, xx, yy-2, window, flags, NULL, DisplayClass::UnitShadow);
+
+		Move_Point(xx, yy, SecondaryFacing.Current()+DIR_S, _stretch[face]*2);
+		CC_Draw_Shape(AircraftTypeClass::LRotorData, shapenum, xx, yy-2, window, flags, NULL, DisplayClass::UnitShadow);
+
+	} else {
+
+		/*
+		**	Single rotor centered about shape.
+		*/
+		CC_Draw_Shape(AircraftTypeClass::RRotorData, shapenum, x, ((y-Lepton_To_Pixel(Height))-2), window, flags, NULL, DisplayClass::UnitShadow);
+	}
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Read_INI -- Reads aircraft object data from an INI file.                     *
+ *                                                                                             *
+ *    This routine is used to read the aircraft object data from the INI file buffer           *
+ *    specified. This is used by the scenario loader code to interpret the INI file and        *
+ *    create the specified objects therein.                                                    *
+ *                                                                                             *
+ * INPUT:   buffer   -- Pointer to the INI buffer.                                             *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/26/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AircraftClass::Read_INI(CCINIClass & ini)
+{
+	AircraftClass	* air;			// Working unit pointer.
+	HousesType		inhouse;			// Unit house.
+	AircraftType	classid;			// Unit class.
+	char				buf[128];
+
+	int counter = ini.Entry_Count(INI_Name());
+	for (int index = 0; index < counter; index++) {
+		char const * entry = ini.Get_Entry(INI_Name(), index);
+
+		ini.Get_String(INI_Name(), entry, NULL, buf, sizeof(buf)-1);
+		inhouse = HouseTypeClass::From_Name(strtok(buf, ","));
+		if (inhouse != HOUSE_NONE) {
+			classid = AircraftTypeClass::From_Name(strtok(NULL, ","));
+
+			if (classid != AIRCRAFT_NONE) {
+
+				air = new AircraftClass(classid, inhouse);
+				if (air) {
+					COORDINATE	coord;
+					int	strength;
+					DirType dir;
+
+					/*
+					**	Read the raw data.
+					*/
+					char * token = strtok(NULL, ",");
+					if (token) {
+						strength = atoi(token);
+					} else {
+						strength = 0;
+					}
+
+					token = strtok(NULL, ",");
+					if (token) {
+						coord = Cell_Coord((CELL)atoi(token));
+					} else {
+						coord = 0xFFFFFFFFL;
+					}
+
+					token = strtok(NULL, ",");
+					if (token) {
+						dir = (DirType)atoi(token);
+					} else {
+						dir = DIR_N;
+					}
+
+					if (!Map.In_Radar(Coord_Cell(coord))) {
+						delete air;
+					} else {
+
+						air->Strength = air->Class->MaxStrength * fixed(strength, 256);
+						if (air->Unlimbo(coord, dir)) {
+							air->Assign_Mission(AircraftClass::Mission_From_Name(strtok(NULL, ",\n\r")));
+						} else {
+							delete air;
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Mission_Hunt -- Maintains hunt AI for the aircraft.                          *
+ *                                                                                             *
+ *    Hunt AI consists of finding a target and attacking it. If there is no target assigned    *
+ *    and this unit doesn't automatically hunt for more targets, then it will change           *
+ *    mission to a more passive (land and await further orders) type.                          *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the number of ticks before calling this routine again.                *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/26/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+int AircraftClass::Mission_Hunt(void)
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	if (Class->IsFixedWing) {
+
+		if (TarCom != NavCom) {
+			Assign_Destination(TarCom);
+		}
+
+		enum {
+			LOOK_FOR_TARGET,
+			TAKE_OFF,
+			FLY_TO_TARGET,
+			DROP_BOMBS,
+			REGROUP
+		};
+		switch (Status) {
+
+			/*
+			**	Acquiring target stage.
+			*/
+			case LOOK_FOR_TARGET:
+				if (Target_Legal(TarCom)) {
+					Status = TAKE_OFF;
+					return(1);
+				} else {
+					if (!Team.Is_Valid()) {
+						if (Session.Type != GAME_NORMAL) {
+							Assign_Target(Greatest_Threat(THREAT_TIBERIUM));
+						}
+						if (!Target_Legal(TarCom)) {
+							Assign_Target(Greatest_Threat(THREAT_NORMAL));
+						}
+
+						/*
+						**	If there is no target, then this aircraft should just do its normal thing.
+						*/
+						if (!Target_Legal(TarCom) && !Team.Is_Valid()) {
+							Enter_Idle_Mode();
+						}
+					}
+				}
+				break;
+
+			/*
+			**	Make the aircraft take off from the airstrip.
+			*/
+			case TAKE_OFF:
+				/*
+				**	If the aircraft is high enough to begin its mission, then do so.
+				*/
+				if (Process_Take_Off())  {
+					IsTakingOff = false;
+					Set_Speed(0xFF);
+
+					/*
+					**	After takeoff is complete, break radio contact.
+					*/
+					if (In_Radio_Contact()/*KO && Map[Coord].Cell_Building() == Contact_With_Whom()*/) {
+						Transmit_Message(RADIO_OVER_OUT);
+					}
+
+					Status = FLY_TO_TARGET;
+				}
+				return(1);
+
+			/*
+			**	Homing in on target stage.
+			*/
+			case FLY_TO_TARGET:
+				switch (Can_Fire(TarCom, 0)) {
+					case FIRE_FACING:
+						/*
+						**	Catch the case where it is tightly circling the target. In that
+						**	case, increase the delay so that it has a chance to fly away and
+						**	break the circle cycle.
+						*/
+						if (In_Range(TarCom, 0) || Passenger) {
+							return(TICKS_PER_SECOND * 2);
+						}
+						if (!PrimaryFacing.Is_Rotating() && Target_Legal(TarCom)) {
+							PrimaryFacing.Set_Desired(Direction(TarCom));
+						}
+						break;
+
+					case FIRE_AMMO:
+						Status = REGROUP;
+						break;
+
+					case FIRE_CANT:
+					case FIRE_ILLEGAL:
+						if (Mission == MISSION_ATTACK) {
+							Status = REGROUP;
+						} else {
+							Status = LOOK_FOR_TARGET;
+						}
+						break;
+
+					case FIRE_OK:
+						Status = DROP_BOMBS;
+						return(1);
+
+					default:
+						if (!PrimaryFacing.Is_Rotating() && Target_Legal(TarCom)) {
+							PrimaryFacing.Set_Desired(Direction(TarCom));
+						}
+						break;
+				}
+				return(TICKS_PER_SECOND/2);
+
+			/*
+			**	Dropping a stream of bombs phase.
+			*/
+			case DROP_BOMBS:
+				TARGET targ;
+				switch (Can_Fire(TarCom, 0)) {
+					case FIRE_OK:
+						targ = ::As_Target(Coord_Move(Center_Coord(), SecondaryFacing, Weapon_Range(0)-0x0200));
+						if (Class->PrimaryWeapon != NULL) {
+							if (Class->PrimaryWeapon->IsCamera) {
+								Status = REGROUP;
+							} else {
+								Map[::As_Cell(TarCom)].Incoming(Coord, true);
+							}
+
+							/*
+							**	Force the target to be the actual target if this aircraft is
+							**	equipped with homing projectile.
+							*/
+							if (Class->PrimaryWeapon->Bullet != NULL && Class->PrimaryWeapon->Bullet->ROT > 0) {
+								targ = TarCom;
+							}
+						}
+						Fire_At(targ, 0);
+						if (Class->Is_Two_Shooter()) {
+							Fire_At(targ, 0);
+						}
+						return(Arm);
+
+					case FIRE_RANGE:
+					case FIRE_FACING:
+						Status = FLY_TO_TARGET;
+						return(TICKS_PER_SECOND*4);
+
+					case FIRE_ILLEGAL:
+						if (Mission == MISSION_ATTACK) {
+							Status = REGROUP;
+						} else {
+							Status = LOOK_FOR_TARGET;
+						}
+						break;
+
+					case FIRE_CANT:
+						Status = REGROUP;
+						break;
+
+					case FIRE_AMMO:
+						AttacksRemaining--;
+						Status = REGROUP;
+						break;
+
+					default:
+						break;
+				}
+				return(1);
+
+			/*
+			**	Pull away to regroup for possibly another attack or a retreat.
+			*/
+			case REGROUP:
+				if (Ammo == 0) {
+					AttacksRemaining = 0;
+					if (Team.Is_Valid()) Team->Remove(this);
+					Enter_Idle_Mode();
+				}
+
+				if (Mission == MISSION_ATTACK || (Class->PrimaryWeapon != NULL && Class->PrimaryWeapon->IsCamera) || (!AttacksRemaining && !Is_Something_Attached())) {
+
+					if (IsALoaner)  {
+						if (Team) Team->Remove(this);
+						Assign_Mission(MISSION_RETREAT);
+						Commence();
+					} else {
+						if (!Team.Is_Valid()) Enter_Idle_Mode();
+					}
+					Commence();
+				} else {
+					Status = LOOK_FOR_TARGET;
+				}
+				break;
+
+			default:
+				break;
+		}
+	} else {
+		if (!Ammo) {
+			if (Team) Team->Remove(this);
+			Enter_Idle_Mode();
+		} else {
+			if (!Target_Legal(TarCom)) {
+				if (Session.Type != GAME_NORMAL) {
+					Assign_Target(Greatest_Threat(THREAT_TIBERIUM));
+				}
+				if (!Target_Legal(TarCom)) {
+					Assign_Target(Greatest_Threat(THREAT_NORMAL));
+				}
+				if (!Target_Legal(TarCom)) {
+					Enter_Idle_Mode();
+					return(1);
+				}
+			}
+
+			Assign_Mission(MISSION_ATTACK);
+			return(1);
+		}
+	}
+	return(MissionControl[Mission].Normal_Delay() + Random_Pick(0, 2));
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::AI -- Processes the normal non-graphic AI for the aircraft.                  *
+ *                                                                                             *
+ *    This handles the non-graphic AI processing for the aircraft. This usually entails        *
+ *    maintenance and other AI functions.                                                      *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/26/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AircraftClass::AI(void)
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	/*
+	**	A Mission change can always occur if the aircraft is landed or flying.
+	*/
+	if (!IsLanding && !IsTakingOff) {
+		Commence();
+	}
+
+	/*
+	**	Perform any base class AI processing. If during this process, the aircraft was
+	**	destroyed, then detect this and bail from this AI routine early.
+	*/
+	FootClass::AI();
+	if (!IsActive) {
+		return;
+	}
+
+	/*
+	**	A Mission change can always occur if the aircraft is landed or flying.
+	*/
+	if (!IsLanding && !IsTakingOff) {
+		Commence();
+	}
+
+	/*
+	**	Handle any body rotation at this time. Body rotation can occur even if the
+	**	flying object is not actually moving.
+	*/
+	Rotation_AI();
+
+	/*
+	**	Handle any aircraft movement at this time.
+	*/
+	Movement_AI();
+
+	/*
+	**	Any aircraft that is not in the ground layer must be redrawn. This is a
+	**	performance hit, but there is no other choice. The cells under an aircraft
+	**	do not know if there is an aircraft above it. Thus, it cannot flag the
+	**	aircraft to redraw. As a consequence, all aircraft must redraw.
+	*/
+	if (In_Which_Layer() != LAYER_GROUND) {
+		Mark();
+	}
+
+	/*
+	**	Perform sighting every so often as controlled by the sight timer.
+	*/
+	if (IsOwnedByPlayer && Class->SightRange && SightTimer == 0) {
+		Look();
+		SightTimer = TICKS_PER_SECOND;
+	}
+
+	/*
+	**	Handle landing and taking off logic. Helicopters are prime users of this technique. The
+	**	aircraft will either gain or lose altitude as appropriate. As the aircraft transitions
+	**	between flying level and ground level, it will be moved into the appropriate render
+	**	layer.
+	*/
+	if (Landing_Takeoff_AI()) {
+		return;
+	}
+
+	/*
+	**	Always flag the map draw process to occur if there is an aircraft in the view.
+	**	This ensures that it will be rendered even if there is nothing else that flagged
+	**	the map to be redrawn.
+	*/
+	if (Map.In_View(Coord_Cell(Coord))) {
+		Map.Flag_To_Redraw(false);
+		Map.DisplayClass::IsToRedraw = true;
+	}
+
+	/*
+	**	When aircraft leave the edge of the map, they might get destroyed. This occurs if the
+	**	aircraft is a non-player produced unit and it has completed its mission. A transport
+	**	helicopter that has already delivered reinforcements is a good example of this.
+	*/
+	if (Edge_Of_World_AI()) {
+		return;
+	}
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Overlap_List -- Returns with list of cells the aircraft overlaps.            *
+ *                                                                                             *
+ *    When aircraft are flying, they can overlap quite a number of cells. These cells can      *
+ *    be determined from the coordinate where the aircraft is centered and the size of the     *
+ *    aircraft's shape. Landed aircraft are a special case and are usually much smaller        *
+ *    than when flying.                                                                        *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with a pointer to a cell offset list that specifies all cells that         *
+ *          the aircraft overlaps given the aircraft's current state.                          *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/26/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+short const * AircraftClass::Overlap_List(bool redraw) const
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	static short const _list[] = {
+		-(MAP_CELL_W-1), -MAP_CELL_W, -(MAP_CELL_W+1),
+		-1, 0, 1,
+		(MAP_CELL_W-1), MAP_CELL_W, (MAP_CELL_W+1),
+		-((MAP_CELL_W*2)-1), -(MAP_CELL_W*2), -((MAP_CELL_W*2)+1),
+		-((MAP_CELL_W*3)-1), -(MAP_CELL_W*3), -((MAP_CELL_W*3)+1),
+		REFRESH_EOL
+	};
+
+	static short const _listbadger[] = {
+		-(MAP_CELL_W-2), -(MAP_CELL_W-1), -MAP_CELL_W, -(MAP_CELL_W+1), -(MAP_CELL_W+2),
+		-2, -1, 0, 1, 2,
+		(MAP_CELL_W-2), (MAP_CELL_W-1), MAP_CELL_W, (MAP_CELL_W+1), (MAP_CELL_W+2),
+		-((MAP_CELL_W*2)-2), -((MAP_CELL_W*2)-1), -(MAP_CELL_W*2), -((MAP_CELL_W*2)+1), -((MAP_CELL_W*2)+2),
+		-((MAP_CELL_W*3)-2), -((MAP_CELL_W*3)-1), -(MAP_CELL_W*3), -((MAP_CELL_W*3)+1), -((MAP_CELL_W*3)+2),
+		REFRESH_EOL
+	};
+
+	if (redraw || Height != 0) {
+#ifdef PARTIAL
+		Rect rect;
+		if (!IsSelected && Class->DimensionData != NULL && Class->IsFixedWing) {
+			int shapenum = min(Shape_Number(), Get_Build_Frame_Count(Class->Get_Image_Data())-1);
+			if (!Class->DimensionData[shapenum].Is_Valid()) {
+				Class->DimensionData[shapenum] = Shape_Dimensions(Class->Get_Image_Data(), shapenum);
+			}
+			rect = Class->DimensionData[shapenum];
+
+			/*
+			**	Increase the rectangle for the aircraft since the aircraft could
+			**	have its shape algorithmically rotated.
+			*/
+			rect.X -= 5;
+			rect.Y -= 5;
+			rect.Width += 10;
+			rect.Height += 10;
+
+			Rect hrect = rect;
+
+			hrect.Y -= Lepton_To_Pixel(Height);
+
+			return(Coord_Spillage_List(Coord, Union(rect, hrect), true));
+		}
+#endif
+
+		if (*this == AIRCRAFT_BADGER) {
+			return(_listbadger);
+		} else {
+			return(_list);
+		}
+	}
+	return(Class->Overlap_List());
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Init -- Initialize the aircraft system to an empty state.                    *
+ *                                                                                             *
+ *    This routine is used to clear out the aircraft allocation system. It is called in        *
+ *    preparation for a scenario load or save game load.                                       *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   09/24/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AircraftClass::Init(void)
+{
+	Aircraft.Free_All();
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Mission_Unload -- Handles unloading cargo.                                   *
+ *                                                                                             *
+ *    This function is used to handle finding, heading toward, landing, and unloading the      *
+ *    cargo from the aircraft. Once unloading of cargo has occurred, then the aircraft follows *
+ *    a different mission.                                                                     *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns the number of game ticks to delay before calling this function again.      *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   10/31/94   JLB : Created.                                                                 *
+ *=============================================================================================*/
+int AircraftClass::Mission_Unload(void)
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	if (Class->IsFixedWing) {
+
+		Assign_Target(NavCom);
+		return(Mission_Hunt());
+
+	} else {
+		enum {
+			SEARCH_FOR_LZ,
+			FLY_TO_LZ,
+			LAND_ON_LZ,
+			UNLOAD_PASSENGERS,
+			TAKE_OFF
+		};
+
+		switch (Status) {
+
+			/*
+			**	Search for an appropriate destination spot if one isn't already assigned.
+			*/
+			case SEARCH_FOR_LZ:
+				if (Height == 0 && (Target_Legal(NavCom) || Coord == As_Coord(NavCom))) {
+					Status = UNLOAD_PASSENGERS;
+				} else {
+					if (!Is_LZ_Clear(NavCom)) {
+
+						FootClass * foot = Attached_Object();
+						if (foot != NULL && foot->Team && foot->Team->Class->Origin != -1) {
+							Assign_Destination(::As_Target(Scen.Waypoint[foot->Team->Class->Origin]));
+						} else {
+							Assign_Destination(New_LZ(::As_Target(Scen.Waypoint[WAYPT_REINF])));
+							if (Team.Is_Valid()) {
+								Team->Assign_Mission_Target(NavCom);
+							}
+						}
+					} else {
+						if (Height == FLIGHT_LEVEL) {
+							Status = FLY_TO_LZ;
+						} else {
+							Status = TAKE_OFF;
+						}
+					}
+				}
+				break;
+
+			/*
+			**	Fly to destination.
+			*/
+			case FLY_TO_LZ:
+				if (Is_LZ_Clear(NavCom)) {
+					int distance = Process_Fly_To(true, NavCom);
+
+					if (distance < 0x0100) {
+						SecondaryFacing.Set_Desired(Pose_Dir());
+
+						if (distance < 0x0010) {
+							Status = LAND_ON_LZ;
+						}
+						return(1);
+					} else {
+						SecondaryFacing.Set_Desired(PrimaryFacing.Desired());
+						return(5);
+					}
+				} else {
+					Status = SEARCH_FOR_LZ;
+				}
+				break;
+
+			/*
+			**	Landing phase. Just delay until landing is complete. At that time,
+			**	transition to the unloading phase.
+			*/
+			case LAND_ON_LZ:
+				if (IsTakingOff) {
+					Status = TAKE_OFF;
+				} else {
+					if (Process_Landing()) {
+						Status = UNLOAD_PASSENGERS;
+					}
+				}
+				return(1);
+
+			/*
+			**	Hold while unloading passengers. When passengers are unloaded the order for this
+			**	transport gets changed to MISSION_RETREAT.
+			*/
+			case UNLOAD_PASSENGERS:
+				if (!IsTethered) {
+					if (Is_Something_Attached()) {
+						FootClass * unit = (FootClass *)Detach_Object();
+
+						/*
+						**	First thing is to lift the transport off of the map so that the unlimbo
+						**	process for the passengers is more likely to succeed.
+						*/
+						Map.Pick_Up(Coord_Cell(Coord), this);
+
+						if (!Exit_Object(unit)) {
+							delete unit;
+						}
+
+						/*
+						**	Restore the transport back down on the map.
+						*/
+						Map.Place_Down(Coord_Cell(Coord), this);
+
+						if (!Is_Something_Attached()) {
+							Enter_Idle_Mode();
+						}
+
+					} else  {
+
+						Enter_Idle_Mode();
+					}
+				}
+				break;
+
+			/*
+			**	Aircraft is now taking off. Once the aircraft reaches flying altitude then it
+			**	will either take off or look for another landing spot to try again.
+			*/
+			case TAKE_OFF:  {
+				if (Process_Take_Off()) {
+					if (Is_Something_Attached()) {
+						Status = SEARCH_FOR_LZ;
+
+						/*
+						**	Break off radio contact with the helipad it is taking off from.
+						*/
+						if (In_Radio_Contact() && Map[Coord].Cell_Building() == Contact_With_Whom()) {
+							Transmit_Message(RADIO_OVER_OUT);
+						}
+					} else  {
+						Enter_Idle_Mode();
+					}
+				}
+				return(1);
+			}
+
+			default:
+				break;
+		}
+	}
+	return(MissionControl[Mission].Normal_Delay() + Random_Pick(0, 2));
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Is_LZ_Clear -- Determines if landing zone is free for landing.               *
+ *                                                                                             *
+ *    This routine examines the landing zone (as specified by the target parameter) in order   *
+ *    to determine if it is free to be landed upon. Call this routine when it is necessary     *
+ *    to double check this. Typically this occurs right before a helicopter lands and also     *
+ *    when determining the landing zone in the first place.                                    *
+ *                                                                                             *
+ * INPUT:   target   -- The target that is the "landing zone".                                 *
+ *                                                                                             *
+ * OUTPUT:  bool; Is the landing zone clear for landing?                                       *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   10/31/94   JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool AircraftClass::Is_LZ_Clear(TARGET target) const
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	if (!Target_Legal(target)) return(false);
+	CELL cell = ::As_Cell(target);
+	if (!Map.In_Radar(cell)) return(false);
+
+	/*
+	**	If the requested landing location is occupied, then only consider that location
+	**	legal if the occupying object is in radio contact with the aircraft. This presumes that
+	**	the two objects know what they are doing.
+	*/
+	ObjectClass * object = Map[cell].Cell_Object();
+	if (object) {
+		if (object == this) return(true);
+
+		if (In_Radio_Contact() && Contact_With_Whom() == object) {
+			return(true);
+		}
+		return(false);
+	}
+
+	if (!Map[cell].Is_Clear_To_Move(SPEED_TRACK, false, false)) return(false);
+
+	return(true);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Sort_Y -- Figures the sorting coordinate.                                    *
+ *                                                                                             *
+ *    This routine is used to determine the coordinate to use for sorting the aircraft. This   *
+ *    sorting value is used when the aircraft is on the ground. At that time the aircraft      *
+ *    must be rendered in proper relationship to the other ground objects.                     *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the coordinate to use when sorting the aircraft with other ground     *
+ *          objects.                                                                           *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   11/02/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+COORDINATE AircraftClass::Sort_Y(void) const
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	return(Coord_Add(Coord, 0x00800000L));
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Mission_Retreat -- Handles the aircraft logic for leaving the battlefield.   *
+ *                                                                                             *
+ *    This mission will be followed when the aircraft decides that it is time to leave the     *
+ *    battle. Typically, this occurs when a loaner transport has dropped off its load or when  *
+ *    an attack air vehicle has expended its ordinance.                                        *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the number of game ticks to delay before calling this routine again.  *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   03/19/1995 JLB : Created.                                                                 *
+ *   08/13/1995 JLB : Handles aircraft altitude gain after takeoff logic.                      *
+ *=============================================================================================*/
+int AircraftClass::Mission_Retreat(void)
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	if (Class->IsFixedWing) {
+		if (Class->IsFixedWing && Height < FLIGHT_LEVEL) {
+			Height += 1;
+			return(3);
+		}
+		return(TICKS_PER_SECOND*10);
+	}
+
+	enum {
+		TAKE_OFF,
+		FACE_MAP_EDGE,
+		KEEP_FLYING
+	};
+	switch (Status) {
+
+		/*
+		**	Take off if landed.
+		*/
+		case TAKE_OFF:
+			if (Process_Take_Off()) {
+				Status = FACE_MAP_EDGE;
+			}
+			return(1);
+
+		/*
+		**	Set facing and speed toward the friendly map edge.
+		*/
+		case FACE_MAP_EDGE:
+			Set_Speed(0xFF);
+
+			/*
+			**	Take advantage of the fact that the source map edge enumerations happen to
+			**	occur in a clockwise order and are the first four enumerations of the map
+			**	edge default for the house. If this value is masked and then shifted, a
+			**	normalized direction value results. Use this value to head the aircraft
+			**	toward the "friendly" map edge.
+			*/
+			PrimaryFacing.Set_Desired((DirType)((House->Control.Edge & 0x03) << 6));
+			SecondaryFacing.Set_Desired(PrimaryFacing.Desired());
+			Status = KEEP_FLYING;
+			break;
+
+		/*
+		**	Just do nothing since we are headed toward the map edge. When the edge is
+		**	reached, the aircraft should be automatically eliminated.
+		*/
+		case KEEP_FLYING:
+			break;
+
+		default:
+			break;
+	}
+	return(MissionControl[Mission].Normal_Delay() + Random_Pick(0, 2));
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Exit_Object -- Unloads passenger from aircraft.                              *
+ *                                                                                             *
+ *    This routine is called when the aircraft is to unload a passenger. The passenger must    *
+ *    be able to move under its own power. Typical situation is when a transport helicopter    *
+ *    is to unload an infantry unit.                                                           *
+ *                                                                                             *
+ * INPUT:   unit  -- Pointer to the unit that is to be unloaded from this aircraft.            *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the unit unloaded successfully?                                          *
+ *                                                                                             *
+ * WARNINGS:   The unload process is merely started by this routine. Radio contact is          *
+ *             established with the unloading unit and when the unit is clear of the aircraft  *
+ *             the radio contact will be broken and then the aircraft is free to pursue        *
+ *             other.                                                                          *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   01/10/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+int AircraftClass::Exit_Object(TechnoClass * unit)
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	static FacingType _toface[FACING_COUNT] = {FACING_S, FACING_SW, FACING_SE, FACING_NW, FACING_NE, FACING_N, FACING_W, FACING_E};
+	CELL	cell;
+
+	/*
+	**	Find a free cell to drop the unit off at.
+	*/
+	for (FacingType face = FACING_N; face < FACING_COUNT; face++) {
+		cell = Adjacent_Cell(Coord_Cell(Coord), _toface[face]);
+		if (unit->Can_Enter_Cell(cell) == MOVE_OK) break;
+	}
+
+	// Should perform a check here to see if no cell could be found.
+
+	/*
+	**	If the passenger can be placed on the map, then start it moving toward the
+	**	destination cell and establish radio contact with the transport. This is used
+	**	to make sure that the transport waits until the passenger is clear before
+	**	unloading the next passenger or taking off.
+	*/
+	if (unit->Unlimbo(Coord, Facing_Dir(_toface[face]))) {
+		unit->Assign_Mission(MISSION_MOVE);
+		unit->Assign_Destination(::As_Target(cell));
+		if (Transmit_Message(RADIO_HELLO, unit) == RADIO_ROGER) {
+			Transmit_Message(RADIO_UNLOAD);
+		}
+		return(true);
+	}
+	return(false);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Paradrop_Cargo -- Drop a passenger by parachute.                             *
+ *                                                                                             *
+ *    Call this routine when a passenger needs to be dropped off by parachute. One passenger   *
+ *    is offloaded by a call to this routine.                                                  *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the delay time that it is safe to wait before processing any further  *
+ *          paradrop actions.                                                                  *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/26/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+int AircraftClass::Paradrop_Cargo(void)
+{
+	FootClass * passenger = Detach_Object();
+	if (passenger) {
+		if (!passenger->Paradrop(Center_Coord())) {
+			Attach(passenger);
+		} else {
+
+			/*
+			**	Play a sound effect of the parachute opening.
+			*/
+			Sound_Effect(VOC_CHUTE1, Coord);
+
+			if (Team.Is_Valid()) {
+				Team->Remove(passenger);
+				if (passenger->House->IsHuman) {
+					Assign_Mission(MISSION_GUARD);
+				} else {
+					Assign_Mission(MISSION_HUNT);
+				}
+			}
+//			Arm = Rearm_Delay(IsSecondShot);
+			Arm = 0;
+		}
+	}
+	return(Arm);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Fire_At -- Handles firing a projectile from an aircraft.                     *
+ *                                                                                             *
+ *    Sometimes, aircraft firing needs special handling. Example: for napalm bombs, the        *
+ *    bomb travels forward at nearly the speed of the delivery aircraft, not necessarily the   *
+ *    default speed defined in the BulletTypeClass structure.                                  *
+ *                                                                                             *
+ * INPUT:   target   -- The target that the projectile is heading for.                         *
+ *                                                                                             *
+ *          which    -- Which weapon to use in the attack. 0=primary, 1=secondary.             *
+ *                                                                                             *
+ * OUTPUT:  Returns with a pointer to the bullet that was created as a result of this attack.  *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   03/19/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+BulletClass * AircraftClass::Fire_At(TARGET target, int which)
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	/*
+	**	Passenger aircraft will actually paradrop their cargo instead of
+	**	firing their weapon.
+	*/
+	if (Is_Something_Attached()) {
+		Paradrop_Cargo();
+		return(0);
+	}
+
+	/*
+	**	If the weapon is actually a camera, then perform the "snapshot" of the
+	**	ground instead of normal weapon fire.
+	*/
+	if (Class->PrimaryWeapon != NULL && Class->PrimaryWeapon->IsCamera) {
+		if (House->Is_Ally(PlayerPtr)) {
+			Map.Sight_From(Coord_Cell(Center_Coord()), 9, House, false);
+		}
+		Ammo = 0;
+		Arm = Rearm_Delay(IsSecondShot);
+		return(0);
+	}
+
+
+	BulletClass * bullet = FootClass::Fire_At(target, which);
+
+	if (bullet) {
+
+		/*
+		**	Falling bullets move at a speed proportionate to the delivery craft.
+		*/
+		if (bullet->Class->IsDropping) {
+			bullet->Fly_Speed(40, MPH_MEDIUM_SLOW);		// TCTC To fix.
+		}
+	}
+	return(bullet);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Take_Damage -- Applies damage to the aircraft.                               *
+ *                                                                                             *
+ *    This routine is used to apply damage to the specified aircraft. This is where any        *
+ *    special crash animation will be initiated.                                               *
+ *                                                                                             *
+ * INPUT:   damage   -- Reference to the damage that will be applied to the aircraft.          *
+ *                      This value will be filled in with the actual damage that was           *
+ *                      applied.                                                               *
+ *                                                                                             *
+ *          distance -- Distance from the source of the explosion to this aircraft.            *
+ *                                                                                             *
+ *          warhead  -- The warhead type that the damage occurs from.                          *
+ *                                                                                             *
+ *          source   -- Pointer to the originator of the damage. This can be used so that      *
+ *                      proper "thank you" can be delivered.                                   *
+ *                                                                                             *
+ * OUTPUT:  Returns with the result of the damage as it affects this aircraft.                 *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/26/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+ResultType AircraftClass::Take_Damage(int & damage, int distance, WarheadType warhead, TechnoClass * source, int forced)
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	ResultType res = RESULT_NONE;
+
+	/*
+	**	Flying aircraft take half damage.
+	*/
+	if (Height) {
+		damage /= 2;
+	}
+
+	/*
+	**	Apply the damage to the aircraft.
+	*/
+	res = FootClass::Take_Damage(damage, distance, warhead, source, forced);
+
+	/*
+	**	Special action is performed if the aircraft is killed -- the cargo is destroyed
+	**	as well.
+	*/
+	switch (res) {
+		case RESULT_DESTROYED:
+			Kill_Cargo(source);
+			Death_Announcement();
+			new AnimClass(ANIM_FBALL1, Target_Coord());
+
+			/*
+			**	Parachute a survivor if possible.
+			*/
+			if (Class->IsCrew && Percent_Chance(90) && Map[Center_Coord()].Is_Clear_To_Move(SPEED_FOOT, true, false)) {
+				InfantryClass * infantry = new InfantryClass(INFANTRY_E1, House->Class->House);
+				if (infantry != NULL) {
+					if (!infantry->Paradrop(Center_Coord())) {
+						delete infantry;
+					}
+				}
+			}
+
+			delete this;
+			break;
+
+		default:
+		case RESULT_HALF:
+			break;
+	}
+
+	return(res);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Mission_Move -- Handles movement mission.                                    *
+ *                                                                                             *
+ *    This state machine routine is used when an aircraft (usually helicopter) is to move      *
+ *    from one location to another. It will handle any necessary take off and landing this     *
+ *    may require.                                                                             *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the number of game frames that should elapse before this routine      *
+ *          is called again.                                                                   *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/19/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+int AircraftClass::Mission_Move(void)
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	if (Class->IsFixedWing) {
+
+		enum  {
+			TAKE_OFF,
+			FLY_TOWARD_TARGET
+		};
+
+		switch (Status) {
+			int distance;
+
+			case TAKE_OFF:
+
+				/*
+				**	If the aircraft is high enough to begin its mission, then do so.
+				*/
+				if (Process_Take_Off())  {
+					IsTakingOff = false;
+					Set_Speed(0xFF);
+
+					/*
+					**	After takeoff is complete, break radio contact.
+					*/
+					if (In_Radio_Contact() && Map[Coord].Cell_Building() == Contact_With_Whom()) {
+						Transmit_Message(RADIO_OVER_OUT);
+					}
+
+					Status = FLY_TOWARD_TARGET;
+				}
+				return(1);
+
+			case FLY_TOWARD_TARGET:
+				PrimaryFacing.Set_Desired(Direction(NavCom));
+				distance = Distance(NavCom);
+
+				if (distance < 0x00C0) {
+					MissionType mission = MISSION_GUARD;
+
+					if (!IsALoaner) {
+						/*
+						**	Normal aircraft try to find a good landing spot to rest.
+						*/
+						BuildingClass * building = Find_Docking_Bay(Class->Building, false);
+#ifdef FIXIT_CARRIER	//	checked - ajw 9/28/98
+	if (!Class->IsFixedWing) {
+		int dist = 0x7FFFFFFF;
+		if (building) dist=Distance(building);
+		for (int index = 0; index < Vessels.Count(); index++) {
+			VesselClass *ship = Vessels.Ptr(index);
+			if (ship != NULL && *ship == VESSEL_CARRIER && !ship->IsInLimbo && ship->IsActive && ship->House == House && ship->How_Many() < ship->Class->Max_Passengers() ) {
+				if (Distance(ship) < dist || !building) {
+					building = (BuildingClass *)ship;
+					dist = Distance(ship);
+				}
+//				break;
+			}
+		}
+	}
+#endif
+						Assign_Destination(TARGET_NONE);
+#ifdef FIXIT_CARRIER	//	checked - ajw 9/28/98
+						if (building && (Transmit_Message(RADIO_HELLO, building) == RADIO_ROGER || building->What_Am_I() == RTTI_VESSEL) ) {
+#else
+						if (building && Transmit_Message(RADIO_HELLO, building) == RADIO_ROGER) {
+#endif
+							mission = MISSION_ENTER;
+#ifdef FIXIT_CARRIER	//	checked - ajw 9/28/98
+	if (building->What_Am_I() == RTTI_VESSEL) {
+		Assign_Destination(building->As_Target());
+	}
+#endif
+						} else {
+							Assign_Destination(Good_LZ());
+
+							/*
+							** If this aircraft has nowhere else to go, meaning that
+							** there is no airfield available, then it has to crash.
+							*/
+							if (Is_Target_Cell(NavCom)) {
+
+								if (Process_Landing()) {
+									Strength = 1;
+									int damage = Strength;
+									Take_Damage(damage, 0, WARHEAD_AP, 0, true);
+									return(1);
+								}
+								return(500);
+							}
+							mission = MISSION_MOVE;
+						}
+						Assign_Mission(mission);
+						Commence();
+					} else {
+						if (!Team.Is_Valid()) {
+							Enter_Idle_Mode();
+						}
+					}
+					return(1);
+				}
+				break;
+
+			default:
+				break;
+		}
+
+		return(5);
+	}
+
+	enum {
+		VALIDATE_LZ,
+		TAKE_OFF,
+		FLY_TO_LZ,
+		LAND
+	};
+	switch (Status) {
+
+		/*
+		**	Double check and change LZ if necessary.
+		*/
+		case VALIDATE_LZ:
+			if (!Target_Legal(NavCom)) {
+				Enter_Idle_Mode();
+			} else {
+				if (!Is_LZ_Clear(NavCom) || !Cell_Seems_Ok(As_Cell(NavCom))) {
+					Assign_Destination(New_LZ(NavCom));
+					if (Team.Is_Valid()) {
+						Team->Assign_Mission_Target(NavCom);
+					}
+				} else {
+					Status = TAKE_OFF;
+				}
+			}
+			break;
+
+		/*
+		**	Take off if necessary.
+		*/
+		case TAKE_OFF:
+			if (!Target_Legal(NavCom)) {
+				Status = VALIDATE_LZ;
+			} else {
+				if (Process_Take_Off()) {
+
+					/*
+					**	After takeoff is complete, break radio contact with any helipad that this
+					**	helicopter is taking off from.
+					*/
+					if (In_Radio_Contact() && Map[Coord].Cell_Building() == Contact_With_Whom()) {
+						Transmit_Message(RADIO_OVER_OUT);
+					}
+
+					Status = FLY_TO_LZ;
+				}
+				return(1);
+			}
+			break;
+
+		/*
+		**	Fly toward target.
+		*/
+		case FLY_TO_LZ:
+			if (Is_LZ_Clear(NavCom)) {
+				int distance = Process_Fly_To(true, NavCom);
+
+				if (distance < 0x0080) {
+					if (Target_Legal(TarCom)) {
+						SecondaryFacing.Set_Desired(Direction(TarCom));
+					} else {
+						SecondaryFacing.Set_Desired(Pose_Dir());
+					}
+
+					if (distance < 0x0010) {
+						Status = LAND;
+					}
+					return(1);
+				}
+
+//				SecondaryFacing.Set_Desired(::Direction(Fire_Coord(0), As_Coord(NavCom)));
+				SecondaryFacing.Set_Desired(Direction(NavCom));
+
+			} else {
+				Assign_Destination(New_LZ(NavCom));
+				if (Team.Is_Valid()) {
+					Team->Assign_Mission_Target(NavCom);
+				}
+				if (!Target_Legal(NavCom)) {
+					Status = LAND;
+				}
+			}
+			return(1);
+
+		/*
+		**	Land on target.
+		*/
+		case LAND:
+			if (IsTakingOff) {
+				Assign_Destination(New_LZ(NavCom));
+				if (Team.Is_Valid()) {
+					Team->Assign_Mission_Target(NavCom);
+				}
+				Status = TAKE_OFF;
+			}
+			if (Process_Landing()) {
+				if (MissionQueue == MISSION_NONE) {
+					Enter_Idle_Mode();
+				}
+			}
+			return(1);
+
+		default:
+			break;
+	}
+
+	return(MissionControl[Mission].Normal_Delay() + Random_Pick(0, 2));
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Enter_Idle_Mode -- Gives the aircraft an appropriate mission.                *
+ *                                                                                             *
+ *    Use this routine when the mission for the aircraft is in doubt. This routine will find   *
+ *    an appropriate mission for the aircraft and dispatch it.                                 *
+ *                                                                                             *
+ * INPUT:   initial  -- Is this called when the unit just leaves a factory or is initially     *
+ *                      or is initially placed on the map?                                     *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/05/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AircraftClass::Enter_Idle_Mode(bool )
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	MissionType mission = MISSION_GUARD;
+	if (Class->IsFixedWing) {
+		if (In_Which_Layer() == LAYER_GROUND) {
+			if (IsALoaner) {
+				mission = MISSION_RETREAT;
+			} else {
+				Assign_Destination(TARGET_NONE);
+				Assign_Target(TARGET_NONE);
+				mission = MISSION_GUARD;
+			}
+		} else {
+
+			/*
+			**	If this transport is a loaner and part of a team, then remove it from
+			**	the team it is attached to.
+			*/
+			if ((IsALoaner && House->IsHuman) || (!House->IsHuman && !Ammo)) {
+				if (Team.Is_Valid() && Team->Has_Entered_Map()) {
+					Team->Remove(this);
+				}
+			}
+			if (Team.Is_Valid()) return;
+
+			/*
+			**	Weapon equipped helicopters that run out of ammo and were
+			**	brought in as reinforcements will leave the map.
+			*/
+			if (Mission != MISSION_ATTACK && IsALoaner && Ammo == 0 && Class->PrimaryWeapon != NULL) {
+				mission = MISSION_HUNT;
+			} else {
+
+				if (!IsALoaner) {
+					/*
+					**	Normal aircraft try to find a good landing spot to rest.
+					*/
+					BuildingClass * building = Find_Docking_Bay(Class->Building, false);
+					Assign_Destination(TARGET_NONE);
+					if (building != NULL && Transmit_Message(RADIO_HELLO, building) == RADIO_ROGER) {
+						if (Class->IsFixedWing) {
+							Status = 0;	//BG - reset the mission status to avoid landing on the ground next to the airstrip
+							if (IsLanding) {
+								Process_Take_Off();
+							}
+						}
+						mission = MISSION_ENTER;
+					} else {
+						mission = MISSION_RETREAT;
+					}
+				}
+			}
+		}
+
+	} else {
+
+		if (In_Which_Layer() == LAYER_GROUND) {
+			if (IsALoaner) {
+				if (Is_Something_Attached()) {
+
+					/*
+					**	In the case of a computer controlled helicopter that hold passengers,
+					**	don't unload when landing. Wait for specific instructions from the
+					**	controlling team.
+					*/
+					if (Team.Is_Valid()) {
+//					if (Team.Is_Valid() && !House->IsHuman) {
+						mission = MISSION_GUARD;
+					} else {
+						mission = MISSION_UNLOAD;
+					}
+				} else {
+					mission = MISSION_RETREAT;
+				}
+			} else {
+				Assign_Destination(TARGET_NONE);
+				Assign_Target(TARGET_NONE);
+				mission = MISSION_GUARD;
+			}
+		} else {
+			if (Is_Something_Attached()) {
+				if (IsALoaner) {
+					if (Team) {
+						mission = MISSION_GUARD;
+					} else {
+						mission = MISSION_UNLOAD;
+						Assign_Destination(Good_LZ());
+					}
+				} else {
+					Assign_Destination(Good_LZ());
+					mission = MISSION_MOVE;
+				}
+			} else {
+
+				/*
+				**	If this transport is a loaner and part of a team, then remove it from
+				**	the team it is attached to.
+				*/
+				if ((IsALoaner && House->IsHuman) || (!House->IsHuman && !Ammo)) {
+					if (Team.Is_Valid() && Team->Has_Entered_Map()) {
+						Team->Remove(this);
+					}
+				}
+
+				if (Class->PrimaryWeapon != NULL) {
+
+					/*
+					**	Weapon equipped helicopters that run out of ammo and were
+					**	brought in as reinforcements will leave the map.
+					*/
+					if (IsALoaner) {
+
+						/*
+						**	If it has no ammo, then break off of the team and leave the map.
+						**	If it can fight, then give it fighting orders.
+						*/
+						if (Ammo == 0) {
+							if (Team.Is_Valid()) Team->Remove(this);
+							mission = MISSION_RETREAT;
+						} else {
+							if (!Team.Is_Valid()) {
+								mission = MISSION_HUNT;
+							}
+						}
+
+					} else {
+
+						/*
+						**	Normal aircraft try to find a good landing spot to rest.
+						*/
+						BuildingClass * building = Find_Docking_Bay(Class->Building, false);
+#ifdef FIXIT_CARRIER	//	checked - ajw 9/28/98
+	if (!Class->IsFixedWing) {
+		int dist = 0x7FFFFFFF;
+		if (building) dist=Distance(building);
+		for (int index = 0; index < Vessels.Count(); index++) {
+			VesselClass *ship = Vessels.Ptr(index);
+			if (ship != NULL && *ship == VESSEL_CARRIER && !ship->IsInLimbo && ship->IsActive && ship->House == House && ship->How_Many() < ship->Class->Max_Passengers()/* && !ship->In_Radio_Contact()*/) {
+				if (Distance(ship) < dist || !building) {
+					building = (BuildingClass *)ship;
+					dist = Distance(ship);
+				}
+//				break;
+			}
+		}
+	}
+#endif
+						Assign_Destination(TARGET_NONE);
+#ifdef FIXIT_CARRIER	//	checked - ajw 9/28/98
+						if (building && (Transmit_Message(RADIO_HELLO, building) == RADIO_ROGER || building->What_Am_I() == RTTI_VESSEL) ) {
+#else
+						if (building && Transmit_Message(RADIO_HELLO, building) == RADIO_ROGER) {
+#endif
+							mission = MISSION_ENTER;
+#ifdef FIXIT_CARRIER	//	checked - ajw 9/28/98
+							if (building->What_Am_I() == RTTI_VESSEL) {
+								Assign_Destination(building->As_Target());
+							}
+#endif
+						} else {
+							Assign_Destination(Good_LZ());
+							mission = MISSION_MOVE;
+						}
+					}
+				} else {
+					if (Team) return;
+
+					Assign_Destination(Good_LZ());
+					mission = MISSION_MOVE;
+				}
+			}
+		}
+	}
+	Assign_Mission(mission);
+	Commence();
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Process_Fly_To -- Handles state machine for flying to destination.           *
+ *                                                                                             *
+ *    This support routine is used when the helicopter is to fly to the destination. It can    *
+ *    optionally slow the helicopter down as it approaches the destination.                    *
+ *                                                                                             *
+ * INPUT:   slowdown -- Should the aircraft be slowed down when it approaches the dest?        *
+ *                                                                                             *
+ * OUTPUT:  Returns with the distance remaining between the aircraft and the destination.      *
+ *                                                                                             *
+ * WARNINGS:   Because the aircraft can move at a fast speed, the distance to target value     *
+ *             will probably never be zero. The likely case will be that the aircraft          *
+ *             overshoots the target.                                                          *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/14/1995 JLB : Created.                                                                 *
+ *   03/05/1996 JLB : Specifies destination target value.                                      *
+ *=============================================================================================*/
+int AircraftClass::Process_Fly_To(bool slowdown, TARGET dest)
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	if (Class->IsFixedWing) slowdown = false;
+
+	COORDINATE coord;
+	if (Is_Target_Building(dest)) {
+		coord = As_Building(dest)->Docking_Coord();
+	} else {
+		coord = As_Coord(dest);
+	}
+	int distance = Distance(coord);
+
+	PrimaryFacing.Set_Desired(Direction(coord));
+
+	if (slowdown) {
+		int speed = min(distance, 0x0300);
+		speed = Bound(speed/3, 0x0020, 0x00FF);
+		if (Speed != speed) {
+			Set_Speed(speed);
+		}
+	}
+
+	if (distance < 0x0010) {
+		if (slowdown) {
+			Set_Speed(0);
+		}
+		distance = 0;
+	}
+	return(distance);
+}
+
+
+#ifdef CHEAT_KEYS
+/***********************************************************************************************
+ * AircraftClass::Debug_Dump -- Displays the status of the aircraft to the mono monitor.       *
+ *                                                                                             *
+ *    This displays the current status of the aircraft class to the mono monitor. By this      *
+ *    display bugs may be tracked down or prevented.                                           *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/02/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AircraftClass::Debug_Dump(MonoClass * mono) const
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	mono->Set_Cursor(0, 0);
+	mono->Print(Text_String(TXT_DEBUG_AIRCRAFT));
+	mono->Set_Cursor(1, 11);mono->Printf("%3d", AttacksRemaining);
+
+	FootClass::Debug_Dump(mono);
+}
+#endif
+
+
+/***********************************************************************************************
+ * AircraftClass::Active_Click_With -- Handles clicking over specified object.                 *
+ *                                                                                             *
+ *    This routine is used when the player clicks over the speicifed object. It will assign    *
+ *    the appropriate mission to the aircraft.                                                 *
+ *                                                                                             *
+ * INPUT:   action   -- The action that was nominally determined by the What_Action function.  *
+ *                                                                                             *
+ *          object   -- The object over which the mouse was clicked.                           *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   This routine will alter the game sequence and causes an event packet to be      *
+ *             propagated to all connected machines.                                           *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/19/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AircraftClass::Active_Click_With(ActionType action, ObjectClass * object)
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	action = What_Action(object);
+
+	switch (action) {
+		case ACTION_NOMOVE:
+			return;
+
+		case ACTION_ENTER:
+			Player_Assign_Mission(MISSION_ENTER, TARGET_NONE, object->As_Target());
+			break;
+
+		case ACTION_SELF:
+			Player_Assign_Mission(MISSION_UNLOAD, TARGET_NONE, TARGET_NONE);
+			break;
+
+		default:
+			break;
+	}
+	FootClass::Active_Click_With(action, object);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Active_Click_With -- Handles clicking over specified cell.                   *
+ *                                                                                             *
+ *    This routine is used when the player clicks the mouse of the specified cell. It will     *
+ *    assign the appropriate mission to the aircraft.                                          *
+ *                                                                                             *
+ * INPUT:   action   -- The action nominally determined by What_Action().                      *
+ *                                                                                             *
+ *          cell     -- The cell over which the mouse was clicked.                             *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   This routine will affect the game sequence and causes an event object to be     *
+ *             propagated to all connected machines.                                           *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/19/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AircraftClass::Active_Click_With(ActionType action, CELL cell)
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	FootClass::Active_Click_With(action, cell);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Player_Assign_Mission -- Handles player input to assign a mission.           *
+ *                                                                                             *
+ *    This routine is called as a result of player input with the intent to change the         *
+ *    mission of the aircraft.                                                                 *
+ *                                                                                             *
+ * INPUT:   mission  -- The mission requested of the aircraft.                                 *
+ *                                                                                             *
+ *          target   -- The value to assign to the aircraft's targeting computer.              *
+ *                                                                                             *
+ *          dest.    -- The value to assign to the aircraft's navigation computer.             *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   The mission specified will be executed at an indeterminate future game frame.   *
+ *             This is controlled by net/modem propagation delay.                              *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/19/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AircraftClass::Player_Assign_Mission(MissionType mission, TARGET target, TARGET destination)
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	if (AllowVoice) {
+		if (mission == MISSION_ATTACK) {
+			Response_Attack();
+		} else {
+			Response_Move();
+		}
+	}
+	Queue_Mission(TargetClass(this), mission, target, destination);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::What_Action -- Determines what action to perform.                            *
+ *                                                                                             *
+ *    This routine is used to determine what action will likely be performed if the mouse      *
+ *    were clicked over the object specified. The display system calls this routine to         *
+ *    control the mouse shape.                                                                 *
+ *                                                                                             *
+ * INPUT:   target   -- Pointer to the object that the mouse is currently over.                *
+ *                                                                                             *
+ * OUTPUT:  Returns with the action that will occur if the mouse were clicked over the         *
+ *          object specified.                                                                  *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/19/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+ActionType AircraftClass::What_Action(ObjectClass const * target) const
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	ActionType action = FootClass::What_Action(target);
+
+	if (action == ACTION_SELF && !How_Many()) {
+		action = ACTION_NONE;
+	}
+
+	if (action == ACTION_ATTACK && Class->PrimaryWeapon == NULL) {
+		action = ACTION_NONE;
+	}
+
+	if (House->IsPlayerControl && House->Is_Ally(target) && target->What_Am_I() == RTTI_BUILDING && ((AircraftClass *)this)->Transmit_Message(RADIO_CAN_LOAD, (TechnoClass*)target) == RADIO_ROGER) {
+		action = ACTION_ENTER;
+	}
+#ifdef FIXIT_CARRIER	//	checked - ajw 9/28/98
+	if (!Class->IsFixedWing && House->IsPlayerControl && House->Is_Ally(target) && target->What_Am_I() == RTTI_VESSEL && *(VesselClass *)target == VESSEL_CARRIER && ((AircraftClass *)this)->Transmit_Message(RADIO_CAN_LOAD, (TechnoClass*)target) == RADIO_ROGER) {
+		action = ACTION_ENTER;
+	}
+#endif
+
+	if (Class->IsFixedWing && action == ACTION_MOVE) {
+		action = ACTION_NOMOVE;
+	}
+
+	if (action == ACTION_NONE) {
+		action = What_Action(Coord_Cell(target->Center_Coord()));
+	}
+
+	/*
+	**	Special return to friendly repair factory action.
+	*/
+	if (House->IsPlayerControl && action == ACTION_SELECT && target->What_Am_I() == RTTI_BUILDING) {
+		BuildingClass * building = (BuildingClass *)target;
+		if (building->Class->Type == STRUCT_REPAIR && !building->In_Radio_Contact() && !building->Is_Something_Attached()) {
+			action = ACTION_ENTER;
+		}
+	}
+
+	return(action);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::What_Action -- Determines what action to perform.                            *
+ *                                                                                             *
+ *    This routine will determine what action would occur if the mouse were clicked over the   *
+ *    cell specified. The display system calls this routine to determine what mouse shape      *
+ *    to use.                                                                                  *
+ *                                                                                             *
+ * INPUT:   cell  -- The cell over which the mouse is currently positioned.                    *
+ *                                                                                             *
+ * OUTPUT:  Returns with the action that will be performed if the mouse were clicked at the    *
+ *          specified cell location.                                                           *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/19/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+ActionType AircraftClass::What_Action(CELL cell) const
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	ActionType action = FootClass::What_Action(cell);
+
+	if (action == ACTION_MOVE && Session.Type == GAME_NORMAL && !Map[cell].IsVisible) {
+		action = ACTION_NOMOVE;
+	}
+
+	if (action == ACTION_ATTACK && Class->PrimaryWeapon == NULL) {
+		action = ACTION_NONE;
+	}
+
+	if (Class->IsFixedWing && action == ACTION_MOVE) {
+		action = ACTION_NOMOVE;
+	}
+
+	return(action);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Pose_Dir -- Fetches the natural landing facing.                              *
+ *                                                                                             *
+ *    Use this routine to get the desired facing the aircraft should assume when landing.      *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the normal default facing the aircraft should have when landed.       *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/19/1995 JLB : Created.                                                                 *
+ *   03/04/1996 JLB : Fixed wing aircraft always face down the runway.                         *
+ *=============================================================================================*/
+DirType AircraftClass::Pose_Dir(void) const
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	if (*this == AIRCRAFT_TRANSPORT) {
+		return(DIR_N);
+	}
+	if (Class->IsFixedWing)  {
+		return(DIR_E);
+	}
+	return(DIR_NE);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Mission_Attack -- Handles the attack mission for aircraft.                   *
+ *                                                                                             *
+ *    This routine is the state machine that handles the attack mission for aircraft. It will  *
+ *    handling homing in on and firing on the target in the aircraft's targeting computer.     *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the number of game ticks to pass before this routine must be called   *
+ *          again.                                                                             *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/19/1995 JLB : Created.                                                                 *
+ *   09/22/1995 JLB : Fixes brain dead helicopter for Nod scen #7.                             *
+ *=============================================================================================*/
+int AircraftClass::Mission_Attack(void)
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	if (Class->IsFixedWing) {
+		return(Mission_Hunt());
+	}
+
+	enum {
+		VALIDATE_AZ,
+		PICK_ATTACK_LOCATION,
+		TAKE_OFF,
+		FLY_TO_POSITION,
+		FIRE_AT_TARGET,
+		FIRE_AT_TARGET2,
+		RETURN_TO_BASE
+	};
+	switch (Status) {
+
+		/*
+		**	Double check target and validate the attack zone.
+		*/
+		case VALIDATE_AZ:
+			if (!Target_Legal(TarCom)) {
+				Status = RETURN_TO_BASE;
+			} else {
+				Status = PICK_ATTACK_LOCATION;
+			}
+			break;
+
+		/*
+		**	Pick a good location to attack from.
+		*/
+		case PICK_ATTACK_LOCATION:
+			if (!Target_Legal(TarCom)) {
+				Status = RETURN_TO_BASE;
+			} else {
+				Assign_Destination(Good_Fire_Location(TarCom));
+				if (Target_Legal(NavCom)) {
+					Status = TAKE_OFF;
+				} else {
+					Status = RETURN_TO_BASE;
+				}
+			}
+			break;
+
+		/*
+		**	Take off (if necessary).
+		*/
+		case TAKE_OFF:
+			if (!Target_Legal(TarCom)) {
+				Status = RETURN_TO_BASE;
+			} else {
+				if (Process_Take_Off()) {
+					Status = FLY_TO_POSITION;
+
+					/*
+					**	Break off radio contact with the helipad it is taking off from.
+					*/
+					if (In_Radio_Contact() && Map[Coord].Cell_Building() == Contact_With_Whom()) {
+						Transmit_Message(RADIO_OVER_OUT);
+					}
+
+					/*
+					**	Start flying toward the destination by skewing at first.
+					**	As the flight progresses, the body will rotate to face
+					**	the direction of travel.
+					*/
+					int diff = SecondaryFacing.Difference(Direction(NavCom));
+					diff = Bound(diff, -128, 128);
+					PrimaryFacing = DirType((int)SecondaryFacing.Current()+diff);
+				}
+				return(1);
+			}
+			break;
+
+		/*
+		**	Fly to attack location.
+		*/
+		case FLY_TO_POSITION:
+			if (Target_Legal(TarCom)) {
+
+				/*
+				**	If the navcom was cleared mysteriously, then try to pick
+				**	a new attack location. This is a likely event if the player
+				**	clicks on a new target while in flight to an existing target.
+				*/
+				if (!Target_Legal(NavCom)) {
+					Status = PICK_ATTACK_LOCATION;
+					return(1);
+				}
+
+				int distance = Process_Fly_To(true, NavCom);
+
+				if (distance < 0x0200) {
+					SecondaryFacing.Set_Desired(Direction(TarCom));
+
+					if (distance < 0x0010) {
+						Status = FIRE_AT_TARGET;
+						Assign_Destination(TARGET_NONE);
+					}
+				} else {
+					SecondaryFacing.Set_Desired(::Direction(Fire_Coord(0), As_Coord(NavCom)));
+					return(1);
+				}
+			} else {
+				Status = RETURN_TO_BASE;
+			}
+			return(1);
+
+		/*
+		**	Fire at the target.
+		*/
+		case FIRE_AT_TARGET:
+			if (!Target_Legal(TarCom)) {
+				Status = RETURN_TO_BASE;
+				return(1);
+			}
+
+			PrimaryFacing.Set_Desired(Direction(TarCom));
+			SecondaryFacing.Set_Desired(Direction(TarCom));
+			switch (Can_Fire(TarCom, 0)) {
+				case FIRE_CLOAKED:
+					Do_Uncloak();
+					break;
+
+				case FIRE_OK:
+					Fire_At(TarCom, 0);
+					Map[::As_Cell(TarCom)].Incoming(Coord, true);
+					Status = FIRE_AT_TARGET2;
+					break;
+
+				case FIRE_REARM:
+				case FIRE_FACING:
+					break;
+
+				default:
+					if (!Ammo) {
+						Status = RETURN_TO_BASE;
+					} else {
+						Status = FIRE_AT_TARGET2;
+					}
+					break;
+			}
+			return(1);
+
+		/*
+		**	Fire at the target.
+		*/
+		case FIRE_AT_TARGET2:
+			if (!Target_Legal(TarCom)) {
+				Status = RETURN_TO_BASE;
+				return(1);
+			}
+
+			PrimaryFacing.Set_Desired(Direction(TarCom));
+			SecondaryFacing.Set_Desired(Direction(TarCom));
+			switch (Can_Fire(TarCom, 0)) {
+				case FIRE_CLOAKED:
+					Do_Uncloak();
+					break;
+
+				case FIRE_REARM:
+					break;
+
+				case FIRE_OK:
+					Fire_At(TarCom, 0);
+					Map[::As_Cell(TarCom)].Incoming(Coord, true);
+
+					if (Ammo) {
+						Status = Rule.IsCurleyShuffle ? PICK_ATTACK_LOCATION : FIRE_AT_TARGET;
+					} else {
+						Status = RETURN_TO_BASE;
+					}
+					break;
+
+				default:
+					if (!Ammo) {
+						Status = RETURN_TO_BASE;
+					} else {
+						if (!In_Range(TarCom)) {
+							Status = PICK_ATTACK_LOCATION;
+						} else {
+							Status = Rule.IsCurleyShuffle ? PICK_ATTACK_LOCATION : FIRE_AT_TARGET;
+						}
+					}
+					break;
+			}
+			break;
+
+		/*
+		**	Fly back to landing spot.
+		*/
+		case RETURN_TO_BASE:
+			/*
+			**	Break off of firing at the target if there is no more
+			**	point in attacking it this mission. The player will
+			**	reassign a target for the next mission.
+			*/
+			if (!Ammo && (IsALoaner || House->IsHuman)) {
+				Assign_Target(TARGET_NONE);
+			}
+			Assign_Destination(TARGET_NONE);
+			Enter_Idle_Mode();
+			break;
+
+		default:
+			break;
+	}
+
+	return(MissionControl[Mission].Normal_Delay() + Random_Pick(0, 2));
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::New_LZ -- Find a good landing zone.                                          *
+ *                                                                                             *
+ *    Use this routine to locate a good landing zone that is nearby the location specified.    *
+ *    By using this routine it is possible to assign the same landing zone to several          *
+ *    aircraft and they will land nearby without conflict.                                     *
+ *                                                                                             *
+ * INPUT:   oldlz -- Target value of desired landing zone (usually a cell target value).       *
+ *                                                                                             *
+ * OUTPUT:  Returns with the new good landing zone. It might be the same value passed in.      *
+ *                                                                                             *
+ * WARNINGS:   The landing zone might be a goodly distance away from the ideal if there is     *
+ *             extensive blocking terrain in the vicinity.                                     *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/19/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+TARGET AircraftClass::New_LZ(TARGET oldlz) const
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	if (Target_Legal(oldlz) && (!Is_LZ_Clear(oldlz) || !Cell_Seems_Ok(As_Cell(oldlz)))) {
+		COORDINATE coord = As_Coord(oldlz);
+
+		/*
+		**	Scan outward in a series of concentric rings up to certain distance
+		**	in cells.
+		*/
+		for (int radius = 0; radius < Rule.LZScanRadius / CELL_LEPTON_W; radius++) {
+			FacingType modifier = Random_Pick(FACING_N, FACING_NW);
+			CELL lastcell = -1;
+
+			/*
+			**	Perform a radius scan out from the original center location. Try to
+			**	find a cell that is allowed to be a legal LZ.
+			*/
+			for (FacingType facing = FACING_N; facing < FACING_COUNT; facing++) {
+				CELL newcell = Coord_Cell(Coord_Move(coord, Facing_Dir(facing+modifier), radius * ICON_LEPTON_W));
+				if (Map.In_Radar(newcell)) {
+					TARGET newtarget = ::As_Target(newcell);
+
+					if (newcell != lastcell && Is_LZ_Clear(newtarget) && Cell_Seems_Ok(newcell)) {
+						return(newtarget);
+					}
+					lastcell = newcell;
+				}
+			}
+		}
+	}
+	return(oldlz);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Receive_Message -- Handles receipt of radio messages.                        *
+ *                                                                                             *
+ *    This routine receives all radio messages directed at this aircraft. It is used to handle *
+ *    all inter-object coordination. Typically, this would be for transport helicopters and    *
+ *    other complex landing operations required of helicopters.                                *
+ *                                                                                             *
+ * INPUT:   from     -- The source of this radio message.                                      *
+ *                                                                                             *
+ *          message  -- The message itself.                                                    *
+ *                                                                                             *
+ *          param    -- An optional parameter that may be used to transfer additional          *
+ *                      data.                                                                  *
+ *                                                                                             *
+ * OUTPUT:  Returns with the radio response from the aircraft.                                 *
+ *                                                                                             *
+ * WARNINGS:   Some radio messages are handled by the base classes.                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/19/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+RadioMessageType AircraftClass::Receive_Message(RadioClass * from, RadioMessageType message, long & param)
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	switch (message) {
+
+		case RADIO_PREPARED:
+			if (Target_Legal(TarCom)) return(RADIO_NEGATIVE);
+			if ((Height == 0 && Ammo == Class->MaxAmmo) || (Height > 0 && Ammo > 0)) return(RADIO_ROGER);
+			return(RADIO_NEGATIVE);
+
+		/*
+		**	Something disastrous has happened to the object in contact with. Fall back
+		**	and regroup. This means that any landing process is immediately aborted.
+		*/
+		case RADIO_RUN_AWAY:
+			if (IsLanding) {
+				IsLanding = false;
+				IsTakingOff = true;
+			}
+			if (Class->IsFixedWing) {
+				Assign_Destination(Good_LZ());
+				if (!Target_Legal(NavCom)) {
+					Assign_Mission(MISSION_RETREAT);
+				} else {
+					Assign_Mission(MISSION_MOVE);
+				}
+			} else {
+				Scatter(0, true);
+			}
+			break;
+
+		/*
+		**	The ground control requests that this specified landing spot be used.
+		*/
+		case RADIO_MOVE_HERE:
+			FootClass::Receive_Message(from, message, param);
+			if (Is_Target_Building(param)) {
+				if (Transmit_Message(RADIO_CAN_LOAD, As_Techno(param)) != RADIO_ROGER) {
+					return(RADIO_NEGATIVE);
+				}
+				Assign_Mission(MISSION_ENTER);
+				Assign_Destination((TARGET)param);
+			} else {
+				Assign_Mission(MISSION_MOVE);
+				Assign_Destination((TARGET)param);
+			}
+			Commence();
+			return(RADIO_ROGER);
+
+		/*
+		**	Ground control is requesting if the aircraft requires navigation direction.
+		*/
+		case RADIO_NEED_TO_MOVE:
+			FootClass::Receive_Message(from, message, param);
+			if (!Target_Legal(NavCom) && !IsTakingOff && !IsLanding) {
+				return(RADIO_ROGER);
+			}
+			return(RADIO_NEGATIVE);
+
+		/*
+		**	This message is sent by the passenger when it determines that it has
+		**	entered the transport.
+		*/
+		case RADIO_IM_IN:
+			if (How_Many() == Class->Max_Passengers()) {
+				Close_Door(5, 4);
+			}
+
+			/*
+			**	If a civilian has entered the transport, then the transport will immediately
+			**	fly off the map.
+			*/
+			if (_Counts_As_Civ_Evac(from)) {
+				Assign_Mission(MISSION_RETREAT);
+			}
+			return(RADIO_ATTACH);
+
+		/*
+		**	Docking maintenance message received. Check to see if new orders should be given
+		**	to the impatient unit.
+		*/
+		case RADIO_DOCKING:
+			if (Class->Max_Passengers() > 0 && How_Many() < Class->Max_Passengers()) {
+				FootClass::Receive_Message(from, message, param);
+
+				if (!IsTethered && !IsLanding && !IsTakingOff && Height == 0) {
+
+					Open_Door(5, 4);
+
+					/*
+					**	If the potential passenger needs someplace to go, then figure out a good
+					**	spot and tell it to go.
+					*/
+					if (Transmit_Message(RADIO_NEED_TO_MOVE, from) == RADIO_ROGER) {
+						CELL cell;
+						/*DirType dir =*/ Desired_Load_Dir(from, cell);
+
+						/*
+						**	If no adjacent free cells are detected, then passenger loading
+						**	cannot occur. Break radio contact.
+						*/
+						if (cell == 0) {
+							Transmit_Message(RADIO_OVER_OUT, from);
+						} else {
+							param = (long)::As_Target(cell);
+
+							/*
+							**	Tell the potential passenger where it should go. If the passenger is
+							**	already at the staging location, then tell it to move onto the transport
+							**	directly.
+							*/
+							if (Transmit_Message(RADIO_MOVE_HERE, param, from) == RADIO_YEA_NOW_WHAT) {
+								param = (long)As_Target();
+								Transmit_Message(RADIO_TETHER);
+								if (Transmit_Message(RADIO_MOVE_HERE, param, from) != RADIO_ROGER) {
+									Transmit_Message(RADIO_OVER_OUT, from);
+								} else {
+									Contact_With_Whom()->Unselect();
+								}
+							}
+						}
+					}
+				}
+				return(RADIO_ROGER);
+			}
+			break;
+
+		/*
+		**	Asks if the passenger can load on this transport.
+		*/
+		case RADIO_CAN_LOAD:
+			if (Class->Max_Passengers() == 0 || from == NULL || !House->Is_Ally(from->Owner())) return(RADIO_STATIC);
+			if (/*!In_Radio_Contact() &&*/ How_Many() < Class->Max_Passengers()) {
+				return(RADIO_ROGER);
+			}
+			return(RADIO_NEGATIVE);
+
+		default:
+			break;
+	}
+
+	/*
+	**	Let the base class take over processing this message.
+	*/
+	return(FootClass::Receive_Message(from, message, param));
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Desired_Load_Dir -- Determines where passengers should line up.              *
+ *                                                                                             *
+ *    This routine is used by the transport helicopter to determine the location where the     *
+ *    infantry passengers should line up before loading.                                       *
+ *                                                                                             *
+ * INPUT:   object   -- The object that is trying to load up on this transport.                *
+ *                                                                                             *
+ *                   -- Reference to the cell that the passengers should move to before the    *
+ *                      actual load process may begin.                                         *
+ *                                                                                             *
+ * OUTPUT:  Returns with the direction that the helicopter should face for the load operation. *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/12/1995 JLB : Created.                                                                 *
+ *   07/30/1995 JLB : Revamped to scan all adjacent cells.                                     *
+ *=============================================================================================*/
+DirType AircraftClass::Desired_Load_Dir(ObjectClass * object, CELL & moveto) const
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	CELL center = Coord_Cell(Center_Coord());
+	for (int sweep = FACING_N; sweep < FACING_S; sweep++) {
+		moveto = Adjacent_Cell(center, FacingType(FACING_S+sweep));
+		if (Map.In_Radar(moveto) && (Coord_Cell(object->Center_Coord()) == moveto || Map[moveto].Is_Clear_To_Move(SPEED_FOOT, false, false))) return(DIR_N);
+
+		moveto = Adjacent_Cell(center, FacingType(FACING_S-sweep));
+		if (Map.In_Radar(moveto) && (Coord_Cell(object->Center_Coord()) == moveto || Map[moveto].Is_Clear_To_Move(SPEED_FOOT, false, false))) return(DIR_N);
+	}
+	return(DIR_N);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Process_Take_Off -- State machine support for taking off.                    *
+ *                                                                                             *
+ *    This routine is used by the main game state machine processor. This utility routine      *
+ *    handles a helicopter as it transitions from landed to flying state.                      *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Has the helicopter reached flight level now?                                       *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/12/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool AircraftClass::Process_Take_Off(void)
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	IsLanding = false;
+	IsTakingOff = true;
+
+	if (Class->IsFixedWing)  {
+		Set_Speed(0xFF);
+		if (Height == FLIGHT_LEVEL)  {
+			return(true);
+		}
+
+	} else {
+
+		switch (Height) {
+			case 0:
+				Close_Door(5, 4);
+				PrimaryFacing = SecondaryFacing;
+				break;
+
+			case FLIGHT_LEVEL/2:
+				PrimaryFacing.Set_Desired(Direction(NavCom));
+				break;
+
+			case FLIGHT_LEVEL-(FLIGHT_LEVEL/3):
+				SecondaryFacing.Set_Desired(PrimaryFacing.Desired());
+				Set_Speed(0x20);
+				break;
+
+			case FLIGHT_LEVEL-(FLIGHT_LEVEL/5):
+				Set_Speed(0x40);
+				break;
+
+			case FLIGHT_LEVEL:
+				Set_Speed(0xFF);
+				IsTakingOff = false;
+				return(true);
+
+			default:
+				break;
+		}
+	}
+	return(false);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Process_Landing -- Landing process state machine handler.                    *
+ *                                                                                             *
+ *    This is a support routine that is called by the main state machine routines. This        *
+ *    routine is responsible for handling the helicopter as it transitions from flight to      *
+ *    landing.                                                                                 *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Has the helicopter completely landed now?                                          *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/12/1995 JLB : Created.                                                                 *
+ *   03/04/1996 JLB : Handles fixed wing aircraft.                                             *
+ *=============================================================================================*/
+bool AircraftClass::Process_Landing(void)
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	IsTakingOff = false;
+	IsLanding = true;
+
+	if (Class->IsFixedWing)  {
+		int distance = Distance(NavCom);
+
+		if (distance > 0x0100)  {
+			SecondaryFacing.Set_Desired(::Direction(Fire_Coord(0), As_Coord(NavCom)));
+		}
+
+		switch (Height) {
+			case 0:
+				Set_Speed(0);
+				IsLanding = false;
+				return(true);
+
+			default:
+//				if (distance*2 > Class->LandingSpeed) {
+//					Set_Speed(Class->LandingSpeed);
+//				} else {
+//					Set_Speed(distance/2);
+//				}
+
+				Set_Speed(Class->LandingSpeed / House->AirspeedBias);
+				break;
+		}
+
+	} else {
+		switch (Height) {
+			case 0:
+				IsLanding = false;
+				return(true);
+
+			case FLIGHT_LEVEL/2:
+				Set_Speed(0);
+				break;
+
+			case FLIGHT_LEVEL:
+				break;
+
+			default:
+				break;
+		}
+	}
+	return(false);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Can_Enter_Cell -- Determines if the aircraft can land at this location.      *
+ *                                                                                             *
+ *    This routine is used when the passability of a cell needs to be determined. This is      *
+ *    necessary when scanning for a location that the aircraft can land.                       *
+ *                                                                                             *
+ * INPUT:   cell  -- The cell location to check for landing.                                   *
+ *                                                                                             *
+ * OUTPUT:  Returns a value indicating if the cell is a legal landing spot or not.             *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/12/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+MoveType AircraftClass::Can_Enter_Cell(CELL cell, FacingType ) const
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	if (!Map.In_Radar(cell)) return(MOVE_NO);
+
+	CellClass * cellptr = &Map[cell];
+
+	ObjectClass const * occupier = cellptr->Cell_Occupier();
+
+	if (occupier == NULL ||
+		!occupier->Is_Techno() ||
+		((TechnoClass *)occupier)->House->Is_Ally(House) ||
+		(((TechnoClass *)occupier)->Cloak != CLOAKED &&
+			(ScenarioInit == 0 && (occupier->What_Am_I() != RTTI_BUILDING || !((BuildingClass*)occupier)->Class->IsInvisible)) )
+		) {
+
+		if (!cellptr->Is_Clear_To_Move(SPEED_TRACK, false, false)) return(MOVE_NO);
+	}
+
+	if (Session.Type == GAME_NORMAL && IsOwnedByPlayer && !cellptr->IsMapped) {
+		return(MOVE_NO);
+	}
+
+	return(MOVE_OK);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Good_Fire_Location -- Searches for and finds a good spot to fire from.       *
+ *                                                                                             *
+ *    Given the specified target, this routine will locate a good spot for the aircraft to     *
+ *    fire at the target.                                                                      *
+ *                                                                                             *
+ * INPUT:   target   -- The target that is desired to be attacked.                             *
+ *                                                                                             *
+ * OUTPUT:  Returns with the target location of the place that firing should be made from.     *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/12/1995 JLB : Created.                                                                 *
+ *   06/14/1995 JLB : Finer resolution on ring scan.                                           *
+ *   11/02/1996 JLB : Bias fire position to get closer to moving objects.                      *
+ *=============================================================================================*/
+TARGET AircraftClass::Good_Fire_Location(TARGET target) const
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	if (Target_Legal(target)) {
+		int range = Weapon_Range(0);
+		COORDINATE tcoord = As_Coord(target);
+		CELL bestcell = 0;
+		CELL best2cell = 0;
+		int bestval = -1;
+		int best2val = -1;
+
+		/*
+		**	Try to get closer to a target that is moving.
+		*/
+		COORDINATE altcoord = 0;
+		if (Is_Target_Object(target) && As_Object(target)->Is_Foot()) {
+			TARGET alttarg = ((FootClass *)As_Object(target))->NavCom;
+			if (Target_Legal(alttarg)) {
+				altcoord = As_Coord(alttarg);
+			}
+		}
+
+		for (int r = range-0x0100; r > 0x0100; r -= 0x0100) {
+			for (int face = 0; face < 255; face += 16) {
+				COORDINATE newcoord = Coord_Move(tcoord, (DirType)face, r);
+				CELL newcell = Coord_Cell(newcoord);
+
+				if (Map.In_Radar(newcell) && (Session.Type != GAME_NORMAL || Map[newcell].IsVisible) && Cell_Seems_Ok(newcell, true)) {
+					int dist;
+					if (altcoord != 0) {
+						dist = ::Distance(newcoord, altcoord);
+					} else {
+						dist = Distance(newcoord);
+					}
+					if (bestval == -1 || dist < bestval) {
+						best2val = bestval;
+						best2cell = bestcell;
+						bestval = dist;
+						bestcell = newcell;
+					}
+				}
+			}
+			if (bestval != -1) break;
+		}
+
+		if (best2val == -1) {
+			best2cell = bestcell;
+		}
+
+		/*
+		**	If it found a good firing location, then return this location as
+		**	a target value.
+		*/
+		if (bestval != -1) {
+			if (Percent_Chance(50)) {
+				return(::As_Target(bestcell));
+			} else {
+				return(::As_Target(best2cell));
+			}
+		}
+	}
+	return(TARGET_NONE);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Cell_Seems_Ok -- Checks to see if a cell is good to enter.                   *
+ *                                                                                             *
+ *    This routine examines the navigation computers of other aircraft in order to see if the  *
+ *    specified cell is safe to fly to. The intent of this routine is to avoid unnecessary     *
+ *    mid-air collisions.                                                                      *
+ *                                                                                             *
+ * INPUT:   cell     -- The cell to examine for clear airspace.                                *
+ *                                                                                             *
+ *          strict   -- Should the scan consider the aircraft, that is making this check, a    *
+ *                      blocking aircraft. Typically, the aircraft itself is not considered    *
+ *                      a blockage -- an aircraft can always exist where it is currently       *
+ *                      located. A strict check is useful for helicopters that need to move    *
+ *                      around at the slightest provocation.                                   *
+ *                                                                                             *
+ * OUTPUT:  Is the specified cell free from airspace conflicts?                                *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/19/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool AircraftClass::Cell_Seems_Ok(CELL cell, bool strict) const
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	/*
+	**	Make sure that no other aircraft are heading to the selected location. If they
+	**	are, then don't consider the location as valid.
+	*/
+	TARGET astarget = ::As_Target(cell);
+	for (int index = 0; index < Aircraft.Count(); index++) {
+		AircraftClass * air = Aircraft.Ptr(index);
+		if (air && (strict || air != this) && !air->IsInLimbo) {
+			if (Coord_Cell(air->Coord) == cell || air->NavCom == astarget) {
+				return(false);
+			}
+		}
+	}
+	return(true);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Pip_Count -- Returns the number of "objects" in aircraft.                    *
+ *                                                                                             *
+ *    This routine is used by the render logic to draw the little container "pips". This       *
+ *    corresponds to the number of passengers for a transport helicopter or the number of      *
+ *    shots remaining for an attack helicopter.                                                *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the number of "pips" to render on the aircraft.                       *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/11/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+int AircraftClass::Pip_Count(void) const
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	int retval = 0;
+
+	if (Class->Max_Passengers() > 0) {
+		retval = How_Many();
+	} else {
+		if (Ammo) {
+			retval = Class->Max_Pips() * fixed(Ammo, Class->MaxAmmo);
+			if (!retval) retval = 1;
+		}
+	}
+	return(retval);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Mission_Enter -- Control aircraft to fly to the helipad or repair center.    *
+ *                                                                                             *
+ *    This routine is used when the aircraft needs to fly for either rearming or repairing.    *
+ *    It tries to establish contact with the support building. Once contact is established     *
+ *    the ground controller takes care of commanding the aircraft.                             *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the delay before this routine should be called again.                 *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/12/1995 JLB : Created.                                                                 *
+ *   07/04/1995 JLB : Ground controller gives orders.                                          *
+ *=============================================================================================*/
+int AircraftClass::Mission_Enter(void)
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	enum {
+		INITIAL,
+		TAKEOFF,
+		ALTITUDE,
+		STACK,
+		DOWNWIND,
+		CROSSWIND,
+		TRAVEL,
+		LANDING
+	};
+
+	/*
+	**	Verify that it has a valid NavCom. If it doesn't then request one from the
+	**	building this building is trying to land upon. If that fails, then enter
+	**	idle mode.
+	*/
+	if (!Target_Legal(NavCom) && In_Which_Layer() != LAYER_GROUND) {
+		if (Transmit_Message(RADIO_DOCKING) != RADIO_ROGER) {
+			Enter_Idle_Mode();
+			return(1);
+		}
+	}
+
+	switch (Status) {
+		case INITIAL:
+			if (Height < FLIGHT_LEVEL || IsLanding) {
+				Status = TAKEOFF;
+			} else {
+				Status = ALTITUDE;
+			}
+			break;
+
+		case TAKEOFF:
+			if (Process_Take_Off()) {
+				/*
+				**	After takeoff is complete, break radio contact with any helipad that this
+				**	helicopter is taking off from.
+				*/
+				if (In_Radio_Contact() && Map[Coord].Cell_Building() == Contact_With_Whom()) {
+					Transmit_Message(RADIO_OVER_OUT);
+				}
+				Status = ALTITUDE;
+			}
+			break;
+
+		case ALTITUDE:
+			/*
+			**	Establish radio contact with the building this helicopter is trying
+			**	to land at.
+			*/
+			if (In_Radio_Contact()) {
+				if (!Target_Legal(NavCom)) {
+					Transmit_Message(RADIO_DOCKING);
+					if (!Target_Legal(NavCom)) {
+						Enter_Idle_Mode();
+						return(1);
+					}
+				}
+				Status = STACK;
+			} else {
+				TechnoClass * tech = As_Techno(NavCom);
+				if (tech && Transmit_Message(RADIO_CAN_LOAD, tech) == RADIO_ROGER) {
+					Transmit_Message(RADIO_HELLO, tech);
+					Transmit_Message(RADIO_DOCKING);
+					Status = STACK;
+				} else {
+#ifdef FIXIT_CARRIER	//	checked - ajw 9/28/98
+					if (tech->What_Am_I() != RTTI_VESSEL) {
+						Assign_Destination(TARGET_NONE);
+						Enter_Idle_Mode();
+					}
+#else
+					Assign_Destination(TARGET_NONE);
+					Enter_Idle_Mode();
+#endif
+				}
+			}
+			break;
+
+		case STACK:
+			if (Class->IsFixedWing)  {
+				int distance;
+				TARGET togo;
+
+				BuildingClass const * building = As_Building(NavCom);
+				if (building)  {
+					togo = ::As_Target(building->Check_Point(CHECK_STACK));
+				} else {
+					togo = NavCom;
+				}
+
+				distance = Process_Fly_To(true, togo);
+				if (distance < 0x0080)  {
+					Status = DOWNWIND;
+				}
+			} else {
+				Status = DOWNWIND;
+			}
+			break;
+
+		case DOWNWIND:
+			if (Class->IsFixedWing)  {
+				int distance;
+				TARGET togo;
+
+				Set_Speed(200);
+				BuildingClass const * building = As_Building(NavCom);
+				if (building)  {
+					togo = ::As_Target(building->Check_Point(CHECK_DOWNWIND));
+				} else {
+					togo = NavCom;
+				}
+
+				distance = Process_Fly_To(true, togo);
+				if (distance < 0x0080)  {
+					Status = CROSSWIND;
+				}
+			} else {
+				Status = CROSSWIND;
+			}
+			break;
+
+		case CROSSWIND:
+			if (Class->IsFixedWing)  {
+				int distance;
+				TARGET togo;
+
+				Set_Speed(140);
+				BuildingClass const * building = As_Building(NavCom);
+				if (building)  {
+					togo = ::As_Target(building->Check_Point(CHECK_CROSSWIND));
+				} else {
+					togo = NavCom;
+				}
+
+				distance = Process_Fly_To(true, togo);
+				if (distance < 0x0080)  {
+					Status = TRAVEL;
+				}
+			} else {
+				Status = TRAVEL;
+			}
+			break;
+
+		case TRAVEL:
+			Transmit_Message(RADIO_DOCKING);
+#ifdef FIXIT_CARRIER	//	checked - ajw 9/28/98
+			if (!In_Radio_Contact() && !Is_Target_Vessel(NavCom)) {
+#else
+			if (!In_Radio_Contact()) {
+#endif
+				Assign_Destination(TARGET_NONE);
+				Enter_Idle_Mode();
+			} else {
+				int distance = Process_Fly_To(true, NavCom);
+
+				if (Class->IsFixedWing)  {
+
+					if (distance < 0x0400)  {
+						Status = LANDING;
+					}
+					return(1);
+
+				} else {
+					if (distance < 0x0080) {
+						if (Target_Legal(TarCom)) {
+							SecondaryFacing.Set_Desired(Direction(TarCom));
+						} else {
+							SecondaryFacing.Set_Desired(Pose_Dir());
+						}
+
+#ifdef FIXIT_CARRIER	//	checked - ajw 9/28/98
+ if (Is_Target_Vessel(NavCom) && !In_Radio_Contact()) {
+ 	Enter_Idle_Mode();
+ 	break;
+ }
+#endif
+						if (distance < 0x0010) {
+							Status = LANDING;
+#ifdef FIXIT_CARRIER	//	checked - ajw 9/28/98
+	if(Is_Target_Vessel(NavCom) && As_Vessel(NavCom)->NavCom) {
+		Status = TRAVEL;
+	}
+#endif
+
+						}
+						break;
+					} else {
+						SecondaryFacing.Set_Desired(Direction(NavCom));
+//						SecondaryFacing.Set_Desired(::Direction(Fire_Coord(0), As_Coord(NavCom)));
+					}
+				}
+				return(3);
+			}
+			break;
+
+		case LANDING:
+			if (IsTakingOff && !Class->IsFixedWing) {
+				Assign_Destination(TARGET_NONE);
+				Enter_Idle_Mode();
+			}
+#ifdef FIXIT_CARRIER	//	checked - ajw 9/28/98
+// If we were trying to land on a carrier and it moved, take off again
+	if ( As_Vessel(NavCom) && !In_Radio_Contact()) {
+		Status = INITIAL;
+		break;
+	}
+#endif
+			if (Process_Landing()) {
+				switch (Transmit_Message(RADIO_IM_IN)) {
+					case RADIO_ROGER:
+						Assign_Mission(MISSION_GUARD);
+						break;
+
+					case RADIO_ATTACH:
+#ifdef FIXIT_CARRIER	//	checked - ajw 9/28/98
+						if(Contact_With_Whom()->What_Am_I() != RTTI_VESSEL) Limbo();
+#else
+						Limbo();
+#endif
+						Contact_With_Whom()->Attach(this);
+						break;
+
+					default:
+						Enter_Idle_Mode();
+				}
+			}
+			break;
+
+		default:
+			break;
+	}
+	return(1);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Good_LZ -- Locates a good spot to land.                                      *
+ *                                                                                             *
+ *    This routine is used when helicopters need a place to land, but there are no obvious     *
+ *    spots (i.e., helipad) available. It will try to land near a friendly helipad or friendly *
+ *    building if there are no helipads anywhere. In the event that there are no friendly      *
+ *    buildings anywhere on the map, then just land right where it is flying.                  *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the target location where this aircraft should land. This value may   *
+ *          not be a clear cell, but the normal landing logic will resolve that problem.       *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/12/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+TARGET AircraftClass::Good_LZ(void) const
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	/*
+	**	Scan through all of the buildings and try to land near
+	**	the helipad (if there is one) or the nearest friendly building.
+	*/
+	CELL bestcell = 0;
+	int bestdist = -1;
+	for (int index = 0; index < Buildings.Count(); index++) {
+		BuildingClass * building = Buildings.Ptr(index);
+
+		if (building && !building->IsInLimbo && building->House == House) {
+			int dist = Distance(building);
+			if (*building == Class->Building) {
+				dist /= 4;
+			}
+			if (bestdist == -1 || dist < bestdist) {
+				bestdist = dist;
+				bestcell = Coord_Cell(building->Center_Coord());
+			}
+		}
+	}
+
+	/*
+	**	Return with the suitable location if one was found.
+	*/
+	if (bestdist != -1) {
+		return(::As_Target(bestcell));
+	}
+
+	/*
+	**	No good location was found. Just try to land here.
+	*/
+	return(::As_Target(Coord_Cell(Coord)));
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Set_Speed -- Sets the speed for the aircraft.                                *
+ *                                                                                             *
+ *    This routine will set the speed for the aircraft. The speed is specified as a fraction   *
+ *    of full speed.                                                                           *
+ *                                                                                             *
+ * INPUT:   speed -- The fixed point fractional speed setting. 0x00 is stopped, 0xFF is full   *
+ *                   speed.                                                                    *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/19/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AircraftClass::Set_Speed(int speed)
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	FootClass::Set_Speed(speed);
+
+	MPHType sp = MPHType(min(Class->MaxSpeed * SpeedBias * House->AirspeedBias, MPH_LIGHT_SPEED));
+	Fly_Speed(speed, sp);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Fire_Direction -- Determines the direction of fire.                          *
+ *                                                                                             *
+ *    This routine will determine what direction a projectile would take if it were fired      *
+ *    from the aircraft. This is the direction that the aircraft's body is facing.             *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the direction of projectile fire.                                     *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/19/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+DirType AircraftClass::Fire_Direction(void) const
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	return(SecondaryFacing.Current());
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::~AircraftClass -- Destructor for aircraft object.                            *
+ *                                                                                             *
+ *    This is the destructor for aircraft. It will limbo the aircraft if it isn't already      *
+ *    and also removes the aircraft from any team it may be attached to.                       *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/24/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+AircraftClass::~AircraftClass(void)
+{
+	if (GameActive && Class) {
+
+		/*
+		**	Remove this member from any team it may be associated with. This must occur at the
+		**	top most level of the inheritance hierarchy because it may call virtual functions.
+		*/
+		if (Team) {
+			Team->Remove(this);
+			Team = NULL;
+		}
+
+		House->Tracking_Remove(this);
+
+		/*
+		**	If there are any cargo members, delete them.
+		*/
+		while (Is_Something_Attached()) {
+			delete Detach_Object();
+		}
+
+		AircraftClass::Limbo();
+		Class = 0;
+	}
+	ID = -1;
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Scatter -- Causes the aircraft to move away a bit.                           *
+ *                                                                                             *
+ *    This routine will cause the aircraft to move away from its current location and then     *
+ *    enter some idle mode. Typically this is called when the aircraft is attacked while on    *
+ *    the ground.                                                                              *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/08/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AircraftClass::Scatter(COORDINATE , bool, bool )
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	/*
+	**	Certain missions prevent scattering regardless of whether it would be
+	**	a good idea or not.
+	*/
+	if (!MissionControl[Mission].IsScatter) return;
+
+	/*
+	**	Fixed wing aircraft never scatter.
+	*/
+	if (Class->IsFixedWing) return;
+
+	if (IsLanding || Height == 0) {
+		IsLanding = false;
+		IsTakingOff = true;
+	}
+	Enter_Idle_Mode();
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Mission_Guard -- Handles aircraft in guard mode.                             *
+ *                                                                                             *
+ *    Aircraft don't like to be in guard mode if in flight. If this situation is detected,     *
+ *    then figure out what the aircraft should be doing and go do it.                          *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the number of game frames to delay before calling this routine again. *
+ *                                                                                             *
+ * WARNINGS:   This routine typically calls the normal guard logic for ground units.           *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/18/1995 JLB : Created.                                                                 *
+ *   10/10/1995 JLB : Hunts for harvesters that are unescorted.                                *
+ *=============================================================================================*/
+int AircraftClass::Mission_Guard(void)
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	if (Height == FLIGHT_LEVEL) {
+
+		/*
+		**	If part of a team, then do nothing, since the team
+		**	handler will take care of giving this aircraft a
+		**	mission.
+		*/
+		if (Team) {
+			if (Target_Legal(NavCom)) {
+				Assign_Mission(MISSION_MOVE);
+			}
+			return(MissionControl[Mission].Normal_Delay());
+		}
+
+		if (Class->PrimaryWeapon == NULL) {
+			Assign_Destination(::As_Target(Coord_Cell(Coord)));
+			Assign_Mission(MISSION_MOVE);
+		} else {
+			if (!Team.Is_Valid()) Enter_Idle_Mode();
+		}
+		return(1);
+	}
+	if (House->IsHuman) return(MissionControl[Mission].Normal_Delay());
+
+	/*
+	**	If the aircraft is very badly damaged, then it will search for a
+	**	repair bay first.
+	*/
+	if (House->Available_Money() >= 100 && Health_Ratio() <= Rule.ConditionYellow) {
+		if (!In_Radio_Contact() ||
+			(Height == 0 &&
+				(Contact_With_Whom()->What_Am_I() != RTTI_BUILDING || *((BuildingClass *)Contact_With_Whom()) != STRUCT_REPAIR))) {
+
+
+			BuildingClass * building = Find_Docking_Bay(STRUCT_REPAIR, true);
+			if (building != NULL) {
+				Assign_Destination(building->As_Target());
+				Assign_Target(TARGET_NONE);
+				Assign_Mission(MISSION_ENTER);
+				return(1);
+			}
+		}
+	}
+
+	/*
+	**	If the aircraft cannot attack anything because of lack of ammo,
+	**	abort any normal guard logic in order to look for a helipad
+	**	to rearm.
+	*/
+	if (Ammo == 0 && Is_Weapon_Equipped()) {
+		if (!In_Radio_Contact()) {
+			BuildingClass * building = Find_Docking_Bay(STRUCT_HELIPAD, false);
+#ifdef FIXIT_CARRIER	//	checked - ajw 9/28/98
+	if (!Class->IsFixedWing) {
+		int dist = 0x7FFFFFFF;
+		if (building) dist=Distance(building);
+		for (int index = 0; index < Vessels.Count(); index++) {
+			VesselClass *ship = Vessels.Ptr(index);
+			if (ship != NULL && *ship == VESSEL_CARRIER && !ship->IsInLimbo && ship->IsActive && ship->House == House && ship->How_Many() < ship->Class->Max_Passengers()) {
+				if (Distance(ship) < dist || !building) {
+					building = (BuildingClass *)ship;
+					dist = Distance(ship);
+				}
+//				break;
+			}
+		}
+	}
+#endif
+			if (building != NULL) {
+				Assign_Destination(building->As_Target());
+				Assign_Target(TARGET_NONE);
+				Assign_Mission(MISSION_ENTER);
+				return(1);
+			}
+		}
+	}
+
+	/*
+	**	If the aircraft already has a target, then attack it if possible.
+	*/
+	if (Target_Legal(TarCom)) {
+		Assign_Mission(MISSION_ATTACK);
+		return(1);
+	}
+
+	/*
+	**	Transport helicopters don't really do anything but just sit there.
+	*/
+	if (!Is_Weapon_Equipped()) {
+		return(TICKS_PER_SECOND*3);
+	}
+
+	/*
+	**	Computer controlled helicopters will defend themselves by bouncing around
+	**	and looking for a free helipad.
+	*/
+	if (Height == 0 && !In_Radio_Contact()) {
+		Scatter(0, true);
+		return(TICKS_PER_SECOND*3);
+	}
+
+	/*
+	**	Perform a special check to hunt for harvesters that are outside of the protective
+	**	shield of their base.
+	*/
+	if (House->State != STATE_ATTACKED) {
+		TARGET target = House->Find_Juicy_Target(Coord);
+
+		if (Target_Legal(target)) {
+			Assign_Target(target);
+			Assign_Mission(MISSION_ATTACK);
+		}
+	}
+
+	return(FootClass::Mission_Guard());
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Mission_Guard_Area -- Handles the aircraft guard area logic.                 *
+ *                                                                                             *
+ *    This routine handles area guard logic for aircraft. Aircraft require special handling    *
+ *    for this mode since they are to guard area only if they are in a position to do so.      *
+ *    Otherwise they just defend themselves.                                                   *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the number of game frames to delay before calling this routine        *
+ *          again.                                                                             *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/10/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+int AircraftClass::Mission_Guard_Area(void)
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	if (Height == FLIGHT_LEVEL) {
+		if (!Team.Is_Valid()) Enter_Idle_Mode();
+		return(1);
+	}
+	if (House->IsHuman) return(TICKS_PER_SECOND);
+
+	if (Height == 0 && !In_Radio_Contact()) {
+		Scatter(0, true);
+		return(TICKS_PER_SECOND*3);
+	}
+
+	if (Target_Legal(TarCom)) {
+		Assign_Mission(MISSION_ATTACK);
+		return(1);
+	}
+	return(FootClass::Mission_Guard_Area());
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Response_Attack -- Gives audio response to attack order.                     *
+ *                                                                                             *
+ *    This routine is used to give an audio response to an attack order.                       *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/10/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AircraftClass::Response_Attack(void)
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	static VocType _response[] = {
+		VOC_AFFIRM,
+		VOC_ACKNOWL
+	};
+	VocType response = _response[Sim_Random_Pick(0, ARRAY_SIZE(_response)-1)];
+	if (AllowVoice) {
+		Sound_Effect(response, fixed(1), -(ID+1));
+	}
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Response_Move -- Gives audio response to move request.                       *
+ *                                                                                             *
+ *    This routine is used to give an audio response to movement orders.                       *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/10/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AircraftClass::Response_Move(void)
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	static VocType _response[] = {
+		VOC_ACKNOWL,
+		VOC_AFFIRM
+	};
+	VocType response = _response[Sim_Random_Pick(0, ARRAY_SIZE(_response)-1)];
+	if (AllowVoice) {
+		Sound_Effect(response, fixed(1), -(ID+1));
+	}
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Response_Select -- Gives audio response when selected.                       *
+ *                                                                                             *
+ *    This routine is called when an audio response for selection is desired.                  *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/10/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AircraftClass::Response_Select(void)
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	static VocType _response[] = {
+		VOC_VEHIC,
+		VOC_REPORT,
+		VOC_YESSIR,
+		VOC_YESSIR,
+		VOC_YESSIR,
+		VOC_AWAIT
+	};
+	VocType response = _response[Sim_Random_Pick(0, ARRAY_SIZE(_response)-1)];
+	if (AllowVoice) {
+		Sound_Effect(response, fixed(1), -(ID+1));
+	}
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Can_Fire -- Checks to see if the aircraft can fire.                          *
+ *                                                                                             *
+ *    This routine is used to determine if the aircraft can fire its weapon at the target      *
+ *    specified. If it cannot, then the reason why is returned.                                *
+ *                                                                                             *
+ * INPUT:   target   -- The target that the aircraft might fire upon.                          *
+ *                                                                                             *
+ *          which    -- The weapon that will be used to fire.                                  *
+ *                                                                                             *
+ * OUTPUT:  Returns with the reason why it can't fire or with FIRE_OK.                         *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   03/05/1996 JLB : Created.                                                                 *
+ *   07/11/1996 JLB : Fixed for camera carrying aircraft.                                      *
+ *=============================================================================================*/
+FireErrorType AircraftClass::Can_Fire(TARGET target, int which) const
+{
+	assert(Aircraft.ID(this) == ID);
+	assert(IsActive);
+
+	if (Passenger && !Is_Something_Attached()) {
+		return(FIRE_AMMO);
+	}
+
+	bool camera = (Class->PrimaryWeapon != NULL && Class->PrimaryWeapon->IsCamera);
+	bool fudge = (Passenger || (Class->PrimaryWeapon != NULL && Class->PrimaryWeapon->Bullet != NULL && Class->PrimaryWeapon->Bullet->IsParachuted));
+
+	if (fudge && !camera && !Ammo && !Passenger) {
+		return(FIRE_AMMO);
+	}
+
+	/*
+	**	Passenger aircraft that wish to 'fire' actually are requesting to
+	**	paradrop or 'throw out' the cargo. This is always allowed if the terrain under the
+	**	aircraft is generally clear.
+	*/
+	if (camera || (fudge && Passenger && Is_Something_Attached()))  {
+		if (Arm != 0) return(FIRE_REARM);
+
+		if (Distance(target) < (camera ? 0x0380 : 0x0200) && Map.In_Radar(Coord_Cell(Center_Coord()))) {
+//		if (Distance(target) < (camera ? 0x0380 : 0x0280) && Map.In_Radar(Coord_Cell(Center_Coord()))) {
+			return(FIRE_OK);
+		}
+		return(FIRE_RANGE);
+	}
+
+	FireErrorType canfire = FootClass::Can_Fire(target, which);
+
+	if (canfire == FIRE_OK) {
+
+		/*
+		**	Double check to make sure that the facing is roughly toward
+		**	the target. If the difference is too great, then firing is
+		**	temporarily postponed.
+		*/
+		if (Class->IsFixedWing) {
+
+			int diff = PrimaryFacing.Difference(Direction(TarCom));
+			if (ABS(diff) > (fudge ? 16 : 8)) {
+				return(FIRE_FACING);
+			}
+		}
+	}
+	return(canfire);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Landing_Takeoff_AI -- Handle aircraft take off and landing processing.       *
+ *                                                                                             *
+ *    This routine handles the tricky maneuver of taking off and landing. The process of       *
+ *    landing is not entirely safe and thus the aircraft may be destroyed as a consequence.    *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the aircraft destroyed by this process?                                  *
+ *                                                                                             *
+ * WARNINGS:   Only call this routine once per aircraft per game logic loop. Be sure to        *
+ *             examine the return value and if true, abort all further processing of this      *
+ *             aircraft since it is now dead.                                                  *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/29/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool AircraftClass::Landing_Takeoff_AI(void)
+{
+	/*
+	**	Handle landing and taking off logic. Helicopters are prime users of this technique. The
+	**	aircraft will either gain or lose altitude as appropriate. As the aircraft transitions
+	**	between flying level and ground level, it will be moved into the appropriate render
+	**	layer.
+	*/
+	if (Is_Door_Closed() && (IsLanding || IsTakingOff)) {
+		LayerType layer = In_Which_Layer();
+
+		if (IsLanding) {
+			Mark(MARK_UP);
+			if (Height) Height -= Pixel_To_Lepton(1);
+			if (Height <= 0) {
+				Height = 0;
+				IsLanding = false;
+				Set_Speed(0);
+
+				/*
+				**	If the NavCom now equals the destination, then clear out the NavCom.
+				*/
+				if (Coord_Cell(Center_Coord()) == As_Cell(NavCom)) {
+					Assign_Destination(TARGET_NONE);
+				}
+
+				/*
+				** If a fixed-wing aircraft just landed on the ground, blow him up
+				*/
+				if (Class->IsFixedWing && Mission != MISSION_ENTER) {
+					Strength = 1;
+
+					int damage = Strength;
+					Map.Remove(this, layer);
+					Take_Damage(damage, 0, WARHEAD_AP, 0, true);
+					return(true);
+				}
+
+				if (Target_Legal(NavCom) && As_Techno(NavCom) == Contact_With_Whom()) {
+					if (In_Radio_Contact() && Transmit_Message(RADIO_IM_IN) != RADIO_ROGER) {
+						Scatter(0, true);
+					}
+				}
+			}
+			Mark(MARK_DOWN);
+		}
+		if (IsTakingOff) {
+			Mark(MARK_UP);
+//			Map.Remove(this, layer);
+			Height += Pixel_To_Lepton(1);
+			if (Height >= FLIGHT_LEVEL) {
+				Height = FLIGHT_LEVEL;
+				IsTakingOff = false;
+			}
+//			Map.Submit(this, In_Which_Layer());
+			Mark(MARK_DOWN);
+		}
+
+		/*
+		**	Make adjustments for altitude by moving from one layer to another as
+		**	necessary.
+		*/
+		if (layer != In_Which_Layer()) {
+
+			/*
+			**	When the aircraft is about to enter the ground layer, perform on last
+			**	check to see if it is legal to enter that location. If not, then
+			**	start the take off process. Let the normal logic handle this
+			**	change of plans.
+			*/
+			bool ok = true;
+			if (In_Which_Layer() == LAYER_GROUND && !IsTakingOff && !Class->IsFixedWing) {
+				if (!Is_LZ_Clear(::As_Target(Coord_Cell(Coord)))) {
+					IsTakingOff = true;
+					Mark(MARK_UP);
+					Height += Pixel_To_Lepton(1);
+					Mark(MARK_DOWN);
+					ok = false;
+				}
+			}
+
+			if (ok) {
+
+				Map.Remove(this, layer);
+				Map.Submit(this, In_Which_Layer());
+
+				/*
+				**	When the aircraft is close to the ground, it should exist as a ground object.
+				**	This aspect is controlled by the Place_Down and Pick_Up functions.
+				*/
+				if (In_Which_Layer() == LAYER_GROUND) {
+					Assign_Destination(TARGET_NONE);		// Clear the navcom.
+					Transmit_Message(RADIO_TETHER);
+					Look();
+//					Map.Sight_From(Coord_Cell(Coord), 1, House, false);
+				} else  {
+					Transmit_Message(RADIO_UNTETHER);
+
+					/*
+					**	If the navigation computer is not attached to the object this
+					**	aircraft is in radio contact with, then assume that radio
+					**	contact is now superfluous. Break radio contact.
+					*/
+					if (In_Radio_Contact() && Target_Legal(NavCom) && NavCom != Contact_With_Whom()->As_Target()) {
+						Transmit_Message(RADIO_OVER_OUT);
+					}
+				}
+			}
+		}
+	}
+	return(false);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Edge_Of_World_AI -- Detect if aircraft has exited the map.                   *
+ *                                                                                             *
+ *    Certain aircraft will be eliminated when they leave the edge of the world presumably     *
+ *    after completing their mission. An exception is for aircraft that have been newly        *
+ *    created as reinforcements and have not yet completed their mission.                      *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the aircraft deleted by this routine?                                    *
+ *                                                                                             *
+ * WARNINGS:   Be sure to call this routine only once per aircraft per game logic loop. If     *
+ *             the return value is true, then abort any further processing of this aircraft    *
+ *             since it has been eliminated.                                                   *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/29/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool AircraftClass::Edge_Of_World_AI(void)
+{
+	if (!Map.In_Radar(Coord_Cell(Coord))) {
+		if (Mission == MISSION_RETREAT /*|| (*this == AIRCRAFT_CARGO && !Is_Something_Attached())*/) {
+
+			/*
+			**	Check to see if there are any civilians aboard. If so, then flag the house
+			**	that the civilian evacuation trigger event has been fulfilled.
+			*/
+			while (Is_Something_Attached()) {
+				FootClass * obj = Detach_Object();
+
+				/*
+				**	Flag the owning house that civ evacuation has occurred.
+				*/
+				if (_Counts_As_Civ_Evac(obj)) {
+					obj->House->IsCivEvacuated = true;
+				}
+
+				if (obj->Team.Is_Valid()) obj->Team->IsLeaveMap = true;
+
+#ifdef OLD
+				/*
+				**	Transport planes that leave can only be because they carry purchased
+				**	equipment and must be have their cost refunded.
+				*/
+				if (*this == AIRCRAFT_CARGO) {
+					House->Refund_Money(obj->Class_Of().Cost_Of());
+				}
+#endif
+				delete obj;
+			}
+			if (Team.Is_Valid()) {
+				Team->IsLeaveMap = true;
+			}
+			Stun();
+			delete this;
+			return(true);
+		}
+	} else {
+		IsLocked = true;
+	}
+	return(false);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Movement_AI -- Handles aircraft physical movement logic.                     *
+ *                                                                                             *
+ *    This routine manages the aircraft movement across the map. If any movement occurred, the *
+ *    aircraft will be flagged to be redrawn.                                                  *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   Only call this routine once per aircraft per game logic loop.                   *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/29/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AircraftClass::Movement_AI(void)
+{
+	/*
+	**	If for some strange reason, there is a valid NavCom, but this aircraft is not
+	**	in a movement order, then give it a movement order.
+	*/
+	if (Target_Legal(NavCom) && Mission == MISSION_GUARD && MissionQueue == MISSION_NONE) {
+		Assign_Mission(MISSION_MOVE);
+	}
+
+	if (Speed != 0) {
+		if (In_Which_Layer() == LAYER_GROUND)  {
+			Mark(MARK_UP);
+			Physics(Coord, PrimaryFacing);
+			Mark(MARK_DOWN);
+		} else {
+			Mark(MARK_CHANGE_REDRAW);
+			if (Physics(Coord, PrimaryFacing) != RESULT_NONE) {
+				Mark(MARK_CHANGE_REDRAW);
+			}
+		}
+	}
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Rotation_AI -- Handle aircraft body and flight rotation.                     *
+ *                                                                                             *
+ *    This will process the aircraft visible body and flight model rotation operations. If     *
+ *    any rotation occurred, the aircraft will be flagged to be redrawn.                       *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   Only call this routine once per aircraft per game logic loop.                   *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/29/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AircraftClass::Rotation_AI(void)
+{
+	if (PrimaryFacing.Is_Rotating()) {
+		Mark(MARK_CHANGE_REDRAW);
+		if (PrimaryFacing.Rotation_Adjust(Class->ROT)) {
+			Mark(MARK_CHANGE_REDRAW);
+		}
+	}
+	if (Class->IsFixedWing) {
+		SecondaryFacing = PrimaryFacing;
+	}
+	if (SecondaryFacing.Is_Rotating()) {
+		Mark(MARK_CHANGE_REDRAW);
+		if (SecondaryFacing.Rotation_Adjust(Class->ROT)) {
+			Mark(MARK_CHANGE_REDRAW);
+		}
+	}
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Per_Cell_Process -- Handle the aircraft per cell process.                    *
+ *                                                                                             *
+ *    This is a seldom used function since its only purpose is to be called when an aircraft   *
+ *    lands on the ground.                                                                     *
+ *                                                                                             *
+ * INPUT:   why   -- Why was this per cell process function called.                            *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   09/15/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AircraftClass::Per_Cell_Process(PCPType why)
+{
+	BStart(BENCH_PCP);
+	FootClass::Per_Cell_Process(why);
+	BEnd(BENCH_PCP);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Assign_Destination -- Assigns movement destination to the object.            *
+ *                                                                                             *
+ *    This routine is called when the object needs to have a new movement destination          *
+ *    assigned.  Aircraft have their own version of this routine because a fixed-wing plane	  *
+ *    trying to land will behave poorly if given a new destinatio while it's landing.			  *                                                                                         *
+ *                                                                                             *
+ * INPUT:   destination -- The destination to assign to this object.                           *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/24/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AircraftClass::Assign_Destination(TARGET dest)
+{
+	assert(IsActive);
+	if (dest == NavCom) return;
+
+	if (Target_Legal(dest) && Class->IsFixedWing && (IsLanding || (Target_Legal(NavCom) && dest != NavCom))) {
+//	if (Target_Legal(dest) /*&& Class->IsFixedWing*/ && (IsLanding || (Target_Legal(NavCom) && dest != NavCom))) {
+
+//		if (Class->IsFixedWing || As_Cell(dest) != Coord_Cell(Center_Coord())) {
+			Process_Take_Off();
+			Status = 0;
+//		}
+	}
+	FootClass::Assign_Destination(dest);
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::In_Which_Layer -- Calculates the display layer of the aircraft.              *
+ *                                                                                             *
+ *    This examines the aircraft to determine what display layer it should be located          *
+ *    in. Fixed wing aircraft must always be in the top layer if they are flying even though   *
+ *    they may be low to the ground.                                                           *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the layer that this aircraft resides in.                              *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   10/20/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+LayerType AircraftClass::In_Which_Layer(void) const
+{
+	if (Class->IsFixedWing && Height > 0) {
+		return(LAYER_TOP);
+	}
+	return(FootClass::In_Which_Layer());
+}
+
+
+/***********************************************************************************************
+ * AircraftClass::Look -- Aircraft will look if they are on the ground always.                 *
+ *                                                                                             *
+ *    Aircraft perform a look operation according to their sight range. If the aircraft is     *
+ *    on the ground, then it will look a distance of one cell regardless of what its           *
+ *    specified sight range is.                                                                *
+ *                                                                                             *
+ * INPUT:   incremental -- Is this an incremental look?                                        *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   10/23/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AircraftClass::Look(bool incremental)
+{
+	assert(IsActive);
+	assert(!IsInLimbo);
+
+	int sight_range = Techno_Type_Class()->SightRange;
+	if (Height == 0) {
+		sight_range = 1;
+	}
+
+	if (sight_range) {
+		Map.Sight_From(Coord_Cell(Coord), sight_range, House, incremental);
+	}
+}

+ 248 - 0
CODE/AIRCRAFT.H

@@ -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 - 0
CODE/ALLOC.CPP

@@ -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 - 0
CODE/ANIM.CPP

@@ -0,0 +1,1108 @@
+/*
+**	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.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 : Dune                                                         *
+ *                                                                                             *
+ *                    File Name : ANIM.CPP                                                     *
+ *                                                                                             *
+ *                   Programmer : Joe L. Bostic                                                *
+ *                                                                                             *
+ *                   Start Date : June 3, 1991                                                 *
+ *                                                                                             *
+ *---------------------------------------------------------------------------------------------*
+ * Functions:                                                                                  *
+ *   AnimClass::AI -- This is the low level anim processor.                                    *
+ *   AnimClass::AnimClass -- The constructor for animation objects.                            *
+ *   AnimClass::Attach_To -- Attaches animation to object specified.                           *
+ *   AnimClass::Center_Coord -- Determine center of animation.                                 *
+ *   AnimClass::Detach -- Remove animation if attached to target.                              *
+ *   AnimClass::Do_Atom_Damage -- Do atom bomb damage centered around the cell specified.      *
+ *   AnimClass::Draw_It -- Draws the animation at the location specified.                      *
+ *   AnimClass::In_Which_Layer -- Determines what render layer the anim should be in.          *
+ *   AnimClass::Init -- Performs pre-scenario initialization.                                  *
+ *   AnimClass::Mark -- Signals to map that redrawing is necessary.                            *
+ *   AnimClass::Middle -- Processes any middle events.                                         *
+ *   AnimClass::Occupy_List -- Determines the occupy list for the animation.                   *
+ *   AnimClass::Overlap_List -- Determines the overlap list for the animation.                 *
+ *   AnimClass::Render -- Draws an animation object.                                           *
+ *   AnimClass::Sort_Y -- Returns with the sorting coordinate for the animation.               *
+ *   AnimClass::Start -- Processes initial animation side effects.                             *
+ *   AnimClass::delete -- Returns an anim object back to the free pool.                        *
+ *   AnimClass::new -- Allocates an anim object from the pool.                                 *
+ *   AnimClass::~AnimClass -- Destructor for anim objects.                                     *
+ *   Anim_From_Name -- Given a name, this finds the corresponding anim type.                   *
+ *   Shorten_Attached_Anims -- Reduces attached animation durations.                           *
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+#include	"function.h"
+#define   VIC   1
+
+/***********************************************************************************************
+ * Anim_From_Name -- Given a name, this finds the corresponding anim type.                     *
+ *                                                                                             *
+ *    This routine will convert the supplied ASCII name into the animation type that it        *
+ *    represents.                                                                              *
+ *                                                                                             *
+ * INPUT:   name  -- Pointer to the ASCII name to convert.                                     *
+ *                                                                                             *
+ * OUTPUT:  Returns with the animation type that matches the name specified. If no match could *
+ *          be found, then ANIM_NONE is returned.                                              *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/06/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+AnimType Anim_From_Name(char const * name)
+{
+  #ifdef VIC
+	if (name == NULL) return(ANIM_NONE);
+
+	for (AnimType anim = ANIM_FIRST; anim < ANIM_COUNT; anim++) {
+		if (stricmp(AnimTypeClass::As_Reference(anim).IniName, name) == 0) {
+			return(anim);
+		}
+	}
+#endif
+	return(ANIM_NONE);
+}
+
+
+/***********************************************************************************************
+ * Shorten_Attached_Anims -- Reduces attached animation durations.                             *
+ *                                                                                             *
+ *    This routine is used to reduce the amount of time any attached animations will process.  *
+ *    Typical use of this is when an object is on fire and the object should now be destroyed  *
+ *    but the attached animations are to run until completion before destruction can follow.   *
+ *    This routine will make the animation appear to run its course, but in as short of time   *
+ *    as possible. The shortening effect is achieved by reducing the number of times the       *
+ *    animation will loop.                                                                     *
+ *                                                                                             *
+ * INPUT:   obj   -- Pointer to the object that all attached animations will be processed.     *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   12/11/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void Shorten_Attached_Anims(ObjectClass * obj)
+{
+	if (obj != NULL) {
+		for (int index = 0; index < Anims.Count(); index++) {
+			AnimClass & anim = * Anims.Ptr(index);
+
+			if (As_Object(anim.xObject) == obj) {
+				anim.Loops = 0;
+			}
+		}
+	}
+}
+
+
+/***********************************************************************************************
+ * AnimClass::Sort_Y -- Returns with the sorting coordinate for the animation.                 *
+ *                                                                                             *
+ *    This routine is used by the sorting system. Animations that are located in the ground    *
+ *    layer will be sorted by this the value returned from this function.                      *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the sort coordinate to use for this animation.                        *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   10/17/1994 JLB : Created.                                                                 *
+ *   12/15/1994 JLB : Handles flat anims (infantry decay anims).                               *
+ *=============================================================================================*/
+COORDINATE AnimClass::Sort_Y(void) const
+{
+#ifdef VIC
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+
+	if (xObject != TARGET_NONE) {
+		return(Coord_Add(As_Object(xObject)->Sort_Y(), 0x00010000L));
+	}
+	if (*this == ANIM_MOVE_FLASH) {
+		return(Coord_Add(Center_Coord(), XYP_COORD(0, -24)));
+	}
+	if (Class->IsGroundLayer || *this == ANIM_LZ_SMOKE) {
+		return(Coord_Add(Center_Coord(), XYP_COORD(0, 14)));
+	}
+#endif
+	return(Coord);
+}
+
+
+/***********************************************************************************************
+ * AnimClass::Center_Coord -- Determine center of animation.                                   *
+ *                                                                                             *
+ *    This support function will return the "center" of the animation. The actual coordinate   *
+ *    of the animation may be dependant on if the the animation is attached to an object.      *
+ *    In such a case, it must factor in the object's location.                                 *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns the coordinate of the center of the animation. The coordinate is in real   *
+ *          game coordinates -- taking into consideration if the animation is attached.        *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   09/19/1994 JLB : Created.                                                                 *
+ *   02/02/1996 JLB : Coordinate based on visual center of object.                             *
+ *=============================================================================================*/
+COORDINATE AnimClass::Center_Coord(void) const
+{
+#ifdef VIC
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+
+	if (xObject != TARGET_NONE) {
+		return(Coord_Add(Coord, As_Object(xObject)->Target_Coord()));
+	}
+#endif
+	return(Coord);
+}
+
+
+/***********************************************************************************************
+ * AnimClass::Render -- Draws an animation object.                                             *
+ *                                                                                             *
+ *    This is the working routine that renders the animation shape. It gets called once        *
+ *    per animation per frame. It needs to be fast.                                            *
+ *                                                                                             *
+ * INPUT:   bool; Should the animation be rendered in spite of render flag?                    *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the animation rendered?                                                  *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/31/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool AnimClass::Render(bool forced) const
+{
+#ifdef VIC
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+
+	if (Delay) return(false);
+	if (Map[Center_Coord()].IsVisible) {
+		IsToDisplay = true;
+	}
+#endif
+	return(ObjectClass::Render(forced));
+}
+
+
+/***********************************************************************************************
+ * AnimClass::Draw_It -- Draws the animation at the location specified.                        *
+ *                                                                                             *
+ *    This routine is used to render the animation object at the location specified. This is   *
+ *    how the map imagery gets updated.                                                        *
+ *                                                                                             *
+ * INPUT:   x,y      -- The pixel coordinates to draw the animation at.                        *
+ *                                                                                             *
+ *          window   -- The to base the draw coordinates upon.                                 *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   09/24/1994 JLB : Created.                                                                 *
+ *   05/19/1995 JLB : Added white translucent effect.                                          *
+ *=============================================================================================*/
+void AnimClass::Draw_It(int x, int y, WindowNumberType window) const
+{
+#ifdef VIC
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+
+	if (!IsInvisible) {
+		BStart(BENCH_ANIMS);
+
+		IsTheaterShape = Class->IsTheater;
+
+		void const * shapefile = Get_Image_Data();
+		if (shapefile != NULL) {
+			void const * transtable = NULL;
+			int shapenum = Class->Start + Fetch_Stage();
+			void const * remap = NULL;
+
+			/*
+			**	If the translucent table hasn't been determined yet, then check to see if it
+			**	should use the white or normal translucent tables.
+			*/
+			if (transtable == NULL && Class->IsWhiteTrans) transtable = DisplayClass::WhiteTranslucentTable;
+			if (transtable == NULL && Class->IsTranslucent) transtable = DisplayClass::TranslucentTable;
+			if (Class->Type == ANIM_ATOM_BLAST) transtable = Map.UnitShadow;
+
+			/*
+			**	Set the shape flags to properly take into account any fading or ghosting
+			**	table necessary.
+			*/
+			ShapeFlags_Type flags = SHAPE_CENTER|SHAPE_WIN_REL;
+			if (transtable != NULL) flags = flags | SHAPE_GHOST;
+
+			/*
+			**	Draw the animation shape.
+			*/
+			CC_Draw_Shape(shapefile, shapenum, x, y, window, flags, remap, transtable);
+		}
+		IsTheaterShape = false;
+		BEnd(BENCH_ANIMS);
+	}
+#endif
+}
+
+
+/***********************************************************************************************
+ * AnimClass::Mark -- Signals to map that redrawing is necessary.                              *
+ *                                                                                             *
+ *    This routine is used by the animation logic system to inform the map that the cells      *
+ *    under the animation must be rerendered.                                                  *
+ *                                                                                             *
+ * INPUT:                                                                                      *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/31/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool AnimClass::Mark(MarkType mark)
+{
+#ifdef VIC
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+
+	if (ObjectClass::Mark(mark)) {
+		Map.Refresh_Cells(Coord_Cell(Center_Coord()), Overlap_List());
+//		ObjectClass::Mark(mark);
+		return(true);
+	}
+#endif
+	return(false);
+}
+
+
+/***********************************************************************************************
+ * AnimClass::Overlap_List -- Determines the overlap list for the animation.                   *
+ *                                                                                             *
+ *    Use this routine to fetch the overlap list for the animation. This overlap list is the   *
+ *    cells that this animation spills over.                                                   *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns a pointer to the overlap list for this particular instance of the          *
+ *          animation.                                                                         *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   03/19/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+short const * AnimClass::Overlap_List(void) const
+{
+#ifdef VIC
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+	static short const OverlapAtom[] = {
+		(-MAP_CELL_W * 2) - 1, (-MAP_CELL_W * 2), (-MAP_CELL_W * 2) + 1,
+		(-MAP_CELL_W * 1) - 1, (-MAP_CELL_W * 1), (-MAP_CELL_W * 1) + 1,
+		(-MAP_CELL_W * 0) - 1, (-MAP_CELL_W * 0), (-MAP_CELL_W * 0) + 1,
+		( MAP_CELL_W * 1) - 1, ( MAP_CELL_W * 1), ( MAP_CELL_W * 1) + 1,
+		( MAP_CELL_W * 2) - 1, ( MAP_CELL_W * 2), ( MAP_CELL_W * 2) + 1,
+ 		REFRESH_EOL
+	};
+
+	if (IsToDelete) {
+		static short const _list[] = {REFRESH_EOL};
+		return(_list);
+	}
+
+	if (Class->Type == ANIM_ATOM_BLAST) {
+		return(OverlapAtom);
+	}
+
+#ifdef PARTIAL
+IsTheaterShape = Class->IsTheater;
+	if (Class->Get_Image_Data() != NULL) {
+		int shapenum = Class->Start + Fetch_Stage();
+		int count = Get_Build_Frame_Count(Class->Get_Image_Data());
+		shapenum = min(shapenum, count-1);
+
+		if (Class->DimensionData == NULL) {
+			Class->DimensionData = new Rect [count];
+		}
+		if (Class->DimensionData != NULL && !Class->DimensionData[shapenum].Is_Valid()) {
+			Class->DimensionData[shapenum] = Shape_Dimensions(Class->Get_Image_Data(), shapenum);
+IsTheaterShape = false;
+			return(Coord_Spillage_List(Center_Coord(), Class->DimensionData[shapenum]));
+		}
+	}
+IsTheaterShape = false;
+#endif
+#endif
+	return(Coord_Spillage_List(Center_Coord(), Class->Size));
+}
+
+
+/***********************************************************************************************
+ * AnimClass::Occupy_List -- Determines the occupy list for the animation.                     *
+ *                                                                                             *
+ *    Animations always occupy only the cell that their center is located over. As such, this  *
+ *    routine always returns a simple (center cell) occupation list.                           *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the occupation list for the animation.                                *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   03/19/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+short const * AnimClass::Occupy_List(bool) const
+{
+#ifdef VIC
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+
+	static short _simple[] = {REFRESH_EOL};
+
+#endif
+	return(_simple);
+}
+
+
+/***********************************************************************************************
+ * AnimClass::Init -- Performs pre-scenario initialization.                                    *
+ *                                                                                             *
+ *    This routine is used to initialize the animation system prior to a scenario being loaded *
+ *    or reloaded. It effectively removes all animations from the system.                      *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/31/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AnimClass::Init(void)
+{
+	Anims.Free_All();
+}
+
+
+/***********************************************************************************************
+ * AnimClass::new -- Allocates an anim object from the pool.                                   *
+ *                                                                                             *
+ *    This routine is used to allocate a free anim class object from the preallocated pool     *
+ *    in the near heap. If there are no free animation objects, then null is returned.         *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with a pointer to a free anim object.                                      *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/31/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void * AnimClass::operator new(size_t)
+{
+	void * ptr = Anims.Allocate();
+	if (ptr != NULL) {
+		((AnimClass *)ptr)->IsActive = true;
+	}
+	return(ptr);
+}
+
+
+/***********************************************************************************************
+ * AnimClass::delete -- Returns an anim object back to the free pool.                          *
+ *                                                                                             *
+ *    This routine is used to return an anim object back to the pool of free anim objects.     *
+ *    Anim objects so returned are available to be reallocated for the next animation.         *
+ *                                                                                             *
+ * INPUT:   ptr   -- Pointer to the anim object to return to the pool.                         *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/31/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AnimClass::operator delete(void * ptr)
+{
+	if (ptr != NULL) {
+		((AnimClass *)ptr)->IsActive = false;
+	}
+	Anims.Free((AnimClass *)ptr);
+}
+
+
+/***********************************************************************************************
+ * AnimClass::AnimClass -- The constructor for animation objects.                              *
+ *                                                                                             *
+ *    This routine is used as the constructor of animation objects. It initializes and adds    *
+ *    the animation object to the display and logic systems.                                   *
+ *                                                                                             *
+ * INPUT:   animnum  -- The animation number to start.                                         *
+ *                                                                                             *
+ *          coord    -- The location of the animation.                                         *
+ *                                                                                             *
+ *          timedelay-- The delay before the animation starts.                                 *
+ *                                                                                             *
+ *          loop     -- The number of times to loop this animation.                            *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/31/1994 JLB : Created.                                                                 *
+ *   08/03/1994 JLB : Added a delayed affect parameter.                                        *
+ *=============================================================================================*/
+AnimClass::AnimClass(AnimType animnum, COORDINATE coord, unsigned char timedelay, unsigned char loop) :
+	ObjectClass(RTTI_ANIM, Anims.ID(this)),
+	Class(AnimTypes.Ptr((int)animnum)),
+	xObject(TARGET_NONE),
+	OwnerHouse(HOUSE_NONE),
+	Loops(1),
+	IsToDelete(false),
+	IsBrandNew(true),
+	IsInvisible(false),
+	Delay(timedelay),
+	Accum(0)
+{
+#ifdef VIC
+	if (Class->Stages == -1) {
+IsTheaterShape = Class->IsTheater;
+		((int&)Class->Stages) = Get_Build_Frame_Count(Class->Get_Image_Data());
+IsTheaterShape = false;
+
+	}
+	if (Class->LoopEnd == -1) {
+		((int&)Class->LoopEnd) = Class->Stages;
+	}
+	if (Class->IsNormalized) {
+		Set_Rate(Options.Normalize_Delay(Class->Delay));
+	} else {
+		Set_Rate(Class->Delay);
+	}
+	Set_Stage(0);
+
+	if (Class->IsGroundLayer) {
+		Height = FLIGHT_LEVEL;
+	}
+
+	AnimClass::Unlimbo(coord);
+
+	/*
+	**	Drop zone smoke always reveals the map around itself.
+	*/
+	if (*this == ANIM_LZ_SMOKE) {
+		Map.Sight_From(Coord_Cell(coord), Rule.DropZoneRadius / CELL_LEPTON_W, PlayerPtr, false);
+	}
+
+	Loops = (unsigned char)(max(loop, 1) * Class->Loops);
+	Loops = (unsigned char)max(Loops, 1);
+
+	/*
+	**	If the animation starts immediately, then play the associated sound effect now.
+	*/
+	if (!Delay) {
+		Start();
+	}
+#endif
+}
+
+
+/***********************************************************************************************
+ * AnimClass::~AnimClass -- Destructor for anim objects.                                       *
+ *                                                                                             *
+ *    This destructor handles removing the animation object from the system. It might require  *
+ *    informing any object this animation is attached to that it is no longer attached.        *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   11/29/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+AnimClass::~AnimClass(void)
+{
+#ifdef VIC
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+	if (GameActive) {
+
+		/*
+		**	If this anim is attached to another object
+		**	then check to see if this is the last anim attached to it. If this
+		**	is the case, then inform the object that it is no longer attached to
+		**	an animation.
+		*/
+		if (Target_Legal(xObject) && As_Object(xObject) != NULL) {
+			ObjectClass * to = As_Object(xObject);
+
+			/*
+			**	Remove the object from the appropriate display list.
+			*/
+			Map.Remove(this, In_Which_Layer());
+
+			/*
+			**	Scan for any other animations that are attached to the object that
+			**	this animation is attached to. If there are no others, then inform the
+			**	attached object of this fact.
+			*/
+			for (int index = 0; index < Anims.Count(); index++) {
+				if (Anims.Ptr(index) != this && Anims.Ptr(index)->xObject == xObject) break;
+			}
+
+			/*
+			**	Tell the object that it is no longer being damaged.
+			*/
+			if (index == Anims.Count()) {
+				to->Fire_Out();
+				to->Mark(MARK_OVERLAP_UP);
+				to->IsAnimAttached = false;
+				to->Mark(MARK_OVERLAP_DOWN);
+			}
+			Coord = Coord_Add(to->Center_Coord(), Coord);
+			xObject = TARGET_NONE;
+		}
+
+		Limbo();
+	}
+
+	xObject = TARGET_NONE;
+	Class = 0;
+	ID = -1;
+
+#endif
+}
+
+
+/***********************************************************************************************
+ * AnimClass::AI -- This is the low level anim processor.                                      *
+ *                                                                                             *
+ *    This routine is called once per frame per animation. It handles transition between       *
+ *    animation frames and marks the map for redraw as necessary.                              *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   Speed is of upmost importance.                                                  *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/31/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AnimClass::AI(void)
+{
+#ifdef VIC
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+
+	/*
+	**	For ground level based animations (ones that can run slowly as well as
+	**	occur behind other ground objects) always cause the cell to be redrawn.
+	*/
+#ifdef PARTIAL
+	if (!Delay && Class->IsGroundLayer) {
+		Map.Refresh_Cells(Coord_Cell(Center_Coord()), Overlap_List());
+	}
+#else
+	Map.Refresh_Cells(Coord_Cell(Center_Coord()), Overlap_List());
+#endif
+
+	/*
+	**	Special case check to make sure that building on top of a smoke marker
+	**	causes the smoke marker to vanish.
+	*/
+	if (Class->Type == ANIM_LZ_SMOKE && Map[Center_Coord()].Cell_Building()) {
+		IsToDelete = true;
+	}
+
+	/*
+	**	Delete this animation and bail early if the animation is flagged to be deleted
+	**	immediately.
+	*/
+	if (IsToDelete) {
+		delete this;
+		return;
+	}
+
+	/*
+	**	If this is a brand new animation, then don't process it the first logic pass
+	**	since it might end up skipping the first animation frame before it has had a
+	**	chance to draw it.
+	*/
+	if (IsBrandNew) {
+		IsBrandNew = false;
+		return;
+	}
+
+#ifdef FIXIT_MULTI_SAVE
+	if (Class->Stages == -1) {
+		IsTheaterShape = Class->IsTheater;
+		((int&)Class->Stages) = Get_Build_Frame_Count(Class->Get_Image_Data());
+		IsTheaterShape = false;
+	}
+	if (Class->LoopEnd == -1) {
+		((int&)Class->LoopEnd) = Class->Stages;
+	}
+#endif
+
+	if (Delay) {
+		Delay--;
+		if (!Delay) {
+			Start();
+		}
+	} else {
+
+#ifdef FIXIT_MULTI_SAVE
+		if (Class->Stages == -1) {
+			IsTheaterShape = Class->IsTheater;
+			((int&)Class->Stages) = Get_Build_Frame_Count(Class->Get_Image_Data());
+			IsTheaterShape = false;
+		}
+		if (Class->LoopEnd == -1) {
+			((int&)Class->LoopEnd) = Class->Stages;
+		}
+#endif
+
+		/*
+		**	This is necessary because there is no recording of animations on the map
+		**	and thus the animation cannot be intelligently flagged for redraw. Most
+		**	animations move fast enough that they would need to be redrawn every
+		**	game frame anyway so this isn't TOO bad.
+		*/
+		Mark(MARK_CHANGE);
+
+		if (StageClass::Graphic_Logic()) {
+			int stage = Fetch_Stage();
+
+			/*
+			**	If this animation is attached to another object and it is a
+			**	damaging kind of animation, then do the damage to the other
+			**	object.
+			*/
+			if (xObject != TARGET_NONE && Class->Damage > 0) {
+				Accum += Class->Damage;
+
+				if (Accum >= 1) {
+
+					/*
+					**	Administer the damage. If the object was destroyed by this anim,
+					**	then the attached damaging anim is also destroyed.
+					*/
+					int damage = Accum;
+					Accum -= damage;
+					if (As_Object(xObject)->Take_Damage(damage, 0, WARHEAD_FIRE) == RESULT_DESTROYED) {
+						delete this;
+						return;
+					}
+				}
+			}
+
+			/*
+			**	During the biggest stage (covers the most ground), perform any ground altering
+			**	action required. This masks craters and scorch marks, so that they appear
+			**	naturally rather than "popping" into existence while in plain sight.
+			*/
+			if (Class->Biggest && Class->Start+stage == Class->Biggest) {
+				Middle();
+			}
+
+			/*
+			**	Check to see if the last frame has been displayed. If so, then the
+			**	animation either ends or loops.
+			*/
+			if ((Loops <= 1 && stage >= Class->Stages) || (Loops > 1 && stage >= Class->LoopEnd-Class->Start)) {
+
+				/*
+				**	Determine if this animation should loop another time. If so, then start the loop
+				**	but if not, then proceed into the animation termination handler.
+				*/
+				if (Loops) Loops--;
+				if (Loops) {
+					Set_Stage(Class->LoopStart);
+				} else {
+
+					/*
+					**	The animation should end now, but first check to see if
+					**	it needs to chain into another animation. If so, then the
+					**	animation isn't technically over. It metamorphoses into the
+					**	new form.
+					*/
+					if (Class->ChainTo != ANIM_NONE) {
+
+						Class = (AnimTypeClass *)&AnimTypeClass::As_Reference(Class->ChainTo);
+
+						if (Class->Stages == -1) {
+IsTheaterShape = Class->IsTheater;
+							((int&)Class->Stages) = Get_Build_Frame_Count(Class->Get_Image_Data());
+IsTheaterShape = false;
+						}
+						if (Class->LoopEnd == -1) {
+							((int&)Class->LoopEnd) = Class->Stages;
+						}
+
+						IsToDelete = false;
+						Loops = Class->Loops;
+						Accum = 0;
+						if (Class->IsNormalized) {
+							Set_Rate(Options.Normalize_Delay(Class->Delay));
+						} else {
+							Set_Rate(Class->Delay);
+						}
+						Set_Stage(Class->Start);
+						Start();
+					} else {
+						delete this;
+					}
+				}
+			}
+		}
+	}
+#endif
+}
+
+
+/***********************************************************************************************
+ * AnimClass::Attach_To -- Attaches animation to object specified.                             *
+ *                                                                                             *
+ *    An animation can be "attached" to an object. In such cases, the animation is rendered    *
+ *    as an offset from the center of the object it is attached to. This allows affects such   *
+ *    as fire or smoke to be consistently placed on the vehicle it is associated with.         *
+ *                                                                                             *
+ * INPUT:   obj   -- Pointer to the object to attach the animation to.                         *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   09/19/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AnimClass::Attach_To(ObjectClass * obj)
+{
+#ifdef VIC
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+
+	if (obj == NULL) return;
+	assert(obj->IsActive);
+
+	obj->Mark(MARK_OVERLAP_UP);
+	obj->IsAnimAttached = true;
+	obj->Mark(MARK_OVERLAP_DOWN);
+	Map.Remove(this, In_Which_Layer());
+	xObject = obj->As_Target();
+	Map.Submit(this, In_Which_Layer());
+	Coord = Coord_Sub(Coord, obj->Target_Coord());
+#endif
+}
+
+
+/***********************************************************************************************
+ * AnimClass::In_Which_Layer -- Determines what render layer the anim should be in.            *
+ *                                                                                             *
+ *    Use this routine to find out which display layer (ground or air) that the animation      *
+ *    should be in. This information is used to place the animation into the correct display   *
+ *    list.                                                                                    *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the layer that the animation should exist in.                         *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   12/25/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+LayerType AnimClass::In_Which_Layer(void) const
+{
+#ifdef VIC
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+
+	if (Class->Type >= ANIM_CORPSE1 && Class->Type <= ANIM_CORPSE3) {
+		return(LAYER_SURFACE);
+	}
+
+	if (Target_Legal(xObject) || Class->IsGroundLayer) {
+		return(LAYER_GROUND);
+	}
+#endif
+	return(LAYER_AIR);
+}
+
+
+/***********************************************************************************************
+ * AnimClass::Start -- Processes initial animation side effects.                               *
+ *                                                                                             *
+ *    This routine is called when the animation first starts. Sometimes there are side effects *
+ *    associated with this animation that must occur immediately. Typically, this is the       *
+ *    sound effect assigned to this animation. If this animation is supposed to attach itself  *
+ *    to any object at its location, then do so at this time as well.                          *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/30/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AnimClass::Start(void)
+{
+#ifdef VIC
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+
+	Mark();
+
+	/*
+	**	Play the sound effect for this animation.
+	*/
+	Sound_Effect(Class->Sound, Coord);
+
+	/*
+	**	If the stage where collateral effects occur is the first stage of the animation, then
+	**	perform this action now. Subsequent checks against this stage value starts with the
+	**	second frame of the animation.
+	*/
+	if (!Class->Biggest) {
+		Middle();
+	}
+#endif
+}
+
+
+/***********************************************************************************************
+ * AnimClass::Middle -- Processes any middle events.                                           *
+ *                                                                                             *
+ *    This routine is called when the animation as reached its largest stage. Typically, this  *
+ *    routine is used to cause scorches or craters to appear at a cosmetically pleasing        *
+ *    moment.                                                                                  *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/30/1995 JLB : Created.                                                                 *
+ *   10/17/1995 JLB : Ion camera added.                                                        *
+ *=============================================================================================*/
+void AnimClass::Middle(void)
+{
+#ifdef VIC
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+
+	CELL cell = Coord_Cell(Center_Coord());
+	CellClass * cellptr = &Map[cell];
+
+	if (Class->Type == ANIM_ATOM_BLAST) {
+		Do_Atom_Damage(OwnerHouse, cell);
+	}
+
+	/*
+	**	If this animation leaves scorch marks (e.g., napalm), then do so at this time.
+	*/
+	if (Class->IsScorcher) {
+		new SmudgeClass(Random_Pick(SMUDGE_SCORCH1, SMUDGE_SCORCH6), Center_Coord());
+	}
+
+	/*
+	**	Some animations leave a crater when they occur. Artillery is a good example.
+	**	Craters always remove the Tiberium where they occur.
+	*/
+	if (Class->IsCraterForming) {
+
+		/*
+		**	Craters reduce the level of Tiberium in the cell.
+		*/
+		cellptr->Reduce_Tiberium(6);
+
+		/*
+		**	If there already is a crater in the cell, then just expand the
+		**	crater.
+		*/
+		new SmudgeClass(SMUDGE_CRATER1, Center_Coord());
+	}
+
+	AnimClass * newanim;
+
+	/*
+	**	If this animation spawns side effects during its lifetime, then
+	**	do so now. Usually, these side effects are in the form of other
+	**	animations.
+	*/
+	switch (Class->Type) {
+		case ANIM_NAPALM1:
+		case ANIM_NAPALM2:
+		case ANIM_NAPALM3:
+			new AnimClass(ANIM_FIRE_SMALL, Map.Closest_Free_Spot(Coord_Scatter(Center_Coord(), 0x0040), true), 0, Random_Pick(1, 2));
+			if (Percent_Chance(50)) {
+				new AnimClass(ANIM_FIRE_SMALL, Map.Closest_Free_Spot(Coord_Scatter(Center_Coord(), 0x00A0), true), 0, Random_Pick(1, 2));
+			}
+			if (Percent_Chance(50)) {
+				new AnimClass(ANIM_FIRE_MED, Map.Closest_Free_Spot(Coord_Scatter(Center_Coord(), 0x0070), true), 0, Random_Pick(1, 2));
+			}
+			break;
+
+		case ANIM_FIRE_MED:
+		case ANIM_FIRE_MED2:
+			newanim = new AnimClass(ANIM_FIRE_SMALL, Center_Coord(), 0, Random_Pick(1, 2));
+			if (newanim != NULL && xObject != TARGET_NONE) {
+				newanim->Attach_To(As_Object(xObject));
+			}
+			break;
+
+		default:
+			break;
+	}
+#endif
+}
+
+
+/***********************************************************************************************
+ * AnimClass::Detach -- Remove animation if attached to target.                                *
+ *                                                                                             *
+ *    This routine is called when the specified target is being removed from the game. If this *
+ *    animation happens to be attached to this object, then the animation must be remove as    *
+ *    well.                                                                                    *
+ *                                                                                             *
+ * INPUT:   target   -- The target that is about to be destroyed.                              *
+ *                                                                                             *
+ *          all      -- Is the target being destroyed RIGHT NOW? If not, then it will be       *
+ *                      destroyed soon. In that case, the animation should continue to remain  *
+ *                      attached for cosmetic reasons.                                         *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/30/1995 JLB : Created.                                                                 *
+ *   07/02/1995 JLB : Detach is a precursor to animation destruction.                          *
+ *=============================================================================================*/
+void AnimClass::Detach(TARGET target, bool all)
+{
+#ifdef VIC
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+
+	if (xObject == target && all) {
+		Map.Remove(this, In_Which_Layer());
+		xObject = TARGET_NONE;
+		IsToDelete = true;
+		Mark(MARK_UP);
+	}
+#endif
+}
+
+
+/***********************************************************************************************
+ * AnimClass::Do_Atom_Damage -- Do atom bomb damage centered around the cell specified.        *
+ *                                                                                             *
+ *    This routine will apply damage around the ground-zero cell specified.                    *
+ *                                                                                             *
+ * INPUT:   ownerhouse  -- The owner of this atom bomb.                                        *
+ *                                                                                             *
+ *          cell        -- The ground zero location to apply the atom bomb damage.             *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/06/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AnimClass::Do_Atom_Damage(HousesType ownerhouse, CELL cell)
+{
+#ifdef VIC
+	/*
+	**	Find someone to blame the explosion on. This is necessary in
+	**	order to properly enact retribution and record the kill for
+	**	score purposes.
+	*/
+	BuildingClass * building = NULL;
+	TechnoClass * backup = NULL;
+	if (ownerhouse != HOUSE_NONE) {
+		for (int index = 0; index < Logic.Count(); index++) {
+			ObjectClass * obj = Logic[index];
+
+			if (obj != NULL && obj->Is_Techno() && obj->Owner() == ownerhouse) {
+				backup = (TechnoClass *)obj;
+				if (obj->What_Am_I() == RTTI_BUILDING && *((BuildingClass *)obj) == STRUCT_MSLO) {
+					building = (BuildingClass *)obj;
+					break;
+				}
+			}
+		}
+
+		if (building == NULL) building = (BuildingClass *)backup;
+	}
+
+	int radius;
+	int rawdamage;
+	if (Session.Type == GAME_NORMAL) {
+		radius = 4;
+		rawdamage = Rule.AtomDamage;
+		WhitePalette.Set(FADE_PALETTE_SLOW, Call_Back);
+	} else {
+		radius = 3;
+		rawdamage = Rule.AtomDamage/5;
+	}
+
+	Wide_Area_Damage(Cell_Coord(cell), radius * CELL_LEPTON_W, rawdamage, building, WARHEAD_FIRE);
+	Shake_The_Screen(3);
+	if (Session.Type == GAME_NORMAL) {
+		GamePalette.Set(FADE_PALETTE_SLOW, Call_Back);
+	}
+#endif
+}
+
+

+ 1062 - 0
CODE/ANIM.CPP.BAK

@@ -0,0 +1,1062 @@
+/*
+**	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\anim.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 : Dune                                                         *
+ *                                                                                             *
+ *                    File Name : ANIM.CPP                                                     *
+ *                                                                                             *
+ *                   Programmer : Joe L. Bostic                                                *
+ *                                                                                             *
+ *                   Start Date : June 3, 1991                                                 *
+ *                                                                                             *
+ *---------------------------------------------------------------------------------------------*
+ * Functions:                                                                                  *
+ *   AnimClass::AI -- This is the low level anim processor.                                    *
+ *   AnimClass::AnimClass -- The constructor for animation objects.                            *
+ *   AnimClass::Attach_To -- Attaches animation to object specified.                           *
+ *   AnimClass::Center_Coord -- Determine center of animation.                                 *
+ *   AnimClass::Detach -- Remove animation if attached to target.                              *
+ *   AnimClass::Do_Atom_Damage -- Do atom bomb damage centered around the cell specified.      *
+ *   AnimClass::Draw_It -- Draws the animation at the location specified.                      *
+ *   AnimClass::In_Which_Layer -- Determines what render layer the anim should be in.          *
+ *   AnimClass::Init -- Performs pre-scenario initialization.                                  *
+ *   AnimClass::Mark -- Signals to map that redrawing is necessary.                            *
+ *   AnimClass::Middle -- Processes any middle events.                                         *
+ *   AnimClass::Occupy_List -- Determines the occupy list for the animation.                   *
+ *   AnimClass::Overlap_List -- Determines the overlap list for the animation.                 *
+ *   AnimClass::Render -- Draws an animation object.                                           *
+ *   AnimClass::Sort_Y -- Returns with the sorting coordinate for the animation.               *
+ *   AnimClass::Start -- Processes initial animation side effects.                             *
+ *   AnimClass::delete -- Returns an anim object back to the free pool.                        *
+ *   AnimClass::new -- Allocates an anim object from the pool.                                 *
+ *   AnimClass::~AnimClass -- Destructor for anim objects.                                     *
+ *   Anim_From_Name -- Given a name, this finds the corresponding anim type.                   *
+ *   Shorten_Attached_Anims -- Reduces attached animation durations.                           *
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+#include	"function.h"
+
+
+/***********************************************************************************************
+ * Anim_From_Name -- Given a name, this finds the corresponding anim type.                     *
+ *                                                                                             *
+ *    This routine will convert the supplied ASCII name into the animation type that it        *
+ *    represents.                                                                              *
+ *                                                                                             *
+ * INPUT:   name  -- Pointer to the ASCII name to convert.                                     *
+ *                                                                                             *
+ * OUTPUT:  Returns with the animation type that matches the name specified. If no match could *
+ *          be found, then ANIM_NONE is returned.                                              *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/06/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+AnimType Anim_From_Name(char const * name)
+{
+  #ifdef 0
+	if (name == NULL) return(ANIM_NONE);
+
+	for (AnimType anim = ANIM_FIRST; anim < ANIM_COUNT; anim++) {
+		if (stricmp(AnimTypeClass::As_Reference(anim).IniName, name) == 0) {
+			return(anim);
+		}
+	}
+#endif
+	return(ANIM_NONE);
+}
+
+
+/***********************************************************************************************
+ * Shorten_Attached_Anims -- Reduces attached animation durations.                             *
+ *                                                                                             *
+ *    This routine is used to reduce the amount of time any attached animations will process.  *
+ *    Typical use of this is when an object is on fire and the object should now be destroyed  *
+ *    but the attached animations are to run until completion before destruction can follow.   *
+ *    This routine will make the animation appear to run its course, but in as short of time   *
+ *    as possible. The shortening effect is achieved by reducing the number of times the       *
+ *    animation will loop.                                                                     *
+ *                                                                                             *
+ * INPUT:   obj   -- Pointer to the object that all attached animations will be processed.     *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   12/11/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void Shorten_Attached_Anims(ObjectClass * obj)
+{
+	if (obj != NULL) {
+		for (int index = 0; index < Anims.Count(); index++) {
+			AnimClass & anim = * Anims.Ptr(index);
+
+			if (As_Object(anim.xObject) == obj) {
+				anim.Loops = 0;
+			}
+		}
+	}
+}
+
+
+/***********************************************************************************************
+ * AnimClass::Sort_Y -- Returns with the sorting coordinate for the animation.                 *
+ *                                                                                             *
+ *    This routine is used by the sorting system. Animations that are located in the ground    *
+ *    layer will be sorted by this the value returned from this function.                      *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the sort coordinate to use for this animation.                        *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   10/17/1994 JLB : Created.                                                                 *
+ *   12/15/1994 JLB : Handles flat anims (infantry decay anims).                               *
+ *=============================================================================================*/
+COORDINATE AnimClass::Sort_Y(void) const
+{
+#ifdef 0
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+
+	if (xObject != TARGET_NONE) {
+		return(Coord_Add(As_Object(xObject)->Sort_Y(), 0x00010000L));
+	}
+	if (*this == ANIM_MOVE_FLASH) {
+		return(Coord_Add(Center_Coord(), XYP_COORD(0, -24)));
+	}
+	if (Class->IsGroundLayer || *this == ANIM_LZ_SMOKE) {
+		return(Coord_Add(Center_Coord(), XYP_COORD(0, 14)));
+	}
+#endif
+	return(Coord);
+}
+
+
+/***********************************************************************************************
+ * AnimClass::Center_Coord -- Determine center of animation.                                   *
+ *                                                                                             *
+ *    This support function will return the "center" of the animation. The actual coordinate   *
+ *    of the animation may be dependant on if the the animation is attached to an object.      *
+ *    In such a case, it must factor in the object's location.                                 *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns the coordinate of the center of the animation. The coordinate is in real   *
+ *          game coordinates -- taking into consideration if the animation is attached.        *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   09/19/1994 JLB : Created.                                                                 *
+ *   02/02/1996 JLB : Coordinate based on visual center of object.                             *
+ *=============================================================================================*/
+COORDINATE AnimClass::Center_Coord(void) const
+{
+#ifdef 0
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+
+	if (xObject != TARGET_NONE) {
+		return(Coord_Add(Coord, As_Object(xObject)->Target_Coord()));
+	}
+#endif
+	return(Coord);
+}
+
+
+/***********************************************************************************************
+ * AnimClass::Render -- Draws an animation object.                                             *
+ *                                                                                             *
+ *    This is the working routine that renders the animation shape. It gets called once        *
+ *    per animation per frame. It needs to be fast.                                            *
+ *                                                                                             *
+ * INPUT:   bool; Should the animation be rendered in spite of render flag?                    *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the animation rendered?                                                  *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/31/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool AnimClass::Render(bool forced) const
+{
+#ifdef 0
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+
+	if (Delay) return(false);
+	if (Map[Center_Coord()].IsVisible) {
+		IsToDisplay = true;
+	}
+#endif
+	return(ObjectClass::Render(forced));
+}
+
+
+/***********************************************************************************************
+ * AnimClass::Draw_It -- Draws the animation at the location specified.                        *
+ *                                                                                             *
+ *    This routine is used to render the animation object at the location specified. This is   *
+ *    how the map imagery gets updated.                                                        *
+ *                                                                                             *
+ * INPUT:   x,y      -- The pixel coordinates to draw the animation at.                        *
+ *                                                                                             *
+ *          window   -- The to base the draw coordinates upon.                                 *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   09/24/1994 JLB : Created.                                                                 *
+ *   05/19/1995 JLB : Added white translucent effect.                                          *
+ *=============================================================================================*/
+void AnimClass::Draw_It(int x, int y, WindowNumberType window) const
+{
+#ifdef 0
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+
+	if (!IsInvisible) {
+		BStart(BENCH_ANIMS);
+
+		void const * shapefile = Get_Image_Data();
+		if (shapefile != NULL) {
+			void const * transtable = NULL;
+			int shapenum = Class->Start + Fetch_Stage();
+			void const * remap = NULL;
+
+			/*
+			**	If the translucent table hasn't been determined yet, then check to see if it
+			**	should use the white or normal translucent tables.
+			*/
+			if (transtable == NULL && Class->IsWhiteTrans) transtable = DisplayClass::WhiteTranslucentTable;
+			if (transtable == NULL && Class->IsTranslucent) transtable = DisplayClass::TranslucentTable;
+			if (Class->Type == ANIM_ATOM_BLAST) transtable = Map.UnitShadow;
+
+			/*
+			**	Set the shape flags to properly take into account any fading or ghosting
+			**	table necessary.
+			*/
+			ShapeFlags_Type flags = SHAPE_CENTER|SHAPE_WIN_REL;
+			if (transtable != NULL) flags = flags | SHAPE_GHOST;
+
+			/*
+			**	Draw the animation shape.
+			*/
+			CC_Draw_Shape(shapefile, shapenum, x, y, window, flags, remap, transtable);
+		}
+		BEnd(BENCH_ANIMS);
+	}
+#endif
+}
+
+
+/***********************************************************************************************
+ * AnimClass::Mark -- Signals to map that redrawing is necessary.                              *
+ *                                                                                             *
+ *    This routine is used by the animation logic system to inform the map that the cells      *
+ *    under the animation must be rerendered.                                                  *
+ *                                                                                             *
+ * INPUT:                                                                                      *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/31/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool AnimClass::Mark(MarkType mark)
+{
+#ifdef 0
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+
+	if (ObjectClass::Mark(mark)) {
+		Map.Refresh_Cells(Coord_Cell(Center_Coord()), Overlap_List());
+//		ObjectClass::Mark(mark);
+		return(true);
+	}
+#endif
+	return(false);
+}
+
+
+/***********************************************************************************************
+ * AnimClass::Overlap_List -- Determines the overlap list for the animation.                   *
+ *                                                                                             *
+ *    Use this routine to fetch the overlap list for the animation. This overlap list is the   *
+ *    cells that this animation spills over.                                                   *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns a pointer to the overlap list for this particular instance of the          *
+ *          animation.                                                                         *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   03/19/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+short const * AnimClass::Overlap_List(void) const
+{
+#ifdef 0
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+	static short const OverlapAtom[] = {
+		(-MAP_CELL_W * 2) - 1, (-MAP_CELL_W * 2), (-MAP_CELL_W * 2) + 1,
+		(-MAP_CELL_W * 1) - 1, (-MAP_CELL_W * 1), (-MAP_CELL_W * 1) + 1,
+		(-MAP_CELL_W * 0) - 1, (-MAP_CELL_W * 0), (-MAP_CELL_W * 0) + 1,
+		( MAP_CELL_W * 1) - 1, ( MAP_CELL_W * 1), ( MAP_CELL_W * 1) + 1,
+		( MAP_CELL_W * 2) - 1, ( MAP_CELL_W * 2), ( MAP_CELL_W * 2) + 1,
+ 		REFRESH_EOL
+	};
+
+	if (IsToDelete) {
+		static short const _list[] = {REFRESH_EOL};
+		return(_list);
+	}
+
+	if (Class->Type == ANIM_ATOM_BLAST) {
+		return(OverlapAtom);
+	}
+
+#ifdef PARTIAL
+	if (Class->Get_Image_Data() != NULL) {
+		int shapenum = Class->Start + Fetch_Stage();
+		int count = Get_Build_Frame_Count(Class->Get_Image_Data());
+		shapenum = min(shapenum, count-1);
+
+		if (Class->DimensionData == NULL) {
+			Class->DimensionData = new Rect [count];
+		}
+		if (Class->DimensionData != NULL && !Class->DimensionData[shapenum].Is_Valid()) {
+			Class->DimensionData[shapenum] = Shape_Dimensions(Class->Get_Image_Data(), shapenum);
+			return(Coord_Spillage_List(Center_Coord(), Class->DimensionData[shapenum]));
+		}
+	}
+#endif
+#endif
+	return(Coord_Spillage_List(Center_Coord(), Class->Size));
+}
+
+
+/***********************************************************************************************
+ * AnimClass::Occupy_List -- Determines the occupy list for the animation.                     *
+ *                                                                                             *
+ *    Animations always occupy only the cell that their center is located over. As such, this  *
+ *    routine always returns a simple (center cell) occupation list.                           *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the occupation list for the animation.                                *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   03/19/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+short const * AnimClass::Occupy_List(bool) const
+{
+#ifdef 0
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+
+	static short _simple[] = {REFRESH_EOL};
+
+#endif
+	return(_simple);
+}
+
+
+/***********************************************************************************************
+ * AnimClass::Init -- Performs pre-scenario initialization.                                    *
+ *                                                                                             *
+ *    This routine is used to initialize the animation system prior to a scenario being loaded *
+ *    or reloaded. It effectively removes all animations from the system.                      *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/31/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AnimClass::Init(void)
+{
+	Anims.Free_All();
+}
+
+
+/***********************************************************************************************
+ * AnimClass::new -- Allocates an anim object from the pool.                                   *
+ *                                                                                             *
+ *    This routine is used to allocate a free anim class object from the preallocated pool     *
+ *    in the near heap. If there are no free animation objects, then null is returned.         *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with a pointer to a free anim object.                                      *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/31/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void * AnimClass::operator new(size_t)
+{
+	void * ptr = Anims.Allocate();
+	if (ptr != NULL) {
+		((AnimClass *)ptr)->IsActive = true;
+	}
+	return(ptr);
+}
+
+
+/***********************************************************************************************
+ * AnimClass::delete -- Returns an anim object back to the free pool.                          *
+ *                                                                                             *
+ *    This routine is used to return an anim object back to the pool of free anim objects.     *
+ *    Anim objects so returned are available to be reallocated for the next animation.         *
+ *                                                                                             *
+ * INPUT:   ptr   -- Pointer to the anim object to return to the pool.                         *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/31/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AnimClass::operator delete(void * ptr)
+{
+	if (ptr != NULL) {
+		((AnimClass *)ptr)->IsActive = false;
+	}
+	Anims.Free((AnimClass *)ptr);
+}
+
+
+/***********************************************************************************************
+ * AnimClass::AnimClass -- The constructor for animation objects.                              *
+ *                                                                                             *
+ *    This routine is used as the constructor of animation objects. It initializes and adds    *
+ *    the animation object to the display and logic systems.                                   *
+ *                                                                                             *
+ * INPUT:   animnum  -- The animation number to start.                                         *
+ *                                                                                             *
+ *          coord    -- The location of the animation.                                         *
+ *                                                                                             *
+ *          timedelay-- The delay before the animation starts.                                 *
+ *                                                                                             *
+ *          loop     -- The number of times to loop this animation.                            *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/31/1994 JLB : Created.                                                                 *
+ *   08/03/1994 JLB : Added a delayed affect parameter.                                        *
+ *=============================================================================================*/
+AnimClass::AnimClass(AnimType animnum, COORDINATE coord, unsigned char timedelay, unsigned char loop) :
+	ObjectClass(RTTI_ANIM, Anims.ID(this)),
+	Class(AnimTypes.Ptr((int)animnum)),
+	xObject(TARGET_NONE),
+	OwnerHouse(HOUSE_NONE),
+	Loops(1),
+	IsToDelete(false),
+	IsBrandNew(true),
+	IsInvisible(false),
+	Delay(timedelay),
+	Accum(0)
+{
+#ifdef 0
+	if (Class->Stages == -1) {
+		((int&)Class->Stages) = Get_Build_Frame_Count(Class->Get_Image_Data());
+	}
+	if (Class->LoopEnd == -1) {
+		((int&)Class->LoopEnd) = Class->Stages;
+	}
+	if (Class->IsNormalized) {
+		Set_Rate(Options.Normalize_Delay(Class->Delay));
+	} else {
+		Set_Rate(Class->Delay);
+	}
+	Set_Stage(0);
+
+	if (Class->IsGroundLayer) {
+		Height = FLIGHT_LEVEL;
+	}
+
+	AnimClass::Unlimbo(coord);
+
+	/*
+	**	Drop zone smoke always reveals the map around itself.
+	*/
+	if (*this == ANIM_LZ_SMOKE) {
+		Map.Sight_From(Coord_Cell(coord), Rule.DropZoneRadius / CELL_LEPTON_W, PlayerPtr, false);
+	}
+
+	Loops = (unsigned char)(max(loop, 1) * Class->Loops);
+	Loops = (unsigned char)max(Loops, 1);
+
+	/*
+	**	If the animation starts immediately, then play the associated sound effect now.
+	*/
+	if (!Delay) {
+		Start();
+	}
+#endif
+}
+
+
+/***********************************************************************************************
+ * AnimClass::~AnimClass -- Destructor for anim objects.                                       *
+ *                                                                                             *
+ *    This destructor handles removing the animation object from the system. It might require  *
+ *    informing any object this animation is attached to that it is no longer attached.        *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   11/29/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+AnimClass::~AnimClass(void)
+{
+#ifdef 0
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+	if (GameActive) {
+
+		/*
+		**	If this anim is attached to another object
+		**	then check to see if this is the last anim attached to it. If this
+		**	is the case, then inform the object that it is no longer attached to
+		**	an animation.
+		*/
+		if (Target_Legal(xObject) && As_Object(xObject) != NULL) {
+			ObjectClass * to = As_Object(xObject);
+
+			/*
+			**	Remove the object from the appropriate display list.
+			*/
+			Map.Remove(this, In_Which_Layer());
+
+			/*
+			**	Scan for any other animations that are attached to the object that
+			**	this animation is attached to. If there are no others, then inform the
+			**	attached object of this fact.
+			*/
+			for (int index = 0; index < Anims.Count(); index++) {
+				if (Anims.Ptr(index) != this && Anims.Ptr(index)->xObject == xObject) break;
+			}
+
+			/*
+			**	Tell the object that it is no longer being damaged.
+			*/
+			if (index == Anims.Count()) {
+				to->Fire_Out();
+				to->Mark(MARK_OVERLAP_UP);
+				to->IsAnimAttached = false;
+				to->Mark(MARK_OVERLAP_DOWN);
+			}
+			Coord = Coord_Add(to->Center_Coord(), Coord);
+			xObject = TARGET_NONE;
+		}
+
+		Limbo();
+	}
+
+	xObject = TARGET_NONE;
+	Class = 0;
+	ID = -1;
+#endif
+}
+
+
+/***********************************************************************************************
+ * AnimClass::AI -- This is the low level anim processor.                                      *
+ *                                                                                             *
+ *    This routine is called once per frame per animation. It handles transition between       *
+ *    animation frames and marks the map for redraw as necessary.                              *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   Speed is of upmost importance.                                                  *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/31/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AnimClass::AI(void)
+{
+#ifdef 0
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+
+	/*
+	**	For ground level based animations (ones that can run slowly as well as
+	**	occur behind other ground objects) always cause the cell to be redrawn.
+	*/
+#ifdef PARTIAL
+	if (!Delay && Class->IsGroundLayer) {
+		Map.Refresh_Cells(Coord_Cell(Center_Coord()), Overlap_List());
+	}
+#else
+	Map.Refresh_Cells(Coord_Cell(Center_Coord()), Overlap_List());
+#endif
+
+	/*
+	**	Special case check to make sure that building on top of a smoke marker
+	**	causes the smoke marker to vanish.
+	*/
+	if (Class->Type == ANIM_LZ_SMOKE && Map[Center_Coord()].Cell_Building()) {
+		IsToDelete = true;
+	}
+
+	/*
+	**	Delete this animation and bail early if the animation is flagged to be deleted
+	**	immediately.
+	*/
+	if (IsToDelete) {
+		delete this;
+		return;
+	}
+
+	/*
+	**	If this is a brand new animation, then don't process it the first logic pass
+	**	since it might end up skipping the first animation frame before it has had a
+	**	chance to draw it.
+	*/
+	if (IsBrandNew) {
+		IsBrandNew = false;
+		return;
+	}
+
+	if (Delay) {
+		Delay--;
+		if (!Delay) {
+			Start();
+		}
+	} else {
+
+		/*
+		**	This is necessary because there is no recording of animations on the map
+		**	and thus the animation cannot be intelligently flagged for redraw. Most
+		**	animations move fast enough that they would need to be redrawn every
+		**	game frame anyway so this isn't TOO bad.
+		*/
+		Mark(MARK_CHANGE);
+
+		if (StageClass::Graphic_Logic()) {
+			int stage = Fetch_Stage();
+
+			/*
+			**	If this animation is attached to another object and it is a
+			**	damaging kind of animation, then do the damage to the other
+			**	object.
+			*/
+			if (xObject != TARGET_NONE && Class->Damage > 0) {
+				Accum += Class->Damage;
+
+				if (Accum >= 1) {
+
+					/*
+					**	Administer the damage. If the object was destroyed by this anim,
+					**	then the attached damaging anim is also destroyed.
+					*/
+					int damage = Accum;
+					Accum -= damage;
+					if (As_Object(xObject)->Take_Damage(damage, 0, WARHEAD_FIRE) == RESULT_DESTROYED) {
+						delete this;
+						return;
+					}
+				}
+			}
+
+			/*
+			**	During the biggest stage (covers the most ground), perform any ground altering
+			**	action required. This masks craters and scorch marks, so that they appear
+			**	naturally rather than "popping" into existence while in plain sight.
+			*/
+			if (Class->Biggest && Class->Start+stage == Class->Biggest) {
+				Middle();
+			}
+
+			/*
+			**	Check to see if the last frame has been displayed. If so, then the
+			**	animation either ends or loops.
+			*/
+			if ((Loops <= 1 && stage >= Class->Stages) || (Loops > 1 && stage >= Class->LoopEnd-Class->Start)) {
+
+				/*
+				**	Determine if this animation should loop another time. If so, then start the loop
+				**	but if not, then proceed into the animation termination handler.
+				*/
+				if (Loops) Loops--;
+				if (Loops) {
+					Set_Stage(Class->LoopStart);
+				} else {
+
+					/*
+					**	The animation should end now, but first check to see if
+					**	it needs to chain into another animation. If so, then the
+					**	animation isn't technically over. It metamorphoses into the
+					**	new form.
+					*/
+					if (Class->ChainTo != ANIM_NONE) {
+
+						Class = (AnimTypeClass *)&AnimTypeClass::As_Reference(Class->ChainTo);
+
+						if (Class->Stages == -1) {
+							((int&)Class->Stages) = Get_Build_Frame_Count(Class->Get_Image_Data());
+						}
+						if (Class->LoopEnd == -1) {
+							((int&)Class->LoopEnd) = Class->Stages;
+						}
+
+						IsToDelete = false;
+						Loops = Class->Loops;
+						Accum = 0;
+						if (Class->IsNormalized) {
+							Set_Rate(Options.Normalize_Delay(Class->Delay));
+						} else {
+							Set_Rate(Class->Delay);
+						}
+						Set_Stage(Class->Start);
+						Start();
+					} else {
+						delete this;
+					}
+				}
+			}
+		}
+	}
+#endif
+}
+
+
+/***********************************************************************************************
+ * AnimClass::Attach_To -- Attaches animation to object specified.                             *
+ *                                                                                             *
+ *    An animation can be "attached" to an object. In such cases, the animation is rendered    *
+ *    as an offset from the center of the object it is attached to. This allows affects such   *
+ *    as fire or smoke to be consistently placed on the vehicle it is associated with.         *
+ *                                                                                             *
+ * INPUT:   obj   -- Pointer to the object to attach the animation to.                         *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   09/19/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AnimClass::Attach_To(ObjectClass * obj)
+{
+#ifdef 0
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+
+	if (obj == NULL) return;
+	assert(obj->IsActive);
+
+	obj->Mark(MARK_OVERLAP_UP);
+	obj->IsAnimAttached = true;
+	obj->Mark(MARK_OVERLAP_DOWN);
+	Map.Remove(this, In_Which_Layer());
+	xObject = obj->As_Target();
+	Map.Submit(this, In_Which_Layer());
+	Coord = Coord_Sub(Coord, obj->Target_Coord());
+#endif
+}
+
+
+/***********************************************************************************************
+ * AnimClass::In_Which_Layer -- Determines what render layer the anim should be in.            *
+ *                                                                                             *
+ *    Use this routine to find out which display layer (ground or air) that the animation      *
+ *    should be in. This information is used to place the animation into the correct display   *
+ *    list.                                                                                    *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the layer that the animation should exist in.                         *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   12/25/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+LayerType AnimClass::In_Which_Layer(void) const
+{
+#ifdef 0
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+
+	if (Target_Legal(xObject) || Class->IsGroundLayer) {
+		return(LAYER_GROUND);
+	}
+
+	return(LAYER_AIR);
+}
+
+
+/***********************************************************************************************
+ * AnimClass::Start -- Processes initial animation side effects.                               *
+ *                                                                                             *
+ *    This routine is called when the animation first starts. Sometimes there are side effects *
+ *    associated with this animation that must occur immediately. Typically, this is the       *
+ *    sound effect assigned to this animation. If this animation is supposed to attach itself  *
+ *    to any object at its location, then do so at this time as well.                          *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/30/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AnimClass::Start(void)
+{
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+
+	Mark();
+
+	/*
+	**	Play the sound effect for this animation.
+	*/
+	Sound_Effect(Class->Sound, Coord);
+
+	/*
+	**	If the stage where collateral effects occur is the first stage of the animation, then
+	**	perform this action now. Subsequent checks against this stage value starts with the
+	**	second frame of the animation.
+	*/
+	if (!Class->Biggest) {
+		Middle();
+	}
+}
+
+
+/***********************************************************************************************
+ * AnimClass::Middle -- Processes any middle events.                                           *
+ *                                                                                             *
+ *    This routine is called when the animation as reached its largest stage. Typically, this  *
+ *    routine is used to cause scorches or craters to appear at a cosmetically pleasing        *
+ *    moment.                                                                                  *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/30/1995 JLB : Created.                                                                 *
+ *   10/17/1995 JLB : Ion camera added.                                                        *
+ *=============================================================================================*/
+void AnimClass::Middle(void)
+{
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+
+	CELL cell = Coord_Cell(Center_Coord());
+	CellClass * cellptr = &Map[cell];
+
+	if (Class->Type == ANIM_ATOM_BLAST) {
+		Do_Atom_Damage(OwnerHouse, cell);
+	}
+
+	/*
+	**	If this animation leaves scorch marks (e.g., napalm), then do so at this time.
+	*/
+	if (Class->IsScorcher) {
+		new SmudgeClass(Random_Pick(SMUDGE_SCORCH1, SMUDGE_SCORCH6), Center_Coord());
+	}
+
+	/*
+	**	Some animations leave a crater when they occur. Artillery is a good example.
+	**	Craters always remove the Tiberium where they occur.
+	*/
+	if (Class->IsCraterForming) {
+
+		/*
+		**	Craters reduce the level of Tiberium in the cell.
+		*/
+		cellptr->Reduce_Tiberium(6);
+
+		/*
+		**	If there already is a crater in the cell, then just expand the
+		**	crater.
+		*/
+		new SmudgeClass(SMUDGE_CRATER1, Center_Coord());
+	}
+
+	AnimClass * newanim;
+
+	/*
+	**	If this animation spawns side effects during its lifetime, then
+	**	do so now. Usually, these side effects are in the form of other
+	**	animations.
+	*/
+	switch (Class->Type) {
+		case ANIM_NAPALM1:
+		case ANIM_NAPALM2:
+		case ANIM_NAPALM3:
+			new AnimClass(ANIM_FIRE_SMALL, Map.Closest_Free_Spot(Coord_Scatter(Center_Coord(), 0x0040), true), 0, Random_Pick(1, 2));
+			if (Percent_Chance(50)) {
+				new AnimClass(ANIM_FIRE_SMALL, Map.Closest_Free_Spot(Coord_Scatter(Center_Coord(), 0x00A0), true), 0, Random_Pick(1, 2));
+			}
+			if (Percent_Chance(50)) {
+				new AnimClass(ANIM_FIRE_MED, Map.Closest_Free_Spot(Coord_Scatter(Center_Coord(), 0x0070), true), 0, Random_Pick(1, 2));
+			}
+			break;
+
+		case ANIM_FIRE_MED:
+		case ANIM_FIRE_MED2:
+			newanim = new AnimClass(ANIM_FIRE_SMALL, Center_Coord(), 0, Random_Pick(1, 2));
+			if (newanim != NULL && xObject != TARGET_NONE) {
+				newanim->Attach_To(As_Object(xObject));
+			}
+			break;
+
+		default:
+			break;
+	}
+}
+
+
+/***********************************************************************************************
+ * AnimClass::Detach -- Remove animation if attached to target.                                *
+ *                                                                                             *
+ *    This routine is called when the specified target is being removed from the game. If this *
+ *    animation happens to be attached to this object, then the animation must be remove as    *
+ *    well.                                                                                    *
+ *                                                                                             *
+ * INPUT:   target   -- The target that is about to be destroyed.                              *
+ *                                                                                             *
+ *          all      -- Is the target being destroyed RIGHT NOW? If not, then it will be       *
+ *                      destroyed soon. In that case, the animation should continue to remain  *
+ *                      attached for cosmetic reasons.                                         *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/30/1995 JLB : Created.                                                                 *
+ *   07/02/1995 JLB : Detach is a precursor to animation destruction.                          *
+ *=============================================================================================*/
+void AnimClass::Detach(TARGET target, bool all)
+{
+	assert(Anims.ID(this) == ID);
+	assert(IsActive);
+
+	if (xObject == target && all) {
+		Map.Remove(this, In_Which_Layer());
+		xObject = TARGET_NONE;
+		IsToDelete = true;
+		Mark(MARK_UP);
+	}
+}
+
+
+/***********************************************************************************************
+ * AnimClass::Do_Atom_Damage -- Do atom bomb damage centered around the cell specified.        *
+ *                                                                                             *
+ *    This routine will apply damage around the ground-zero cell specified.                    *
+ *                                                                                             *
+ * INPUT:   ownerhouse  -- The owner of this atom bomb.                                        *
+ *                                                                                             *
+ *          cell        -- The ground zero location to apply the atom bomb damage.             *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/06/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void AnimClass::Do_Atom_Damage(HousesType ownerhouse, CELL cell)
+{
+	/*
+	**	Find someone to blame the explosion on. This is necessary in
+	**	order to properly enact retribution and record the kill for
+	**	score purposes.
+	*/
+	BuildingClass * building = NULL;
+	TechnoClass * backup = NULL;
+	if (ownerhouse != HOUSE_NONE) {
+		for (int index = 0; index < Logic.Count(); index++) {
+			ObjectClass * obj = Logic[index];
+
+			if (obj != NULL && obj->Is_Techno() && obj->Owner() == ownerhouse) {
+				backup = (TechnoClass *)obj;
+				if (obj->What_Am_I() == RTTI_BUILDING && *((BuildingClass *)obj) == STRUCT_MSLO) {
+					building = (BuildingClass *)obj;
+					break;
+				}
+			}
+		}
+
+		if (building == NULL) building = (BuildingClass *)backup;
+	}
+
+	int radius;
+	int rawdamage;
+	if (Session.Type == GAME_NORMAL) {
+		radius = 4;
+		rawdamage = Rule.AtomDamage;
+		WhitePalette.Set(FADE_PALETTE_SLOW, Call_Back);
+	} else {
+		radius = 3;
+		rawdamage = Rule.AtomDamage/5;
+	}
+
+	Wide_Area_Damage(Cell_Coord(cell), radius * CELL_LEPTON_W, rawdamage, building, WARHEAD_FIRE);
+	Shake_The_Screen(3);
+	if (Session.Type == GAME_NORMAL) {
+		GamePalette.Set(FADE_PALETTE_SLOW, Call_Back);
+	}
+}
+
+

+ 156 - 0
CODE/ANIM.H

@@ -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 - 0
CODE/AUDIO.CPP

@@ -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 - 0
CODE/AUDIO.CPP.BAK

@@ -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 - 0
CODE/AUDIO.H

@@ -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 - 0
CODE/B64PIPE.CPP

@@ -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 - 0
CODE/B64PIPE.H

@@ -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 - 0
CODE/B64STRAW.CPP

@@ -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 - 0
CODE/B64STRAW.H

@@ -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 - 0
CODE/BAR.CPP

@@ -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 - 0
CODE/BAR.H

@@ -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 - 0
CODE/BASE.CPP

@@ -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 - 0
CODE/BASE.H

@@ -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 - 0
CODE/BASE64.CPP

@@ -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 - 0
CODE/BASE64.H

@@ -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 - 0
CODE/BBDATA.CPP

@@ -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 - 0
CODE/BDATA.CPP

@@ -0,0 +1,3834 @@
+/*
+**	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/BDATA.CPP 2     3/03/97 10:37p 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 : BDATA.CPP                                                    *
+ *                                                                                             *
+ *                   Programmer : Joe L. Bostic                                                *
+ *                                                                                             *
+ *                   Start Date : September 10, 1993                                           *
+ *                                                                                             *
+ *                  Last Update : October 2, 1996 [JLB]                                        *
+ *                                                                                             *
+ *---------------------------------------------------------------------------------------------*
+ * Functions:                                                                                  *
+ *   BuildingTypeClass::As_Reference -- Fetches reference to the building type specified.      *
+ *   BuildingTypeClass::Bib_And_Offset -- Determines the bib and appropriate cell offset.      *
+ *   BuildingTypeClass::BuildingTypeClass -- This is the constructor for the building types.   *
+ *   BuildingTypeClass::Coord_Fixup -- Adjusts coordinate to be legal for assignment.          *
+ *   BuildingTypeClass::Cost_Of -- Fetches the cost of this building.                          *
+ *   BuildingTypeClass::Create_And_Place -- Creates and places a building object onto the map. *
+ *   BuildingTypeClass::Create_One_Of -- Creates a building of this type.                      *
+ *   BuildingTypeClass::Dimensions -- Fetches the pixel dimensions of the building.            *
+ *   BuildingTypeClass::Display -- Renders a generic view of building.                         *
+ *   BuildingTypeClass::Flush_For_Placement -- Tries to clear placement area for this building *
+ *   BuildingTypeClass::Full_Name -- Fetches the name to give this building.                   *
+ *   BuildingTypeClass::Height -- Determines the height of the building in icons.              *
+ *   BuildingTypeClass::Init -- Performs theater specific initialization.                      *
+ *   BuildingTypeClass::Init_Anim -- Initialize an animation control for a building.           *
+ *   BuildingTypeClass::Init_Heap -- Initialize the heap as necessary for the building type obj*
+ *   BuildingTypeClass::Max_Pips -- Determines the maximum pips to display.                    *
+ *   BuildingTypeClass::Occupy_List -- Fetches the occupy list for the building.               *
+ *   BuildingTypeClass::One_Time -- Performs special one time action for buildings.            *
+ *   BuildingTypeClass::Overlap_List -- Fetches the overlap list for the building.             *
+ *   BuildingTypeClass::Prep_For_Add -- Prepares scenario editor for adding an object.         *
+ *   BuildingTypeClass::Raw_Cost -- Fetches the raw (base) cost of this building type.         *
+ *   BuildingTypeClass::Read_INI -- Fetch building type data from the INI database.            *
+ *   BuildingTypeClass::Width -- Determines width of building in icons.                        *
+ *   BuildingTypeClass::operator delete -- Deletes a building type object from the special heap*
+ *   BuildingTypeClass::operator new -- Allocates a building type object from the special heap.*
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+#include	"function.h"
+
+
+#define FATSHIP
+
+#define	MCW	MAP_CELL_W
+
+#define XYCELL(x,y)	(y*MAP_CELL_W+x)
+static short const ExitPyle[] = {
+	XYCELL(1,2),
+	XYCELL(2,2),
+	XYCELL(0,2),
+	XYCELL(-1,2),
+	XYCELL(-1,-1),
+	XYCELL(0,-1),
+	XYCELL(1,-1),
+	XYCELL(2,-1),
+	XYCELL(2,-1),
+	XYCELL(-1,0),
+	XYCELL(2,0),
+	XYCELL(2,1),
+	XYCELL(-1,1),
+	REFRESH_EOL
+};
+
+static short const ExitSub[] = {
+	XYCELL( 0, 2),
+	XYCELL( 2, 2),
+	XYCELL(-1, 2),
+	XYCELL( 1, 2),
+	XYCELL( 3, 2)
+};
+
+static short const ExitWeap[] = {
+	XYCELL(1,2),
+	XYCELL(-1,3),
+	XYCELL(0,3),
+	XYCELL(1,3),
+	XYCELL(-2,3),
+	XYCELL(2,3),
+	REFRESH_EOL
+};
+
+static short const ComList[] = {0, 1, MCW, MCW+1, REFRESH_EOL};
+static short const List000111111[] = {(MCW*1), (MCW*1)+1, (MCW*1)+2, (MCW*2), (MCW*2)+1, (MCW*2)+2, REFRESH_EOL};
+static short const List0010[] = {MCW, REFRESH_EOL};
+static short const List0011[] = {(MCW*1), (MCW*1)+1, REFRESH_EOL};
+static short const List010111100[] = {1, (MCW*1), (MCW*1)+1, (MCW*1)+2, (MCW*2), REFRESH_EOL};
+static short const List0111[] = {1, (MCW*1), (MCW*1)+1, REFRESH_EOL};
+static short const List1000[] = {0, REFRESH_EOL};
+static short const List101000011[] = {0, 2, (MCW*2)+1, (MCW*2)+2, REFRESH_EOL};
+static short const List1100[] = {0, 1, REFRESH_EOL};
+static short const List1101[] = {0, 1, (MCW*1)+1, REFRESH_EOL};
+static short const List11[] = {0, 1, REFRESH_EOL};
+static short const List12[] = {MCW, REFRESH_EOL};
+static short const List1[] = {0, REFRESH_EOL};
+static short const List21[] = {0, 1, REFRESH_EOL};
+static short const List22[] = {0, 1, MCW, MCW+1, REFRESH_EOL};
+static short const List22_0011[] = {MCW, MCW+1, REFRESH_EOL};
+static short const List22_1100[] = {0, 1, REFRESH_EOL};
+static short const List2[] = {0, 1, MCW+1, MCW, REFRESH_EOL};
+static short const List32[] = {0, 1, 2, MCW, MCW+1, MCW+2, REFRESH_EOL};
+//static short const List42[] = {0, 1, 2, 3, MCW, MCW+1, MCW+2, MCW+3, REFRESH_EOL};
+static short const ListFix[] = {1, MCW, MCW+1, MCW+2, MCW+MCW+1, REFRESH_EOL};
+static short const ListWeap[] = {0, 1, 2, (MCW*1), (MCW*1)+1, (MCW*1)+2, REFRESH_EOL};
+static short const ListWestwood[] = {1, 2, 3, MCW+1, MCW+2, MCW+3, REFRESH_EOL};
+static short const OListSAM[] = {-MCW, -(MCW-1), REFRESH_EOL};
+#ifdef FATSHIP
+static short const ListSPen[] = {0, 1, 2, MCW, MCW+1, MCW+2, MCW+MCW, MCW+MCW+1, MCW+MCW+2, REFRESH_EOL};
+static short const OListSPen[] = {REFRESH_EOL};
+#else
+static short const ListSPen[] = {1, MCW, MCW+1, MCW+2, MCW+MCW+1, REFRESH_EOL};
+static short const OListSPen[] = {0, 2, MCW+MCW, MCW+MCW+2, REFRESH_EOL};
+#endif
+static short const OListWestwood[] = {0, MCW, REFRESH_EOL};
+static short const StoreList[] = {0, REFRESH_EOL};
+
+static short const ListFactory[] = {0, 1, 2, (MCW*1), (MCW*1)+1, (MCW*1)+2, (MCW*2), (MCW*2)+1, (MCW*2)+2, REFRESH_EOL};
+
+static short const OListFix[] = {0, 2, MCW+MCW, MCW+MCW+2, REFRESH_EOL};
+static short const OListWeap[] = {REFRESH_EOL};
+static short const OComList[] = {1, REFRESH_EOL};
+static short const OList12[] = {0, REFRESH_EOL};
+static short const OListTmpl[] = {0, 1, 2, REFRESH_EOL};
+
+
+/***************************************************************************
+*/
+static BuildingTypeClass const ClassBarrel(
+	STRUCT_BARREL,
+	TXT_BARREL,						// NAME:			Short name of the structure.
+	"BARL",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		true,							// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassBarrel3(
+	STRUCT_BARREL3,
+	TXT_BARREL,						// NAME:			Short name of the structure.
+	"BRL3",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		true,							// Is it invisible to radar?
+		false,						// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassAVMine(
+	STRUCT_AVMINE,
+	TXT_AVMINE,						// NAME:			Short name of the structure.
+	"MINV",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_NONE,						// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		true,							// Is it invisible to radar?
+		false,						// Can the player select this?
+		false,						// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassAPMine(
+	STRUCT_APMINE,
+	TXT_APMINE,						// NAME:			Short name of the structure.
+	"MINP",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_NONE,						// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		true,							// Is it invisible to radar?
+		false,						// Can the player select this?
+		false,						// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassIronCurtain(
+	STRUCT_IRON_CURTAIN,
+	TXT_IRON_CURTAIN,				// NAME:			Short name of the structure.
+	"IRON",							// NAME:			Short name of the structure.
+	FACING_S,						// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_22, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List22_0011,// OCCUPYLIST:	List of active foundation squares.
+	(short const *)List22_1100	// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassForwardCom(
+	STRUCT_FORWARD_COM,
+	TXT_FORWARD_COM,				// NAME:			Short name of the structure.
+	"FCOM",							// NAME:			Short name of the structure.
+	FACING_S,						// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_22, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List22_0011,// OCCUPYLIST:	List of active foundation squares.
+	(short const *)List22_1100	// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassAdvancedTech(
+	STRUCT_ADVANCED_TECH,
+	TXT_ADVANCED_TECH,			// NAME:			Short name of the structure.
+	"ATEK",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_22, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List22,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassChronosphere(
+	STRUCT_CHRONOSPHERE,
+	TXT_CHRONOSPHERE,				// NAME:			Short name of the structure.
+	"PDOX",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_22, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List22,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassWeapon(
+	STRUCT_WEAP,
+	TXT_WEAPON_FACTORY,			// NAME:			Short name of the structure.
+	"WEAP",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XY_Coord(CELL_LEPTON_W+(CELL_LEPTON_W/2), CELL_LEPTON_H),			// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_UNITTYPE,					// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_32, 						// SIZE:			Building size.
+	(short const *)ExitWeap,	// Preferred exit cell list.
+	(short const *)ListWeap,	// OCCUPYLIST:	List of active foundation squares.
+	(short const *)OListWeap	// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassShipYard(
+	STRUCT_SHIP_YARD,
+	TXT_SHIP_YARD,					// NAME:			Short name of the structure.
+	"SYRD",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(22+(CELL_PIXEL_W/2), ((CELL_PIXEL_H*2)-(CELL_PIXEL_H/2))),			// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_VESSELTYPE,				// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_33, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)ListSPen,	// OCCUPYLIST:	List of active foundation squares.
+	(short const *)OListSPen	// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassSubPen(
+	STRUCT_SUB_PEN,
+	TXT_SUB_PEN,					// NAME:			Short name of the structure.
+	"SPEN",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(22+(CELL_PIXEL_W/2), ((CELL_PIXEL_H*2)-(CELL_PIXEL_H/2))),			// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_VESSELTYPE,				// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_33, 						// SIZE:			Building size.
+	(short const *)ExitSub,		// Preferred exit cell list.
+	(short const *)ListSPen,	// OCCUPYLIST:	List of active foundation squares.
+	(short const *)OListSPen	// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassPillbox(
+	STRUCT_PILLBOX,
+	TXT_PILLBOX,					// NAME:			Short name of the structure.
+	"PBOX",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0010,							//	Vertical offset.
+	0x0040,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassCamoPillbox(
+	STRUCT_CAMOPILLBOX,
+	TXT_CAMOPILLBOX,				// NAME:			Short name of the structure.
+	"HBOX",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0010,							//	Vertical offset.
+	0x0040,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassTesla(
+	STRUCT_TESLA,
+	TXT_TESLA,						// NAME:			Short name of the structure.
+	"TSLA",							// NAME:			Short name of the structure.
+	FACING_S,						// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x00C8,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_12, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List12,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)OList12		// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassTurret(
+	STRUCT_TURRET,
+	TXT_TURRET,						// NAME:			Short name of the structure.
+	"GUN",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0030,							//	Vertical offset.
+	0x0080,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		true,							// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	(DirType)208,					// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassAAGun(
+	STRUCT_AAGUN,
+	TXT_AAGUN,						// NAME:			Short name of the structure.
+	"AGUN",							// NAME:			Short name of the structure.
+	FACING_S,						// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		true,							// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_NE,							// Starting idle frame to match construction.
+	BSIZE_12, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List12,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)OList12		// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassFlameTurret(
+	STRUCT_FLAME_TURRET,
+	TXT_FLAME_TURRET,				// NAME:			Short name of the structure.
+	"FTUR",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassConst(
+	STRUCT_CONST,
+	TXT_CONST_YARD,				// NAME:			Short name of the structure.
+	"FACT",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_BUILDINGTYPE,			// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_33, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)ListFactory,// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassFakeConst(
+	STRUCT_FAKECONST,
+	TXT_FAKE_CONST,				// NAME:			Short name of the structure.
+	"FACF",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		true,							// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_33, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)ListFactory,// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassFakeWeapon(
+	STRUCT_FAKEWEAP,
+	TXT_FAKE_WEAP,					// NAME:			Short name of the structure.
+	"WEAF",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(10+(CELL_PIXEL_W/2), ((CELL_PIXEL_H*3)-(CELL_PIXEL_H/2))-21),			// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		true,							// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_32, 						// SIZE:			Building size.
+	(short const *)ExitWeap,	// Preferred exit cell list.
+	(short const *)ListWeap,	// OCCUPYLIST:	List of active foundation squares.
+	(short const *)OListWeap	// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassRefinery(
+	STRUCT_REFINERY,
+	TXT_REFINERY,					// NAME:			Short name of the structure.
+	"PROC",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_33, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List010111100,	// OCCUPYLIST:	List of active foundation squares.
+	(short const *)List101000011	// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassStorage(
+	STRUCT_STORAGE,
+	TXT_STORAGE,					// NAME:			Short name of the structure.
+	"SILO",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)StoreList,	// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassHelipad(
+	STRUCT_HELIPAD,
+	TXT_HELIPAD,					// NAME:			Short name of the structure.
+	"HPAD",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_AIRCRAFTTYPE,			// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_22, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List2,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassCommand(
+	STRUCT_RADAR,
+	TXT_COMMAND,					// NAME:			Short name of the structure.
+	"DOME",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_22, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)ComList,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassGapGenerator(
+	STRUCT_GAP,
+	TXT_GAP_GENERATOR,			// NAME:			Short name of the structure.
+	"GAP",							// NAME:			Short name of the structure.
+	FACING_S,						// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_12, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List0010,	// OCCUPYLIST:	List of active foundation squares.
+	(short const *)List1			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassSAM(
+	STRUCT_SAM,
+	TXT_SAM,							// NAME:			Short name of the structure.
+	"SAM",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0030,							//	Vertical offset.
+	0x0080,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		true,							// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_21, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List21,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)OListSAM		// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassMissileSilo(
+	STRUCT_MSLO,
+	TXT_MSLO,						// NAME:			Short name of the structure.
+	"MSLO",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_21, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List21,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)OListSAM		// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassAirStrip(
+	STRUCT_AIRSTRIP,
+	TXT_AIRSTRIP,					// NAME:			Short name of the structure.
+	"AFLD",							// NAME:			Short name of the structure.
+	FACING_S,						// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_AIRCRAFTTYPE,			// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_32, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List32,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassPower(
+	STRUCT_POWER,
+	TXT_POWER,						// NAME:			Short name of the structure.
+	"POWR",							// NAME:			Short name of the structure.
+	FACING_S,						// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_22, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List22,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)List22_1100	// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassAdvancedPower(
+	STRUCT_ADVANCED_POWER,
+	TXT_ADVANCED_POWER,			// NAME:			Short name of the structure.
+	"APWR",							// NAME:			Short name of the structure.
+	FACING_S,						// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_33, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List000111111,	// OCCUPYLIST:	List of active foundation squares.
+	(short const *)OListTmpl	// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassSovietTech(
+	STRUCT_SOVIET_TECH,
+	TXT_SOVIET_TECH,				// NAME:			Short name of the structure.
+	"STEK",							// NAME:			Short name of the structure.
+	FACING_S,						// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_33, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List000111111,	// OCCUPYLIST:	List of active foundation squares.
+	(short const *)OListTmpl	// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassHospital(
+	STRUCT_HOSPITAL,
+	TXT_HOSPITAL,					// NAME:			Short name of the structure.
+	"HOSP",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_22, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List2,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassBioLab(
+	STRUCT_BIO_LAB,
+	TXT_BIO_LAB,					// NAME:			Short name of the structure.
+	"BIO",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_22, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List2,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassBarracks(
+	STRUCT_BARRACKS,
+	TXT_BARRACKS,					// NAME:			Short name of the structure.
+	"BARR",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+//	XYP_COORD(24,47),				// Exit point for produced units.
+	XYP_COORD(18,47),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_INFANTRYTYPE,			// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_22, 						// SIZE:			Building size.
+	(short const *)ExitPyle,	// Preferred exit cell list.
+	(short const *)List22,		// OCCUPYLIST:	List of active foundation squares.
+	NULL								// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassTent(
+	STRUCT_TENT,
+	TXT_BARRACKS,					// NAME:			Short name of the structure.
+	"TENT",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(24,47),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_INFANTRYTYPE,			// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_22, 						// SIZE:			Building size.
+	(short const *)ExitPyle,	// Preferred exit cell list.
+	(short const *)List22,		// OCCUPYLIST:	List of active foundation squares.
+	NULL								// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassKennel(
+	STRUCT_KENNEL,
+	TXT_KENNEL,						// NAME:			Short name of the structure.
+	"KENN",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(8,16),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_INFANTRYTYPE,			// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+//	(short const *)ExitPyle,	// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	NULL								// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassFakeShipYard(
+	STRUCT_FAKE_YARD,
+	TXT_FAKE_YARD,					// NAME:			Short name of the structure.
+	"SYRF",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(22+(CELL_PIXEL_W/2), ((CELL_PIXEL_H*2)-(CELL_PIXEL_H/2))),			// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		true,							// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_33, 						// SIZE:			Building size.
+	(short const *)ExitWeap,	// Preferred exit cell list.
+	(short const *)ListSPen,	// OCCUPYLIST:	List of active foundation squares.
+	(short const *)OListSPen	// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassFakeSubPen(
+	STRUCT_FAKE_PEN,
+	TXT_FAKE_PEN,					// NAME:			Short name of the structure.
+	"SPEF",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(22+(CELL_PIXEL_W/2), ((CELL_PIXEL_H*2)-(CELL_PIXEL_H/2))),			// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		true,							// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_33, 						// SIZE:			Building size.
+	(short const *)ExitSub,		// Preferred exit cell list.
+	(short const *)ListSPen,	// OCCUPYLIST:	List of active foundation squares.
+	(short const *)OListSPen	// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassFakeCommand(
+	STRUCT_FAKE_RADAR,
+	TXT_FAKE_RADAR,				// NAME:			Short name of the structure.
+	"DOMF",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		true,							// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_22, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)ComList,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)OComList		// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassRepair(
+	STRUCT_REPAIR,
+	TXT_FIX_IT,						// NAME:			Short name of the structure.
+	"FIX",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		false,						// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_33, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)ListFix,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)OListFix		// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV01(
+	STRUCT_V01,
+	TXT_CIV1,						// NAME:			Short name of the structure.
+	"V01",							// NAME:			Short name of the structure.
+	FACING_S,						// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		true,							// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_22, 						// SIZE: Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List0011,	// OCCUPYLIST:	List of active foundation squares.
+	(short const *)List1100		// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV02(
+	STRUCT_V02,
+	TXT_CIV2,						// NAME:			Short name of the structure.
+	"V02",							// NAME:			Short name of the structure.
+	FACING_S,						// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		true,							// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_22, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List0011,	// OCCUPYLIST:	List of active foundation squares.
+	(short const *)List1100		// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV03(
+	STRUCT_V03,
+	TXT_CIV3,						// NAME:			Short name of the structure.
+	"V03",							// NAME:			Short name of the structure.
+	FACING_S,						// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		true,							// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_22, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List0111,	// OCCUPYLIST:	List of active foundation squares.
+	(short const *)List1000		// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV04(
+	STRUCT_V04,
+	TXT_CIV4,						// NAME:			Short name of the structure.
+	"V04",							// NAME:			Short name of the structure.
+	FACING_S,						// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		true,							// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_22, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List0011,	// OCCUPYLIST:	List of active foundation squares.
+	(short const *)List1100		// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV05(
+	STRUCT_V05,
+	TXT_CIV5,						// NAME:			Short name of the structure.
+	"V05",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		true,							// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_21, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List11,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV06(
+	STRUCT_V06,
+	TXT_CIV6,						// NAME:			Short name of the structure.
+	"V06",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		true,							// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_21, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List11,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV07(
+	STRUCT_V07,
+	TXT_CIV7,						// NAME:			Short name of the structure.
+	"V07",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		true,							// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_21, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List11,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV08(
+	STRUCT_V08,
+	TXT_CIV8,						// NAME:			Short name of the structure.
+	"V08",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		true,							// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV09(
+	STRUCT_V09,
+	TXT_CIV9,						// NAME:			Short name of the structure.
+	"V09",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		true,							// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV10(
+	STRUCT_V10,
+	TXT_CIV10,						// NAME:			Short name of the structure.
+	"V10",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		true,							// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV11(
+	STRUCT_V11,
+	TXT_CIV11,						// NAME:			Short name of the structure.
+	"V11",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		true,							// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV12(
+	STRUCT_V12,
+	TXT_CIV12,						// NAME:			Short name of the structure.
+	"V12",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		true,							// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV13(
+	STRUCT_V13,
+	TXT_CIV13,						// NAME:			Short name of the structure.
+	"V13",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		true,							// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV14(
+	STRUCT_V14,
+	TXT_CIV14,						// NAME:			Short name of the structure.
+	"V14",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		true,							// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV15(
+	STRUCT_V15,
+	TXT_CIV15,						// NAME:			Short name of the structure.
+	"V15",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		true,							// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV16(
+	STRUCT_V16,
+	TXT_CIV16,						// NAME:			Short name of the structure.
+	"V16",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		true,							// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV17(
+	STRUCT_V17,
+	TXT_CIV17,						// NAME:			Short name of the structure.
+	"V17",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		true,							// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV18(
+	STRUCT_V18,
+	TXT_CIV18,						// NAME:			Short name of the structure.
+	"V18",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		true,							// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV19(
+	STRUCT_PUMP,
+	TXT_PUMP,						// NAME:			Short name of the structure.
+	"V19",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV20(
+	STRUCT_V20,
+	TXT_CIV20,						// NAME:			Short name of the structure.
+	"V20",							// NAME:			Short name of the structure.
+	FACING_S,						// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_22, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List0011,	// OCCUPYLIST:	List of active foundation squares.
+	(short const *)List1100		// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV21(
+	STRUCT_V21,
+	TXT_CIV21,						// NAME:			Short name of the structure.
+	"V21",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_22, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1101,	// OCCUPYLIST:	List of active foundation squares.
+	(short const *)List0010		// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV22(
+	STRUCT_V22,
+	TXT_CIV22,						// NAME:			Short name of the structure.
+	"V22",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_21, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List11,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV23(
+	STRUCT_V23,
+	TXT_CIV23,						// NAME:			Short name of the structure.
+	"V23",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV24(
+	STRUCT_V24,
+	TXT_CIV24,						// NAME:			Short name of the structure.
+	"V24",							// NAME:			Short name of the structure.
+	FACING_S,						// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_22, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List0011,	// OCCUPYLIST:	List of active foundation squares.
+	(short const *)List1100		// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV25(
+	STRUCT_V25,
+	TXT_CIV25,						// NAME:			Short name of the structure.
+	"V25",							// NAME:			Short name of the structure.
+	FACING_S,						// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_22, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List0111,	// OCCUPYLIST:	List of active foundation squares.
+	(short const *)List1000		// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV26(
+	STRUCT_V26,
+	TXT_CIV26,						// NAME:			Short name of the structure.
+	"V26",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_21, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List11,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV27(
+	STRUCT_V27,
+	TXT_CIV27,						// NAME:			Short name of the structure.
+	"V27",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV28(
+	STRUCT_V28,
+	TXT_CIV28,						// NAME:			Short name of the structure.
+	"V28",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV29(
+	STRUCT_V29,
+	TXT_CIV29,						// NAME:			Short name of the structure.
+	"V29",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV30(
+	STRUCT_V30,
+	TXT_CIV30,						// NAME:			Short name of the structure.
+	"V30",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_21, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List11,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV31(
+	STRUCT_V31,
+	TXT_CIV31,						// NAME:			Short name of the structure.
+	"V31",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_21, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List11,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV32(
+	STRUCT_V32,
+	TXT_CIV32,						// NAME:			Short name of the structure.
+	"V32",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_21, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List11,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV33(
+	STRUCT_V33,
+	TXT_CIV33,						// NAME:			Short name of the structure.
+	"V33",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_21, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List11,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV34(
+	STRUCT_V34,
+	TXT_CIV34,						// NAME:			Short name of the structure.
+	"V34",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV35(
+	STRUCT_V35,
+	TXT_CIV35,						// NAME:			Short name of the structure.
+	"V35",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+static BuildingTypeClass const ClassV36(
+	STRUCT_V36,
+	TXT_CIV36,						// NAME:			Short name of the structure.
+	"V36",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+static BuildingTypeClass const ClassV37(
+	STRUCT_V37,
+	TXT_CIV37,						// NAME:			Short name of the structure.
+	"V37",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		true,							// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_42, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)ListWestwood,	// OCCUPYLIST:	List of active foundation squares.
+	(short const *)OListWestwood	// OVERLAPLIST:List of overlap cell offset.
+);
+static BuildingTypeClass const ClassMission(
+	STRUCT_MISSION,
+	TXT_CIVMISS,					// NAME:			Short name of the structure.
+	"MISS",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_32, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List32,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+// Sandbag wall
+static BuildingTypeClass const Sandbag(
+	STRUCT_SANDBAG_WALL,
+	TXT_SANDBAG_WALL,				// NAME:			Short name of the structure.
+	"SBAG",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_NONE,						// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		true,							// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		false,						// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+// Cyclone fence
+static BuildingTypeClass const Cyclone(
+	STRUCT_CYCLONE_WALL,
+	TXT_CYCLONE_WALL,				// NAME:			Short name of the structure.
+	"CYCL",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_NONE,						// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		true,							// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		false,						// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+// Brick wall
+static BuildingTypeClass const Brick(
+	STRUCT_BRICK_WALL,
+	TXT_BRICK_WALL,				// NAME:			Short name of the structure.
+	"BRIK",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_NONE,						// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		true,							// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		false,						// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+// Barbwire wall
+static BuildingTypeClass const Barbwire(
+	STRUCT_BARBWIRE_WALL,
+	TXT_BARBWIRE_WALL,			// NAME:			Short name of the structure.
+	"BARB",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_NONE,						// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		true,							// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		false,						// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+// Wood wall
+static BuildingTypeClass const Wood(
+	STRUCT_WOOD_WALL,
+	TXT_WOOD_WALL,					// NAME:			Short name of the structure.
+	"WOOD",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_NONE,						// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		true,							// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		false,						// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+static BuildingTypeClass const Fence(
+	STRUCT_FENCE,
+	TXT_FENCE,						// NAME:			Short name of the structure.
+	"FENC",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_NONE,						// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		true,							// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		false,						// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+
+
+#ifdef FIXIT_ANTS
+static BuildingTypeClass const ClassQueen(
+	STRUCT_QUEEN,
+	TXT_NONE,						// NAME:			Short name of the structure.
+	"QUEE",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(24,47),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		true,							// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		false,						// Simple (one frame) damage imagery?
+		false,						// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		false,						// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		true,							// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_21, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List11,		// OCCUPYLIST:	List of active foundation squares.
+	NULL								// OVERLAPLIST:List of overlap cell offset.
+);
+static BuildingTypeClass const ClassLarva1(
+	STRUCT_LARVA1,
+	TXT_NONE,						// NAME:			Short name of the structure.
+	"LAR1",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		true,							// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+static BuildingTypeClass const ClassLarva2(
+	STRUCT_LARVA2,
+	TXT_NONE,						// NAME:			Short name of the structure.
+	"LAR2",							// NAME:			Short name of the structure.
+	FACING_NONE,					// Foundation direction from center of building.
+	XYP_COORD(0,0),				// Exit point for produced units.
+	REMAP_ALTERNATE,				// Sidebar remap logic.
+	0x0000,							//	Vertical offset.
+	0x0000,							// Primary weapon offset along turret centerline.
+	0x0000,							// Primary weapon lateral offset along turret centerline.
+		false,						// Is this building a fake (decoy?)
+		false,						// Animation rate is regulated for constant speed?
+		true,							// Always use the given name for the building?
+		false,						// Is this a wall type structure?
+		true,							// Simple (one frame) damage imagery?
+		true,							// Is it invisible to radar?
+		true,							// Can the player select this?
+		true,							// Is this a legal target for attack or move?
+		true,							// Is this an insignificant building?
+		false,						// Theater specific graphic image?
+		false,						// Does it have a rotating turret?
+		false,						// Can the building be color remapped to indicate owner?
+	RTTI_NONE,						// The object type produced at this factory.
+	DIR_N,							// Starting idle frame to match construction.
+	BSIZE_11, 						// SIZE:			Building size.
+	NULL,								// Preferred exit cell list.
+	(short const *)List1,		// OCCUPYLIST:	List of active foundation squares.
+	(short const *)NULL			// OVERLAPLIST:List of overlap cell offset.
+);
+#endif
+void const * BuildingTypeClass::WarFactoryOverlay;
+void const * LightningShapes;
+
+
+/***********************************************************************************************
+ * BuildingTypeClass::BuildingTypeClass -- This is the constructor for the building types.     *
+ *                                                                                             *
+ *    This is the constructor used to create the building types.                               *
+ *                                                                                             *
+ * INPUT:   see below...                                                                       *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/29/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+BuildingTypeClass::BuildingTypeClass(
+						StructType type,
+						int name,
+						char const * ininame,
+						FacingType foundation,
+						COORDINATE exitpoint,
+						RemapType remap,
+						int verticaloffset,
+						int primaryoffset,
+						int primarylateral,
+						bool is_fake,
+						bool is_regulated,
+						bool is_nominal,
+						bool is_wall,
+						bool is_simpledamage,
+						bool is_stealthy,
+						bool is_selectable,
+						bool is_legal_target,
+						bool is_insignificant,
+						bool is_theater,
+						bool is_turret_equipped,
+						bool is_remappable,
+						RTTIType tobuild,
+						DirType sframe,
+						BSizeType size,
+						short const * exitlist,
+						short const * sizelist,
+						short const * overlap) :
+								TechnoTypeClass(RTTI_BUILDINGTYPE,
+													int(type),
+													name,
+													ininame,
+													remap,
+													verticaloffset,
+													primaryoffset,
+													primarylateral,
+													primaryoffset,
+													primarylateral,
+													is_nominal,
+													is_stealthy,
+													is_selectable,
+													is_legal_target,
+													is_insignificant,
+													false,
+													is_theater,
+													is_turret_equipped,
+													is_remappable,
+													true,
+													(is_turret_equipped ? 32 : 1),
+													SPEED_NONE),
+	IsBase(true),
+	IsFake(is_fake),
+	IsBibbed(false),
+	IsWall(is_wall),
+	IsSimpleDamage(is_simpledamage),
+	IsCaptureable(false),
+	IsRegulated(is_regulated),
+	IsPowered(false),
+	IsUnsellable(false),
+	FoundationFace(foundation),
+	Adjacent(1),
+	ToBuild(tobuild),
+	ExitCoordinate(exitpoint),
+	ExitList(exitlist),
+	Type(type),
+	StartFace(sframe),
+	Capacity(0),
+	Power(0),
+	Drain(0),
+	Size(size),
+	OccupyList(sizelist),
+	OverlapList(overlap),
+	BuildupData(0)
+{
+
+	Anims[BSTATE_CONSTRUCTION].Start = 0;
+	Anims[BSTATE_CONSTRUCTION].Count = 1;
+	Anims[BSTATE_CONSTRUCTION].Rate = 0;
+
+	Anims[BSTATE_IDLE].Start = 0;
+	Anims[BSTATE_IDLE].Count = 1;
+	Anims[BSTATE_IDLE].Rate = 0;
+
+	Anims[BSTATE_ACTIVE].Start = 0;
+	Anims[BSTATE_ACTIVE].Count = 1;
+	Anims[BSTATE_ACTIVE].Rate = 0;
+
+	Anims[BSTATE_AUX1].Start = 0;
+	Anims[BSTATE_AUX1].Count = 1;
+	Anims[BSTATE_AUX1].Rate = 0;
+
+	Anims[BSTATE_AUX2].Start = 0;
+	Anims[BSTATE_AUX2].Count = 1;
+	Anims[BSTATE_AUX2].Rate = 0;
+}
+
+
+/***********************************************************************************************
+ * BuildingTypeClass::operator new -- Allocates a building type object from the special heap.  *
+ *                                                                                             *
+ *    This routine will allocate a building type object from the special heap used just for    *
+ *    allocation of object of this type.                                                       *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with a pointer to the newly allocated object. If the allocation could not  *
+ *          succeed, then NULL will be returned.                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/06/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void * BuildingTypeClass::operator new(size_t)
+{
+	return(BuildingTypes.Alloc());
+}
+
+
+/***********************************************************************************************
+ * BuildingTypeClass::operator delete -- Deletes a building type object from the special heap. *
+ *                                                                                             *
+ *    This will delete a previously allocated building type object. The memory is returned     *
+ *    to the special heap that is used for that purpose.                                       *
+ *                                                                                             *
+ * INPUT:   ptr   -- Pointer to the building type object to return to the special heap.        *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/06/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BuildingTypeClass::operator delete(void * ptr)
+{
+	BuildingTypes.Free((BuildingTypeClass *)ptr);
+}
+
+
+/***********************************************************************************************
+ * BuildingTypeClass::Init_Heap -- Initialize the heap as necessary for the building type obje *
+ *                                                                                             *
+ *    This routine performs the necessary heap initializations. Since we know exactly what     *
+ *    building type objects will be needed, they are pre-allocated at this time.               *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   Call this routine only once.                                                    *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/06/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BuildingTypeClass::Init_Heap(void)
+{
+	/*
+	**	These building type class objects must be allocated in the exact order that they
+	**	are specified in the StructType enumeration. This is necessary because the heap
+	**	allocation block index serves double duty as the type number index.
+	*/
+	new BuildingTypeClass(ClassAdvancedTech);	// STRUCT_ADVANCED_TECH
+	new BuildingTypeClass(ClassIronCurtain);	// STRUCT_IRON_CURTAIN
+	new BuildingTypeClass(ClassWeapon);			//	STRUCT_WEAP
+	new BuildingTypeClass(ClassChronosphere);	// STRUCT_CHRONOSPHERE
+	new BuildingTypeClass(ClassPillbox);		//	STRUCT_PILLBOX
+	new BuildingTypeClass(ClassCamoPillbox);	//	STRUCT_CAMOPILLBOX
+	new BuildingTypeClass(ClassCommand);		//	STRUCT_RADAR
+	new BuildingTypeClass(ClassGapGenerator);	// STRUCT_GAP
+	new BuildingTypeClass(ClassTurret);			//	STRUCT_TURRET
+	new BuildingTypeClass(ClassAAGun);			// STRUCT_AAGUN
+	new BuildingTypeClass(ClassFlameTurret);	//	STRUCT_FLAME_TURRET
+	new BuildingTypeClass(ClassConst);			//	STRUCT_CONST
+	new BuildingTypeClass(ClassRefinery);		//	STRUCT_REFINERY
+	new BuildingTypeClass(ClassStorage);		//	STRUCT_STORAGE
+	new BuildingTypeClass(ClassHelipad);		//	STRUCT_HELIPAD
+	new BuildingTypeClass(ClassSAM);				//	STRUCT_SAM
+	new BuildingTypeClass(ClassAirStrip);		//	STRUCT_AIRSTRIP
+	new BuildingTypeClass(ClassPower);			//	STRUCT_POWER
+	new BuildingTypeClass(ClassAdvancedPower);//	STRUCT_ADVANCED_POWER
+	new BuildingTypeClass(ClassSovietTech);	// STRUCT_SOVIET_TECH
+	new BuildingTypeClass(ClassHospital);		//	STRUCT_HOSPITAL
+	new BuildingTypeClass(ClassBarracks);		//	STRUCT_BARRACKS
+	new BuildingTypeClass(ClassTent);			//	STRUCT_TENT
+	new BuildingTypeClass(ClassKennel);			// STRUCT_KENNEL
+	new BuildingTypeClass(ClassRepair);			//	STRUCT_REPAIR
+	new BuildingTypeClass(ClassBioLab);			//	STRUCT_BIO_LAB
+	new BuildingTypeClass(ClassMission);		//	STRUCT_MISSION
+	new BuildingTypeClass(ClassShipYard);		//	STRUCT_SHIP_YARD
+	new BuildingTypeClass(ClassSubPen);			//	STRUCT_SUB_PEN
+	new BuildingTypeClass(ClassMissileSilo);	// STRUCT_MSLO
+	new BuildingTypeClass(ClassForwardCom);	// STRUCT_FORWARD_COM
+	new BuildingTypeClass(ClassTesla);			//	STRUCT_TESLA
+	new BuildingTypeClass(ClassFakeWeapon);	// STRUCT_FAKEWEAP
+	new BuildingTypeClass(ClassFakeConst);		// STRUCT_FAKECONST
+	new BuildingTypeClass(ClassFakeShipYard);	// STRUCT_FAKE_YARD
+	new BuildingTypeClass(ClassFakeSubPen);	// STRUCT_FAKE_PEN
+	new BuildingTypeClass(ClassFakeCommand);	// STRUCT_FAKE_RADAR
+	new BuildingTypeClass(Sandbag);				// STRUCT_SANDBAG_WALL
+	new BuildingTypeClass(Cyclone);				//	STRUCT_CYCLONE_WALL
+	new BuildingTypeClass(Brick);					// STRUCT_BRICK_WALL
+	new BuildingTypeClass(Barbwire);				// STRUCT_BARBWIRE_WALL
+	new BuildingTypeClass(Wood);					//	STRUCT_WOOD_WALL
+	new BuildingTypeClass(Fence);					// STRUCT_FENCE
+	new BuildingTypeClass(ClassAVMine);			// STRUCT_AVMINE
+	new BuildingTypeClass(ClassAPMine);			// STRUCT_APMINE
+	new BuildingTypeClass(ClassV01);				//	STRUCT_V1
+	new BuildingTypeClass(ClassV02);				//	STRUCT_V2
+	new BuildingTypeClass(ClassV03);				//	STRUCT_V3
+	new BuildingTypeClass(ClassV04);				//	STRUCT_V4
+	new BuildingTypeClass(ClassV05);				//	STRUCT_V5
+	new BuildingTypeClass(ClassV06);				//	STRUCT_V6
+	new BuildingTypeClass(ClassV07);				//	STRUCT_V7
+	new BuildingTypeClass(ClassV08);				//	STRUCT_V8
+	new BuildingTypeClass(ClassV09);				//	STRUCT_V9
+	new BuildingTypeClass(ClassV10);				//	STRUCT_V10
+	new BuildingTypeClass(ClassV11);				//	STRUCT_V11
+	new BuildingTypeClass(ClassV12);				//	STRUCT_V12
+	new BuildingTypeClass(ClassV13);				//	STRUCT_V13
+	new BuildingTypeClass(ClassV14);				//	STRUCT_V14
+	new BuildingTypeClass(ClassV15);				//	STRUCT_V15
+	new BuildingTypeClass(ClassV16);				//	STRUCT_V16
+	new BuildingTypeClass(ClassV17);				//	STRUCT_V17
+	new BuildingTypeClass(ClassV18);				//	STRUCT_V18
+	new BuildingTypeClass(ClassV19);				//	STRUCT_PUMP
+	new BuildingTypeClass(ClassV20);				//	STRUCT_V20
+	new BuildingTypeClass(ClassV21);				//	STRUCT_V21
+	new BuildingTypeClass(ClassV22);				//	STRUCT_V22
+	new BuildingTypeClass(ClassV23);				//	STRUCT_V23
+	new BuildingTypeClass(ClassV24);				//	STRUCT_V24
+	new BuildingTypeClass(ClassV25);				//	STRUCT_V25
+	new BuildingTypeClass(ClassV26);				//	STRUCT_V26
+	new BuildingTypeClass(ClassV27);				//	STRUCT_V27
+	new BuildingTypeClass(ClassV28);				//	STRUCT_V28
+	new BuildingTypeClass(ClassV29);				//	STRUCT_V29
+	new BuildingTypeClass(ClassV30);				//	STRUCT_V30
+	new BuildingTypeClass(ClassV31);				//	STRUCT_V31
+	new BuildingTypeClass(ClassV32);				//	STRUCT_V32
+	new BuildingTypeClass(ClassV33);				//	STRUCT_V33
+	new BuildingTypeClass(ClassV34);				//	STRUCT_V34
+	new BuildingTypeClass(ClassV35);				//	STRUCT_V35
+	new BuildingTypeClass(ClassV36);				//	STRUCT_V36
+	new BuildingTypeClass(ClassV37);				//	STRUCT_V37
+	new BuildingTypeClass(ClassBarrel);			// STRUCT_BARREL
+	new BuildingTypeClass(ClassBarrel3);		// STRUCT_BARREL3
+
+#ifdef FIXIT_ANTS
+	new BuildingTypeClass(ClassQueen);			// STRUCT_QUEEN
+	new BuildingTypeClass(ClassLarva1);			// STRUCT_LARVA1
+	new BuildingTypeClass(ClassLarva2);			// STRUCT_LARVA2
+#endif
+
+}
+
+
+/***********************************************************************************************
+ * BuildingTypeClass::One_Time -- Performs special one time action for buildings.              *
+ *                                                                                             *
+ *    This routine is used to do the one time action necessary to handle building type class   *
+ *    objects. This entails loading of the building shapes and the brain file used by          *
+ *    buildings.                                                                               *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   This routine should only be called ONCE.                                        *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/28/1994 JLB : Created.                                                                 *
+ *   06/11/1994 JLB : Updated construction time and frame count logic.                         *
+ *=============================================================================================*/
+void BuildingTypeClass::One_Time(void)
+{
+	static const struct {
+		StructType	Class;			// Building class number.
+		BStateType	Stage;			// Animation sequence to assign animation range to.
+		int			Start;			// Starting frame number.
+		int			Length;			// Number of frames (-1 means use all frames).
+		int			Rate;				// Rate of animation.
+	} _anims[] = {
+		{STRUCT_CHRONOSPHERE,	BSTATE_IDLE,	0, 4, 3},	// idling
+		{STRUCT_CHRONOSPHERE,	BSTATE_ACTIVE,	4, 16,3},	// charging up and activating
+		{STRUCT_MSLO,				BSTATE_IDLE,	0, 0, 0},
+		{STRUCT_MSLO,				BSTATE_ACTIVE,	0, 5, 2},	// door opening
+		{STRUCT_MSLO,				BSTATE_AUX1,	4, 1, 0},	// door held open
+		{STRUCT_MSLO,				BSTATE_AUX2,	5, 3, 2},	// door closing
+		{STRUCT_CAMOPILLBOX,		BSTATE_ACTIVE,	0,	2, 1},
+		{STRUCT_GAP,				BSTATE_IDLE,	0,	32,3},
+		{STRUCT_AIRSTRIP,			BSTATE_IDLE,	0,	0,	0},
+		{STRUCT_AIRSTRIP,			BSTATE_AUX1,	0,	8,	3},
+		{STRUCT_BARRACKS,			BSTATE_ACTIVE,	0,	10,3},
+		{STRUCT_BARRACKS,			BSTATE_IDLE,	0,	10,3},
+		{STRUCT_TENT,				BSTATE_ACTIVE,	0,	10,3},
+		{STRUCT_TENT,				BSTATE_IDLE,	0,	10,3},
+#ifdef FIXIT_ANTS
+		{STRUCT_QUEEN,				BSTATE_IDLE,	0,	10,3},
+#endif
+		{STRUCT_CONST,				BSTATE_ACTIVE,	0,	26,3},
+		{STRUCT_FAKECONST,		BSTATE_ACTIVE,	0,	26,3},
+		{STRUCT_HELIPAD,			BSTATE_ACTIVE,	0,	7,	4},
+		{STRUCT_HELIPAD,			BSTATE_IDLE,	0,	0,	0},
+		{STRUCT_HOSPITAL,			BSTATE_IDLE,	0,	4,	3},
+		{STRUCT_PUMP,				BSTATE_IDLE,	0,	14,4},
+		{STRUCT_REPAIR,			BSTATE_ACTIVE,	0,	7,	2},
+		{STRUCT_REPAIR,			BSTATE_IDLE,	0,	1,	0},
+		{STRUCT_V20,				BSTATE_IDLE,	0,	3,	3},
+		{STRUCT_V21,				BSTATE_IDLE,	0,	3,	3},
+		{STRUCT_V22,				BSTATE_IDLE,	0,	3,	3},
+		{STRUCT_V23,				BSTATE_IDLE,	0,	3,	3},
+		{STRUCT_WEAP,				BSTATE_ACTIVE,	0,	1,	0},
+		{STRUCT_WEAP,				BSTATE_IDLE,	0,	1,	0},
+		{STRUCT_FAKEWEAP,			BSTATE_ACTIVE,	0,	1,	0},
+		{STRUCT_FAKEWEAP,			BSTATE_IDLE,	0,	1,	0},
+		{STRUCT_IRON_CURTAIN,	BSTATE_ACTIVE,	0,	11,3},
+		{STRUCT_TESLA,				BSTATE_ACTIVE,	0,	10,2},
+	};
+
+	for (StructType sindex = STRUCT_FIRST; sindex < STRUCT_COUNT; sindex++) {
+		char	fullname[_MAX_FNAME+_MAX_EXT];
+		char	buffer[_MAX_FNAME];
+		BuildingTypeClass const & building = As_Reference(sindex);
+		/*
+		**	Fetch the sidebar cameo image for this building.
+		*/
+		if (building.Level != -1) {
+//		if (building.IsBuildable) {
+			sprintf(buffer, "%sICON", building.Graphic_Name());
+
+			if (building.IsFake) {
+				buffer[3] = 'F';
+			}
+
+			_makepath(fullname, NULL, NULL, buffer, ".SHP");
+			((void const *&)building.CameoData) = MFCD::Retrieve(fullname);
+		}
+
+		/*
+		**	Fetch the construction animation for this building.
+		*/
+		sprintf(buffer, "%sMAKE", building.Graphic_Name());
+		_makepath(fullname, NULL, NULL, buffer, ".SHP");
+		void const * dataptr;
+		dataptr = MFCD::Retrieve(fullname);
+		((void const *&)building.BuildupData) = dataptr;
+		if (dataptr != NULL) {
+			int timedelay = 1;
+			int count = Get_Build_Frame_Count(dataptr);
+			if (count > 0) {
+				timedelay = (Rule.BuildupTime * TICKS_PER_MINUTE) / count;
+			}
+			building.Init_Anim(BSTATE_CONSTRUCTION, 0, count, timedelay);
+		}
+
+		/*
+		**	Fetch the normal game shape for this building.
+		*/
+		_makepath(fullname, NULL, NULL, building.Graphic_Name(), ".SHP");
+		((void const *&)building.ImageData) = MFCD::Retrieve(fullname);
+	}
+
+	// Try to load weap2.shp and tesla coil's lightning shapes
+	char fullname[_MAX_FNAME+_MAX_EXT];
+	_makepath(fullname, NULL, NULL, (char const *)"WEAP2",".SHP");
+	WarFactoryOverlay = MFCD::Retrieve(fullname);
+	_makepath(fullname, NULL, NULL, (char const *)"LITNING",".SHP");
+	LightningShapes = MFCD::Retrieve(fullname);
+
+	/*
+	**	Install all the special animation sequences for the different building types.
+	*/
+	for (unsigned index = 0; index < (sizeof(_anims) / sizeof(_anims[0])); index++) {
+		As_Reference(_anims[index].Class).Init_Anim(_anims[index].Stage, _anims[index].Start, _anims[index].Length, _anims[index].Rate);
+	}
+
+}
+
+
+/***********************************************************************************************
+ * Struct_From_Name -- Find BData structure from its name.                                     *
+ *                                                                                             *
+ *    This routine will convert an ASCII name for a building class into                        *
+ *    the actual building class it represents.                                                 *
+ *                                                                                             *
+ * INPUT:   name  -- ASCII representation of a building class.                                 *
+ *                                                                                             *
+ * OUTPUT:  Returns with the actual building class number that the string                      *
+ *          represents.                                                                        *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   10/07/1992 JLB : Created.                                                                 *
+ *   05/02/1994 JLB : Converted to member function.                                            *
+ *=============================================================================================*/
+StructType BuildingTypeClass::From_Name(char const * name)
+{
+	if (name != NULL) {
+		for (StructType classid = STRUCT_FIRST; classid < STRUCT_COUNT; classid++) {
+			if (stricmp(As_Reference(classid).IniName, name) == 0) {
+				return(classid);
+			}
+		}
+	}
+	return(STRUCT_NONE);
+}
+
+
+#ifdef SCENARIO_EDITOR
+/***********************************************************************************************
+ * BuildingTypeClass::Display -- Renders a generic view of building.                           *
+ *                                                                                             *
+ *    This routine is used to display a generic representation of the                          *
+ *    building. Typical use of this occurs with the scenario editor.                           *
+ *                                                                                             *
+ * INPUT:   x,y      -- Coordinate to display the building (centered).                         *
+ *                                                                                             *
+ *          window   -- The window the building should be rendered                             *
+ *                      relative to.                                                           *
+ *                                                                                             *
+ *          house    -- The house color to use for the building.                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/23/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BuildingTypeClass::Display(int x, int y, WindowNumberType window, HousesType ) const
+{
+	void const * ptr = Get_Cameo_Data();
+	if (ptr == NULL) {
+		IsTheaterShape = IsTheater;
+		ptr = Get_Image_Data();
+	}
+	CC_Draw_Shape(ptr, 0, x, y, window, SHAPE_CENTER|SHAPE_WIN_REL);
+	IsTheaterShape = false;
+}
+
+
+/***********************************************************************************************
+ * BuildingTypeClass::Prep_For_Add -- Prepares scenario editor for adding a                    *
+ *                                                                                             *
+ *    This routine is used to prepare the scenario editor for the addition                     *
+ *    of a building object to the game.                                                        *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/23/1994 JLB : Created.                                                                 *
+ *   06/04/1994 JLB : Uses map editing interface routines.                                     *
+ *=============================================================================================*/
+void BuildingTypeClass::Prep_For_Add(void)
+{
+	for (StructType index = STRUCT_FIRST; index < STRUCT_COUNT; index++) {
+		if (As_Reference(index).Get_Image_Data()) {
+			Map.Add_To_List(&As_Reference(index));
+		}
+	}
+}
+#endif
+
+
+/***********************************************************************************************
+ * BuildingTypeClass::Create_And_Place -- Creates and places a building object onto the map.   *
+ *                                                                                             *
+ *    This routine is used by the scenario editor to create and place buildings on the map.    *
+ *                                                                                             *
+ * INPUT:   cell     -- The cell that the building is to be placed upon.                       *
+ *                                                                                             *
+ *          house    -- The owner of the building.                                             *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the building successfully created and placed on the map?                 *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/28/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool BuildingTypeClass::Create_And_Place(CELL cell, HousesType house) const
+{
+	BuildingClass * ptr;
+
+	ptr = new BuildingClass(Type, house);
+	if (ptr != NULL) {
+		return(ptr->Unlimbo(Cell_Coord(cell), DIR_N));
+	}
+	return(false);
+}
+
+
+/***********************************************************************************************
+ * BuildingTypeClass::Create_One_Of -- Creates a building of this type.                        *
+ *                                                                                             *
+ *    This routine will create a building object of this type. The building object is in a     *
+ *    limbo state. It is presumed that the building object will be unlimboed at the correct    *
+ *    place and time. Typical use is when the building is created in a factory situation       *
+ *    and will be placed on the map when construction completes.                               *
+ *                                                                                             *
+ * INPUT:   house -- Pointer to the house that is to be the owner of the building.             *
+ *                                                                                             *
+ * OUTPUT:  Returns with a pointer to the building. If the building could not be created       *
+ *          then a NULL is returned.                                                           *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/07/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+ObjectClass * BuildingTypeClass::Create_One_Of(HouseClass * house) const
+{
+	HousesType htype = HOUSE_NEUTRAL;
+	if (house != NULL) {
+		htype = house->Class->House;
+	}
+	return(new BuildingClass(Type, htype));
+}
+
+
+/***********************************************************************************************
+ * BuildingTypeClass::Init_Anim -- Initialize an animation control for a building.             *
+ *                                                                                             *
+ *    This routine will initialize one animation control element for a                         *
+ *    specified building. This modifies a "const" class and thus must                          *
+ *    perform some strategic casting to get away with this.                                    *
+ *                                                                                             *
+ * INPUT:   state -- The animation state to apply these data values to.                        *
+ *                                                                                             *
+ *          start -- Starting frame for the building's animation.                              *
+ *                                                                                             *
+ *          count -- The number of frames in this animation.                                   *
+ *                                                                                             *
+ *          rate  -- The countdown timer between animation frames.                             *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   04/18/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BuildingTypeClass::Init_Anim(BStateType state, int start, int count, int rate) const
+{
+	((int &)Anims[state].Start) = start;
+	((int &)Anims[state].Count) = count;
+	((int &)Anims[state].Rate) = rate;
+}
+
+
+/***********************************************************************************************
+ * BuildingTypeClass::Init -- Performs theater specific initialization.                        *
+ *                                                                                             *
+ *    This routine is used to perform any initialization that is custom per theater.           *
+ *    Typically, this is fetching the building shape data for those building types that have   *
+ *    theater specific art.                                                                    *
+ *                                                                                             *
+ * INPUT:   theater  -- The theater to base this initialization on.                            *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   01/21/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BuildingTypeClass::Init(TheaterType theater)
+{
+	if (theater != LastTheater) {
+		char fullname[_MAX_FNAME+_MAX_EXT];
+
+		for (StructType sindex = STRUCT_FIRST; sindex < STRUCT_COUNT; sindex++) {
+			BuildingTypeClass const * classptr = &As_Reference(sindex);
+
+			if (classptr->IsTheater) {
+				_makepath(fullname, NULL, NULL, classptr->Graphic_Name(), Theaters[theater].Suffix);
+				((void const *&)classptr->ImageData) = MFCD::Retrieve(fullname);
+
+				/*
+				**	Buildup data is probably theater specific as well. Fetch a pointer to the
+				**	data at this time as well.
+				*/
+				sprintf(fullname, "%sMAKE.%s", classptr->Graphic_Name(), Theaters[theater].Suffix);
+				((void const *&)classptr->BuildupData) = MFCD::Retrieve(fullname);
+				if (classptr->BuildupData) {
+					int timedelay = 1;
+					int count = Get_Build_Frame_Count(classptr->BuildupData);
+					if (count != 0) {
+						timedelay = (5 * TICKS_PER_SECOND) / count;
+					}
+					classptr->Init_Anim(BSTATE_CONSTRUCTION, 0, count, timedelay);
+				}
+			}
+		}
+	}
+}
+
+
+/***********************************************************************************************
+ * BuildingTypeClass::Dimensions -- Fetches the pixel dimensions of the building.              *
+ *                                                                                             *
+ *    This routine will fetch the dimensions of the building (in pixels). These dimensions are *
+ *    used to render the selection rectangle and the health bar.                               *
+ *                                                                                             *
+ * INPUT:   width    -- Reference to the pixel width (to be filled in).                        *
+ *                                                                                             *
+ *          height   -- Reference to the pixel height (to be filled in).                       *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   01/23/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BuildingTypeClass::Dimensions(int &width, int &height) const
+{
+	width = Width() * ICON_PIXEL_W;
+	width -= (width/5);
+	height = Height() * ICON_PIXEL_H;
+	height -= (height/5);
+}
+
+
+/***********************************************************************************************
+ * BuildingTypeClass::As_Reference -- Fetches reference to the building type specified.        *
+ *                                                                                             *
+ *    This routine will fetch a reference to the BuildingTypeClass as indicated by the         *
+ *    building type number specified.                                                          *
+ *                                                                                             *
+ * INPUT:   type  -- The building type number to convert into a BuildingTypeClass reference.   *
+ *                                                                                             *
+ * OUTPUT:  Returns with a reference to the building type class as indicated by the            *
+ *          parameter.                                                                         *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   01/23/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+BuildingTypeClass & BuildingTypeClass::As_Reference(StructType type)
+{
+	return(*BuildingTypes.Ptr(type));
+}
+
+
+/***********************************************************************************************
+ * BuildingTypeClass::Occupy_List -- Fetches the occupy list for the building.                 *
+ *                                                                                             *
+ *    Use this routine to fetch the occupy list pointer for the building. The occupy list is   *
+ *    used to determine what cells the building occupies and thus precludes other buildings    *
+ *    or objects from using.                                                                   *
+ *                                                                                             *
+ * 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 list to be used to determine what cells    *
+ *          this building occupies.                                                            *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   01/23/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+short const * BuildingTypeClass::Occupy_List(bool placement) const
+{
+	SmudgeType bib = SMUDGE_NONE;
+	CELL cell=0;
+
+	if (placement && Bib_And_Offset(bib, cell)) {
+
+		SmudgeTypeClass const & smudge = SmudgeTypeClass::As_Reference(bib);
+		static short _list[25];
+		short * dest = &_list[0];
+
+		/*
+		**	Copy the bib overlap list into the working buffer.
+		*/
+		short const * src = smudge.Occupy_List();
+		while (*src != REFRESH_EOL) {
+			*dest++ = (*src++) + cell;
+		}
+
+		/*
+		**	Append the building occupy list to this working buffer.
+		*/
+		src = OccupyList;
+		while (src && *src != REFRESH_EOL) {
+			*dest++ = *src++;
+		}
+		*dest = REFRESH_EOL;
+
+		return(&_list[0]);
+	}
+
+	if (OccupyList != NULL) {
+		return(OccupyList);
+	}
+
+	static short const _templap[] = {REFRESH_EOL};
+	return(&_templap[0]);
+}
+
+
+/***********************************************************************************************
+ * BuildingTypeClass::Overlap_List -- Fetches the overlap list for the building.               *
+ *                                                                                             *
+ *    This routine will fetch the overlap list for the building. The overlap list is used      *
+ *    to determine what cells the building's graphics cover, but is not considered to occupy   *
+ *    for movement purposes.                                                                   *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with a pointer to the cell offset list that is used to determine the       *
+ *          cells that this building overlaps.                                                 *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   01/23/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+short const * BuildingTypeClass::Overlap_List(void) const
+{
+	if (OverlapList != NULL) {
+		return(OverlapList);
+	}
+
+	static short const _templap[] = {REFRESH_EOL};
+	return(&_templap[0]);
+}
+
+
+/***********************************************************************************************
+ * BuildingTypeClass::Width -- Determines width of building in icons.                          *
+ *                                                                                             *
+ *    Use this routine to determine the width of the building type in icons.                   *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the building width in icons.                                          *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   02/23/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+int BuildingTypeClass::Width(void) const
+{
+	static int width[BSIZE_COUNT] = {
+		1,
+		2,
+		1,
+		2,
+		2,
+		3,
+		3,
+		4,
+		5
+	};
+	return(width[Size]);
+}
+
+
+/***********************************************************************************************
+ * BuildingTypeClass::Height -- Determines the height of the building in icons.                *
+ *                                                                                             *
+ *    Use this routine to find the height of the building in icons.                            *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the building height in icons.                                         *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   02/23/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+int BuildingTypeClass::Height(bool bib) const
+{
+	static int height[BSIZE_COUNT] = {
+		1,
+		1,
+		2,
+		2,
+		3,
+		2,
+		3,
+		2,
+		5
+	};
+	return(height[Size] + ((bib && IsBibbed) ? 1 : 0));
+}
+
+
+/***********************************************************************************************
+ * BuildingTypeClass::Bib_And_Offset -- Determines the bib and appropriate cell offset.        *
+ *                                                                                             *
+ *    This routine is used to determine what (if any) bib should be used for this building     *
+ *    and also the cell offset for the upper left corner of the bib smudge type.               *
+ *                                                                                             *
+ * INPUT:   bib   -- Reference to the bib that should be used for this building.               *
+ *                                                                                             *
+ *          cell  -- The cell offset for the upper left corner of the bib. This offset is      *
+ *                   relative to the upper left corner of the building.                        *
+ *                                                                                             *
+ * OUTPUT:  Is a bib required for this building? If the result is true, then the correct       *
+ *          bib and cell offset will be filled in.                                             *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/23/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool BuildingTypeClass::Bib_And_Offset(SmudgeType & bib, CELL & cell) const
+{
+	bib = SMUDGE_NONE;
+
+	if (IsBibbed) {
+		switch (Width()) {
+			case 2:
+				bib = SMUDGE_BIB3;
+				break;
+
+			case 3:
+				bib = SMUDGE_BIB2;
+				break;
+
+			case 4:
+				bib = SMUDGE_BIB1;
+				break;
+
+			default:
+				bib = SMUDGE_NONE;
+				break;
+		}
+
+		/*
+		**	Adjust the bib position for special buildings that have the bib as part
+		**	of the building art itself.
+		*/
+		if (bib != SMUDGE_NONE) {
+			cell += ((Height()-1)*MAP_CELL_W);
+		}
+	}
+	return(bib != SMUDGE_NONE);
+}
+
+
+/***********************************************************************************************
+ * BuildingTypeClass::Max_Pips -- Determines the maximum pips to display.                      *
+ *                                                                                             *
+ *    Use this routine to determine the maximum number of pips to display on this building     *
+ *    when it is rendered. Typically, this is the tiberium capacity divided by 100.            *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the number of pips to display on this building when selected.         *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/29/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+int BuildingTypeClass::Max_Pips(void) const
+{
+	int maxpips = (Width() * ICON_PIXEL_W) / 4;
+	return(Bound((int)(Capacity/100), 0, maxpips));
+}
+
+
+/***********************************************************************************************
+ * BuildingTypeClass::Raw_Cost -- Fetches the raw (base) cost of this building type.           *
+ *                                                                                             *
+ *    This routine is used to fetch the real raw base cost of the building. The raw cost       *
+ *    is the cost of the building less any free unit that would come with the building         *
+ *    if it were built in the normal fashion. Specifically, the helicopter cost is subtracted  *
+ *    from the helipad and the harvester cost is subtracted from the refinery. This cost       *
+ *    is used for refunding.                                                                   *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns the raw (base) cost to build the building of this type.                    *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   09/21/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+int BuildingTypeClass::Raw_Cost(void) const
+{
+	int cost = TechnoTypeClass::Raw_Cost();
+
+	if (Type == STRUCT_HELIPAD && !Rule.IsSeparate) {
+		cost -= (AircraftTypeClass::As_Reference(AIRCRAFT_HIND).Cost + AircraftTypeClass::As_Reference(AIRCRAFT_HIND).Cost)/2;
+	}
+	if (Type == STRUCT_REFINERY) {
+		cost -= UnitTypeClass::As_Reference(UNIT_HARVESTER).Cost;
+	}
+	return(cost);
+}
+
+
+/***********************************************************************************************
+ * BuildingTypeClass::Cost_Of -- Fetches the cost of this building.                            *
+ *                                                                                             *
+ *    This routine will fetch the cost to build the building of this type.                     *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the cost to produce this building.                                    *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   09/21/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+int BuildingTypeClass::Cost_Of(void) const
+{
+	if (Rule.IsSeparate && Type == STRUCT_HELIPAD) {
+		return(Raw_Cost());
+	}
+	return(TechnoTypeClass::Cost_Of());
+}
+
+
+/***********************************************************************************************
+ * BuildingTypeClass::Flush_For_Placement -- Tries to clear placement area for this building t *
+ *                                                                                             *
+ *    This routine is called when a clear space for placement is desired at the cell location  *
+ *    specified. Typical use of this routine is by the computer when it wants to build up      *
+ *    its base.                                                                                *
+ *                                                                                             *
+ * INPUT:   cell  -- The cell that the building of this type would like to be placed down at.  *
+ *                                                                                             *
+ *          house -- Pointer to the house that want to clear the foundation zone.              *
+ *                                                                                             *
+ * OUTPUT:  Placement is temporarily blocked, please try again later?                          *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   09/27/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool BuildingTypeClass::Flush_For_Placement(CELL cell, HouseClass * house)  const
+{
+	bool again = false;
+	if (cell > 0) {
+		short const * list = Occupy_List(true);
+
+		while (*list != REFRESH_EOL) {
+			CELL newcell = cell + *list++;
+
+			if (Map.In_Radar(newcell)) {
+				TechnoClass * occupier = Map[newcell].Cell_Techno();
+				if (occupier != NULL) {
+					again = true;
+					if (occupier->House->Is_Ally(house) && occupier->Is_Foot() && !Target_Legal(((FootClass *)occupier)->NavCom)) {
+						Map[newcell].Incoming(0, true);
+					} else {
+//						Base_Is_Attacked(occupier);
+					}
+				}
+			}
+		}
+	}
+	return(again);
+}
+
+
+/***********************************************************************************************
+ * BuildingTypeClass::Read_INI -- Fetch building type data from the INI database.              *
+ *                                                                                             *
+ *    This routine will fetch the building type class data from the INI database file.         *
+ *                                                                                             *
+ * INPUT:   ini   -- Reference to the INI database that will be examined.                      *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the building entry found and the data extracted?                         *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/19/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool BuildingTypeClass::Read_INI(CCINIClass & ini)
+{
+	if (TechnoTypeClass::Read_INI(ini)) {
+		Speed = ini.Get_Bool(Name(), "WaterBound", (Speed == SPEED_FLOAT)) ? SPEED_FLOAT : SPEED_NONE;
+		Capacity = ini.Get_Int(Name(), "Storage", Capacity);
+		Adjacent = ini.Get_Int(Name(), "Adjacent", Adjacent);
+		IsCaptureable = ini.Get_Bool(Name(), "Capturable", IsCaptureable);
+		IsPowered = ini.Get_Bool(Name(), "Powered", IsPowered);
+		IsBibbed = ini.Get_Bool(Name(), "Bib", IsBibbed);
+		IsUnsellable = ini.Get_Bool(Name(), "Unsellable", IsUnsellable);
+		IsBase = ini.Get_Bool(Name(), "BaseNormal", IsBase);
+		Power = ini.Get_Int(Name(), "Power", (Power > 0) ? Power : -Drain);
+		if (Power < 0) {
+			Drain = -Power;
+			Power = 0;
+		}
+		return(true);
+	}
+	return(false);
+}
+
+
+/***********************************************************************************************
+ * BuildingTypeClass::Coord_Fixup -- Adjusts coordinate to be legal for assignment.            *
+ *                                                                                             *
+ *    This routine will adjust the specified coordinate so that it will be legal for assignment*
+ *    to this building. All buildings are given a coordinate that is in the upper left corner  *
+ *    of a cell. This routine will drop the fractional component of the coordinate.            *
+ *                                                                                             *
+ * INPUT:   coord -- The coordinate to fixup into a legal to assign value.                     *
+ *                                                                                             *
+ * OUTPUT:  Returns with a coordinate that can be assigned to the building.                    *
+ *                                                                                             *
+ * WARNINGS:   The coordinate is not examined to see if the cell is legal for placing the      *
+ *             building. It merely adjusts the coordinate so that is legal at first glance.    *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/14/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+COORDINATE BuildingTypeClass::Coord_Fixup(COORDINATE coord) const
+{
+	return Coord_Whole(coord);
+}
+
+
+/***********************************************************************************************
+ * BuildingTypeClass::Full_Name -- Fetches the name to give this building.                     *
+ *                                                                                             *
+ *    This routine will return the displayable given name for this building type. Normally,    *
+ *    this is the official name as well, however in the case of civilian buildings, the        *
+ *    name will just be "Civilian Building" unless special options are in place.               *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the text number of the building type.                                 *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   10/02/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+int BuildingTypeClass::Full_Name(void) const
+{
+	if (Debug_Map || Rule.IsNamed || *this < STRUCT_V01 || *this > STRUCT_V37) {
+		return(TechnoTypeClass::Full_Name());
+	}
+	return(TXT_CIVILIAN_BUILDING);
+}

+ 167 - 0
CODE/BENCH.CPP

@@ -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 - 0
CODE/BENCH.H

@@ -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 - 0
CODE/BFILE.MAK

@@ -0,0 +1,2122 @@
+#
+#	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\bfile.mav   5.0   11 Nov 1996 09:40:38   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 : MAKEFILE                                 *
+#*                                                                         *
+#*                   Programmer : Joe L. Bostic                            *
+#*                                                                         *
+#*                   Start Date : March 25, 1993                           *
+#*                                                                         *
+#*                  Last Update : March 25, 1993   [JLB]                   *
+#*                                                                         *
+#*-------------------------------------------------------------------------*
+
+
+# Comment out the following line to disable "include file autodependency".
+.AUTODEPEND
+#.SWAP
+
+!include	"rules.mak"
+
+
+##########################################################################
+
+MAPFILES = \
+
+CACHEMAP = \
+	BRIEFING.AUD \
+	BAR3RED.SHP \
+	BAR3BLU.SHP \
+	COUNTRYA.SHP \
+	COUNTRYE.SHP \
+	CREDSA.SHP \
+	CREDSU.SHP \
+	HISCORE1.SHP \
+	HISCORE2.SHP \
+	TIME.SHP \
+	CLOCK1.AUD \
+	COUNTRY4.AUD \
+	MAPWIPE2.AUD \
+	MAPWIPE5.AUD \
+	TONEY10.AUD \
+	TONEY4.AUD \
+	TONEY7.AUD \
+	SFX4.AUD \
+	BEEPY6.AUD \
+	KEYSTROK.AUD \
+	APPEAR1.AUD \
+	SCOLD1.AUD \
+	COUNTRY1.AUD \
+	ALI-TRAN.WSA \
+	SOV-TRAN.WSA \
+	ALIBACKH.PCX \
+	SOVBACKH.PCX \
+	BAR3RHR.SHP \
+	BAR3BHR.SHP \
+	CREDSAHR.SHP \
+	CREDSUHR.SHP \
+	HISC1-HR.SHP \
+	HISC2-HR.SHP \
+	TIMEHR.SHP \
+	MLTIPLYR.WSA \
+
+LOCALFILES = \
+	PROLOG.CPS \
+	MAP.AUD \
+	TITLE.CPS \
+	PALETTE.CPS \
+	INTRO.AUD \
+	EGOPAL.PAL \
+	RULES.INI \
+	CREDITS.TXT \
+	ALIPAPER.CPS \
+	3POINT.FNT \
+	8POINT.FNT \
+	EDITFNT.FNT \
+	CONQUER.ENG \
+	DEBUG.ENG \
+	LED.FNT \
+	SNOW.PAL \
+	TEMPERAT.PAL \
+	INTERIOR.PAL \
+	VCR.FNT \
+	HOLE0000.LUT \
+	HOLE0001.LUT \
+	HOLE0002.LUT \
+	HOLE0003.LUT \
+	HOLE0004.LUT \
+	HOLE0005.LUT \
+	HOLE0006.LUT \
+	HOLE0007.LUT \
+	HOLE0008.LUT \
+	HOLE0009.LUT \
+	HOLE0010.LUT \
+	HOLE0011.LUT \
+	HOLE0012.LUT \
+	HOLE0013.LUT \
+	HOLE0014.LUT \
+	HOLE0015.LUT \
+	HOLE0016.LUT \
+	HOLE0017.LUT \
+	HOLE0018.LUT \
+	HOLE0019.LUT \
+	HOLE0020.LUT \
+	HOLE0021.LUT \
+	HOLE0022.LUT \
+	HOLE0023.LUT \
+	HOLE0024.LUT \
+	HOLE0025.LUT \
+	HOLE0026.LUT \
+	HOLE0027.LUT \
+	HOLE0028.LUT \
+	HOLE0029.LUT \
+	HOLE0030.LUT \
+	HOLE0031.LUT \
+	HOLE0032.LUT \
+	HOLE0033.LUT \
+	HOLE0034.LUT \
+	HOLE0035.LUT \
+	HOLE0036.LUT \
+	HOLE0037.LUT \
+	HOLE0038.LUT \
+	HOLE0039.LUT \
+	HOLE0040.LUT \
+	HOLE0041.LUT \
+	HOLE0042.LUT \
+	HOLE0043.LUT \
+	HOLE0044.LUT \
+	HOLE0045.LUT \
+	HOLE0046.LUT \
+	HOLE0047.LUT \
+#	TEMPSCOR.FNT \
+#	6POINT.FNT \
+#	GRAD6FNT.FNT \
+#	SCOREFNT.FNT \
+
+
+# Files that have counterparts in both high and low resolutions.
+# These files will be built into the HIRES.MIX and LORES.MIX files.
+HILORES = \
+	TRANICON.SHP \
+	PIPS.SHP \
+	PULSE.SHP \
+	ATOMICON.SHP \
+	WARPICON.SHP \
+	C1.SHP \
+	C2.SHP \
+	CHAN.SHP \
+	DELPHI.SHP \
+	E1.SHP \
+	E2.SHP \
+	E3.SHP \
+	E4.SHP \
+	E5.SHP \
+	E6.SHP \
+	E7.SHP \
+	EINSTEIN.SHP \
+	GNRL.SHP \
+	MEDI.SHP \
+	SPY.SHP \
+	THF.SHP \
+	DD-BKGND.SHP \
+	DD-BOTM.SHP \
+	DD-CRNR.SHP \
+	DD-EDGE.SHP \
+	DD-LEFT.SHP \
+	DD-RIGHT.SHP \
+	DD-TOP.SHP \
+	12METFNT.FNT \
+	GRAD6FNT.FNT \
+	HELP.FNT \
+	6POINT.FNT \
+	TYPE.FNT \
+	SCOREFNT.FNT \
+	1TNKICON.SHP \
+	2TNKICON.SHP \
+	3TNKICON.SHP \
+	4TNKICON.SHP \
+	AFLDICON.SHP \
+	AGUNICON.SHP \
+	APCICON.SHP \
+	APWRICON.SHP \
+	ARTYICON.SHP \
+	ATEKICON.SHP \
+	BADRICON.SHP \
+	BARRICON.SHP \
+	BRIKICON.SHP \
+	BTN-DN.SHP \
+	BTN-PL.SHP \
+	BTN-ST.SHP \
+	BTN-UP.SHP \
+	CAICON.SHP \
+	CAMICON.SHP \
+	CLOCK.SHP \
+	DDICON.SHP \
+	DOGICON.SHP \
+	DOMEICON.SHP \
+	DOMFICON.SHP \
+	E1ICON.SHP \
+	E2ICON.SHP \
+	E3ICON.SHP \
+	E4ICON.SHP \
+	E6ICON.SHP \
+	E7ICON.SHP \
+	FACFICON.SHP \
+	FACTICON.SHP \
+	FENCICON.SHP \
+	FIXICON.SHP \
+	FTURICON.SHP \
+	GAPICON.SHP \
+	GPSSICON.SHP \
+	GUNICON.SHP \
+	HARVICON.SHP \
+	HBOXICON.SHP \
+	HELIICON.SHP \
+	HINDICON.SHP \
+	HPADICON.SHP \
+	INFXICON.SHP \
+	IRONICON.SHP \
+	JEEPICON.SHP \
+	KENNICON.SHP \
+	LSTICON.SHP \
+	MAP.SHP \
+	MCVICON.SHP \
+	MEDIICON.SHP \
+	MGGICON.SHP \
+	MIGICON.SHP \
+	MNLYICON.SHP \
+	MOUSE.SHP \
+	MRJICON.SHP \
+	MSLOICON.SHP \
+	NATORADR.SHP \
+	PBMBICON.SHP \
+	PBOXICON.SHP \
+	PDOXICON.SHP \
+	PINFICON.SHP \
+	POWER.SHP \
+	POWERBAR.SHP \
+	POWRICON.SHP \
+	PROCICON.SHP \
+	PTICON.SHP \
+	REPAIR.SHP \
+	SAMICON.SHP \
+	SBAGICON.SHP \
+	SELL.SHP \
+	SIDEBAR.SHP \
+	SILOICON.SHP \
+	SMIGICON.SHP \
+	SONRICON.SHP \
+	SOVPAPER.CPS \
+	SPEFICON.SHP \
+	SPENICON.SHP \
+	SPYICON.SHP \
+	SSICON.SHP \
+	STEKICON.SHP \
+	STRIP.SHP \
+	STRIPDN.SHP \
+	STRIPUP.SHP \
+	SYRDICON.SHP \
+	SYRFICON.SHP \
+	TABS.SHP \
+	TENTICON.SHP \
+	THFICON.SHP \
+	TRUKICON.SHP \
+	TSLAICON.SHP \
+	U2ICON.SHP \
+	USSRRADR.SHP \
+	V2RLICON.SHP \
+	WEAFICON.SHP \
+	WEAPICON.SHP \
+	YAKICON.SHP \
+	NRADRFRM.SHP \
+	URADRFRM.SHP \
+	SIDE1NA.SHP \
+	SIDE1US.SHP \
+	SIDE2NA.SHP \
+	SIDE2US.SHP \
+	SIDE3NA.SHP \
+	SIDE3US.SHP \
+	STRIPNA.SHP \
+	STRIPUS.SHP \
+
+#	MOEBICON.SHP \
+
+HILORES1 = \
+	MECH.SHP \
+	SHOK.SHP \
+	CARRICON.SHP \
+	CTNKICON.SHP \
+	DTRKICON.SHP \
+	MECHICON.SHP \
+	MSUBICON.SHP \
+	QTNKICON.SHP \
+	SHOKICON.SHP \
+	STNKICON.SHP \
+	TTNKICON.SHP \
+
+# These helper macros substitute the extension so that
+# the appropriate art build rule will be invoked.
+xLOHILORES = $(HILORES:.SHP=.LOW)
+LOHILORES = $(xLOHILORES:.FNT=.LNT)
+xHIHILORES = $(HILORES:.SHP=.HI)
+HIHILORES = $(xHIHILORES:.FNT=.HNT)
+
+xLOHILORES1 = $(HILORES1:.SHP=.LOW)
+LOHILORES1 = $(xLOHILORES1:.FNT=.LNT)
+xHIHILORES1 = $(HILORES1:.SHP=.HI)
+HIHILORES1 = $(xHIHILORES1:.FNT=.HNT)
+
+#
+# Files required for hires/Win95 version only
+#
+# This mix file is cached
+#
+HIRESFILES = \
+	ALIPAPER.PCX \
+      	PROLOG.PCX \
+	SOVPAPER.PCX \
+	AFTR_HI.PCX \
+	ALY1.PCX \
+	APC_HI.PCX \
+	APHI0049.PCX \
+	BNHI0020.PCX \
+	DCHI0040.PCX \
+	FRHI0166.PCX \
+	LAB.PCX \
+	LANDSBRG.PCX \
+	MAHI0107.PCX \
+	MIG_HI.PCX \
+	MTFACTHI.PCX \
+	NEEDLE.PCX \
+	SOV2.PCX \
+	SPY.PCX \
+	STALIN.PCX \
+	TENT.PCX \
+#	ENG_HI.PCX \
+
+
+CONQUERFILES = \
+	PARABOMB.SHP \
+	RADARFRM.SHP \
+	ARMOR.SHP \
+	FPOWER.SHP \
+	SPEED.SHP \
+	TQUAKE.SHP \
+	H2O_EXP1.SHP \
+	H2O_EXP2.SHP \
+	H2O_EXP3.SHP \
+	FLAK.SHP \
+	EBTN-DN.SHP \
+	EBTN-UP.SHP \
+	ATOMSFX.SHP \
+	TWINKLE1.SHP \
+	TWINKLE2.SHP \
+	TWINKLE3.SHP \
+	CHRONBOX.SHP \
+	GPSBOX.SHP \
+	INVULBOX.SHP \
+	PARABOX.SHP \
+	SONARBOX.SHP \
+	SPUTNIK.SHP \
+	SPUTDOOR.SHP \
+	ATOMICDN.SHP \
+	ATOMICUP.SHP \
+	TYPE.FNT \
+	120MM.SHP \
+	1TNK.SHP \
+	2TNK.SHP \
+	3TNK.SHP \
+	4TNK.SHP \
+	50CAL.SHP \
+	AFLD.SHP \
+	AGUN.SHP \
+	APC.SHP \
+	APWR.SHP \
+	ART-EXP1.SHP \
+	ARTY.SHP \
+	ATEK.SHP \
+	BADR.SHP \
+	BARB.SHP \
+	BARL.SHP \
+	BARR.SHP \
+	BIO.SHP \
+	BOMB.SHP \
+	BOMBLET.SHP \
+	BRIK.SHP \
+	BRL3.SHP \
+	BURN-L.SHP \
+	BURN-M.SHP \
+	BURN-S.SHP \
+	CA.SHP \
+	CYCL.SHP \
+	DD.SHP \
+	DEVIATOR.SHP \
+	DOG.SHP \
+	DOGBULLT.SHP \
+	DOLLAR.SHP \
+	DOME.SHP \
+	DRAGON.SHP \
+	EARTH.SHP \
+	ELECTDOG.SHP \
+	EMPULSE.SHP \
+	FACT.SHP \
+	FB1.SHP \
+	FB2.SHP \
+	FBALL1.SHP \
+	FCOM.SHP \
+	FENC.SHP \
+	FIRE1.SHP \
+	FIRE2.SHP \
+	FIRE3.SHP \
+	FIRE4.SHP \
+	FIX.SHP \
+	FLAGFLY.SHP \
+	FLMSPT.SHP \
+	FPLS.SHP \
+	FRAG1.SHP \
+	FTNK.SHP \
+	FTUR.SHP \
+	GAP.SHP \
+	GUN.SHP \
+	GUNFIRE.SHP \
+	HARV.SHP \
+	HELI.SHP \
+	HIND.SHP \
+	HOSP.SHP \
+	HPAD.SHP \
+	INVUN.SHP \
+	IRON.SHP \
+	JEEP.SHP \
+	KENN.SHP \
+	LITNING.SHP \
+	LROTOR.SHP \
+	LST.SHP \
+	MCV.SHP \
+	MGG.SHP \
+	MGUN.SHP \
+	MHQ.SHP \
+	MIG.SHP \
+	MINE.SHP \
+	MINIGUN.SHP \
+	MINP.SHP \
+	MINV.SHP \
+	MISS.SHP \
+	MISSILE.SHP \
+	MISSILE2.SHP \
+	MLRS.SHP \
+	MNLY.SHP \
+	MRJ.SHP \
+	NAPALM1.SHP \
+	NAPALM2.SHP \
+	NAPALM3.SHP \
+	ORCA.SHP \
+	PARACH.SHP \
+	PATRIOT.SHP \
+	PBOX.SHP \
+	PDOX.SHP \
+	PIFF.SHP \
+	PIFFPIFF.SHP \
+	POWR.SHP \
+	PROC.SHP \
+	PT.SHP \
+	RAPID.SHP \
+	RROTOR.SHP \
+	SAM.SHP \
+	SAMFIRE.SHP \
+	SBAG.SHP \
+	SCRATE.SHP \
+	SELECT.SHP \
+	SHADOW.SHP \
+	SILO.SHP \
+	SMIG.SHP \
+	SMOKEY.SHP \
+	SMOKE_M.SHP \
+	SMOKLAND.SHP \
+	SPEN.SHP \
+	SS.SHP \
+	SSAM.SHP \
+	STEALTH2.SHP \
+	STEK.SHP \
+	STNK.SHP \
+	SYRD.SHP \
+	TENT.SHP \
+	TRAN.SHP \
+	TRANS.ICN \
+	TRUK.SHP \
+	TSLA.SHP \
+	TURR.SHP \
+	U2.SHP \
+	V19.SHP \
+	V2.SHP \
+	V2RL.SHP \
+	VEH-HIT1.SHP \
+	VEH-HIT2.SHP \
+	VEH-HIT3.SHP \
+	WAKE.SHP \
+	WCRATE.SHP \
+	WWCRATE.SHP \
+	WEAP.SHP \
+	WEAP2.SHP \
+	WOOD.SHP \
+	YAK.SHP \
+	AFLDMAKE.SHP \
+	AGUNMAKE.SHP \
+	APWRMAKE.SHP \
+	ATEKMAKE.SHP \
+	BARRMAKE.SHP \
+	BIOMAKE.SHP \
+	DOMEMAKE.SHP \
+	FACTMAKE.SHP \
+	FIXMAKE.SHP \
+	FTURMAKE.SHP \
+	GAPMAKE.SHP \
+	GUNMAKE.SHP \
+	HOSPMAKE.SHP \
+	HPADMAKE.SHP \
+	IRONMAKE.SHP \
+	KENNMAKE.SHP \
+	MINPMAKE.SHP \
+	MINVMAKE.SHP \
+	PBOXMAKE.SHP \
+	POWRMAKE.SHP \
+	PDOXMAKE.SHP \
+	PROCMAKE.SHP \
+	PUMPMAKE.SHP \
+	SAMMAKE.SHP \
+	SILOMAKE.SHP \
+	SPENMAKE.SHP \
+	STEKMAKE.SHP \
+	SYRDMAKE.SHP \
+	TENTMAKE.SHP \
+	TSLAMAKE.SHP \
+	WEAPMAKE.SHP \
+
+GENERALMAPFILES = \
+	MISSIONS.PKT \
+	CSTRIKE.PKT \
+	TUTORIAL.INI \
+        SCG01EA.INI \     
+        SCG40EA.INI \     
+        SCG41EA.INI \     
+        SCG42EA.INI \     
+        SCG43EA.INI \     
+        SCG44EA.INI \     
+        SCG45EA.INI \     
+        SCG46EA.INI \     
+        SCG47EA.INI \     
+        SCG48EA.INI \     
+        SCU40EA.INI \     
+        SCU41EA.INI \     
+        SCU42EA.INI \     
+        SCU43EA.INI \     
+        SCU44EA.INI \     
+        SCU45EA.INI \     
+        SCU46EA.INI \     
+        SCU47EA.INI \     
+        SCU48EA.INI \     
+	SCU01EA.INI \     
+	SCM01EA.INI \      
+	SCM02EA.INI \ 
+	SCM03EA.INI \ 
+	SCM04EA.INI \ 
+	SCM05EA.INI \ 
+	SCM06EA.INI \ 
+	SCM07EA.INI \ 
+	SCM08EA.INI \ 
+	SCM09EA.INI \ 
+	SCM10EA.INI \ 
+	SCM11EA.INI \ 
+	SCM12EA.INI \ 
+	SCM13EA.INI \ 
+	SCM14EA.INI \ 
+	SCM15EA.INI \ 
+	SCM16EA.INI \ 
+	SCM17EA.INI \ 
+	SCM18EA.INI \ 
+	SCM19EA.INI \ 
+	SCM20EA.INI \ 
+	SCM21EA.INI \ 
+	SCM22EA.INI \ 
+	SCM23EA.INI \ 
+	SCM24EA.INI \ 
+	SCMD0EA.INI \
+	SCMD1EA.INI \
+	SCMD2EA.INI \
+	SCMD3EA.INI \
+	SCMD4EA.INI \
+	SCMD5EA.INI \
+	SCMD6EA.INI \
+	SCMD7EA.INI \
+	SCMD8EA.INI \
+	SCMD9EA.INI \
+	SCME0EA.INI \
+	SCME1EA.INI \
+	SCME2EA.INI \
+	SCME3EA.INI \
+	SCME4EA.INI \
+	SCME5EA.INI \
+	SCME6EA.INI \
+	SCME7EA.INI \
+	SCME8EA.INI \
+	SCME9EA.INI \
+	SCMF0EA.INI \
+	SCMF1EA.INI \
+	SCMF2EA.INI \
+	SCMF3EA.INI \
+	SCMF4EA.INI \
+	SCMF5EA.INI \
+	SCMF6EA.INI \
+	SCMF7EA.INI \
+	SCMF8EA.INI \
+	SCMF9EA.INI \
+	SCMG0EA.INI \
+	SCMG1EA.INI \
+	SCMG2EA.INI \
+	SCMG3EA.INI \
+	SCMG4EA.INI \
+	SCMG5EA.INI \
+	SCMG6EA.INI \
+	SCMG7EA.INI \
+	SCMG8EA.INI \
+	SCMG9EA.INI \
+	SCMH0EA.INI \
+	SCMH1EA.INI \
+	SCMH2EA.INI \
+	SCMH3EA.INI \
+	SCMH4EA.INI \
+	SCMH5EA.INI \
+	SCMH6EA.INI \
+	SCMH7EA.INI \
+	SCMH8EA.INI \
+	SCMH9EA.INI \
+	SCMI0EA.INI \
+	SCMI1EA.INI \
+	SCMI2EA.INI \
+	SCMI3EA.INI \
+	SCMI4EA.INI \
+	SCMI5EA.INI \
+	SCMI6EA.INI \
+	SCMI7EA.INI \
+	SCMI8EA.INI \
+	SCMI9EA.INI \
+	SCMJ0EA.INI \
+	SCMJ1EA.INI \
+	SCMJ2EA.INI \
+	SCMJ3EA.INI \
+	SCMJ4EA.INI \
+	SCMJ5EA.INI \
+	SCMJ6EA.INI \
+	SCMJ7EA.INI \
+	SCMJ8EA.INI \
+	SCMJ9EA.INI \
+	SCMK0EA.INI \
+	SCMK1EA.INI \
+	SCMK2EA.INI \
+	SCMK3EA.INI \
+	SCMK4EA.INI \
+	SCMK5EA.INI \
+	SCMK6EA.INI \
+	SCMK7EA.INI \
+	SCMK8EA.INI \
+	SCMK9EA.INI \
+	SCML0EA.INI \
+	SCML1EA.INI \
+	SCML2EA.INI \
+	SCML3EA.INI \
+	SCML4EA.INI \
+	SCML5EA.INI \
+	SCML6EA.INI \
+	SCML7EA.INI \
+	SCML8EA.INI \
+	SCML9EA.INI \
+	SCMM0EA.INI \
+	SCMM1EA.INI \
+	SCMM2EA.INI \
+	SCMM3EA.INI \
+	SCMM4EA.INI \
+	SCMM5EA.INI \
+	SCMM6EA.INI \
+	SCMM7EA.INI \
+	SCMM8EA.INI \
+	SCMM9EA.INI \
+      	SCM25EA.INI \
+	SCM26EA.INI \
+	SCM27EA.INI \
+	SCM28EA.INI \
+	SCM29EA.INI \
+	SCM30EA.INI \
+	SCM31EA.INI \ 
+	SCM32EA.INI \ 
+	SCM33EA.INI \
+	SCM34EA.INI \
+     	SCM35EA.INI \
+	SCM36EA.INI \
+	SCM37EA.INI \
+	SCM38EA.INI \
+	SCM39EA.INI \
+	SCM40EA.INI \
+	SCM41EA.INI \
+	SCM42EA.INI \
+	SCM43EA.INI \
+	SCM44EA.INI \
+	SCM45EA.INI \
+	SCM46EA.INI \
+	SCM47EA.INI \
+	SCM48EA.INI \
+	SCM49EA.INI \
+	SCM50EA.INI \
+	SCM51EA.INI \
+	SCM52EA.INI \
+	SCM53EA.INI \
+	SCM54EA.INI \
+	SCM55EA.INI \
+	SCM56EA.INI \
+	SCM57EA.INI \
+	SCM58EA.INI \
+	SCM59EA.INI \
+	SCM60EA.INI \
+	SCM61EA.INI \
+	SCM62EA.INI \
+	SCM63EA.INI \
+	SCM64EA.INI \
+	SCM65EA.INI \
+	SCM66EA.INI \
+	SCM67EA.INI \
+	SCM68EA.INI \
+	SCM69EA.INI \
+	SCM70EA.INI \
+	SCM71EA.INI \
+	SCM72EA.INI \
+	SCM73EA.INI \
+	SCM74EA.INI \
+	SCM75EA.INI \
+	SCM76EA.INI \
+	SCM77EA.INI \
+	SCM78EA.INI \
+	SCM79EA.INI \
+	SCM80EA.INI \
+	SCM81EA.INI \
+	SCM82EA.INI \
+	SCM83EA.INI \
+	SCM84EA.INI \
+	SCM85EA.INI \
+	SCM86EA.INI \
+	SCM87EA.INI \
+	SCM88EA.INI \
+	SCM89EA.INI \	
+	SCM90EA.INI \
+	SCM91EA.INI \
+	SCM92EA.INI \
+	SCM93EA.INI \
+	SCM94EA.INI \
+	SCM95EA.INI \
+	SCM96EA.INI \
+	SCM97EA.INI \
+	SCM98EA.INI \
+	SCM99EA.INI \
+	SCM100EA.INI \
+	SCM101EA.INI \
+	SCM102EA.INI \
+	SCM103EA.INI \
+	SCM104EA.INI \
+	SCM105EA.INI \
+	SCM106EA.INI \
+	SCM107EA.INI \
+	SCM108EA.INI \
+	SCM109EA.INI \
+	SCM110EA.INI \
+	SCM111EA.INI \
+	SCM112EA.INI \
+	SCM113EA.INI \
+	SCM114EA.INI \
+	SCM115EA.INI \
+	SCM116EA.INI \
+	SCM117EA.INI \
+	SCM118EA.INI \
+ 	SCM119EA.INI \    
+	SCM120EA.INI \     
+	SCM121EA.INI \    
+	SCM122EA.INI \     
+	SCM123EA.INI \    
+	SCM124EA.INI \    
+	SCM125EA.INI \    
+	SCM126EA.INI \    
+	SCM127EA.INI \    
+	SCM128EA.INI \    
+	SCM129EA.INI \ 
+	SCM130EA.INI \   
+
+NETMAPFILES = \
+
+# Files that aren't cached.
+GENERALFILES = \
+	AFTR_LO.CPS \
+	ALY1-LO.CPS \
+	APC_LO.CPS \
+	APLO0049.CPS \
+	BNLO0020.CPS \
+	DCLO0040.CPS \
+	FRLO0166.CPS \
+	LAB-LO.CPS \
+	LANDS-LO.CPS \
+	MALO0107.CPS \
+	MIG_LO.CPS \
+	MTFACTLO.CPS \
+	NEEDL-LO.CPS \
+	SOV2-LO.CPS \
+	SPY-LO.CPS \
+	STALN-LO.CPS \
+	TENT-LO.CPS \
+	TITLE.CPS \
+	PPAPER.CPS \
+	MSAA.WSA \
+	MSAB.WSA \
+	MSAC.WSA \
+	MSAD.WSA \
+	MSAE.WSA \
+	MSAF.WSA \
+	MSAG.WSA \
+	MSAH.WSA \
+	MSAI.WSA \
+	MSAJ.WSA \
+	MSAK.WSA \
+	MSAL.WSA \
+	MSAM.WSA \
+	MSAN.WSA \
+	MSSA.WSA \
+	MSSB.WSA \
+	MSSC.WSA \
+	MSSD.WSA \
+	MSSE.WSA \
+	MSSF.WSA \
+	MSSG.WSA \
+	MSSH.WSA \
+	MSSI.WSA \
+	MSSJ.WSA \
+	MSSK.WSA \
+	MSSL.WSA \
+	MSSM.WSA \
+	MSSN.WSA \
+
+INTERIORFILES = \
+	BOXES01.INT \
+	BOXES02.INT \
+	BOXES03.INT \
+	BOXES04.INT \
+	BOXES05.INT \
+	BOXES06.INT \
+	BOXES07.INT \
+	BOXES08.INT \
+	BOXES09.INT \
+	XTRA0001.INT \
+	XTRA0002.INT \
+	XTRA0003.INT \
+	XTRA0004.INT \
+	XTRA0005.INT \
+	XTRA0006.INT \
+	XTRA0007.INT \
+	XTRA0008.INT \
+	XTRA0009.INT \
+	XTRA0010.INT \
+	XTRA0011.INT \
+	XTRA0012.INT \
+	XTRA0013.INT \
+	XTRA0014.INT \
+	XTRA0015.INT \
+	XTRA0016.INT \
+	CLEAR1.INT \
+	MOVEFLSH.INT \
+	ARRO0001.INT \
+	ARRO0002.INT \
+	ARRO0003.INT \
+	ARRO0004.INT \
+	ARRO0005.INT \
+	ARRO0006.INT \
+	ARRO0007.INT \
+	ARRO0008.INT \
+	ARRO0009.INT \
+	ARRO0010.INT \
+	ARRO0011.INT \
+	ARRO0012.INT \
+	ARRO0013.INT \
+	ARRO0014.INT \
+	ARRO0015.INT \
+	FLOR0001.INT \
+	FLOR0002.INT \
+	FLOR0003.INT \
+	FLOR0004.INT \
+	FLOR0005.INT \
+	FLOR0006.INT \
+	FLOR0007.INT \
+	GFLR0001.INT \
+	GFLR0002.INT \
+	GFLR0003.INT \
+	GFLR0004.INT \
+	GFLR0005.INT \
+	GSTR0001.INT \
+	GSTR0002.INT \
+	GSTR0003.INT \
+	GSTR0004.INT \
+	GSTR0005.INT \
+	GSTR0006.INT \
+	GSTR0007.INT \
+	GSTR0008.INT \
+	GSTR0009.INT \
+	GSTR0010.INT \
+	GSTR0011.INT \
+	LWAL0001.INT \
+	LWAL0002.INT \
+	LWAL0003.INT \
+	LWAL0004.INT \
+	LWAL0005.INT \
+	LWAL0006.INT \
+	LWAL0007.INT \
+	LWAL0008.INT \
+	LWAL0009.INT \
+	LWAL0010.INT \
+	LWAL0011.INT \
+	LWAL0012.INT \
+	LWAL0013.INT \
+	LWAL0014.INT \
+	LWAL0015.INT \
+	LWAL0016.INT \
+	LWAL0017.INT \
+	LWAL0018.INT \
+	LWAL0019.INT \
+	LWAL0020.INT \
+	LWAL0021.INT \
+	LWAL0022.INT \
+	LWAL0023.INT \
+	LWAL0024.INT \
+	LWAL0025.INT \
+	LWAL0026.INT \
+	LWAL0027.INT \
+	STRP0001.INT \
+	STRP0002.INT \
+	STRP0003.INT \
+	STRP0004.INT \
+	STRP0005.INT \
+	STRP0006.INT \
+	STRP0007.INT \
+	STRP0008.INT \
+	STRP0009.INT \
+	STRP0010.INT \
+	STRP0011.INT \
+	WALL0001.INT \
+	WALL0002.INT \
+	WALL0003.INT \
+	WALL0004.INT \
+	WALL0005.INT \
+	WALL0006.INT \
+	WALL0007.INT \
+	WALL0008.INT \
+	WALL0009.INT \
+	WALL0010.INT \
+	WALL0011.INT \
+	WALL0012.INT \
+	WALL0013.INT \
+	WALL0014.INT \
+	WALL0015.INT \
+	WALL0016.INT \
+	WALL0017.INT \
+	WALL0018.INT \
+	WALL0019.INT \
+	WALL0020.INT \
+	WALL0021.INT \
+	WALL0022.INT \
+	WALL0023.INT \
+	WALL0024.INT \
+	WALL0025.INT \
+	WALL0026.INT \
+	WALL0027.INT \
+	WALL0028.INT \
+	WALL0029.INT \
+	WALL0030.INT \
+	WALL0031.INT \
+	WALL0032.INT \
+	WALL0033.INT \
+	WALL0034.INT \
+	WALL0035.INT \
+	WALL0036.INT \
+	WALL0037.INT \
+	WALL0038.INT \
+	WALL0039.INT \
+	WALL0040.INT \
+	WALL0041.INT \
+	WALL0042.INT \
+	WALL0043.INT \
+	WALL0044.INT \
+	WALL0045.INT \
+	WALL0046.INT \
+	WALL0047.INT \
+	WALL0048.INT \
+	WALL0049.INT \
+
+# Both the temperate and snow sets have identical template entries.
+TEMPERATEFILES = \
+	MINE.TEM \
+	ICE01.TEM \
+	ICE02.TEM \
+	ICE03.TEM \
+	ICE04.TEM \
+	ICE05.TEM \
+	MOVEFLSH.TEM \
+	BR1X.TEM \
+	BR2X.TEM \
+	BRIDGE1X.TEM \
+	BRIDGE2X.TEM \
+	BRIDGE1H.TEM \
+	BRIDGE2H.TEM \
+	F01.TEM \
+	F02.TEM \
+	F03.TEM \
+	F04.TEM \
+	F05.TEM \
+	F06.TEM \
+	ELECTRO.TEM \
+	B1.TEM \
+	B2.TEM \
+	B3.TEM \
+	BIB1.TEM \
+	BIB2.TEM \
+	BIB3.TEM \
+	BR1A.TEM \
+	BR1B.TEM \
+	BR1C.TEM \
+	BR2A.TEM \
+	BR2B.TEM \
+	BR2C.TEM \
+	BR3A.TEM \
+	BR3B.TEM \
+	BR3C.TEM \
+	BR3D.TEM \
+	BR3E.TEM \
+	BR3F.TEM \
+	BRIDGE1.TEM \
+	BRIDGE1D.TEM \
+	BRIDGE2.TEM \
+	BRIDGE2D.TEM \
+	CLEAR1.TEM \
+	CORPSE1.TEM \
+	CORPSE2.TEM \
+	CORPSE3.TEM \
+	CR1.TEM \
+	CR2.TEM \
+	CR3.TEM \
+	CR4.TEM \
+	CR5.TEM \
+	CR6.TEM \
+	D01.TEM \
+	D02.TEM \
+	D03.TEM \
+	D04.TEM \
+	D05.TEM \
+	D06.TEM \
+	D07.TEM \
+	D08.TEM \
+	D09.TEM \
+	D10.TEM \
+	D11.TEM \
+	D12.TEM \
+	D13.TEM \
+	D14.TEM \
+	D15.TEM \
+	D16.TEM \
+	D17.TEM \
+	D18.TEM \
+	D19.TEM \
+	D20.TEM \
+	D21.TEM \
+	D22.TEM \
+	D23.TEM \
+	D24.TEM \
+	D25.TEM \
+	D26.TEM \
+	D27.TEM \
+	D28.TEM \
+	D29.TEM \
+	D30.TEM \
+	D31.TEM \
+	D32.TEM \
+	D33.TEM \
+	D34.TEM \
+	D35.TEM \
+	D36.TEM \
+	D37.TEM \
+	D38.TEM \
+	D39.TEM \
+	D40.TEM \
+	D41.TEM \
+	D42.TEM \
+	D43.TEM \
+	D44.TEM \
+	D45.TEM \
+	FALLS1.TEM \
+	FALLS1A.TEM \
+	FALLS2.TEM \
+	FALLS2A.TEM \
+	FORD1.TEM \
+	FORD2.TEM \
+	GEM01.TEM \
+	GEM02.TEM \
+	GEM03.TEM \
+	GEM04.TEM \
+	GOLD01.TEM \
+	GOLD02.TEM \
+	GOLD03.TEM \
+	GOLD04.TEM \
+	HBOX.TEM \
+	MSLOMAKE.TEM \
+	HBOXMAKE.TEM \
+	MSLO.TEM \
+	P01.TEM \
+	P02.TEM \
+	P03.TEM \
+	P04.TEM \
+	P07.TEM \
+	P08.TEM \
+	P13.TEM \
+	P14.TEM \
+	RC01.TEM \
+	RC02.TEM \
+	RC03.TEM \
+	RC04.TEM \
+	RF01.TEM \
+	RF02.TEM \
+	RF03.TEM \
+	RF04.TEM \
+	RF05.TEM \
+	RF06.TEM \
+	RF07.TEM \
+	RF08.TEM \
+	RF09.TEM \
+	RF10.TEM \
+	RF11.TEM \
+	RV01.TEM \
+	RV02.TEM \
+	RV03.TEM \
+	RV04.TEM \
+	RV05.TEM \
+	RV06.TEM \
+	RV07.TEM \
+	RV08.TEM \
+	RV09.TEM \
+	RV10.TEM \
+	RV11.TEM \
+	RV12.TEM \
+	RV13.TEM \
+	RV14.TEM \
+	RV15.TEM \
+	S01.TEM \
+	S02.TEM \
+	S03.TEM \
+	S04.TEM \
+	S05.TEM \
+	S06.TEM \
+	S07.TEM \
+	S08.TEM \
+	S09.TEM \
+	S10.TEM \
+	S11.TEM \
+	S12.TEM \
+	S13.TEM \
+	S14.TEM \
+	S15.TEM \
+	S16.TEM \
+	S17.TEM \
+	S18.TEM \
+	S19.TEM \
+	S20.TEM \
+	S21.TEM \
+	S22.TEM \
+	S23.TEM \
+	S24.TEM \
+	S25.TEM \
+	S26.TEM \
+	S27.TEM \
+	S28.TEM \
+	S29.TEM \
+	S30.TEM \
+	S31.TEM \
+	S32.TEM \
+	S33.TEM \
+	S34.TEM \
+	S35.TEM \
+	S36.TEM \
+	S37.TEM \
+	S38.TEM \
+	SC1.TEM \
+	SC2.TEM \
+	SC3.TEM \
+	SC4.TEM \
+	SC5.TEM \
+	SC6.TEM \
+	SH01.TEM \
+	SH02.TEM \
+	SH03.TEM \
+	SH04.TEM \
+	SH05.TEM \
+	SH06.TEM \
+	SH07.TEM \
+	SH08.TEM \
+	SH09.TEM \
+	SH10.TEM \
+	SH11.TEM \
+	SH12.TEM \
+	SH13.TEM \
+	SH14.TEM \
+	SH15.TEM \
+	SH16.TEM \
+	SH17.TEM \
+	SH18.TEM \
+	SH19.TEM \
+	SH20.TEM \
+	SH21.TEM \
+	SH22.TEM \
+	SH23.TEM \
+	SH24.TEM \
+	SH25.TEM \
+	SH26.TEM \
+	SH27.TEM \
+	SH28.TEM \
+	SH29.TEM \
+	SH30.TEM \
+	SH31.TEM \
+	SH32.TEM \
+	SH33.TEM \
+	SH34.TEM \
+	SH35.TEM \
+	SH36.TEM \
+	SH37.TEM \
+	SH38.TEM \
+	SH39.TEM \
+	SH40.TEM \
+	SH41.TEM \
+	SH42.TEM \
+	SH43.TEM \
+	SH44.TEM \
+	SH45.TEM \
+	SH46.TEM \
+	SH47.TEM \
+	SH48.TEM \
+	SH49.TEM \
+	SH50.TEM \
+	SH51.TEM \
+	SH52.TEM \
+	SH53.TEM \
+	SH54.TEM \
+	SH55.TEM \
+	SH56.TEM \
+	T01.TEM \
+	T02.TEM \
+	T03.TEM \
+	T05.TEM \
+	T06.TEM \
+	T07.TEM \
+	T08.TEM \
+	T10.TEM \
+	T11.TEM \
+	T12.TEM \
+	T13.TEM \
+	T14.TEM \
+	T15.TEM \
+	T16.TEM \
+	T17.TEM \
+	TC01.TEM \
+	TC02.TEM \
+	TC03.TEM \
+	TC04.TEM \
+	TC05.TEM \
+	V01.TEM \
+	V02.TEM \
+	V03.TEM \
+	V04.TEM \
+	V05.TEM \
+	V06.TEM \
+	V07.TEM \
+	V08.TEM \
+	V09.TEM \
+	V10.TEM \
+	V11.TEM \
+	V12.TEM \
+	V13.TEM \
+	V14.TEM \
+	V15.TEM \
+	V16.TEM \
+	V17.TEM \
+	V18.TEM \
+	W1.TEM \
+	W2.TEM \
+	WC01.TEM \
+	WC02.TEM \
+	WC03.TEM \
+	WC04.TEM \
+	WC05.TEM \
+	WC06.TEM \
+	WC07.TEM \
+	WC08.TEM \
+	WC09.TEM \
+	WC10.TEM \
+	WC11.TEM \
+	WC12.TEM \
+	WC13.TEM \
+	WC14.TEM \
+	WC15.TEM \
+	WC16.TEM \
+	WC17.TEM \
+	WC18.TEM \
+	WC19.TEM \
+	WC20.TEM \
+	WC21.TEM \
+	WC22.TEM \
+	WC23.TEM \
+	WC24.TEM \
+	WC25.TEM \
+	WC26.TEM \
+	WC27.TEM \
+	WC28.TEM \
+	WC29.TEM \
+	WC30.TEM \
+	WC31.TEM \
+	WC32.TEM \
+	WC33.TEM \
+	WC34.TEM \
+	WC35.TEM \
+	WC36.TEM \
+	WC37.TEM \
+	WC38.TEM \
+
+# Every temperate theater terrain file has a snow theater counterpart.
+SNOWFILES = $(TEMPERATEFILES:.TEM=.SNO)
+
+# Sound effects (Juvenile or Adult)
+SFX = \
+
+# Generic wave files (never changes).
+WAVFILES = \
+	AACANON3.AUD \
+	BEEPSLCT.AUD \
+	BLEEP11.AUD \
+	BLEEP12.AUD \
+	BLEEP13.AUD \
+	BLEEP17.AUD \
+	BLEEP5.AUD \
+	BLEEP6.AUD \
+	BLEEP9.AUD \
+	BOMBIT1.AUD \
+	BUILD5.AUD \
+	BUZZY1.AUD \       
+	CANNON1.AUD \
+	CANNON2.AUD \
+	CASHDN1.AUD \
+	CASHTURN.AUD \
+	CASHUP1.AUD \
+	CHRONO2.AUD \
+	CHROTNK1.AUD \
+	CHUTE1.AUD \
+	CMON1.AUD \
+	CRMBLE2.AUD \
+	DEDMAN1.AUD \
+	DEDMAN10.AUD \
+	DEDMAN2.AUD \
+	DEDMAN3.AUD \
+	DEDMAN4.AUD \
+	DEDMAN5.AUD \
+	DEDMAN6.AUD \
+	DEDMAN7.AUD \
+	DEDMAN8.AUD \
+	DOGG5P.AUD \
+	DOGW3PX.AUD \
+	DOGW5.AUD \
+	DOGW6.AUD \
+	DOGW7.AUD \
+	DOGY1.AUD \
+	EAFFIRM1.AUD \
+	EENGIN1.AUD \
+	EINAH1.AUD \
+	EINOK1.AUD \
+	EINYES1.AUD \
+	EMOVOUT1.AUD \
+	EYESSIR1.AUD \
+	FIREBL3.AUD \
+	FIRETRT1.AUD \
+	FIXIT1.AUD \
+	GIRLOKAY.AUD \
+	GIRLYEAH.AUD \
+	GOTIT1.AUD \
+	GRENADE1.AUD \
+	GUN11.AUD \
+	GUN13.AUD \
+	GUN27.AUD \
+	GUN5.AUD \
+	GUYOKAY1.AUD \
+	GUYYEAH1.AUD \
+	H2OBOMB2.AUD \
+	HEAL2.AUD \
+	HYDROD1.AUD \
+	INVUL2.AUD \
+	IRONCUR9.AUD \
+	JBURN1.AUD \
+	JCHRGE1.AUD \
+	JCRISP1.AUD \
+	JDANCE1.AUD \
+	JJUICE1.AUD \
+	JJUMP1.AUD \
+	JLIGHT1.AUD \
+	JPOWER1.AUD \
+	JSHOCK1.AUD \
+	JYES1.AUD \
+	KABOOM1.AUD \
+	KABOOM12.AUD \
+	KABOOM15.AUD \
+	KABOOM22.AUD \
+	KABOOM25.AUD \
+	KABOOM30.AUD \
+	KEEPEM1.AUD \
+	LAUGH1.AUD \
+	LEFTY1.AUD \
+	MADCHRG2.AUD \
+	MADEXPLO.AUD \
+	MAFFIRM1.AUD \
+	MBOSS1.AUD \
+	MHEAR1.AUD \
+	MHOTDIG1.AUD \
+	MHOWDY1.AUD \
+	MHUH1.AUD \
+	MGUNINF1.AUD \
+	MINE1.AUD \
+	MINEBLO1.AUD \
+	MINELAY1.AUD \
+	MISSILE1.AUD \
+	MISSILE6.AUD \
+	MISSILE7.AUD \
+	MLAFF1.AUD \
+	MMOVOUT1.AUD \
+	MRESPON1.AUD \
+	MRISE1.AUD \
+	MWRENCH1.AUD \
+	MYEEHAW1.AUD \
+	MYES1.AUD \
+	MYESSIR1.AUD \
+	ONIT1.AUD \
+	PILLBOX1.AUD \
+	PLACBLDG.AUD \
+	RABEEP1.AUD \
+	RADARDN1.AUD \
+	RADARON2.AUD \
+	RAMENU1.AUD \
+	ROKROLL1.AUD \
+	SAFFIRM1.AUD \
+	SANDBAG2.AUD \
+	SCOLDY1.AUD \
+	SCOMND1.AUD \
+	SHKTROP1.AUD \
+	SILENCER.AUD \
+	SINDEED1.AUD \
+	SKING1.AUD \
+	SMOUT1.AUD \
+	SOKAY1.AUD \
+	SONPULSE.AUD \
+	SONWAY1.AUD \
+	SPLASH9.AUD \
+	SQUISHY2.AUD \
+	SUBSHOW1.AUD \
+	SWHAT1.AUD \
+	SYEAH1.AUD \
+	SYESSIR1.AUD \
+	TANDETH1.AUD \
+	TANK5.AUD \
+	TANK6.AUD \
+	TESLA1.AUD \
+	TORPEDO1.AUD \
+	TSLACHG2.AUD \
+	TUFFGUY1.AUD \
+	TURRET1.AUD \
+	WALLKIL2.AUD \
+	YEAH1.AUD \
+	YES1.AUD \
+	YO1.AUD \
+
+# Vehicle responses
+RESPONSE1 = \
+	ACKNO.AUD \
+	AFFIRM1.AUD \
+	AWAIT1.AUD \
+	REPORT1.AUD \
+	VEHIC1.AUD \
+	YESSIR1.AUD \
+
+# Infantry responses
+RESPONSE2 = \
+	ACKNO.AUD \
+	AFFIRM1.AUD \
+	AWAIT1.AUD \
+	NOPROB.AUD \
+	OVEROUT.AUD \
+	READY.AUD \
+	REPORT1.AUD \
+	RITAWAY.AUD \
+	ROGER.AUD \
+	UGOTIT.AUD \
+	YESSIR1.AUD \
+
+#TSCOREFILES = \
+#	cps\record.bin \
+#	WIN1.AUD \
+#	MAP1.AUD \
+
+VARFILES = \
+
+SCOREFILES = \
+	CREDITS.AUD  \
+	AWAIT.AUD    \
+	BIGF226M.AUD \
+	CRUS226M.AUD \
+	DENSE_R.AUD  \
+	FAC1226M.AUD \
+	FAC2226M.AUD \
+	FOGGER1A.AUD \
+	HELL226M.AUD \
+	MUD1A.AUD \
+	RADIO2.AUD \
+	ROLLOUT.AUD \
+	RUN1226M.AUD \
+	SCORE.AUD \
+	SMSH226M.AUD \
+	SNAKE.AUD \
+	TERMINAT.AUD \
+	TREN226M.AUD \
+	TWIN.AUD \
+	VECTOR1A.AUD \
+	WORK226M.AUD \
+	2ND_HAND.AUD \   
+	ARAZIOD.AUD \   
+	BACKSTAB.AUD \
+	CHAOS2.AUD \ 
+	SHUT_IT.AUD \   
+	TWINMIX1.AUD \   
+	UNDER3.AUD \   
+	VR2.AUD \
+	BOG.AUD \
+	FLOAT_V2.AUD \
+	GLOOM.AUD \
+	GRNDWIRE.AUD \
+	RPT.AUD \
+	SEARCH.AUD \
+	TRACTION.AUD \
+	WASTELND.AUD \
+
+SPEECHFILES = \
+	STRCKIL1.AUD \
+	NOPOWR1.AUD \
+	SAVE1.AUD \
+	LOAD1.AUD \
+	10MINR.AUD \
+	1MINR.AUD \
+	1OBJMET1.AUD \
+	20MINR.AUD \
+	2MINR.AUD \
+	2OBJMET1.AUD \
+	30MINR.AUD \
+	3MINR.AUD \
+	3OBJMET1.AUD \
+	40MINR.AUD \
+	4MINR.AUD \
+	5MINR.AUD \
+	AAPPRO1.AUD \
+	AARIVE1.AUD \
+	AARIVE1.AUD \
+	AARRIVE1.AUD \
+	AARRIVN1.AUD \
+	AARRIVS1.AUD \
+	AARRIVW1.AUD \
+	AAVAIL1.AUD \
+	ABLDGIN1.AUD \
+	AFALLEN1.AUD \
+	ALAUNCH1.AUD \
+	APREP1.AUD \
+	AREADY1.AUD \
+	ARMORUP1.AUD \
+	ASELECT1.AUD \
+	ATLNCH1.AUD \
+	ATPREP1.AUD \
+	AUNITL1.AUD \
+	BASEATK1.AUD \
+	BCT1.AUD \
+	BLDGINF1.AUD \
+	BLDGPRG1.AUD \
+	CANCLD1.AUD \
+	CHROCHR1.AUD \
+	CHRORDY1.AUD \
+	CHROYES1.AUD \
+	CMDCNTR1.AUD \
+	CNTLDED1.AUD \
+	COMNDOF1.AUD \
+	COMNDOR1.AUD \
+	CONSCMP1.AUD \
+	CONVLST1.AUD \
+	CONVYAP1.AUD \
+	CREDIT1.AUD \
+	ENMYAPP1.AUD \
+	FIREPO1.AUD \
+	FLARE1.AUD \
+	FLAREE1.AUD \
+	FLAREN1.AUD \
+	FLARES1.AUD \
+	FLAREW1.AUD \
+	IRONCHG1.AUD \
+	IRONRDY1.AUD \
+	KOSYFRE1.AUD \
+	KOSYRES1.AUD \
+	LOPOWER1.AUD \
+	MERCF1.AUD \
+	MERCR1.AUD \
+	MISNLST1.AUD \
+	MISNWON1.AUD \
+	MTIMEIN1.AUD \
+	NAVYLST1.AUD \
+	NEWOPT1.AUD \
+	NOBUILD1.AUD \
+	NODEPLY1.AUD \
+	NOFUNDS1.AUD \
+	NOFUNDS1.AUD \
+	OBJMET1.AUD \
+	OBJNMET1.AUD \
+	OBJNRCH1.AUD \
+	OBJRCH1.AUD \
+	ONHOLD1.AUD \
+	OPTERM1.AUD \
+	PRIBLDG1.AUD \
+	PROGRES1.AUD \
+	PULSE1.AUD \
+	REINFOR1.AUD \
+	REPAIR1.AUD \
+	REPAIR1.AUD \
+	SATLNCH1.AUD \
+	SILOND1.AUD \
+	SLCTTGT1.AUD \
+	SOVEFAL1.AUD \
+	SOVEMP1.AUD \
+	SOVFAPP1.AUD \
+	SOVFORC1.AUD \
+	SOVREIN1.AUD \
+	SPYPLN1.AUD \
+	STRUCAP1.AUD \
+	STRUSLD1.AUD \
+	TANYAF1.AUD \
+	TANYAR1.AUD \
+	TARGFRE1.AUD \
+	TARGRES1.AUD \
+	TIMERGO1.AUD \
+	TIMERNO1.AUD \
+	TRAIN1.AUD \
+	UNITFUL1.AUD \
+	UNITLST1.AUD \
+	UNITRDY1.AUD \
+	UNITREP1.AUD \
+	UNITSLD1.AUD \
+	UNITSPD1.AUD \
+	XPLOPLC1.AUD \
+#	ABLDGC1.AUD \
+#	SOVBLDG1.AUD \
+#	SOVSTRC1.AUD \
+#	SOVUNTD1.AUD \
+#	AUNITD1.AUD \
+#	ASTRUCD1.AUD \
+
+#ALLIESVQ = \
+DUMMYVQ = \
+	AAGUN.VQA \
+	AFTRMATH.VQA \
+	ALLY1.VQA \
+	ALLY10.VQA \
+	ALLY10B.VQA \
+	ALLY11.VQA \
+	ALLY12.VQA \
+	ALLY14.VQA \
+	ALLY2.VQA \
+	ALLY4.VQA \
+	ALLY5.VQA \
+	ALLY6.VQA \
+	ALLY8.VQA \
+	ALLY9.VQA \
+	ALLYEND.VQA \
+	ALLYMORF.VQA \
+	APCESCPE.VQA \
+	ASSESS.VQA \
+	BATTLE.VQA \
+	1BINOC.VQA \
+	BMAP.VQA \
+	BRDGTILT.VQA \
+	CRONTEST.VQA \
+	CRONFAIL.VQA \
+	DESTROYR.VQA \
+	DUD.VQA \
+	ELEVATOR.VQA \
+	FLARE.VQA \
+	FROZEN.VQA \
+	GRVESTNE.VQA \
+	LANDING.VQA \
+	MASASSLT.VQA \
+	MCV.VQA \
+	MCV_LAND.VQA \
+	MONTPASS.VQA \
+	OILDRUM.VQA \
+	OVERRUN.VQA \
+	PROLOG.VQA \
+	REDINTRO.VQA \
+	SHIPSINK.VQA \
+	SHORBOM1.VQA \
+	SHORBOM2.VQA \
+	SHORBOMB.VQA \
+	SNOWBOMB.VQA \
+	SOVIET1.VQA \
+	SOVTSTAR.VQA \
+	SPY.VQA \
+	TANYA1.VQA \
+	TANYA2.VQA \
+	TOOFAR.VQA \
+	TRINITY.VQA \
+#	TRAILER.VQA \
+
+SOVIETVQ = \
+       	AAGUN.VQA \
+	CRONFAIL.VQA \
+	AIRFIELD.VQA \
+	ALLY1.VQA \
+	ALLYMORF.VQA \
+	AVERTED.VQA \
+	BEACHEAD.VQA \
+	BMAP.VQA \
+	BOMBRUN.VQA \
+	COUNTDWN.VQA \
+	DOUBLE.VQA \
+	DPTHCHRG.VQA \
+	EXECUTE.VQA \
+	FLARE.VQA \
+	LANDING.VQA \
+	MCVBRDGE.VQA \
+	MIG.VQA \
+	MOVINGIN.VQA \
+	MTNKFACT.VQA \
+	NUKESTOK.VQA \
+	ONTHPRWL.VQA \
+	PERISCOP.VQA \
+	PROLOG.VQA \
+	RADRRAID.VQA \
+	REDINTRO.VQA \
+	SEARCH.VQA \
+	SFROZEN.VQA \
+	SITDUCK.VQA \
+	SLNTSRVC.VQA \
+	SNOWBOMB.VQA \
+	SNSTRAFE.VQA \
+	SOVBATL.VQA \
+	SOVCEMET.VQA \
+	SOVFINAL.VQA \
+	SOVIET1.VQA \
+	SOVIET10.VQA \
+	SOVIET11.VQA \
+	SOVIET12.VQA \
+	SOVIET13.VQA \
+	SOVIET14.VQA \
+	SOVIET2.VQA \
+	SOVIET3.VQA \
+	SOVIET4.VQA \
+	SOVIET5.VQA \
+	SOVIET6.VQA \
+	SOVIET7.VQA \
+	SOVIET8.VQA \
+	SOVIET9.VQA \
+	SOVMCV.VQA \
+	SOVTSTAR.VQA \
+	SPOTTER.VQA \
+	STRAFE.VQA \
+	TAKE_OFF.VQA \
+	TESLA.VQA \
+	V2ROCKET.VQA \
+#	TRAILER.VQA \
+
+ALLIESVQ = \
+	AFTRMATH.VQA \
+	ALLY1.VQA \
+	ALLYMORF.VQA \
+	APCESCPE.VQA \
+ BATTLE.VQA \
+	BMAP.VQA \	
+	CRONFAIL.VQA \
+ DPTHCHRG.VQA \
+	EXECUTE.VQA \
+	FLARE.VQA \	
+	FROZEN.VQA \
+	GRVESTNE.VQA \
+	LANDING.VQA \
+	MASASSLT.VQA \
+ NUKESTOK.VQA \
+ ONTHPRWL.VQA \
+	OVERRUN.VQA \
+	PROLOG.VQA \
+	REDINTRO.VQA \
+	SFROZEN.VQA \
+ SLNTSRVC.VQA \
+	SNOWBOMB.VQA \
+ SNOWBASE.VQA \
+ SOVMCV.VQA \
+	SNSTRAFE.VQA \
+	SOVBATL.VQA \
+	SOVCEMET.VQA \
+	SOVIET1.VQA \
+	SOVTSTAR.VQA \
+	SPY.VQA \
+ STRAFE.VQA \
+	TESLA.VQA \
+	TOOFAR.VQA \
+	TRINITY.VQA \
+	V2ROCKET.VQA \		
+#	ANTEND.VQA \
+#	ANTINTRO.VQA \
+	
+
+
+# Files required for hires/Win95 version only
+#
+# This mix file is not cached
+#
+NOCACHEHIRESFILES= \
+	ENGLISH.VQA \
+	$(ALLIESVQ:.VQA=.VQP) \
+	$(SOVIETVQ:.VQA=.VQP) \
+       
+
+LINTOBJECTS1 = $(OBJECTS:,=)
+LINTOBJECTS = $(LINTOBJECTS1:.OBJ=.LOB)
+
+# Mixfiles that should reside on the CD-ROM drive.
+CD1MIXFILES = \
+	CONQUER.MIX \
+	EDHI.MIX \
+	EDLO.MIX \
+	GENERAL.MIX \
+	INTERIOR.MIX \
+	MOVIES1.MIX \
+	SCORES.MIX \
+	SNOW.MIX \
+	SOUNDS.MIX \
+ 	RUSSIAN.MIX \
+	ALLIES.MIX \
+	TEMPERAT.MIX \
+	
+
+
+# Mixfiles that should reside on the hard drive.
+LOCALMIXFILES = \
+	EDITOR.MIX \
+	HIRES.MIX \
+	LOCAL.MIX \
+	LORES.MIX \
+	NCHIRES.MIX \
+	SPEECH.MIX \
+	
+
+# Mixfiles as they appear on the CD and hard drive.
+PACKFILES=	$(.path.cd1)MAIN.MIX  EXPAND2.MIX  $(.path.cd1)tobreaki\REDALERT.MIX
+
+
+# Ant assets SOME ASSETS ARE HERE FOR OVERRIDING
+EXPANDFILES= \
+	ANT1.SHP \
+	ANT2.SHP \
+	ANT3.SHP \
+	QUEE.SHP \
+	CREDITS.ENG \
+	HILL01.TEM \
+	ANTBITE.AUD \
+	ANTDIE.AUD \
+	ANTDIE.SHP \
+	LAR1.SHP \
+	LAR2.SHP \
+	TITLE.PCX \							  
+	MISSION.INI \
+	BUZZY1.AUD \       
+	STAVCMDR.AUD \     
+	STAVCRSE.AUD \     
+	STAVYES.AUD \      
+	STAVMOV.AUD \
+	CONQUER.ENG \   
+	RAMBO1.AUD \
+	RAMBO2.AUD \
+	RAMBO3.AUD \
+	TITLE.CPS \
+	TUTORIAL.INI \
+	BMAP.VQP \
+	ANTEND.VQP \
+	ANTINTRO.VQP \
+
+# Aftermath expansion files
+EXPAND2FILES= \
+	CARR.SHP \
+	CTNK.SHP \
+	DTRK.SHP \
+	MSUB.SHP \
+	QTNK.SHP \
+	TTNK.SHP \
+	STNK.SHP \
+	AFTRMATH.INI \
+	ANT1.SHP \
+	ANT2.SHP \
+	ANT3.SHP \
+	ANTBITE.AUD \
+	ANTDIE.AUD \
+	ANTDIE.SHP \
+	BUZZY1.AUD \       
+	CONQUER.ENG \   
+	CREDITS.TXT \
+	HILL01.TEM \
+	LAR1.SHP \
+	LAR2.SHP \
+	MISSION.INI \
+	MPLAYER.INI \
+	QUEE.SHP \
+	STAVCMDR.AUD \     
+	STAVCRSE.AUD \     
+	STAVYES.AUD \      
+	STAVMOV.AUD \
+ TANK01.AUD \
+	TITLE.PCX \							  
+	TITLE.CPS \
+	TUTORIAL.INI \
+	BMAP.VQP \
+ stup_fix.shp \
+
+
+
+#############################################################
+# Rebuilds all the mixfiles.				  
+packfiles:	always $(PACKFILES)
+
+always:
+	copy f:\projects\c&c0\editor\english\*.mix $(.path.mix) /u
+
+
+####################################################################
+# All mixfiles that exist on the CD-ROM are embedded within this mega-mixfile.
+$(.path.cd1)MAIN.MIX: $(CD1MIXFILES)
+	UTILS\MIXFILE -k -I$(.path.mix) &&!
+	$**
+! $(.path.cd1)$&.mix
+
+
+# All mixfiles that exist in the local directory are embedded within this mega-mixfile.
+$(.path.cd1)install\REDALERT.MIX: $(LOCALMIXFILES)
+	UTILS\MIXFILE -k  -I$(.path.mix) &&!
+	$**
+! $(.path.cd1)install\$&.mix
+
+
+####################################################################
+# These are the various sub-mixfiles.
+CONQUER.MIX: $(CONQUERFILES) $(CACHEMAP) .\key.ini
+	UTILS\MIXFILE -k -h -I$(.path.cps) &&!
+	$(CONQUERFILES) $(CACHEMAP)
+! $(.path.mix)$&.mix
+
+TEMPERAT.MIX: $(TEMPERATEFILES) .\key.ini
+	UTILS\MIXFILE -h -k -I$(.path.cps) &&!
+	$(TEMPERATEFILES)
+! $(.path.mix)$&.mix
+
+SNOW.MIX: $(SNOWFILES) .\key.ini
+	UTILS\MIXFILE -h -k -I$(.path.cps) &&!
+	$(SNOWFILES)
+! $(.path.mix)$&.mix
+
+INTERIOR.MIX: $(INTERIORFILES) .\key.ini
+	UTILS\MIXFILE -h -k -I$(.path.cps) &&!
+	$(INTERIORFILES)
+! $(.path.mix)$&.mix
+
+GENERAL.MIX: $(GENERALFILES) $(GENERALMAPFILES) $(NETMAPFILES) $(MAPFILES) .\key.ini
+	UTILS\MIXFILE -k -I$(.path.cps) -I$(.path.ini) &&!
+	$(GENERALFILES) $(GENERALMAPFILES) $(NETMAPFILES) $(MAPFILES)
+! $(.path.mix)$&.mix
+
+SCORES.MIX: $(SCOREFILES)
+	UTILS\MIXFILE -k -I$(.path.cps) -I$(.path.ini) &&!
+	$**
+! $(.path.mix)$&.mix
+
+SOUNDS.MIX: $(WAVFILES) $(SFX)
+	UTILS\MIXFILE -h -k -EA60=V00 -EA61=V01 -EA62=V02 -EA63=V03 -I$(.path.aud) &&!
+	$**
+! $(.path.mix)$&.mix
+
+RUSSIAN.MIX: $(RESPONSE1:.AUD=.R00) $(RESPONSE2:.AUD=.R01) $(RESPONSE1:.AUD=.R02) $(RESPONSE2:.AUD=.R03)
+	UTILS\MIXFILE -h -k -I$(.path.aud) &&!
+	$**
+! $(.path.mix)$&.mix
+
+LIMITED.MIX: BLEEP11.AUD
+	UTILS\MIXFILE -h -k -I$(.path.aud) &&!
+	$**
+! $(.path.mix)$&.mix
+
+ALLIES.MIX: $(RESPONSE1:.AUD=.V00) $(RESPONSE2:.AUD=.V01) $(RESPONSE1:.AUD=.V02) $(RESPONSE2:.AUD=.V03)
+	UTILS\MIXFILE -h -k -I$(.path.aud) &&!
+	$**
+! $(.path.mix)$&.mix
+
+MOVIES1.MIX: $(ALLIESVQ)
+	UTILS\MIXFILE -k -I$(.path.vqa) &&!
+	$**
+! $(.path.mix)$&.mix
+
+
+
+
+
+NCHIRES.MIX: $(NOCACHEHIRESFILES:.SHP=.HI)
+	UTILS\MIXFILE -k -I$(.path.vqp) -I$(.path.cps) &&!
+	$(NOCACHEHIRESFILES)
+! $(.path.mix)$&.mix
+
+LOCAL.MIX: $(LOCALFILES) .\key.ini
+	UTILS\MIXFILE -h -k -E.A6=.AUD -I$(.path.ini) -I$(.path.txt) -I$(.path.cps) &&!
+	$(LOCALFILES)
+! $(.path.mix)$&.mix
+
+LORES.MIX: $(LOHILORES) .\key.ini
+	UTILS\MIXFILE -h -k -E.LOW=.SHP -E.LNT=.FNT -I$(.path.cps) &&!
+	$(LOHILORES)
+! $(.path.mix)$&.mix
+
+HIRES.MIX: $(HIRESFILES:.SHP=.HI) $(HIHILORES) .\key.ini
+	UTILS\MIXFILE -h -k -E.HI=.SHP -E.HNT=.FNT -I$(.path.cps) &&!
+	$(HIRESFILES:.SHP=.HI) $(HIHILORES)
+! $(.path.mix)$&.mix
+
+LORES1.MIX: $(LOHILORES1) .\key.ini
+	UTILS\MIXFILE -h -k -E.LOW=.SHP -E.LNT=.FNT -I$(.path.cps) &&!
+	$(LOHILORES1)
+! $(.path.mix)$&.mix
+
+HIRES1.MIX: $(HIHILORES1) .\key.ini
+	UTILS\MIXFILE -h -k -E.HI=.SHP -E.HNT=.FNT -I$(.path.cps) &&!
+	$(HIHILORES1)
+! $(.path.mix)$&.mix
+
+SPEECH.MIX: $(SPEECHFILES)
+	UTILS\MIXFILE -k -I$(.path.aud) &&!
+	$**
+! $(.path.mix)$&.mix
+
+
+EXPAND.MIX: $(EXPANDFILES)			   
+	UTILS\MIXFILE -k  -I$(.path.mix)  &&!
+	$**
+! $(.path.mix)$&.mix
+
+EXPAND2.MIX: $(EXPAND2FILES)			   
+	UTILS\MIXFILE -k  -I$(.path.mix)  &&!
+	$**
+! $(.path.mix)$&.mix
+
+#############################################################
+# Special rule to create the mouse shape (which must be a shape file)
+mouse.hi:	$(.path.anm)hires\mouse.anm
+	-utils\makeshps $(.path.lbm)palettes\temperat.lbm &&!
+ &$(.path.anm)hires\mouse.anm;
+ end;
+! $(.path.hi)$&.hi $(SHAPEBUFFSIZE)
+
+# Special rule to create the mouse shape (which must be a shape file)
+mouse.low:	$(.path.anm)lores\mouse.anm
+	-utils\makeshps $(.path.lbm)palettes\temperat.lbm &&!
+ &$(.path.anm)lores\mouse.anm;
+ end;
+! $(.path.low)$&.low $(SHAPEBUFFSIZE)
+
+
+#############################################################
+# Special build rule for radar animations so that they won't.
+#
+NATORADR.HI: $(.path.anm)hires\NATORADR.ANM
+	utils\newkeyf $** $(.path.hi)$&.hi -l -k
+
+USSRRADR.HI: $(.path.anm)hires\USSRRADR.ANM
+	utils\newkeyf $** $(.path.hi)$&.hi -l -k
+
+NATORADR.LOW: $(.path.anm)lores\NATORADR.ANM
+	utils\newkeyf $** $(.path.low)$&.low -l -k
+
+USSRRADR.LOW: $(.path.anm)lores\USSRRADR.ANM
+	utils\newkeyf $** $(.path.low)$&.low -l -k
+
+
+#############################################################
+# Debug text file creation.
+debug.eng:	debug.txt
+	utils\textmake -b1000 eng\$&.txt $(.path.eng)$&.eng $&.h
+
+

+ 2098 - 0
CODE/BFILE2.MAK

@@ -0,0 +1,2098 @@
+#
+#	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\bfile.mav   5.0   11 Nov 1996 09:40:38   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 : MAKEFILE                                 *
+#*                                                                         *
+#*                   Programmer : Joe L. Bostic                            *
+#*                                                                         *
+#*                   Start Date : March 25, 1993                           *
+#*                                                                         *
+#*                  Last Update : March 25, 1993   [JLB]                   *
+#*                                                                         *
+#*-------------------------------------------------------------------------*
+
+
+# Comment out the following line to disable "include file autodependency".
+.AUTODEPEND
+#.SWAP
+
+!include	"rules.mak"
+
+
+##########################################################################
+
+MAPFILES = \
+
+CACHEMAP = \
+	BRIEFING.AUD \
+	BAR3RED.SHP \
+	BAR3BLU.SHP \
+	COUNTRYA.SHP \
+	COUNTRYE.SHP \
+	CREDSA.SHP \
+	CREDSU.SHP \
+	HISCORE1.SHP \
+	HISCORE2.SHP \
+	TIME.SHP \
+	CLOCK1.AUD \
+	COUNTRY4.AUD \
+	MAPWIPE2.AUD \
+	MAPWIPE5.AUD \
+	TONEY10.AUD \
+	TONEY4.AUD \
+	TONEY7.AUD \
+	SFX4.AUD \
+	BEEPY6.AUD \
+	KEYSTROK.AUD \
+	APPEAR1.AUD \
+	SCOLD1.AUD \
+	COUNTRY1.AUD \
+	ALI-TRAN.WSA \
+	SOV-TRAN.WSA \
+	ALIBACKH.PCX \
+	SOVBACKH.PCX \
+	BAR3RHR.SHP \
+	BAR3BHR.SHP \
+	CREDSAHR.SHP \
+	CREDSUHR.SHP \
+	HISC1-HR.SHP \
+	HISC2-HR.SHP \
+	TIMEHR.SHP \
+	MLTIPLYR.WSA \
+
+LOCALFILES = \
+	PROLOG.CPS \
+	MAP.AUD \
+	TITLE.CPS \
+	PALETTE.CPS \
+	INTRO.AUD \
+	EGOPAL.PAL \
+	RULES.INI \
+	CREDITS.TXT \
+	ALIPAPER.CPS \
+	3POINT.FNT \
+	8POINT.FNT \
+	EDITFNT.FNT \
+	CONQUER.ENG \
+	DEBUG.ENG \
+	LED.FNT \
+	SNOW.PAL \
+	TEMPERAT.PAL \
+	INTERIOR.PAL \
+	VCR.FNT \
+	HOLE0000.LUT \
+	HOLE0001.LUT \
+	HOLE0002.LUT \
+	HOLE0003.LUT \
+	HOLE0004.LUT \
+	HOLE0005.LUT \
+	HOLE0006.LUT \
+	HOLE0007.LUT \
+	HOLE0008.LUT \
+	HOLE0009.LUT \
+	HOLE0010.LUT \
+	HOLE0011.LUT \
+	HOLE0012.LUT \
+	HOLE0013.LUT \
+	HOLE0014.LUT \
+	HOLE0015.LUT \
+	HOLE0016.LUT \
+	HOLE0017.LUT \
+	HOLE0018.LUT \
+	HOLE0019.LUT \
+	HOLE0020.LUT \
+	HOLE0021.LUT \
+	HOLE0022.LUT \
+	HOLE0023.LUT \
+	HOLE0024.LUT \
+	HOLE0025.LUT \
+	HOLE0026.LUT \
+	HOLE0027.LUT \
+	HOLE0028.LUT \
+	HOLE0029.LUT \
+	HOLE0030.LUT \
+	HOLE0031.LUT \
+	HOLE0032.LUT \
+	HOLE0033.LUT \
+	HOLE0034.LUT \
+	HOLE0035.LUT \
+	HOLE0036.LUT \
+	HOLE0037.LUT \
+	HOLE0038.LUT \
+	HOLE0039.LUT \
+	HOLE0040.LUT \
+	HOLE0041.LUT \
+	HOLE0042.LUT \
+	HOLE0043.LUT \
+	HOLE0044.LUT \
+	HOLE0045.LUT \
+	HOLE0046.LUT \
+	HOLE0047.LUT \
+#	TEMPSCOR.FNT \
+#	6POINT.FNT \
+#	GRAD6FNT.FNT \
+#	SCOREFNT.FNT \
+
+
+# Files that have counterparts in both high and low resolutions.
+# These files will be built into the HIRES.MIX and LORES.MIX files.
+HILORES = \
+	TRANICON.SHP \
+	PIPS.SHP \
+	PULSE.SHP \
+	ATOMICON.SHP \
+	WARPICON.SHP \
+	C1.SHP \
+	C2.SHP \
+	CHAN.SHP \
+	DELPHI.SHP \
+	E1.SHP \
+	E2.SHP \
+	E3.SHP \
+	E4.SHP \
+	E5.SHP \
+	E6.SHP \
+	E7.SHP \
+	EINSTEIN.SHP \
+	GNRL.SHP \
+	MECH.SHP \
+	MEDI.SHP \
+	SHOK.SHP \
+	SPY.SHP \
+	THF.SHP \
+	DD-BKGND.SHP \
+	DD-BOTM.SHP \
+	DD-CRNR.SHP \
+	DD-EDGE.SHP \
+	DD-LEFT.SHP \
+	DD-RIGHT.SHP \
+	DD-TOP.SHP \
+	12METFNT.FNT \
+	GRAD6FNT.FNT \
+	HELP.FNT \
+	6POINT.FNT \
+	TYPE.FNT \
+	SCOREFNT.FNT \
+	1TNKICON.SHP \
+	2TNKICON.SHP \
+	3TNKICON.SHP \
+	4TNKICON.SHP \
+	AFLDICON.SHP \
+	AGUNICON.SHP \
+	APCICON.SHP \
+	APWRICON.SHP \
+	ARTYICON.SHP \
+	ATEKICON.SHP \
+	BADRICON.SHP \
+	BARRICON.SHP \
+	BRIKICON.SHP \
+	BTN-DN.SHP \
+	BTN-PL.SHP \
+	BTN-ST.SHP \
+	BTN-UP.SHP \
+	CAICON.SHP \
+	CAMICON.SHP \
+	CARRICON.SHP \
+	CLOCK.SHP \
+	CTNKICON.SHP \
+	DDICON.SHP \
+	DOGICON.SHP \
+	DOMEICON.SHP \
+	DOMFICON.SHP \
+	DTRKICON.SHP \
+	E1ICON.SHP \
+	E2ICON.SHP \
+	E3ICON.SHP \
+	E4ICON.SHP \
+	E6ICON.SHP \
+	E7ICON.SHP \
+	FACFICON.SHP \
+	FACTICON.SHP \
+	FENCICON.SHP \
+	FIXICON.SHP \
+	FTURICON.SHP \
+	GAPICON.SHP \
+	GPSSICON.SHP \
+	GUNICON.SHP \
+	HARVICON.SHP \
+	HBOXICON.SHP \
+	HELIICON.SHP \
+	HINDICON.SHP \
+	HPADICON.SHP \
+	INFXICON.SHP \
+	IRONICON.SHP \
+	JEEPICON.SHP \
+	KENNICON.SHP \
+	LSTICON.SHP \
+	MAP.SHP \
+	MCVICON.SHP \
+	MECHICON.SHP \
+	MEDIICON.SHP \
+	MGGICON.SHP \
+	MIGICON.SHP \
+	MNLYICON.SHP \
+	MOUSE.SHP \
+	MRJICON.SHP \
+	MSLOICON.SHP \
+	MSUBICON.SHP \
+	NATORADR.SHP \
+	PBMBICON.SHP \
+	PBOXICON.SHP \
+	PDOXICON.SHP \
+	PINFICON.SHP \
+	POWER.SHP \
+	POWERBAR.SHP \
+	POWRICON.SHP \
+	PROCICON.SHP \
+	PTICON.SHP \
+	QTNKICON.SHP \
+	REPAIR.SHP \
+	SAMICON.SHP \
+	SBAGICON.SHP \
+	SELL.SHP \
+	SHOKICON.SHP \
+	SIDEBAR.SHP \
+	SILOICON.SHP \
+	SMIGICON.SHP \
+	SONRICON.SHP \
+	SOVPAPER.CPS \
+	SPEFICON.SHP \
+	SPENICON.SHP \
+	SPYICON.SHP \
+	SSICON.SHP \
+	STEKICON.SHP \
+	STRIP.SHP \
+	STRIPDN.SHP \
+	STRIPUP.SHP \
+	SYRDICON.SHP \
+	SYRFICON.SHP \
+	TABS.SHP \
+	TENTICON.SHP \
+	THFICON.SHP \
+	TRUKICON.SHP \
+	TTNKICON.SHP \
+	TSLAICON.SHP \
+	U2ICON.SHP \
+	USSRRADR.SHP \
+	V2RLICON.SHP \
+	WEAFICON.SHP \
+	WEAPICON.SHP \
+	YAKICON.SHP \
+	NRADRFRM.SHP \
+	URADRFRM.SHP \
+	SIDE1NA.SHP \
+	SIDE1US.SHP \
+	SIDE2NA.SHP \
+	SIDE2US.SHP \
+	SIDE3NA.SHP \
+	SIDE3US.SHP \
+	STRIPNA.SHP \
+	STRIPUS.SHP \
+
+#	MOEBICON.SHP \
+
+# These helper macros substitute the extension so that
+# the appropriate art build rule will be invoked.
+xLOHILORES = $(HILORES:.SHP=.LOW)
+LOHILORES = $(xLOHILORES:.FNT=.LNT)
+xHIHILORES = $(HILORES:.SHP=.HI)
+HIHILORES = $(xHIHILORES:.FNT=.HNT)
+
+#
+# Files required for hires/Win95 version only
+#
+# This mix file is cached
+#
+HIRESFILES = \
+	ALIPAPER.PCX \
+      	PROLOG.PCX \
+	SOVPAPER.PCX \
+	AFTR_HI.PCX \
+	ALY1.PCX \
+	APC_HI.PCX \
+	APHI0049.PCX \
+	BNHI0020.PCX \
+	DCHI0040.PCX \
+	FRHI0166.PCX \
+	LAB.PCX \
+	LANDSBRG.PCX \
+	MAHI0107.PCX \
+	MIG_HI.PCX \
+	MTFACTHI.PCX \
+	NEEDLE.PCX \
+	SOV2.PCX \
+	SPY.PCX \
+	STALIN.PCX \
+	TENT.PCX \
+#	ENG_HI.PCX \
+
+
+CONQUERFILES = \
+	PARABOMB.SHP \
+	RADARFRM.SHP \
+	ARMOR.SHP \
+	FPOWER.SHP \
+	SPEED.SHP \
+	TQUAKE.SHP \
+	H2O_EXP1.SHP \
+	H2O_EXP2.SHP \
+	H2O_EXP3.SHP \
+	FLAK.SHP \
+	EBTN-DN.SHP \
+	EBTN-UP.SHP \
+	ATOMSFX.SHP \
+	TWINKLE1.SHP \
+	TWINKLE2.SHP \
+	TWINKLE3.SHP \
+	CHRONBOX.SHP \
+	GPSBOX.SHP \
+	INVULBOX.SHP \
+	PARABOX.SHP \
+	SONARBOX.SHP \
+	SPUTNIK.SHP \
+	SPUTDOOR.SHP \
+	ATOMICDN.SHP \
+	ATOMICUP.SHP \
+	TYPE.FNT \
+	120MM.SHP \
+	1TNK.SHP \
+	2TNK.SHP \
+	3TNK.SHP \
+	4TNK.SHP \
+	50CAL.SHP \
+	AFLD.SHP \
+	AGUN.SHP \
+	APC.SHP \
+	APWR.SHP \
+	ART-EXP1.SHP \
+	ARTY.SHP \
+	ATEK.SHP \
+	BADR.SHP \
+	BARB.SHP \
+	BARL.SHP \
+	BARR.SHP \
+	BIO.SHP \
+	BOMB.SHP \
+	BOMBLET.SHP \
+	BRIK.SHP \
+	BRL3.SHP \
+	BURN-L.SHP \
+	BURN-M.SHP \
+	BURN-S.SHP \
+	CA.SHP \
+	CYCL.SHP \
+	DD.SHP \
+	DEVIATOR.SHP \
+	DOG.SHP \
+	DOGBULLT.SHP \
+	DOLLAR.SHP \
+	DOME.SHP \
+	DRAGON.SHP \
+	EARTH.SHP \
+	ELECTDOG.SHP \
+	EMPULSE.SHP \
+	FACT.SHP \
+	FB1.SHP \
+	FB2.SHP \
+	FBALL1.SHP \
+	FCOM.SHP \
+	FENC.SHP \
+	FIRE1.SHP \
+	FIRE2.SHP \
+	FIRE3.SHP \
+	FIRE4.SHP \
+	FIX.SHP \
+	FLAGFLY.SHP \
+	FLMSPT.SHP \
+	FPLS.SHP \
+	FRAG1.SHP \
+	FTNK.SHP \
+	FTUR.SHP \
+	GAP.SHP \
+	GUN.SHP \
+	GUNFIRE.SHP \
+	HARV.SHP \
+	HELI.SHP \
+	HIND.SHP \
+	HOSP.SHP \
+	HPAD.SHP \
+	INVUN.SHP \
+	IRON.SHP \
+	JEEP.SHP \
+	KENN.SHP \
+	LITNING.SHP \
+	LROTOR.SHP \
+	LST.SHP \
+	MCV.SHP \
+	MGG.SHP \
+	MGUN.SHP \
+	MHQ.SHP \
+	MIG.SHP \
+	MINE.SHP \
+	MINIGUN.SHP \
+	MINP.SHP \
+	MINV.SHP \
+	MISS.SHP \
+	MISSILE.SHP \
+	MISSILE2.SHP \
+	MLRS.SHP \
+	MNLY.SHP \
+	MRJ.SHP \
+	NAPALM1.SHP \
+	NAPALM2.SHP \
+	NAPALM3.SHP \
+	ORCA.SHP \
+	PARACH.SHP \
+	PATRIOT.SHP \
+	PBOX.SHP \
+	PDOX.SHP \
+	PIFF.SHP \
+	PIFFPIFF.SHP \
+	POWR.SHP \
+	PROC.SHP \
+	PT.SHP \
+	RAPID.SHP \
+	RROTOR.SHP \
+	SAM.SHP \
+	SAMFIRE.SHP \
+	SBAG.SHP \
+	SCRATE.SHP \
+	SELECT.SHP \
+	SHADOW.SHP \
+	SILO.SHP \
+	SMIG.SHP \
+	SMOKEY.SHP \
+	SMOKE_M.SHP \
+	SMOKLAND.SHP \
+	SPEN.SHP \
+	SS.SHP \
+	SSAM.SHP \
+	STEALTH2.SHP \
+	STEK.SHP \
+	STNK.SHP \
+	SYRD.SHP \
+	TENT.SHP \
+	TRAN.SHP \
+	TRANS.ICN \
+	TRUK.SHP \
+	TSLA.SHP \
+	TURR.SHP \
+	U2.SHP \
+	V19.SHP \
+	V2.SHP \
+	V2RL.SHP \
+	VEH-HIT1.SHP \
+	VEH-HIT2.SHP \
+	VEH-HIT3.SHP \
+	WAKE.SHP \
+	WCRATE.SHP \
+	WWCRATE.SHP \
+	WEAP.SHP \
+	WEAP2.SHP \
+	WOOD.SHP \
+	YAK.SHP \
+	AFLDMAKE.SHP \
+	AGUNMAKE.SHP \
+	APWRMAKE.SHP \
+	ATEKMAKE.SHP \
+	BARRMAKE.SHP \
+	BIOMAKE.SHP \
+	DOMEMAKE.SHP \
+	FACTMAKE.SHP \
+	FIXMAKE.SHP \
+	FTURMAKE.SHP \
+	GAPMAKE.SHP \
+	GUNMAKE.SHP \
+	HOSPMAKE.SHP \
+	HPADMAKE.SHP \
+	IRONMAKE.SHP \
+	KENNMAKE.SHP \
+	MINPMAKE.SHP \
+	MINVMAKE.SHP \
+	PBOXMAKE.SHP \
+	POWRMAKE.SHP \
+	PDOXMAKE.SHP \
+	PROCMAKE.SHP \
+	PUMPMAKE.SHP \
+	SAMMAKE.SHP \
+	SILOMAKE.SHP \
+	SPENMAKE.SHP \
+	STEKMAKE.SHP \
+	SYRDMAKE.SHP \
+	TENTMAKE.SHP \
+	TSLAMAKE.SHP \
+	WEAPMAKE.SHP \
+
+GENERALMAPFILES = \
+	MISSIONS.PKT \
+	TUTORIAL.INI \
+	SCA01EA.INI \
+	SCA02EA.INI \
+	SCA03EA.INI \
+	SCA04EA.INI \
+        SCG01EA.INI \     
+        SCG40EA.INI \     
+        SCG41EA.INI \     
+        SCG42EA.INI \     
+        SCG43EA.INI \     
+        SCG44EA.INI \     
+        SCG45EA.INI \     
+        SCG46EA.INI \     
+        SCG47EA.INI \     
+        SCG48EA.INI \     
+        SCU40EA.INI \     
+        SCU41EA.INI \     
+        SCU42EA.INI \     
+        SCU43EA.INI \     
+        SCU44EA.INI \     
+        SCU45EA.INI \     
+        SCU46EA.INI \     
+        SCU47EA.INI \     
+        SCU48EA.INI \     
+	SCU01EA.INI \     
+	SCM01EA.INI \      
+	SCM02EA.INI \ 
+	SCM03EA.INI \ 
+	SCM04EA.INI \ 
+	SCM05EA.INI \ 
+	SCM06EA.INI \ 
+	SCM07EA.INI \ 
+	SCM08EA.INI \ 
+	SCM09EA.INI \ 
+	SCM10EA.INI \ 
+	SCM11EA.INI \ 
+	SCM12EA.INI \ 
+	SCM13EA.INI \ 
+	SCM14EA.INI \ 
+	SCM15EA.INI \ 
+	SCM16EA.INI \ 
+	SCM17EA.INI \ 
+	SCM18EA.INI \ 
+	SCM19EA.INI \ 
+	SCM20EA.INI \ 
+	SCM21EA.INI \ 
+	SCM22EA.INI \ 
+	SCM23EA.INI \ 
+	SCM24EA.INI \ 
+    	SCM25EA.INI \
+	SCM26EA.INI \
+	SCM27EA.INI \
+	SCM28EA.INI \
+	SCM29EA.INI \
+	SCM30EA.INI \
+	SCM31EA.INI \ 
+	SCM32EA.INI \ 
+	SCM33EA.INI \
+	SCM34EA.INI \
+     	SCM35EA.INI \
+	SCM36EA.INI \
+	SCM37EA.INI \
+	SCM38EA.INI \
+	SCM39EA.INI \
+	SCM40EA.INI \
+	SCM41EA.INI \
+	SCM42EA.INI \
+	SCM43EA.INI \
+	SCM44EA.INI \
+	SCM45EA.INI \
+	SCM46EA.INI \
+	SCM47EA.INI \
+	SCM48EA.INI \
+	SCM49EA.INI \
+	SCM50EA.INI \
+	SCM51EA.INI \
+	SCM52EA.INI \
+	SCM53EA.INI \
+	SCM54EA.INI \
+	SCM55EA.INI \
+	SCM56EA.INI \
+	SCM57EA.INI \
+	SCM58EA.INI \
+	SCM59EA.INI \
+	SCM60EA.INI \
+	SCM61EA.INI \
+	SCM62EA.INI \
+	SCM63EA.INI \
+	SCM64EA.INI \
+	SCM65EA.INI \
+	SCM66EA.INI \
+	SCM67EA.INI \
+	SCM68EA.INI \
+	SCM69EA.INI \
+	SCM70EA.INI \
+	SCM71EA.INI \
+	SCM72EA.INI \
+	SCM73EA.INI \
+	SCM74EA.INI \
+	SCM75EA.INI \
+	SCM76EA.INI \
+	SCM77EA.INI \
+	SCM78EA.INI \
+	SCM79EA.INI \
+	SCM80EA.INI \
+	SCM81EA.INI \
+	SCM82EA.INI \
+	SCM83EA.INI \
+	SCM84EA.INI \
+	SCM85EA.INI \
+	SCM86EA.INI \
+	SCM87EA.INI \
+	SCM88EA.INI \
+	SCM89EA.INI \	
+	SCM90EA.INI \
+	SCM91EA.INI \
+	SCM92EA.INI \
+	SCM93EA.INI \
+	SCM94EA.INI \
+	SCM95EA.INI \
+	SCM96EA.INI \
+	SCM97EA.INI \
+	SCM98EA.INI \
+	SCM99EA.INI \
+	SCM100EA.INI \
+	SCM101EA.INI \
+	SCM102EA.INI \
+	SCM103EA.INI \
+	SCM104EA.INI \
+	SCM105EA.INI \
+	SCM106EA.INI \
+	SCM107EA.INI \
+	SCM108EA.INI \
+	SCM109EA.INI \
+	SCM110EA.INI \
+	SCM111EA.INI \
+	SCM112EA.INI \
+	SCM113EA.INI \
+	SCM114EA.INI \
+	SCM115EA.INI \
+	SCM116EA.INI \
+	SCM117EA.INI \
+	SCM118EA.INI \
+ 	SCM119EA.INI \    
+	SCM120EA.INI \     
+	SCM121EA.INI \    
+	SCM122EA.INI \     
+	SCM123EA.INI \    
+	SCM124EA.INI \    
+	SCM125EA.INI \    
+	SCM126EA.INI \    
+	SCM127EA.INI \    
+	SCM128EA.INI \    
+	SCM129EA.INI \ 
+	SCM130EA.INI \   
+	SCMD0EA.INI \
+	SCMD1EA.INI \
+	SCMD2EA.INI \
+	SCMD3EA.INI \
+	SCMD4EA.INI \
+	SCMD5EA.INI \
+	SCMD6EA.INI \
+	SCMD7EA.INI \
+	SCMD8EA.INI \
+	SCMD9EA.INI \
+	SCME0EA.INI \
+	SCME1EA.INI \
+	SCME2EA.INI \
+	SCME3EA.INI \
+	SCME4EA.INI \
+	SCME5EA.INI \
+	SCME6EA.INI \
+	SCME7EA.INI \
+	SCME8EA.INI \
+	SCME9EA.INI \
+	SCMF0EA.INI \
+	SCMF1EA.INI \
+	SCMF2EA.INI \
+	SCMF3EA.INI \
+	SCMF4EA.INI \
+	SCMF5EA.INI \
+	SCMF6EA.INI \
+	SCMF7EA.INI \
+	SCMF8EA.INI \
+	SCMF9EA.INI \
+	SCMG0EA.INI \
+	SCMG1EA.INI \
+	SCMG2EA.INI \
+	SCMG3EA.INI \
+	SCMG4EA.INI \
+	SCMG5EA.INI \
+	SCMG6EA.INI \
+	SCMG7EA.INI \
+	SCMG8EA.INI \
+	SCMG9EA.INI \
+	SCMH0EA.INI \
+	SCMH1EA.INI \
+	SCMH2EA.INI \
+	SCMH3EA.INI \
+	SCMH4EA.INI \
+	SCMH5EA.INI \
+	SCMH6EA.INI \
+	SCMH7EA.INI \
+	SCMH8EA.INI \
+	SCMH9EA.INI \
+	SCMI0EA.INI \
+	SCMI1EA.INI \
+	SCMI2EA.INI \
+	SCMI3EA.INI \
+	SCMI4EA.INI \
+	SCMI5EA.INI \
+	SCMI6EA.INI \
+	SCMI7EA.INI \
+	SCMI8EA.INI \
+	SCMI9EA.INI \
+	SCMJ0EA.INI \
+	SCMJ1EA.INI \
+	SCMJ2EA.INI \
+	SCMJ3EA.INI \
+	SCMJ4EA.INI \
+	SCMJ5EA.INI \
+	SCMJ6EA.INI \
+	SCMJ7EA.INI \
+	SCMJ8EA.INI \
+	SCMJ9EA.INI \
+	SCMK0EA.INI \
+	SCMK1EA.INI \
+	SCMK2EA.INI \
+	SCMK3EA.INI \
+	SCMK4EA.INI \
+	SCMK5EA.INI \
+	SCMK6EA.INI \
+	SCMK7EA.INI \
+	SCMK8EA.INI \
+	SCMK9EA.INI \
+	SCML0EA.INI \
+	SCML1EA.INI \
+	SCML2EA.INI \
+	SCML3EA.INI \
+	SCML4EA.INI \
+	SCML5EA.INI \
+	SCML6EA.INI \
+	SCML7EA.INI \
+	SCML8EA.INI \
+	SCML9EA.INI \
+	SCMM0EA.INI \
+	SCMM1EA.INI \
+	SCMM2EA.INI \
+	SCMM3EA.INI \
+	SCMM4EA.INI \
+	SCMM5EA.INI \
+	SCMM6EA.INI \
+	SCMM7EA.INI \
+	SCMM8EA.INI \
+	SCMM9EA.INI \
+   
+NETMAPFILES = \
+
+# Files that aren't cached.
+GENERALFILES = \
+	AFTR_LO.CPS \
+	ALY1-LO.CPS \
+	APC_LO.CPS \
+	APLO0049.CPS \
+	BNLO0020.CPS \
+	DCLO0040.CPS \
+	FRLO0166.CPS \
+	LAB-LO.CPS \
+	LANDS-LO.CPS \
+	MALO0107.CPS \
+	MIG_LO.CPS \
+	MTFACTLO.CPS \
+	NEEDL-LO.CPS \
+	SOV2-LO.CPS \
+	SPY-LO.CPS \
+	STALN-LO.CPS \
+	TENT-LO.CPS \
+	TITLE.CPS \
+	PPAPER.CPS \
+	MSAA.WSA \
+	MSAB.WSA \
+	MSAC.WSA \
+	MSAD.WSA \
+	MSAE.WSA \
+	MSAF.WSA \
+	MSAG.WSA \
+	MSAH.WSA \
+	MSAI.WSA \
+	MSAJ.WSA \
+	MSAK.WSA \
+	MSAL.WSA \
+	MSAM.WSA \
+	MSAN.WSA \
+	MSSA.WSA \
+	MSSB.WSA \
+	MSSC.WSA \
+	MSSD.WSA \
+	MSSE.WSA \
+	MSSF.WSA \
+	MSSG.WSA \
+	MSSH.WSA \
+	MSSI.WSA \
+	MSSJ.WSA \
+	MSSK.WSA \
+	MSSL.WSA \
+	MSSM.WSA \
+	MSSN.WSA \
+
+INTERIORFILES = \
+	BOXES01.INT \
+	BOXES02.INT \
+	BOXES03.INT \
+	BOXES04.INT \
+	BOXES05.INT \
+	BOXES06.INT \
+	BOXES07.INT \
+	BOXES08.INT \
+	BOXES09.INT \
+	XTRA0001.INT \
+	XTRA0002.INT \
+	XTRA0003.INT \
+	XTRA0004.INT \
+	XTRA0005.INT \
+	XTRA0006.INT \
+	XTRA0007.INT \
+	XTRA0008.INT \
+	XTRA0009.INT \
+	XTRA0010.INT \
+	XTRA0011.INT \
+	XTRA0012.INT \
+	XTRA0013.INT \
+	XTRA0014.INT \
+	XTRA0015.INT \
+	XTRA0016.INT \
+	CLEAR1.INT \
+	MOVEFLSH.INT \
+	ARRO0001.INT \
+	ARRO0002.INT \
+	ARRO0003.INT \
+	ARRO0004.INT \
+	ARRO0005.INT \
+	ARRO0006.INT \
+	ARRO0007.INT \
+	ARRO0008.INT \
+	ARRO0009.INT \
+	ARRO0010.INT \
+	ARRO0011.INT \
+	ARRO0012.INT \
+	ARRO0013.INT \
+	ARRO0014.INT \
+	ARRO0015.INT \
+	FLOR0001.INT \
+	FLOR0002.INT \
+	FLOR0003.INT \
+	FLOR0004.INT \
+	FLOR0005.INT \
+	FLOR0006.INT \
+	FLOR0007.INT \
+	GFLR0001.INT \
+	GFLR0002.INT \
+	GFLR0003.INT \
+	GFLR0004.INT \
+	GFLR0005.INT \
+	GSTR0001.INT \
+	GSTR0002.INT \
+	GSTR0003.INT \
+	GSTR0004.INT \
+	GSTR0005.INT \
+	GSTR0006.INT \
+	GSTR0007.INT \
+	GSTR0008.INT \
+	GSTR0009.INT \
+	GSTR0010.INT \
+	GSTR0011.INT \
+	LWAL0001.INT \
+	LWAL0002.INT \
+	LWAL0003.INT \
+	LWAL0004.INT \
+	LWAL0005.INT \
+	LWAL0006.INT \
+	LWAL0007.INT \
+	LWAL0008.INT \
+	LWAL0009.INT \
+	LWAL0010.INT \
+	LWAL0011.INT \
+	LWAL0012.INT \
+	LWAL0013.INT \
+	LWAL0014.INT \
+	LWAL0015.INT \
+	LWAL0016.INT \
+	LWAL0017.INT \
+	LWAL0018.INT \
+	LWAL0019.INT \
+	LWAL0020.INT \
+	LWAL0021.INT \
+	LWAL0022.INT \
+	LWAL0023.INT \
+	LWAL0024.INT \
+	LWAL0025.INT \
+	LWAL0026.INT \
+	LWAL0027.INT \
+	STRP0001.INT \
+	STRP0002.INT \
+	STRP0003.INT \
+	STRP0004.INT \
+	STRP0005.INT \
+	STRP0006.INT \
+	STRP0007.INT \
+	STRP0008.INT \
+	STRP0009.INT \
+	STRP0010.INT \
+	STRP0011.INT \
+	WALL0001.INT \
+	WALL0002.INT \
+	WALL0003.INT \
+	WALL0004.INT \
+	WALL0005.INT \
+	WALL0006.INT \
+	WALL0007.INT \
+	WALL0008.INT \
+	WALL0009.INT \
+	WALL0010.INT \
+	WALL0011.INT \
+	WALL0012.INT \
+	WALL0013.INT \
+	WALL0014.INT \
+	WALL0015.INT \
+	WALL0016.INT \
+	WALL0017.INT \
+	WALL0018.INT \
+	WALL0019.INT \
+	WALL0020.INT \
+	WALL0021.INT \
+	WALL0022.INT \
+	WALL0023.INT \
+	WALL0024.INT \
+	WALL0025.INT \
+	WALL0026.INT \
+	WALL0027.INT \
+	WALL0028.INT \
+	WALL0029.INT \
+	WALL0030.INT \
+	WALL0031.INT \
+	WALL0032.INT \
+	WALL0033.INT \
+	WALL0034.INT \
+	WALL0035.INT \
+	WALL0036.INT \
+	WALL0037.INT \
+	WALL0038.INT \
+	WALL0039.INT \
+	WALL0040.INT \
+	WALL0041.INT \
+	WALL0042.INT \
+	WALL0043.INT \
+	WALL0044.INT \
+	WALL0045.INT \
+	WALL0046.INT \
+	WALL0047.INT \
+	WALL0048.INT \
+	WALL0049.INT \
+
+# Both the temperate and snow sets have identical template entries.
+TEMPERATEFILES = \
+	MINE.TEM \
+	ICE01.TEM \
+	ICE02.TEM \
+	ICE03.TEM \
+	ICE04.TEM \
+	ICE05.TEM \
+	MOVEFLSH.TEM \
+	BR1X.TEM \
+	BR2X.TEM \
+	BRIDGE1X.TEM \
+	BRIDGE2X.TEM \
+	BRIDGE1H.TEM \
+	BRIDGE2H.TEM \
+	F01.TEM \
+	F02.TEM \
+	F03.TEM \
+	F04.TEM \
+	F05.TEM \
+	F06.TEM \
+	ELECTRO.TEM \
+	B1.TEM \
+	B2.TEM \
+	B3.TEM \
+	BIB1.TEM \
+	BIB2.TEM \
+	BIB3.TEM \
+	BR1A.TEM \
+	BR1B.TEM \
+	BR1C.TEM \
+	BR2A.TEM \
+	BR2B.TEM \
+	BR2C.TEM \
+	BR3A.TEM \
+	BR3B.TEM \
+	BR3C.TEM \
+	BR3D.TEM \
+	BR3E.TEM \
+	BR3F.TEM \
+	BRIDGE1.TEM \
+	BRIDGE1D.TEM \
+	BRIDGE2.TEM \
+	BRIDGE2D.TEM \
+	CLEAR1.TEM \
+	CORPSE1.TEM \
+	CORPSE2.TEM \
+	CORPSE3.TEM \
+	CR1.TEM \
+	CR2.TEM \
+	CR3.TEM \
+	CR4.TEM \
+	CR5.TEM \
+	CR6.TEM \
+	D01.TEM \
+	D02.TEM \
+	D03.TEM \
+	D04.TEM \
+	D05.TEM \
+	D06.TEM \
+	D07.TEM \
+	D08.TEM \
+	D09.TEM \
+	D10.TEM \
+	D11.TEM \
+	D12.TEM \
+	D13.TEM \
+	D14.TEM \
+	D15.TEM \
+	D16.TEM \
+	D17.TEM \
+	D18.TEM \
+	D19.TEM \
+	D20.TEM \
+	D21.TEM \
+	D22.TEM \
+	D23.TEM \
+	D24.TEM \
+	D25.TEM \
+	D26.TEM \
+	D27.TEM \
+	D28.TEM \
+	D29.TEM \
+	D30.TEM \
+	D31.TEM \
+	D32.TEM \
+	D33.TEM \
+	D34.TEM \
+	D35.TEM \
+	D36.TEM \
+	D37.TEM \
+	D38.TEM \
+	D39.TEM \
+	D40.TEM \
+	D41.TEM \
+	D42.TEM \
+	D43.TEM \
+	D44.TEM \
+	D45.TEM \
+	FALLS1.TEM \
+	FALLS1A.TEM \
+	FALLS2.TEM \
+	FALLS2A.TEM \
+	FORD1.TEM \
+	FORD2.TEM \
+	GEM01.TEM \
+	GEM02.TEM \
+	GEM03.TEM \
+	GEM04.TEM \
+	GOLD01.TEM \
+	GOLD02.TEM \
+	GOLD03.TEM \
+	GOLD04.TEM \
+	HBOX.TEM \
+	MSLOMAKE.TEM \
+	HBOXMAKE.TEM \
+	MSLO.TEM \
+	P01.TEM \
+	P02.TEM \
+	P03.TEM \
+	P04.TEM \
+	P07.TEM \
+	P08.TEM \
+	P13.TEM \
+	P14.TEM \
+	RC01.TEM \
+	RC02.TEM \
+	RC03.TEM \
+	RC04.TEM \
+	RF01.TEM \
+	RF02.TEM \
+	RF03.TEM \
+	RF04.TEM \
+	RF05.TEM \
+	RF06.TEM \
+	RF07.TEM \
+	RF08.TEM \
+	RF09.TEM \
+	RF10.TEM \
+	RF11.TEM \
+	RV01.TEM \
+	RV02.TEM \
+	RV03.TEM \
+	RV04.TEM \
+	RV05.TEM \
+	RV06.TEM \
+	RV07.TEM \
+	RV08.TEM \
+	RV09.TEM \
+	RV10.TEM \
+	RV11.TEM \
+	RV12.TEM \
+	RV13.TEM \
+	RV14.TEM \
+	RV15.TEM \
+	S01.TEM \
+	S02.TEM \
+	S03.TEM \
+	S04.TEM \
+	S05.TEM \
+	S06.TEM \
+	S07.TEM \
+	S08.TEM \
+	S09.TEM \
+	S10.TEM \
+	S11.TEM \
+	S12.TEM \
+	S13.TEM \
+	S14.TEM \
+	S15.TEM \
+	S16.TEM \
+	S17.TEM \
+	S18.TEM \
+	S19.TEM \
+	S20.TEM \
+	S21.TEM \
+	S22.TEM \
+	S23.TEM \
+	S24.TEM \
+	S25.TEM \
+	S26.TEM \
+	S27.TEM \
+	S28.TEM \
+	S29.TEM \
+	S30.TEM \
+	S31.TEM \
+	S32.TEM \
+	S33.TEM \
+	S34.TEM \
+	S35.TEM \
+	S36.TEM \
+	S37.TEM \
+	S38.TEM \
+	SC1.TEM \
+	SC2.TEM \
+	SC3.TEM \
+	SC4.TEM \
+	SC5.TEM \
+	SC6.TEM \
+	SH01.TEM \
+	SH02.TEM \
+	SH03.TEM \
+	SH04.TEM \
+	SH05.TEM \
+	SH06.TEM \
+	SH07.TEM \
+	SH08.TEM \
+	SH09.TEM \
+	SH10.TEM \
+	SH11.TEM \
+	SH12.TEM \
+	SH13.TEM \
+	SH14.TEM \
+	SH15.TEM \
+	SH16.TEM \
+	SH17.TEM \
+	SH18.TEM \
+	SH19.TEM \
+	SH20.TEM \
+	SH21.TEM \
+	SH22.TEM \
+	SH23.TEM \
+	SH24.TEM \
+	SH25.TEM \
+	SH26.TEM \
+	SH27.TEM \
+	SH28.TEM \
+	SH29.TEM \
+	SH30.TEM \
+	SH31.TEM \
+	SH32.TEM \
+	SH33.TEM \
+	SH34.TEM \
+	SH35.TEM \
+	SH36.TEM \
+	SH37.TEM \
+	SH38.TEM \
+	SH39.TEM \
+	SH40.TEM \
+	SH41.TEM \
+	SH42.TEM \
+	SH43.TEM \
+	SH44.TEM \
+	SH45.TEM \
+	SH46.TEM \
+	SH47.TEM \
+	SH48.TEM \
+	SH49.TEM \
+	SH50.TEM \
+	SH51.TEM \
+	SH52.TEM \
+	SH53.TEM \
+	SH54.TEM \
+	SH55.TEM \
+	SH56.TEM \
+	T01.TEM \
+	T02.TEM \
+	T03.TEM \
+	T05.TEM \
+	T06.TEM \
+	T07.TEM \
+	T08.TEM \
+	T10.TEM \
+	T11.TEM \
+	T12.TEM \
+	T13.TEM \
+	T14.TEM \
+	T15.TEM \
+	T16.TEM \
+	T17.TEM \
+	TC01.TEM \
+	TC02.TEM \
+	TC03.TEM \
+	TC04.TEM \
+	TC05.TEM \
+	V01.TEM \
+	V02.TEM \
+	V03.TEM \
+	V04.TEM \
+	V05.TEM \
+	V06.TEM \
+	V07.TEM \
+	V08.TEM \
+	V09.TEM \
+	V10.TEM \
+	V11.TEM \
+	V12.TEM \
+	V13.TEM \
+	V14.TEM \
+	V15.TEM \
+	V16.TEM \
+	V17.TEM \
+	V18.TEM \
+	W1.TEM \
+	W2.TEM \
+	WC01.TEM \
+	WC02.TEM \
+	WC03.TEM \
+	WC04.TEM \
+	WC05.TEM \
+	WC06.TEM \
+	WC07.TEM \
+	WC08.TEM \
+	WC09.TEM \
+	WC10.TEM \
+	WC11.TEM \
+	WC12.TEM \
+	WC13.TEM \
+	WC14.TEM \
+	WC15.TEM \
+	WC16.TEM \
+	WC17.TEM \
+	WC18.TEM \
+	WC19.TEM \
+	WC20.TEM \
+	WC21.TEM \
+	WC22.TEM \
+	WC23.TEM \
+	WC24.TEM \
+	WC25.TEM \
+	WC26.TEM \
+	WC27.TEM \
+	WC28.TEM \
+	WC29.TEM \
+	WC30.TEM \
+	WC31.TEM \
+	WC32.TEM \
+	WC33.TEM \
+	WC34.TEM \
+	WC35.TEM \
+	WC36.TEM \
+	WC37.TEM \
+	WC38.TEM \
+
+# Every temperate theater terrain file has a snow theater counterpart.
+SNOWFILES = $(TEMPERATEFILES:.TEM=.SNO)
+
+# Sound effects (Juvenile or Adult)
+SFX = \
+
+# Generic wave files (never changes).
+WAVFILES = \
+	AACANON3.AUD \
+	BEEPSLCT.AUD \
+	BLEEP11.AUD \
+	BLEEP12.AUD \
+	BLEEP13.AUD \
+	BLEEP17.AUD \
+	BLEEP5.AUD \
+	BLEEP6.AUD \
+	BLEEP9.AUD \
+	BOMBIT1.AUD \
+	BUILD5.AUD \
+	BUZZY1.AUD \       
+	CANNON1.AUD \
+	CANNON2.AUD \
+	CASHDN1.AUD \
+	CASHTURN.AUD \
+	CASHUP1.AUD \
+	CHRONO2.AUD \
+	CHROTNK1.AUD \
+	CHUTE1.AUD \
+	CMON1.AUD \
+	CRMBLE2.AUD \
+	DEDMAN1.AUD \
+	DEDMAN10.AUD \
+	DEDMAN2.AUD \
+	DEDMAN3.AUD \
+	DEDMAN4.AUD \
+	DEDMAN5.AUD \
+	DEDMAN6.AUD \
+	DEDMAN7.AUD \
+	DEDMAN8.AUD \
+	DOGG5P.AUD \
+	DOGW3PX.AUD \
+	DOGW5.AUD \
+	DOGW6.AUD \
+	DOGW7.AUD \
+	DOGY1.AUD \
+	EAFFIRM1.AUD \
+	EENGIN1.AUD \
+	EINAH1.AUD \
+	EINOK1.AUD \
+	EINYES1.AUD \
+	EMOVOUT1.AUD \
+	EYESSIR1.AUD \
+	FIREBL3.AUD \
+	FIRETRT1.AUD \
+	FIXIT1.AUD \
+	GIRLOKAY.AUD \
+	GIRLYEAH.AUD \
+	GOTIT1.AUD \
+	GRENADE1.AUD \
+	GUN11.AUD \
+	GUN13.AUD \
+	GUN27.AUD \
+	GUN5.AUD \
+	GUYOKAY1.AUD \
+	GUYYEAH1.AUD \
+	H2OBOMB2.AUD \
+	HEAL2.AUD \
+	HYDROD1.AUD \
+	INVUL2.AUD \
+	IRONCUR9.AUD \
+	JBURN1.AUD \
+	JCHRGE1.AUD \
+	JCRISP1.AUD \
+	JDANCE1.AUD \
+	JJUICE1.AUD \
+	JJUMP1.AUD \
+	JLIGHT1.AUD \
+	JPOWER1.AUD \
+	JSHOCK1.AUD \
+	JYES1.AUD \
+	KABOOM1.AUD \
+	KABOOM12.AUD \
+	KABOOM15.AUD \
+	KABOOM22.AUD \
+	KABOOM25.AUD \
+	KABOOM30.AUD \
+	KEEPEM1.AUD \
+	LAUGH1.AUD \
+	LEFTY1.AUD \
+	MADCHRG2.AUD \
+	MADEXPLO.AUD \
+	MAFFIRM1.AUD \
+	MBOSS1.AUD \
+	MHEAR1.AUD \
+	MHOTDIG1.AUD \
+	MHOWDY1.AUD \
+	MHUH1.AUD \
+	MGUNINF1.AUD \
+	MINE1.AUD \
+	MINEBLO1.AUD \
+	MINELAY1.AUD \
+	MISSILE1.AUD \
+	MISSILE6.AUD \
+	MISSILE7.AUD \
+	MLAFF1.AUD \
+	MMOVOUT1.AUD \
+	MRESPON1.AUD \
+	MRISE1.AUD \
+	MWRENCH1.AUD \
+	MYEEHAW1.AUD \
+	MYES1.AUD \
+	MYESSIR1.AUD \
+	ONIT1.AUD \
+	PILLBOX1.AUD \
+	PLACBLDG.AUD \
+	RABEEP1.AUD \
+	RADARDN1.AUD \
+	RADARON2.AUD \
+	RAMENU1.AUD \
+	ROKROLL1.AUD \
+	SAFFIRM1.AUD \
+	SANDBAG2.AUD \
+	SCOLDY1.AUD \
+	SCOMND1.AUD \
+	SHKTROP1.AUD \
+	SILENCER.AUD \
+	SINDEED1.AUD \
+	SKING1.AUD \
+	SMOUT1.AUD \
+	SOKAY1.AUD \
+	SONPULSE.AUD \
+	SONWAY1.AUD \
+	SPLASH9.AUD \
+	SQUISHY2.AUD \
+	SUBSHOW1.AUD \
+	SWHAT1.AUD \
+	SYEAH1.AUD \
+	SYESSIR1.AUD \
+	TANDETH1.AUD \
+	TANK5.AUD \
+	TANK6.AUD \
+	TESLA1.AUD \
+	TORPEDO1.AUD \
+	TSLACHG2.AUD \
+	TUFFGUY1.AUD \
+	TURRET1.AUD \
+	WALLKIL2.AUD \
+	YEAH1.AUD \
+	YES1.AUD \
+	YO1.AUD \
+
+# Vehicle responses
+RESPONSE1 = \
+	ACKNO.AUD \
+	AFFIRM1.AUD \
+	AWAIT1.AUD \
+	REPORT1.AUD \
+	VEHIC1.AUD \
+	YESSIR1.AUD \
+
+# Infantry responses
+RESPONSE2 = \
+	ACKNO.AUD \
+	AFFIRM1.AUD \
+	AWAIT1.AUD \
+	NOPROB.AUD \
+	OVEROUT.AUD \
+	READY.AUD \
+	REPORT1.AUD \
+	RITAWAY.AUD \
+	ROGER.AUD \
+	UGOTIT.AUD \
+	YESSIR1.AUD \
+
+#TSCOREFILES = \
+#	cps\record.bin \
+#	WIN1.AUD \
+#	MAP1.AUD \
+
+VARFILES = \
+
+SCOREFILES = \
+	CREDITS.AUD  \
+	AWAIT.AUD    \
+	BIGF226M.AUD \
+	CRUS226M.AUD \
+	DENSE_R.AUD  \
+	FAC1226M.AUD \
+	FAC2226M.AUD \
+	FOGGER1A.AUD \
+	HELL226M.AUD \
+	MUD1A.AUD \
+	RADIO2.AUD \
+	ROLLOUT.AUD \
+	RUN1226M.AUD \
+	SCORE.AUD \
+	SMSH226M.AUD \
+	SNAKE.AUD \
+	TERMINAT.AUD \
+	TREN226M.AUD \
+	TWIN.AUD \
+	VECTOR1A.AUD \
+	WORK226M.AUD \
+	2ND_HAND.AUD \   
+	ARAZIOD.AUD \   
+	BACKSTAB.AUD \
+	CHAOS2.AUD \ 
+	SHUT_IT.AUD \   
+	TWINMIX1.AUD \   
+	UNDER3.AUD \   
+	VR2.AUD \
+	BOG.AUD \
+	FLOAT_V2.AUD \
+	GLOOM.AUD \
+	GRNDWIRE.AUD \
+	RPT.AUD \
+	SEARCH.AUD \
+	TRACTION.AUD \
+	WASTELND.AUD \
+
+SPEECHFILES = \
+	STRCKIL1.AUD \
+	NOPOWR1.AUD \
+	SAVE1.AUD \
+	LOAD1.AUD \
+	10MINR.AUD \
+	1MINR.AUD \
+	1OBJMET1.AUD \
+	20MINR.AUD \
+	2MINR.AUD \
+	2OBJMET1.AUD \
+	30MINR.AUD \
+	3MINR.AUD \
+	3OBJMET1.AUD \
+	40MINR.AUD \
+	4MINR.AUD \
+	5MINR.AUD \
+	AAPPRO1.AUD \
+	AARIVE1.AUD \
+	AARIVE1.AUD \
+	AARRIVE1.AUD \
+	AARRIVN1.AUD \
+	AARRIVS1.AUD \
+	AARRIVW1.AUD \
+	AAVAIL1.AUD \
+	ABLDGIN1.AUD \
+	AFALLEN1.AUD \
+	ALAUNCH1.AUD \
+	APREP1.AUD \
+	AREADY1.AUD \
+	ARMORUP1.AUD \
+	ASELECT1.AUD \
+	ATLNCH1.AUD \
+	ATPREP1.AUD \
+	AUNITL1.AUD \
+	BASEATK1.AUD \
+	BCT1.AUD \
+	BLDGINF1.AUD \
+	BLDGPRG1.AUD \
+	CANCLD1.AUD \
+	CHROCHR1.AUD \
+	CHRORDY1.AUD \
+	CHROYES1.AUD \
+	CMDCNTR1.AUD \
+	CNTLDED1.AUD \
+	COMNDOF1.AUD \
+	COMNDOR1.AUD \
+	CONSCMP1.AUD \
+	CONVLST1.AUD \
+	CONVYAP1.AUD \
+	CREDIT1.AUD \
+	ENMYAPP1.AUD \
+	FIREPO1.AUD \
+	FLARE1.AUD \
+	FLAREE1.AUD \
+	FLAREN1.AUD \
+	FLARES1.AUD \
+	FLAREW1.AUD \
+	IRONCHG1.AUD \
+	IRONRDY1.AUD \
+	KOSYFRE1.AUD \
+	KOSYRES1.AUD \
+	LOPOWER1.AUD \
+	MERCF1.AUD \
+	MERCR1.AUD \
+	MISNLST1.AUD \
+	MISNWON1.AUD \
+	MTIMEIN1.AUD \
+	NAVYLST1.AUD \
+	NEWOPT1.AUD \
+	NOBUILD1.AUD \
+	NODEPLY1.AUD \
+	NOFUNDS1.AUD \
+	NOFUNDS1.AUD \
+	OBJMET1.AUD \
+	OBJNMET1.AUD \
+	OBJNRCH1.AUD \
+	OBJRCH1.AUD \
+	ONHOLD1.AUD \
+	OPTERM1.AUD \
+	PRIBLDG1.AUD \
+	PROGRES1.AUD \
+	PULSE1.AUD \
+	REINFOR1.AUD \
+	REPAIR1.AUD \
+	REPAIR1.AUD \
+	SATLNCH1.AUD \
+	SILOND1.AUD \
+	SLCTTGT1.AUD \
+	SOVEFAL1.AUD \
+	SOVEMP1.AUD \
+	SOVFAPP1.AUD \
+	SOVFORC1.AUD \
+	SOVREIN1.AUD \
+	SPYPLN1.AUD \
+	STRUCAP1.AUD \
+	STRUSLD1.AUD \
+	TANYAF1.AUD \
+	TANYAR1.AUD \
+	TARGFRE1.AUD \
+	TARGRES1.AUD \
+	TIMERGO1.AUD \
+	TIMERNO1.AUD \
+	TRAIN1.AUD \
+	UNITFUL1.AUD \
+	UNITLST1.AUD \
+	UNITRDY1.AUD \
+	UNITREP1.AUD \
+	UNITSLD1.AUD \
+	UNITSPD1.AUD \
+	XPLOPLC1.AUD \
+#	ABLDGC1.AUD \
+#	SOVBLDG1.AUD \
+#	SOVSTRC1.AUD \
+#	SOVUNTD1.AUD \
+#	AUNITD1.AUD \
+#	ASTRUCD1.AUD \
+
+#ALLIESVQ = \
+DUMMYVQ = \
+	AAGUN.VQA \
+	AFTRMATH.VQA \
+	ALLY1.VQA \
+	ALLY10.VQA \
+	ALLY10B.VQA \
+	ALLY11.VQA \
+	ALLY12.VQA \
+	ALLY14.VQA \
+	ALLY2.VQA \
+	ALLY4.VQA \
+	ALLY5.VQA \
+	ALLY6.VQA \
+	ALLY8.VQA \
+	ALLY9.VQA \
+	ALLYEND.VQA \
+	ALLYMORF.VQA \
+	APCESCPE.VQA \
+	ASSESS.VQA \
+	BATTLE.VQA \
+	1BINOC.VQA \
+	BMAP.VQA \
+	BRDGTILT.VQA \
+	CRONTEST.VQA \
+	CRONFAIL.VQA \
+	DESTROYR.VQA \
+	DUD.VQA \
+	ELEVATOR.VQA \
+	FLARE.VQA \
+	FROZEN.VQA \
+	GRVESTNE.VQA \
+	LANDING.VQA \
+	MASASSLT.VQA \
+	MCV.VQA \
+	MCV_LAND.VQA \
+	MONTPASS.VQA \
+	OILDRUM.VQA \
+	OVERRUN.VQA \
+	PROLOG.VQA \
+	REDINTRO.VQA \
+	SHIPSINK.VQA \
+	SHORBOM1.VQA \
+	SHORBOM2.VQA \
+	SHORBOMB.VQA \
+	SNOWBOMB.VQA \
+	SOVIET1.VQA \
+	SOVTSTAR.VQA \
+	SPY.VQA \
+	TANYA1.VQA \
+	TANYA2.VQA \
+	TOOFAR.VQA \
+	TRINITY.VQA \
+#	TRAILER.VQA \
+
+SOVIETVQ = \
+       	AAGUN.VQA \
+	CRONFAIL.VQA \
+	AIRFIELD.VQA \
+	ALLY1.VQA \
+	ALLYMORF.VQA \
+	AVERTED.VQA \
+	BEACHEAD.VQA \
+	BMAP.VQA \
+	BOMBRUN.VQA \
+	COUNTDWN.VQA \
+	DOUBLE.VQA \
+	DPTHCHRG.VQA \
+	EXECUTE.VQA \
+	FLARE.VQA \
+	LANDING.VQA \
+	MCVBRDGE.VQA \
+	MIG.VQA \
+	MOVINGIN.VQA \
+	MTNKFACT.VQA \
+	NUKESTOK.VQA \
+	ONTHPRWL.VQA \
+	PERISCOP.VQA \
+	PROLOG.VQA \
+	RADRRAID.VQA \
+	REDINTRO.VQA \
+	SEARCH.VQA \
+	SFROZEN.VQA \
+	SITDUCK.VQA \
+	SLNTSRVC.VQA \
+	SNOWBOMB.VQA \
+	SNSTRAFE.VQA \
+	SOVBATL.VQA \
+	SOVCEMET.VQA \
+	SOVFINAL.VQA \
+	SOVIET1.VQA \
+	SOVIET10.VQA \
+	SOVIET11.VQA \
+	SOVIET12.VQA \
+	SOVIET13.VQA \
+	SOVIET14.VQA \
+	SOVIET2.VQA \
+	SOVIET3.VQA \
+	SOVIET4.VQA \
+	SOVIET5.VQA \
+	SOVIET6.VQA \
+	SOVIET7.VQA \
+	SOVIET8.VQA \
+	SOVIET9.VQA \
+	SOVMCV.VQA \
+	SOVTSTAR.VQA \
+	SPOTTER.VQA \
+	STRAFE.VQA \
+	TAKE_OFF.VQA \
+	TESLA.VQA \
+	V2ROCKET.VQA \
+#	TRAILER.VQA \
+
+ALLIESVQ = \
+	SOVIET1.VQA \
+	ALLY1.VQA \
+	V2ROCKET.VQA \		
+	BMAP.VQA \	
+	SNSTRAFE.VQA \
+	SOVTSTAR.VQA \
+	SOVBATL.VQA \
+	SOVCEMET.VQA \
+	FLARE.VQA \	
+	ALLYMORF.VQA \
+	SPY.VQA \
+	FROZEN.VQA \
+	GRVESTNE.VQA \
+	CRONFAIL.VQA \
+	APCESCPE.VQA \
+	EXECUTE.VQA \
+	TOOFAR.VQA \
+	TRINITY.VQA \
+	TESLA.VQA \
+	MASASSLT.VQA \
+	OVERRUN.VQA \
+	PROLOG.VQA \
+	REDINTRO.VQA \
+	AFTRMATH.VQA \
+	PROLOG.VQA \
+	SNOWBOMB.VQA \
+	LANDING.VQA \
+	SFROZEN.VQA \
+	ANTEND.VQA \
+	ANTINTRO.VQA \
+	
+
+
+# Files required for hires/Win95 version only
+#
+# This mix file is not cached
+#
+NOCACHEHIRESFILES= \
+	ENGLISH.VQA \
+	$(ALLIESVQ:.VQA=.VQP) \
+	$(SOVIETVQ:.VQA=.VQP) \
+       
+
+LINTOBJECTS1 = $(OBJECTS:,=)
+LINTOBJECTS = $(LINTOBJECTS1:.OBJ=.LOB)
+
+# Mixfiles that should reside on the CD-ROM drive.
+CD1MIXFILES = \
+	CONQUER.MIX \
+	EDHI.MIX \
+	EDLO.MIX \
+	GENERAL.MIX \
+	INTERIOR.MIX \
+	MOVIES1.MIX \
+	SCORES.MIX \
+	SNOW.MIX \
+	SOUNDS.MIX \
+ 	RUSSIAN.MIX \
+	ALLIES.MIX \
+	TEMPERAT.MIX \
+	
+
+
+# Mixfiles that should reside on the hard drive.
+LOCALMIXFILES = \
+	EDITOR.MIX \
+	HIRES.MIX \
+	LOCAL.MIX \
+	LORES.MIX \
+	NCHIRES.MIX \
+	SPEECH.MIX \
+	
+
+# Mixfiles as they appear on the CD and hard drive.
+PACKFILES=	$(.path.cd1)MAIN.MIX  EXPAND2.MIX  $(.path.cd1)tobreaki\REDALERT.MIX
+
+
+# Ant assets SOME ASSETS ARE HERE FOR OVERRIDING
+EXPANDFILES= \
+	ANT1.SHP \
+	ANT2.SHP \
+	ANT3.SHP \
+	QUEE.SHP \
+	CREDITS.ENG \
+	HILL01.TEM \
+	ANTBITE.AUD \
+	ANTDIE.AUD \
+	ANTDIE.SHP \
+	LAR1.SHP \
+	LAR2.SHP \
+	TITLE.PCX \							  
+	MISSION.INI \
+	BUZZY1.AUD \       
+	STAVCMDR.AUD \     
+	STAVCRSE.AUD \     
+	STAVYES.AUD \      
+	STAVMOV.AUD \
+	CONQUER.ENG \   
+	RAMBO1.AUD \
+	RAMBO2.AUD \
+	RAMBO3.AUD \
+	TITLE.CPS \
+	ANTEND.VQP \
+	TUTORIAL.INI \
+	ANTINTRO.VQP \
+	BMAP.VQP \
+
+# Aftermath expansion files
+EXPAND2FILES= \
+	CARR.SHP \
+	CTNK.SHP \
+	DTRK.SHP \
+	MSUB.SHP \
+	QTNK.SHP \
+	TTNK.SHP \
+	STNK.SHP \
+	AFTRMATH.INI \
+	ANT1.SHP \
+	ANT2.SHP \
+	ANT3.SHP \
+	ANTBITE.AUD \
+	ANTDIE.AUD \
+	ANTDIE.SHP \
+	BMAP.VQP \
+	BUZZY1.AUD \       
+	CONQUER.ENG \   
+	CREDITS.ENG \
+	HILL01.TEM \
+	LAR1.SHP \
+	LAR2.SHP \
+	MISSION.INI \
+	MPLAYER.INI \
+	QUEE.SHP \
+	STAVCMDR.AUD \     
+	STAVCRSE.AUD \     
+	STAVYES.AUD \      
+	STAVMOV.AUD \
+	TITLE.PCX \							  
+	TITLE.CPS \
+	TUTORIAL.INI \
+
+
+
+#############################################################
+# Rebuilds all the mixfiles.				  
+packfiles:	always $(PACKFILES)
+
+always:
+	copy f:\projects\c&c0\editor\english\*.mix $(.path.mix) /u
+
+
+####################################################################
+# All mixfiles that exist on the CD-ROM are embedded within this mega-mixfile.
+$(.path.cd1)MAIN.MIX: $(CD1MIXFILES)
+	UTILS\MIXFILE -k -I$(.path.mix) &&!
+	$**
+! $(.path.cd1)$&.mix
+
+
+# All mixfiles that exist in the local directory are embedded within this mega-mixfile.
+$(.path.cd1)install\REDALERT.MIX: $(LOCALMIXFILES)
+	UTILS\MIXFILE -k  -I$(.path.mix) &&!
+	$**
+! $(.path.cd1)install\$&.mix
+
+
+####################################################################
+# These are the various sub-mixfiles.
+CONQUER.MIX: $(CONQUERFILES) $(CACHEMAP) .\key.ini
+	UTILS\MIXFILE -k -h -I$(.path.cps) &&!
+	$(CONQUERFILES) $(CACHEMAP)
+! $(.path.mix)$&.mix
+
+TEMPERAT.MIX: $(TEMPERATEFILES) .\key.ini
+	UTILS\MIXFILE -h -k -I$(.path.cps) &&!
+	$(TEMPERATEFILES)
+! $(.path.mix)$&.mix
+
+SNOW.MIX: $(SNOWFILES) .\key.ini
+	UTILS\MIXFILE -h -k -I$(.path.cps) &&!
+	$(SNOWFILES)
+! $(.path.mix)$&.mix
+
+INTERIOR.MIX: $(INTERIORFILES) .\key.ini
+	UTILS\MIXFILE -h -k -I$(.path.cps) &&!
+	$(INTERIORFILES)
+! $(.path.mix)$&.mix
+
+GENERAL.MIX: $(GENERALFILES) $(GENERALMAPFILES) $(NETMAPFILES) $(MAPFILES) .\key.ini
+	UTILS\MIXFILE -k -I$(.path.cps) -I$(.path.ini) &&!
+	$(GENERALFILES) $(GENERALMAPFILES) $(NETMAPFILES) $(MAPFILES)
+! $(.path.mix)$&.mix
+
+SCORES.MIX: $(SCOREFILES)
+	UTILS\MIXFILE -k -I$(.path.cps) -I$(.path.ini) &&!
+	$**
+! $(.path.mix)$&.mix
+
+SOUNDS.MIX: $(WAVFILES) $(SFX)
+	UTILS\MIXFILE -h -k -EA60=V00 -EA61=V01 -EA62=V02 -EA63=V03 -I$(.path.aud) &&!
+	$**
+! $(.path.mix)$&.mix
+
+RUSSIAN.MIX: $(RESPONSE1:.AUD=.R00) $(RESPONSE2:.AUD=.R01) $(RESPONSE1:.AUD=.R02) $(RESPONSE2:.AUD=.R03)
+	UTILS\MIXFILE -h -k -I$(.path.aud) &&!
+	$**
+! $(.path.mix)$&.mix
+
+LIMITED.MIX: BLEEP11.AUD
+	UTILS\MIXFILE -h -k -I$(.path.aud) &&!
+	$**
+! $(.path.mix)$&.mix
+
+ALLIES.MIX: $(RESPONSE1:.AUD=.V00) $(RESPONSE2:.AUD=.V01) $(RESPONSE1:.AUD=.V02) $(RESPONSE2:.AUD=.V03)
+	UTILS\MIXFILE -h -k -I$(.path.aud) &&!
+	$**
+! $(.path.mix)$&.mix
+
+MOVIES1.MIX: $(ALLIESVQ)
+	UTILS\MIXFILE -k -I$(.path.vqa) &&!
+	$**
+! $(.path.mix)$&.mix
+
+
+
+
+
+NCHIRES.MIX: $(NOCACHEHIRESFILES:.SHP=.HI)
+	UTILS\MIXFILE -k -I$(.path.vqp) -I$(.path.cps) &&!
+	$(NOCACHEHIRESFILES)
+! $(.path.mix)$&.mix
+
+LOCAL.MIX: $(LOCALFILES) .\key.ini
+	UTILS\MIXFILE -h -k -E.A6=.AUD -I$(.path.ini) -I$(.path.txt) -I$(.path.cps) &&!
+	$(LOCALFILES)
+! $(.path.mix)$&.mix
+
+LORES.MIX: $(LOHILORES) .\key.ini
+	UTILS\MIXFILE -h -k -E.LOW=.SHP -E.LNT=.FNT -I$(.path.cps) &&!
+	$(LOHILORES)
+! $(.path.mix)$&.mix
+
+HIRES.MIX: $(HIRESFILES:.SHP=.HI) $(HIHILORES) .\key.ini
+	UTILS\MIXFILE -h -k -E.HI=.SHP -E.HNT=.FNT -I$(.path.cps) &&!
+	$(HIRESFILES:.SHP=.HI) $(HIHILORES)
+! $(.path.mix)$&.mix
+
+SPEECH.MIX: $(SPEECHFILES)
+	UTILS\MIXFILE -k -I$(.path.aud) &&!
+	$**
+! $(.path.mix)$&.mix
+
+
+EXPAND.MIX: $(EXPANDFILES)			   
+	UTILS\MIXFILE -k  -I$(.path.mix)  &&!
+	$**
+! $(.path.mix)$&.mix
+
+EXPAND2.MIX: $(EXPAND2FILES)			   
+	UTILS\MIXFILE -k  -I$(.path.mix)  &&!
+	$**
+! $(.path.mix)$&.mix
+
+#############################################################
+# Special rule to create the mouse shape (which must be a shape file)
+mouse.hi:	$(.path.anm)hires\mouse.anm
+	-utils\makeshps $(.path.lbm)palettes\temperat.lbm &&!
+ &$(.path.anm)hires\mouse.anm;
+ end;
+! $(.path.hi)$&.hi $(SHAPEBUFFSIZE)
+
+# Special rule to create the mouse shape (which must be a shape file)
+mouse.low:	$(.path.anm)lores\mouse.anm
+	-utils\makeshps $(.path.lbm)palettes\temperat.lbm &&!
+ &$(.path.anm)lores\mouse.anm;
+ end;
+! $(.path.low)$&.low $(SHAPEBUFFSIZE)
+
+
+#############################################################
+# Special build rule for radar animations so that they won't.
+#
+NATORADR.HI: $(.path.anm)hires\NATORADR.ANM
+	utils\newkeyf $** $(.path.hi)$&.hi -l -k
+
+USSRRADR.HI: $(.path.anm)hires\USSRRADR.ANM
+	utils\newkeyf $** $(.path.hi)$&.hi -l -k
+
+NATORADR.LOW: $(.path.anm)lores\NATORADR.ANM
+	utils\newkeyf $** $(.path.low)$&.low -l -k
+
+USSRRADR.LOW: $(.path.anm)lores\USSRRADR.ANM
+	utils\newkeyf $** $(.path.low)$&.low -l -k
+
+
+#############################################################
+# Debug text file creation.
+debug.eng:	debug.txt
+	utils\textmake -b1000 eng\$&.txt $(.path.eng)$&.eng $&.h
+
+

+ 987 - 0
CODE/BFIOFILE.CPP

@@ -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 - 0
CODE/BFIOFILE.H

@@ -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 - 0
CODE/BIGCHECK.CPP

@@ -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 - 0
CODE/BIGCHECK.H

@@ -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 - 0
CODE/BLOWFISH.CPP

@@ -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 - 0
CODE/BLOWFISH.H

@@ -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 - 0
CODE/BLOWPIPE.CPP

@@ -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 - 0
CODE/BLOWPIPE.H

@@ -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 - 0
CODE/BLWSTRAW.CPP

@@ -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 - 0
CODE/BLWSTRAW.H

@@ -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 - 0
CODE/BMP8.CPP

@@ -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 - 0
CODE/BMP8.H

@@ -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 - 0
CODE/BUFF.CPP

@@ -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 - 0
CODE/BUFF.H

@@ -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 - 0
CODE/BUFFERX.H

@@ -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 - 0
CODE/BUGS.TXT

@@ -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 - 0
CODE/BUILDING.CPP

@@ -0,0 +1,5712 @@
+/*
+**	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.CPP 5     3/13/97 5:18p Joe_b $ */
+/***********************************************************************************************
+ ***              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.CPP                                                 *
+ *                                                                                             *
+ *                   Programmer : Joe L. Bostic                                                *
+ *                                                                                             *
+ *                   Start Date : September 10, 1993                                           *
+ *                                                                                             *
+ *                  Last Update : October 27, 1996 [JLB]                                       *
+ *                                                                                             *
+ *---------------------------------------------------------------------------------------------*
+ * Functions:                                                                                  *
+ *   BuildingClass::AI -- Handles non-graphic AI processing for buildings.                     *
+ *   BuildingClass::Active_Click_With -- Handles cell selection for buildings.                 *
+ *   BuildingClass::Animation_AI -- Handles normal building animation processing.              *
+ *   BuildingClass::Assign_Target -- Assigns a target to the building.                         *
+ *   BuildingClass::Begin_Mode -- Begins an animation mode for the building.                   *
+ *   BuildingClass::BuildingClass -- Constructor for buildings.                                *
+ *   BuildingClass::Can_Demolish -- Can the player demolish (sell back) the building?          *
+ *   BuildingClass::Can_Enter_Cell -- Determines if building can be placed down.               *
+ *   BuildingClass::Can_Fire -- Determines if this building can fire.                          *
+ *   BuildingClass::Can_Player_Move -- Can this building be moved?                             *
+ *   BuildingClass::Captured -- Captures the building.                                         *
+ *   BuildingClass::Center_Coord -- Fetches the center coordinate for the building.            *
+ *   BuildingClass::Charging_AI -- Handles the special charging logic for Tesla coils.         *
+ *   BuildingClass::Check_Point -- Fetches the landing checkpoint for the given flight pattern.*
+ *   BuildingClass::Click_With -- Handles clicking on the map while the building is selected.  *
+ *   BuildingClass::Crew_Type -- This determines the crew that this object generates.          *
+ *   BuildingClass::Death_Announcement -- Announce the death of this building.                 *
+ *   BuildingClass::Debug_Dump -- Displays building status to the monochrome screen.           *
+ *   BuildingClass::Detach -- Handles target removal from the game system.                     *
+ *   BuildingClass::Detach_All -- Possibly abandons production according to factory type.      *
+ *   BuildingClass::Docking_Coord -- Fetches the coordinate to use for docking.                *
+ *   BuildingClass::Draw_It -- Displays the building at the location specified.                *
+ *   BuildingClass::Drop_Debris -- Drops rubble when building is destroyed.                    *
+ *   BuildingClass::Enter_Idle_Mode -- The building will enter its idle mode.                  *
+ *   BuildingClass::Exit_Coord -- Determines location where object will leave it.              *
+ *   BuildingClass::Exit_Object -- Initiates an object to leave the building.                  *
+ *   BuildingClass::Factory_AI -- Handle factory production and initiation.                    *
+ *   BuildingClass::Find_Exit_Cell -- Find a clear location to exit an object from this buildin*
+ *   BuildingClass::Fire_Direction -- Fetches the direction of firing.                         *
+ *   BuildingClass::Fire_Out -- Handles when attached animation expires.                       *
+ *   BuildingClass::Flush_For_Placement -- Handles clearing a zone for object placement.       *
+ *   BuildingClass::Get_Image_Data -- Fetch the image pointer for the building.                *
+ *   BuildingClass::Grand_Opening -- Handles construction completed special operations.        *
+ *   BuildingClass::Greatest_Threat -- Searches for target that building can fire upon.        *
+ *   BuildingClass::How_Many_Survivors -- This determine the maximum number of survivors.      *
+ *   BuildingClass::Init -- Initialize the building system to an empty null state.             *
+ *   BuildingClass::Limbo -- Handles power adjustment as building goes into limbo.             *
+ *   BuildingClass::Mark -- Building interface to map rendering system.                        *
+ *   BuildingClass::Mission_Attack -- Handles attack mission for building.                     *
+ *   BuildingClass::Mission_Construction -- Handles mission construction.                      *
+ *   BuildingClass::Mission_Deconstruction -- Handles building deconstruction.                 *
+ *   BuildingClass::Mission_Guard -- Handles guard mission for combat buildings.               *
+ *   BuildingClass::Mission_Harvest -- Handles refinery unloading harvesters.                  *
+ *   BuildingClass::Mission_Missile -- State machine for nuclear missile launch.               *
+ *   BuildingClass::Mission_Repair -- Handles the repair (active) state for building.          *
+ *   BuildingClass::Mission_Unload -- Handles the unload mission for a building.               *
+ *   BuildingClass::Pip_Count -- Determines "full" pips to display for building.               *
+ *   BuildingClass::Power_Output -- Fetches the current power output from this building.       *
+ *   BuildingClass::Read_INI -- Reads buildings from INI file.                                 *
+ *   BuildingClass::Receive_Message -- Handle an incoming message to the building.             *
+ *   BuildingClass::Remap_Table -- Fetches the remap table to use for this building.           *
+ *   BuildingClass::Remove_Gap_Effect -- Stop a gap generator from jamming cells               *
+ *   BuildingClass::Repair -- Initiates or terminates the repair process.                      *
+ *   BuildingClass::Repair_AI -- Handle the repair (and sell) logic for the building.          *
+ *   BuildingClass::Revealed -- Reveals the building to the specified house.                   *
+ *   BuildingClass::Rotation_AI -- Process any turret rotation required of this building.      *
+ *   BuildingClass::Sell_Back -- Controls the sell back (demolish) operation.                  *
+ *   BuildingClass::Shape_Number -- Fetch the shape number for this building.                  *
+ *   BuildingClass::Sort_Y -- Returns the building coordinate used for sorting.                *
+ *   BuildingClass::Take_Damage -- Inflicts damage points upon a building.                     *
+ *   BuildingClass::Target_Coord -- Return the coordinate to use when firing on this building. *
+ *   BuildingClass::Toggle_Primary -- Toggles the primary factory state.                       *
+ *   BuildingClass::Turret_Facing -- Fetches the turret facing for this building.              *
+ *   BuildingClass::Unlimbo -- Removes a building from limbo state.                            *
+ *   BuildingClass::Update_Buildables -- Informs sidebar of additional construction options.   *
+ *   BuildingClass::Value -- Determine the value of this building.                             *
+ *   BuildingClass::What_Action -- Determines action to perform if click on specified object.  *
+ *   BuildingClass::What_Action -- Determines what action will occur.                          *
+ *   BuildingClass::Write_INI -- Write out the building data to the INI file specified.        *
+ *   BuildingClass::delete -- Deallocates building object.                                     *
+ *   BuildingClass::new -- Allocates a building object from building pool.                     *
+ *   BuildingClass::~BuildingClass -- Destructor for building type objects.                    *
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+#include	"function.h"
+
+
+enum SAMState {
+	SAM_READY,					// Launcher can be facing any direction tracking targets.
+	SAM_FIRING					// Stationary while missile is being fired.
+};
+
+
+/***************************************************************************
+**	Center of building offset table.
+*/
+COORDINATE const BuildingClass::CenterOffset[BSIZE_COUNT] = {
+	0x00800080L,
+	0x008000FFL,
+	0x00FF0080L,
+	0x00FF00FFL,
+	0x018000FFL,
+	0x00FF0180L,
+	0x01800180L,
+
+	0x00FF0200L,
+
+	0x02800280L,
+};
+
+
+/***********************************************************************************************
+ * BuildingClass::Receive_Message -- Handle an incoming message to the building.               *
+ *                                                                                             *
+ *    This routine handles an incoming message to the building. Messages regulate the          *
+ *    various cooperative ventures between buildings and units. This might include such        *
+ *    actions as coordinating the construction yard animation with the actual building's       *
+ *    construction animation.                                                                  *
+ *                                                                                             *
+ * INPUT:   from     -- The originator of the message received.                                *
+ *                                                                                             *
+ *          message  -- The radio message received.                                            *
+ *                                                                                             *
+ *          param    -- Reference to an optional parameter that might be used to return        *
+ *                      extra information to the message originator.                           *
+ *                                                                                             *
+ * OUTPUT:  Returns with the response to the message (typically, this is just RADIO_OK).       *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/09/1994 JLB : Created.                                                                 *
+ *   06/26/1995 JLB : Forces refinery load anim to start immediately.                          *
+ *   08/13/1995 JLB : Uses ScenarioInit for special loose "CAN_LOAD" check.                    *
+ *=============================================================================================*/
+RadioMessageType BuildingClass::Receive_Message(RadioClass * from, RadioMessageType message, long & param)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	switch (message) {
+
+		/*
+		**	This message is received as a request to attach/load/dock with this building.
+		**	Verify that this is allowed and return the appropriate response.
+		*/
+		case RADIO_CAN_LOAD:
+			TechnoClass::Receive_Message(from, message, param);
+			if (!House->Is_Ally(from)) return(RADIO_STATIC);
+			if (Mission == MISSION_CONSTRUCTION || Mission == MISSION_DECONSTRUCTION || BState == BSTATE_CONSTRUCTION || (!ScenarioInit && In_Radio_Contact() && Contact_With_Whom() != from)) return(RADIO_NEGATIVE);
+			switch (Class->Type) {
+				case STRUCT_AIRSTRIP:
+					if (from->What_Am_I() == RTTI_AIRCRAFT && ((AircraftClass const *)from)->Class->IsFixedWing) {
+						return(RADIO_ROGER);
+					}
+					break;
+
+				case STRUCT_HELIPAD:
+					if (from->What_Am_I() == RTTI_AIRCRAFT && !((AircraftClass const *)from)->Class->IsFixedWing) {
+						return(RADIO_ROGER);
+					}
+					break;
+
+				case STRUCT_REPAIR:
+					if (from->What_Am_I() == RTTI_UNIT || (from->What_Am_I() == RTTI_AIRCRAFT)) {
+						if (Transmit_Message(RADIO_ON_DEPOT, from) != RADIO_ROGER) {
+							return(RADIO_ROGER);
+						}
+					}
+					return(RADIO_NEGATIVE);
+
+				case STRUCT_REFINERY:
+					if (from->What_Am_I() == RTTI_UNIT &&
+						*((UnitClass *)from) == UNIT_HARVESTER &&
+						(ScenarioInit || !Is_Something_Attached())) {
+
+						return(RADIO_ROGER);
+					}
+					break;
+
+				default:
+					break;
+			}
+			return(RADIO_STATIC);
+
+		/*
+		**	This message is received when the object has attached itself to this
+		**	building.
+		*/
+		case RADIO_IM_IN:
+			if (Mission == MISSION_DECONSTRUCTION) {
+				return(RADIO_NEGATIVE);
+			}
+			switch (Class->Type) {
+				case STRUCT_REPAIR:
+					IsReadyToCommence = true;
+					Assign_Mission(MISSION_REPAIR);
+					from->Assign_Mission(MISSION_SLEEP);
+					return(RADIO_ROGER);
+
+				case STRUCT_AIRSTRIP:
+				case STRUCT_HELIPAD:
+					Assign_Mission(MISSION_REPAIR);
+					from->Assign_Mission(MISSION_SLEEP);
+					return(RADIO_ROGER);
+
+				case STRUCT_REFINERY:
+					Mark(MARK_CHANGE);
+					from->Assign_Mission(MISSION_UNLOAD);
+					return(RADIO_ROGER);
+
+				default:
+					break;
+			}
+			break;
+
+		/*
+		**	Docking maneuver maintenance message. See if new order should be given to the
+		**	unit trying to dock.
+		*/
+		case RADIO_DOCKING:
+			TechnoClass::Receive_Message(from, message, param);
+
+			/*
+			**	When in radio contact for loading, the refinery starts
+			**	flashing the lights.
+			*/
+			if (*this == STRUCT_REFINERY && BState != BSTATE_FULL) {
+				Begin_Mode(BSTATE_FULL);
+			}
+
+			/*
+			**	If this building is already in radio contact, then it might
+			**	be able to satisfy the request to load by bumping off any
+			**	preoccupying task.
+			*/
+			if (*this == STRUCT_REPAIR) {
+				if (Contact_With_Whom() != from) {
+					if (Transmit_Message(RADIO_ON_DEPOT) == RADIO_ROGER) {
+						if (Transmit_Message(RADIO_NEED_REPAIR) == RADIO_NEGATIVE) {
+							Transmit_Message(RADIO_RUN_AWAY);
+							return(RADIO_ROGER);
+						}
+//					} else {
+//						if (Transmit_Message(RADIO_NEED_TO_MOVE, from) == RADIO_ROGER) {
+//							param = (long)As_Target();
+//							Transmit_Message(RADIO_MOVE_HERE, param, from);
+//						}
+					}
+				} else {
+					if (Transmit_Message(RADIO_NEED_REPAIR) == RADIO_NEGATIVE) {
+						return(RADIO_NEGATIVE);
+					}
+				}
+			}
+
+			/*
+			**	Establish contact with the object if this building isn't already in contact
+			**	with another.
+			*/
+			if (!In_Radio_Contact()) {
+				Transmit_Message(RADIO_HELLO, from);
+			}
+
+			if (Transmit_Message(RADIO_NEED_TO_MOVE) == RADIO_ROGER) {
+				switch (Class->Type) {
+					case STRUCT_AIRSTRIP:
+						param = As_Target();
+						break;
+
+					case STRUCT_HELIPAD:
+						param = As_Target();
+						break;
+
+					case STRUCT_REPAIR:
+						Transmit_Message(RADIO_TETHER);
+						param = ::As_Target(Coord_Cell(Center_Coord()));
+						break;
+
+					case STRUCT_REFINERY:
+						param = ::As_Target(Coord_Cell(Adjacent_Cell(Center_Coord(), DIR_S)));
+						break;
+				}
+
+				/*
+				**	Tell the harvester to move to the docking pad of the building.
+				*/
+				if (Transmit_Message(RADIO_MOVE_HERE, param) == RADIO_YEA_NOW_WHAT) {
+
+					/*
+					**	Since the harvester is already there, tell it to begin the backup
+					**	procedure now. If it can't, then tell it to get outta here.
+					*/
+					Transmit_Message(RADIO_TETHER);
+					if (*this == STRUCT_REFINERY && Transmit_Message(RADIO_BACKUP_NOW, from) != RADIO_ROGER) {
+						from->Scatter(NULL, true, true);
+					}
+				}
+			}
+			return(RADIO_ROGER);
+
+		/*
+		**	If a transport or harvester is requesting permission to head toward, dock
+		**	and load/unload, check to make sure that this is allowed given the current
+		**	state of the building.
+		*/
+		case RADIO_ARE_REFINERY:
+			if (Is_Something_Attached() || In_Radio_Contact() || IsInLimbo || House->Class->House != from->Owner() || (*this != STRUCT_REFINERY/* && *this != STRUCT_REPAIR*/)) {
+				return(RADIO_NEGATIVE);
+			}
+			return(RADIO_ROGER);
+
+		/*
+		**	Someone is telling us that it is starting construction. This should only
+		**	occur if this is a construction yard and a building was just placed on
+		**	the map.
+		*/
+		case RADIO_BUILDING:
+			Assign_Mission(MISSION_REPAIR);
+			TechnoClass::Receive_Message(from, message, param);
+			return(RADIO_ROGER);
+
+		/*
+		**	Someone is telling us that they have finished construction. This should
+		**	only occur if this is a construction yard and the building that was being
+		**	constructed has finished. In this case, stop the construction yard
+		**	animation.
+		*/
+		case RADIO_COMPLETE:
+			if (Mission != MISSION_DECONSTRUCTION) {
+				Assign_Mission(MISSION_GUARD);
+			}
+			TechnoClass::Receive_Message(from, message, param);
+			return(RADIO_ROGER);
+
+		/*
+		**	This message may occur unexpectedly if the unit in contact with this
+		**	building is suddenly destroyed. Handle any cleanup necessary. For example,
+		**	a construction yard should stop its construction animation in this case.
+		*/
+		case RADIO_OVER_OUT:
+			Begin_Mode(BSTATE_IDLE);
+			TechnoClass::Receive_Message(from, message, param);
+			return(RADIO_ROGER);
+
+		/*
+		**	This message is received when an object has completely left
+		** building. Sometimes special cleanup action is required when
+		**	this event occurs.
+		*/
+		case RADIO_UNLOADED:
+			if (*this == STRUCT_REPAIR) {
+				if (Distance(from) < 0x0180) {
+					return(RADIO_ROGER);
+				}
+			}
+			TechnoClass::Receive_Message(from, message, param);
+			if (*this == STRUCT_WEAP || *this == STRUCT_AIRSTRIP || *this == STRUCT_REPAIR) return(RADIO_RUN_AWAY);
+			return(RADIO_ROGER);
+
+		default:
+			break;
+	}
+
+	/*
+	**	Pass along the message to the default message handler in the radio itself.
+	*/
+	return(TechnoClass::Receive_Message(from, message, param));
+}
+
+
+#ifdef CHEAT_KEYS
+/***********************************************************************************************
+ * BuildingClass::Debug_Dump -- Displays building status to the monochrome screen.             *
+ *                                                                                             *
+ *    This utility function will output the current status of the building class to the        *
+ *    monochrome screen. It is through this data that bugs may be fixed or detected.           *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/31/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BuildingClass::Debug_Dump(MonoClass * mono) const
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	mono->Set_Cursor(0, 0);
+	mono->Print(Text_String(TXT_DEBUG_BUILDING));
+	mono->Fill_Attrib(66, 13, 12, 1, IsRepairing ? MonoClass::INVERSE : MonoClass::NORMAL);
+	mono->Fill_Attrib(66, 14, 12, 1, IsToRebuild ? MonoClass::INVERSE : MonoClass::NORMAL);
+	mono->Fill_Attrib(66, 15, 12, 1, IsAllowedToSell ? MonoClass::INVERSE : MonoClass::NORMAL);
+	mono->Fill_Attrib(66, 16, 12, 1, IsCharging ? MonoClass::INVERSE : MonoClass::NORMAL);
+	mono->Fill_Attrib(66, 17, 12, 1, IsCharged ? MonoClass::INVERSE : MonoClass::NORMAL);
+	mono->Fill_Attrib(66, 18, 12, 1, IsJamming ? MonoClass::INVERSE : MonoClass::NORMAL);
+	mono->Fill_Attrib(66, 19, 12, 1, IsJammed ? MonoClass::INVERSE : MonoClass::NORMAL);
+
+	mono->Set_Cursor(1, 11);
+	if (Factory) {
+		mono->Printf("%s %d%%", Factory->Get_Object()->Class_Of().IniName, (100*Factory->Completion())/FactoryClass::STEP_COUNT);
+	}
+
+	TechnoClass::Debug_Dump(mono);
+}
+#endif
+
+
+/***********************************************************************************************
+ * BuildingClass::Draw_It -- Displays the building at the location specified.                  *
+ *                                                                                             *
+ *    This is the low level graphic routine that displays the building at the location         *
+ *    specified.                                                                               *
+ *                                                                                             *
+ * INPUT:   x,y   -- The coordinate to draw the building at.                                   *
+ *                                                                                             *
+ *          window   -- The clipping window to use.                                            *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/20/1994 JLB : Created.                                                                 *
+ *   06/27/1994 JLB : Takes a clipping window parameter.                                       *
+ *   07/06/1995 JLB : Handles damaged silos correctly.                                         *
+ *=============================================================================================*/
+void BuildingClass::Draw_It(int x, int y, WindowNumberType window) const
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	/*
+	**	The shape file to use for rendering depends on whether the building
+	**	is undergoing construction or not.
+	*/
+	void const * shapefile = Get_Image_Data();
+	if (shapefile == NULL) return;
+
+	/*
+	**	Actually draw the building shape.
+	*/
+	IsTheaterShape = Class->IsTheater;	//Let Build_Frame know if this is a theater specific shape
+	Techno_Draw_Object(shapefile, Shape_Number(), x, y, window);
+	IsTheaterShape = false;
+
+	/*
+	** Patch for adding overlay onto weapon factory.  Only add the overlay if
+	** the building has more than 1 hp.  Also, if the building's in radio
+	** contact, he must be unloading a constructed vehicle, so draw that
+	** vehicle before drawing the overlay.
+	*/
+	if (BState != BSTATE_CONSTRUCTION) {
+
+		/*
+		**	A Tethered object is always rendered AFTER the building.
+		*/
+		if (IsTethered && In_Radio_Contact() && !Contact_With_Whom()->IsInLimbo && Contact_With_Whom()->What_Am_I() != RTTI_BUILDING) {
+			TechnoClass * contact = Contact_With_Whom();
+
+			assert(contact->IsActive);
+			int xxx = x + ((int)Lepton_To_Pixel((int)Coord_X(contact->Render_Coord())) - (int)Lepton_To_Pixel((int)Coord_X(Render_Coord())));
+			int yyy = y + ((int)Lepton_To_Pixel((int)Coord_Y(contact->Render_Coord())) - (int)Lepton_To_Pixel((int)Coord_Y(Render_Coord())));
+			contact->Draw_It(xxx, yyy, window);
+			contact->IsToDisplay = false;
+		}
+
+		/*
+		**	Draw the weapon factory custom overlay graphic.
+		*/
+		if ( (*this == STRUCT_WEAP || *this == STRUCT_FAKEWEAP)) {
+			int shapenum = Door_Stage();
+			if (Health_Ratio() <= Rule.ConditionYellow) shapenum += 4;
+			Techno_Draw_Object(Class->WarFactoryOverlay, shapenum, x, y, window);
+		}
+
+		/*
+		**	Draw any repair feedback graphic required.
+		*/
+		if (IsRepairing && IsWrenchVisible) {
+			CC_Draw_Shape(ObjectTypeClass::SelectShapes, SELECT_WRENCH, x, y, window, SHAPE_CENTER|SHAPE_WIN_REL);
+		}
+	}
+
+	TechnoClass::Draw_It(x, y, window);
+
+	/*
+	** If this is a factory that we're spying on, show what it's producing
+	*/
+	if (SpiedBy & (1<<(PlayerPtr->Class->House)) && IsSelected) {
+
+		/*
+		**	Fetch the factory that is associate with this building. For computer controlled buildings, the
+		**	factory pointer is integral to the building itself. For human controlled buildings, the factory
+		**	pointer is part of the house structure and must be retrieved from there.
+		*/
+		FactoryClass * factory = NULL;
+		if (House->IsHuman) {
+			factory = House->Fetch_Factory(Class->ToBuild);
+		} else {
+			factory = Factory;
+		}
+
+		/*
+		**	If there is a factory associated with this building, then fetch any attached
+		**	object under production and display its cameo image over the top of this building.
+		*/
+		if (factory != NULL) {
+			TechnoClass * obj = factory->Get_Object();
+			if (obj != NULL) {
+#ifdef FIXIT_CSII
+				CC_Draw_Shape(obj->Techno_Type_Class()->Get_Cameo_Data(), 0, x, y, window, SHAPE_CENTER|SHAPE_WIN_REL|SHAPE_NORMAL, NULL);
+#else
+				void const * remapper = obj->House->Remap_Table(false, obj->Techno_Type_Class()->Remap);
+				CC_Draw_Shape(obj->Techno_Type_Class()->Get_Cameo_Data(), 0, x, y, window, SHAPE_CENTER|SHAPE_WIN_REL | ((remapper != NULL) ? SHAPE_FADING : SHAPE_NORMAL), remapper);
+#endif
+			}
+		}
+	}
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Shape_Number -- Fetch the shape number for this building.                    *
+ *                                                                                             *
+ *    This routine will examine the current state of the building and return with the shape    *
+ *    number to use. The shape number is subordinate to the building graphic image data.       *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the shape number to use when rendering this building.                 *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/29/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+int BuildingClass::Shape_Number(void) const
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	int shapenum = Fetch_Stage();
+
+	/*
+	**	The shape file to use for rendering depends on whether the building
+	**	is undergoing construction or not.
+	*/
+	if (BState == BSTATE_CONSTRUCTION) {
+
+		/*
+		**	If the building is deconstructing, then the display frame progresses
+		**	from the end to the beginning. Reverse the shape number accordingly.
+		*/
+		if (Mission == MISSION_DECONSTRUCTION) {
+			shapenum = (Class->Anims[BState].Start+Class->Anims[BState].Count-1)-shapenum;
+		}
+
+	} else {
+
+		/*
+		**	If this is a camouflaged pill box and it is not owned by the player, then
+		**	it is displayed with the MEGA-camouflaged imagery.
+		*/
+		if ((!IsOwnedByPlayer) && (*this == STRUCT_CAMOPILLBOX)) {
+			shapenum += 1;
+		}
+
+		/*
+		**	The Tesla Coil has a stage value that can be overridden by
+		**	its current state.
+		*/
+		if (*this == STRUCT_TESLA) {
+			if (IsCharged) {
+				shapenum = 3;
+			} else {
+				if (IsCharging) {
+					shapenum = Fetch_Stage();
+				} else {
+					shapenum = 0;
+				}
+			}
+		}
+
+		/*
+		**	Buildings that contain a turret handle their shape determination
+		**	differently than normal buildings. They need to take into consideration
+		**	the direction the turret is facing.
+		*/
+		if (Class->IsTurretEquipped) {
+			shapenum = UnitClass::BodyShape[Dir_To_32(PrimaryFacing.Current())];
+
+			if (*this == STRUCT_SAM) {
+
+				/*
+				**	SAM sites that are free to rotate fetch their animation frame
+				**	from the building's turret facing. All other animation stages
+				**	fetch their frame from the embedded animation sequencer.
+				*/
+//				if (Status == SAM_READY || Status == SAM_FIRING || Status == SAM_LOCKING) {
+//					shapenum = Fetch_Stage();
+//				}
+				if (Health_Ratio() <= Rule.ConditionYellow) {
+					shapenum += 35;
+				}
+			} else {
+				if (IsInRecoilState) {
+					shapenum += 32;
+				}
+				if (Health_Ratio() <= Rule.ConditionYellow) {
+					shapenum += 64;
+				}
+			}
+		} else {
+
+			/*
+			**	If it is a significantly damaged weapons factory, it is shown in
+			**	the worst state possible.
+			*/
+			if (*this == STRUCT_WEAP || *this == STRUCT_FAKEWEAP) {
+				shapenum = 0;
+				if (Health_Ratio() <= Rule.ConditionYellow) {
+					shapenum = 1;
+				}
+
+			} else {
+
+				/*
+				**	Special render stage for silos. The stage is dependent on the current
+				**	Tiberium collected as it relates to Tiberium capacity.
+				*/
+				if (*this == STRUCT_STORAGE) {
+
+					int level = 0;
+					if (House->Capacity) {
+						level = (House->Tiberium * 5) / House->Capacity;
+					}
+
+					shapenum += Bound(level, 0, 4);
+					if (Health_Ratio() <= Rule.ConditionYellow) {
+						shapenum += 5;
+					}
+
+				} else {
+
+					/*
+					**	If below half strenth, then show the damage frames of the
+					**	building.
+					*/
+					if (Health_Ratio() <= Rule.ConditionYellow) {
+						int last1 = Class->Anims[BSTATE_IDLE].Start + Class->Anims[BSTATE_IDLE].Count;
+						int last2 = Class->Anims[BSTATE_ACTIVE].Start + Class->Anims[BSTATE_ACTIVE].Count;
+						int largest = max(last1, last2);
+						last2 = Class->Anims[BSTATE_AUX1].Start + Class->Anims[BSTATE_AUX1].Count;
+						largest = max(largest, last2);
+						last2 = Class->Anims[BSTATE_AUX2].Start + Class->Anims[BSTATE_AUX2].Count;
+						largest = max(largest, last2);
+						shapenum += largest;
+					}
+				}
+			}
+		}
+	}
+	return(shapenum);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Mark -- Building interface to map rendering system.                          *
+ *                                                                                             *
+ *    This routine is used to mark the map cells so that when it renders                       *
+ *    the underlying icons will also be updated as necessary.                                  *
+ *                                                                                             *
+ * INPUT:   mark  -- Type of image change (MARK_UP, _DOWN, _CHANGE)                            *
+ *             MARK_UP  -- Building is removed.                                                *
+ *             MARK_CHANGE -- Building changes shape.                                          *
+ *             MARK_DOWN -- Building is added.                                                 *
+ *                                                                                             *
+ * OUTPUT:  bool; Did the mark operation succeed? Failure could be the result of marking down  *
+ *                when the building is already marked down, or visa versa.                     *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   03/31/1994 JLB : Created.                                                                 *
+ *   04/15/1994 JLB : Converted to member function.                                            *
+ *   04/16/1994 JLB : Added health bar tracking.                                               *
+ *   12/23/1994 JLB : Calls low level check before proceeding.                                 *
+ *   01/27/1995 JLB : Special road spacer template added.                                      *
+ *=============================================================================================*/
+bool BuildingClass::Mark(MarkType mark)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	if (TechnoClass::Mark(mark)) {
+		short const * offset = Overlap_List();
+		short const * occupy = Occupy_List();
+		CELL cell = Coord_Cell(Coord);
+		SmudgeType bib;
+
+		switch (mark) {
+			case MARK_UP:
+				Map.Pick_Up(cell, this);
+				if (Class->Bib_And_Offset(bib, cell)) {
+					SmudgeClass * smudge = new SmudgeClass(bib);
+					if (smudge != NULL) {
+						smudge->Disown(cell);
+						delete smudge;
+					}
+				}
+				break;
+
+			case MARK_DOWN:
+
+				/*
+				**	Special wall logic is handled here. A building that is really a wall
+				**	gets converted into an overlay wall type when it is placed down. The
+				**	actual building object itself is destroyed.
+				*/
+				if (Class->IsWall) {
+					switch (Class->Type) {
+						case STRUCT_BRICK_WALL:
+							new OverlayClass(OVERLAY_BRICK_WALL, cell, House->Class->House);
+							break;
+
+						case STRUCT_BARBWIRE_WALL:
+							new OverlayClass(OVERLAY_BARBWIRE_WALL, cell, House->Class->House);
+							break;
+
+						case STRUCT_SANDBAG_WALL:
+							new OverlayClass(OVERLAY_SANDBAG_WALL, cell, House->Class->House);
+							break;
+
+						case STRUCT_WOOD_WALL:
+							new OverlayClass(OVERLAY_WOOD_WALL, cell, House->Class->House);
+							break;
+
+						case STRUCT_CYCLONE_WALL:
+							new OverlayClass(OVERLAY_CYCLONE_WALL, cell, House->Class->House);
+							break;
+
+						case STRUCT_FENCE:
+							new OverlayClass(OVERLAY_FENCE, cell, House->Class->House);
+							break;
+
+						default:
+							break;
+					}
+					Transmit_Message(RADIO_OVER_OUT);
+					delete this;
+
+				} else {
+					if (Can_Enter_Cell(cell) == MOVE_OK) {
+						/*
+						**	Determine if a bib is required for this building. If one is, then
+						**	create and place it.
+						*/
+						CELL newcell = cell;
+						if (Class->Bib_And_Offset(bib, newcell)) {
+							new SmudgeClass(bib, Cell_Coord(newcell), Class->IsBase ? House->Class->House : HOUSE_NONE);
+						}
+
+						Map.Place_Down(cell, this);
+					} else {
+						return(false);
+					}
+				}
+				break;
+
+			case MARK_CHANGE_REDRAW:
+				Map.Refresh_Cells(cell, Overlap_List(true));
+				break;
+
+			default:
+				Map.Refresh_Cells(cell, Overlap_List(false));
+				Map.Refresh_Cells(cell, occupy);
+				break;
+		}
+		return(true);
+	}
+	return(false);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::AI -- Handles non-graphic AI processing for buildings.                       *
+ *                                                                                             *
+ *    This function is to handle the AI logic for the building. The graphic logic (facing,     *
+ *    firing, and animation) is handled elsewhere.                                             *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/31/1994 JLB : Created.                                                                 *
+ *   12/26/1994 JLB : Handles production.                                                      *
+ *   06/11/1995 JLB : Revamped.                                                                *
+ *=============================================================================================*/
+void BuildingClass::AI(void)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	/*
+	**	Process building animation state changes. Transition to a following state
+	**	if there is one specified and the current animation sequence has expired.
+	**	This process must occur before mission AI since the mission AI relies on
+	**	the bstate change to occur immediately before the MissionClass::AI.
+	*/
+	Animation_AI();
+
+	/*
+	**	If now is a good time to act on a new mission, then do so. This process occurs
+	**	here because some outside event may have requested a mission change for the building.
+	**	Such outside requests (player input) must be initiated BEFORE the normal AI process.
+	*/
+	if (IsReadyToCommence && BState != BSTATE_CONSTRUCTION) {
+
+		/*
+		**	Clear the commencement flag ONLY if something actually occurred. By acting
+		**	this way, a building can set the IsReadyToCommence flag before it goes
+		**	to "sleep" knowing that it will wake up as soon as a new mission comes
+		**	along.
+		*/
+		if (Commence()) {
+			IsReadyToCommence = false;
+		}
+	}
+
+	/*
+	**	Proceed with normal logic processing. This is where the mission processing
+	**	occurs. This call must be located after the animation sequence makes the
+	**	transition to the next frame (see above) in order for the mission logic to
+	**	act at the exact moment of graphic transition BEFORE it has a chance to
+	**	be displayed.
+	*/
+	TechnoClass::AI();
+
+	/*
+	**	Bail if the object died in the AI routine.
+	*/
+	if (!IsActive) {
+		return;
+	}
+
+	/*
+	**	Building ammo is instantly reloaded.
+	*/
+	if (!Ammo) {
+		Ammo = Class->MaxAmmo;
+	}
+
+	/*
+	**	If now is a good time to act on a new mission, then do so. This occurs here because
+	**	some AI event may have requested a mission change (usually from another mission
+	**	state machine). This must occur here before it has a chance to render.
+	*/
+	if (IsReadyToCommence) {
+
+		/*
+		**	Clear the commencement flag ONLY if something actually occurred. By acting
+		**	this way, a building can set the IsReadyToCommence flag before it goes
+		**	to "sleep" knowing that it will wake up as soon as a new mission comes
+		**	along.
+		*/
+		if (Commence()) {
+			IsReadyToCommence = false;
+		}
+	}
+
+	/*
+	**	If a change of animation was requested, then make the change
+	**	now. The building animation system acts independently but subordinate
+	**	to the mission state machine system. By performing the animation change-up
+	**	here, the mission AI system is ensured of immediate visual affect when it
+	**	decides to change the animation state of the building.
+	*/
+	if (QueueBState != BSTATE_NONE) {
+		if (BState != QueueBState) {
+			BState = QueueBState;
+			BuildingTypeClass::AnimControlType const * ctrl = Fetch_Anim_Control();
+			if (BState == BSTATE_CONSTRUCTION || BState == BSTATE_IDLE) {
+				Set_Rate(Options.Normalize_Delay(ctrl->Rate));
+			} else {
+				Set_Rate(ctrl->Rate);
+			}
+			Set_Stage(ctrl->Start);
+		}
+		QueueBState = BSTATE_NONE;
+	}
+
+	/*
+	**	If the building's strength has changed, then update the power
+	**	accordingly.
+	*/
+	if (Strength != LastStrength) {
+		int oldpower = Power_Output();
+		LastStrength = Strength;
+		int newpower = Power_Output();
+		House->Adjust_Power(newpower - oldpower);
+	}
+
+	/*
+	**	Check to see if the destruction countdown timer is active. If so, then decrement it.
+	**	When this timer reaches zero, the building is removed from the map. All the explosions
+	**	are presumed to be in progress at this time.
+	*/
+	if (Strength == 0) {
+		if (CountDown == 0) {
+			Limbo();
+			Drop_Debris(WhomToRepay);
+			delete this;
+		}
+		return;
+	}
+
+	/*
+	**	Charging logic.
+	*/
+	Charging_AI();
+
+	/*
+	**	Handle any repair process that may be going on.
+	*/
+	Repair_AI();
+
+	/*
+	**	For computer controlled buildings, determine what should be produced and start
+	**	production accordingly.
+	*/
+	Factory_AI();
+
+	/*
+	**	Check for demolition timeout. When timeout has expired, the building explodes.
+	*/
+	if (IsGoingToBlow && CountDown == 0) {
+		int damage = Strength;
+		Take_Damage(damage, 0, WARHEAD_FIRE, As_Techno(WhomToRepay), true);
+		if (!IsActive) {
+			return;
+		}
+		Mark(MARK_CHANGE);
+	}
+
+	/*
+	**	Turret equiped buildings must handle turret rotation logic here. This entails
+	**	rotating the turret to the desired facing as well as figuring out what that
+	**	desired facing should be.
+	*/
+	Rotation_AI();
+
+	/*
+	** Gap Generators need to scan if they've just become activated, or if
+	** the power has just come on enough so they can scan.  Also, they need
+	** to un-jam if the power has just dropped off.
+	*/
+	if (*this == STRUCT_GAP) {
+		if (Arm == 0) {
+			IsJamming = false;
+			Arm = TICKS_PER_MINUTE * Rule.GapRegenInterval + Random_Pick(1, TICKS_PER_SECOND);
+		}
+
+		if (!IsJamming) {
+			if (House->Power_Fraction() >= 1) {
+				Map.Jam_From(Coord_Cell(Center_Coord()), Rule.GapShroudRadius, House);
+				IsJamming = true;
+			}
+		} else {
+			if (House->Power_Fraction() < 1) {
+				IsJamming = false;
+				Map.UnJam_From(Coord_Cell(Center_Coord()), Rule.GapShroudRadius, House);
+			}
+		}
+	}
+
+	/*
+	** Radar facilities and SAMs need to check for the proximity of a mobile
+	** radar jammer.
+	*/
+	if ((*this == STRUCT_RADAR || *this == STRUCT_SAM) && (Frame % TICKS_PER_SECOND) == 0) {
+		IsJammed = false;
+		for (int index = 0; index < Units.Count(); index++) {
+			UnitClass * obj = Units.Ptr(index);
+			if (obj != NULL &&
+					!obj->IsInLimbo &&
+					!obj->House->Is_Ally(House) &&
+					obj->Class->IsJammer &&
+					Distance(obj) <= Rule.RadarJamRadius) {
+
+				IsJammed = true;
+				break;
+			}
+		}
+	}
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Unlimbo -- Removes a building from limbo state.                              *
+ *                                                                                             *
+ *    Use this routine to transform a building that has been held in limbo                     *
+ *    state, into one that really exists on the map. Once a building as                        *
+ *    been unlimboed, then it becomes a normal object in the game world.                       *
+ *                                                                                             *
+ * INPUT:   pos   -- The position to place the building on the map.                            *
+ *                                                                                             *
+ *          dir (optional) -- not used for this class                                          *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the unlimbo successful?                                                  *
+ *                                                                                             *
+ * WARNINGS:   The unlimbo operation might not be successful if the                            *
+ *             building could not be placed at the location specified.                         *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   04/16/1994 JLB : Created.                                                                 *
+ *   06/07/1994 JLB : Matches virtual function format for base class.                          *
+ *   05/09/1995 JLB : Handles wall placement.                                                  *
+ *   06/18/1995 JLB : Checks for wall legality before placing down.                            *
+ *=============================================================================================*/
+bool BuildingClass::Unlimbo(COORDINATE coord, DirType dir)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	/*
+	**	If this is a wall type building, then it never gets unlimboed. Instead, it gets
+	**	converted to an overlay type.
+	*/
+	if (Class->IsWall) {
+		if (Can_Enter_Cell(Coord_Cell(coord), FACING_NONE) == MOVE_OK) {
+			OverlayType otype = OVERLAY_NONE;
+			switch (Class->Type) {
+				case STRUCT_SANDBAG_WALL:
+					otype	= OVERLAY_SANDBAG_WALL;
+					break;
+
+				case STRUCT_CYCLONE_WALL:
+					otype = OVERLAY_CYCLONE_WALL;
+					break;
+
+				case STRUCT_BRICK_WALL:
+					otype = OVERLAY_BRICK_WALL;
+					break;
+
+				case STRUCT_BARBWIRE_WALL:
+					otype = OVERLAY_BARBWIRE_WALL;
+					break;
+
+				case STRUCT_WOOD_WALL:
+					otype = OVERLAY_WOOD_WALL;
+					break;
+
+				case STRUCT_FENCE:
+					otype = OVERLAY_FENCE;
+					break;
+
+				default:
+					otype = OVERLAY_NONE;
+					break;
+
+			}
+			if (otype != OVERLAY_NONE) {
+				ObjectClass * o = OverlayTypeClass::As_Reference(otype).Create_One_Of(House);
+				if (o && o->Unlimbo(coord)) {
+					Map[coord].Owner = House->Class->House;
+					Transmit_Message(RADIO_OVER_OUT);
+					Map.Sight_From(Coord_Cell(coord), Class->SightRange, House);
+					delete this;
+					return(true);
+				}
+			}
+		}
+		return(false);
+	}
+
+	/*
+	**	Normal building unlimbo process.
+	*/
+	if (TechnoClass::Unlimbo(coord, dir)) {
+
+		/*
+		**	Ensure that the owning house knows about the
+		**	new object.
+		*/
+		House->BScan |= (1L << Class->Type);
+		House->ActiveBScan |= (1L << Class->Type);
+
+		/*
+		**	Recalculate the center point of the house's base.
+		*/
+		House->Recalc_Center();
+
+		/*
+		**	Update the total factory type, assuming this building has a factory.
+		*/
+		House->Active_Add(this);
+
+		/*
+		**	Possibly the sidebar will be affected by this addition.
+		*/
+		House->IsRecalcNeeded = true;
+		LastStrength = 0;
+
+		if ((!IsDiscoveredByPlayer && Map[coord].IsVisible) || Session.Type != GAME_NORMAL) {
+			Revealed(PlayerPtr);
+		}
+		if (!House->IsHuman) {
+			Revealed(House);
+		}
+
+		if (IsOwnedByPlayer) {
+			Map.PowerClass::IsToRedraw = true;
+			Map.Flag_To_Redraw(false);
+		}
+
+		if ((Class->Ownable & (HOUSEF_GOOD | HOUSEF_BAD)) != (HOUSEF_GOOD | HOUSEF_BAD)) {
+			if (Class->Ownable & HOUSEF_GOOD) {
+				ActLike = HOUSE_GREECE;
+			} else {
+				ActLike = HOUSE_USSR;
+			}
+		}
+
+		return(true);
+	}
+	return(false);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Take_Damage -- Inflicts damage points upon a building.                       *
+ *                                                                                             *
+ *    This routine will inflict damage points upon the specified building.                     *
+ *    It will handle the damage animation and building destruction. Use                        *
+ *    this routine whenever a building is attacked.                                            *
+ *                                                                                             *
+ * INPUT:   damage   -- Amount of damage to inflict.                                           *
+ *                                                                                             *
+ *          distance -- The distance from the damage center point to the object's center point.*
+ *                                                                                             *
+ *          warhead  -- The kind of damage to inflict.                                         *
+ *                                                                                             *
+ *          source   -- The source of the damage. This is used to change targeting.            *
+ *                                                                                             *
+ *          forced   -- Is the damage forced upon the object regardless of whether it          *
+ *                      is normally immune?                                                    *
+ *                                                                                             *
+ * OUTPUT:  true/false; Was the building destroyed?                                            *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/21/1991     : Created.                                                                 *
+ *   04/15/1994 JLB : Converted to member function.                                            *
+ *   04/16/1994 JLB : Added warhead modifier to damage.                                        *
+ *   06/03/1994 JLB : Added source of damage as target value.                                  *
+ *   06/20/1994 JLB : Source is a base class pointer.                                          *
+ *   11/22/1994 JLB : Shares base damage handler for techno objects.                           *
+ *   07/15/1995 JLB : Power ratio gets adjusted.                                               *
+ *=============================================================================================*/
+ResultType BuildingClass::Take_Damage(int & damage, int distance, WarheadType warhead, TechnoClass * source, int forced)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	ResultType res = RESULT_NONE;
+	int shakes;
+
+	if (this != source /*&& !Class->IsInsignificant*/) {
+
+		if (source) {
+			House->LATime = Frame;
+			House->LAType = source->What_Am_I();
+			House->LAZone = House->Which_Zone(this);
+			House->LAEnemy = source->Owner();
+
+			if (!House->Is_Ally(source)) {
+				House->Enemy = source->Owner();
+			}
+
+			Base_Is_Attacked(source);
+		}
+
+		short const * offset = Occupy_List();
+
+		/*
+		** Memorize who they used to be in radio contact with.
+		*/
+		TechnoClass *tech = Contact_With_Whom();
+		/*
+		**	Perform the low level damage assessment.
+		*/
+		res = TechnoClass::Take_Damage(damage, distance, warhead, source, forced);
+		switch (res) {
+			case RESULT_DESTROYED:
+
+				/*
+				**	Add the building to the base prebuild list if allowed. This will force
+				**	the computer to rebuild this structure if it can.
+				*/
+				if (IsToRebuild && Class->Level != -1 && Base.House == House->Class->House && Base.Get_Node(this) == 0) {
+//				if (IsToRebuild && Class->IsBuildable && Base.House == House->Class->House && Base.Get_Node(this) == 0) {
+					Base.Nodes.Add(BaseNodeClass(Class->Type, Coord_Cell(Coord)));
+				}
+
+				/*
+				**	Destroy all attached objects.
+				*/
+				while (Attached_Object()) {
+					FootClass * obj = Detach_Object();
+
+					Detach_All(true);
+					delete obj;
+				}
+
+				/*
+				** If we were in contact with a landed plane, blow the plane up too.
+				*/
+				if (tech && tech->IsActive && tech->What_Am_I() == RTTI_AIRCRAFT && ((AircraftClass *)tech)->Class->IsFixedWing && ((AircraftClass *)tech)->In_Which_Layer() == LAYER_GROUND) {
+					int damage = 500;
+					tech->Take_Damage(damage, 0, WARHEAD_AP, source, forced);
+				}
+
+				Sound_Effect(VOC_KABOOM22, Coord);
+				while (*offset != REFRESH_EOL) {
+					CELL cell = Coord_Cell(Coord) + *offset++;
+
+					/*
+					**	If the building is destroyed, then lots of
+					**	explosions occur.
+					*/
+					new SmudgeClass(Random_Pick(SMUDGE_CRATER1, SMUDGE_CRATER6), Cell_Coord(cell));
+					if (Percent_Chance(50)) {
+						new AnimClass(ANIM_FIRE_SMALL, Coord_Scatter(Cell_Coord(cell), 0x0080), Random_Pick(0, 7), Random_Pick(1, 3));
+						if (Percent_Chance(50)) {
+							new AnimClass(ANIM_FIRE_MED, Coord_Scatter(Cell_Coord(cell), 0x0040), Random_Pick(0, 7), Random_Pick(1, 3));
+						}
+					}
+					new AnimClass(ANIM_FBALL1, Coord_Scatter(Cell_Coord(cell), 0x0040), Random_Pick(0, 3));
+				}
+
+				shakes = Class->Cost_Of() / 400;
+				if (shakes) {
+					Shake_The_Screen(shakes);
+				}
+				Sound_Effect(VOC_CRUMBLE, Coord);
+				if (Mission == MISSION_DECONSTRUCTION) {
+					CountDown = 0;
+					Set_Rate(0);
+				} else {
+					CountDown = 8;
+				}
+
+				/*
+				**	If it is in radio contact and the object seems to be attached, then tell
+				**	it to run away.
+				*/
+				if (In_Radio_Contact() && Transmit_Message(RADIO_NEED_TO_MOVE) == RADIO_ROGER) {
+					Transmit_Message(RADIO_RUN_AWAY);
+				}
+
+				/*
+				**	A force destruction will not generate survivors.
+				*/
+				if (forced || *this == STRUCT_KENNEL) {
+					IsSurvivorless = true;
+				}
+
+				/*
+				** Destruction of a radar facility or advanced communications
+				** center will cause the spiedby field to change...
+				*/
+				if (SpiedBy) {
+					SpiedBy = 0;
+					StructType struc = *this;
+					if (struc == STRUCT_RADAR /* || struc == STRUCT_EYE */) {
+						Update_Radar_Spied();
+					}
+				}
+
+				/*
+				** Destruction of a gap generator will cause the cells it affects
+				** to stop being jammed.
+				*/
+				if (*this == STRUCT_GAP) {
+					Remove_Gap_Effect();
+				}
+
+				/*
+				** Destruction of a shipyard or sub pen may cause attached ships
+				** who are repairing themselves to discontinue repairs.
+				*/
+				if (*this == STRUCT_SHIP_YARD || *this == STRUCT_SUB_PEN) {
+					for (int index = 0; index < Vessels.Count(); index++) {
+						VesselClass *obj = Vessels.Ptr(index);
+						if (obj && !obj->IsInLimbo && obj->House == House) {
+							if (obj->IsSelfRepairing) {
+								if (::Distance(Center_Coord(), obj->Center_Coord()) < 0x0200) {
+									obj->IsSelfRepairing = false;
+									obj->IsToSelfRepair = false;
+								}
+							}
+						}
+					}
+				}
+
+				/*
+				** Destruction of a barrel will cause the surrounding squares to
+				** be hit with damage.
+				*/
+				if (*this == STRUCT_BARREL || *this == STRUCT_BARREL3) {
+					COORDINATE center = Center_Coord();
+					CELL cellcenter = Coord_Cell(center);
+
+					BulletClass * bullet;
+
+					bullet = new BulletClass(BULLET_INVISIBLE, ::As_Target(Adjacent_Cell(cellcenter, FACING_N)), 0, 200, WARHEAD_FIRE, MPH_MEDIUM_FAST);
+					if (bullet) {
+						bullet->Unlimbo(center, DIR_N);
+					}
+
+					bullet = new BulletClass(BULLET_INVISIBLE, ::As_Target(Adjacent_Cell(cellcenter, FACING_E)), 0, 200, WARHEAD_FIRE, MPH_MEDIUM_FAST);
+					if (bullet) {
+						bullet->Unlimbo(center, DIR_E);
+					}
+
+					bullet = new BulletClass(BULLET_INVISIBLE, ::As_Target(Adjacent_Cell(cellcenter, FACING_S)), 0, 200, WARHEAD_FIRE, MPH_MEDIUM_FAST);
+					if (bullet) {
+						bullet->Unlimbo(center, DIR_S);
+					}
+
+					bullet = new BulletClass(BULLET_INVISIBLE, ::As_Target(Adjacent_Cell(cellcenter, FACING_W)), 0, 200, WARHEAD_FIRE, MPH_MEDIUM_FAST);
+					if (bullet) {
+						bullet->Unlimbo(center, DIR_W);
+					}
+				}
+				break;
+
+			case RESULT_HALF:
+				if (*this == STRUCT_PUMP) {
+					AnimClass * anim = new AnimClass(ANIM_OILFIELD_BURN, Coord_Add(Coord, 0x00400130L), 1);
+					if (anim) {
+						anim->Attach_To(this);
+					}
+				}
+				// Fall into next case.
+
+			case RESULT_MAJOR:
+				Sound_Effect(VOC_KABOOM1, Coord);
+				while (*offset != REFRESH_EOL) {
+					CELL cell = Coord_Cell(Coord) + *offset++;
+					AnimClass * anim = NULL;
+
+					/*
+					**	Show pieces of fire to indicate that a significant change in
+					**	damage level has occurred.
+					*/
+					if (warhead == WARHEAD_FIRE) {
+						switch (Random_Pick(0, 5+Class->Width()+Class->Height())) {
+							case 0:
+								break;
+
+							case 1:
+							case 2:
+							case 3:
+							case 4:
+							case 5:
+								anim = new AnimClass(ANIM_ON_FIRE_SMALL, Coord_Scatter(Cell_Coord(cell), 0x0060), 0, Random_Pick(1, 3));
+								break;
+
+							case 6:
+							case 7:
+							case 8:
+								anim = new AnimClass(ANIM_ON_FIRE_MED, Coord_Scatter(Cell_Coord(cell), 0x0060), 0, Random_Pick(1, 3));
+								break;
+
+							case 9:
+								anim = new AnimClass(ANIM_ON_FIRE_BIG, Coord_Scatter(Cell_Coord(cell), 0x0060), 0, 1);
+								break;
+
+							default:
+								break;
+						}
+					} else {
+						if (Percent_Chance(50)) {
+							/*
+							** Building may catch on fire, but only if it wasn't a
+							** renovator that caused the damage.
+							*/
+							if (source == NULL || source->What_Am_I() != RTTI_INFANTRY || *(InfantryClass *)source != INFANTRY_RENOVATOR) {
+								anim = new AnimClass(ANIM_FIRE_SMALL, Coord_Scatter(Cell_Coord(cell), 0x0060), Random_Pick(0, 7), Random_Pick(1, 3));
+							}
+						}
+					}
+					/*
+					**	If the animation was created, then attach it to the building.
+					*/
+					if (anim) {
+						anim->Attach_To(this);
+					}
+				}
+				break;
+
+			case RESULT_NONE:
+				break;
+
+			case RESULT_LIGHT:
+				break;
+		}
+
+		if (source && res != RESULT_NONE) {
+
+			/*
+			**	If any damage occurred, then inform the house of this fact. If it is the player's
+			**	house, it might announce this fact.
+			*/
+			if (!Class->IsInsignificant) {
+				House->Attacked();
+			}
+
+			/*
+			** Save the type of the house that's doing the damage, so if the building burns
+			** to death credit can still be given for the kill
+			*/
+			WhoLastHurtMe = source->Owner();
+
+			/*
+			**	When certain buildings are hit, they "snap out of it" and
+			**	return fire if they are able and allowed.
+			*/
+			if (*this != STRUCT_SAM && *this != STRUCT_AAGUN &&
+				!House->Is_Ally(source) &&
+				Class->PrimaryWeapon != NULL &&
+				(!Target_Legal(TarCom) || !In_Range(TarCom))) {
+
+				if (source->What_Am_I() != RTTI_AIRCRAFT && (!House->IsHuman || Rule.IsSmartDefense)) {
+					Assign_Target(source->As_Target());
+				} else {
+
+					/*
+					**	Generate a random rotation effect since there is nothing else that this
+					**	building can do.
+					*/
+					if (!PrimaryFacing.Is_Rotating()) {
+						PrimaryFacing.Set_Desired(Random_Pick(DIR_N, DIR_MAX));
+					}
+				}
+			}
+		}
+	}
+
+	return(res);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::new -- Allocates a building object from building pool.                       *
+ *                                                                                             *
+ *    This routine will allocate a building slot from the building alloc                       *
+ *    system.                                                                                  *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with a pointer to the allocated building. If NULL is                       *
+ *          returned, then this indicates a failure to allocate.                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   04/11/1994 JLB : Created.                                                                 *
+ *   04/21/1994 JLB : Converted to operator new.                                               *
+ *   05/17/1994 JLB : Revamped allocation scheme                                               *
+ *   07/29/1994 JLB : Simplified.                                                              *
+ *=============================================================================================*/
+void * BuildingClass::operator new(size_t )
+{
+	void * ptr = Buildings.Allocate();
+	if (ptr) {
+		((BuildingClass *)ptr)->IsActive = true;
+	}
+	return(ptr);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::delete -- Deallocates building object.                                       *
+ *                                                                                             *
+ *    This is the memory deallocation operation for a building object.                         *
+ *    Since buildings are allocated out of a fixed memory block, all that                      *
+ *    is needed is to flag the unit as inactive.                                               *
+ *                                                                                             *
+ * INPUT:   ptr   -- Pointer to building to deallocate.                                        *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   04/21/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BuildingClass::operator delete(void *ptr)
+{
+	if (ptr) {
+		((BuildingClass *)ptr)->IsActive = false;
+	}
+	Buildings.Free((BuildingClass *)ptr);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::BuildingClass -- Constructor for buildings.                                  *
+ *                                                                                             *
+ *    This routine inserts a building into the object tracking system.                         *
+ *    It is placed into a limbo state unless a location is provided for                        *
+ *    it to unlimbo at.                                                                        *
+ *                                                                                             *
+ * INPUT:   type  -- The structure type to make this object.                                   *
+ *                                                                                             *
+ *          house -- The owner of this building.                                               *
+ *                                                                                             *
+ *          pos   -- The position to unlimbo the building. If -1 is                            *
+ *                   specified, then the building remains in a limbo                           *
+ *                   state.                                                                    *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   04/21/1994 JLB : Created.                                                                 *
+ *   08/07/1995 JLB : Fixed act like value to match expected value.                            *
+ *=============================================================================================*/
+BuildingClass::BuildingClass(StructType type, HousesType house) :
+	TechnoClass(RTTI_BUILDING, Buildings.ID(this), house),
+	Class(BuildingTypes.Ptr((int)type)),
+	Factory(0),
+	ActLike(House->ActLike),
+	IsToRebuild(false),
+	IsToRepair(false),
+	IsAllowedToSell(true),
+	IsReadyToCommence(false),
+	IsRepairing(false),
+	IsWrenchVisible(false),
+	IsGoingToBlow(false),
+	IsSurvivorless(false),
+	IsCharging(false),
+	IsCharged(false),
+	IsCaptured(false),
+	IsJamming(false),
+	IsJammed(false),
+	HasFired(false),
+	HasOpened(false),
+	CountDown(0),
+	BState(BSTATE_NONE),
+	QueueBState(BSTATE_NONE),
+	WhoLastHurtMe(house),
+	WhomToRepay(TARGET_NONE),
+	AnimToTrack(TARGET_NONE),
+	LastStrength(0),
+	PlacementDelay(0)
+{
+	House->Tracking_Add(this);
+	IsSecondShot = !Class->Is_Two_Shooter();
+	Strength = Class->MaxStrength;
+	Ammo = Class->MaxAmmo;
+
+	/*
+	**	If the building could never be built, then it can never be sold either. This
+	**	is due to the lack of buildup animation.
+	*/
+	if (Class->Get_Buildup_Data() != NULL) {
+//	if (!Class->IsBuildable) {
+		IsAllowedToSell = false;
+	}
+
+//	if (Session.Type == GAME_INTERNET) {
+//		House->BuildingTotals->Increment_Unit_Total( (int) type);
+//	}
+
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::~BuildingClass -- Destructor for building type objects.                      *
+ *                                                                                             *
+ *    This destructor for building objects will put the building in limbo if possible.         *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   01/18/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+BuildingClass::~BuildingClass(void)
+{
+	if (GameActive && Class) {
+		if (House) {
+			House->Tracking_Remove(this);
+		}
+		BuildingClass::Limbo();
+	}
+	Class = 0;
+
+	delete (FactoryClass *)Factory;
+	Factory = 0;
+	ID = -1;
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Drop_Debris -- Drops rubble when building is destroyed.                      *
+ *                                                                                             *
+ *    This routine is called when a building is destroyed. It handles                          *
+ *    placing the rubble down.                                                                 *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/14/1994 JLB : Created.                                                                 *
+ *   06/13/1995 JLB : Added smoke and normal infantry survivor possibility.                    *
+ *   07/16/1995 JLB : Survival rate depends on if captured or sabotaged.                       *
+ *=============================================================================================*/
+void BuildingClass::Drop_Debris(TARGET source)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	CELL const * offset;
+	CELL cell;
+
+	/*
+	**	Generate random survivors from the destroyed building.
+	*/
+	cell = Coord_Cell(Coord);
+	offset = Occupy_List();
+	int odds = 2;
+	if (Target_Legal(WhomToRepay)) odds -= 1;
+	if (IsCaptured) odds += 6;
+	int count = How_Many_Survivors();
+	while (*offset != REFRESH_EOL) {
+		CELL	newcell;
+
+		newcell = cell + *offset++;
+		CellClass const * cellptr = &Map[newcell];
+
+		/*
+		**	Infantry could run out of a destroyed building.
+		*/
+		if (!House->IsToDie && count > 0) {
+			InfantryClass * i = NULL;
+
+			if (Random_Pick(0, odds) == 1) {
+				i = NULL;
+				InfantryType typ = Crew_Type();
+				if (typ != INFANTRY_NONE) i = new InfantryClass(typ, House->Class->House);
+				if (i != NULL) {
+					if (Class->Get_Buildup_Data() != NULL && i->Class->IsNominal) i->IsTechnician = true;
+					ScenarioInit++;
+					if (i->Unlimbo(Cell_Coord(newcell), DIR_N)) {
+						count--;
+						i->Strength = Random_Pick(5, (int)i->Class->MaxStrength);
+						i->Scatter(0, true);
+						if (source != TARGET_NONE && !House->Is_Ally(As_Object(source))) {
+							i->Assign_Mission(MISSION_ATTACK);
+							i->Assign_Target(source);
+						} else {
+							if (House->IsHuman) {
+								i->Assign_Mission(MISSION_GUARD);
+							} else {
+								i->Assign_Mission(MISSION_HUNT);
+							}
+						}
+					} else {
+						delete i;
+					}
+					ScenarioInit--;
+				}
+			}
+		}
+
+		/*
+		**	Smoke and fire only appear on terrestrail cells. They should not appear on
+		**	rivers, clifs, or water cells.
+		*/
+		if (cellptr->Is_Clear_To_Move(SPEED_TRACK, true, true)) {
+
+			/*
+			**	Possibly add some smoke rising from the ashes of the building.
+			*/
+			switch (Random_Pick(0, 5)) {
+				case 0:
+				case 1:
+				case 2:
+					new AnimClass(ANIM_SMOKE_M, Coord_Scatter(Cell_Coord(newcell), 0x0050, false), Random_Pick(0, 5), Random_Pick(1, 2));
+					break;
+
+				default:
+					break;
+			}
+
+			/*
+			**	The building always scars the ground in some fashion.
+			*/
+			if (Percent_Chance(25)) {
+				new SmudgeClass(Random_Pick(SMUDGE_SCORCH1, SMUDGE_SCORCH6), Cell_Coord(newcell));
+			} else {
+				new SmudgeClass(Random_Pick(SMUDGE_CRATER1, SMUDGE_CRATER6), Coord_Scatter(Cell_Coord(newcell), 0x0080, false));
+			}
+		}
+	}
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Active_Click_With -- Handles clicking on the map while the building is selected.*
+ *                                                                                             *
+ *    This interface routine handles when the player clicks on the map while this building     *
+ *    is currently selected. This is used to assign an override target to a turret or          *
+ *    guard tower.                                                                             *
+ *                                                                                             *
+ * INPUT:   target   -- The target that was clicked upon.                                      *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/28/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BuildingClass::Active_Click_With(ActionType action, ObjectClass * object)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	if (action == ACTION_ATTACK && object != NULL) {
+		Player_Assign_Mission(MISSION_ATTACK, object->As_Target());
+	}
+
+	if (action == ACTION_SELF && Class->Is_Factory()) {
+		OutList.Add(EventClass(EventClass::PRIMARY, TargetClass(this)));
+	}
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Active_Click_With -- Handles cell selection for buildings.                   *
+ *                                                                                             *
+ *    This routine really only serves one purpose -- to allow targeting of the ground for      *
+ *    buildings that are equipped with weapons.                                                *
+ *                                                                                             *
+ * INPUT:   action   -- The requested action to perform.                                       *
+ *                                                                                             *
+ *          cell     -- The cell location to perform the action upon.                          *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/04/1995 JLB : Created.                                                                 *
+ *   10/04/1995 JLB : Handles construction yard undeploy to move logic.                        *
+ *=============================================================================================*/
+void BuildingClass::Active_Click_With(ActionType action, CELL cell)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	if (action == ACTION_ATTACK) {
+		Player_Assign_Mission(MISSION_ATTACK, ::As_Target(cell));
+	}
+
+	if (action == ACTION_MOVE && *this == STRUCT_CONST) {
+		OutList.Add(EventClass(EventClass::ARCHIVE, TargetClass(this), TargetClass(cell)));
+		OutList.Add(EventClass(EventClass::SELL, TargetClass(this)));
+	}
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Assign_Target -- Assigns a target to the building.                           *
+ *                                                                                             *
+ *    Assigning of a target to a building makes sense if the building is one that can attack.  *
+ *    This routine would be used to assign the attack target to a turret or guard tower.       *
+ *                                                                                             *
+ * INPUT:   target   -- The target that was clicked on while this building was selected.       *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/28/1994 JLB : Created.                                                                 *
+ *   11/02/1994 JLB : Checks for range before assigning target.                                *
+ *=============================================================================================*/
+void BuildingClass::Assign_Target(TARGET target)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	if (*this != STRUCT_SAM && *this != STRUCT_AAGUN && !In_Range(target, 0)) {
+		target = TARGET_NONE;
+	}
+
+	TechnoClass::Assign_Target(target);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Init -- Initialize the building system to an empty null state.               *
+ *                                                                                             *
+ *    This routine initializes the building system in preparation for a scenario load.         *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   09/19/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BuildingClass::Init(void)
+{
+	Buildings.Free_All();
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Exit_Object -- Initiates an object to leave the building.                    *
+ *                                                                                             *
+ *    This function is used to cause an object to exit the building. It is called when a       *
+ *    factory produces a vehicle or other mobile object and that object needs to exit the      *
+ *    building to join the ranks of a regular unit. Typically, the object is placed down on    *
+ *    the map such that it overlaps the building and then it is given a movement order so that *
+ *    it will move to an adjacent free cell.                                                   *
+ *                                                                                             *
+ * INPUT:   base  -- Pointer to the object that is to exit the building.                       *
+ *                                                                                             *
+ * OUTPUT:  Returns the success rating for the exit attempt;                                   *
+ *             0  = complete failure (refund money please)                                     *
+ *             1  = temporarily prevented (try again later please)                             *
+ *             2  = successful                                                                 *
+ *                                                                                             *
+ * WARNINGS:   The building is placed in radio contact with the object. The object is in a     *
+ *             tethered condition. This condition will be automatically broken when the        *
+ *             object reaches the adjacent square.                                             *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   11/28/1994 JLB : Created.                                                                 *
+ *   04/10/1995 JLB : Handles building production by computer.                                 *
+ *   06/17/1995 JLB : Handles refinery exit.                                                   *
+ *=============================================================================================*/
+int BuildingClass::Exit_Object(TechnoClass * base)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	if (!base) return(0);
+
+	TechnoTypeClass const * ttype = (TechnoTypeClass const *)&base->Class_Of();
+
+	/*
+	**	A unit exiting a building is always considered to be "locked". That means, it
+	**	will be considered as to have legally entered the visible map domain.
+	*/
+	base->IsLocked = true;
+
+	/*
+	**	Find a good cell to unload the object to. The object, probably a vehicle
+	**	will drive/walk to the adjacent free cell.
+	*/
+	CELL cell = 0;
+
+	switch (base->What_Am_I()) {
+
+		case RTTI_AIRCRAFT:
+			if (!In_Radio_Contact()) {
+				AircraftClass * air = (AircraftClass *)base;
+
+				air->Height = 0;
+				ScenarioInit++;
+				if (air->Unlimbo(Docking_Coord(), air->Pose_Dir())) {
+					Transmit_Message(RADIO_HELLO, air);
+					Transmit_Message(RADIO_TETHER);
+					ScenarioInit--;
+					return(2);
+				}
+				ScenarioInit--;
+			} else {
+				AircraftClass * air = (AircraftClass *)base;
+
+				if (Cell_X(Coord_Cell(Center_Coord())) - Map.MapCellX < Map.MapCellWidth/2) {
+					cell = XY_Cell(Map.MapCellX-1, Random_Pick(0, Map.MapCellHeight-1)+Map.MapCellY);
+				} else {
+					cell = XY_Cell(Map.MapCellX+Map.MapCellWidth, Random_Pick(0, Map.MapCellHeight-1)+Map.MapCellY);
+				}
+				ScenarioInit++;
+				if (air->Unlimbo(Cell_Coord(cell), DIR_N)) {
+//BG				air->Assign_Destination(::As_Target(Nearby_Location(air)));
+/*BG*/			air->Assign_Destination(::As_Target(air->Nearby_Location(this)));
+					air->Assign_Mission(MISSION_MOVE);
+					ScenarioInit--;
+					return(2);
+				}
+				ScenarioInit--;
+			}
+			break;
+
+		case RTTI_VESSEL:
+			switch (Class->Type) {
+				case STRUCT_SUB_PEN:
+				case STRUCT_SHIP_YARD:
+					ScenarioInit++;
+					cell = Find_Exit_Cell(base);
+					if (cell != 0 && base->Unlimbo(Cell_Coord(cell), Direction(Cell_Coord(cell)))) {
+						base->Assign_Mission(MISSION_GUARD);
+						ScenarioInit--;
+						return(2);
+					}
+					ScenarioInit--;
+					break;
+
+				default:
+					break;
+			}
+			break;
+
+		case RTTI_INFANTRY:
+		case RTTI_UNIT:
+			switch (Class->Type) {
+				case STRUCT_REFINERY:
+					if (base->What_Am_I() == RTTI_UNIT) {
+						cell = Coord_Cell(Center_Coord());
+						UnitClass * unit = (UnitClass *)base;
+
+						cell = Adjacent_Cell(cell, FACING_SW);
+						ScenarioInit++;
+						if (unit->Unlimbo(Cell_Coord(Adjacent_Cell(cell, DIR_S)), DIR_SW_X2)) {
+							unit->PrimaryFacing = DIR_S;
+							unit->Assign_Mission(MISSION_HARVEST);
+						}
+						ScenarioInit--;
+					} else {
+						base->Scatter(0, true);
+					}
+					break;
+
+				case STRUCT_WEAP:
+					if (Mission == MISSION_UNLOAD) {
+						for(int index = 0; index < Buildings.Count(); index++) {
+							BuildingClass *bldg = Buildings.Ptr(index);
+							if (bldg->Owner() == Owner() && *bldg == STRUCT_WEAP && bldg != this && bldg->Mission == MISSION_GUARD && !bldg->Factory) {
+								FactoryClass * temp = Factory;
+								bldg->Factory = Factory;
+								Factory = 0;
+								int retval = (bldg->Exit_Object(base));
+								bldg->Factory = 0;
+								Factory = temp;
+								return(retval);
+							}
+						}
+						return(1);	// fail while we're still unloading previous
+					}
+					ScenarioInit++;
+					if (base->Unlimbo(Exit_Coord(), DIR_S)) {
+						base->Mark(MARK_UP);
+						base->Coord = Exit_Coord();
+						base->Mark(MARK_DOWN);
+						Transmit_Message(RADIO_HELLO, base);
+						Transmit_Message(RADIO_TETHER);
+						Assign_Mission(MISSION_UNLOAD);
+						ScenarioInit--;
+						return(2);
+					}
+					ScenarioInit--;
+					break;
+
+				case STRUCT_BARRACKS:
+				case STRUCT_TENT:
+				case STRUCT_KENNEL:
+
+					cell = Find_Exit_Cell(base);
+					if (cell != 0) {
+						DirType	dir = Direction(cell);
+						COORDINATE		start = Exit_Coord();
+
+						ScenarioInit++;
+						if (base->Unlimbo(start, dir)) {
+
+							base->Assign_Mission(MISSION_MOVE);
+
+							/*
+							**	When disembarking from a transport then guard an area around the
+							**	center of the base.
+							*/
+							base->Assign_Destination(::As_Target(cell));
+							if (House->IQ >= Rule.IQGuardArea) {
+								base->Assign_Mission(MISSION_GUARD_AREA);
+								base->ArchiveTarget = ::As_Target(House->Where_To_Go((FootClass *)base));
+							}
+
+							/*
+							**	Establish radio contact so unload coordination can occur. This
+							**	radio contact should always succeed.
+							*/
+							if (Transmit_Message(RADIO_HELLO, base) == RADIO_ROGER) {
+								Transmit_Message(RADIO_UNLOAD);
+							}
+							ScenarioInit--;
+							return(2);
+						}
+						ScenarioInit--;
+					}
+					break;
+
+				default:
+					cell = Find_Exit_Cell(base);
+					if (cell != 0) {
+						DirType	dir = Direction(cell);
+						COORDINATE		start = Exit_Coord();
+
+						ScenarioInit++;
+						if (base->Unlimbo(start, dir)) {
+
+							base->Assign_Mission(MISSION_MOVE);
+
+							/*
+							**	When disembarking from a transport then guard an area around the
+							**	center of the base.
+							*/
+							base->Assign_Destination(::As_Target(cell));
+							if (House->IQ >= Rule.IQGuardArea) {
+								base->Assign_Mission(MISSION_GUARD_AREA);
+								base->ArchiveTarget = ::As_Target(House->Where_To_Go((FootClass *)base));
+							}
+							ScenarioInit--;
+							return(2);
+						}
+						ScenarioInit--;
+					}
+					break;
+			}
+			break;
+
+		case RTTI_BUILDING:
+
+			if (!House->IsHuman) {
+
+				/*
+				**	Find the next available spot to place this newly created building. If the
+				**	building could be placed at the desired location, fine. If not, then this
+				**	routine will return failure. The calling routine will probably abandon this
+				**	building in preference to building another.
+				*/
+				BaseNodeClass * node = Base.Next_Buildable(((BuildingClass *)base)->Class->Type);
+				COORDINATE coord = 0;
+				if (node) {
+					coord = Cell_Coord(node->Cell);
+				} else {
+
+					/*
+					**	Find a suitable new spot to place.
+					*/
+					coord = House->Find_Build_Location((BuildingClass *)base);
+				}
+
+				if (coord) {
+					if (Flush_For_Placement(base, Coord_Cell(coord))) {
+						return(1);
+					}
+					if (base->Unlimbo(coord)) {
+						if (node && ((BuildingClass *)base)->Class->Type == House->BuildStructure) {
+							House->BuildStructure = STRUCT_NONE;
+						}
+						return(2);
+					}
+				}
+			}
+			break;
+
+		default:
+			break;
+	}
+
+	/*
+	**	Failure to exit the object results in a false return value.
+	*/
+	return(0);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Update_Buildables -- Informs sidebar of additional construction options.     *
+ *                                                                                             *
+ *    This routine will tell the sidebar of objects that can be built. The function is called  *
+ *    whenever a building matures.                                                             *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   11/11/1994 JLB : Created.                                                                 *
+ *   12/23/1994 JLB : Only updates for PLAYER buildings.                                       *
+ *=============================================================================================*/
+void BuildingClass::Update_Buildables(void)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	if (House == PlayerPtr && !IsInLimbo && IsDiscoveredByPlayer) {
+		switch (Class->ToBuild) {
+			StructType i;
+			UnitType u;
+			InfantryType f;
+			AircraftType a;
+			VesselType v;
+
+			case RTTI_VESSELTYPE:
+				for (v = VESSEL_FIRST; v < VESSEL_COUNT; v++) {
+					if (PlayerPtr->Can_Build(&VesselTypeClass::As_Reference(v), ActLike)) {
+						Map.Add(RTTI_VESSELTYPE, v);
+					}
+				}
+				break;
+
+			case RTTI_BUILDINGTYPE:
+				for (i = STRUCT_FIRST; i < STRUCT_COUNT; i++) {
+					if (PlayerPtr->Can_Build(&BuildingTypeClass::As_Reference(i), ActLike)) {
+						Map.Add(RTTI_BUILDINGTYPE, i);
+					}
+				}
+				break;
+
+			case RTTI_UNITTYPE:
+				for (u = UNIT_FIRST; u < UNIT_COUNT; u++) {
+					if (PlayerPtr->Can_Build(&UnitTypeClass::As_Reference(u), ActLike)) {
+						Map.Add(RTTI_UNITTYPE, u);
+					}
+				}
+				break;
+
+			case RTTI_INFANTRYTYPE:
+				for (f = INFANTRY_FIRST; f < INFANTRY_COUNT; f++) {
+					if (PlayerPtr->Can_Build(&InfantryTypeClass::As_Reference(f), ActLike)) {
+						if (InfantryTypeClass::As_Reference(f).IsDog) {
+							if (*this == STRUCT_KENNEL) {
+								Map.Add(RTTI_INFANTRYTYPE, f);
+							}
+						} else {
+							if (*this != STRUCT_KENNEL) {
+								Map.Add(RTTI_INFANTRYTYPE, f);
+							}
+						}
+					}
+				}
+				break;
+
+			case RTTI_AIRCRAFTTYPE:
+				for (a = AIRCRAFT_FIRST; a < AIRCRAFT_COUNT; a++) {
+					if (PlayerPtr->Can_Build(&AircraftTypeClass::As_Reference(a), ActLike)) {
+						Map.Add(RTTI_AIRCRAFTTYPE, a);
+					}
+				}
+				break;
+
+			default:
+				break;
+		}
+	}
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Fire_Out -- Handles when attached animation expires.                         *
+ *                                                                                             *
+ *    This routine is used to perform any fixups necessary when the attached animation has     *
+ *    terminated. This occurs when the fire & smoke animation that a SAM site produces stops.  *
+ *    At that point, normal reload procedures can commence.                                    *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   11/30/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BuildingClass::Fire_Out(void)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Limbo -- Handles power adjustment as building goes into limbo.               *
+ *                                                                                             *
+ *    This routine will handle the power adjustments for the associated house when the         *
+ *    building goes into limbo. This means that its power drain or production is subtracted    *
+ *    from the house accumulated totals.                                                       *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the building limboed?                                                    *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   12/24/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool BuildingClass::Limbo(void)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	if (!IsInLimbo) {
+
+		/*
+		**	Update the total factory type, assuming this building has a factory.
+		*/
+		House->Active_Remove(this);
+		House->IsRecalcNeeded = true;
+		House->Recalc_Center();
+
+		/*
+		**	Update the power status of the owner's house.
+		*/
+		House->Adjust_Power(-Power_Output());
+		House->Adjust_Drain(-Class->Drain);
+		House->Adjust_Capacity(-Class->Capacity, true);
+		if (House == PlayerPtr) {
+			Map.PowerClass::IsToRedraw = true;
+			Map.Flag_To_Redraw(false);
+		}
+
+		/*
+		**	This could be a building that builds. If so, then the sidebar may need adjustment.
+		** Set IsInLimbo to true to "fool" the sidebar into knowing that this building
+		** isn't available.  Set it back to false so the rest of the Limbo code works.
+		** Otherwise, the sidebar won't properly remove non-available buildables.
+		*/
+//		if (IsOwnedByPlayer && !ScenarioInit) {
+//			IsInLimbo = true;
+//			Map.Recalc();
+//			IsInLimbo = false;
+//		}
+	}
+	return(TechnoClass::Limbo());
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Turret_Facing -- Fetches the turret facing for this building.                *
+ *                                                                                             *
+ *    This will return the turret facing for this building. Some buildings don't have a        *
+ *    visual turret (e.g., pillbox) so they return a turret facing that always faces their     *
+ *    current target.                                                                          *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the current facing of the turret.                                     *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/29/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+DirType BuildingClass::Turret_Facing(void) const
+{
+	if (!Class->IsTurretEquipped && Target_Legal(TarCom)) {
+		return(::Direction(Center_Coord(), As_Coord(TarCom)));
+	}
+	return(PrimaryFacing.Current());
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Greatest_Threat -- Searches for target that building can fire upon.          *
+ *                                                                                             *
+ *    This routine intercepts the Greatest_Threat function so that it can add the ability      *
+ *    to search for ground targets, if this isn't a SAM site.                                  *
+ *                                                                                             *
+ * INPUT:   threat   -- The base threat control value. Typically, it might be THREAT_RANGE     *
+ *                      or THREAT_NORMAL.                                                      *
+ *                                                                                             *
+ * OUTPUT:  Returns with a suitable target. If none could be found, then TARGET_NONE is        *
+ *          returned instead.                                                                  *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   01/01/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+TARGET BuildingClass::Greatest_Threat(ThreatType threat) const
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	if (Class->PrimaryWeapon != NULL) {
+		threat = threat | Class->PrimaryWeapon->Allowed_Threats();
+	}
+	if (Class->SecondaryWeapon != NULL) {
+		threat = threat | Class->SecondaryWeapon->Allowed_Threats();
+	}
+	if (House->IsHuman) {
+		threat = threat & ~THREAT_BUILDINGS;
+	}
+	threat = threat | THREAT_RANGE;
+
+//	if (Class->PrimaryWeapon != NULL) {
+//		if (Class->PrimaryWeapon->Bullet->IsAntiAircraft) {
+//			threat = threat | THREAT_AIR;
+//		}
+//		if (Class->PrimaryWeapon->Bullet->IsAntiGround) {
+//			threat = threat | THREAT_BUILDINGS|THREAT_INFANTRY|THREAT_BOATS|THREAT_VEHICLES;
+//		}
+//		threat = threat | THREAT_RANGE;
+//	}
+	return(TechnoClass::Greatest_Threat(threat));
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Grand_Opening -- Handles construction completed special operations.          *
+ *                                                                                             *
+ *    This routine is called when construction has finished. Typically, this enables           *
+ *    new production options for factories.                                                    *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   01/08/1995 JLB : Created.                                                                 *
+ *   06/13/1995 JLB : Added helipad.                                                           *
+ *=============================================================================================*/
+void BuildingClass::Grand_Opening(bool captured)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	if (!HasOpened || captured) {
+		HasOpened = true;
+
+		/*
+		**	Adjust the owning house according to the power, drain, and Tiberium capacity that
+		**	this building has.
+		*/
+		House->Adjust_Drain(Class->Drain);
+		House->Adjust_Capacity(Class->Capacity);
+		House->IsRecalcNeeded = true;
+
+		/*	SPECIAL CASE:
+		**	Tiberium Refineries get a free harvester. Add a harvester to the
+		**	reinforcement list at this time.
+		*/
+		if (*this == STRUCT_REFINERY && !ScenarioInit && !captured && !Debug_Map && (!House->IsHuman || PurchasePrice == 0 || PurchasePrice > Class->Raw_Cost())) {
+			CELL cell = Coord_Cell(Adjacent_Cell(Center_Coord(), DIR_S));
+
+			UnitClass * unit = new UnitClass(UNIT_HARVESTER, House->Class->House);
+			if (unit != NULL) {
+
+				/*
+				**	Try to place down the harvesters. If it could not be placed, then try
+				**	to place it in a nearby location.
+				*/
+				if (!unit->Unlimbo(Cell_Coord(cell), DIR_W)) {
+					cell = unit->Nearby_Location(this);
+
+					/*
+					**	If the harvester could still not be placed, then refund the money
+					**	to the owner and then bail.
+					*/
+					if (!unit->Unlimbo(Cell_Coord(cell), DIR_SW)) {
+						House->Refund_Money(unit->Class->Cost_Of());
+						delete unit;
+					}
+				}
+			} else {
+
+				/*
+				**	If the harvester could not be created in the first place, then give
+				**	the full refund price to the owning player.
+				*/
+				House->Refund_Money(UnitTypeClass::As_Reference(UNIT_HARVESTER).Cost_Of());
+			}
+		}
+
+		/*
+		**	Helicopter pads get a free attack helicopter.
+		*/
+		if (!Rule.IsSeparate && *this == STRUCT_HELIPAD && !captured) {
+			ScenarioInit++;
+			AircraftClass * air = 0;
+			if (House->ActLike == HOUSE_USSR || House->ActLike == HOUSE_BAD || House->ActLike == HOUSE_UKRAINE) {
+				air = new AircraftClass(AIRCRAFT_HIND, House->Class->House);
+			} else {
+				air = new AircraftClass(AIRCRAFT_LONGBOW, House->Class->House);
+			}
+			if (air) {
+				air->Height = 0;
+				if (air->Unlimbo(Docking_Coord(), air->Pose_Dir())) {
+					air->Assign_Mission(MISSION_GUARD);
+					air->Transmit_Message(RADIO_HELLO, this);
+					Transmit_Message(RADIO_TETHER);
+				}
+			}
+			ScenarioInit--;
+		}
+	}
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Repair -- Initiates or terminates the repair process.                        *
+ *                                                                                             *
+ *    This routine will start, stop, or toggle the repair process. When a building repairs, it *
+ *    occurs incrementally over time.                                                          *
+ *                                                                                             *
+ * INPUT:   control  -- Determines how to control the repair process.                          *
+ *                      0: Turns repair process off (if it was on).                            *
+ *                      1: Turns repair process on (if it was off).                            *
+ *                      -1:Toggles repair process to other state.                              *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   01/08/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BuildingClass::Repair(int control)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	switch (control) {
+		case -1:
+			IsRepairing = (IsRepairing == false);
+			break;
+
+		case 1:
+			if (IsRepairing) return;
+			IsRepairing = true;
+			break;
+
+		case 0:
+			if (!IsRepairing) return;
+			IsRepairing = false;
+			break;
+
+		default:
+			break;
+	}
+
+	/*
+	**	At this point, we know that the repair state has changed. Perform
+	**	appropriate action.
+	*/
+	VocType soundid = VOC_NONE;
+	if (IsRepairing) {
+		if (Strength == Class->MaxStrength) {
+			soundid = VOC_SCOLD;
+		} else {
+			soundid = VOC_CLICK;
+			if (House->IsPlayerControl) {
+				Clicked_As_Target();
+			}
+			IsWrenchVisible = true;
+		}
+	} else {
+		soundid = VOC_CLICK;
+	}
+	if (House->IsPlayerControl) {
+		Sound_Effect(soundid, Coord);
+	}
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Sell_Back -- Controls the sell back (demolish) operation.                    *
+ *                                                                                             *
+ *    This routine will initiate or stop the sell back process for a building. It is called    *
+ *    when the player clicks on a building when the sell mode is active.                       *
+ *                                                                                             *
+ * INPUT:   control  -- The action to perform. 0 = turn deconstruction off, 1 = deconstruct,   *
+ *                      -1 = toggle deconstruction state.                                      *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/25/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BuildingClass::Sell_Back(int control)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	if (Class->Get_Buildup_Data()) {
+		bool decon = false;
+		switch (control) {
+			case -1:
+				decon = (Mission != MISSION_DECONSTRUCTION);
+				break;
+
+			case 1:
+				if (Mission == MISSION_DECONSTRUCTION) return;
+				if (IsGoingToBlow) return;
+				decon = true;
+				break;
+
+			case 0:
+				if (Mission != MISSION_DECONSTRUCTION) return;
+				decon = false;
+				break;
+
+			default:
+				break;
+		}
+
+		/*
+		**	At this point, we know that the repair state has changed. Perform
+		**	appropriate action.
+		*/
+		if (decon) {
+			Assign_Mission(MISSION_DECONSTRUCTION);
+			Commence();
+			if (House->IsPlayerControl) {
+				Clicked_As_Target();
+			}
+		}
+		if (House->IsPlayerControl) {
+			Sound_Effect(VOC_CLICK);
+		}
+	}
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::What_Action -- Determines action to perform if click on specified object.    *
+ *                                                                                             *
+ *    This routine will determine what action to perform if the mouse was clicked on the       *
+ *    object specified. This determination is used to control the mouse imagery and the        *
+ *    function process when the mouse button is pressed.                                       *
+ *                                                                                             *
+ * INPUT:   object   -- Pointer to the object that, if clicked on, will control what action    *
+ *                      is to be performed.                                                    *
+ *                                                                                             *
+ * OUTPUT:  Returns with the ActionType that will occur if the mouse is clicked over the       *
+ *          object specified while the building is currently selected.                         *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   01/18/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+ActionType BuildingClass::What_Action(ObjectClass const * object) const
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	ActionType action = TechnoClass::What_Action(object);
+
+	if (action == ACTION_SELF) {
+		int index;
+		if (Class->Is_Factory() && PlayerPtr == House && *House->Factory_Counter(Class->ToBuild) > 1) {
+			switch (Class->ToBuild) {
+				case RTTI_INFANTRYTYPE:
+				case RTTI_INFANTRY:
+					action = ACTION_NONE;
+					if (*this == STRUCT_KENNEL) {
+						for (index = 0; index < Buildings.Count(); index++) {
+							BuildingClass *bldg = Buildings.Ptr(index);
+							if (bldg != this && bldg->Owner() == Owner() && *bldg == STRUCT_KENNEL) {
+								action = ACTION_SELF;
+								break;
+							}
+						}
+					} else {
+						for (index = 0; index < Buildings.Count(); index++) {
+							BuildingClass *bldg = Buildings.Ptr(index);
+							if (bldg != this && bldg->Owner() == Owner() && bldg->Class->ToBuild == RTTI_INFANTRYTYPE && *bldg != STRUCT_KENNEL) {
+								action = ACTION_SELF;
+								break;
+							}
+						}
+					}
+					break;
+
+				case RTTI_NONE:
+					action = ACTION_NONE;
+					break;
+
+				default:
+					break;
+			}
+
+		} else {
+			action = ACTION_NONE;
+		}
+	}
+
+	/*
+	**	Don't allow targeting of SAM sites, even if the CTRL key
+	**	is held down. Also don't allow targeting if the object is too
+	**	far away.
+	*/
+	if (action == ACTION_ATTACK && (*this == STRUCT_SAM || *this == STRUCT_AAGUN || !In_Range(object, 0))) {
+		action = ACTION_NONE;
+	}
+
+	if (action == ACTION_MOVE) {
+		action = ACTION_NONE;
+	}
+
+	return(action);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::What_Action -- Determines what action will occur.                            *
+ *                                                                                             *
+ *    This routine examines the cell specified and returns with the action that will be        *
+ *    performed if that cell were clicked upon while the building is selected.                 *
+ *                                                                                             *
+ * INPUT:   cell  -- The cell to examine.                                                      *
+ *                                                                                             *
+ * OUTPUT:  Returns the ActionType that indicates what should occur if the mouse is clicked    *
+ *          on this cell.                                                                      *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   01/18/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+ActionType BuildingClass::What_Action(CELL cell) const
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	ActionType action = TechnoClass::What_Action(cell);
+
+	if (action == ACTION_MOVE && (*this != STRUCT_CONST || !Rule.IsMCVDeploy)) {
+		action = ACTION_NONE;
+	}
+
+	/*
+	**	Don't allow targeting of SAM sites, even if the CTRL key
+	**	is held down.
+	*/
+	if (action == ACTION_ATTACK && Class->PrimaryWeapon != NULL && !Class->PrimaryWeapon->Bullet->IsAntiGround) {
+//	if (action == ACTION_ATTACK && (*this == STRUCT_SAM || *this == STRUCT_AAGUN)) {
+		action = ACTION_NONE;
+	}
+
+	return(action);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Begin_Mode -- Begins an animation mode for the building.                     *
+ *                                                                                             *
+ *    This routine will start the building animating. This animation will loop indefinitely    *
+ *    until explicitly stopped.                                                                *
+ *                                                                                             *
+ * INPUT:   bstate   -- The animation state to initiate.                                       *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   The building graphic state will reflect the first stage of this animation the   *
+ *             very next time it is rendered.                                                  *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/25/1995 JLB : Created.                                                                 *
+ *   07/02/1995 JLB : Uses normalize animation rate where applicable.                          *
+ *=============================================================================================*/
+void BuildingClass::Begin_Mode(BStateType bstate)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	QueueBState = bstate;
+	if (BState == BSTATE_NONE || bstate == BSTATE_CONSTRUCTION || ScenarioInit) {
+		BState = bstate;
+		QueueBState = BSTATE_NONE;
+		BuildingTypeClass::AnimControlType const * ctrl = Fetch_Anim_Control();
+
+		int rate = ctrl->Rate;
+		if (Class->IsRegulated && bstate != BSTATE_CONSTRUCTION) {
+			rate = Options.Normalize_Delay(rate);
+		}
+		Set_Rate(rate);
+		Set_Stage(ctrl->Start);
+	}
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Center_Coord -- Fetches the center coordinate for the building.              *
+ *                                                                                             *
+ *    This routine is used to set the center coordinate for this building.                     *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the coordinate for the center location for the building.              *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   03/10/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+COORDINATE BuildingClass::Center_Coord(void) const
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	return(Coord_Add(Coord, CenterOffset[Class->Size]));
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Docking_Coord -- Fetches the coordinate to use for docking.                  *
+ *                                                                                             *
+ *    This routine will return the coordinate to use when an object wishes to dock with this   *
+ *    building. Normally the docking coordinate would be the center of the building.           *
+ *    Exceptions to this would be the airfield and helipad. Their docking coordinates are      *
+ *    offset to match the building artwork.                                                    *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the coordinate to head to when trying to dock with this building.     *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   09/21/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+COORDINATE BuildingClass::Docking_Coord(void) const
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	if (*this == STRUCT_HELIPAD) {
+		return(Coord_Add(Coord, XYP_COORD(24, 18)));
+	}
+	if (*this == STRUCT_AIRSTRIP) {
+		return(Coord_Add(Coord, XYP_COORD(ICON_PIXEL_W + ICON_PIXEL_W/2, 28)));
+	}
+	return(TechnoClass::Docking_Coord());
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Can_Fire -- Determines if this building can fire.                            *
+ *                                                                                             *
+ *    Use this routine to see if the building can fire its weapon.                             *
+ *                                                                                             *
+ *                                                                                             *
+ * INPUT:   target   -- The target that firing upon is desired.                                *
+ *                                                                                             *
+ *          which    -- Which weapon to use when firing. 0=primary, 1=secondary.               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the fire possibility code. If firing is allowed, then FIRE_OK is      *
+ *          returned. Other cases will result in appropriate fire code value that indicates    *
+ *          why firing is not allowed.                                                         *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/03/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+FireErrorType BuildingClass::Can_Fire(TARGET target, int which) const
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	FireErrorType canfire = TechnoClass::Can_Fire(target, which);
+
+	if (canfire == FIRE_OK) {
+
+		/*
+		**	Double check to make sure that the facing is roughly toward
+		**	the target. If the difference is too great, then firing is
+		**	temporarily postponed.
+		*/
+		if (Class->IsTurretEquipped) {
+			int diff = PrimaryFacing.Difference(Direction(TarCom));
+			diff = abs(diff);
+			if (ABS(diff) > (*this == STRUCT_SAM ? 64 : 8)) {
+//			if (ABS(diff) > 8) {
+				return(FIRE_FACING);
+			}
+
+			/*
+			**	If the turret is rotating then firing must be delayed.
+			*/
+//			if (PrimaryFacing.Is_Rotating()) {
+//				return(FIRE_ROTATING);
+//			}
+		}
+
+		/*
+		**	Certain buildings cannot fire if there is insufficient power.
+		*/
+		if (Class->IsPowered && House->Power_Fraction() < 1) {
+			return(FIRE_BUSY);
+		}
+
+		/*
+		** If an obelisk can fire, check the state of charge.
+		*/
+		if (Class->PrimaryWeapon != NULL && Class->PrimaryWeapon->IsElectric && !IsCharged) {
+			return(FIRE_BUSY);
+		}
+	}
+	return(canfire);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Toggle_Primary -- Toggles the primary factory state.                         *
+ *                                                                                             *
+ *    This routine will change the primary factory state of this building. The primary         *
+ *    factory is the one that units will be produced from (by default).                        *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Is this building NOW the primary factory?                                          *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/03/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool BuildingClass::Toggle_Primary(void)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	if (IsLeader) {
+		IsLeader = false;
+	} else {
+		for (int index = 0; index < Buildings.Count(); index++) {
+			BuildingClass * building = Buildings.Ptr(index);
+
+			if (!building->IsInLimbo && building->Owner() == Owner() && building->Class->ToBuild == Class->ToBuild) {
+				if (Class->ToBuild == RTTI_INFANTRYTYPE) {
+					if (*building == STRUCT_KENNEL && *this == STRUCT_KENNEL) {
+						building->IsLeader = false;
+					} else {
+						if (*building != STRUCT_KENNEL && *this != STRUCT_KENNEL) {
+							building->IsLeader = false;
+						}
+					}
+				} else {
+					building->IsLeader = false;
+				}
+			}
+		}
+		IsLeader = true;
+		if ((HouseClass *)House == PlayerPtr) {
+			Speak(VOX_PRIMARY_SELECTED);
+		}
+	}
+	Mark(MARK_CHANGE);
+	return(IsLeader);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Captured -- Captures the building.                                           *
+ *                                                                                             *
+ *    This routine will change the owner of the building. It handles updating any related      *
+ *    game systems as a result. Factories are the most prone to have great game related        *
+ *    consequences when captured. This could also affect the sidebar and building ownership.   *
+ *                                                                                             *
+ * INPUT:   newowner -- Pointer to the house that is now the new owner.                        *
+ *                                                                                             *
+ * OUTPUT:  Was the capture attempt successful?                                                *
+ *                                                                                             *
+ * WARNINGS:   Capturing could fail if the house is already owned by the one specified or      *
+ *             the building isn't allowed to be captured.                                      *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/03/1995 JLB : Created.                                                                 *
+ *   07/05/1995 JLB : Fixed production problem with capturing enemy buildings.                 *
+ *=============================================================================================*/
+bool BuildingClass::Captured(HouseClass * newowner)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	if (Class->IsCaptureable && newowner != House) {
+#ifdef TOFIX
+		switch (Owner()) {
+			case HOUSE_GOOD:
+				Speak(VOX_GDI_CAPTURED);
+				break;
+
+			case HOUSE_BAD:
+				Speak(VOX_NOD_CAPTURED);
+				break;
+		}
+#endif
+
+		/*
+		** Make sure the capturer isn't spying on his own building, and if
+		** it was a radar facility, update the target house's RadarSpied field.
+		*/
+		if (SpiedBy & (1<<(newowner->Class->House)) ) {
+			SpiedBy -= (1<<(newowner->Class->House));
+			if (*this == STRUCT_RADAR) {
+				Update_Radar_Spied();
+			}
+		}
+
+		if (House == PlayerPtr) {
+			Map.PowerClass::IsToRedraw = true;
+			Map.Flag_To_Redraw(false);
+		}
+
+		if (*this == STRUCT_GAP) {
+			Remove_Gap_Effect();
+			IsJamming = false;
+			Arm = 0;
+		}
+
+		/*
+		** Add this building to the list of buildings captured this game. For internet stats purposes.
+		*/
+		if (Session.Type == GAME_INTERNET) {
+			newowner->CapturedBuildings->Increment_Unit_Total (Class->Type);
+		}
+
+		House->Adjust_Power(-Power_Output());
+		LastStrength = 0;
+		House->Adjust_Drain(-Class->Drain);
+		int booty = House->Adjust_Capacity(-Class->Capacity, true);
+
+		/*
+		**	If there is something loaded, then it gets captured as well.
+		*/
+		TechnoClass * tech = Attached_Object();
+		if (tech) tech->Captured(newowner);
+
+		/*
+		**	If something isn't technically attached, but is sitting on this
+		**	building for another reason (e.g., helicopter on helipad), then it
+		**	gets captured as well.
+		*/
+		tech = Contact_With_Whom();
+		if (tech) {
+			if (Transmit_Message(RADIO_NEED_TO_MOVE) == RADIO_ROGER && (::Distance(tech->Center_Coord(), Docking_Coord()) < 0x0040 ||
+				(tech->What_Am_I() == RTTI_AIRCRAFT && ((AircraftClass *)tech)->Class->IsFixedWing && ((AircraftClass *)tech)->In_Which_Layer() == LAYER_GROUND)) ) {
+				tech->Captured(newowner);
+			} else {
+				Transmit_Message(RADIO_RUN_AWAY);
+				Transmit_Message(RADIO_OVER_OUT);
+			}
+		}
+
+		/*
+		**	Abort any computer production in progress.
+		*/
+		if (Factory) {
+			delete (FactoryClass *)Factory;
+			Factory = 0;
+		}
+
+		/*
+		**	Decrement the factory counter for the original owner.
+		*/
+		House->Active_Remove(this);
+
+		/*
+		**	Flag that both owners now need to update their buildable lists.
+		*/
+		House->IsRecalcNeeded = true;
+		newowner->IsRecalcNeeded = true;
+		HouseClass * oldowner = House;
+		TARGET tocap = As_Target();
+
+		IsCaptured = true;
+		TechnoClass::Captured(newowner);
+
+		oldowner->ToCapture = tocap;
+		oldowner->Recalc_Center();
+		House->Recalc_Center();
+		if (House->ToCapture == As_Target()) {
+			House->ToCapture = TARGET_NONE;
+		}
+
+		SmudgeType bib;
+		CELL cell = Coord_Cell(Coord);
+		if (Class->Bib_And_Offset(bib, cell)) {
+			SmudgeClass * smudge = new SmudgeClass(bib);
+			if (smudge) {
+				smudge->Disown(cell);
+				delete smudge;
+			}
+#ifdef FIXIT_CAPTURE_BIB
+			if (Session.Type == GAME_NORMAL) {
+				new SmudgeClass(bib, Cell_Coord(cell), Class->IsBase ? House->Class->House : HOUSE_NONE);
+			} else {
+				new SmudgeClass(bib, Cell_Coord(cell), House->Class->House);
+			}
+#else
+			new SmudgeClass(bib, Cell_Coord(cell), House->Class->House);
+#endif
+		}
+
+		House->Harvested(booty);
+		House->Stole(Refund_Amount());
+
+		/*
+		**	Increment the factory count for the new owner.
+		*/
+		House->Active_Add(this);
+
+		IsRepairing = false;
+		Grand_Opening(true);
+
+		Mark(MARK_CHANGE);
+
+		/*
+		**	Perform a look operation when captured if it was the player
+		**	that performed the capture.
+		*/
+		if (House == PlayerPtr) {
+			Look(false);
+		}
+		/*
+		** If it was spied upon by the player who just captured it, clear the
+		** spiedby flag for that house.
+		*/
+		if (SpiedBy & (1 << (newowner->Class->House))) {
+			SpiedBy &= ~(1 << (newowner->Class->House));
+		}
+
+		/*
+		** Update the new building's colors on the radar map.
+		*/
+		short const * offset = Occupy_List();
+		while (*offset != REFRESH_EOL) {
+			CELL cell = Coord_Cell(Coord) + *offset++;
+			Map.Radar_Pixel(cell);
+		}
+		return(true);
+	}
+	return(false);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Sort_Y -- Returns the building coordinate used for sorting.                  *
+ *                                                                                             *
+ *    The coordinate value returned from this function should be used for sorting purposes.    *
+ *    It has special offset adjustment applied so that vehicles don't overlap (as much).       *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with a coordinate value suitable to be used for sorting.                   *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/23/1995 JLB : Created.                                                                 *
+ *   06/19/1995 JLB : Handles buildings that come with bibs built-in.                          *
+ *=============================================================================================*/
+COORDINATE BuildingClass::Sort_Y(void) const
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	if (*this == STRUCT_REPAIR) {
+		return(Coord);
+	}
+	if (*this == STRUCT_BARRACKS /*|| *this == STRUCT_POWER*/) {
+		return(Center_Coord());
+	}
+	if (*this == STRUCT_REFINERY) {
+		return(Center_Coord());
+	}
+
+	/*
+	**	Mines need to bias their sort location such that they are typically drawn
+	**	before any objects that might overlap them.
+	*/
+	if (*this == STRUCT_AVMINE || *this == STRUCT_APMINE) {
+		return(Coord_Move(Center_Coord(), DIR_N, CELL_LEPTON_H));
+	}
+
+	return(Coord_Add(Center_Coord(), XY_Coord(0, (Class->Height()*256)/3)));
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Can_Enter_Cell -- Determines if building can be placed down.                 *
+ *                                                                                             *
+ *    This routine will determine if the building can be placed down at the location           *
+ *    specified.                                                                               *
+ *                                                                                             *
+ * INPUT:   cell  -- The cell to examine. This is usually the cell of the upper left corner    *
+ *                   of the building if it were to be placed down.                             *
+ *                                                                                             *
+ * OUTPUT:  Returns with the move legality value for placement at the location specified. This *
+ *          will either be MOVE_OK or MOVE_NO.                                                 *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/25/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+MoveType BuildingClass::Can_Enter_Cell(CELL cell, FacingType) const
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	if (*this == STRUCT_CONST && IsDown) {
+		return(Map[cell].Is_Clear_To_Build(Class->Speed) ? MOVE_OK : MOVE_NO);
+	}
+
+	if (!Debug_Map && ScenarioInit == 0 && Session.Type == GAME_NORMAL && House->IsPlayerControl && !Map[cell].IsMapped) {
+		return(MOVE_NO);
+	}
+
+	return(Class->Legal_Placement(cell) ? MOVE_OK : MOVE_NO);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Can_Demolish -- Can the player demolish (sell back) the building?            *
+ *                                                                                             *
+ *    Determines if the player can sell this building. Selling is possible if the building     *
+ *    is not currently in construction or deconstruction animation.                            *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Can the building be demolished at this time?                                       *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/25/1995 JLB : Created.                                                                 *
+ *   07/01/1995 JLB : If there is no buildup data, then the building can't be sold.            *
+ *   07/17/1995 JLB : Cannot sell a refinery that has a harvester attached.                    *
+ *=============================================================================================*/
+bool BuildingClass::Can_Demolish(void) const
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	if (Class->IsUnsellable) return(false);
+
+	if (Class->Get_Buildup_Data() && BState != BSTATE_CONSTRUCTION && Mission != MISSION_DECONSTRUCTION && Mission != MISSION_CONSTRUCTION) {
+		if (*this == STRUCT_REFINERY && Is_Something_Attached()) return(false);
+		return(true);
+	}
+	return(false);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Mission_Guard -- Handles guard mission for combat buildings.                 *
+ *                                                                                             *
+ *    Buildings that can attack are given this mission. They will wait until a suitable target *
+ *    comes within range and then launch into the attack mission. Buildings that have no       *
+ *    weaponry will just sit in this routine forever.                                          *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the number of game frames to delay before this routine will be called *
+ *          again.                                                                             *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/25/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+int BuildingClass::Mission_Guard(void)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	/*
+	**	If this building has a weapon, then search for a target to attack. When
+	**	a target is found, switch into attack mode to deal with the threat.
+	*/
+	if (Is_Weapon_Equipped()) {
+
+		/*
+		**	Weapon equipped buildings are ALWAYS ready to launch into another mission if
+		**	they are sitting around in guard mode.
+		*/
+		IsReadyToCommence = true;
+
+		/*
+		**	If there is no target available, then search for one.
+		*/
+		if (!Target_Legal(TarCom)) {
+			ThreatType threat = THREAT_NORMAL;
+			Assign_Target(Greatest_Threat(threat));
+		}
+
+		/*
+		**	There is a valid target. Switch into attack mode right away.
+		*/
+		if (Target_Legal(TarCom)) {
+			Assign_Mission(MISSION_ATTACK);
+			Commence();
+			return(1);
+		}
+	} else {
+
+		/*
+		**	This is the very simple state machine that basically does
+		**	nothing. This is the mode that non weapon equipped buildings
+		**	are normally in.
+		*/
+		enum {
+			INITIAL_ENTRY,
+			IDLE
+		};
+		switch (Status) {
+			case INITIAL_ENTRY:
+				Begin_Mode(BSTATE_IDLE);
+				Status = IDLE;
+				break;
+
+			case IDLE:
+				/*
+				**	Special case to break out of guard mode if this is a repair
+				**	facility and there is a customer waiting at the grease pit.
+				*/
+				if (*this == STRUCT_REPAIR &&
+					In_Radio_Contact() &&
+					Contact_With_Whom()->Is_Techno() &&
+					((TechnoClass *)Contact_With_Whom())->Mission == MISSION_ENTER &&
+					Distance(Contact_With_Whom()) < 0x0040 &&
+					Transmit_Message(RADIO_NEED_TO_MOVE) == RADIO_ROGER) {
+
+					Assign_Mission(MISSION_REPAIR);
+					return(1);
+				}
+				break;
+
+			default:
+				break;
+		}
+
+		if (*this == STRUCT_REPAIR) {
+			return(MissionControl[Mission].Normal_Delay() + Random_Pick(0, 2));
+		} else {
+			return(MissionControl[Mission].Normal_Delay() * 3 + Random_Pick(0, 2));
+		}
+	}
+	return(MissionControl[Mission].AA_Delay() + Random_Pick(0, 2));
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Mission_Construction -- Handles mission construction.                        *
+ *                                                                                             *
+ *    This routine will handle mission construction. When this mission is complete, the        *
+ *    building will begin normal operation.                                                    *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the number of game frames to delay before calling this routine        *
+ *          again.                                                                             *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/25/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+int BuildingClass::Mission_Construction(void)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	enum {
+		INITIAL,
+		DURING
+	};
+	switch (Status) {
+		case INITIAL:
+			Begin_Mode(BSTATE_CONSTRUCTION);
+			Transmit_Message(RADIO_BUILDING);
+			if (House->IsPlayerControl) {
+				Sound_Effect(VOC_CONSTRUCTION, Coord);
+			}
+			Status = DURING;
+			break;
+
+		case DURING:
+			if (IsReadyToCommence) {
+
+				/*
+				**	When construction is complete, then transmit this
+				**	to the construction yard so that it can stop its
+				**	construction animation.
+				*/
+				Transmit_Message(RADIO_COMPLETE);		// "I'm finished."
+				Transmit_Message(RADIO_OVER_OUT);		// "You're free."
+				Begin_Mode(BSTATE_IDLE);
+				Grand_Opening();
+				Assign_Mission(MISSION_GUARD);
+				PrimaryFacing = Class->StartFace;
+			}
+			break;
+
+		default:
+			break;
+	}
+	return(1);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Mission_Deconstruction -- Handles building deconstruction.                   *
+ *                                                                                             *
+ *    This state machine is only used when the building is deconstructing as a result of       *
+ *    selling.  When this mission is finished, the building will no longer exist.              *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the number of game frames to delay before calling this routine again. *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/25/1995 JLB : Created.                                                                 *
+ *   08/13/1995 JLB : Enable selling of units on a repair bay.                                 *
+ *   08/20/1995 JLB : Scatters infantry from scattered starting points.                        *
+ *=============================================================================================*/
+int BuildingClass::Mission_Deconstruction(void)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	/*
+	**	Always force repair off.
+	*/
+	Repair(0);
+
+	enum {
+		INITIAL,
+		HOLDING,
+		DURING
+	};
+	switch (Status) {
+		case INITIAL:
+
+			/*
+			**	Special check for the repair bay which has the ability to sell
+			**	whatever is on it. If there is something on the repair bay, then
+			**	it will be sold. If there is nothing on the repair bay, then
+			**	the repair bay itself will be sold.
+			*/
+			if ( (*this == STRUCT_REPAIR || *this == STRUCT_AIRSTRIP) && Transmit_Message(RADIO_NEED_TO_MOVE) == RADIO_ROGER && Distance(Contact_With_Whom()) < 0x0080) {
+				TechnoClass * tech = Contact_With_Whom();
+				Transmit_Message(RADIO_OVER_OUT);
+				if (IsOwnedByPlayer) Speak(VOX_UNIT_SOLD);
+				tech->Sell_Back(1);
+				Assign_Mission(MISSION_GUARD);
+				return(1);
+			}
+
+			/*
+			** Selling off a shipyard or sub pen may cause attached ships
+			** who are repairing themselves to discontinue repairs.
+			*/
+			if (*this == STRUCT_SHIP_YARD || *this == STRUCT_SUB_PEN) {
+				for (int index = 0; index < Vessels.Count(); index++) {
+					VesselClass * obj = Vessels.Ptr(index);
+					if (obj && !obj->IsInLimbo && obj->House == House) {
+						if (obj->IsSelfRepairing) {
+							if (::Distance(Center_Coord(), obj->Center_Coord()) < 0x0200) {
+								obj->IsSelfRepairing = false;
+								obj->IsToSelfRepair = false;
+							}
+						}
+					}
+				}
+			}
+
+			IsReadyToCommence = false;
+			Transmit_Message(RADIO_RUN_AWAY);
+			Status = HOLDING;
+			break;
+
+		case HOLDING:
+			if (!IsTethered) {
+
+				/*
+				**	The crew will evacuate from the building. The number of crew
+				**	members leaving is equal to the unrecovered cost of the building
+				**	divided by 100 (the typical cost of a minigunner infantryman).
+				*/
+				if (!Target_Legal(ArchiveTarget) || !Rule.IsMCVDeploy || *this != STRUCT_CONST) {
+					int count = How_Many_Survivors();
+					bool engine = false;
+
+					while (count) {
+
+						/*
+						**	Ensure that the player only gets ONE engineer and not from a captured
+						**	construction yard.
+						*/
+						InfantryType typ = Crew_Type();
+						while (typ == INFANTRY_RENOVATOR && engine) {
+							typ = Crew_Type();
+						}
+						if (typ == INFANTRY_RENOVATOR) engine = true;
+
+						InfantryClass * infantry = 0;
+						if (typ != INFANTRY_NONE) infantry = new InfantryClass(typ, House->Class->House);
+						if (infantry != NULL) {
+							ScenarioInit++;
+							COORDINATE coord = Coord_Add(Center_Coord(), XYP_COORD(0, -12));
+							coord = Map[coord].Closest_Free_Spot(coord, false);
+
+							if (infantry->Unlimbo(coord, DIR_N)) {
+								if (infantry->Class->IsNominal) infantry->IsTechnician = true;
+								ScenarioInit--;
+								infantry->Scatter(0, true);
+								ScenarioInit++;
+								infantry->Assign_Mission(MISSION_GUARD_AREA);
+							} else {
+								delete infantry;
+							}
+							ScenarioInit--;
+						}
+						count--;
+					}
+				}
+
+				if (House->IsPlayerControl) {
+					Sound_Effect(VOC_CASHTURN, Coord);
+				}
+				Status = DURING;
+				Begin_Mode(BSTATE_CONSTRUCTION);
+				Detach_All(true);
+				Transmit_Message(RADIO_OVER_OUT);
+				IsReadyToCommence = false;
+				break;
+			}
+			Transmit_Message(RADIO_RUN_AWAY);
+			break;
+
+		case DURING:
+			if (IsReadyToCommence) {
+				House->IsRecalcNeeded = true;
+				if (IsOwnedByPlayer) Speak(VOX_STRUCTURE_SOLD);
+
+				/*
+				**	Construction yards that deconstruct, really just revert back
+				**	to an MCV.
+				*/
+				if (Target_Legal(ArchiveTarget) && *this == STRUCT_CONST && House->IsHuman && Strength > 0) {
+					ScenarioInit++;
+					UnitClass * unit = new UnitClass(UNIT_MCV, House->Class->House);
+					ScenarioInit--;
+					if (unit != NULL) {
+
+						/*
+						**	Unlimbo the MCV onto the map. The MCV should start in the same
+						**	health condition that the construction yard was in.
+						*/
+						fixed ratio = Health_Ratio();
+						int money = Refund_Amount();
+						TARGET arch = ArchiveTarget;
+						COORDINATE place = Coord_Snap(Adjacent_Cell(Coord, DIR_SE));
+
+						delete this;
+
+						if (unit->Unlimbo(place, DIR_SW)) {
+							unit->Strength = unit->Class_Of().MaxStrength * ratio;
+
+							/*
+							**	Lift the move destination from the building and assign
+							**	it to the unit.
+							*/
+							if (Target_Legal(arch)) {
+								unit->Assign_Destination(arch);
+								unit->Assign_Mission(MISSION_MOVE);
+							}
+
+						} else {
+
+							/*
+							**	If, for some strange reason, the MCV could not be placed on the
+							**	map, then give the player some money to compensate.
+							*/
+							House->Refund_Money(money);
+						}
+					} else {
+						House->Refund_Money(Refund_Amount());
+						delete this;
+					}
+
+				} else {
+
+					/*
+					** Selling off a gap generator will cause the cells it affects
+					** to stop being jammed.
+					*/
+					if (*this == STRUCT_GAP) {
+						Remove_Gap_Effect();
+					}
+
+					/*
+					**	A sold building still counts as a kill, but it just isn't directly
+					**	attributed to the enemy.
+					*/
+					WhoLastHurtMe = HOUSE_NONE;
+					Record_The_Kill(NULL);
+
+					/*
+					**	The player gets part of the money back for the sell.
+					*/
+					House->Refund_Money(Refund_Amount());
+					House->Stole(-Refund_Amount());
+					Limbo();
+
+					/*
+					**	Finally, delete the building from the game.
+					*/
+					delete this;
+				}
+			}
+			break;
+
+		default:
+			break;
+	}
+	return(1);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Mission_Attack -- Handles attack mission for building.                       *
+ *                                                                                             *
+ *    Buildings that can attack are processed by this attack mission state machine.            *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the number of game frames to delay before calling this routine        *
+ *          again.                                                                             *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/25/1995 JLB : Created.                                                                 *
+ *   02/22/1996 JLB : SAM doesn't lower back into ground.                                      *
+ *=============================================================================================*/
+int BuildingClass::Mission_Attack(void)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	if (*this == STRUCT_SAM) {
+		switch (Status) {
+
+			/*
+			**	This is the target tracking state of the launcher. It will rotate
+			**	to face the current TarCom of the launcher.
+			*/
+			case SAM_READY:
+				if ((Class->IsPowered && House->Power_Fraction() < 1) || IsJammed) {
+					return(1);
+				}
+				if (!Target_Legal(TarCom) || !Is_Target_Aircraft(TarCom) || As_Aircraft(TarCom)->Height == 0) {
+					Assign_Target(TARGET_NONE);
+					Status = SAM_READY;
+					Assign_Mission(MISSION_GUARD);
+					Commence();
+					return(1);
+				} else {
+					if (!PrimaryFacing.Is_Rotating()) {
+						DirType facing = Direction(TarCom);
+						if (PrimaryFacing.Difference(facing)) {
+							PrimaryFacing.Set_Desired(facing);
+						} else {
+							Status = SAM_FIRING;
+						}
+					}
+				}
+				return(1);
+
+			/*
+			**	The launcher is in the process of firing.
+			*/
+			case SAM_FIRING:
+				if (!Target_Legal(TarCom) || !Is_Target_Aircraft(TarCom) || As_Aircraft(TarCom)->Height == 0) {
+					Assign_Target(TARGET_NONE);
+					Status = SAM_READY;
+				} else {
+					FireErrorType error = Can_Fire(TarCom, 0);
+					if (error == FIRE_ILLEGAL || error == FIRE_CANT || error == FIRE_RANGE) {
+						Assign_Target(TARGET_NONE);
+						Status = SAM_READY;
+					} else {
+						if (error == FIRE_FACING) {
+							Status = SAM_READY;
+						} else {
+							if (error == FIRE_OK) {
+								Fire_At(TarCom, 0);
+								Fire_At(TarCom, 1);
+								Status = SAM_READY;
+							}
+						}
+					}
+				}
+				return(1);
+
+			default:
+				break;
+		}
+		return(MissionControl[Mission].AA_Delay() + Random_Pick(0, 2));
+
+	}
+
+	if (!Target_Legal(TarCom)) {
+		Assign_Target(TARGET_NONE);
+		Assign_Mission(MISSION_GUARD);
+		Commence();
+		return(1);
+	}
+
+	int primary = What_Weapon_Should_I_Use(TarCom);
+	IsReadyToCommence = true;
+	switch (Can_Fire(TarCom, primary)) {
+		case FIRE_ILLEGAL:
+		case FIRE_CANT:
+		case FIRE_RANGE:
+		case FIRE_AMMO:
+			Assign_Target(TARGET_NONE);
+			Assign_Mission(MISSION_GUARD);
+			Commence();
+			break;
+
+		case FIRE_FACING:
+			PrimaryFacing.Set_Desired(Direction(TarCom));
+			return(2);
+
+		case FIRE_REARM:
+			PrimaryFacing.Set_Desired(Direction(TarCom));
+			return(Arm);
+
+		case FIRE_BUSY:
+			return(1);
+
+		case FIRE_CLOAKED:
+			Do_Uncloak();
+			break;
+
+		case FIRE_OK:
+			Fire_At(TarCom, primary);
+			return(1);
+
+		default:
+			break;
+	}
+	PrimaryFacing.Set_Desired(Direction(TarCom));
+	return(1);
+//	return(MissionControl[Mission].Normal_Delay() + Random_Pick(0, 2));
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Mission_Harvest -- Handles refinery unloading harvesters.                    *
+ *                                                                                             *
+ *    This state machine handles the refinery when it unloads the harvester.                   *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the number of game frames to delay before calling this routine        *
+ *          again.                                                                             *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/25/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+int BuildingClass::Mission_Harvest(void)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	enum {
+		INITIAL,					// Dock the Tiberium cannister.
+		WAIT_FOR_DOCK,			// Waiting for docking to complete.
+		MIDDLE,					// Offload "bails" of tiberium.
+		WAIT_FOR_UNDOCK		// Waiting for undocking to complete.
+	};
+	switch (Status) {
+		case INITIAL:
+			Status = WAIT_FOR_DOCK;
+			break;
+
+		case WAIT_FOR_DOCK:
+			if (IsReadyToCommence) {
+				IsReadyToCommence = false;
+				Status = MIDDLE;
+			}
+			break;
+
+		case MIDDLE:
+			if (IsReadyToCommence) {
+				IsReadyToCommence = false;
+
+				/*
+				**	Force any bib squatters to scatter.
+				*/
+				Map[Adjacent_Cell(Coord_Cell(Center_Coord()), DIR_S)].Incoming(0, true, true);
+
+				FootClass * techno = Attached_Object();
+				if (techno) {
+					int bail = techno->Offload_Tiberium_Bail();
+
+					if (bail) {
+						House->Harvested(bail);
+						if (techno->Tiberium_Load() > 0) {
+							return(1);
+						}
+					}
+				}
+				Status = WAIT_FOR_UNDOCK;
+			}
+			break;
+
+		case WAIT_FOR_UNDOCK:
+			if (IsReadyToCommence) {
+
+				/*
+				**	Detach harvester and go back into idle state.
+				*/
+				Assign_Mission(MISSION_GUARD);
+			}
+			break;
+
+		default:
+			break;
+	}
+	return(1);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Mission_Repair -- Handles the repair (active) state for building.            *
+ *                                                                                             *
+ *    This state machine is used when the building is active in some sort of repair or         *
+ *    construction mode. The construction yard will animate. The repair facility will repair   *
+ *    anything that it docked on it.                                                           *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the number of game frames to delay before calling this routine again. *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/25/1995 JLB : Created.                                                                 *
+ *   06/25/1995 JLB : Handles repair facility                                                  *
+ *   07/29/1995 JLB : Repair rate is controlled by power rating.                               *
+ *=============================================================================================*/
+int BuildingClass::Mission_Repair(void)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	if (*this == STRUCT_CONST) {
+		enum {
+			INITIAL,
+			DURING
+		};
+		switch (Status) {
+			case INITIAL:
+				Begin_Mode(BSTATE_ACTIVE);
+				Status = DURING;
+				break;
+
+			case DURING:
+				if (!In_Radio_Contact()) {
+					Assign_Mission(MISSION_GUARD);
+				}
+				break;
+
+			default:
+				break;
+		}
+		return(1);
+	}
+
+	if (*this == STRUCT_REPAIR) {
+		enum {
+			INITIAL,
+			IDLE,
+			DURING
+		};
+		switch (Status) {
+			case INITIAL:
+				{
+					if (!In_Radio_Contact()) {
+						Begin_Mode(BSTATE_IDLE);
+						Assign_Mission(MISSION_GUARD);
+						return(1);
+					}
+					IsReadyToCommence = false;
+					int distance = 0x10;
+					TechnoClass *tech = Contact_With_Whom();
+
+					/*
+					** BG: If the unit to repair is an aircraft, and the aircraft is
+					** fixed-wing, and it's landed, be much more liberal with the
+					** distance check.  Fixed-wing aircraft are very inaccurate with
+					** their landings.
+					*/
+					if (tech->What_Am_I() == RTTI_AIRCRAFT) {
+						if ( ((AircraftClass *)tech)->Class->IsFixedWing &&
+							((AircraftClass *)tech)->In_Which_Layer() == LAYER_GROUND) {
+							distance = 0x80;
+						}
+					}
+					if (Transmit_Message(RADIO_NEED_TO_MOVE) == RADIO_ROGER && Distance(Contact_With_Whom()) < distance) {
+						Status = IDLE;
+						return(TICKS_PER_SECOND/4);
+					}
+					break;
+				}
+
+			case IDLE:
+				if (!In_Radio_Contact()) {
+					Assign_Mission(MISSION_GUARD);
+					return(1);
+				}
+
+				if (Transmit_Message(RADIO_NEED_TO_MOVE) == RADIO_ROGER) {
+					TechnoClass * radio = Contact_With_Whom();
+
+					if ( ((radio->Health_Ratio() < Rule.ConditionGreen) ||
+						   (radio->What_Am_I() == RTTI_UNIT && *(UnitClass *)radio == UNIT_MINELAYER))
+							&& Transmit_Message(RADIO_REPAIR) == RADIO_ROGER) {
+
+						/*
+						**	If the object over the repair bay is marked as useless, then
+						**	sell it back to get some money.
+						*/
+						if (radio->IsUseless) {
+							if (!radio->House->IsHuman) {
+								radio->Sell_Back(1);
+							}
+							Status = INITIAL;
+							IsReadyToCommence = true;
+						} else {
+							if (IsOwnedByPlayer) Speak(VOX_REPAIRING);
+							Status = DURING;
+							Begin_Mode(BSTATE_ACTIVE);
+							IsReadyToCommence = false;
+						}
+					} else {
+//						Transmit_Message(RADIO_RUN_AWAY);
+///*BG*/					if(radio->Health_Ratio() >= Rule.ConditionGreen) {
+//								Transmit_Message(RADIO_RUN_AWAY);
+//							}
+					}
+				}
+				break;
+
+			case DURING:
+				if (!In_Radio_Contact()) {
+					Begin_Mode(BSTATE_IDLE);
+					Status = IDLE;
+					return(1);
+				}
+
+				/*
+				**	Check to see if the repair light blink has completed and the attached
+				**	unit is not doing something else. If these conditions are favorable,
+				**	the repair can proceed another step.
+				*/
+				if (IsReadyToCommence && Transmit_Message(RADIO_NEED_TO_MOVE) == RADIO_ROGER) {
+					IsReadyToCommence = false;
+
+					/*
+					**	Tell the attached unit to repair one step. It will respond with how
+					**	it fared.
+					*/
+					switch (Transmit_Message(RADIO_REPAIR)) {
+
+						/*
+						**	The repair step proceeded smoothly. Proceed normally with the
+						**	repair process.
+						*/
+						case RADIO_ROGER:
+							break;
+
+						/*
+						**	The repair operation was aborted because of some reason. Presume
+						**	that the reason is because of low cash.
+						*/
+						case RADIO_CANT:
+							if (IsOwnedByPlayer) Speak(VOX_NO_CASH);
+							Begin_Mode(BSTATE_IDLE);
+							Status = IDLE;
+							break;
+
+						/*
+						**	The repair step resulted in a completely repaired unit.
+						*/
+						case RADIO_ALL_DONE:
+							if (IsOwnedByPlayer) Speak(VOX_UNIT_REPAIRED);
+//							Transmit_Message(RADIO_RUN_AWAY);
+							Begin_Mode(BSTATE_IDLE);
+							Status = IDLE;
+							break;
+
+						/*
+						**	The repair step could not be completed because this unit is already
+						**	at full strength.
+						*/
+						case RADIO_NEGATIVE:
+						default:
+//							Transmit_Message(RADIO_RUN_AWAY);
+							Begin_Mode(BSTATE_IDLE);
+							Status = IDLE;
+							break;
+
+					}
+				}
+				return(1);
+
+			default:
+				break;
+		}
+		return(MissionControl[Mission].Normal_Delay());
+	}
+
+	if (*this == STRUCT_HELIPAD || *this == STRUCT_AIRSTRIP) {
+		enum {
+			INITIAL,
+			DURING
+		};
+		switch (Status) {
+			case INITIAL:
+				if (Transmit_Message(RADIO_NEED_TO_MOVE) == RADIO_ROGER && Transmit_Message(RADIO_PREPARED) == RADIO_NEGATIVE) {
+					Begin_Mode(BSTATE_ACTIVE);
+					Contact_With_Whom()->Assign_Mission(MISSION_SLEEP);
+					Status = DURING;
+					return(1);
+				}
+				Assign_Mission(MISSION_GUARD);
+				break;
+
+			case DURING:
+				if (IsReadyToCommence) {
+					if (!In_Radio_Contact() || Transmit_Message(RADIO_NEED_TO_MOVE) == RADIO_NEGATIVE) {
+						Assign_Mission(MISSION_GUARD);
+						return(1);
+					}
+
+					if (Transmit_Message(RADIO_PREPARED) == RADIO_ROGER) {
+						Contact_With_Whom()->Assign_Mission(MISSION_GUARD);
+						Assign_Mission(MISSION_GUARD);
+						return(1);
+					}
+
+					if (Transmit_Message(RADIO_RELOAD) != RADIO_ROGER) {
+						Assign_Mission(MISSION_GUARD);
+						Contact_With_Whom()->Assign_Mission(MISSION_GUARD);
+						return(1);
+					} else {
+						fixed pfrac = Saturate(House->Power_Fraction(), 1);
+						if (pfrac < fixed::_1_2) pfrac = fixed::_1_2;
+						int time = Inverse(pfrac) * Rule.ReloadRate * TICKS_PER_MINUTE;
+//						int time = Bound((int)(TICKS_PER_SECOND * Saturate(House->Power_Fraction(), 1)), 0, TICKS_PER_SECOND);
+//						time = (TICKS_PER_SECOND*3) - time;
+						IsReadyToCommence = false;
+						return(time);
+					}
+				}
+				break;
+
+			default:
+				break;
+		}
+		return(3);
+	}
+	return(TICKS_PER_SECOND);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Mission_Missile -- State machine for nuclear missile launch.                 *
+ *                                                                                             *
+ *    This handles the Temple of Nod launching its nuclear missile.                            *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the number of frames to delay before calling this routine again.      *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/04/1995 JLB : Commented.                                                               *
+ *=============================================================================================*/
+int BuildingClass::Mission_Missile(void)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	if (*this == STRUCT_ADVANCED_TECH) {
+		enum {
+			DOOR_OPENING,
+			LAUNCH_UP,
+			SATELLITE_DEPLOY,
+			DONE_LAUNCH
+		};
+
+		switch (Status) {
+
+			/*
+			** The initial case is responsible for starting the door
+			** opening on the building, the missile rising, and smoke broiling.
+			*/
+			case DOOR_OPENING:
+				{
+#ifdef FIXIT_VERSION_3
+					COORDINATE door = Coord_Move(Center_Coord(), (DirType)0xC0, 0x30);
+					AnimClass * sput = new AnimClass(ANIM_SPUTDOOR, door);
+					if (sput) {
+						IsReadyToCommence = false;
+						Status = LAUNCH_UP;
+						AnimToTrack = sput->As_Target();
+					}
+#else
+					IsReadyToCommence = false;
+					COORDINATE door = Coord_Move(Center_Coord(), (DirType)0xC0, 0x30);
+					AnimClass * sput = new AnimClass(ANIM_SPUTDOOR, door);
+					Status = LAUNCH_UP;
+					AnimToTrack = sput->As_Target();
+					return(1);
+#endif
+				}
+
+			/*
+			** Once the smoke has been going for a little while this
+			** actually handles launching the missile into the air.
+			*/
+			case LAUNCH_UP:
+				{
+					AnimClass * sput = As_Animation(AnimToTrack);
+					if (sput) {
+						if (sput->Fetch_Stage() >= 19) {
+							CELL center = Coord_Cell(Center_Coord());
+							CELL cell = XY_Cell( Cell_X(center), 1);
+							TARGET targ = ::As_Target(cell);
+
+							BulletClass * bullet = new BulletClass(BULLET_GPS_SATELLITE, targ, this, 200, WARHEAD_FIRE, MPH_ROCKET);
+							if (bullet) {
+								COORDINATE launch = Coord_Move(Center_Coord(), (DirType)0xC0, 0x30);
+								if (!bullet->Unlimbo(launch, DIR_N)) {
+									delete bullet;
+									bullet = NULL;
+								}
+							}
+
+							if (bullet) {
+								Assign_Mission(MISSION_GUARD);
+							}
+						}
+					}
+				}
+				return(1);
+		}
+	}
+
+	if (*this == STRUCT_MSLO) {
+		enum {
+			INITIAL,
+			DOOR_OPENING,
+			LAUNCH_UP,
+			LAUNCH_DOWN,
+			DONE_LAUNCH
+		};
+
+		switch (Status) {
+
+			/*
+			** The initial case is responsible for starting the door
+			** opening on the building.
+			*/
+			case INITIAL:
+				IsReadyToCommence = false;
+				Begin_Mode(BSTATE_ACTIVE);	// open the door
+				Status = DOOR_OPENING;
+				return(1);
+
+			/*
+			** This polls for the case when the door is actually open and
+			** then kicks off the missile smoke.
+			*/
+			case DOOR_OPENING:
+				if (IsReadyToCommence) {
+					Begin_Mode(BSTATE_AUX1);	// hold the door open
+					Status = LAUNCH_UP;
+					return(14);
+				}
+				return(1);
+
+			/*
+			** Once the smoke has been going for a little while this
+			** actually handles launching the missile into the air.
+			*/
+			case LAUNCH_UP:
+				{
+					CELL center = Coord_Cell(Center_Coord());
+					CELL cell = XY_Cell( Cell_X(center), 1);
+					TARGET targ = ::As_Target(cell);
+					BulletClass * bullet = new BulletClass(BULLET_NUKE_UP, targ, this, 200, WARHEAD_HE, MPH_VERY_FAST);
+					if (bullet) {
+						COORDINATE launch = Coord_Move(Center_Coord(), (DirType)28, 0xA0);
+						if (!bullet->Unlimbo(launch, DIR_N)) {
+							delete bullet;
+							bullet = NULL;
+						}
+					}
+
+					if (bullet) {
+						Speak(VOX_ABOMB_LAUNCH);
+						Status = LAUNCH_DOWN;
+						/*
+						** Hack: If it's the artificial nukes, don't let the bullets come down (as
+						** they're the only ones that blow up).  We know it's artificial if you're
+						** at tech level 10 or below, because you can't build the nuclear silo until
+						** tech level 15 or so.
+						*/
+						if (House->Control.TechLevel <= 10) {
+							return(6);
+						}
+						bullet = new BulletClass(BULLET_NUKE_DOWN, ::As_Target(House->NukeDest), this, 200, WARHEAD_NUKE, MPH_VERY_FAST);
+						if (bullet) {
+							int celly = Cell_Y(House->NukeDest);
+							celly -= 64;
+							if (celly < 1) celly = 1;
+							COORDINATE start = Cell_Coord(XY_Cell(Cell_X(House->NukeDest), celly));
+							if (!bullet->Unlimbo(start, DIR_S)) {
+								delete bullet;
+							}
+						}
+						return(8 * TICKS_PER_SECOND);
+					}
+				}
+				return(1);
+
+			/*
+			** Once the missile is in the air, this handles waiting for
+			** the missile to be off the screen and then launching one down
+			** over the target.
+			*/
+			case LAUNCH_DOWN:
+				{
+					Begin_Mode(BSTATE_AUX2);	// start the door closing
+
+#ifdef OBSOLETE
+					/*
+					** Hack: If it's the artificial nukes, don't let the bullets come down (as
+					** they're the only ones that blow up).  We know it's artificial if you're
+					** at tech level 10 or below, because you can't build the nuclear silo until
+					** tech level 15 or so.
+					*/
+					if (House->Control.TechLevel <= 10) {
+						Status = DONE_LAUNCH;
+						return(6);
+					}
+					BulletClass * bullet = new BulletClass(BULLET_NUKE_DOWN, ::As_Target(House->NukeDest), this, 200, WARHEAD_NUKE, MPH_VERY_FAST);
+					if (bullet) {
+						int celly = Cell_Y(House->NukeDest);
+						celly -= 15;
+						if (celly < 1) celly = 1;
+						COORDINATE start = Cell_Coord(XY_Cell(Cell_X(House->NukeDest), celly));
+						if (!bullet->Unlimbo(start, DIR_S)) {
+							delete bullet;
+						}
+					}
+					if (bullet) {
+#endif
+						Status = DONE_LAUNCH;
+						return(6);
+					}
+#ifdef OBSOLETE
+				}
+				return(1);
+#endif
+
+			/*
+			** Once the missile is done launching this handles allowing
+			** the building to sit there with its door closed.
+			*/
+			case DONE_LAUNCH:
+				Begin_Mode(BSTATE_IDLE);	// keep the door closed.
+				Assign_Mission(MISSION_GUARD);
+				return(60);
+		}
+	}
+	return(MissionControl[Mission].Normal_Delay());
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Revealed -- Reveals the building to the specified house.                     *
+ *                                                                                             *
+ *    This routine will reveal the building to the specified house. It will handle updating    *
+ *    the sidebar for player owned buildings. A player owned building that hasn't been         *
+ *    revealed, is in a state of pseudo-limbo. It cannot be used for any of its special        *
+ *    abilities even though it exists on the map for all other purposes.                       *
+ *                                                                                             *
+ * INPUT:   house -- The house that this building is being revealed to.                        *
+ *                                                                                             *
+ * OUTPUT:  Was this building revealed by this procedure?                                      *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/25/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool BuildingClass::Revealed(HouseClass * house)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	if (TechnoClass::Revealed(house)) {
+
+		if (!ScenarioInit) {
+			House->JustBuiltStructure = Class->Type;
+			House->IsBuiltSomething = true;
+		}
+		House->IsRecalcNeeded = true;
+
+		/*
+		**	Perform any grand opening here so that in the scenarios where a player
+		**	owned house is not yet revealed, it won't be reflected in the sidebar
+		**	selection icons.
+		*/
+		if (!In_Radio_Contact() && House->IsHuman && Mission != MISSION_CONSTRUCTION) {
+			Grand_Opening();
+		} else {
+			if (!In_Radio_Contact() && !House->IsHuman && house == House && Mission != MISSION_CONSTRUCTION) {
+				Grand_Opening();
+			}
+		}
+
+		return(true);
+	}
+	return(false);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Enter_Idle_Mode -- The building will enter its idle mode.                    *
+ *                                                                                             *
+ *    This routine is called when the exact mode of the building isn't known. By examining     *
+ *    the building's condition, this routine will assign an appropriate mission.               *
+ *                                                                                             *
+ * INPUT:   initial  -- This this being called during scenario init?                           *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/25/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BuildingClass::Enter_Idle_Mode(bool initial)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	/*
+	**	Assign an appropriate mission for the building. If the ScenarioInit flag is true, then
+	**	this must be an initial building. Start such buildings in idle state. For other buildings
+	**	it indicates that it is being placed during game play and thus it must start in
+	**	the "construction" mission.
+	*/
+	MissionType mission = MISSION_GUARD;
+
+
+	if (!initial || ScenarioInit || Debug_Map) {
+		Begin_Mode(BSTATE_IDLE);
+		mission = MISSION_GUARD;
+	} else {
+		Begin_Mode(BSTATE_CONSTRUCTION);
+		mission = MISSION_CONSTRUCTION;
+	}
+	Assign_Mission(mission);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Pip_Count -- Determines "full" pips to display for building.                 *
+ *                                                                                             *
+ *    This routine will determine the number of pips that should be filled in when rendering   *
+ *    the building.                                                                            *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns the number of pips to display as filled in.                                *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/28/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+int BuildingClass::Pip_Count(void) const
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	return(Class->Max_Pips() * House->Tiberium_Fraction());
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Death_Announcement -- Announce the death of this building.                   *
+ *                                                                                             *
+ *    This routine is called when the building is destroyed by "unnatural" means. Typically    *
+ *    as a result of combat. If the building is known to the player, then it should be         *
+ *    announced.                                                                               *
+ *                                                                                             *
+ * INPUT:   source   -- The object most directly responsible for the building's death.         *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/04/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BuildingClass::Death_Announcement(TechnoClass const * source) const
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	if (source != NULL && House->IsPlayerControl) {
+		Speak(VOX_STRUCTURE_DESTROYED);
+	}
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Fire_Direction -- Fetches the direction of firing.                           *
+ *                                                                                             *
+ *    This routine will return with the default direction to use when firing from this         *
+ *    building. This is the facing of the turret except for the case of non-turret equipped    *
+ *    buildings that have a weapon (e.g., guard tower).                                        *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the default firing direction for this building.                       *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/04/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+DirType BuildingClass::Fire_Direction(void) const
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	if (Class->IsTurretEquipped) {
+		return(PrimaryFacing.Current());
+	}
+	return(Direction(TarCom));
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Remap_Table -- Fetches the remap table to use for this building.             *
+ *                                                                                             *
+ *    Use this routine to fetch the remap table to use.  This override function is needed      *
+ *    because the default remap table for techno objects presumes the object is a unit.        *
+ *    Buildings aren't units.                                                                  *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the proper remap table to use for this building.                      *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/08/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void const * BuildingClass::Remap_Table(void)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	return(House->Remap_Table(IsBlushing, Class->Remap));
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Mission_Unload -- Handles the unload mission for a building.                 *
+ *                                                                                             *
+ *    This is the unload mission for a building. This really only applies to the weapon's      *
+ *    factory, since it needs the sophistication of an unload mission due to the door          *
+ *    animation.                                                                               *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the number of game frames to delay before calling this routine        *
+ *          again.                                                                             *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/29/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+int BuildingClass::Mission_Unload(void)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	if (*this == STRUCT_WEAP) {
+		CELL cell = Coord_Cell(Coord) + Class->ExitList[0];
+		COORDINATE coord = Cell_Coord(cell);
+		CellClass * cellptr = &Map[cell];
+		enum {
+			INITIAL,
+			CLEAR_BIB,
+			OPEN,
+			LEAVE,
+			CLOSE
+		};
+		enum {
+			DOOR_STAGES = 5,
+			DOOR_RATE = 8
+		};
+		UnitClass * unit;
+		switch (Status) {
+			/*
+			**	Start the door opening.
+			*/
+			case INITIAL:
+//				if (cellptr->Cell_Techno()) {
+//					cellptr->Incoming(0, true);
+//				}
+				unit = (UnitClass *)Contact_With_Whom();
+				if (unit) {
+					unit->Assign_Mission(MISSION_GUARD);
+					unit->Commence();
+				}
+				Open_Door(DOOR_RATE, DOOR_STAGES);
+				Status = CLEAR_BIB;
+				break;
+
+			/*
+			**	Now that the occupants can peek out the door, they will tell
+			**	everyone that could be blocking the way, that they should
+			**	scatter away.
+			*/
+			case CLEAR_BIB:
+				if (cellptr->Cell_Techno()) {
+					cellptr->Incoming(0, true, true);
+
+					/*
+					**	Scatter everything around the weapon's factory door.
+					*/
+					for (FacingType f = FACING_FIRST; f < FACING_COUNT; f++) {
+						CellClass * cptr = &cellptr->Adjacent_Cell(f);
+						if (cptr->Cell_Building() == NULL) {
+							cptr->Incoming(coord, true, true);
+						}
+					}
+				} else {
+					Status = OPEN;
+				}
+				break;
+
+			/*
+			**	When the door is finally open and the way is clear, tell the
+			**	unit to drive out.
+			*/
+			case OPEN:
+				if (Is_Door_Open()) {
+					unit = (UnitClass *)Contact_With_Whom();
+					if (unit) {
+						unit->Assign_Mission(MISSION_MOVE);
+
+						if (House->IQ >= Rule.IQGuardArea) {
+							unit->Assign_Mission(MISSION_GUARD_AREA);
+							unit->ArchiveTarget = ::As_Target(House->Where_To_Go(unit));
+						}
+						unit->Force_Track(DriveClass::OUT_OF_WEAPON_FACTORY, coord);
+//						unit->Force_Track(DriveClass::OUT_OF_WEAPON_FACTORY, Adjacent_Cell(Adjacent_Cell(Center_Coord(), FACING_S), FACING_S));
+						unit->Set_Speed(128);
+						Status = LEAVE;
+					} else {
+						Close_Door(DOOR_RATE, DOOR_STAGES);
+						Status = CLOSE;
+					}
+				}
+				break;
+
+			/*
+			**	Wait until the unit has completely left the building.
+			*/
+			case LEAVE:
+				if (!IsTethered) {
+					Close_Door(DOOR_RATE, DOOR_STAGES);
+					Status = CLOSE;
+				} else {
+
+//					if (In_Radio_Contact() && !((FootClass *)Contact_With_Whom())->IsDriving) {
+//						Transmit_Message(RADIO_OVER_OUT);
+//					}
+
+				}
+				break;
+
+			/*
+			**	Wait while the door closes.
+			*/
+			case CLOSE:
+				if (Is_Door_Closed()) {
+					Enter_Idle_Mode();
+				}
+				break;
+
+			default:
+				break;
+		}
+		return(MissionControl[Mission].Normal_Delay() + Random_Pick(0, 2));
+	}
+
+	Assign_Mission(MISSION_GUARD);
+	return(1);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Power_Output -- Fetches the current power output from this building.         *
+ *                                                                                             *
+ *    This routine will return the current power output for this building. The power output    *
+ *    is adjusted according to the damage level of the building.                               *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns the current power output for this building.                                *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/29/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+int BuildingClass::Power_Output(void) const
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	if (Class->Power) {
+		return(Class->Power * fixed(LastStrength, Class->MaxStrength));
+	}
+	return(0);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Detach -- Handles target removal from the game system.                       *
+ *                                                                                             *
+ *    This routine is called when the specified target is about to be removed from the game    *
+ *    system.                                                                                  *
+ *                                                                                             *
+ * INPUT:   target   -- The target to be removed from this building's targeting computer.      *
+ *                                                                                             *
+ *          all      -- Is the target about to be completely eliminated?                       *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/29/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BuildingClass::Detach(TARGET target, bool all)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	TechnoClass::Detach(target, all);
+	if (target == WhomToRepay) {
+		WhomToRepay = TARGET_NONE;
+	}
+	if (target == AnimToTrack) {
+		AnimToTrack = TARGET_NONE;
+	}
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Crew_Type -- This determines the crew that this object generates.            *
+ *                                                                                             *
+ *    When selling very cheap buildings (such as the silo), a technician will pop out since    *
+ *    generating minigunners would be overkill -- the player could use this loophole to        *
+ *    gain an advantage.                                                                       *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns the infantry type that this building will generate as a survivor.          *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/05/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+InfantryType BuildingClass::Crew_Type(void) const
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	switch (Class->Type) {
+		case STRUCT_STORAGE:
+			if (Percent_Chance(50)) {
+				return(INFANTRY_C1);
+			} else {
+				return(INFANTRY_C7);
+			}
+
+		case STRUCT_CONST:
+			if (!IsCaptured && House->IsHuman && Percent_Chance(25)) {
+				return(INFANTRY_RENOVATOR);
+			}
+			break;
+
+		case STRUCT_KENNEL:
+			if (Percent_Chance(50)) {
+				return(INFANTRY_DOG);
+			} else {
+				return(INFANTRY_NONE);
+			}
+
+		case STRUCT_TENT:
+		case STRUCT_BARRACKS:
+			return(INFANTRY_E1);
+
+		default:
+			break;
+	}
+	return(TechnoClass::Crew_Type());
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Detach_All -- Possibly abandons production according to factory type.        *
+ *                                                                                             *
+ *    When this routine is called, it indicates that the building is about to be destroyed     *
+ *    or captured. In such a case any production it may be doing, must be abandoned.           *
+ *                                                                                             *
+ * INPUT:   all   -- Is the object about the be completely destroyed?                          *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/05/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BuildingClass::Detach_All(bool all)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	/*
+	**	If it is producing something, then it must be abandoned.
+	*/
+	if (Factory) {
+		Factory->Abandon();
+		delete (FactoryClass *)Factory;
+		Factory = 0;
+	}
+
+	/*
+	** If the owner HouseClass is building something, and this building can
+	** build that thing, we may be the last building for that house that can
+	** build that thing; if so, abandon production of it.
+	*/
+	if (House) {
+		FactoryClass * factory = House->Fetch_Factory(Class->ToBuild);
+
+		/*
+		**	If a factory was found, then temporarily disable this building and then
+		**	determine if any object that is being produced can still be produced. If
+		**	not, then the object being produced must be abandoned.
+		*/
+		if (factory) {
+			TechnoClass * object = factory->Get_Object();
+			IsInLimbo = true;
+			if (object && !object->Techno_Type_Class()->Who_Can_Build_Me(true, false, House->Class->House)) {
+				House->Abandon_Production(Class->ToBuild);
+			}
+			IsInLimbo = false;
+		}
+	}
+
+	TechnoClass::Detach_All(all);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Flush_For_Placement -- Handles clearing a zone for object placement.         *
+ *                                                                                             *
+ *    This routine is used to clear the way for placement of the specified object (usually     *
+ *    a building). If there are friendly units blocking the placement area, they are told      *
+ *    to scatter. Enemy blocking units are attacked.                                           *
+ *                                                                                             *
+ * INPUT:   techno   -- Pointer to the object that is desired to be placed.                    *
+ *                                                                                             *
+ *          cell     -- The cell that placement wants to occur at.                             *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/06/1995 JLB : Created.                                                                 *
+ *   09/27/1995 JLB : Revised to use type class function.                                      *
+ *=============================================================================================*/
+bool BuildingClass::Flush_For_Placement(TechnoClass * techno, CELL cell)
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	if (techno) {
+		return (((BuildingTypeClass const &)techno->Class_Of()).Flush_For_Placement(cell, House));
+	}
+	return(false);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Find_Exit_Cell -- Find a clear location to exit an object from this building *
+ *                                                                                             *
+ *    This routine is called when the building needs to discharge a unit. It will find a       *
+ *    nearby (adjacent) cell that is clear enough for the specified object to enter. Typical   *
+ *    use of this routine is when the airfield disgorges its cargo.                            *
+ *                                                                                             *
+ * INPUT:   techno   -- Pointer to the object that wishes to exit this building.               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the cell number to use for object placement. If no free location      *
+ *          could be found, then zero (0) is returned.                                         *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   09/21/1995 JLB : Created.                                                                 *
+ *   02/20/1996 JLB : Added default case for exit cell calculation.                            *
+ *=============================================================================================*/
+CELL BuildingClass::Find_Exit_Cell(TechnoClass const * techno) const
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	CELL const * ptr;
+	CELL origin = Coord_Cell(Coord);
+
+	ptr = Class->ExitList;
+	if (ptr != NULL) {
+		while (*ptr != REFRESH_EOL) {
+			CELL cell = origin + *ptr++;
+			if (Map.In_Radar(cell) && techno->Can_Enter_Cell(cell) == MOVE_OK) {
+				return(cell);
+			}
+		}
+	} else {
+		int x1, x2;
+		int y1, y2;
+		CELL cell;
+
+		y1 = -1;
+		y2 = Class->Height();
+		for (x1 = -1; x1 <= Class->Width(); x1++) {
+			cell = origin + x1 + (y1 * MAP_CELL_W);
+			if (Map.In_Radar(cell) && techno->Can_Enter_Cell(cell) == MOVE_OK) {
+				return(cell);
+			}
+			cell = origin + x1 + (y2 * MAP_CELL_W);
+			if (Map.In_Radar(cell) && techno->Can_Enter_Cell(cell) == MOVE_OK) {
+				return(cell);
+			}
+		}
+
+		x1 = -1;
+		x2 = Class->Width();
+		for (y1 = -1; y1 <= Class->Height(); y1++) {
+			cell = origin + (y1 * MAP_CELL_W) + x1;
+			if (Map.In_Radar(cell) && techno->Can_Enter_Cell(cell) == MOVE_OK) {
+				return(cell);
+			}
+			cell = origin + (y1 * MAP_CELL_W) + x2;
+			if (Map.In_Radar(cell) && techno->Can_Enter_Cell(cell) == MOVE_OK) {
+				return(cell);
+			}
+		}
+	}
+	return(0);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Can_Player_Move -- Can this building be moved?                               *
+ *                                                                                             *
+ *    This routine answers the question 'can this building be moved?' Typically, only the      *
+ *    construction yard can be moved and it does this by undeploying back into a MCV.          *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Can the building move to a new location under player control?                      *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   10/04/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool BuildingClass::Can_Player_Move(void) const
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	return(*this == STRUCT_CONST);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Exit_Coord -- Determines location where object will leave it.                *
+ *                                                                                             *
+ *    This routine will return the coordinate where an object that wishes to leave the         *
+ *    building will exit at.                                                                   *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the coordinate that the object should be created at.                  *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   02/20/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+COORDINATE BuildingClass::Exit_Coord(void) const
+{
+	assert(Buildings.ID(this) == ID);
+	assert(IsActive);
+
+	if (Class->ExitCoordinate) {
+		return(Coord_Add(Coord, Class->ExitCoordinate));
+	}
+	return(TechnoClass::Exit_Coord());
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Check_Point -- Fetches the landing checkpoint for the given flight pattern.  *
+ *                                                                                             *
+ *    Use this routine to coordinate a landing operation. The specified checkpoint is          *
+ *    converted into a cell number. The landing aircraft should fly over that cell and then    *
+ *    request the next check point.                                                            *
+ *                                                                                             *
+ * INPUT:   cp    -- The check point to convert to a cell number.                              *
+ *                                                                                             *
+ * OUTPUT:  Returns with the cell that the aircraft should fly over in order to complete       *
+ *          that portion of the landing pattern.                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/06/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+CELL BuildingClass::Check_Point(CheckPointType cp) const
+{
+	CELL xoffset = 6;		// Downwind offset.
+	CELL yoffset = 5;		// Crosswind offset.
+	CELL cell = Coord_Cell(Center_Coord());
+
+	switch (cp) {
+		case CHECK_STACK:
+			xoffset = 0;
+			break;
+
+		case CHECK_CROSSWIND:
+			yoffset = 0;
+			break;
+
+		case CHECK_DOWNWIND:
+		default:
+			break;
+	}
+
+	if ((Cell_X(cell) - Map.MapCellX) > Map.MapCellWidth/2)  {
+		xoffset = -xoffset;
+	}
+
+	if ((Cell_Y(cell) - Map.MapCellY) > Map.MapCellHeight/2)  {
+		yoffset = -yoffset;
+	}
+
+	return(XY_Cell(Cell_X(cell)+xoffset, Cell_Y(cell)+yoffset));
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Update_Radar_Spied - set house's RadarSpied field appropriately.				  *
+ *                                                                                             *
+ *    This routine is called when a radar facility is captured or destroyed.  It fills in the  *
+ *    RadarSpied field of the house based on whether there's a spied-upon radar facility or not*
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  House->RadarSpied field gets set appropriately.												  *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   03/22/1996 BWG : Created.                                                                 *
+ *=============================================================================================*/
+void BuildingClass::Update_Radar_Spied(void)
+{
+	House->RadarSpied = 0;
+	for (int index = 0; index < Buildings.Count(); index++) {
+		BuildingClass * obj = Buildings.Ptr(index);
+		if (obj && !obj->IsInLimbo && obj->House == House) {
+			if (*obj == STRUCT_RADAR /* || *obj == STRUCT_EYE */) {
+				House->RadarSpied |= obj->SpiedBy;
+			}
+		}
+	}
+	Map.RadarClass::Flag_To_Redraw(true);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Read_INI -- Reads buildings from INI file.                                   *
+ *                                                                                             *
+ *    This is the basic scenario initialization of building function. It                       *
+ *    is called when reading the scenario startup INI file and it handles                      *
+ *    creation of all specified buildings.                                                     *
+ *                                                                                             *
+ *    INI entry format:                                                                        *
+ *      Housename, Typename, Strength, Cell, Facing, Triggername                               *
+ *                                                                                             *
+ * INPUT:   buffer   -- Pointer to the loaded INI file data.                                   *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/24/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BuildingClass::Read_INI(CCINIClass & ini)
+{
+	BuildingClass			* b;			// Working unit pointer.
+	HousesType				bhouse;		// Building house.
+	StructType				classid;		// Building type.
+	CELL						cell;			// Cell of building.
+	char						buf[128];
+	char						* trigname;	// building's trigger's name
+
+
+	int len = ini.Entry_Count(INI_Name());
+	for (int index = 0; index < len; index++) {
+		char const * entry = ini.Get_Entry(INI_Name(), index);
+
+		/*
+		**	Get a building entry.
+		*/
+		ini.Get_String(INI_Name(), entry, NULL, buf, sizeof(buf));
+
+		/*
+		**	1st token: house name.
+		*/
+		bhouse = HouseTypeClass::From_Name(strtok(buf, ","));
+
+		/*
+		**	2nd token: building name.
+		*/
+		classid = BuildingTypeClass::From_Name(strtok(NULL, ","));
+
+		if (bhouse != HOUSE_NONE && classid != STRUCT_NONE) {
+			int	strength;
+			DirType facing;
+
+			/*
+			**	3rd token: strength.
+			*/
+			strength = atoi(strtok(NULL, ","));
+
+			/*
+			**	4th token: cell #.
+			*/
+			cell = atoi(strtok(NULL, ","));
+
+			/*
+			**	5th token: facing.
+			*/
+			facing = (DirType)atoi(strtok(NULL, ","));
+
+			/*
+			**	6th token: triggername (can be NULL).
+			*/
+			trigname = strtok(NULL, ",");
+
+			bool sellable = false;
+			char * token_pointer = strtok(NULL, ",");
+			if (token_pointer) {
+				sellable = atoi(token_pointer);
+			}
+
+			bool rebuild = false;
+			token_pointer = strtok(NULL, ",");
+			if (token_pointer) {
+				rebuild = atoi(token_pointer);
+			}
+
+			b = new BuildingClass(classid, bhouse);
+			if (b) {
+
+				TriggerTypeClass * tp = TriggerTypeClass::From_Name(trigname);
+				if (tp) {
+					TriggerClass * tt = Find_Or_Make(tp);
+					if (tt) {
+						tt->AttachCount++;
+						b->Trigger = tt;
+					}
+				}
+				b->IsAllowedToSell = sellable;
+				b->IsToRebuild = rebuild;
+				b->IsToRepair = rebuild || *b == STRUCT_CONST;
+
+				if (b->Unlimbo(Cell_Coord(cell), facing)) {
+					strength = min(strength, 0x100);
+					strength = b->Class->MaxStrength * fixed(strength, 256);
+					b->Strength = strength;
+					if (b->Strength > b->Class->MaxStrength-3) b->Strength = b->Class->MaxStrength;
+					b->IsALemon = false;
+				} else {
+
+					/*
+					**	If the building could not be unlimboed on the map, then this indicates
+					**	a serious error. Delete the building.
+					*/
+					delete b;
+				}
+			}
+		}
+	}
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Write_INI -- Write out the building data to the INI file specified.          *
+ *                                                                                             *
+ *    This will store the building data (as it relates to scenario initialization) to the      *
+ *    INI database specified.                                                                  *
+ *                                                                                             *
+ * INPUT:   ini   -- Reference to the INI database that the building data will be stored to.   *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/06/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BuildingClass::Write_INI(CCINIClass & ini)
+{
+	/*
+	**	First, clear out all existing building data from the ini file.
+	*/
+	ini.Clear(INI_Name());
+
+	/*
+	**	Write the data out.
+	*/
+	for (int index = 0; index < Buildings.Count(); index++) {
+		BuildingClass * building = Buildings.Ptr(index);
+		if (!building->IsInLimbo) {
+			char	uname[10];
+			char	buf[127];
+
+			sprintf(uname, "%d", index);
+			sprintf(buf, "%s,%s,%d,%u,%d,%s,%d,%d",
+				building->House->Class->IniName,
+				building->Class->IniName,
+				building->Health_Ratio()*256,
+				Coord_Cell(building->Coord),
+				building->PrimaryFacing.Current(),
+				building->Trigger.Is_Valid() ? building->Trigger->Class->IniName : "None",
+				building->IsAllowedToSell,
+				building->IsToRebuild
+				);
+			ini.Put_String(INI_Name(), uname, buf);
+		}
+	}
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Target_Coord -- Return the coordinate to use when firing on this building.   *
+ *                                                                                             *
+ *    This routine will determine the "center" location of this building for purposes of       *
+ *    targeting. Usually, this location is somewhere near the foundation of the building.      *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the coordinate to use when firing upon this building (or trying to    *
+ *          walk onto it).                                                                     *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/19/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+COORDINATE BuildingClass::Target_Coord(void) const
+{
+	COORDINATE coord = Center_Coord();
+
+	if (Class->FoundationFace != FACING_NONE) {
+		return(Adjacent_Cell(coord, Class->FoundationFace));
+	}
+	return(coord);
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Factory_AI -- Handle factory production and initiation.                      *
+ *                                                                                             *
+ *    Some building (notably the computer controlled ones) can have a factory object attached. *
+ *    This routine handles processing of that factory and also detecting when production       *
+ *    should begin in order to initiate production.                                            *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   Only call this routine once per building per game logic loop.                   *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/29/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BuildingClass::Factory_AI(void)
+{
+	/*
+	**	Handle any production tied to this building. Only computer controlled buildings have
+	**	production attached to the building itself. The player uses the sidebar interface for
+	**	all production control.
+	*/
+	if (Factory.Is_Valid() && Factory->Has_Completed() && PlacementDelay == 0) {
+		TechnoClass * product = Factory->Get_Object();
+//		FactoryClass * fact = Factory;
+
+		switch (Exit_Object(product)) {
+
+			/*
+			**	If the object could not leave the factory, then either request
+			**	a transport, place the (what must be a) building using another method, or
+			**	abort the production and refund money.
+			*/
+			case 0:
+				Factory->Abandon();
+				delete (FactoryClass *)Factory;
+				Factory = 0;
+				break;
+
+			/*
+			**	Exiting this building is prevented by some temporary blockage. Wait
+			**	a bit before trying again.
+			*/
+			case 1:
+				PlacementDelay = TICKS_PER_SECOND*3;
+				break;
+
+			/*
+			**	The object was successfully sent from this factory. Inform the house
+			**	tracking logic that the requested object has been produced.
+			*/
+			case 2:
+				switch (product->What_Am_I()) {
+					case RTTI_VESSEL:
+						House->JustBuiltVessel = ((VesselClass*)product)->Class->Type;
+						House->IsBuiltSomething = true;
+						break;
+
+					case RTTI_UNIT:
+						House->JustBuiltUnit = ((UnitClass*)product)->Class->Type;
+						House->IsBuiltSomething = true;
+						break;
+
+					case RTTI_INFANTRY:
+						House->JustBuiltInfantry = ((InfantryClass*)product)->Class->Type;
+						House->IsBuiltSomething = true;
+						break;
+
+					case RTTI_BUILDING:
+						House->JustBuiltStructure = ((BuildingClass*)product)->Class->Type;
+						House->IsBuiltSomething = true;
+						break;
+
+					case RTTI_AIRCRAFT:
+						House->JustBuiltAircraft = ((AircraftClass*)product)->Class->Type;
+						House->IsBuiltSomething = true;
+						break;
+
+					default:
+						break;
+				}
+//				fact->Completed();
+				Factory->Completed();
+//				delete fact;
+				delete (FactoryClass *)Factory;
+				Factory = 0;
+				break;
+
+			default:
+				break;
+		}
+	}
+
+	/*
+	**	Pick something to create for this factory.
+	*/
+	if (House->IsStarted && Mission != MISSION_CONSTRUCTION && Mission != MISSION_DECONSTRUCTION) {
+
+		/*
+		**	Buildings that produce other objects have special factory logic handled here.
+		*/
+		if (Class->ToBuild != RTTI_NONE) {
+			if (Factory.Is_Valid()) {
+
+				/*
+				**	If production has halted, then just abort production and make the
+				**	funds available for something else.
+				*/
+				if (PlacementDelay == 0 && !Factory->Is_Building()) {
+					Factory->Abandon();
+					delete (FactoryClass *)Factory;
+					Factory = 0;
+				}
+
+			} else {
+
+				/*
+				**	Only look to start production if there is at least a small amount of
+				**	money available. In cases where there is no practical money left, then
+				**	production can never complete -- don't bother starting it.
+				*/
+				if (House->IsStarted && House->Available_Money() > 10) {
+					TechnoTypeClass const * techno = House->Suggest_New_Object(Class->ToBuild, *this == STRUCT_KENNEL);
+
+					/*
+					**	If a suitable object type was selected for production, then start
+					**	producing it now.
+					*/
+					if (techno != NULL) {
+						Factory = new FactoryClass;
+						if (Factory.Is_Valid()) {
+							if (!Factory->Set(*techno, *House)) {
+								delete (FactoryClass *)Factory;
+								Factory = 0;
+							} else {
+								House->Production_Begun(Factory->Get_Object());
+								Factory->Start();
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Rotation_AI -- Process any turret rotation required of this building.        *
+ *                                                                                             *
+ *    Some buildings have a turret and this routine handles processing the turret rotation.    *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   Only call this routine once per building per game logic loop.                   *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/29/1996 JLB : Created.                                                                 *
+ *   10/27/1996 JLB : Rotation does not occur if power and no power avail.                     *
+ *=============================================================================================*/
+void BuildingClass::Rotation_AI(void)
+{
+	if (Class->IsTurretEquipped &&
+			Mission != MISSION_CONSTRUCTION &&
+			Mission != MISSION_DECONSTRUCTION &&
+			(!Class->IsPowered || House->Power_Fraction() >= 1)) {
+
+		/*
+		**	Rotate turret to match desired facing.
+		*/
+		if (PrimaryFacing.Is_Rotating()) {
+			if (PrimaryFacing.Rotation_Adjust(Class->ROT)) {
+				Mark(MARK_CHANGE);
+			}
+		}
+	}
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Charging_AI -- Handles the special charging logic for Tesla coils.           *
+ *                                                                                             *
+ *    This handles the special logic required of the charging tesla coil. It requires special  *
+ *    processing since its charge up is dependant upon the target and power surplus of the     *
+ *    owning house.                                                                            *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/29/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BuildingClass::Charging_AI(void)
+{
+	if (Class->PrimaryWeapon != NULL && Class->PrimaryWeapon->IsElectric && BState != BSTATE_CONSTRUCTION) {
+		if (Target_Legal(TarCom) && House->Power_Fraction() >= 1) {
+			if (!IsCharged) {
+				if (IsCharging) {
+//					if (stagechange) {
+						Mark(MARK_CHANGE);
+						if (Fetch_Stage() >= 9) {
+							IsCharged = true;
+							IsCharging = false;
+							Set_Rate(0);
+						}
+//					}
+				} else if (!Arm) {
+					IsCharged = false;
+					IsCharging = true;
+					Set_Stage(0);
+					Set_Rate(3);
+					Sound_Effect(VOC_TESLA_POWER_UP, Coord);
+				}
+			}
+		} else {
+			if (IsCharging || IsCharged) {
+				Mark(MARK_CHANGE);
+				IsCharging = false;
+				IsCharged = false;
+				Set_Stage(0);
+				Set_Rate(0);
+			}
+		}
+	}
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Repair_AI -- Handle the repair (and sell) logic for the building.            *
+ *                                                                                             *
+ *    This routine handle the repair animation and healing logic. It also detects when the     *
+ *    (computer controlled) building should begin repair or sell itself.                       *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   Only call this routine once per building per game logic loop.                   *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/29/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BuildingClass::Repair_AI(void)
+{
+	if (House->IQ >= Rule.IQRepairSell && Mission != MISSION_CONSTRUCTION && Mission != MISSION_DECONSTRUCTION) {
+		/*
+		**	Possibly start repair process if the building is below half strength.
+		*/
+//		unsigned ratio = MIN(House->Smartness, 0x00F0);
+		if (Can_Repair()) {
+			if (House->Available_Money() >= Rule.RepairThreshhold) {
+				if (!House->DidRepair) {
+					if (!IsRepairing && (IsCaptured || IsToRepair || House->IsHuman || Session.Type != GAME_NORMAL)) {
+						House->DidRepair = true;	// flag that this house did its repair allocation for this frame
+						Repair(1);
+
+						if (!House->IsHuman) {
+							House->RepairTimer = Random_Pick((int)(House->RepairDelay * (TICKS_PER_MINUTE/4)), (int)(House->RepairDelay * TICKS_PER_MINUTE * 2));
+						}
+					}
+				}
+			} else {
+				if ((Session.Type != GAME_NORMAL || IsAllowedToSell) && IsTickedOff && House->Control.TechLevel >= Rule.IQSellBack && Random_Pick(0, 50) < House->Control.TechLevel && !Trigger.Is_Valid() && *this != STRUCT_CONST && Health_Ratio() < Rule.ConditionRed) {
+					Sell_Back(1);
+				}
+			}
+		}
+	}
+
+	/*
+	**	If it is repairing, then apply any repair effects as necessary.
+	*/
+	if (IsRepairing && (Frame % (Rule.RepairRate * TICKS_PER_MINUTE)) == 0) {
+		IsWrenchVisible = (IsWrenchVisible == false);
+		Mark(MARK_CHANGE);
+		int cost = Class->Repair_Cost();
+		int step = Class->Repair_Step();
+
+		/*
+		**	Check for and expend any necessary monies to continue the repair.
+		*/
+		if (House->Available_Money() >= cost) {
+			House->Spend_Money(cost);
+			Strength += step;
+
+			if (Strength >= Class->MaxStrength) {
+				Strength = Class->MaxStrength;
+				IsRepairing = false;
+			}
+		} else {
+			IsRepairing = false;
+		}
+	}
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Animation_AI -- Handles normal building animation processing.                *
+ *                                                                                             *
+ *    This will process the general building animation mechanism. It detects when the          *
+ *    building animation sequence has completed and flags the building to perform mission      *
+ *    changes as a result.                                                                     *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   Call this routine only once per building per game logic loop.                   *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/29/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BuildingClass::Animation_AI(void)
+{
+	bool stagechange = Graphic_Logic();
+	bool toloop = false;
+
+	/*
+	**	Always refresh the SAM site if it has an animation change.
+	*/
+	if (*this == STRUCT_SAM && stagechange) Mark(MARK_CHANGE);
+
+	if ((!Class->IsTurretEquipped && *this != STRUCT_TESLA) || Mission == MISSION_CONSTRUCTION || Mission == MISSION_DECONSTRUCTION) {
+		if (stagechange) {
+
+			/*
+			**	Check for animation end or if special case of MCV deconstructing when it is allowed
+			**	to convert back into an MCV.
+			*/
+			BuildingTypeClass::AnimControlType const * ctrl = Fetch_Anim_Control();
+
+			/*
+			**	When the last frame of the current animation sequence is reached, flag that
+			**	a new mission may be started. This must occur before the animation actually
+			**	loops so that if a mission change does occur, it will have a chance to change
+			**	the building graphic before the last frame is replaced by the first frame of
+			**	the loop.
+			*/
+			if (Fetch_Stage() == ctrl->Start+ctrl->Count-1  || (!Target_Legal(ArchiveTarget) /*Special.IsMCVDeploy*/ && *this == STRUCT_CONST && Mission == MISSION_DECONSTRUCTION && Fetch_Stage() == (42-19))) {
+				IsReadyToCommence = true;
+			}
+
+			/*
+			**	If the animation advances beyond the last frame, then start the animation
+			**	sequence over from the beginning.
+			*/
+			if (Fetch_Stage() >= ctrl->Start+ctrl->Count) {
+				toloop = true;
+			}
+			Mark(MARK_CHANGE);
+		} else {
+			if (BState == BSTATE_NONE || Fetch_Rate() == 0) {
+				IsReadyToCommence = true;
+			}
+		}
+	}
+
+	/*
+	**	If there is a door that is animating, then it might cause this building
+	**	to be redrawn. Check for and flag to redraw as necessary.
+	*/
+	if (Time_To_Redraw()) {
+		Clear_Redraw_Flag();
+		Mark(MARK_CHANGE);
+	}
+
+	/*
+	**	The animation sequence has looped. Restart it and flag this loop condition.
+	**	This is used to tell the mission system that the animation has completed. It
+	**	also signals that now is a good time to act on any pending mission.
+	*/
+	if (toloop) {
+		BuildingTypeClass::AnimControlType const * ctrl = Fetch_Anim_Control();
+		if (BState == BSTATE_CONSTRUCTION || BState == BSTATE_IDLE) {
+			Set_Rate(Options.Normalize_Delay(ctrl->Rate));
+		} else {
+			Set_Rate(ctrl->Rate);
+		}
+		Set_Stage(ctrl->Start);
+		Mark(MARK_CHANGE);
+	}
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::How_Many_Survivors -- This determine the maximum number of survivors.        *
+ *                                                                                             *
+ *    This routine is called to determine how many survivors should run from this building     *
+ *    when it is either sold or destroyed. Buildings that are captured have fewer survivors.   *
+ *    The number of survivors is a portion of the cost of the building divided by the cost     *
+ *    of a minigunner.                                                                         *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the number of soldiers that should run from this building.            *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/04/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+int BuildingClass::How_Many_Survivors(void) const
+{
+	if (IsSurvivorless || !Class->IsCrew) return(0);
+
+	int divisor = InfantryTypeClass::As_Reference(INFANTRY_E1).Raw_Cost();
+	if (divisor == 0) return(0);
+	if (IsCaptured) divisor *= 2;
+	int count = (Class->Raw_Cost() * Rule.SurvivorFraction) / divisor;
+	return(Bound(count, 1, 5));
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Get_Image_Data -- Fetch the image pointer for the building.                  *
+ *                                                                                             *
+ *    This routine will return with a pointer to the shape data for the building. The shape    *
+ *    data is different than normal when the building is undergoing construction and           *
+ *    disassembly.                                                                             *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with a pointer to the shape data for this building.                        *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/06/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void const * BuildingClass::Get_Image_Data(void) const
+{
+	if (BState == BSTATE_CONSTRUCTION) {
+		return(Class->Get_Buildup_Data());
+	}
+	return(TechnoClass::Get_Image_Data());
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Value -- Determine the value of this building.                               *
+ *                                                                                             *
+ *    The value of the building is normally just its ordinary assigned value. However, in the  *
+ *    case of fakes, the value is artificially enhanced to match the structure that is         *
+ *    being faked.                                                                             *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the point value of the building type.                                 *
+ *                                                                                             *
+ * WARNINGS:   The point value returned should not be used for scoring, only for target        *
+ *             scanning.                                                                       *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   09/16/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+int BuildingClass::Value(void) const
+{
+	if (Class->IsFake) {
+		switch (Class->Type) {
+			case STRUCT_FAKEWEAP:
+				return(BuildingTypeClass::As_Reference(STRUCT_WEAP).Reward + BuildingTypeClass::As_Reference(STRUCT_WEAP).Risk);
+
+			case STRUCT_FAKECONST:
+				return(BuildingTypeClass::As_Reference(STRUCT_CONST).Reward + BuildingTypeClass::As_Reference(STRUCT_CONST).Risk);
+
+			case STRUCT_FAKE_YARD:
+				return(BuildingTypeClass::As_Reference(STRUCT_SHIP_YARD).Reward + BuildingTypeClass::As_Reference(STRUCT_SHIP_YARD).Risk);
+
+			case STRUCT_FAKE_PEN:
+				return(BuildingTypeClass::As_Reference(STRUCT_SUB_PEN).Reward + BuildingTypeClass::As_Reference(STRUCT_SUB_PEN).Risk);
+
+			case STRUCT_FAKE_RADAR:
+				return(BuildingTypeClass::As_Reference(STRUCT_RADAR).Reward + BuildingTypeClass::As_Reference(STRUCT_RADAR).Risk);
+
+			default:
+				break;
+		}
+	}
+	return(TechnoClass::Value());
+}
+
+
+/***********************************************************************************************
+ * BuildingClass::Remove_Gap_Effect -- Stop a gap generator from jamming cells.					  *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none																										  *
+ *                                                                                             *
+ * WARNINGS:   																										  *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   09/20/1996 BWG : Created.                                                                 *
+ *=============================================================================================*/
+void BuildingClass::Remove_Gap_Effect(void)
+{
+	// unjam this one's field...
+	Map.UnJam_From(Coord_Cell(Center_Coord()), Rule.GapShroudRadius, House);
+	if (!House->IsPlayerControl && PlayerPtr->IsGPSActive) {
+		Map.Sight_From(Coord_Cell(Center_Coord()), Rule.GapShroudRadius, PlayerPtr);
+	}
+	// and rejam any overlapping buildings' fields
+	for (int index = 0; index < Buildings.Count(); index++) {
+		BuildingClass *obj = Buildings.Ptr(index);
+		if (obj && !obj->IsInLimbo && obj->House == House && *obj == STRUCT_GAP && obj!=this) {
+			obj->IsJamming = false;
+			obj->Arm = 0;
+//			Map.Jam_From(Coord_Cell(obj->Center_Coord()), Rule.GapShroudRadius, PlayerPtr);
+		}
+	}
+}
+
+
+short const * BuildingClass::Overlap_List(bool redraw) const
+{
+	if ((SpiedBy & (1 << PlayerPtr->Class->House)) != 0 && IsSelected && (*this == STRUCT_BARRACKS || *this == STRUCT_TENT)) {
+		static short const _list[] = {
+			-1, 2, (MAP_CELL_W*1)-1, (MAP_CELL_W*1)+2, REFRESH_EOL
+		};
+		return(_list);
+	}
+	return(TechnoClass::Overlap_List(redraw));
+}

+ 356 - 0
CODE/BUILDING.H

@@ -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 - 0
CODE/BULLET.CPP

@@ -0,0 +1,1070 @@
+/*
+**	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.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 : BULLET.CPP                                                   *
+ *                                                                                             *
+ *                   Programmer : Joe L. Bostic                                                *
+ *                                                                                             *
+ *                   Start Date : April 23, 1994                                               *
+ *                                                                                             *
+ *                  Last Update : October 10, 1996 [JLB]                                       *
+ *                                                                                             *
+ *---------------------------------------------------------------------------------------------*
+ * Functions:                                                                                  *
+ *   BulletClass::AI -- Logic processing for bullet.                                           *
+ *   BulletClass::BulletClass -- Bullet constructor.                                           *
+ *   BulletClass::Bullet_Explodes -- Performs bullet explosion logic.                          *
+ *   BulletClass::Detach -- Removes specified target from this bullet's targeting system.      *
+ *   BulletClass::Draw_It -- Displays the bullet at location specified.                        *
+ *   BulletClass::In_Which_Layer -- Fetches the layer that the bullet resides in.              *
+ *   BulletClass::Init -- Clears the bullets array for scenario preparation.                   *
+ *   BulletClass::Is_Forced_To_Explode -- Checks if bullet should explode NOW.                 *
+ *   BulletClass::Mark -- Performs related map refreshing under bullet.                        *
+ *   BulletClass::Occupy_List -- Determines the bullet occupation list.                        *
+ *   BulletClass::Shape_Number -- Fetches the shape number for the bullet object.              *
+ *   BulletClass::Sort_Y -- Sort coordinate for bullet rendering.                              *
+ *   BulletClass::Target_Coord -- Fetches coordinate to use when firing on this object.        *
+ *   BulletClass::Unlimbo -- Transitions a bullet object into the game render/logic system.    *
+ *   BulletClass::delete -- Bullet memory delete.                                              *
+ *   BulletClass::new -- Allocates memory for bullet object.                                   *
+ *   BulletClass::~BulletClass -- Destructor for bullet objects.                               *
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+#include	"function.h"
+
+
+/***********************************************************************************************
+ * BulletClass::BulletClass -- Bullet constructor.                                             *
+ *                                                                                             *
+ *    This is the constructor for the bullet class. It handles all                             *
+ *    initialization of the bullet and starting it in motion toward its                        *
+ *    target.                                                                                  *
+ *                                                                                             *
+ * INPUT:   id       -- The type of bullet this is (could be missile).                         *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/02/1994 JLB : Created.                                                                 *
+ *   06/20/1994 JLB : Firer is a base class pointer.                                           *
+ *   12/10/1994 JLB : Auto calculate range optional.                                           *
+ *   12/12/1994 JLB : Handles small arms as an instantaneous effect.                           *
+ *   12/23/1994 JLB : Fixed scatter algorithm for non-homing projectiles.                      *
+ *   12/31/1994 JLB : Removed range parameter (not needed).                                    *
+ *=============================================================================================*/
+BulletClass::BulletClass(BulletType id, TARGET target, TechnoClass * payback, int strength, WarheadType warhead, int speed) :
+	ObjectClass(RTTI_BULLET, Bullets.ID(this)),
+	Class(BulletTypes.Ptr((int)id)),
+	Payback(payback),
+	PrimaryFacing(DIR_N),
+	IsInaccurate(false),
+	IsToAnimate(false),
+	IsLocked(true),
+	TarCom(target),
+	MaxSpeed(speed),
+	Warhead(warhead)
+{
+	Strength = strength;
+	Height = FLIGHT_LEVEL;
+}
+
+
+/***********************************************************************************************
+ * BulletClass::~BulletClass -- Destructor for bullet objects.                                 *
+ *                                                                                             *
+ *    The bullet destructor must detect if a dog has been attached to this bullet. If so,      *
+ *    then the attached dog must be unlimboed back onto the map. This operation is necessary   *
+ *    because, unlike other objects, the dog flies with the bullet it fires.                   *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/06/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+BulletClass::~BulletClass(void)
+{
+	if (GameActive) {
+
+		/*
+		**	SPECIAL CASE:
+		**	The dog is attached to the dog bullet in a limbo state. When the bullet is
+		**	destroyed, the dog must come back out of limbo at the closest location possible to
+		**	the bullet.
+		*/
+		if (Payback != NULL && Payback->What_Am_I() == RTTI_INFANTRY && ((InfantryClass *)Payback)->Class->IsDog) {
+
+			InfantryClass * dog = (InfantryClass *)Payback;
+			if (dog) {
+				bool unlimbo = false;
+				DirType dogface = dog->PrimaryFacing;
+				COORDINATE newcoord = Coord;
+
+				/*
+				**	Ensure that the coordinate, that the dog is to appear at, is legal. If not,
+				**	then find a nearby legal location.
+				*/
+				if (Can_Enter_Cell(newcoord) != MOVE_OK) {
+					newcoord = Map.Nearby_Location(Coord_Cell(newcoord), dog->Class->Speed);
+				}
+
+				/*
+				** Try to put the dog down where the target impacted.  If we can't
+				** put it in that cell, then scan through the adjacent cells,
+				** starting with our current heading, until we find a place where
+				** we can put him down.  If all 8 adjacent cell checks fail, then
+				** just delete the dog.
+				*/
+				for (int i = -1; i < 8; i++) {
+					if (i != -1) {
+						newcoord = Adjacent_Cell(Coord, FacingType(i));
+					}
+					ScenarioInit++;
+					if (dog->Unlimbo(newcoord, dog->PrimaryFacing)) {
+						dog->Mark(MARK_DOWN);
+						dog->Do_Action(DO_DOG_MAUL, true);
+						if (dog->WasSelected) {
+							dog->Select();
+						}
+						ScenarioInit--;
+						unlimbo = true;
+						break;
+					}
+					ScenarioInit--;
+				}
+
+				Payback = 0;
+
+				if (!unlimbo) {
+					delete dog;
+				}
+			}
+		}
+		BulletClass::Limbo();
+	}
+
+	Class=0;
+	Payback=0;
+}
+
+
+/***********************************************************************************************
+ * BulletClass::new -- Allocates memory for bullet object.                                     *
+ *                                                                                             *
+ *    This function will "allocate" a block of memory for a bullet object.                     *
+ *    This memory block is merely lifted from a fixed pool of blocks.                          *
+ *                                                                                             *
+ * INPUT:   size  -- The size of the memory block needed.                                      *
+ *                                                                                             *
+ * OUTPUT:  Returns with a pointer to an available bullet object block.                        *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/02/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void * BulletClass::operator new(size_t )
+{
+	void * ptr = Bullets.Allocate();
+	if (ptr) {
+		((BulletClass *)ptr)->IsActive = true;
+	}
+	return(ptr);
+}
+
+
+/***********************************************************************************************
+ * BulletClass::delete -- Bullet memory delete.                                                *
+ *                                                                                             *
+ *    Since bullets memory is merely "allocated" out of a pool, it never                       *
+ *    actually gets deleted.                                                                   *
+ *                                                                                             *
+ * INPUT:   ptr   -- Generic pointer to bullet object.                                         *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/02/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BulletClass::operator delete(void * ptr)
+{
+	if (ptr) {
+		((BulletClass *)ptr)->IsActive = false;
+	}
+	Bullets.Free((BulletClass *)ptr);
+}
+
+
+/***********************************************************************************************
+ * BulletClass::Occupy_List -- Determines the bullet occupation list.                          *
+ *                                                                                             *
+ *    This function will determine the cell occupation list and return a pointer to it. Most   *
+ *    bullets are small and the list is usually short, but on occasion, it can be a list that  *
+ *    rivals the size of regular vehicles.                                                     *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with a pointer to the cell offset list that covers all the cells a bullet  *
+ *          is over.                                                                           *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/20/1994 JLB : Created.                                                                 *
+ *   01/05/1995 JLB : Handles projectiles with altitude.                                       *
+ *=============================================================================================*/
+short const * BulletClass::Occupy_List(bool) const
+{
+	assert(Bullets.ID(this) == ID);
+	assert(IsActive);
+
+	/*
+	**	Super-gigundo units use the >= 64 coord spillage list logic.
+	*/
+	if (Class->IsGigundo) {
+		static short _list[] = {
+			-1, 0, 1,
+			MAP_CELL_W*1-1, MAP_CELL_W*1, MAP_CELL_W*1+1,
+			-MAP_CELL_W*1-1, -MAP_CELL_W*1, -MAP_CELL_W*1+1,
+			MAP_CELL_W*2-1, MAP_CELL_W*2, MAP_CELL_W*2+1,
+			-MAP_CELL_W*2-1, -MAP_CELL_W*2, -MAP_CELL_W*2+1,
+			-MAP_CELL_W*3-1, -MAP_CELL_W*3, -MAP_CELL_W*3+1,
+			REFRESH_EOL
+		};
+		return(_list);
+//		return(Coord_Spillage_List(Coord, 64));
+	}
+
+	/*
+	**	Flying units need a special adjustment to the spillage list to take into account
+	**	that the bullet imagery and the shadow are widely separated.
+	*/
+	if (Height > 0) {
+		static short _list[25];
+		const short * ptr = Coord_Spillage_List(Coord, 5);
+		int index = 0;
+		CELL cell1 = Coord_Cell(Coord);
+
+		while (ptr[index] != REFRESH_EOL) {
+			_list[index] = ptr[index];
+			index++;
+		}
+
+		COORDINATE coord = Coord_Move(Coord, DIR_N, Height);
+		CELL cell2 = Coord_Cell(coord);
+		ptr = Coord_Spillage_List(coord, 5);
+		while (*ptr != REFRESH_EOL) {
+			_list[index++] = *ptr + (cell2 - cell1);
+			ptr++;
+		}
+		_list[index] = REFRESH_EOL;
+		return(_list);
+	}
+
+	return(Coord_Spillage_List(Coord, 10));
+}
+
+
+/***********************************************************************************************
+ * BulletClass::Mark -- Performs related map refreshing under bullet.                          *
+ *                                                                                             *
+ *    This routine marks the objects under the bullet so that they will                        *
+ *    be redrawn. This is necessary as the bullet moves -- objects under                       *
+ *    its path need to be restored.                                                            *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/02/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool BulletClass::Mark(MarkType mark)
+{
+	assert(Bullets.ID(this) == ID);
+	assert(IsActive);
+
+	if (ObjectClass::Mark(mark)) {
+		if (!Class->IsInvisible) {
+			Map.Refresh_Cells(Coord_Cell(Coord), Occupy_List());
+		}
+		return(true);
+	}
+	return(false);
+}
+
+
+/***********************************************************************************************
+ * BulletClass::AI -- Logic processing for bullet.                                             *
+ *                                                                                             *
+ *    This routine will perform all logic (flight) logic on the bullet.                        *
+ *    Primarily this is motion, fuse tracking, and detonation logic. Call                      *
+ *    this routine no more than once per bullet per game tick.                                 *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/02/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BulletClass::AI(void)
+{
+	assert(Bullets.ID(this) == ID);
+	assert(IsActive);
+
+	COORDINATE	coord;
+
+	ObjectClass::AI();
+
+	if (!IsActive) return;
+
+	/*
+	**	Ballistic objects are handled here.
+	*/
+	bool forced = false;			// Forced explosion.
+	if ((Class->IsArcing || Class->IsDropping) && !IsFalling) {
+		forced = true;
+	}
+
+	/*
+	**	Homing projectiles constantly change facing to face toward the target but
+	**	they only do so every other game frame (improves game speed and makes
+	**	missiles not so deadly).
+	*/
+	if ((Frame & 0x01) && Class->ROT != 0 && Target_Legal(TarCom)) {
+		PrimaryFacing.Set_Desired(Direction256(Coord, ::As_Coord(TarCom)));
+	}
+
+	/*
+	**	Move the projectile forward according to its speed
+	**	and direction.
+	*/
+	coord = Coord;
+	if (Class->IsFlameEquipped) {
+		if (IsToAnimate) {
+			if (stricmp(Class->GraphicName, "FB1") == 0) {
+				new AnimClass(ANIM_FBALL_FADE, coord, 1);
+			} else {
+				new AnimClass(ANIM_SMOKE_PUFF, coord, 1);
+			}
+		}
+		IsToAnimate = !IsToAnimate;
+	}
+
+	/*
+	**	Handle any body rotation at this time. This process must
+	**	occur every game fame in order to achieve smooth rotation.
+	*/
+	if (PrimaryFacing.Is_Rotating()) {
+		PrimaryFacing.Rotation_Adjust(Class->ROT);
+	}
+	switch (Physics(coord, PrimaryFacing)) {
+		/*
+		**	When a projectile reaches the edge of the world, it
+		**	vanishes from existence -- presumed to explode off
+		**	map.
+		*/
+		case IMPACT_EDGE:
+			Mark();
+			if (Payback != NULL && Class->Type == BULLET_GPS_SATELLITE) {
+				if (Payback->House == PlayerPtr) {
+					if (!Map.Is_Radar_Active()) {
+						Map.Radar_Activate(1);
+					}
+					for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) {
+						Map.Map_Cell(cell, PlayerPtr);
+					}
+					Map.RadarClass::Flag_To_Redraw(true);
+				}
+				Payback->House->IsGPSActive = true;
+				Payback->House->IsVisionary = true;
+			}
+#ifdef OBSOLETE
+			/*
+			** Hack: If it's the artificial nukes, don't let the bullets come down (as
+			** they're the only ones that blow up).  We know it's artificial if you're
+			** at tech level 10 or below, because you can't build the nuclear silo until
+			** tech level 15 or so.
+			*/
+			if (Payback != NULL && Class->Type == BULLET_NUKE_UP && Payback->House->Control.TechLevel <= 10) {
+				BulletClass * bullet = new BulletClass(BULLET_NUKE_DOWN, ::As_Target(Payback->House->NukeDest), Payback, 200, WARHEAD_NUKE, MPH_VERY_FAST);
+				if (bullet) {
+					int celly = Cell_Y(Payback->House->NukeDest);
+					celly -= 15;
+					if (celly < 1) celly = 1;
+					COORDINATE start = Cell_Coord(XY_Cell(Cell_X(Payback->House->NukeDest), celly));
+					if (!bullet->Unlimbo(start, DIR_S)) {
+						delete bullet;
+					}
+				}
+			}
+#endif
+			delete this;
+			break;
+
+		default:
+		case IMPACT_NONE:
+
+		/*
+		**	The projectile has moved. Check its fuse. If detonation
+		**	is signaled, then do so. Otherwise, just move.
+		*/
+		case IMPACT_NORMAL:
+			Mark();
+//			if(Class->Type == BULLET_NUKE_DOWN) {
+//				Render(true);
+//			}
+			if (Class->Type == BULLET_NUKE_UP) {
+				if (Payback != NULL) {
+					if (Distance(Payback->As_Target()) > 0x0C00) {
+						delete this;
+						return;
+					}
+				}
+			}
+			Coord = coord;
+
+			/*
+			**	See if the bullet should be forced to explode now in spite of what
+			**	the fuse would otherwise indicate. Maybe the bullet hit a wall?
+			*/
+			if (!forced) {
+				forced = Is_Forced_To_Explode(Coord);
+			}
+
+			/*
+			**	If the bullet is not to explode, then perform normal flight
+			**	maintenance (usually nothing). Otherwise, explode and then
+			**	delete the bullet.
+			*/
+			if (!forced && (Class->IsDropping || !Fuse_Checkup(Coord))) {
+				/*
+				**	Certain projectiles lose strength when they travel.
+				*/
+				if (Class->IsDegenerate && Strength > 5) {
+					Strength--;
+				}
+
+			} else {
+				Bullet_Explodes(forced);
+				delete this;
+			}
+			break;
+	}
+
+}
+
+
+/***********************************************************************************************
+ * BulletClass::Shape_Number -- Fetches the shape number for the bullet object.                *
+ *                                                                                             *
+ *    Use this routine to fetch a shape number to use for this bullet object.                  *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the shape number to use when drawing this bullet.                     *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/06/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+int BulletClass::Shape_Number(void) const
+{
+	int shapenum = 0;
+
+	if (!Class->IsFaceless) {
+		shapenum = UnitClass::BodyShape[Dir_To_32(PrimaryFacing)];
+	}
+
+	/*
+	**	For tumbling projectiles, fetch offset stage.
+	*/
+	if (Class->Tumble > 0) {
+		shapenum += (long)Frame % Class->Tumble;
+	}
+
+	return(shapenum);
+}
+
+
+/***********************************************************************************************
+ * BulletClass::Draw_It -- Displays the bullet at location specified.                          *
+ *                                                                                             *
+ *    This routine displays the bullet visual at the location specified.                       *
+ *                                                                                             *
+ * INPUT:   x,y   -- The center coordinate to render the bullet at.                            *
+ *                                                                                             *
+ *          window   -- The window to clip to.                                                 *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/20/1994 JLB : Created.                                                                 *
+ *   06/27/1994 JLB : Takes a window clipping parameter.                                       *
+ *   01/08/1995 JLB : Handles translucent colors if necessary.                                 *
+ *=============================================================================================*/
+void BulletClass::Draw_It(int x, int y, WindowNumberType window) const
+{
+	assert(Bullets.ID(this) == ID);
+	assert(IsActive);
+
+	/*
+	**	Certain projectiles aren't visible. This includes small bullets (which are actually
+	**	invisible) and flame thrower flames (which are rendered as an animation instead of a projectile).
+	*/
+	if (Class->IsInvisible) return;
+
+	/*
+	**	If there is no shape loaded for this object, then
+	**	it obviously can't be rendered -- just bail.
+	*/
+	void const * shapeptr = Get_Image_Data();
+	if (shapeptr == NULL) return;
+
+	/*
+	**	Get the basic shape number for this projectile.
+	*/
+	int shapenum = Shape_Number();
+
+	/*
+	**	For flying projectiles, draw the shadow and adjust the actual projectile body
+	**	render position.
+	*/
+	if (Height > 0 && Class->IsShadow) {
+
+		if (Class->IsParachuted) {
+			CC_Draw_Shape(AnimTypeClass::As_Reference(ANIM_PARA_BOMB).Get_Image_Data(), 1, x+Lepton_To_Pixel(Height/2), y+10, window, SHAPE_PREDATOR|SHAPE_CENTER|SHAPE_WIN_REL|SHAPE_FADING, NULL, DisplayClass::UnitShadow);
+		} else {
+			CC_Draw_Shape(shapeptr, shapenum, x, y, window, SHAPE_PREDATOR|SHAPE_CENTER|SHAPE_WIN_REL|SHAPE_FADING, NULL, DisplayClass::UnitShadow);
+		}
+		y -= Lepton_To_Pixel(Height);
+	}
+
+	/*
+	**	Draw the main body of the projectile.
+	*/
+	ShapeFlags_Type flags = SHAPE_NORMAL;
+	if (Class->IsTranslucent) {
+		flags = SHAPE_GHOST;
+	}
+	if (Class->IsSubSurface) {
+		CC_Draw_Shape(shapeptr, shapenum, x, y, window, flags|SHAPE_PREDATOR|SHAPE_CENTER|SHAPE_WIN_REL|SHAPE_FADING, NULL, DisplayClass::FadingShade);
+	} else {
+		CC_Draw_Shape(shapeptr, shapenum, x, y, window, flags|SHAPE_CENTER|SHAPE_WIN_REL, NULL, DisplayClass::UnitShadow);
+	}
+}
+
+
+/***********************************************************************************************
+ * BulletClass::Init -- Clears the bullets array for scenario preparation.                     *
+ *                                                                                             *
+ *    This routine will zero out the bullet tracking list and object array in preparation for  *
+ *    the start of a new scenario. All bullets cease to exists after this function is          *
+ *    called.                                                                                  *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/15/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BulletClass::Init(void)
+{
+	Bullets.Free_All();
+}
+
+
+/***********************************************************************************************
+ * BulletClass::Detach -- Removes specified target from this bullet's targeting system.        *
+ *                                                                                             *
+ *    When an object is removed from the game system, it must be removed all targeting and     *
+ *    tracking systems as well. This routine is used to remove the specified object from the   *
+ *    bullet. If the object isn't part of this bullet's tracking system, then no action is     *
+ *    performed.                                                                               *
+ *                                                                                             *
+ * INPUT:   target   -- The target to remove from this tracking system.                        *
+ *                                                                                             *
+ *          all      -- Is the target going away for good as opposed to just cloaking/hiding?  *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   09/24/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BulletClass::Detach(TARGET target, bool all)
+{
+	assert(Bullets.ID(this) == ID);
+	assert(IsActive);
+
+	ObjectClass * obj = As_Object(target);
+	if (Payback != NULL && obj == Payback) {
+
+		/*
+		** If we're being called as a result of the dog that fired us being put
+		** in limbo, then don't detach.  If for any other reason, detach.
+		*/
+		if (Payback->What_Am_I() != RTTI_INFANTRY || !((InfantryClass *)Payback)->Class->IsDog) {
+			Payback = 0;
+		}
+	}
+
+	if (all && target == TarCom) {
+		TarCom = TARGET_NONE;
+	}
+}
+
+
+/***********************************************************************************************
+ * BulletClass::Unlimbo -- Transitions a bullet object into the game render/logic system.      *
+ *                                                                                             *
+ *    This routine is used to take a bullet object that is in limbo and transition it to the   *
+ *    game system. A bullet object so transitioned, will be drawn and logic processing         *
+ *    performed. In effect, it comes into existence.                                           *
+ *                                                                                             *
+ * INPUT:   coord -- The location where the bullet object is to appear.                        *
+ *                                                                                             *
+ *          dir   -- The initial facing for the bullet object.                                 *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the unlimbo successful?                                                  *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   01/10/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool BulletClass::Unlimbo(COORDINATE coord, DirType dir)
+{
+	assert(Bullets.ID(this) == ID);
+	assert(IsActive);
+
+	/*
+	**	Try to unlimbo the bullet as far as the base class is concerned. Use the already
+	**	set direction and strength if the "punt" values were passed in. This allows a bullet
+	**	to be setup prior to being launched.
+	*/
+	if (!Class->IsHigh) {
+		Height = 0;
+	}
+	if (ObjectClass::Unlimbo(coord)) {
+		Map.Remove(this, In_Which_Layer());
+
+		COORDINATE tcoord = As_Coord(TarCom);
+
+		/*
+		**	Homing projectiles (missiles) do NOT override facing. They just fire in the
+		**	direction specified and let the chips fall where they may.
+		*/
+		if (Class->ROT == 0 && !Class->IsDropping) {
+			dir = Direction(tcoord);
+		}
+
+		/*
+		**	Possibly adjust the target if this projectile is inaccurate. This occurs whenever
+		**	certain weapons are trained upon targets they were never designed to attack. Example: when
+		**	turrets or anti-tank missiles are fired at infantry. Indirect
+		**	fire is inherently inaccurate.
+		*/
+		if (IsInaccurate || Class->IsInaccurate ||
+			((Is_Target_Cell(TarCom) || Is_Target_Infantry(TarCom)) && (Warhead == WARHEAD_AP || Class->IsFueled))) {
+
+			/*
+			**	Inaccuracy for low velocity or homing projectiles manifests itself as a standard
+			**	Circular Error of Probability (CEP) algorithm. High speed projectiles usually
+			**	just overshoot the target by extending the straight line flight.
+			*/
+			if (/*Class->ROT != 0 ||*/ Class->IsArcing) {
+				int scatterdist = (::Distance(coord, tcoord)/16)-0x0040;
+				scatterdist = min(scatterdist, Rule.HomingScatter);
+				scatterdist = max(scatterdist, 0);
+
+				dir = (DirType)((dir + (Random_Pick(0, 10)-5)) & 0x00FF);
+				tcoord = Coord_Scatter(tcoord, Random_Pick(0, scatterdist));
+			} else {
+				int scatterdist = (::Distance(coord, tcoord)/16)-0x0040;
+				scatterdist = min(scatterdist, Rule.BallisticScatter);
+				scatterdist = max(scatterdist, 0);
+				tcoord = Coord_Move(tcoord, dir, Random_Pick(0, scatterdist));
+			}
+		}
+
+		/*
+		**	For very fast and invisible projectiles, just make the projectile exist at the target
+		**	location and dispense with the actual flight.
+		*/
+		if (MaxSpeed == MPH_LIGHT_SPEED && Class->IsInvisible) {
+			Coord = tcoord;
+		}
+
+		/*
+		**	Set the range equal to either the class defined range or the calculated
+		**	number of game frames it would take for the projectile to reach the target.
+		*/
+		int range = 0xFF;
+		if (!Class->IsDropping) {
+			range = (::Distance(tcoord, Coord) / MaxSpeed) + 4;
+		}
+
+		/*
+		**	Projectile speed is usually the default value for that projectile, but
+		**	certain projectiles alter speed according to the distance to the
+		**	target.
+		*/
+		int speed = MaxSpeed;
+		if (speed == MPH_LIGHT_SPEED) speed = MPH_IMMOBILE;
+		if (Class->IsArcing) {
+			speed = MaxSpeed + (Distance(tcoord) / 32);
+
+			/*
+			**	Set minimum speed (i.e., distance) for arcing projectiles.
+			*/
+			speed = max(speed, 25);
+		}
+		if (!Class->IsDropping) {
+			Fly_Speed(255, (MPHType)speed);
+		}
+
+		/*
+		**	Arm the fuse.
+		*/
+		Arm_Fuse(Coord, tcoord, range, ((As_Aircraft(TarCom)!=0) ? 0 : Class->Arming));
+
+		/*
+		**	Projectiles that make a ballistic flight to impact point must determine a
+		**	vertical component for the projectile launch. This is crudely simulated
+		**	by biasing ground speed according to target distance and then giving
+		**	enough vertical velocity to keep the projectile airborne for the
+		**	desired amount of time. The mathematically correct solution would be to
+		**	calculate launch angle (given fixed projectile velocity) and then derive
+		**	the vertical and horizontal components. That solution would require a
+		**	square root and an arcsine lookup table. OUCH!
+		*/
+		Riser = 0;
+		if (Class->IsArcing) {
+			IsFalling = true;
+			Height = 1;
+			Riser = ((Distance(tcoord)/2) / (speed+1)) * Rule.Gravity;
+			Riser = max(Riser, 10);
+		}
+		if (Class->IsDropping) {
+			IsFalling = true;
+			Height = FLIGHT_LEVEL;
+//			Height = Pixel_To_Lepton(24);
+			Riser = 0;
+			if (Class->IsParachuted) {
+				AnimClass * anim = new AnimClass(ANIM_PARA_BOMB, Target_Coord());
+//				AnimClass * anim = new AnimClass(ANIM_PARACHUTE, Target_Coord());
+				if (anim) {
+					anim->Attach_To(this);
+				}
+			}
+		}
+		Map.Submit(this, In_Which_Layer());
+
+		PrimaryFacing = dir;
+		return(true);
+	}
+	return(false);
+}
+
+
+/***********************************************************************************************
+ * BulletClass::Target_Coord -- Fetches coordinate to use when firing on this object.          *
+ *                                                                                             *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the coordinate that should be used when firing at the object.         *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   09/21/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+COORDINATE BulletClass::Target_Coord(void) const
+{
+	assert(Bullets.ID(this) == ID);
+	assert(IsActive);
+
+	return(Coord_Add(XY_Coord(0, -Height), Coord));
+}
+
+
+/***********************************************************************************************
+ * BulletClass::Sort_Y -- Sort coordinate for bullet rendering.                                *
+ *                                                                                             *
+ *    This will return the coordinate to use when sorting this bullet in the display list.     *
+ *    Typically, this only occurs for bullets in the ground layer. Since bullets are to be     *
+ *    seen a bit more than the normal sorting order would otherwise imply, bias the sort       *
+ *    value such that bullets will tend to be drawn on top of the objects.                     *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the coordinate to use when sorting this bullet in the display list.   *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   10/02/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+COORDINATE BulletClass::Sort_Y(void) const
+{
+	assert(this != 0);
+	assert(IsActive);
+
+	return(Coord_Move(Coord, DIR_S, CELL_LEPTON_H/2));
+}
+
+
+/***********************************************************************************************
+ * BulletClass::In_Which_Layer -- Fetches the layer that the bullet resides in.                *
+ *                                                                                             *
+ *    This examines the bullet to determine what rendering layer it should be in. The          *
+ *    normal logic applies unless this is a torpedo. A torpedo is always in the surface        *
+ *    layer.                                                                                   *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the render layer that this bullet should reside in.                   *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   10/10/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+LayerType BulletClass::In_Which_Layer(void) const
+{
+	if (Class->IsSubSurface) {
+		return(LAYER_SURFACE);
+	}
+	return(ObjectClass::In_Which_Layer());
+}
+
+
+/***********************************************************************************************
+ * BulletClass::Is_Forced_To_Explode -- Checks if bullet should explode NOW.                   *
+ *                                                                                             *
+ *    This routine will examine the bullet and where it is travelling in order to determine    *
+ *    if it should prematurely explode. Typical of this would be when a bullet hits a wall     *
+ *    or a torpedo hits a ship -- regardless of where the projectile was originally aimed.     *
+ *                                                                                             *
+ * INPUT:   coord -- The new coordinate to place the bullet at presuming it is forced to       *
+ *                   explode and a modification of the bullet's coordinate is needed.          *
+ *                   Otherwise, the coordinate is not modified.                                *
+ *                                                                                             *
+ * OUTPUT:  bool; Should the bullet explode now?                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   10/10/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool BulletClass::Is_Forced_To_Explode(COORDINATE & coord) const
+{
+	coord = Coord;
+	CellClass const * cellptr = &Map[coord];
+
+	/*
+	**	Check for impact on a wall or other high obstacle.
+	*/
+	if (!Class->IsHigh && cellptr->Overlay != OVERLAY_NONE && OverlayTypeClass::As_Reference(cellptr->Overlay).IsHigh) {
+		coord = Cell_Coord(Coord_Cell(coord));
+		return(true);
+	}
+
+	/*
+	**	Check to make sure that underwater projectiles (torpedoes) will not
+	**	travel in anything but water.
+	*/
+	if (Class->IsSubSurface) {
+		int d = ::Distance(Coord_Fraction(coord), XY_Coord(CELL_LEPTON_W/2, CELL_LEPTON_W/2));
+		if (cellptr->Land_Type() != LAND_WATER || (d < CELL_LEPTON_W/3 && cellptr->Cell_Techno() != NULL && cellptr->Cell_Techno() != Payback)) {
+
+			/*
+			**	Force explosion to be at center of techno object if one is present.
+			*/
+			if (cellptr->Cell_Techno() != NULL) {
+				coord = cellptr->Cell_Techno()->Target_Coord();
+			}
+
+			/*
+			**	However, if the torpedo was blocked by a bridge, then force the
+			**	torpedo to explode on top of that bridge cell.
+			*/
+			if (cellptr->Is_Bridge_Here()) {
+				coord = Coord_Snap(coord);
+			}
+
+			return(true);
+		}
+	}
+
+	/*
+	**	Bullets are generally more effective when they are fired at aircraft.
+	*/
+	if (Class->IsAntiAircraft && As_Aircraft(TarCom) && Distance(TarCom) < 0x0080) {
+		return(true);
+	}
+
+	/*
+	**	No reason for forced explosion was detected, so return 'false' to
+	**	indicate that no forced explosion is required.
+	*/
+	return(false);
+}
+
+
+/***********************************************************************************************
+ * BulletClass::Bullet_Explodes -- Performs bullet explosion logic.                            *
+ *                                                                                             *
+ *    This handles the exploding bullet action. It will generate the animation and the         *
+ *    damage as necessary.                                                                     *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   The bullet should be deleted after this routine is called.                      *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   10/10/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void BulletClass::Bullet_Explodes(bool forced)
+{
+	/*
+	**	When the target is reached, explode and do the damage
+	**	required of it. For homing objects, don't force the explosion to
+	**	match the target position. Non-homing projectiles adjust position so
+	**	that they hit the target. This compensates for the error in line of
+	**	flight logic.
+	*/
+	if ( (Payback != NULL && Payback->What_Am_I() == RTTI_INFANTRY && ((InfantryClass *)Payback)->Class->IsDog) ||
+		(!forced && !Class->IsArcing && Class->ROT == 0 && Fuse_Target())) {
+		Coord = Fuse_Target();
+	}
+
+	/*
+	**	Non-aircraft targets apply damage to the ground.
+	*/
+	if (!Is_Target_Aircraft(TarCom) || As_Aircraft(TarCom)->In_Which_Layer() == LAYER_GROUND) {
+		Explosion_Damage(Coord, Strength, Payback, Warhead);
+		if (!IsActive) return;
+
+	} else {
+
+		/*
+		**	Special damage apply for SAM missiles. This is the only way that missile
+		**	damage affects the aircraft target.
+		*/
+		if (Distance(TarCom) < 0x0080) {
+			AircraftClass * object = As_Aircraft(TarCom);
+
+			int str = Strength;
+			if (object) object->Take_Damage(str, 0, Warhead, Payback);
+		}
+	}
+
+	/*
+	**	For projectiles that are invisible while travelling toward the target,
+	**	allow scatter effect for the impact animation.
+	*/
+	if (Class->IsInvisible) {
+		Coord = Coord_Scatter(Coord, 0x0020);
+	}
+
+	/*
+	**	Fetch the land type that the explosion will be upon. Special case for
+	**	flying aircraft targets, their land type will be LAND_NONE.
+	*/
+	CellClass const * cellptr = &Map[Coord];
+	LandType land = cellptr->Land_Type();
+	if (Is_Target_Aircraft(TarCom) && As_Aircraft(TarCom)->In_Which_Layer() == LAYER_TOP) {
+		land = LAND_NONE;
+	}
+
+	AnimType anim = Combat_Anim(Strength, Warhead, land);
+
+	/*
+	** If it's a water explosion that's going to play, don't play it
+	** if its cell is the same as the center cell of the target ship.
+	*/
+	if (anim >= ANIM_WATER_EXP1 && anim <= ANIM_WATER_EXP3 && Is_Target_Vessel(TarCom)) {
+		if (Coord_Cell(Coord) == Coord_Cell(As_Vessel(TarCom)->Center_Coord())) {
+			anim = (AnimType) (ANIM_VEH_HIT1 + (anim - ANIM_WATER_EXP1));
+		}
+	}
+
+	if (anim != ANIM_NONE) {
+		AnimClass * aptr = new AnimClass(anim, Coord);
+		/*
+		** Special case trap: if they're making the nuclear explosion,
+		** and no anim is available, force the nuclear damage anyway
+		** because nuke damage is done in the middle of the animation
+		** and if there's no animation, there won't be any damage.
+		*/
+		if (!aptr && anim == ANIM_ATOM_BLAST) {
+			HousesType house = HOUSE_NONE;
+			if (Payback) {
+				house = Payback->House->Class->House;
+			}
+			AnimClass::Do_Atom_Damage(house, Coord_Cell(Coord));
+		}
+	}
+
+//				if (Payback && Payback->House == PlayerPtr && stricmp(Class->Name(), "GPSSATELLITE") == 0) {
+	if (Payback && Class->Type == BULLET_GPS_SATELLITE) {
+		if (Payback->House == PlayerPtr) {
+			if (!Map.Is_Radar_Active()) {
+				Map.Radar_Activate(1);
+			}
+			for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) {
+				Map.Map_Cell(cell, PlayerPtr);
+			}
+			Map.RadarClass::Flag_To_Redraw(true);
+		}
+//					Sound_Effect(VOC_SATTACT2);
+		Payback->House->IsGPSActive = true;
+		Payback->House->IsVisionary = true;
+	}
+}

+ 149 - 0
CODE/BULLET.H

@@ -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 - 0
CODE/C&CZERO.PJT

@@ -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 - 0
CODE/CARGO.CPP

@@ -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 - 0
CODE/CARGO.H

@@ -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 - 0
CODE/CARRY.CPP

@@ -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 - 0
CODE/CARRY.H

@@ -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 - 0
CODE/CCDDE.CPP

@@ -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 - 0
CODE/CCDDE.H

@@ -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 - 0
CODE/CCFILE.CPP

@@ -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 - 0
CODE/CCFILE.H

@@ -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 - 0
CODE/CCINI.CPP

@@ -0,0 +1,1487 @@
+/*
+**	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.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 : CCINI.CPP                                                    *
+ *                                                                                             *
+ *                   Programmer : Joe L. Bostic                                                *
+ *                                                                                             *
+ *                   Start Date : 05/24/96                                                     *
+ *                                                                                             *
+ *                  Last Update : November 1, 1996 [JLB]                                       *
+ *                                                                                             *
+ *---------------------------------------------------------------------------------------------*
+ * Functions:                                                                                  *
+ *   CCINIClass::Calculate_Message_Digest -- Calculate a message digest for the current databas*
+ *   CCINIClass::Get_AnimType -- Fetch an animation type number from the INI database.         *
+ *   CCINIClass::Get_ArmorType -- Fetches the armor type from the INI database.                *
+ *   CCINIClass::Get_Buildings -- Fetch a building bitfield from the INI database.             *
+ *   CCINIClass::Get_BulletType -- Fetch the bullet identifier from the INI database.          *
+ *   CCINIClass::Get_CrateType -- Fetches a crate type value from the INI database.            *
+ *   CCINIClass::Get_HousesType -- Fetch a house identifier from the INI database.             *
+ *   CCINIClass::Get_Lepton -- Fetches a lepton value from the INI database.                   *
+ *   CCINIClass::Get_MPHType -- Fetches the speed value as a number from 0 to 100.             *
+ *   CCINIClass::Get_OverlayType -- Fetch the overlay identifier from the INI database.        *
+ *   CCINIClass::Get_Owners -- Fetch the owners (list of house bits).                          *
+ *   CCINIClass::Get_SourceType -- Fetch the source (edge) type from the INI database.         *
+ *   CCINIClass::Get_TerrainType -- Fetch the terrain type identifier from the INI database.   *
+ *   CCINIClass::Get_TheaterType -- Fetch the theater type from the INI database.              *
+ *   CCINIClass::Get_ThemeType -- Fetch the theme identifier.                                  *
+ *   CCINIClass::Get_TriggerType -- Fetch the trigger type identifier from the INI database.   *
+ *   CCINIClass::Get_Unique_ID -- Fetch a unique identifier number for the INI file.           *
+ *   CCINIClass::Get_VQType -- Fetch the VQ movie identifier from the INI database.            *
+ *   CCINIClass::Get_VocType -- Fetch a voc (sound effect) from the INI database.              *
+ *   CCINIClass::Get_WarheadType -- Fetch the warhead type from the INI database.              *
+ *   CCINIClass::Get_WeaponType -- Fetches the weapon type from the INI database.              *
+ *   CCINIClass::Invalidate_Message_Digest -- Flag message digest as being invalid.            *
+ *   CCINIClass::Load -- Load the INI database from the data stream specified.                 *
+ *   CCINIClass::Load -- Load the INI database from the file specified.                        *
+ *   CCINIClass::Put_AnimType -- Stores the animation identifier to the INI database.          *
+ *   CCINIClass::Put_ArmorType -- Store the armor type to the INI database.                    *
+ *   CCINIClass::Put_Buildings -- Store a building list to the INI database.                   *
+ *   CCINIClass::Put_BulletType -- Store the projectile identifier into the INI database.      *
+ *   CCINIClass::Put_CrateType -- Stores the crate value in the section and entry specified.   *
+ *   CCINIClass::Put_HousesType -- Store a house identifier to the INI database.               *
+ *   CCINIClass::Put_Lepton -- Stores a lepton value to the INI database.                      *
+ *   CCINIClass::Put_MPHType -- Stores the speed value to the section & entry specified.       *
+ *   CCINIClass::Put_OverlayType -- Store the overlay identifier into the INI database.        *
+ *   CCINIClass::Put_Owners -- Store the house bitfield to the INI database.                   *
+ *   CCINIClass::Put_SourceType -- Store the source (edge) identifier to the INI database.     *
+ *   CCINIClass::Put_TerrainType -- Store the terrain type number to the INI database.         *
+ *   CCINIClass::Put_TheaterType -- Store the theater identifier to the INI database.          *
+ *   CCINIClass::Put_ThemeType -- Store the theme identifier to the INI database.              *
+ *   CCINIClass::Put_TriggerType -- Store the trigger identifier to the INI database.          *
+ *   CCINIClass::Put_VQType -- Store the VQ movie identifier into the INI database.            *
+ *   CCINIClass::Put_VocType -- Store a sound effect identifier into the INI database.         *
+ *   CCINIClass::Put_WarheadType -- Stores the warhead identifier to the INI database.         *
+ *   CCINIClass::Put_WeaponType -- Store the weapon identifier to the INI database.            *
+ *   CCINIClass::Save -- Pipes the INI database to the pipe specified.                         *
+ *   CCINIClass::Save -- Save the INI data to the file specified.                              *
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+
+#include	"function.h"
+
+
+/***********************************************************************************************
+ * CCINIClass::Load -- Load the INI database from the file specified.                          *
+ *                                                                                             *
+ *    This routine will load the database from the file specified in much the same manner      *
+ *    that the INIClass load function works. However, this class will examine the message      *
+ *    digest (if present) and compare it to the actual digest. If they differ, a special       *
+ *    return value is used. This will allow verification of the integrity of the ini data.     *
+ *                                                                                             *
+ * INPUT:   file  -- Reference to the file that will be read from.                             *
+ *                                                                                             *
+ *          withdigest  -- Should a message digest be examined when loaded. If there is a      *
+ *                         mismatch detected, then an error will be returned.                  *
+ *                                                                                             *
+ * OUTPUT:  If the file was not read, returns 0. If the file was read ok, returns 1. If the    *
+ *          file was read ok, but the digest doesn't verify, returns 2.                        *
+ *                                                                                             *
+ * WARNINGS:   If no message digest was present in the INI file, then no verification can      *
+ *             be performed.                                                                   *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *   08/21/1996 JLB : Handles digest control.                                                  *
+ *=============================================================================================*/
+bool CCINIClass::Load(FileClass & file, bool withdigest)
+{
+	return(Load(FileStraw(file), withdigest));
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Load -- Load the INI database from the data stream specified.                   *
+ *                                                                                             *
+ *    This will load the INI database and in the process, it will fetch and verify any         *
+ *    message digest present.                                                                  *
+ *                                                                                             *
+ * INPUT:   straw -- The data stream to fetch the INI data from.                               *
+ *                                                                                             *
+ *          withdigest  -- Should a message digest be examined when loaded. If there is a      *
+ *                         mismatch detected, then an error will be returned.                  *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the database loaded ok? (hack: returns "2" if digest doesn't match).     *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/10/1996 JLB : Created.                                                                 *
+ *   08/21/1996 JLB : Handles message digest control.                                          *
+ *=============================================================================================*/
+bool CCINIClass::Load(Straw & file, bool withdigest)
+{
+	bool ok = INIClass::Load(file);
+
+	Invalidate_Message_Digest();
+	if (ok && withdigest) {
+
+		/*
+		**	If a digest is present, fetch it.
+		*/
+		unsigned char digest[20];
+		int len = Get_UUBlock("Digest", digest, sizeof(digest));
+		if (len > 0) {
+			Clear("Digest");
+
+			/*
+			**	Calculate the message digest for the INI data that was read.
+			*/
+			Calculate_Message_Digest();
+
+			/*
+			**	If the message digests don't match, then return with the special error code.
+			*/
+			if (memcmp(digest, Digest, sizeof(digest)) != 0) {
+				return(2);
+			}
+		}
+	}
+	return(ok);
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Save -- Save the INI data to the file specified.                                *
+ *                                                                                             *
+ *    This routine will save the INI data to the file. It will add a message digest so that    *
+ *    validity check can be performed when the INI data is subsequently read.                  *
+ *                                                                                             *
+ * INPUT:   file  -- Reference to the file to write the INI data to.                           *
+ *                                                                                             *
+ *          withdigest  -- Should a message digest be generated and saved with the INI         *
+ *                         data file?                                                          *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the INI data saved?                                                      *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *   08/21/1996 JLB : Handles message digest control.                                          *
+ *=============================================================================================*/
+int CCINIClass::Save(FileClass & file, bool withdigest) const
+{
+	return(Save(FilePipe(file), withdigest));
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Save -- Pipes the INI database to the pipe specified.                           *
+ *                                                                                             *
+ *    This routine will pipe the INI data to the pipe segment specified. It is functionally    *
+ *    the same as the save operation. A message digest is added to the output data so that     *
+ *    validity check can occur during a subsequent read.                                       *
+ *                                                                                             *
+ * INPUT:   straw -- Reference to the pipe that will receive the output ini data stream.       *
+ *                                                                                             *
+ *          withdigest  -- Should a message digest be generated and saved with the INI         *
+ *                         data file?                                                          *
+ *                                                                                             *
+ * OUTPUT:  Returns with the number of bytes output to the pipe.                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *   08/21/1996 JLB : Handles message digest control.                                          *
+ *=============================================================================================*/
+int CCINIClass::Save(Pipe & pipe, bool withdigest) const
+{
+	if (!withdigest) {
+		return(INIClass::Save(pipe));
+	}
+
+	/*
+	**	Just in case these entries are present, clear them out.
+	*/
+	((CCINIClass *)this)->Clear("Digest");
+
+	/*
+	**	Calculate what the new digest should be.
+	*/
+	((CCINIClass *)this)->Calculate_Message_Digest();
+
+	/*
+	**	Store the actual digest into the INI database.
+	*/
+	((CCINIClass *)this)->Put_UUBlock("Digest", Digest, sizeof(Digest));
+
+	/*
+	**	Output the database to the pipe specified.
+	*/
+	int length = INIClass::Save(pipe);
+
+	/*
+	**	Remove the digest from the database. It shouldn't stick around as if it were real data
+	**	since it isn't really part of the INI database proper.
+	*/
+	((CCINIClass *)this)->Clear("Digest");
+
+	/*
+	**	Finally, return with the total number of bytes send out the pipe.
+	*/
+	return(length);
+}
+
+
+static inline int _Scale_To_256(int val)
+{
+	val = min(val, 100);
+	val = max(val, 0);
+	val = ((val * 256) / 100);
+	val = min(val, 255);
+	return(val);
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Get_Lepton -- Fetches a lepton value from the INI database.                     *
+ *                                                                                             *
+ *    This routine will fetch the lepton value as if it were expressed as cells. Example;      *
+ *    a value of 1 would mean 256 in leptons.                                                  *
+ *                                                                                             *
+ * INPUT:   section  -- The section identifier to look under.                                  *
+ *                                                                                             *
+ *          entry    -- The entry identifier to find.                                          *
+ *                                                                                             *
+ *          defvalue -- The default value to use if the specified section and entry could      *
+ *                      not be located.                                                        *
+ *                                                                                             *
+ * OUTPUT:  Returns with the lepton value of the section & entry specified. If not found, then *
+ *          the default value is returned.                                                     *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+LEPTON CCINIClass::Get_Lepton(char const * section, char const * entry, LEPTON defvalue) const
+{
+	fixed result = Get_Fixed(section, entry, fixed(defvalue, CELL_LEPTON_W));
+	return(result * CELL_LEPTON_W);
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Put_Lepton -- Stores a lepton value to the INI database.                        *
+ *                                                                                             *
+ *    This routine will store the lepton value as if it were expressed in cells. Example;      *
+ *    A lepton of 128 will be stored as ".5".                                                  *
+ *                                                                                             *
+ * INPUT:   section  -- The section identifier to store the value under.                       *
+ *                                                                                             *
+ *          entry    -- The entry to store the lepton value at.                                *
+ *                                                                                             *
+ *          value    -- The lepton value to store.                                             *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the lepton value stored?                                                 *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool CCINIClass::Put_Lepton(char const * section, char const * entry, LEPTON value)
+{
+	return(Put_Fixed(section, entry, fixed(value, CELL_LEPTON_W)));
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Get_MPHType -- Fetches the speed value as a number from 0 to 100.               *
+ *                                                                                             *
+ *    This routine will fetch the speed value as if it were expressed as a number from 0       *
+ *    to 100. The value of 100 would translate into a speed of 256 leptons per game frame.     *
+ *                                                                                             *
+ * INPUT:   section  -- The section identifier to search for the entry under.                  *
+ *                                                                                             *
+ *          entry    -- The entry identifier to find.                                          *
+ *                                                                                             *
+ *          defvalue -- The default speed value to use if the entry could not be located.      *
+ *                                                                                             *
+ * OUTPUT:  Returns with the speed value. If no entry could be found, then the default value   *
+ *          will be returned.                                                                  *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+MPHType CCINIClass::Get_MPHType(char const * section, char const * entry, MPHType defvalue) const
+{
+	int val = Get_Int(section, entry, ((int)defvalue * 100) / 256);
+	return (MPHType(_Scale_To_256(val)));
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Put_MPHType -- Stores the speed value to the section & entry specified.         *
+ *                                                                                             *
+ *    Use this routine to store a speed value into the INI database. The number stored will    *
+ *    be in a 0..100 format. A speed of 256 leptons per tick would be stored as 100.           *
+ *                                                                                             *
+ * INPUT:   section  -- The section identifier to store the entry under.                       *
+ *                                                                                             *
+ *          entry    -- The entry identifier to store the speed value to.                      *
+ *                                                                                             *
+ *          value    -- The speed value to store.                                              *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the speed value stored?                                                  *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool CCINIClass::Put_MPHType(char const * section, char const * entry, MPHType value)
+{
+	return(Put_Int(section, entry, ((int)value * 100) / 256));
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Get_Owners -- Fetch the owners (list of house bits).                            *
+ *                                                                                             *
+ *    Use this to fetch a house bit array value from the INI database. This value will be      *
+ *    various bit positions set (1 << house#) for each house specified in the database.        *
+ *    Houses can be specified in series by the house name separated by commas or by the        *
+ *    special group names of "soviet", and "allies" to cover the houses that are members of    *
+ *    these groups.                                                                            *
+ *                                                                                             *
+ * INPUT:   section  -- The section identifier to search for the entry under.                  *
+ *                                                                                             *
+ *          entry    -- The entry identifier to search for.                                    *
+ *                                                                                             *
+ *          defvalue -- The default house bitfield to use if the entry could not be found.     *
+ *                                                                                             *
+ * OUTPUT:  Returns with the house bitfield value. If the entry could not be found, then the   *
+ *          default value is returned.                                                         *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+long CCINIClass::Get_Owners(char const * section, char const * entry, long defvalue) const
+{
+	char buffer[128];
+	long ownable = defvalue;
+
+	if (Get_String(section, entry, "", buffer, sizeof(buffer))) {
+
+		ownable = 0;
+		char * name = strtok(buffer, ",");
+
+		while (name) {
+			ownable |= Owner_From_Name(name);
+			name = strtok(NULL, ",");
+		}
+	}
+	return(ownable);
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Put_Owners -- Store the house bitfield to the INI database.                     *
+ *                                                                                             *
+ *    Use this routine to store the house bitfield data into the database. The bitfield format *
+ *    matches the format used by the Get_Owners function. Example; if both England and         *
+ *    Spain were specified in the bitfield, the entry would be stored as "England,Spain".      *
+ *                                                                                             *
+ * INPUT:   section  -- The section identifier to store the entry under.                       *
+ *                                                                                             *
+ *          entry    -- The entry identifier that is assigned the value.                       *
+ *                                                                                             *
+ *          value    -- The value to assign to the entry.                                      *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the entry stored in the INI database?                                    *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool CCINIClass::Put_Owners(char const * section, char const * entry, long value)
+{
+	char buffer[128];
+
+	buffer[0] = '\0';
+
+	if ((value & HOUSEF_ALLIES) == HOUSEF_ALLIES) {
+		strcat(buffer, "allies");
+		value &= ~HOUSEF_ALLIES;
+	}
+	if ((value & HOUSEF_SOVIET) == HOUSEF_SOVIET) {
+		if (buffer[0] != '\0') {
+			strcat(buffer, ",");
+		}
+		strcat(buffer, "soviet");
+		value &= ~HOUSEF_SOVIET;
+	}
+
+	for (HousesType house = HOUSE_FIRST; house < HOUSE_COUNT; house++) {
+		if ((value & (1 << house)) != 0) {
+			if (buffer[0] != '\0') {
+				strcat(buffer, ",");
+			}
+			strcat(buffer, HouseTypeClass::As_Reference(house).Name());
+		}
+	}
+
+	if (buffer[0] != '\0') {
+		return(Put_String(section, entry, buffer));
+	}
+	return(true);
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Get_ArmorType -- Fetches the armor type from the INI database.                  *
+ *                                                                                             *
+ *    This routine will fetch the armor type from the database.                                *
+ *                                                                                             *
+ * INPUT:   section  -- Identifier for the section to search for the entry under.              *
+ *                                                                                             *
+ *          entry    -- Th identifier for the entry to search for.                             *
+ *                                                                                             *
+ *          defvalue -- The default value to use if the entry could not be located.            *
+ *                                                                                             *
+ * OUTPUT:  Returns with the armor type specified in the INI database. If it could not be      *
+ *          found, then the default value is returned instead.                                 *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+ArmorType CCINIClass::Get_ArmorType(char const * section, char const * entry, ArmorType defvalue) const
+{
+	char buffer[128];
+
+	Get_String(section, entry, ArmorName[defvalue], buffer, sizeof(buffer));
+	return(Armor_From_Name(buffer));
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Put_ArmorType -- Store the armor type to the INI database.                      *
+ *                                                                                             *
+ *    Use this routine to store the specified armor type to the INI database.                  *
+ *                                                                                             *
+ * INPUT:   section  -- The section identifier to store the entry under.                       *
+ *                                                                                             *
+ *          entry    -- The entry to store the value at.                                       *
+ *                                                                                             *
+ *          value    -- The value to store in the database.                                    *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the entry stored in the database?                                        *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool CCINIClass::Put_ArmorType(char const * section, char const * entry, ArmorType value)
+{
+	return(Put_String(section, entry, ArmorName[value]));
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Get_VocType -- Fetch a voc (sound effect) from the INI database.                *
+ *                                                                                             *
+ *    This routine will fetch a voc number from the database. The voc number will either       *
+ *    be a valid sound effect or VOC_NONE if no match could be found.                          *
+ *                                                                                             *
+ * INPUT:   section  -- Identifier for the section to search for the entry under.              *
+ *                                                                                             *
+ *          entry    -- The entry to search for.                                               *
+ *                                                                                             *
+ *          defvalue -- The default value to return if the entry could not be located.         *
+ *                                                                                             *
+ * OUTPUT:  Returns with the sound effect (VocType) from the INI database. If the entry could  *
+ *          not be located, then the default value is returned.                                *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+VocType CCINIClass::Get_VocType(char const * section, char const * entry, VocType defvalue) const
+{
+	char buffer[128];
+
+	Get_String(section, entry, Voc_Name(defvalue), buffer, sizeof(buffer));
+	return(Voc_From_Name(buffer));
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Put_VocType -- Store a sound effect identifier into the INI database.           *
+ *                                                                                             *
+ *    Use this routine to store a voc identifier (stored a the text name of the sound) into    *
+ *    the INI database.                                                                        *
+ *                                                                                             *
+ * INPUT:   section  -- Identifier for the section to store the entry under.                   *
+ *                                                                                             *
+ *          entry    -- The entry to assign the value to.                                      *
+ *                                                                                             *
+ *          value    -- The sound effect to store to the entry.                                *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the sound effect entry stored?                                           *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool CCINIClass::Put_VocType(char const * section, char const * entry, VocType value)
+{
+	if (value == VOC_NONE) {
+		return(Put_String(section, entry, "<none>"));
+	}
+	return(Put_String(section, entry, Voc_Name(value)));
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Get_AnimType -- Fetch an animation type number from the INI database.           *
+ *                                                                                             *
+ *    This will fetch an AnimType number from the INI database. The anim is stored as a text   *
+ *    name of the art file used for that anim.                                                 *
+ *                                                                                             *
+ * INPUT:   section  -- The section to search for the entry under.                             *
+ *                                                                                             *
+ *          entry    -- The entry to search for.                                               *
+ *                                                                                             *
+ *          defvalue -- The default AnimType to use if the entry could not be located.         *
+ *                                                                                             *
+ * OUTPUT:  Returns with the anim type specified in the database. If it could not be found,    *
+ *          then the default value is returned.                                                *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+AnimType CCINIClass::Get_AnimType(char const * section, char const * entry, AnimType defvalue) const
+{
+	char buffer[128];
+
+	Get_String(section, entry, Anim_Name(defvalue), buffer, sizeof(buffer));
+	return(Anim_From_Name(buffer));
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Put_AnimType -- Stores the animation identifier to the INI database.            *
+ *                                                                                             *
+ *    This routine will store the animation identifier (stored as the text name of the art     *
+ *    file it uses) to the INI database.                                                       *
+ *                                                                                             *
+ * INPUT:   section  -- The section identifier to place the entry under.                       *
+ *                                                                                             *
+ *          entry    -- The entry identifier to assign the animation number to.                *
+ *                                                                                             *
+ *          value    -- The animation identifier to store with the entry.                      *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the animation identifier stored?                                         *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool CCINIClass::Put_AnimType(char const * section, char const * entry, AnimType value)
+{
+	if (value == ANIM_NONE) {
+		return(Put_String(section, entry, "<none>"));
+	}
+	return(Put_String(section, entry, Anim_Name(value)));
+}
+
+
+UnitType CCINIClass::Get_UnitType(char const * section, char const * entry, UnitType defvalue) const
+{
+	char buffer[128];
+
+	char const * def = "<none>";
+	if (defvalue != UNIT_NONE) {
+		def = UnitTypeClass::As_Reference(defvalue).Name();
+	}
+	Get_String(section, entry, def, buffer, sizeof(buffer));
+	return(UnitTypeClass::From_Name(buffer));
+}
+
+
+bool CCINIClass::Put_UnitType(char const * section, char const * entry, UnitType value)
+{
+	if (value == UNIT_NONE) {
+		return(Put_String(section, entry, "<none>"));
+	}
+	return(Put_String(section, entry, UnitTypeClass::As_Reference(value).Name()));
+}
+
+
+
+/***********************************************************************************************
+ * CCINIClass::Get_WeaponType -- Fetches the weapon type from the INI database.                *
+ *                                                                                             *
+ *    This routine will fetch the weapon type from the INI database. The weapon type is        *
+ *    stored as a custom identifier string.                                                    *
+ *                                                                                             *
+ * INPUT:   section  -- The section identifier to search for the entry under.                  *
+ *                                                                                             *
+ *          entry    -- The entry identifier to search for.                                    *
+ *                                                                                             *
+ *          defvalue -- The default weapon value to return if the entry could not be located.  *
+ *                                                                                             *
+ * OUTPUT:  Returns with the weapon type specified by the entry. If the entry could not be     *
+ *          found then the default value is returned.                                          *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+WeaponType CCINIClass::Get_WeaponType(char const * section, char const * entry, WeaponType defvalue) const
+{
+	char buffer[128];
+
+	if (Get_String(section, entry, "", buffer, sizeof(buffer))) {
+		return(Weapon_From_Name(buffer));
+	}
+	return(defvalue);
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Put_WeaponType -- Store the weapon identifier to the INI database.              *
+ *                                                                                             *
+ *    Store the weapon identifier (as custom string name) to the INI database.                 *
+ *                                                                                             *
+ * INPUT:   section  -- Identifier for the section to store the entry under.                   *
+ *                                                                                             *
+ *          entry    -- Identifier to store the weapon identifier with.                        *
+ *                                                                                             *
+ *          value    -- The weapon identifier to store.                                        *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the weapon identifier stored?                                            *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool CCINIClass::Put_WeaponType(char const * section, char const * entry, WeaponType value)
+{
+	if (value == WEAPON_NONE) {
+		return(Put_String(section, entry, "<none>"));
+	}
+	return(Put_String(section, entry, WeaponTypeClass::As_Pointer(value)->Name()));
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Get_WarheadType -- Fetch the warhead type from the INI database.                *
+ *                                                                                             *
+ *    Will fetch the warhead identifier from the INI database.                                 *
+ *                                                                                             *
+ * INPUT:   section  -- The identifier for the section to search for the entry under.          *
+ *                                                                                             *
+ *          entry    -- The entry to search for.                                               *
+ *                                                                                             *
+ *          defvalue -- The default return value to use if the entry could not be located.     *
+ *                                                                                             *
+ * OUTPUT:  Returns with the found warhead type. If the entry could not be found then the      *
+ *          default warhead value is returned.                                                 *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+WarheadType CCINIClass::Get_WarheadType(char const * section, char const * entry, WarheadType defvalue) const
+{
+	char buffer[128];
+
+	if (Get_String(section, entry, "", buffer, sizeof(buffer))) {
+		for (WarheadType wh = WARHEAD_FIRST; wh < WARHEAD_COUNT; wh++) {
+			if (stricmp(WarheadTypeClass::As_Pointer(wh)->Name(), buffer) == 0) {
+				return(wh);
+			}
+		}
+	}
+	return(defvalue);
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Put_WarheadType -- Stores the warhead identifier to the INI database.           *
+ *                                                                                             *
+ *    This will store the weapon identifier specified to the INI database.                     *
+ *                                                                                             *
+ * INPUT:   section  -- The section identifier to store the entry under.                       *
+ *                                                                                             *
+ *          entry    -- The entry to store the warhead identifier.                             *
+ *                                                                                             *
+ *          value    -- The warhead identifier to store.                                       *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the warhead identifier stored to the database?                           *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool CCINIClass::Put_WarheadType(char const * section, char const * entry, WarheadType value)
+{
+	if (value == WARHEAD_NONE) {
+		return(Put_String(section, entry, "<none>"));
+	}
+	return(Put_String(section, entry, WarheadTypeClass::As_Pointer(value)->Name()));
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Get_OverlayType -- Fetch the overlay identifier from the INI database.          *
+ *                                                                                             *
+ *    This routine will fetch the overlay identifier from the database.                        *
+ *                                                                                             *
+ * INPUT:   section  -- Identifier for the section to search for the entry under.              *
+ *                                                                                             *
+ *          entry    -- The entry to search for.                                               *
+ *                                                                                             *
+ *          defvalue -- The default value to use if the entry could not be located.            *
+ *                                                                                             *
+ * OUTPUT:  Returns with the overlay identifier found. If it could not be found, then the      *
+ *          default value is returned.                                                         *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+OverlayType CCINIClass::Get_OverlayType(char const * section, char const * entry, OverlayType defvalue) const
+{
+	char buffer[128];
+
+	if (Get_String(section, entry, "", buffer, sizeof(buffer))) {
+		return(OverlayTypeClass::From_Name(buffer));
+	}
+	return(defvalue);
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Put_OverlayType -- Store the overlay identifier into the INI database.          *
+ *                                                                                             *
+ *    Use this routine to store the overlay identifier into the INI database.                  *
+ *                                                                                             *
+ * INPUT:   section  -- Identifier for to search for the entry under.                          *
+ *                                                                                             *
+ *          entry    -- The entry to search for.                                               *
+ *                                                                                             *
+ *          value    -- The overlay type value to store with the entry.                        *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the overlay value stored?                                                *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool CCINIClass::Put_OverlayType(char const * section, char const * entry, OverlayType value)
+{
+	assert(value != OVERLAY_NONE);
+	return(Put_String(section, entry, OverlayTypeClass::As_Reference(value).Name()));
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Get_BulletType -- Fetch the bullet identifier from the INI database.            *
+ *                                                                                             *
+ *    Use this routine to fetch the bullet type identifier from the INI database.              *
+ *                                                                                             *
+ * INPUT:   section  -- The section identifier to search for the entry under.                  *
+ *                                                                                             *
+ *          entry    -- The entry to search for.                                               *
+ *                                                                                             *
+ *          defvalue -- The default bullet type value to return if the entry could not be      *
+ *                      located.                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the bullet type identifier found. If the entry could not be found     *
+ *          then the default value is returned.                                                *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+BulletType CCINIClass::Get_BulletType(char const * section, char const * entry, BulletType defvalue) const
+{
+	char buffer[128];
+
+	if (Get_String(section, entry, "", buffer, sizeof(buffer))) {
+		for (BulletType proj = BULLET_FIRST; proj < BULLET_COUNT; proj++) {
+			if (stricmp(BulletTypeClass::As_Reference(proj).Name(), buffer) == 0) {
+//			if (stricmp(ProjectileNames[proj], buffer) == 0) {
+				return(proj);
+			}
+		}
+	}
+	return(defvalue);
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Put_BulletType -- Store the projectile identifier into the INI database.        *
+ *                                                                                             *
+ *    This routine will store the projectile name (as the identifier) to the INI database.     *
+ *                                                                                             *
+ * INPUT:   section  -- The section to store the entry under.                                  *
+ *                                                                                             *
+ *          entry    -- The entry identifier to store the projectile value with.               *
+ *                                                                                             *
+ *          value    -- The projectile identifier to store.                                    *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the projectile identifier stored?                                        *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool CCINIClass::Put_BulletType(char const * section, char const * entry, BulletType value)
+{
+	if (value == BULLET_NONE) {
+		return(Put_String(section, entry, "<none>"));
+	}
+	return(Put_String(section, entry, BulletTypeClass::As_Reference(value).Name()));
+//	return(Put_String(section, entry, ProjectileNames[value]));
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Get_HousesType -- Fetch a house identifier from the INI database.               *
+ *                                                                                             *
+ *    Use this routine to fetch an individual house identifier from the INI database. This is  *
+ *    somewhat similar to the Get_Owners function but is limited to a single house.            *
+ *                                                                                             *
+ * INPUT:   section  -- Identifier for the section to search for the entry under.              *
+ *                                                                                             *
+ *          entry    -- Identifier for the entry to search for.                                *
+ *                                                                                             *
+ *          defvalue -- The default value to use if the entry could not be located.            *
+ *                                                                                             *
+ * OUTPUT:  Returns with the house identifier if it was found. If not found, then the default  *
+ *          value is returned.                                                                 *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+HousesType CCINIClass::Get_HousesType(char const * section, char const * entry, HousesType defvalue) const
+{
+	char buffer[128];
+
+	if (Get_String(section, entry, "", buffer, sizeof(buffer))) {
+		return(HouseTypeClass::From_Name(buffer));
+	}
+	return(defvalue);
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Put_HousesType -- Store a house identifier to the INI database.                 *
+ *                                                                                             *
+ *    Use this routine to store the specified house identifier to the INI database.            *
+ *                                                                                             *
+ * INPUT:   section  -- The section to store the entry under.                                  *
+ *                                                                                             *
+ *          entry    -- Identifier for the entry to search for.                                *
+ *                                                                                             *
+ *          value    -- The house identifier to store in the database.                         *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the house identifier stored?                                             *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool CCINIClass::Put_HousesType(char const * section, char const * entry, HousesType value)
+{
+	return(Put_String(section, entry, HouseTypeClass::As_Reference(value).Name()));
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Get_VQType -- Fetch the VQ movie identifier from the INI database.              *
+ *                                                                                             *
+ *    Fetches the VQ movie name (identifier) from the INI database.                            *
+ *                                                                                             *
+ * INPUT:   section  -- Identifier for the section to search for the entry under.              *
+ *                                                                                             *
+ *          entry    -- Identifier for the entry to search for.                                *
+ *                                                                                             *
+ *          defvalue -- The default value to use if the entry could not be located.            *
+ *                                                                                             *
+ * OUTPUT:  Returns with the VQ movie identifier found. If the entry could not be located,     *
+ *          then the default value is returned.                                                *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+VQType CCINIClass::Get_VQType(char const * section, char const * entry, VQType defvalue) const
+{
+	char buffer[128];
+
+	if (Get_String(section, entry, "", buffer, sizeof(buffer))) {
+		for (VQType vq = VQ_FIRST; vq < VQ_COUNT; vq++) {
+			if (stricmp(buffer, VQName[vq]) == 0) {
+				return(vq);
+			}
+		}
+	}
+	return(defvalue);
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Put_VQType -- Store the VQ movie identifier into the INI database.              *
+ *                                                                                             *
+ *    Use this routine to store the VQ movie identifier into the INI database.                 *
+ *                                                                                             *
+ * INPUT:   section  -- The section to store the entry under.                                  *
+ *                                                                                             *
+ *          entry    -- Identifier for the entry to store.                                     *
+ *                                                                                             *
+ *          value    -- The VQ movie identifier to store to the INI database.                  *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the VQ identifier stored?                                                *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool CCINIClass::Put_VQType(char const * section, char const * entry, VQType value)
+{
+	if (value == VQ_NONE) {
+		return(Put_String(section, entry, "<none>"));
+	}
+	return(Put_String(section, entry, VQName[value]));
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Get_TheaterType -- Fetch the theater type from the INI database.                *
+ *                                                                                             *
+ *    This will fetch the theater identifier from the INI database.                            *
+ *                                                                                             *
+ * INPUT:   section  -- Identifier for the section to search for the entry under.              *
+ *                                                                                             *
+ *          entry    -- Identifier for the entry to search for.                                *
+ *                                                                                             *
+ *          defvalue -- The default value to use if the entry could not be located.            *
+ *                                                                                             *
+ * OUTPUT:  Returns with the theater type found. If the entry could not be found, then the     *
+ *          default value is returned.                                                         *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+TheaterType CCINIClass::Get_TheaterType(char const * section, char const * entry, TheaterType defvalue) const
+{
+	char buffer[128];
+
+	if (Get_String(section, entry, "", buffer, sizeof(buffer))) {
+		return(Theater_From_Name(buffer));
+	}
+	return(defvalue);
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Put_TheaterType -- Store the theater identifier to the INI database.            *
+ *                                                                                             *
+ *    Use this routine to store the theater name to the INI database.                          *
+ *                                                                                             *
+ * INPUT:   section  -- The section to store the entry under.                                  *
+ *                                                                                             *
+ *          entry    -- Identifier for the entry to store.                                     *
+ *                                                                                             *
+ *          value    -- The theater identifier to store.                                       *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the theater identifier stored?                                           *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool CCINIClass::Put_TheaterType(char const * section, char const * entry, TheaterType value)
+{
+	return(Put_String(section, entry, Theaters[value].Name));
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Get_TriggerType -- Fetch the trigger type identifier from the INI database.     *
+ *                                                                                             *
+ *    This routine will fetch the trigger type identifier from the INI database.               *
+ *                                                                                             *
+ * INPUT:   section  -- The section to search for the entry under.                             *
+ *                                                                                             *
+ *          entry    -- Identifier of the entry to search for.                                 *
+ *                                                                                             *
+ * OUTPUT:  Returns with the trigger type pointer if a match was found. No match found will    *
+ *          return a NULL.                                                                     *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+TriggerTypeClass * CCINIClass::Get_TriggerType(char const * section, char const * entry) const
+{
+	char buffer[128];
+
+	if (Get_String(section, entry, "", buffer, sizeof(buffer))) {
+		return(TriggerTypeClass::From_Name(buffer));
+	}
+	return(NULL);
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Put_TriggerType -- Store the trigger identifier to the INI database.            *
+ *                                                                                             *
+ *    This routine will store the trigger (as its name) to the INI database.                   *
+ *                                                                                             *
+ * INPUT:   section  -- The section to store the entry under.                                  *
+ *                                                                                             *
+ *          entry    -- The entry name to store the trigger identifier to.                     *
+ *                                                                                             *
+ *          value    -- The trigger type to store. The trigger name will be stored.            *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the trigger name stored?                                                 *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool CCINIClass::Put_TriggerType(char const * section, char const * entry, TriggerTypeClass * value)
+{
+	return(Put_String(section, entry, value->Name()));
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Get_ThemeType -- Fetch the theme identifier.                                    *
+ *                                                                                             *
+ *    This routine will fetch the theme identifier from the INI database.                      *
+ *                                                                                             *
+ * INPUT:   section  -- The section to search for the entry under.                             *
+ *                                                                                             *
+ *          entry    -- Identifier of the entry to search for.                                 *
+ *                                                                                             *
+ *          defvalue -- The default theme identifier to return if the entry could not be found.*
+ *                                                                                             *
+ * OUTPUT:  Returns with the theme identifier if it was found. If not found, then the default  *
+ *          value is returned instead.                                                         *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+ThemeType CCINIClass::Get_ThemeType(char const * section, char const * entry, ThemeType defvalue) const
+{
+	char buffer[128];
+
+	if (Get_String(section, entry, "", buffer, sizeof(buffer))) {
+		return(Theme.From_Name(buffer));
+	}
+	return(defvalue);
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Put_ThemeType -- Store the theme identifier to the INI database.                *
+ *                                                                                             *
+ *    This routine will store the specified theme identifier to the INI database.              *
+ *                                                                                             *
+ * INPUT:   section  -- Identifier for the section to store the entry under.                   *
+ *                                                                                             *
+ *          entry    -- Identifier for the entry to store the value to.                        *
+ *                                                                                             *
+ *          value    -- The theme identifier to store.                                         *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the theme identifier stored.                                             *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool CCINIClass::Put_ThemeType(char const * section, char const * entry, ThemeType value)
+{
+	return(Put_String(section, entry, Theme.Base_Name(value)));
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Get_SourceType -- Fetch the source (edge) type from the INI database.           *
+ *                                                                                             *
+ *    This routine will fetch the source (reinforcement edge) identifier from the INI          *
+ *    database.                                                                                *
+ *                                                                                             *
+ * INPUT:   section  -- Identifier for the section that the entry will be searched under.      *
+ *                                                                                             *
+ *          entry    -- Identifier for the entry that will be searched for.                    *
+ *                                                                                             *
+ *          defvalue -- The default value to return if the entry could not be located.         *
+ *                                                                                             *
+ * OUTPUT:  Returns with the source type of the entry if found. If not found, then the         *
+ *          default value is returned.                                                         *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+SourceType CCINIClass::Get_SourceType(char const * section, char const * entry, SourceType defvalue) const
+{
+	char buffer[128];
+
+	if (Get_String(section, entry, "", buffer, sizeof(buffer))) {
+		return(Source_From_Name(buffer));
+	}
+	return(defvalue);
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Put_SourceType -- Store the source (edge) identifier to the INI database.       *
+ *                                                                                             *
+ *    This will store the source type (reinforcement edge) to the INI database.                *
+ *                                                                                             *
+ * INPUT:   section  -- The section to store the entry under.                                  *
+ *                                                                                             *
+ *          entry    -- Identifier of the entry to store the source identifier to.             *
+ *                                                                                             *
+ *          value    -- The source (edge) value to store.                                      *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the source identifier stored?                                            *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool CCINIClass::Put_SourceType(char const * section, char const * entry, SourceType value)
+{
+	return(Put_String(section, entry, SourceName[value]));
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Get_CrateType -- Fetches a crate type value from the INI database.              *
+ *                                                                                             *
+ *    This will return with the crate type specified in the INI database.                      *
+ *                                                                                             *
+ * INPUT:   section  -- Identifier for the section to search under.                            *
+ *                                                                                             *
+ *          entry    -- The entry to find the matching crate value for.                        *
+ *                                                                                             *
+ *          defvalue -- The default crate value to return if the entry could not be found.     *
+ *                                                                                             *
+ * OUTPUT:  Returns with the crate type identified with the specified entry. If the entry      *
+ *          could not be located, then the default value is returned.                          *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/08/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+CrateType CCINIClass::Get_CrateType(char const * section, char const * entry, CrateType defvalue) const
+{
+	char buffer[128];
+
+	if (Get_String(section, entry, "", buffer, sizeof(buffer))) {
+		return(Crate_From_Name(buffer));
+	}
+	return(defvalue);
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Put_CrateType -- Stores the crate value in the section and entry specified.     *
+ *                                                                                             *
+ *    This will store the specified crate value to the section and entry specified.            *
+ *                                                                                             *
+ * INPUT:   section  -- The section identifier to store the entry under.                       *
+ *                                                                                             *
+ *          entry    -- The entry identifier to store the crate value with.                    *
+ *                                                                                             *
+ *          value    -- The crate value to store.                                              *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the crate value stored to the INI database?                              *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/08/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool CCINIClass::Put_CrateType(char const * section, char const * entry, CrateType value)
+{
+	return(Put_String(section, entry, CrateNames[value]));
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Get_TerrainType -- Fetch the terrain type identifier from the INI database.     *
+ *                                                                                             *
+ *    Fetches the terrain type number from the INI database.                                   *
+ *                                                                                             *
+ * INPUT:   section  -- The section to search for the entry under.                             *
+ *                                                                                             *
+ *          entry    -- Identifier for the entry to search for.                                *
+ *                                                                                             *
+ *          defvalue -- The default value to use if the entry could not be located.            *
+ *                                                                                             *
+ * OUTPUT:  Returns with the terrain type if found. If the entry wasn't found, then the        *
+ *          default value will be returned.                                                    *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+TerrainType CCINIClass::Get_TerrainType(char const * section, char const * entry, TerrainType defvalue) const
+{
+	char buffer[128];
+
+	if (Get_String(section, entry, "", buffer, sizeof(buffer))) {
+		return(TerrainTypeClass::From_Name(strtok(buffer, ",")));
+	}
+	return(defvalue);
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Put_TerrainType -- Store the terrain type number to the INI database.           *
+ *                                                                                             *
+ *    This will store the terrain type identifier to the INI database.                         *
+ *                                                                                             *
+ * INPUT:   section  -- The section to store the entry under.                                  *
+ *                                                                                             *
+ *          entry    -- Identifier that the terrain number will be stored to.                  *
+ *                                                                                             *
+ *          value    -- The terrain type identifier to store.                                  *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the terrain identifier stored?                                           *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool CCINIClass::Put_TerrainType(char const * section, char const * entry, TerrainType value)
+{
+	return(Put_String(section, entry, TerrainTypeClass::As_Reference(value).Name()));
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Get_Buildings -- Fetch a building bitfield from the INI database.               *
+ *                                                                                             *
+ *    This routing will fetch the a list of buildings from the INI database. The buildings     *
+ *    are expressed as a comma separated list of building identifiers. The return value is     *
+ *    a composite of bits that represent these buildings -- one bit per building type.         *
+ *                                                                                             *
+ * INPUT:   section  -- The section to search for the entry under.                             *
+ *                                                                                             *
+ *          entry    -- The entry to fetch the building list from.                             *
+ *                                                                                             *
+ *          defvalue -- The default value to return if the section and entry could not be      *
+ *                      located.                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the building list (as a bitfield). If the entry could not be          *
+ *          found, the the default value is returned instead.                                  *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/11/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+long CCINIClass::Get_Buildings(char const * section, char const * entry, long defvalue) const
+{
+	char buffer[128];
+	long pre;
+
+	if (Get_String(section, entry, "", buffer, sizeof(buffer))) {
+
+		pre = 0;
+		char * token = strtok(buffer, ",");
+		while (token != NULL && *token != '\0') {
+			StructType building = BuildingTypeClass::From_Name(token);
+			if (building != STRUCT_NONE) {
+				pre |= (1L << building);
+			}
+			token = strtok(NULL, ",");
+		}
+	} else {
+		pre = defvalue;
+	}
+
+	return(pre);
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Put_Buildings -- Store a building list to the INI database.                     *
+ *                                                                                             *
+ *    This will store a list of buildings to the INI database. The buildings are listed by     *
+ *    their identifier names separated by commas.                                              *
+ *                                                                                             *
+ * INPUT:   section  -- The identifier for the section to store the entry under.               *
+ *                                                                                             *
+ *          entry    -- The entry to store the building list to.                               *
+ *                                                                                             *
+ *          value    -- A list of buildings (in the form of a bit field -- one bit per         *
+ *                      building type).                                                        *
+ *                                                                                             *
+ * OUTPUT:  Was the building list stored to the INI file?                                      *
+ *                                                                                             *
+ * WARNINGS:   This is limited to the buildings that can be expressed in a bitfield long.      *
+ *             Which means, there can be only a maximum of 32 building types listed and        *
+ *             even then, the total line length generated must not exceed 128 bytes.           *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/11/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool CCINIClass::Put_Buildings(char const * section, char const * entry, long value)
+{
+	char buffer[128] = "";
+	int maxi = (32 < STRUCT_COUNT) ? 32 : STRUCT_COUNT;
+
+	for (StructType index = STRUCT_FIRST; index < maxi; index++) {
+		if ((value & (1L << index)) != 0) {
+
+			if (buffer[0] != '\0') {
+				strcat(buffer, ",");
+			}
+			strcat(buffer, BuildingTypeClass::As_Reference(index).IniName);
+		}
+	}
+
+	return(Put_String(section, entry, buffer));
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Get_Unique_ID -- Fetch a unique identifier number for the INI file.             *
+ *                                                                                             *
+ *    This is a shorthand version of the message digest. It calculates the ID number from the  *
+ *    message digest itself.                                                                   *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with a 32 bit unique identifier number for the INI database.               *
+ *                                                                                             *
+ * WARNINGS:   Since the return value is only 32 bits, it is much less secure than the         *
+ *             complete message digest.                                                        *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   11/01/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+int CCINIClass::Get_Unique_ID(void) const
+{
+	if (!IsDigestPresent) {
+		((CCINIClass *)this)->Calculate_Message_Digest();
+	}
+
+	return(CRCEngine()(&Digest[0], sizeof(Digest)));
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Calculate_Message_Digest -- Calculate a message digest for the current database *
+ *                                                                                             *
+ *    This will calculate a new message digest according to the current state of the INI       *
+ *    database.                                                                                *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   If the database is changed in any fashion, this message digest will be rendered *
+ *             obsolete.                                                                       *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   11/01/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void CCINIClass::Calculate_Message_Digest(void)
+{
+	/*
+	**	Calculate the message digest for the INI data that was read.
+	*/
+	SHAPipe sha;
+	INIClass::Save(sha);
+	sha.Result(Digest);
+	IsDigestPresent = true;
+}
+
+
+/***********************************************************************************************
+ * CCINIClass::Invalidate_Message_Digest -- Flag message digest as being invalid.              *
+ *                                                                                             *
+ *    This flags the message digest as being invalid so that it will be recalculated when      *
+ *    needed.                                                                                  *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   11/01/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void CCINIClass::Invalidate_Message_Digest(void)
+{
+	IsDigestPresent = false;
+}

+ 120 - 0
CODE/CCINI.H

@@ -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 - 0
CODE/CCMPATH.CPP

@@ -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 - 0
CODE/CCPTR.CPP

@@ -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 - 0
CODE/CCPTR.H

@@ -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 - 0
CODE/CCTEN.CPP

@@ -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 - 0
CODE/CC_ICON.RC

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

+ 1 - 0
CODE/CC_ICON.RH

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

+ 3324 - 0
CODE/CDATA.CPP

@@ -0,0 +1,3324 @@
+/*
+**	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/CDATA.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 : CDATA.CPP                                                    *
+ *                                                                                             *
+ *                   Programmer : Joe L. Bostic                                                *
+ *                                                                                             *
+ *                   Start Date : May 16, 1994                                                 *
+ *                                                                                             *
+ *                  Last Update : July 6, 1996 [JLB]                                           *
+ *                                                                                             *
+ *---------------------------------------------------------------------------------------------*
+ * Functions:                                                                                  *
+ *   TemplateTypeClass::As_Reference -- Fetches a reference to the template specified.         *
+ *   TemplateTypeClass::Create_And_Place -- Creates and places a template object on the map.   *
+ *   TemplateTypeClass::Create_One_Of -- Creates an object of this template type.              *
+ *   TemplateTypeClass::Display -- Displays a generic representation of template.              *
+ *   TemplateTypeClass::From_Name -- Determine template from ASCII name.                       *
+ *   TemplateTypeClass::Init -- Loads graphic data for templates.                              *
+ *   TemplateTypeClass::Land_Type -- Determines land type from template and icon number.       *
+ *   TemplateTypeClass::Occupy_List -- Determines occupation list.                             *
+ *   TemplateTypeClass::One_Time -- Performs one-time initialization                           *
+ *   TemplateTypeClass::Prep_For_Add -- Prepares to add template to scenario.                  *
+ *   TemplateTypeClass::TemplateTypeClass -- Constructor for template type objects.            *
+ *   TemplateTypeClass::operator delete -- Deletes a template type object.                     *
+ *   TemplateTypeClass::operator new -- Allocates a template type from special heap.           *
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+#include	"function.h"
+
+
+static TemplateTypeClass const Empty(
+	TEMPLATE_CLEAR1,
+	THEATERF_TEMPERATE|THEATERF_SNOW|THEATERF_INTERIOR,
+	"CLEAR1",
+	TXT_CLEAR
+);
+static TemplateTypeClass const Clear(
+	TEMPLATE_CLEAR1,
+	THEATERF_TEMPERATE|THEATERF_SNOW|THEATERF_INTERIOR,
+	"CLEAR1",
+	TXT_CLEAR
+);
+static TemplateTypeClass const Road01(
+	TEMPLATE_ROAD01,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D01",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road02(
+	TEMPLATE_ROAD02,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D02",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road03(
+	TEMPLATE_ROAD03,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D03",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road04(
+	TEMPLATE_ROAD04,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D04",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road05(
+	TEMPLATE_ROAD05,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D05",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road06(
+	TEMPLATE_ROAD06,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D06",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road07(
+	TEMPLATE_ROAD07,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D07",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road08(
+	TEMPLATE_ROAD08,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D08",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road09(
+	TEMPLATE_ROAD09,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D09",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road10(
+	TEMPLATE_ROAD10,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D10",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road11(
+	TEMPLATE_ROAD11,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D11",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road12(
+	TEMPLATE_ROAD12,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D12",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road13(
+	TEMPLATE_ROAD13,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D13",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road14(
+	TEMPLATE_ROAD14,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D14",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road15(
+	TEMPLATE_ROAD15,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D15",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road16(
+	TEMPLATE_ROAD16,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D16",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road17(
+	TEMPLATE_ROAD17,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D17",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road18(
+	TEMPLATE_ROAD18,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D18",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road19(
+	TEMPLATE_ROAD19,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D19",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road20(
+	TEMPLATE_ROAD20,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D20",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road21(
+	TEMPLATE_ROAD21,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D21",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road22(
+	TEMPLATE_ROAD22,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D22",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road23(
+	TEMPLATE_ROAD23,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D23",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road24(
+	TEMPLATE_ROAD24,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D24",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road25(
+	TEMPLATE_ROAD25,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D25",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road26(
+	TEMPLATE_ROAD26,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D26",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road27(
+	TEMPLATE_ROAD27,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D27",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road28(
+	TEMPLATE_ROAD28,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D28",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road29(
+	TEMPLATE_ROAD29,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D29",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road30(
+	TEMPLATE_ROAD30,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D30",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road31(
+	TEMPLATE_ROAD31,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D31",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road32(
+	TEMPLATE_ROAD32,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D32",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road33(
+	TEMPLATE_ROAD33,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D33",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road34(
+	TEMPLATE_ROAD34,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D34",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road35(
+	TEMPLATE_ROAD35,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D35",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road36(
+	TEMPLATE_ROAD36,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D36",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road37(
+	TEMPLATE_ROAD37,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D37",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road38(
+	TEMPLATE_ROAD38,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D38",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road39(
+	TEMPLATE_ROAD39,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D39",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road40(
+	TEMPLATE_ROAD40,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D40",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road41(
+	TEMPLATE_ROAD41,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D41",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road42(
+	TEMPLATE_ROAD42,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D42",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road43(
+	TEMPLATE_ROAD43,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D43",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road44(
+	TEMPLATE_ROAD44,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D44",
+	TXT_ROAD
+);
+static TemplateTypeClass const Road45(
+	TEMPLATE_ROAD45,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"D45",
+	TXT_ROAD
+);
+static TemplateTypeClass const Water(
+	TEMPLATE_WATER,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"W1",
+	TXT_WATER
+);
+static TemplateTypeClass const Water2(
+	TEMPLATE_WATER2,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"W2",
+	TXT_WATER
+);
+static TemplateTypeClass const Shore01(
+	TEMPLATE_SHORE01,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH01",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore02(
+	TEMPLATE_SHORE02,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH02",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore03(
+	TEMPLATE_SHORE03,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH03",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore04(
+	TEMPLATE_SHORE04,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH04",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore05(
+	TEMPLATE_SHORE05,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH05",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore06(
+	TEMPLATE_SHORE06,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH06",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore07(
+	TEMPLATE_SHORE07,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH07",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore08(
+	TEMPLATE_SHORE08,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH08",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore09(
+	TEMPLATE_SHORE09,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH09",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore10(
+	TEMPLATE_SHORE10,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH10",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore11(
+	TEMPLATE_SHORE11,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH11",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore12(
+	TEMPLATE_SHORE12,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH12",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore13(
+	TEMPLATE_SHORE13,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH13",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore14(
+	TEMPLATE_SHORE14,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH14",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore15(
+	TEMPLATE_SHORE15,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH15",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore16(
+	TEMPLATE_SHORE16,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH16",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore17(
+	TEMPLATE_SHORE17,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH17",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore18(
+	TEMPLATE_SHORE18,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH18",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore19(
+	TEMPLATE_SHORE19,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH19",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore20(
+	TEMPLATE_SHORE20,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH20",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore21(
+	TEMPLATE_SHORE21,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH21",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore22(
+	TEMPLATE_SHORE22,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH22",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore23(
+	TEMPLATE_SHORE23,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH23",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore24(
+	TEMPLATE_SHORE24,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH24",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore25(
+	TEMPLATE_SHORE25,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH25",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore26(
+	TEMPLATE_SHORE26,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH26",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore27(
+	TEMPLATE_SHORE27,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH27",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore28(
+	TEMPLATE_SHORE28,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH28",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore29(
+	TEMPLATE_SHORE29,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH29",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore30(
+	TEMPLATE_SHORE30,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH30",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore31(
+	TEMPLATE_SHORE31,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH31",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore32(
+	TEMPLATE_SHORE32,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH32",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore33(
+	TEMPLATE_SHORE33,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH33",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore34(
+	TEMPLATE_SHORE34,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH34",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore35(
+	TEMPLATE_SHORE35,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH35",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore36(
+	TEMPLATE_SHORE36,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH36",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore37(
+	TEMPLATE_SHORE37,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH37",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore38(
+	TEMPLATE_SHORE38,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH38",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore39(
+	TEMPLATE_SHORE39,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH39",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore40(
+	TEMPLATE_SHORE40,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH40",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore41(
+	TEMPLATE_SHORE41,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH41",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore42(
+	TEMPLATE_SHORE42,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH42",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore43(
+	TEMPLATE_SHORE43,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH43",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore44(
+	TEMPLATE_SHORE44,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH44",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore45(
+	TEMPLATE_SHORE45,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH45",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore46(
+	TEMPLATE_SHORE46,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH46",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore47(
+	TEMPLATE_SHORE47,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH47",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore48(
+	TEMPLATE_SHORE48,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH48",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore49(
+	TEMPLATE_SHORE49,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH49",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore50(
+	TEMPLATE_SHORE50,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH50",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore51(
+	TEMPLATE_SHORE51,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH51",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore52(
+	TEMPLATE_SHORE52,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH52",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore53(
+	TEMPLATE_SHORE53,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH53",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore54(
+	TEMPLATE_SHORE54,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH54",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore55(
+	TEMPLATE_SHORE55,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH55",
+	TXT_SHORE
+);
+static TemplateTypeClass const Shore56(
+	TEMPLATE_SHORE56,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"SH56",
+	TXT_SHORE
+);
+static TemplateTypeClass const Boulder1(
+	TEMPLATE_BOULDER1,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"B1",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Boulder2(
+	TEMPLATE_BOULDER2,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"B2",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Boulder3(
+	TEMPLATE_BOULDER3,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"B3",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Boulder4(
+	TEMPLATE_BOULDER4,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"B4",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Boulder5(
+	TEMPLATE_BOULDER5,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"B5",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Boulder6(
+	TEMPLATE_BOULDER6,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"B6",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope01(
+	TEMPLATE_SLOPE01,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S01",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope02(
+	TEMPLATE_SLOPE02,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S02",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope03(
+	TEMPLATE_SLOPE03,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S03",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope04(
+	TEMPLATE_SLOPE04,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S04",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope05(
+	TEMPLATE_SLOPE05,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S05",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope06(
+	TEMPLATE_SLOPE06,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S06",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope07(
+	TEMPLATE_SLOPE07,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S07",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope08(
+	TEMPLATE_SLOPE08,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S08",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope09(
+	TEMPLATE_SLOPE09,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S09",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope10(
+	TEMPLATE_SLOPE10,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S10",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope11(
+	TEMPLATE_SLOPE11,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S11",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope12(
+	TEMPLATE_SLOPE12,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S12",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope13(
+	TEMPLATE_SLOPE13,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S13",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope14(
+	TEMPLATE_SLOPE14,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S14",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope15(
+	TEMPLATE_SLOPE15,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S15",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope16(
+	TEMPLATE_SLOPE16,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S16",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope17(
+	TEMPLATE_SLOPE17,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S17",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope18(
+	TEMPLATE_SLOPE18,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S18",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope19(
+	TEMPLATE_SLOPE19,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S19",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope20(
+	TEMPLATE_SLOPE20,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S20",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope21(
+	TEMPLATE_SLOPE21,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S21",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope22(
+	TEMPLATE_SLOPE22,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S22",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope23(
+	TEMPLATE_SLOPE23,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S23",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope24(
+	TEMPLATE_SLOPE24,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S24",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope25(
+	TEMPLATE_SLOPE25,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S25",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope26(
+	TEMPLATE_SLOPE26,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S26",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope27(
+	TEMPLATE_SLOPE27,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S27",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope28(
+	TEMPLATE_SLOPE28,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S28",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope29(
+	TEMPLATE_SLOPE29,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S29",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope30(
+	TEMPLATE_SLOPE30,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S30",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope31(
+	TEMPLATE_SLOPE31,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S31",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope32(
+	TEMPLATE_SLOPE32,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S32",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope33(
+	TEMPLATE_SLOPE33,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S33",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope34(
+	TEMPLATE_SLOPE34,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S34",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope35(
+	TEMPLATE_SLOPE35,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S35",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope36(
+	TEMPLATE_SLOPE36,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S36",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope37(
+	TEMPLATE_SLOPE37,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S37",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Slope38(
+	TEMPLATE_SLOPE38,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"S38",
+	TXT_SLOPE
+);
+static TemplateTypeClass const Patch01(
+	TEMPLATE_PATCH01,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"P01",
+	TXT_PATCH
+);
+static TemplateTypeClass const Patch02(
+	TEMPLATE_PATCH02,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"P02",
+	TXT_PATCH
+);
+static TemplateTypeClass const Patch03(
+	TEMPLATE_PATCH03,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"P03",
+	TXT_PATCH
+);
+static TemplateTypeClass const Patch04(
+	TEMPLATE_PATCH04,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"P04",
+	TXT_PATCH
+);
+static TemplateTypeClass const Patch07(
+	TEMPLATE_PATCH07,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"P07",
+	TXT_PATCH
+);
+static TemplateTypeClass const Patch08(
+	TEMPLATE_PATCH08,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"P08",
+	TXT_PATCH
+);
+static TemplateTypeClass const Patch13(
+	TEMPLATE_PATCH13,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"P13",
+	TXT_PATCH
+);
+static TemplateTypeClass const Patch14(
+	TEMPLATE_PATCH14,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"P14",
+	TXT_PATCH
+);
+static TemplateTypeClass const Patch15(
+	TEMPLATE_PATCH15,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"P15",
+	TXT_PATCH
+);
+static TemplateTypeClass const River01(
+	TEMPLATE_RIVER01,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RV01",
+	TXT_RIVER
+);
+static TemplateTypeClass const River02(
+	TEMPLATE_RIVER02,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RV02",
+	TXT_RIVER
+);
+static TemplateTypeClass const River03(
+	TEMPLATE_RIVER03,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RV03",
+	TXT_RIVER
+);
+static TemplateTypeClass const River04(
+	TEMPLATE_RIVER04,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RV04",
+	TXT_RIVER
+);
+static TemplateTypeClass const River05(
+	TEMPLATE_RIVER05,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RV05",
+	TXT_RIVER
+);
+static TemplateTypeClass const River06(
+	TEMPLATE_RIVER06,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RV06",
+	TXT_RIVER
+);
+static TemplateTypeClass const River07(
+	TEMPLATE_RIVER07,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RV07",
+	TXT_RIVER
+);
+static TemplateTypeClass const River08(
+	TEMPLATE_RIVER08,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RV08",
+	TXT_RIVER
+);
+static TemplateTypeClass const River09(
+	TEMPLATE_RIVER09,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RV09",
+	TXT_RIVER
+);
+static TemplateTypeClass const River10(
+	TEMPLATE_RIVER10,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RV10",
+	TXT_RIVER
+);
+static TemplateTypeClass const River11(
+	TEMPLATE_RIVER11,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RV11",
+	TXT_RIVER
+);
+static TemplateTypeClass const River12(
+	TEMPLATE_RIVER12,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RV12",
+	TXT_RIVER
+);
+static TemplateTypeClass const River13(
+	TEMPLATE_RIVER13,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RV13",
+	TXT_RIVER
+);
+static TemplateTypeClass const River14(
+	TEMPLATE_RIVER14,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RV14",
+	TXT_RIVER
+);
+static TemplateTypeClass const River15(
+	TEMPLATE_RIVER15,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RV15",
+	TXT_RIVER
+);
+static TemplateTypeClass const Ford1(
+	TEMPLATE_FORD1,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"FORD1",
+	TXT_RIVER
+);
+static TemplateTypeClass const Ford2(
+	TEMPLATE_FORD2,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"FORD2",
+	TXT_RIVER
+);
+static TemplateTypeClass const Falls1(
+	TEMPLATE_FALLS1,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"FALLS1",
+	TXT_RIVER
+);
+static TemplateTypeClass const Falls1a(
+	TEMPLATE_FALLS1A,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"FALLS1A",
+	TXT_RIVER
+);
+static TemplateTypeClass const Falls2(
+	TEMPLATE_FALLS2,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"FALLS2",
+	TXT_RIVER
+);
+static TemplateTypeClass const Falls2a(
+	TEMPLATE_FALLS2A,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"FALLS2A",
+	TXT_RIVER
+);
+static TemplateTypeClass const Bridge1x(
+	TEMPLATE_BRIDGE1X,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"BRIDGE1X",
+	TXT_BRIDGE
+);
+static TemplateTypeClass const Bridge1(
+	TEMPLATE_BRIDGE1,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"BRIDGE1",
+	TXT_BRIDGE
+);
+static TemplateTypeClass const Bridge1h(
+	TEMPLATE_BRIDGE1H,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"BRIDGE1H",
+	TXT_BRIDGE
+);
+static TemplateTypeClass const Bridge1d(
+	TEMPLATE_BRIDGE1D,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"BRIDGE1D",
+	TXT_BRIDGE
+);
+static TemplateTypeClass const Bridge2x(
+	TEMPLATE_BRIDGE2X,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"BRIDGE2X",
+	TXT_BRIDGE
+);
+static TemplateTypeClass const Bridge2(
+	TEMPLATE_BRIDGE2,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"BRIDGE2",
+	TXT_BRIDGE
+);
+static TemplateTypeClass const Bridge2h(
+	TEMPLATE_BRIDGE2H,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"BRIDGE2H",
+	TXT_BRIDGE
+);
+static TemplateTypeClass const Bridge2d(
+	TEMPLATE_BRIDGE2D,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"BRIDGE2D",
+	TXT_BRIDGE
+);
+static TemplateTypeClass const Bridge1ax(
+	TEMPLATE_BRIDGE_1AX,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"BR1X",
+	TXT_BRIDGE
+);
+static TemplateTypeClass const Bridge1a(
+	TEMPLATE_BRIDGE_1A,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"BR1A",
+	TXT_BRIDGE
+);
+static TemplateTypeClass const Bridge1b(
+	TEMPLATE_BRIDGE_1B,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"BR1B",
+	TXT_BRIDGE
+);
+static TemplateTypeClass const Bridge1c(
+	TEMPLATE_BRIDGE_1C,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"BR1C",
+	TXT_BRIDGE
+);
+static TemplateTypeClass const Bridge2ax(
+	TEMPLATE_BRIDGE_2AX,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"BR2X",
+	TXT_BRIDGE
+);
+static TemplateTypeClass const Bridge2a(
+	TEMPLATE_BRIDGE_2A,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"BR2A",
+	TXT_BRIDGE
+);
+static TemplateTypeClass const Bridge2b(
+	TEMPLATE_BRIDGE_2B,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"BR2B",
+	TXT_BRIDGE
+);
+static TemplateTypeClass const Bridge2c(
+	TEMPLATE_BRIDGE_2C,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"BR2C",
+	TXT_BRIDGE
+);
+static TemplateTypeClass const Bridge3a(
+	TEMPLATE_BRIDGE_3A,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"BR3A",
+	TXT_BRIDGE
+);
+static TemplateTypeClass const Bridge3b(
+	TEMPLATE_BRIDGE_3B,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"BR3B",
+	TXT_BRIDGE
+);
+static TemplateTypeClass const Bridge3c(
+	TEMPLATE_BRIDGE_3C,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"BR3C",
+	TXT_BRIDGE
+);
+static TemplateTypeClass const Bridge3d(
+	TEMPLATE_BRIDGE_3D,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"BR3D",
+	TXT_BRIDGE
+);
+static TemplateTypeClass const Bridge3e(
+	TEMPLATE_BRIDGE_3E,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"BR3E",
+	TXT_BRIDGE
+);
+static TemplateTypeClass const Bridge3f(
+	TEMPLATE_BRIDGE_3F,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"BR3F",
+	TXT_BRIDGE
+);
+static TemplateTypeClass const ShoreCliff01(
+	TEMPLATE_SHORECLIFF01,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC01",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff02(
+	TEMPLATE_SHORECLIFF02,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC02",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff03(
+	TEMPLATE_SHORECLIFF03,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC03",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff04(
+	TEMPLATE_SHORECLIFF04,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC04",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff05(
+	TEMPLATE_SHORECLIFF05,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC05",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff06(
+	TEMPLATE_SHORECLIFF06,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC06",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff07(
+	TEMPLATE_SHORECLIFF07,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC07",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff08(
+	TEMPLATE_SHORECLIFF08,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC08",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff09(
+	TEMPLATE_SHORECLIFF09,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC09",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff10(
+	TEMPLATE_SHORECLIFF10,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC10",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff11(
+	TEMPLATE_SHORECLIFF11,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC11",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff12(
+	TEMPLATE_SHORECLIFF12,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC12",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff13(
+	TEMPLATE_SHORECLIFF13,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC13",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff14(
+	TEMPLATE_SHORECLIFF14,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC14",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff15(
+	TEMPLATE_SHORECLIFF15,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC15",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff16(
+	TEMPLATE_SHORECLIFF16,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC16",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff17(
+	TEMPLATE_SHORECLIFF17,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC17",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff18(
+	TEMPLATE_SHORECLIFF18,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC18",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff19(
+	TEMPLATE_SHORECLIFF19,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC19",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff20(
+	TEMPLATE_SHORECLIFF20,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC20",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff21(
+	TEMPLATE_SHORECLIFF21,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC21",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff22(
+	TEMPLATE_SHORECLIFF22,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC22",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff23(
+	TEMPLATE_SHORECLIFF23,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC23",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff24(
+	TEMPLATE_SHORECLIFF24,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC24",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff25(
+	TEMPLATE_SHORECLIFF25,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC25",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff26(
+	TEMPLATE_SHORECLIFF26,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC26",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff27(
+	TEMPLATE_SHORECLIFF27,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC27",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff28(
+	TEMPLATE_SHORECLIFF28,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC28",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff29(
+	TEMPLATE_SHORECLIFF29,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC29",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff30(
+	TEMPLATE_SHORECLIFF30,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC30",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff31(
+	TEMPLATE_SHORECLIFF31,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC31",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff32(
+	TEMPLATE_SHORECLIFF32,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC32",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff33(
+	TEMPLATE_SHORECLIFF33,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC33",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff34(
+	TEMPLATE_SHORECLIFF34,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC34",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff35(
+	TEMPLATE_SHORECLIFF35,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC35",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff36(
+	TEMPLATE_SHORECLIFF36,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC36",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff37(
+	TEMPLATE_SHORECLIFF37,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC37",
+	TXT_SHORE
+);
+static TemplateTypeClass const ShoreCliff38(
+	TEMPLATE_SHORECLIFF38,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"WC38",
+	TXT_SHORE
+);
+static TemplateTypeClass const Rough01(
+	TEMPLATE_ROUGH01,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RF01",
+	TXT_ROCK
+);
+static TemplateTypeClass const Rough02(
+	TEMPLATE_ROUGH02,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RF02",
+	TXT_ROCK
+);
+static TemplateTypeClass const Rough03(
+	TEMPLATE_ROUGH03,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RF03",
+	TXT_ROCK
+);
+static TemplateTypeClass const Rough04(
+	TEMPLATE_ROUGH04,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RF04",
+	TXT_ROCK
+);
+static TemplateTypeClass const Rough05(
+	TEMPLATE_ROUGH05,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RF05",
+	TXT_ROCK
+);
+static TemplateTypeClass const Rough06(
+	TEMPLATE_ROUGH06,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RF06",
+	TXT_ROCK
+);
+static TemplateTypeClass const Rough07(
+	TEMPLATE_ROUGH07,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RF07",
+	TXT_ROCK
+);
+static TemplateTypeClass const Rough08(
+	TEMPLATE_ROUGH08,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RF08",
+	TXT_ROCK
+);
+static TemplateTypeClass const Rough09(
+	TEMPLATE_ROUGH09,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RF09",
+	TXT_ROCK
+);
+static TemplateTypeClass const Rough10(
+	TEMPLATE_ROUGH10,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RF10",
+	TXT_ROCK
+);
+static TemplateTypeClass const Rough11(
+	TEMPLATE_ROUGH11,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RF11",
+	TXT_ROCK
+);
+static TemplateTypeClass const RiverCliff01(
+	TEMPLATE_RIVERCLIFF01,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RC01",
+	TXT_RIVER
+);
+static TemplateTypeClass const RiverCliff02(
+	TEMPLATE_RIVERCLIFF02,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RC02",
+	TXT_RIVER
+);
+static TemplateTypeClass const RiverCliff03(
+	TEMPLATE_RIVERCLIFF03,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RC03",
+	TXT_RIVER
+);
+static TemplateTypeClass const RiverCliff04(
+	TEMPLATE_RIVERCLIFF04,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"RC04",
+	TXT_RIVER
+);
+
+static TemplateTypeClass const F01(
+	TEMPLATE_F01,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"F01",
+	TXT_RIVER
+);
+static TemplateTypeClass const F02(
+	TEMPLATE_F02,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"F02",
+	TXT_RIVER
+);
+static TemplateTypeClass const F03(
+	TEMPLATE_F03,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"F03",
+	TXT_RIVER
+);
+static TemplateTypeClass const F04(
+	TEMPLATE_F04,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"F04",
+	TXT_RIVER
+);
+static TemplateTypeClass const F05(
+	TEMPLATE_F05,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"F05",
+	TXT_RIVER
+);
+static TemplateTypeClass const F06(
+	TEMPLATE_F06,
+	THEATERF_TEMPERATE|THEATERF_SNOW,
+	"F06",
+	TXT_RIVER
+);
+
+static TemplateTypeClass const ARRO0001(
+	TEMPLATE_ARRO0001,
+	THEATERF_INTERIOR,
+	"ARRO0001",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const ARRO0002(
+	TEMPLATE_ARRO0002,
+	THEATERF_INTERIOR,
+	"ARRO0002",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const ARRO0003(
+	TEMPLATE_ARRO0003,
+	THEATERF_INTERIOR,
+	"ARRO0003",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const ARRO0004(
+	TEMPLATE_ARRO0004,
+	THEATERF_INTERIOR,
+	"ARRO0004",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const ARRO0005(
+	TEMPLATE_ARRO0005,
+	THEATERF_INTERIOR,
+	"ARRO0005",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const ARRO0006(
+	TEMPLATE_ARRO0006,
+	THEATERF_INTERIOR,
+	"ARRO0006",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const ARRO0007(
+	TEMPLATE_ARRO0007,
+	THEATERF_INTERIOR,
+	"ARRO0007",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const ARRO0008(
+	TEMPLATE_ARRO0008,
+	THEATERF_INTERIOR,
+	"ARRO0008",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const ARRO0009(
+	TEMPLATE_ARRO0009,
+	THEATERF_INTERIOR,
+	"ARRO0009",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const ARRO0010(
+	TEMPLATE_ARRO0010,
+	THEATERF_INTERIOR,
+	"ARRO0010",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const ARRO0011(
+	TEMPLATE_ARRO0011,
+	THEATERF_INTERIOR,
+	"ARRO0011",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const ARRO0012(
+	TEMPLATE_ARRO0012,
+	THEATERF_INTERIOR,
+	"ARRO0012",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const ARRO0013(
+	TEMPLATE_ARRO0013,
+	THEATERF_INTERIOR,
+	"ARRO0013",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const ARRO0014(
+	TEMPLATE_ARRO0014,
+	THEATERF_INTERIOR,
+	"ARRO0014",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const ARRO0015(
+	TEMPLATE_ARRO0015,
+	THEATERF_INTERIOR,
+	"ARRO0015",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const FLOR0001(
+	TEMPLATE_FLOR0001,
+	THEATERF_INTERIOR,
+	"FLOR0001",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const FLOR0002(
+	TEMPLATE_FLOR0002,
+	THEATERF_INTERIOR,
+	"FLOR0002",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const FLOR0003(
+	TEMPLATE_FLOR0003,
+	THEATERF_INTERIOR,
+	"FLOR0003",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const FLOR0004(
+	TEMPLATE_FLOR0004,
+	THEATERF_INTERIOR,
+	"FLOR0004",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const FLOR0005(
+	TEMPLATE_FLOR0005,
+	THEATERF_INTERIOR,
+	"FLOR0005",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const FLOR0006(
+	TEMPLATE_FLOR0006,
+	THEATERF_INTERIOR,
+	"FLOR0006",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const FLOR0007(
+	TEMPLATE_FLOR0007,
+	THEATERF_INTERIOR,
+	"FLOR0007",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const GFLR0001(
+	TEMPLATE_GFLR0001,
+	THEATERF_INTERIOR,
+	"GFLR0001",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const GFLR0002(
+	TEMPLATE_GFLR0002,
+	THEATERF_INTERIOR,
+	"GFLR0002",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const GFLR0003(
+	TEMPLATE_GFLR0003,
+	THEATERF_INTERIOR,
+	"GFLR0003",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const GFLR0004(
+	TEMPLATE_GFLR0004,
+	THEATERF_INTERIOR,
+	"GFLR0004",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const GFLR0005(
+	TEMPLATE_GFLR0005,
+	THEATERF_INTERIOR,
+	"GFLR0005",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const GSTR0001(
+	TEMPLATE_GSTR0001,
+	THEATERF_INTERIOR,
+	"GSTR0001",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const GSTR0002(
+	TEMPLATE_GSTR0002,
+	THEATERF_INTERIOR,
+	"GSTR0002",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const GSTR0003(
+	TEMPLATE_GSTR0003,
+	THEATERF_INTERIOR,
+	"GSTR0003",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const GSTR0004(
+	TEMPLATE_GSTR0004,
+	THEATERF_INTERIOR,
+	"GSTR0004",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const GSTR0005(
+	TEMPLATE_GSTR0005,
+	THEATERF_INTERIOR,
+	"GSTR0005",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const GSTR0006(
+	TEMPLATE_GSTR0006,
+	THEATERF_INTERIOR,
+	"GSTR0006",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const GSTR0007(
+	TEMPLATE_GSTR0007,
+	THEATERF_INTERIOR,
+	"GSTR0007",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const GSTR0008(
+	TEMPLATE_GSTR0008,
+	THEATERF_INTERIOR,
+	"GSTR0008",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const GSTR0009(
+	TEMPLATE_GSTR0009,
+	THEATERF_INTERIOR,
+	"GSTR0009",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const GSTR0010(
+	TEMPLATE_GSTR0010,
+	THEATERF_INTERIOR,
+	"GSTR0010",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const GSTR0011(
+	TEMPLATE_GSTR0011,
+	THEATERF_INTERIOR,
+	"GSTR0011",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const LWAL0001(
+	TEMPLATE_LWAL0001,
+	THEATERF_INTERIOR,
+	"LWAL0001",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const LWAL0002(
+	TEMPLATE_LWAL0002,
+	THEATERF_INTERIOR,
+	"LWAL0002",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const LWAL0003(
+	TEMPLATE_LWAL0003,
+	THEATERF_INTERIOR,
+	"LWAL0003",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const LWAL0004(
+	TEMPLATE_LWAL0004,
+	THEATERF_INTERIOR,
+	"LWAL0004",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const LWAL0005(
+	TEMPLATE_LWAL0005,
+	THEATERF_INTERIOR,
+	"LWAL0005",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const LWAL0006(
+	TEMPLATE_LWAL0006,
+	THEATERF_INTERIOR,
+	"LWAL0006",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const LWAL0007(
+	TEMPLATE_LWAL0007,
+	THEATERF_INTERIOR,
+	"LWAL0007",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const LWAL0008(
+	TEMPLATE_LWAL0008,
+	THEATERF_INTERIOR,
+	"LWAL0008",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const LWAL0009(
+	TEMPLATE_LWAL0009,
+	THEATERF_INTERIOR,
+	"LWAL0009",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const LWAL0010(
+	TEMPLATE_LWAL0010,
+	THEATERF_INTERIOR,
+	"LWAL0010",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const LWAL0011(
+	TEMPLATE_LWAL0011,
+	THEATERF_INTERIOR,
+	"LWAL0011",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const LWAL0012(
+	TEMPLATE_LWAL0012,
+	THEATERF_INTERIOR,
+	"LWAL0012",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const LWAL0013(
+	TEMPLATE_LWAL0013,
+	THEATERF_INTERIOR,
+	"LWAL0013",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const LWAL0014(
+	TEMPLATE_LWAL0014,
+	THEATERF_INTERIOR,
+	"LWAL0014",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const LWAL0015(
+	TEMPLATE_LWAL0015,
+	THEATERF_INTERIOR,
+	"LWAL0015",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const LWAL0016(
+	TEMPLATE_LWAL0016,
+	THEATERF_INTERIOR,
+	"LWAL0016",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const LWAL0017(
+	TEMPLATE_LWAL0017,
+	THEATERF_INTERIOR,
+	"LWAL0017",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const LWAL0018(
+	TEMPLATE_LWAL0018,
+	THEATERF_INTERIOR,
+	"LWAL0018",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const LWAL0019(
+	TEMPLATE_LWAL0019,
+	THEATERF_INTERIOR,
+	"LWAL0019",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const LWAL0020(
+	TEMPLATE_LWAL0020,
+	THEATERF_INTERIOR,
+	"LWAL0020",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const LWAL0021(
+	TEMPLATE_LWAL0021,
+	THEATERF_INTERIOR,
+	"LWAL0021",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const LWAL0022(
+	TEMPLATE_LWAL0022,
+	THEATERF_INTERIOR,
+	"LWAL0022",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const LWAL0023(
+	TEMPLATE_LWAL0023,
+	THEATERF_INTERIOR,
+	"LWAL0023",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const LWAL0024(
+	TEMPLATE_LWAL0024,
+	THEATERF_INTERIOR,
+	"LWAL0024",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const LWAL0025(
+	TEMPLATE_LWAL0025,
+	THEATERF_INTERIOR,
+	"LWAL0025",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const LWAL0026(
+	TEMPLATE_LWAL0026,
+	THEATERF_INTERIOR,
+	"LWAL0026",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const LWAL0027(
+	TEMPLATE_LWAL0027,
+	THEATERF_INTERIOR,
+	"LWAL0027",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const STRP0001(
+	TEMPLATE_STRP0001,
+	THEATERF_INTERIOR,
+	"STRP0001",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const STRP0002(
+	TEMPLATE_STRP0002,
+	THEATERF_INTERIOR,
+	"STRP0002",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const STRP0003(
+	TEMPLATE_STRP0003,
+	THEATERF_INTERIOR,
+	"STRP0003",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const STRP0004(
+	TEMPLATE_STRP0004,
+	THEATERF_INTERIOR,
+	"STRP0004",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const STRP0005(
+	TEMPLATE_STRP0005,
+	THEATERF_INTERIOR,
+	"STRP0005",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const STRP0006(
+	TEMPLATE_STRP0006,
+	THEATERF_INTERIOR,
+	"STRP0006",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const STRP0007(
+	TEMPLATE_STRP0007,
+	THEATERF_INTERIOR,
+	"STRP0007",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const STRP0008(
+	TEMPLATE_STRP0008,
+	THEATERF_INTERIOR,
+	"STRP0008",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const STRP0009(
+	TEMPLATE_STRP0009,
+	THEATERF_INTERIOR,
+	"STRP0009",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const STRP0010(
+	TEMPLATE_STRP0010,
+	THEATERF_INTERIOR,
+	"STRP0010",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const STRP0011(
+	TEMPLATE_STRP0011,
+	THEATERF_INTERIOR,
+	"STRP0011",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0001(
+	TEMPLATE_WALL0001,
+	THEATERF_INTERIOR,
+	"WALL0001",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0002(
+	TEMPLATE_WALL0002,
+	THEATERF_INTERIOR,
+	"WALL0002",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0003(
+	TEMPLATE_WALL0003,
+	THEATERF_INTERIOR,
+	"WALL0003",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0004(
+	TEMPLATE_WALL0004,
+	THEATERF_INTERIOR,
+	"WALL0004",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0005(
+	TEMPLATE_WALL0005,
+	THEATERF_INTERIOR,
+	"WALL0005",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0006(
+	TEMPLATE_WALL0006,
+	THEATERF_INTERIOR,
+	"WALL0006",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0007(
+	TEMPLATE_WALL0007,
+	THEATERF_INTERIOR,
+	"WALL0007",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0008(
+	TEMPLATE_WALL0008,
+	THEATERF_INTERIOR,
+	"WALL0008",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0009(
+	TEMPLATE_WALL0009,
+	THEATERF_INTERIOR,
+	"WALL0009",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0010(
+	TEMPLATE_WALL0010,
+	THEATERF_INTERIOR,
+	"WALL0010",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0011(
+	TEMPLATE_WALL0011,
+	THEATERF_INTERIOR,
+	"WALL0011",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0012(
+	TEMPLATE_WALL0012,
+	THEATERF_INTERIOR,
+	"WALL0012",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0013(
+	TEMPLATE_WALL0013,
+	THEATERF_INTERIOR,
+	"WALL0013",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0014(
+	TEMPLATE_WALL0014,
+	THEATERF_INTERIOR,
+	"WALL0014",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0015(
+	TEMPLATE_WALL0015,
+	THEATERF_INTERIOR,
+	"WALL0015",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0016(
+	TEMPLATE_WALL0016,
+	THEATERF_INTERIOR,
+	"WALL0016",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0017(
+	TEMPLATE_WALL0017,
+	THEATERF_INTERIOR,
+	"WALL0017",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0018(
+	TEMPLATE_WALL0018,
+	THEATERF_INTERIOR,
+	"WALL0018",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0019(
+	TEMPLATE_WALL0019,
+	THEATERF_INTERIOR,
+	"WALL0019",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0020(
+	TEMPLATE_WALL0020,
+	THEATERF_INTERIOR,
+	"WALL0020",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0021(
+	TEMPLATE_WALL0021,
+	THEATERF_INTERIOR,
+	"WALL0021",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0022(
+	TEMPLATE_WALL0022,
+	THEATERF_INTERIOR,
+	"WALL0022",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0023(
+	TEMPLATE_WALL0023,
+	THEATERF_INTERIOR,
+	"WALL0023",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0024(
+	TEMPLATE_WALL0024,
+	THEATERF_INTERIOR,
+	"WALL0024",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0025(
+	TEMPLATE_WALL0025,
+	THEATERF_INTERIOR,
+	"WALL0025",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0026(
+	TEMPLATE_WALL0026,
+	THEATERF_INTERIOR,
+	"WALL0026",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0027(
+	TEMPLATE_WALL0027,
+	THEATERF_INTERIOR,
+	"WALL0027",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0028(
+	TEMPLATE_WALL0028,
+	THEATERF_INTERIOR,
+	"WALL0028",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0029(
+	TEMPLATE_WALL0029,
+	THEATERF_INTERIOR,
+	"WALL0029",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0030(
+	TEMPLATE_WALL0030,
+	THEATERF_INTERIOR,
+	"WALL0030",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0031(
+	TEMPLATE_WALL0031,
+	THEATERF_INTERIOR,
+	"WALL0031",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0032(
+	TEMPLATE_WALL0032,
+	THEATERF_INTERIOR,
+	"WALL0032",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0033(
+	TEMPLATE_WALL0033,
+	THEATERF_INTERIOR,
+	"WALL0033",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0034(
+	TEMPLATE_WALL0034,
+	THEATERF_INTERIOR,
+	"WALL0034",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0035(
+	TEMPLATE_WALL0035,
+	THEATERF_INTERIOR,
+	"WALL0035",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0036(
+	TEMPLATE_WALL0036,
+	THEATERF_INTERIOR,
+	"WALL0036",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0037(
+	TEMPLATE_WALL0037,
+	THEATERF_INTERIOR,
+	"WALL0037",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0038(
+	TEMPLATE_WALL0038,
+	THEATERF_INTERIOR,
+	"WALL0038",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0039(
+	TEMPLATE_WALL0039,
+	THEATERF_INTERIOR,
+	"WALL0039",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0040(
+	TEMPLATE_WALL0040,
+	THEATERF_INTERIOR,
+	"WALL0040",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0041(
+	TEMPLATE_WALL0041,
+	THEATERF_INTERIOR,
+	"WALL0041",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0042(
+	TEMPLATE_WALL0042,
+	THEATERF_INTERIOR,
+	"WALL0042",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0043(
+	TEMPLATE_WALL0043,
+	THEATERF_INTERIOR,
+	"WALL0043",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0044(
+	TEMPLATE_WALL0044,
+	THEATERF_INTERIOR,
+	"WALL0044",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0045(
+	TEMPLATE_WALL0045,
+	THEATERF_INTERIOR,
+	"WALL0045",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0046(
+	TEMPLATE_WALL0046,
+	THEATERF_INTERIOR,
+	"WALL0046",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0047(
+	TEMPLATE_WALL0047,
+	THEATERF_INTERIOR,
+	"WALL0047",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0048(
+	TEMPLATE_WALL0048,
+	THEATERF_INTERIOR,
+	"WALL0048",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const WALL0049(
+	TEMPLATE_WALL0049,
+	THEATERF_INTERIOR,
+	"WALL0049",
+	TXT_INTERIOR
+);
+
+static TemplateTypeClass const Xtra0001(
+	TEMPLATE_XTRA0001,
+	THEATERF_INTERIOR,
+	"XTRA0001",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const Xtra0002(
+	TEMPLATE_XTRA0002,
+	THEATERF_INTERIOR,
+	"XTRA0002",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const Xtra0003(
+	TEMPLATE_XTRA0003,
+	THEATERF_INTERIOR,
+	"XTRA0003",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const Xtra0004(
+	TEMPLATE_XTRA0004,
+	THEATERF_INTERIOR,
+	"XTRA0004",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const Xtra0005(
+	TEMPLATE_XTRA0005,
+	THEATERF_INTERIOR,
+	"XTRA0005",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const Xtra0006(
+	TEMPLATE_XTRA0006,
+	THEATERF_INTERIOR,
+	"XTRA0006",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const Xtra0007(
+	TEMPLATE_XTRA0007,
+	THEATERF_INTERIOR,
+	"XTRA0007",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const Xtra0008(
+	TEMPLATE_XTRA0008,
+	THEATERF_INTERIOR,
+	"XTRA0008",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const Xtra0009(
+	TEMPLATE_XTRA0009,
+	THEATERF_INTERIOR,
+	"XTRA0009",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const Xtra0010(
+	TEMPLATE_XTRA0010,
+	THEATERF_INTERIOR,
+	"XTRA0010",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const Xtra0011(
+	TEMPLATE_XTRA0011,
+	THEATERF_INTERIOR,
+	"XTRA0011",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const Xtra0012(
+	TEMPLATE_XTRA0012,
+	THEATERF_INTERIOR,
+	"XTRA0012",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const Xtra0013(
+	TEMPLATE_XTRA0013,
+	THEATERF_INTERIOR,
+	"XTRA0013",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const Xtra0014(
+	TEMPLATE_XTRA0014,
+	THEATERF_INTERIOR,
+	"XTRA0014",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const Xtra0015(
+	TEMPLATE_XTRA0015,
+	THEATERF_INTERIOR,
+	"XTRA0015",
+	TXT_INTERIOR
+);
+static TemplateTypeClass const Xtra0016(
+	TEMPLATE_XTRA0016,
+	THEATERF_INTERIOR,
+	"XTRA0016",
+	TXT_INTERIOR
+);
+
+#ifdef FIXIT_ANTS
+static TemplateTypeClass const AntHill(
+	TEMPLATE_HILL01,
+	THEATERF_TEMPERATE,
+	"HILL01",
+	TXT_ROCK
+);
+#endif
+
+/***********************************************************************************************
+ * TemplateTypeClass::TemplateTypeClass -- Constructor for template type objects.              *
+ *                                                                                             *
+ *    This is the constructor for the template types.                                          *
+ *                                                                                             *
+ * INPUT:   see below...                                                                       *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/29/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+TemplateTypeClass::TemplateTypeClass(
+	TemplateType iconset,
+	int theater,
+	char const * ininame,
+	int fullname) :
+		ObjectTypeClass(
+			RTTI_TEMPLATETYPE,
+			int(iconset),
+			false,
+			true,
+			false,
+			false,
+			true,
+			true,
+			false,
+			fullname,
+			ininame),
+	Type(iconset),
+	Theater(theater),
+	Width(0),
+	Height(0)
+{
+}
+
+
+/***********************************************************************************************
+ * TemplateTypeClass::operator new -- Allocates a template type from special heap.             *
+ *                                                                                             *
+ *    This allocates a template type object from the special heap used for that purpose.       *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with a pointer to the newly allocated template type object. If no object   *
+ *          could be allocated, then NULL is returned.                                         *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/06/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void * TemplateTypeClass::operator new(size_t)
+{
+	return(TemplateTypes.Alloc());
+}
+
+
+/***********************************************************************************************
+ * TemplateTypeClass::operator delete -- Deletes a template type object.                       *
+ *                                                                                             *
+ *    This routine will return a template type object back to the special heap it was          *
+ *    allocated from.                                                                          *
+ *                                                                                             *
+ * INPUT:   ptr   -- Pointer to the template type object to free.                              *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/06/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void TemplateTypeClass::operator delete(void * ptr)
+{
+	TemplateTypes.Free((TemplateTypeClass *)ptr);
+}
+
+
+static void _Watcom_Ugh_Hack(void)
+{
+	(void)new TemplateTypeClass(Road37);			//	TEMPLATE_ROAD37
+	(void)new TemplateTypeClass(Road38);			//	TEMPLATE_ROAD38
+	(void)new TemplateTypeClass(Road39);			//	TEMPLATE_ROAD39
+	(void)new TemplateTypeClass(Road40);			//	TEMPLATE_ROAD40
+	(void)new TemplateTypeClass(Road41);			//	TEMPLATE_ROAD41
+	(void)new TemplateTypeClass(Road42);			//	TEMPLATE_ROAD42
+	(void)new TemplateTypeClass(Road43);			//	TEMPLATE_ROAD43
+	(void)new TemplateTypeClass(Rough01);			// TEMPLATE_ROUGH01
+	(void)new TemplateTypeClass(Rough02);			// TEMPLATE_ROUGH02
+	(void)new TemplateTypeClass(Rough03);			// TEMPLATE_ROUGH03
+	(void)new TemplateTypeClass(Rough04);			// TEMPLATE_ROUGH04
+	(void)new TemplateTypeClass(Rough05);			// TEMPLATE_ROUGH05
+	(void)new TemplateTypeClass(Rough06);			// TEMPLATE_ROUGH06
+	(void)new TemplateTypeClass(Rough07);			// TEMPLATE_ROUGH07
+	(void)new TemplateTypeClass(Rough08);			// TEMPLATE_ROUGH08
+	(void)new TemplateTypeClass(Rough09);			// TEMPLATE_ROUGH09
+	(void)new TemplateTypeClass(Rough10);			// TEMPLATE_ROUGH10
+	(void)new TemplateTypeClass(Rough11);			// TEMPLATE_ROUGH11
+	(void)new TemplateTypeClass(Road44);			//	TEMPLATE_ROAD44
+	(void)new TemplateTypeClass(Road45);			//	TEMPLATE_ROAD45
+	(void)new TemplateTypeClass(River14);			//	TEMPLATE_RIVER14
+	(void)new TemplateTypeClass(River15);			//	TEMPLATE_RIVER15
+	(void)new TemplateTypeClass(RiverCliff01);	//	TEMPLATE_RIVERCLIFF01
+	(void)new TemplateTypeClass(RiverCliff02);	//	TEMPLATE_RIVERCLIFF02
+	(void)new TemplateTypeClass(RiverCliff03);	//	TEMPLATE_RIVERCLIFF03
+	(void)new TemplateTypeClass(RiverCliff04);	//	TEMPLATE_RIVERCLIFF04
+	(void)new TemplateTypeClass(Bridge1a);			//	TEMPLATE_BRIDGE_1A
+	(void)new TemplateTypeClass(Bridge1b);			//	TEMPLATE_BRIDGE_1B
+	(void)new TemplateTypeClass(Bridge1c);			//	TEMPLATE_BRIDGE_1C
+	(void)new TemplateTypeClass(Bridge2a);			//	TEMPLATE_BRIDGE_2A
+	(void)new TemplateTypeClass(Bridge2b);			//	TEMPLATE_BRIDGE_2B
+	(void)new TemplateTypeClass(Bridge2c);			//	TEMPLATE_BRIDGE_2C
+	(void)new TemplateTypeClass(Bridge3a);			//	TEMPLATE_BRIDGE_3A
+	(void)new TemplateTypeClass(Bridge3b);			//	TEMPLATE_BRIDGE_3B
+	(void)new TemplateTypeClass(Bridge3c);			//	TEMPLATE_BRIDGE_3C
+	(void)new TemplateTypeClass(Bridge3d);			//	TEMPLATE_BRIDGE_3D
+	(void)new TemplateTypeClass(Bridge3e);			//	TEMPLATE_BRIDGE_3E
+	(void)new TemplateTypeClass(Bridge3f);			//	TEMPLATE_BRIDGE_3F
+	(void)new TemplateTypeClass(F01);				//	TEMPLATE_F01
+	(void)new TemplateTypeClass(F02);				//	TEMPLATE_F02
+	(void)new TemplateTypeClass(F03);				//	TEMPLATE_F03
+	(void)new TemplateTypeClass(F04);				//	TEMPLATE_F04
+	(void)new TemplateTypeClass(F05);				//	TEMPLATE_F05
+	(void)new TemplateTypeClass(F06);				//	TEMPLATE_F06
+	(void)new TemplateTypeClass(ARRO0001);			//	TEMPLATE_ARRO0001
+	(void)new TemplateTypeClass(ARRO0002);			//	TEMPLATE_ARRO0002
+	(void)new TemplateTypeClass(ARRO0003);			//	TEMPLATE_ARRO0003
+	(void)new TemplateTypeClass(ARRO0004);			//	TEMPLATE_ARRO0004
+	(void)new TemplateTypeClass(ARRO0005);			//	TEMPLATE_ARRO0005
+	(void)new TemplateTypeClass(ARRO0006);			//	TEMPLATE_ARRO0006
+	(void)new TemplateTypeClass(ARRO0007);			//	TEMPLATE_ARRO0007
+	(void)new TemplateTypeClass(ARRO0008);			//	TEMPLATE_ARRO0008
+	(void)new TemplateTypeClass(ARRO0009);			//	TEMPLATE_ARRO0009
+	(void)new TemplateTypeClass(ARRO0010);			//	TEMPLATE_ARRO0010
+	(void)new TemplateTypeClass(ARRO0011);			//	TEMPLATE_ARRO0011
+	(void)new TemplateTypeClass(ARRO0012);			//	TEMPLATE_ARRO0012
+	(void)new TemplateTypeClass(ARRO0013);			//	TEMPLATE_ARRO0013
+	(void)new TemplateTypeClass(ARRO0014);			//	TEMPLATE_ARRO0014
+	(void)new TemplateTypeClass(ARRO0015);			//	TEMPLATE_ARRO0015
+	(void)new TemplateTypeClass(FLOR0001);			//	TEMPLATE_FLOR0001
+	(void)new TemplateTypeClass(FLOR0002);			//	TEMPLATE_FLOR0002
+	(void)new TemplateTypeClass(FLOR0003);			//	TEMPLATE_FLOR0003
+	(void)new TemplateTypeClass(FLOR0004);			//	TEMPLATE_FLOR0004
+	(void)new TemplateTypeClass(FLOR0005);			//	TEMPLATE_FLOR0005
+	(void)new TemplateTypeClass(FLOR0006);			//	TEMPLATE_FLOR0006
+	(void)new TemplateTypeClass(FLOR0007);			//	TEMPLATE_FLOR0007
+	(void)new TemplateTypeClass(GFLR0001);			//	TEMPLATE_GFLR0001
+	(void)new TemplateTypeClass(GFLR0002);			//	TEMPLATE_GFLR0002
+	(void)new TemplateTypeClass(GFLR0003);			//	TEMPLATE_GFLR0003
+	(void)new TemplateTypeClass(GFLR0004);			//	TEMPLATE_GFLR0004
+	(void)new TemplateTypeClass(GFLR0005);			//	TEMPLATE_GFLR0005
+	(void)new TemplateTypeClass(GSTR0001);			//	TEMPLATE_GSTR0001
+	(void)new TemplateTypeClass(GSTR0002);			//	TEMPLATE_GSTR0002
+	(void)new TemplateTypeClass(GSTR0003);			//	TEMPLATE_GSTR0003
+	(void)new TemplateTypeClass(GSTR0004);			//	TEMPLATE_GSTR0004
+	(void)new TemplateTypeClass(GSTR0005);			//	TEMPLATE_GSTR0005
+	(void)new TemplateTypeClass(GSTR0006);			//	TEMPLATE_GSTR0006
+	(void)new TemplateTypeClass(GSTR0007);			//	TEMPLATE_GSTR0007
+	(void)new TemplateTypeClass(GSTR0008);			//	TEMPLATE_GSTR0008
+	(void)new TemplateTypeClass(GSTR0009);			//	TEMPLATE_GSTR0009
+	(void)new TemplateTypeClass(GSTR0010);			//	TEMPLATE_GSTR0010
+	(void)new TemplateTypeClass(GSTR0011);			//	TEMPLATE_GSTR0011
+	(void)new TemplateTypeClass(LWAL0001);			//	TEMPLATE_LWAL0001
+	(void)new TemplateTypeClass(LWAL0002);			//	TEMPLATE_LWAL0002
+	(void)new TemplateTypeClass(LWAL0003);			//	TEMPLATE_LWAL0003
+	(void)new TemplateTypeClass(LWAL0004);			//	TEMPLATE_LWAL0004
+	(void)new TemplateTypeClass(LWAL0005);			//	TEMPLATE_LWAL0005
+	(void)new TemplateTypeClass(LWAL0006);			//	TEMPLATE_LWAL0006
+	(void)new TemplateTypeClass(LWAL0007);			//	TEMPLATE_LWAL0007
+	(void)new TemplateTypeClass(LWAL0008);			//	TEMPLATE_LWAL0008
+	(void)new TemplateTypeClass(LWAL0009);			//	TEMPLATE_LWAL0009
+	(void)new TemplateTypeClass(LWAL0010);			//	TEMPLATE_LWAL0010
+	(void)new TemplateTypeClass(LWAL0011);			//	TEMPLATE_LWAL0011
+	(void)new TemplateTypeClass(LWAL0012);			//	TEMPLATE_LWAL0012
+	(void)new TemplateTypeClass(LWAL0013);			//	TEMPLATE_LWAL0013
+	(void)new TemplateTypeClass(LWAL0014);			//	TEMPLATE_LWAL0014
+	(void)new TemplateTypeClass(LWAL0015);			//	TEMPLATE_LWAL0015
+	(void)new TemplateTypeClass(LWAL0016);			//	TEMPLATE_LWAL0016
+	(void)new TemplateTypeClass(LWAL0017);			//	TEMPLATE_LWAL0017
+	(void)new TemplateTypeClass(LWAL0018);			//	TEMPLATE_LWAL0018
+	(void)new TemplateTypeClass(LWAL0019);			//	TEMPLATE_LWAL0019
+	(void)new TemplateTypeClass(LWAL0020);			//	TEMPLATE_LWAL0020
+	(void)new TemplateTypeClass(LWAL0021);			//	TEMPLATE_LWAL0021
+	(void)new TemplateTypeClass(LWAL0022);			//	TEMPLATE_LWAL0022
+	(void)new TemplateTypeClass(LWAL0023);			//	TEMPLATE_LWAL0023
+	(void)new TemplateTypeClass(LWAL0024);			//	TEMPLATE_LWAL0024
+	(void)new TemplateTypeClass(LWAL0025);			//	TEMPLATE_LWAL0025
+	(void)new TemplateTypeClass(LWAL0026);			//	TEMPLATE_LWAL0026
+	(void)new TemplateTypeClass(LWAL0027);			//	TEMPLATE_LWAL0027
+	(void)new TemplateTypeClass(STRP0001);			//	TEMPLATE_STRP0001
+	(void)new TemplateTypeClass(STRP0002);			//	TEMPLATE_STRP0002
+	(void)new TemplateTypeClass(STRP0003);			//	TEMPLATE_STRP0003
+	(void)new TemplateTypeClass(STRP0004);			//	TEMPLATE_STRP0004
+	(void)new TemplateTypeClass(STRP0005);			//	TEMPLATE_STRP0005
+	(void)new TemplateTypeClass(STRP0006);			//	TEMPLATE_STRP0006
+	(void)new TemplateTypeClass(STRP0007);			//	TEMPLATE_STRP0007
+	(void)new TemplateTypeClass(STRP0008);			//	TEMPLATE_STRP0008
+	(void)new TemplateTypeClass(STRP0009);			//	TEMPLATE_STRP0009
+	(void)new TemplateTypeClass(STRP0010);			//	TEMPLATE_STRP0010
+	(void)new TemplateTypeClass(STRP0011);			//	TEMPLATE_STRP0011
+	(void)new TemplateTypeClass(WALL0001);			//	TEMPLATE_WALL0001
+	(void)new TemplateTypeClass(WALL0002);			//	TEMPLATE_WALL0002
+	(void)new TemplateTypeClass(WALL0003);			//	TEMPLATE_WALL0003
+	(void)new TemplateTypeClass(WALL0004);			//	TEMPLATE_WALL0004
+	(void)new TemplateTypeClass(WALL0005);			//	TEMPLATE_WALL0005
+	(void)new TemplateTypeClass(WALL0006);			//	TEMPLATE_WALL0006
+	(void)new TemplateTypeClass(WALL0007);			//	TEMPLATE_WALL0007
+	(void)new TemplateTypeClass(WALL0008);			//	TEMPLATE_WALL0008
+	(void)new TemplateTypeClass(WALL0009);			//	TEMPLATE_WALL0009
+	(void)new TemplateTypeClass(WALL0010);			//	TEMPLATE_WALL0010
+	(void)new TemplateTypeClass(WALL0011);			//	TEMPLATE_WALL0011
+	(void)new TemplateTypeClass(WALL0012);			//	TEMPLATE_WALL0012
+	(void)new TemplateTypeClass(WALL0013);			//	TEMPLATE_WALL0013
+	(void)new TemplateTypeClass(WALL0014);			//	TEMPLATE_WALL0014
+	(void)new TemplateTypeClass(WALL0015);			//	TEMPLATE_WALL0015
+	(void)new TemplateTypeClass(WALL0016);			//	TEMPLATE_WALL0016
+	(void)new TemplateTypeClass(WALL0017);			//	TEMPLATE_WALL0017
+	(void)new TemplateTypeClass(WALL0018);			//	TEMPLATE_WALL0018
+	(void)new TemplateTypeClass(WALL0019);			//	TEMPLATE_WALL0019
+	(void)new TemplateTypeClass(WALL0020);			//	TEMPLATE_WALL0020
+	(void)new TemplateTypeClass(WALL0021);			//	TEMPLATE_WALL0021
+	(void)new TemplateTypeClass(WALL0022);			//	TEMPLATE_WALL0022
+	(void)new TemplateTypeClass(WALL0023);			//	TEMPLATE_WALL0023
+	(void)new TemplateTypeClass(WALL0024);			//	TEMPLATE_WALL0024
+	(void)new TemplateTypeClass(WALL0025);			//	TEMPLATE_WALL0025
+	(void)new TemplateTypeClass(WALL0026);			//	TEMPLATE_WALL0026
+	(void)new TemplateTypeClass(WALL0027);			//	TEMPLATE_WALL0027
+	(void)new TemplateTypeClass(WALL0028);			//	TEMPLATE_WALL0028
+	(void)new TemplateTypeClass(WALL0029);			//	TEMPLATE_WALL0029
+	(void)new TemplateTypeClass(WALL0030);			//	TEMPLATE_WALL0030
+	(void)new TemplateTypeClass(WALL0031);			//	TEMPLATE_WALL0031
+	(void)new TemplateTypeClass(WALL0032);			//	TEMPLATE_WALL0032
+	(void)new TemplateTypeClass(WALL0033);			//	TEMPLATE_WALL0033
+	(void)new TemplateTypeClass(WALL0034);			//	TEMPLATE_WALL0034
+	(void)new TemplateTypeClass(WALL0035);			//	TEMPLATE_WALL0035
+	(void)new TemplateTypeClass(WALL0036);			//	TEMPLATE_WALL0036
+	(void)new TemplateTypeClass(WALL0037);			//	TEMPLATE_WALL0037
+	(void)new TemplateTypeClass(WALL0038);			//	TEMPLATE_WALL0038
+	(void)new TemplateTypeClass(WALL0039);			//	TEMPLATE_WALL0039
+	(void)new TemplateTypeClass(WALL0040);			//	TEMPLATE_WALL0040
+	(void)new TemplateTypeClass(WALL0041);			//	TEMPLATE_WALL0041
+	(void)new TemplateTypeClass(WALL0042);			//	TEMPLATE_WALL0042
+	(void)new TemplateTypeClass(WALL0043);			//	TEMPLATE_WALL0043
+	(void)new TemplateTypeClass(WALL0044);			//	TEMPLATE_WALL0044
+	(void)new TemplateTypeClass(WALL0045);			//	TEMPLATE_WALL0045
+	(void)new TemplateTypeClass(WALL0046);			//	TEMPLATE_WALL0046
+	(void)new TemplateTypeClass(WALL0047);			//	TEMPLATE_WALL0047
+	(void)new TemplateTypeClass(WALL0048);			//	TEMPLATE_WALL0048
+	(void)new TemplateTypeClass(WALL0049);			//	TEMPLATE_WALL0049
+	(void)new TemplateTypeClass(Bridge1h);			//	TEMPLATE_BRIDGE1H
+	(void)new TemplateTypeClass(Bridge2h);			//	TEMPLATE_BRIDGE2H
+
+	(void)new TemplateTypeClass(Bridge1ax);		//	TEMPLATE_BRIDGE_1AX
+	(void)new TemplateTypeClass(Bridge2ax);		//	TEMPLATE_BRIDGE_2AX
+	(void)new TemplateTypeClass(Bridge1x);			//	TEMPLATE_BRIDGE1X
+	(void)new TemplateTypeClass(Bridge2x);			//	TEMPLATE_BRIDGE2X
+
+	(void)new TemplateTypeClass(Xtra0001);			//	TEMPLATE_XTRA0001
+	(void)new TemplateTypeClass(Xtra0002);			//	TEMPLATE_XTRA0002
+	(void)new TemplateTypeClass(Xtra0003);			//	TEMPLATE_XTRA0003
+	(void)new TemplateTypeClass(Xtra0004);			//	TEMPLATE_XTRA0004
+	(void)new TemplateTypeClass(Xtra0005);			//	TEMPLATE_XTRA0005
+	(void)new TemplateTypeClass(Xtra0006);			//	TEMPLATE_XTRA0006
+	(void)new TemplateTypeClass(Xtra0007);			//	TEMPLATE_XTRA0007
+	(void)new TemplateTypeClass(Xtra0008);			//	TEMPLATE_XTRA0008
+	(void)new TemplateTypeClass(Xtra0009);			//	TEMPLATE_XTRA0009
+	(void)new TemplateTypeClass(Xtra0010);			//	TEMPLATE_XTRA0010
+	(void)new TemplateTypeClass(Xtra0011);			//	TEMPLATE_XTRA0011
+	(void)new TemplateTypeClass(Xtra0012);			//	TEMPLATE_XTRA0012
+	(void)new TemplateTypeClass(Xtra0013);			//	TEMPLATE_XTRA0013
+	(void)new TemplateTypeClass(Xtra0014);			//	TEMPLATE_XTRA0014
+	(void)new TemplateTypeClass(Xtra0015);			//	TEMPLATE_XTRA0015
+	(void)new TemplateTypeClass(Xtra0016);			//	TEMPLATE_XTRA0016
+
+#ifdef FIXIT_ANTS
+	(void)new TemplateTypeClass(AntHill);			//	TEMPLATE_ROAD36
+#endif
+}
+
+
+
+void TemplateTypeClass::Init_Heap(void)
+{
+	/*
+	**	These template type class objects must be allocated in the exact order that they
+	**	are specified in the TemplateType enumeration. This is necessary because the heap
+	**	allocation block index serves double duty as the type number index.
+	*/
+	(void)new TemplateTypeClass(Clear);				// TEMPLATE_CLEAR1
+	(void)new TemplateTypeClass(Water);				// TEMPLATE_WATER
+	(void)new TemplateTypeClass(Water2);			// TEMPLATE_WATER2
+	(void)new TemplateTypeClass(Shore01);			// TEMPLATE_SHORE1
+	(void)new TemplateTypeClass(Shore02);			// TEMPLATE_SHORE2
+	(void)new TemplateTypeClass(Shore03);			// TEMPLATE_SHORE3
+	(void)new TemplateTypeClass(Shore04);			// TEMPLATE_SHORE4
+	(void)new TemplateTypeClass(Shore05);			// TEMPLATE_SHORE5
+	(void)new TemplateTypeClass(Shore06);			// TEMPLATE_SHORE6
+	(void)new TemplateTypeClass(Shore07);			// TEMPLATE_SHORE7
+	(void)new TemplateTypeClass(Shore08);			// TEMPLATE_SHORE8
+	(void)new TemplateTypeClass(Shore09);			// TEMPLATE_SHORE9
+	(void)new TemplateTypeClass(Shore10);			// TEMPLATE_SHORE10
+	(void)new TemplateTypeClass(Shore11);			//	TEMPLATE_SHORE11
+	(void)new TemplateTypeClass(Shore12);			// TEMPLATE_SHORE12
+	(void)new TemplateTypeClass(Shore13);			// TEMPLATE_SHORE13
+	(void)new TemplateTypeClass(Shore14);			// TEMPLATE_SHORE14
+	(void)new TemplateTypeClass(Shore15);			// TEMPLATE_SHORE15
+	(void)new TemplateTypeClass(Shore16);			//	TEMPLATE_SHORE16
+	(void)new TemplateTypeClass(Shore17);			//	TEMPLATE_SHORE17
+	(void)new TemplateTypeClass(Shore18);			//	TEMPLATE_SHORE18
+	(void)new TemplateTypeClass(Shore19);			// TEMPLATE_SHORE19
+	(void)new TemplateTypeClass(Shore20);			// TEMPLATE_SHORE20
+	(void)new TemplateTypeClass(Shore21);			// TEMPLATE_SHORE21
+	(void)new TemplateTypeClass(Shore22);			//	TEMPLATE_SHORE22
+	(void)new TemplateTypeClass(Shore23);			// TEMPLATE_SHORE23
+	(void)new TemplateTypeClass(Shore24);			//	TEMPLATE_SHORE24
+	(void)new TemplateTypeClass(Shore25);			//	TEMPLATE_SHORE25
+	(void)new TemplateTypeClass(Shore26);			//	TEMPLATE_SHORE26
+	(void)new TemplateTypeClass(Shore27);			//	TEMPLATE_SHORE27
+	(void)new TemplateTypeClass(Shore28);			//	TEMPLATE_SHORE28
+	(void)new TemplateTypeClass(Shore29);			//	TEMPLATE_SHORE29
+	(void)new TemplateTypeClass(Shore30);			//	TEMPLATE_SHORE30
+	(void)new TemplateTypeClass(Shore31);			//	TEMPLATE_SHORE31
+	(void)new TemplateTypeClass(Shore32);			// TEMPLATE_SHORE32
+	(void)new TemplateTypeClass(Shore33);			// TEMPLATE_SHORE33
+	(void)new TemplateTypeClass(Shore34);			//	TEMPLATE_SHORE34
+	(void)new TemplateTypeClass(Shore35);			//	TEMPLATE_SHORE35
+	(void)new TemplateTypeClass(Shore36);			//	TEMPLATE_SHORE36
+	(void)new TemplateTypeClass(Shore37);			//	TEMPLATE_SHORE37
+	(void)new TemplateTypeClass(Shore38);			//	TEMPLATE_SHORE38
+	(void)new TemplateTypeClass(Shore39);			//	TEMPLATE_SHORE39
+	(void)new TemplateTypeClass(Shore40);			//	TEMPLATE_SHORE40
+	(void)new TemplateTypeClass(Shore41);			//	TEMPLATE_SHORE41
+	(void)new TemplateTypeClass(Shore42);			//	TEMPLATE_SHORE42
+	(void)new TemplateTypeClass(Shore43);			//	TEMPLATE_SHORE43
+	(void)new TemplateTypeClass(Shore44);			//	TEMPLATE_SHORE44
+	(void)new TemplateTypeClass(Shore45);			//	TEMPLATE_SHORE45
+	(void)new TemplateTypeClass(Shore46);			//	TEMPLATE_SHORE46
+	(void)new TemplateTypeClass(Shore47);			//	TEMPLATE_SHORE47
+	(void)new TemplateTypeClass(Shore48);			//	TEMPLATE_SHORE48
+	(void)new TemplateTypeClass(Shore49);			//	TEMPLATE_SHORE49
+	(void)new TemplateTypeClass(Shore50);			//	TEMPLATE_SHORE50
+	(void)new TemplateTypeClass(Shore51);			//	TEMPLATE_SHORE51
+	(void)new TemplateTypeClass(Shore52);			//	TEMPLATE_SHORE52
+	(void)new TemplateTypeClass(Shore53);			//	TEMPLATE_SHORE53
+	(void)new TemplateTypeClass(Shore54);			//	TEMPLATE_SHORE54
+	(void)new TemplateTypeClass(Shore55);			//	TEMPLATE_SHORE55
+	(void)new TemplateTypeClass(Shore56);			//	TEMPLATE_SHORE56
+	(void)new TemplateTypeClass(ShoreCliff01);	//	TEMPLATE_SHORECLIFF01
+	(void)new TemplateTypeClass(ShoreCliff02);	//	TEMPLATE_SHORECLIFF02
+	(void)new TemplateTypeClass(ShoreCliff03);	//	TEMPLATE_SHORECLIFF03
+	(void)new TemplateTypeClass(ShoreCliff04);	//	TEMPLATE_SHORECLIFF04
+	(void)new TemplateTypeClass(ShoreCliff05);	//	TEMPLATE_SHORECLIFF05
+	(void)new TemplateTypeClass(ShoreCliff06);	//	TEMPLATE_SHORECLIFF06
+	(void)new TemplateTypeClass(ShoreCliff07);	//	TEMPLATE_SHORECLIFF07
+	(void)new TemplateTypeClass(ShoreCliff08);	//	TEMPLATE_SHORECLIFF08
+	(void)new TemplateTypeClass(ShoreCliff09);	//	TEMPLATE_SHORECLIFF09
+	(void)new TemplateTypeClass(ShoreCliff10);	//	TEMPLATE_SHORECLIFF10
+	(void)new TemplateTypeClass(ShoreCliff11);	//	TEMPLATE_SHORECLIFF11
+	(void)new TemplateTypeClass(ShoreCliff12);	//	TEMPLATE_SHORECLIFF12
+	(void)new TemplateTypeClass(ShoreCliff13);	//	TEMPLATE_SHORECLIFF13
+	(void)new TemplateTypeClass(ShoreCliff14);	//	TEMPLATE_SHORECLIFF14
+	(void)new TemplateTypeClass(ShoreCliff15);	//	TEMPLATE_SHORECLIFF15
+	(void)new TemplateTypeClass(ShoreCliff16);	//	TEMPLATE_SHORECLIFF16
+	(void)new TemplateTypeClass(ShoreCliff17);	//	TEMPLATE_SHORECLIFF17
+	(void)new TemplateTypeClass(ShoreCliff18);	//	TEMPLATE_SHORECLIFF18
+	(void)new TemplateTypeClass(ShoreCliff19);	//	TEMPLATE_SHORECLIFF19
+	(void)new TemplateTypeClass(ShoreCliff20);	//	TEMPLATE_SHORECLIFF20
+	(void)new TemplateTypeClass(ShoreCliff21);	//	TEMPLATE_SHORECLIFF21
+	(void)new TemplateTypeClass(ShoreCliff22);	//	TEMPLATE_SHORECLIFF22
+	(void)new TemplateTypeClass(ShoreCliff23);	//	TEMPLATE_SHORECLIFF23
+	(void)new TemplateTypeClass(ShoreCliff24);	//	TEMPLATE_SHORECLIFF24
+	(void)new TemplateTypeClass(ShoreCliff25);	//	TEMPLATE_SHORECLIFF25
+	(void)new TemplateTypeClass(ShoreCliff26);	//	TEMPLATE_SHORECLIFF26
+	(void)new TemplateTypeClass(ShoreCliff27);	//	TEMPLATE_SHORECLIFF27
+	(void)new TemplateTypeClass(ShoreCliff28);	//	TEMPLATE_SHORECLIFF28
+	(void)new TemplateTypeClass(ShoreCliff29);	//	TEMPLATE_SHORECLIFF29
+	(void)new TemplateTypeClass(ShoreCliff30);	//	TEMPLATE_SHORECLIFF30
+	(void)new TemplateTypeClass(ShoreCliff31);	//	TEMPLATE_SHORECLIFF31
+	(void)new TemplateTypeClass(ShoreCliff32);	//	TEMPLATE_SHORECLIFF32
+	(void)new TemplateTypeClass(ShoreCliff33);	//	TEMPLATE_SHORECLIFF33
+	(void)new TemplateTypeClass(ShoreCliff34);	//	TEMPLATE_SHORECLIFF34
+	(void)new TemplateTypeClass(ShoreCliff35);	//	TEMPLATE_SHORECLIFF35
+	(void)new TemplateTypeClass(ShoreCliff36);	//	TEMPLATE_SHORECLIFF36
+	(void)new TemplateTypeClass(ShoreCliff37);	//	TEMPLATE_SHORECLIFF37
+	(void)new TemplateTypeClass(ShoreCliff38);	//	TEMPLATE_SHORECLIFF38
+	(void)new TemplateTypeClass(Boulder1);			//	TEMPLATE_BOULDER1
+	(void)new TemplateTypeClass(Boulder2);			//	TEMPLATE_BOULDER2
+	(void)new TemplateTypeClass(Boulder3);			//	TEMPLATE_BOULDER3
+	(void)new TemplateTypeClass(Boulder4);			// TEMPLATE_BOULDER4
+	(void)new TemplateTypeClass(Boulder5);			//	TEMPLATE_BOULDER5
+	(void)new TemplateTypeClass(Boulder6);			//	TEMPLATE_BOULDER6
+	(void)new TemplateTypeClass(Patch01);			//	TEMPLATE_PATCH1
+	(void)new TemplateTypeClass(Patch02);			//	TEMPLATE_PATCH2
+	(void)new TemplateTypeClass(Patch03);			//	TEMPLATE_PATCH3
+	(void)new TemplateTypeClass(Patch04);			//	TEMPLATE_PATCH4
+	(void)new TemplateTypeClass(Patch07);			//	TEMPLATE_PATCH7
+	(void)new TemplateTypeClass(Patch08);			//	TEMPLATE_PATCH8
+	(void)new TemplateTypeClass(Patch13);			//	TEMPLATE_PATCH13
+	(void)new TemplateTypeClass(Patch14);			//	TEMPLATE_PATCH14
+	(void)new TemplateTypeClass(Patch15);			//	TEMPLATE_PATCH15
+	(void)new TemplateTypeClass(River01);			//	TEMPLATE_RIVER1
+	(void)new TemplateTypeClass(River02);			//	TEMPLATE_RIVER2
+	(void)new TemplateTypeClass(River03);			//	TEMPLATE_RIVER3
+	(void)new TemplateTypeClass(River04);			//	TEMPLATE_RIVER4
+	(void)new TemplateTypeClass(River05);			//	TEMPLATE_RIVER5
+	(void)new TemplateTypeClass(River06);			//	TEMPLATE_RIVER6
+	(void)new TemplateTypeClass(River07);			//	TEMPLATE_RIVER7
+	(void)new TemplateTypeClass(River08);			//	TEMPLATE_RIVER8
+	(void)new TemplateTypeClass(River09);			//	TEMPLATE_RIVER9
+	(void)new TemplateTypeClass(River10);			//	TEMPLATE_RIVER10
+	(void)new TemplateTypeClass(River11);			//	TEMPLATE_RIVER11
+	(void)new TemplateTypeClass(River12);			//	TEMPLATE_RIVER12
+	(void)new TemplateTypeClass(River13);			//	TEMPLATE_RIVER13
+	(void)new TemplateTypeClass(Falls1);			//	TEMPLATE_FALLS1
+	(void)new TemplateTypeClass(Falls1a);			//	TEMPLATE_FALLS1A
+	(void)new TemplateTypeClass(Falls2);			//	TEMPLATE_FALLS2
+	(void)new TemplateTypeClass(Falls2a);			//	TEMPLATE_FALLS2A
+	(void)new TemplateTypeClass(Ford1);				//	TEMPLATE_FORD1
+	(void)new TemplateTypeClass(Ford2);				//	TEMPLATE_FORD2
+	(void)new TemplateTypeClass(Bridge1);			//	TEMPLATE_BRIDGE1
+	(void)new TemplateTypeClass(Bridge1d);			//	TEMPLATE_BRIDGE1D
+	(void)new TemplateTypeClass(Bridge2);			//	TEMPLATE_BRIDGE2
+	(void)new TemplateTypeClass(Bridge2d);			//	TEMPLATE_BRIDGE2D
+	(void)new TemplateTypeClass(Slope01);			//	TEMPLATE_SLOPE1
+	(void)new TemplateTypeClass(Slope02);			//	TEMPLATE_SLOPE2
+	(void)new TemplateTypeClass(Slope03);			//	TEMPLATE_SLOPE3
+	(void)new TemplateTypeClass(Slope04);			//	TEMPLATE_SLOPE4
+	(void)new TemplateTypeClass(Slope05);			//	TEMPLATE_SLOPE5
+	(void)new TemplateTypeClass(Slope06);			//	TEMPLATE_SLOPE6
+	(void)new TemplateTypeClass(Slope07);			//	TEMPLATE_SLOPE7
+	(void)new TemplateTypeClass(Slope08);			//	TEMPLATE_SLOPE8
+	(void)new TemplateTypeClass(Slope09);			//	TEMPLATE_SLOPE9
+	(void)new TemplateTypeClass(Slope10);			//	TEMPLATE_SLOPE10
+	(void)new TemplateTypeClass(Slope11);			//	TEMPLATE_SLOPE11
+	(void)new TemplateTypeClass(Slope12);			//	TEMPLATE_SLOPE12
+	(void)new TemplateTypeClass(Slope13);			//	TEMPLATE_SLOPE13
+	(void)new TemplateTypeClass(Slope14);			//	TEMPLATE_SLOPE14
+	(void)new TemplateTypeClass(Slope15);			//	TEMPLATE_SLOPE15
+	(void)new TemplateTypeClass(Slope16);			//	TEMPLATE_SLOPE16
+	(void)new TemplateTypeClass(Slope17);			//	TEMPLATE_SLOPE17
+	(void)new TemplateTypeClass(Slope18);			//	TEMPLATE_SLOPE18
+	(void)new TemplateTypeClass(Slope19);			//	TEMPLATE_SLOPE19
+	(void)new TemplateTypeClass(Slope20);			//	TEMPLATE_SLOPE20
+	(void)new TemplateTypeClass(Slope21);			//	TEMPLATE_SLOPE21
+	(void)new TemplateTypeClass(Slope22);			//	TEMPLATE_SLOPE22
+	(void)new TemplateTypeClass(Slope23);			//	TEMPLATE_SLOPE23
+	(void)new TemplateTypeClass(Slope24);			//	TEMPLATE_SLOPE24
+	(void)new TemplateTypeClass(Slope25);			//	TEMPLATE_SLOPE25
+	(void)new TemplateTypeClass(Slope26);			//	TEMPLATE_SLOPE26
+	(void)new TemplateTypeClass(Slope27);			//	TEMPLATE_SLOPE27
+	(void)new TemplateTypeClass(Slope28);			//	TEMPLATE_SLOPE28
+	(void)new TemplateTypeClass(Slope29);			//	TEMPLATE_SLOPE29
+	(void)new TemplateTypeClass(Slope30);			//	TEMPLATE_SLOPE30
+	(void)new TemplateTypeClass(Slope31);			//	TEMPLATE_SLOPE31
+	(void)new TemplateTypeClass(Slope32);			//	TEMPLATE_SLOPE32
+	(void)new TemplateTypeClass(Slope33);			//	TEMPLATE_SLOPE33
+	(void)new TemplateTypeClass(Slope34);			//	TEMPLATE_SLOPE34
+	(void)new TemplateTypeClass(Slope35);			//	TEMPLATE_SLOPE35
+	(void)new TemplateTypeClass(Slope36);			//	TEMPLATE_SLOPE36
+	(void)new TemplateTypeClass(Slope37);			//	TEMPLATE_SLOPE37
+	(void)new TemplateTypeClass(Slope38);			//	TEMPLATE_SLOPE38
+	(void)new TemplateTypeClass(Road01);			//	TEMPLATE_ROAD1
+	(void)new TemplateTypeClass(Road02);			//	TEMPLATE_ROAD2
+	(void)new TemplateTypeClass(Road03);			//	TEMPLATE_ROAD3
+	(void)new TemplateTypeClass(Road04);			//	TEMPLATE_ROAD4
+	(void)new TemplateTypeClass(Road05);			//	TEMPLATE_ROAD5
+	(void)new TemplateTypeClass(Road06);			//	TEMPLATE_ROAD6
+	(void)new TemplateTypeClass(Road07);			//	TEMPLATE_ROAD7
+	(void)new TemplateTypeClass(Road08);			//	TEMPLATE_ROAD8
+	(void)new TemplateTypeClass(Road09);			//	TEMPLATE_ROAD9
+	(void)new TemplateTypeClass(Road10);			//	TEMPLATE_ROAD10
+	(void)new TemplateTypeClass(Road11);			//	TEMPLATE_ROAD11
+	(void)new TemplateTypeClass(Road12);			//	TEMPLATE_ROAD12
+	(void)new TemplateTypeClass(Road13);			//	TEMPLATE_ROAD13
+	(void)new TemplateTypeClass(Road14);			//	TEMPLATE_ROAD14
+	(void)new TemplateTypeClass(Road15);			//	TEMPLATE_ROAD15
+	(void)new TemplateTypeClass(Road16);			//	TEMPLATE_ROAD16
+	(void)new TemplateTypeClass(Road17);			//	TEMPLATE_ROAD17
+	(void)new TemplateTypeClass(Road18);			//	TEMPLATE_ROAD18
+	(void)new TemplateTypeClass(Road19);			//	TEMPLATE_ROAD19
+	(void)new TemplateTypeClass(Road20);			//	TEMPLATE_ROAD20
+	(void)new TemplateTypeClass(Road21);			//	TEMPLATE_ROAD21
+	(void)new TemplateTypeClass(Road22);			//	TEMPLATE_ROAD22
+	(void)new TemplateTypeClass(Road23);			//	TEMPLATE_ROAD23
+	(void)new TemplateTypeClass(Road24);			//	TEMPLATE_ROAD24
+	(void)new TemplateTypeClass(Road25);			//	TEMPLATE_ROAD25
+	(void)new TemplateTypeClass(Road26);			//	TEMPLATE_ROAD26
+	(void)new TemplateTypeClass(Road27);			//	TEMPLATE_ROAD27
+	(void)new TemplateTypeClass(Road28);			//	TEMPLATE_ROAD28
+	(void)new TemplateTypeClass(Road29);			//	TEMPLATE_ROAD29
+	(void)new TemplateTypeClass(Road30);			//	TEMPLATE_ROAD30
+	(void)new TemplateTypeClass(Road31);			//	TEMPLATE_ROAD31
+	(void)new TemplateTypeClass(Road32);			//	TEMPLATE_ROAD32
+	(void)new TemplateTypeClass(Road33);			//	TEMPLATE_ROAD33
+	(void)new TemplateTypeClass(Road34);			//	TEMPLATE_ROAD34
+	(void)new TemplateTypeClass(Road35);			//	TEMPLATE_ROAD35
+	(void)new TemplateTypeClass(Road36);			//	TEMPLATE_ROAD36
+
+	/*
+	**	Separate out the list of new operator calls. Watcom bombs
+	**	if they are kept together.
+	*/
+	_Watcom_Ugh_Hack();
+}
+
+
+/***********************************************************************************************
+ * TemplateTypeClass::Land_Type -- Determines land type from template and icon number.         *
+ *                                                                                             *
+ *    This routine will convert the specified icon number into the appropriate land type. The  *
+ *    land type can be determined from the embedded colors in the "control template" section   *
+ *    of the original art file. This control information is encoded into the icon data file    *
+ *    to be retrieved and interpreted as the program sees fit. The engine only recognizes      *
+ *    the first 16 colors as control colors, so the control map color value serves as an       *
+ *    index into a simple lookup table.                                                        *
+ *                                                                                             *
+ * INPUT:   icon  -- The icon number within this template that is to be examined and used      *
+ *                   to determine the land type.                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the land type that corresponds to the icon number specified.          *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   12/12/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+LandType TemplateTypeClass::Land_Type(int icon) const
+{
+	IconsetClass const * icontrol = (IconsetClass const *)Get_Image_Data();
+
+	if (icontrol != NULL) {
+		unsigned char const * map = icontrol->Control_Map();
+		if (map != NULL) {
+			static LandType _land[16] = {
+				LAND_CLEAR,
+				LAND_CLEAR,
+				LAND_CLEAR,
+				LAND_CLEAR,			// Clear
+				LAND_CLEAR,
+				LAND_CLEAR,
+				LAND_BEACH,			// Beach
+				LAND_CLEAR,
+				LAND_ROCK,			// Rock
+				LAND_ROAD,			// Road
+				LAND_WATER,			// Water
+				LAND_RIVER,			//	River
+				LAND_CLEAR,
+				LAND_CLEAR,
+				LAND_ROUGH,			// Rough
+				LAND_CLEAR,
+			};
+
+			return(_land[map[icon % (icontrol->Map_Width() * icontrol->Map_Height())]]);
+		}
+	}
+	return(LAND_CLEAR);
+}
+
+
+/***********************************************************************************************
+ * TemplateTypeClass::From_Name -- Determine template from ASCII name.                         *
+ *                                                                                             *
+ *    This routine is used to determine the template number given only                         *
+ *    an ASCII representation. The scenario loader uses this routine                           *
+ *    to construct the map from the INI control file.                                          *
+ *                                                                                             *
+ * INPUT:   name  -- Pointer to the ASCII name of the template.                                *
+ *                                                                                             *
+ * OUTPUT:  Returns with the template number. If the name had no match,                        *
+ *          then returns with TEMPLATE_NONE.                                                   *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/23/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+TemplateType TemplateTypeClass::From_Name(char const * name)
+{
+	if (name != NULL) {
+		for (TemplateType index = TEMPLATE_FIRST; index < TEMPLATE_COUNT; index++) {
+			if (stricmp(As_Reference(index).IniName, name) == 0) {
+				return(index);
+			}
+		}
+	}
+	return(TEMPLATE_NONE);
+}
+
+
+/***********************************************************************************************
+ * TemplateTypeClass::Occupy_List -- Determines occupation list.                               *
+ *                                                                                             *
+ *    This routine is used to examine the template map and build an                            *
+ *    occupation list. This list is used to render a template cursor as                        *
+ *    well as placement of icon numbers.                                                       *
+ *                                                                                             *
+ * INPUT:   placement   -- Is this for placement legality checking only? The normal condition  *
+ *                         is for marking occupation flags.                                    *
+ *                                                                                             *
+ * OUTPUT:  Returns with a pointer to the template occupation list.                            *
+ *                                                                                             *
+ * WARNINGS:   The return pointer is valid only until the next time that                       *
+ *             this routine is called.                                                         *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/23/1994 JLB : Created.                                                                 *
+ *   12/12/1995 JLB : Optimized for direct access to iconset data.                             *
+ *=============================================================================================*/
+short const * TemplateTypeClass::Occupy_List(bool) const
+{
+	static short _occupy[13*8+5];
+	short	* ptr;
+
+	IconsetClass const * iconset = (IconsetClass const *)Get_Image_Data();
+	unsigned char const * map = iconset->Map_Data();
+
+	ptr = &_occupy[0];
+	for (int index = 0; index < Width * Height; index++) {
+		if (*map++ != 0xFF) {
+			*ptr++ = (index % Width) + ((index / Width)*MAP_CELL_W);
+		}
+	}
+	*ptr = REFRESH_EOL;
+
+	return((short const *)&_occupy[0]);
+}
+
+
+/***********************************************************************************************
+ * TemplateTypeClass::Init -- Loads graphic data for templates.                                *
+ *                                                                                             *
+ *    This routine loads the template graphic data for all the template                        *
+ *    type supported for the specified theater. This routine is called                         *
+ *    whenever the theater for the scenario is first determined.                               *
+ *                                                                                             *
+ * INPUT:   theater  -- The theater that the template data is to be                            *
+ *                      loaded for.                                                            *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   This routine goes to disk!                                                      *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/23/1994 JLB : Created.                                                                 *
+ *   06/02/1994 JLB : Only handles iconset loading now (as it should).                         *
+ *=============================================================================================*/
+void TemplateTypeClass::Init(TheaterType theater)
+{
+	char fullname[_MAX_FNAME+_MAX_EXT];	// Fully constructed iconset name.
+	void const * ptr;		// Working loaded iconset pointer.
+
+	for (TemplateType index = TEMPLATE_FIRST; index < TEMPLATE_COUNT; index++) {
+		TemplateTypeClass	const & tplate = As_Reference(index);
+
+		((void const *&)tplate.ImageData) = NULL;
+		if (tplate.Theater & (1<<theater)) {
+			_makepath(fullname, NULL, NULL, tplate.IniName, Theaters[theater].Suffix);
+			ptr = MFCD::Retrieve(fullname);
+			((void const *&)tplate.ImageData) = ptr;
+
+#ifdef WIN32
+			Register_Icon_Set((void*)ptr, TRUE);		//Register icon set for video memory caching
+#endif
+
+			((unsigned char &)tplate.Width) = Get_IconSet_MapWidth(ptr);
+			((unsigned char &)tplate.Height) = Get_IconSet_MapHeight(ptr);
+		}
+	}
+}
+
+
+#ifdef SCENARIO_EDITOR
+/***********************************************************************************************
+ * TemplateTypeClass::Display -- Displays a generic representation of template.                *
+ *                                                                                             *
+ *    This routine is used to display a generic view of the template                           *
+ *    object. This is necessary for selection in the scenario editor.                          *
+ *                                                                                             *
+ * INPUT:   x,y   -- The coordinates to center the display about.                              *
+ *                                                                                             *
+ *          window-- The window to base the coordinates upon.                                  *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/23/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void TemplateTypeClass::Display(int x, int y, WindowNumberType window, HousesType ) const
+{
+	int	w,h;
+	int	index;
+	bool	scale;		// Should the template be half sized?
+
+	w = Bound(Width, 1, 13);
+	h = Bound(Height, 1, 8);
+	scale = (w > 3 || h > 3);
+	if (scale) {
+		x -= (w * ICON_PIXEL_W) / 4;
+		y -= (h * ICON_PIXEL_H) / 4;
+	} else {
+		x -= (w * ICON_PIXEL_W) / 2;
+		y -= (h * ICON_PIXEL_H) / 2;
+	}
+	x += WindowList[window][WINDOWX];
+	y += WindowList[window][WINDOWY];
+
+	IconsetClass const * iconset = (IconsetClass const *)Get_Image_Data();
+	unsigned char const * map = iconset->Map_Data();
+
+	for (index = 0; index < w*h; index++) {
+		if (map[index] != 0xFF) {
+			HidPage.Draw_Stamp(iconset, index, 0, 0, NULL, WINDOW_MAIN);
+			if (scale) {
+
+				HidPage.Scale((*LogicPage), 0, 0,
+					x + ((index % w)*(ICON_PIXEL_W/2)),
+					y + ((index / w)*(ICON_PIXEL_H/2)),
+					ICON_PIXEL_W, ICON_PIXEL_H,
+					ICON_PIXEL_W/2, ICON_PIXEL_H/2, (char *)NULL);
+
+			} else {
+				HidPage.Blit((*LogicPage), 0, 0, x + ((index % w)*(ICON_PIXEL_W)),
+					y + ((index / w)*(ICON_PIXEL_H)), ICON_PIXEL_W, ICON_PIXEL_H);
+			}
+		}
+	}
+}
+
+
+/***********************************************************************************************
+ * TemplateTypeClass::Prep_For_Add -- Prepares to add template to scenario.                    *
+ *                                                                                             *
+ *    This routine prepares a list of template objects so that the                             *
+ *    scenario editor can use this list to display a dialog box. The                           *
+ *    selection of a template object will allow its placement upon the                         *
+ *    map.                                                                                     *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/23/1994 JLB : Created.                                                                 *
+ *   05/28/1994 JLB : Only handles real templates now.                                         *
+ *   06/04/1994 JLB : Uses map editing interface functions.                                    *
+ *=============================================================================================*/
+void TemplateTypeClass::Prep_For_Add(void)
+{
+	for (TemplateType index = TEMPLATE_CLEAR1; index < TEMPLATE_COUNT; index++) {
+		if (As_Reference(index).Get_Image_Data()) {
+			Map.Add_To_List(&As_Reference(index));
+		}
+	}
+}
+#endif
+
+
+/***********************************************************************************************
+ * TemplateTypeClass::Create_And_Place -- Creates and places a template object on the map.     *
+ *                                                                                             *
+ *    This support routine is used by the scenario editor to add a template object to the map  *
+ *    and to the game.                                                                         *
+ *                                                                                             *
+ * INPUT:   cell  -- The cell to place the template object.                                    *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the template object placed successfully?                                 *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/28/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool TemplateTypeClass::Create_And_Place(CELL cell, HousesType ) const
+{
+	if (new TemplateClass(Type, cell)) {
+		return(true);
+	}
+	return(false);
+}
+
+
+/***********************************************************************************************
+ * TemplateTypeClass::Create_One_Of -- Creates an object of this template type.                *
+ *                                                                                             *
+ *    This routine will create an object of this type. For certain template objects, such      *
+ *    as walls, it is actually created as a building. The "building" wall is converted into    *
+ *    a template at the moment of placing down on the map.                                     *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with a pointer to the appropriate object for this template type.           *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/18/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+ObjectClass * TemplateTypeClass::Create_One_Of(HouseClass *) const
+{
+	return(new TemplateClass(Type, -1));
+}
+
+
+/***********************************************************************************************
+ * TemplateTypeClass::One_Time -- Performs one-time initialization                             *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/12/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void TemplateTypeClass::One_Time(void)
+{
+}
+
+
+/***********************************************************************************************
+ * TemplateTypeClass::As_Reference -- Fetches a reference to the template specified.           *
+ *                                                                                             *
+ *    This will return a reference to the TemplateTypeClass requested.                         *
+ *                                                                                             *
+ * INPUT:   type  -- The template type to fetch a reference to.                                *
+ *                                                                                             *
+ * OUTPUT:  Returns with a reference to the template type class specified.                     *
+ *                                                                                             *
+ * WARNINGS:   Be sure to pass a valid type parameter. This routine doesn't check it for       *
+ *             legality.                                                                       *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/03/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+TemplateTypeClass & TemplateTypeClass::As_Reference(TemplateType type)
+{
+	return(*TemplateTypes.Ptr(type));
+}
+
+
+COORDINATE TemplateTypeClass::Coord_Fixup(COORDINATE coord) const
+{
+	return Coord_Whole(coord);
+}

+ 720 - 0
CODE/CDFILE.CPP

@@ -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 - 0
CODE/CDFILE.H

@@ -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 - 0
CODE/CELL.CPP

@@ -0,0 +1,3014 @@
+/*
+**	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.CPP 4     3/14/97 1:15p Joe_b $ */
+/***********************************************************************************************
+ ***              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.CPP                                                     *
+ *                                                                                             *
+ *                   Programmer : Joe L. Bostic                                                *
+ *                                                                                             *
+ *                   Start Date : April 29, 1994                                               *
+ *                                                                                             *
+ *                  Last Update : October 6, 1996 [JLB]                                        *
+ *                                                                                             *
+ *---------------------------------------------------------------------------------------------*
+ * Functions:                                                                                  *
+ *   CellClass::Adjacent_Cell -- Determines the adjacent cell according to facing.             *
+ *   CellClass::Adjust_Threat -- Allows adjustment of threat at cell level                     *
+ *   CellClass::Can_Tiberium_Germinate -- Determines if Tiberium can begin growth in the cell. *
+ *   CellClass::Can_Tiberium_Grow -- Determines if Tiberium can grow in this cell.             *
+ *   CellClass::Can_Tiberium_Spread -- Determines if Tiberium can spread from this cell.       *
+ *   CellClass::CellClass -- Constructor for cell objects.                                     *
+ *   CellClass::Cell_Building -- Return with building at specified cell.                       *
+ *   CellClass::Cell_Color   -- Determine what radar color to use for this cell.               *
+ *   CellClass::Cell_Coord -- Returns the coordinate of this cell.                             *
+ *   CellClass::Cell_Find_Object -- Returns ptr to RTTI type occupying cell                    *
+ *   CellClass::Cell_Infantry -- Returns with pointer of first infantry unit.                  *
+ *   CellClass::Cell_Object -- Returns with clickable object in cell.                          *
+ *   CellClass::Cell_Techno -- Return with the unit/building at specified cell.                *
+ *   CellClass::Cell_Terrain -- Determines terrain object in cell.                             *
+ *   CellClass::Cell_Unit -- Returns with pointer to unit occupying cell.                      *
+ *   CellClass::Cell_Vessel -- Returns with pointer to a vessel located in the cell.           *
+ *   CellClass::Clear_Icon -- Calculates what the clear icon number should be.                 *
+ *   CellClass::Closest_Free_Spot -- returns free spot closest to given coord                  *
+ *   CellClass::Concrete_Calc -- Calculates the concrete icon to use for the cell.             *
+ *   CellClass::Draw_It -- Draws the cell imagery at the location specified.                   *
+ *   CellClass::Flag_Place -- Places a house flag down on the cell.                            *
+ *   CellClass::Flag_Remove -- Removes the house flag from the cell.                           *
+ *   CellClass::Goodie_Check -- Performs crate discovery logic.                                *
+ *   CellClass::Grow_Tiberium -- Grows the tiberium in the cell.                               *
+ *   CellClass::Incoming -- Causes objects in cell to "run for cover".                         *
+ *   CellClass::Is_Bridge_Here -- Checks to see if this is a bridge occupied cell.             *
+ *   CellClass::Is_Clear_To_Build -- Determines if cell can be built upon.                     *
+ *   CellClass::Is_Clear_To_Move -- Determines if the cell is generally clear for travel       *
+ *   CellClass::Occupy_Down -- Flag occupation of specified cell.                              *
+ *   CellClass::Occupy_Up -- Removes occupation flag from the specified cell.                  *
+ *   CellClass::Overlap_Down -- This routine is used to mark a cell as being spilled over (over*
+ *   CellClass::Overlap_Unit -- Marks cell as being overlapped by unit.                        *
+ *   CellClass::Overlap_Up -- Removes overlap flag for the cell.                               *
+ *   CellClass::Read -- Reads a particular cell value from a save game file.                   *
+ *   CellClass::Recalc_Attributes -- Recalculates the ground type attributes for the cell.     *
+ *   CellClass::Redraw_Objects -- Redraws all objects overlapping this cell.                   *
+ *   CellClass::Reduce_Tiberium -- Reduces the tiberium in the cell by the amount specified.   *
+ *   CellClass::Reduce_Wall -- Damages a wall, if damage is high enough.                       *
+ *   CellClass::Reserve_Cell -- Marks a cell as being occupied by the specified unit ID.       *
+ *   CellClass::Shimmer -- Causes all objects in the cell to shimmer.                          *
+ *   CellClass::Spot_Index -- returns cell sub-coord index for given COORDINATE                *
+ *   CellClass::Spread_Tiberium -- Spread Tiberium from this cell to an adjacent cell.         *
+ *   CellClass::Tiberium_Adjust -- Adjust the look of the Tiberium for smooth.                 *
+ *   CellClass::Wall_Update -- Updates the imagery for wall objects in cell.                   *
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+#include	"function.h"
+#include	"vortex.h"
+
+/***********************************************************************************************
+ * CellClass::CellClass -- Constructor for cell objects.                                       *
+ *                                                                                             *
+ *    A cell object is constructed into an empty state. It contains no specific objects,       *
+ *    templates, or overlays.                                                                  *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/09/1994 JLB : Created.                                                                 *
+ *   02/20/1996 JLB : Uses initializer list.                                                   *
+ *=============================================================================================*/
+CellClass::CellClass(void) :
+	ID(Map.ID(this)),
+	IsPlot(false),
+	IsCursorHere(false),
+	IsMapped(false),
+	IsVisible(false),
+	IsWaypoint(false),
+	IsRadarCursor(false),
+	IsFlagged(false),
+	IsToShroud(false),
+	Jammed(0),
+	Trigger(NULL),
+	TType(TEMPLATE_NONE),
+	TIcon(0),
+	Overlay(OVERLAY_NONE),
+	OverlayData(0),
+	Smudge(SMUDGE_NONE),
+	SmudgeData(0),
+	Owner(HOUSE_NONE),
+	InfType(HOUSE_NONE),
+	OccupierPtr(0),
+	Land(LAND_CLEAR)
+{
+	for (int zone = MZONE_FIRST; zone < MZONE_COUNT; zone++) {
+		Zones[zone] = 0;
+	}
+	Flag.Composite = 0;
+	for (int index = 0; index < ARRAY_SIZE(Overlapper); index++) {
+		Overlapper[index] = 0;
+	}
+}
+
+
+/***********************************************************************************************
+ * CellClass::Cell_Color   -- Determine what radar color to use for this cell.                 *
+ *                                                                                             *
+ *    Use this routine to determine what radar color to render a radar                         *
+ *    pixel with. This routine is called many many times to render the                         *
+ *    radar map, so it must be fast.                                                           *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the color to display the radar pixel with.                            *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   03/01/1994 JLB : Created.                                                                 *
+ *   04/30/1994 JLB : Converted to member function.                                            *
+ *   05/31/1994 JLB : Takes into account any stealth characteristics of object.                *
+ *=============================================================================================*/
+int CellClass::Cell_Color(bool override) const
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+
+	BuildingClass * object = Cell_Building();
+	if (object && !object->Class->IsInvisible) {
+		return(ColorRemaps[object->House->RemapColor].Bar);
+	}
+
+	if (override) {
+		return(TBLACK);
+	}
+	if (LastTheater == THEATER_SNOW) {
+		return(::SnowColor[Land_Type()]);
+	} else {
+		return(::GroundColor[Land_Type()]);
+	}
+}
+
+
+/***********************************************************************************************
+ * CellClass::Cell_Techno -- Return with the unit/building at specified cell.                  *
+ *                                                                                             *
+ *    Returns an object located in the cell. If there is a                                     *
+ *    building present, it returns a pointer to that, otherwise it returns                     *
+ *    a pointer to one of the units there. If nothing is present in the                        *
+ *    specified cell, then it returns NULL.                                                    *
+ *                                                                                             *
+ * INPUT:   x,y   -- Coordinate offset (from upper left corner) to use as an aid in selecting  *
+ *                   the desired object within the cell.                                       *
+ *                                                                                             *
+ * OUTPUT:  Returns a pointer to a building or unit located in cell. If                        *
+ *          nothing present, just returns NULL.                                                *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/05/1992 JLB : Created.                                                                 *
+ *   04/30/1994 JLB : Converted to member function.                                            *
+ *=============================================================================================*/
+TechnoClass * CellClass::Cell_Techno(int x, int y) const
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+
+	ObjectClass * object;
+	COORDINATE		click;			// Coordinate of click relative to cell corner.
+	TechnoClass * close = NULL;
+	long		distance = 0;	// Recorded closest distance.
+
+	/*
+	**	Create a coordinate value that represent the pixel location within the cell. This is
+	**	actually the lower significant bits (leptons) of a regular coordinate value.
+	*/
+	click = XY_Coord(Pixel_To_Lepton(x), Pixel_To_Lepton(y));
+
+	if (Cell_Occupier()) {
+		object = Cell_Occupier();
+		while (object) {
+			if (object->Is_Techno()) {
+				COORDINATE coord = Coord_Fraction(object->Center_Coord());
+				long dist = Distance(coord, click);
+				if (!close || dist < distance) {
+					close = (TechnoClass *)object;
+					distance = dist;
+				}
+			}
+			object = object->Next;
+		}
+	}
+	return(close);
+}
+
+
+/***************************************************************************
+ * CellClass::Cell_Find_Object -- Returns ptr to RTTI type occupying cell  *
+ *                                                                         *
+ * INPUT:		RTTIType the RTTI type we are searching for                 *
+ *                                                                         *
+ * OUTPUT:		none                                                        *
+ *                                                                         *
+ * WARNINGS:   none                                                        *
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   03/17/1995 PWG : Created.                                             *
+ *   06/12/1995 JLB : Returns object class pointer.                        *
+ *=========================================================================*/
+ObjectClass * CellClass::Cell_Find_Object(RTTIType rtti) const
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+	assert(rtti != RTTI_NONE);
+
+	ObjectClass * object = Cell_Occupier();
+
+	while (object != NULL) {
+		if (object->What_Am_I() == rtti) {
+			return(object);
+		}
+		object = object->Next;
+	}
+	return(NULL);
+}
+
+
+/***********************************************************************************************
+ * CellClass::Cell_Building -- Return with building at specified cell.                         *
+ *                                                                                             *
+ *    Given a cell, determine if there is a building associated                                *
+ *    and return with a pointer to this building.                                              *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with a pointer to the building associated with the                         *
+ *          cell. If there is no building associated, then NULL is                             *
+ *          returned.                                                                          *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/05/1992 JLB : Created.                                                                 *
+ *   04/30/1994 JLB : Converted to member function.                                            *
+ *=============================================================================================*/
+BuildingClass * CellClass::Cell_Building(void) const
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+
+	return((BuildingClass *)Cell_Find_Object(RTTI_BUILDING));
+}
+
+
+/***********************************************************************************************
+ * CellClass::Cell_Terrain -- Determines terrain object in cell.                               *
+ *                                                                                             *
+ *    This routine is used to determine the terrain object (if any) that                       *
+ *    overlaps this cell.                                                                      *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with a pointer to the terrain object that overlaps                         *
+ *          this cell. If there is no terrain object present, then NULL                        *
+ *          is returned.                                                                       *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/18/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+TerrainClass * CellClass::Cell_Terrain(void) const
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+
+	return((TerrainClass *)Cell_Find_Object(RTTI_TERRAIN));
+}
+
+
+/***********************************************************************************************
+ * CellClass::Cell_Object -- Returns with clickable object in cell.                            *
+ *                                                                                             *
+ *    This routine is used to determine which object is to be selected                         *
+ *    by a player click upon the cell. Not all objects that overlap the                        *
+ *    cell are selectable by the player. This routine sorts out which                          *
+ *    is which and returns with the appropriate object pointer.                                *
+ *                                                                                             *
+ * INPUT:   x,y   -- Coordinate (from upper left corner of cell) to use as a guide when        *
+ *                   selecting the object within the cell. This plays a role in those cases    *
+ *                   where several objects (such as infantry) exist within the same cell.      *
+ *                                                                                             *
+ * OUTPUT:  Returns with pointer to the object clickable within the                            *
+ *          cell. NULL is returned if there is no clickable object                             *
+ *          present.                                                                           *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/13/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+ObjectClass * CellClass::Cell_Object(int x, int y) const
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+
+	ObjectClass * ptr;
+
+	/*
+	**	Hack so that aircraft landed on helipads can still be selected if directly
+	**	clicked on.
+	*/
+	ptr = (ObjectClass *)Cell_Find_Object(RTTI_AIRCRAFT);
+	if (ptr) {
+		return(ptr);
+	}
+
+	ptr = Cell_Techno(x, y);
+	if (ptr) {
+		return(ptr);
+	}
+	ptr = Cell_Terrain();
+	if (ptr) return(ptr);
+	return(ptr);
+}
+
+
+/***********************************************************************************************
+ * CellClass::Redraw_Objects -- Redraws all objects overlapping this cell.                     *
+ *                                                                                             *
+ *    This is a low level routine that marks all objects that overlap this                     *
+ *    cell to be redrawn. It is necessary to call this routine whenever                        *
+ *    the underlying icon has to be redrawn.                                                   *
+ *                                                                                             *
+ * INPUT:   forced   -- Should this redraw be forced even if flags                             *
+ *                      indicate that it would be redundant?                                   *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/18/1994 JLB : Created.                                                                 *
+ *   06/20/1994 JLB : Simplified to use object pointers.                                       *
+ *   12/24/1994 JLB : Only checks if cell is in view and not flagged already.                  *
+ *=============================================================================================*/
+void CellClass::Redraw_Objects(bool forced)
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+
+	CELL	cell = Cell_Number();
+
+	if (Map.In_View(cell) && (forced || !Map.Is_Cell_Flagged(cell))) {
+
+		/*
+		**	Flag the icon to be redrawn.
+		*/
+		Map.Flag_Cell(cell);
+
+		/*
+		**	Flag the main object in the cell to be redrawn.
+		*/
+		if (Cell_Occupier() != NULL) {
+			ObjectClass * optr = Cell_Occupier();
+			while (optr != NULL && optr->IsActive) {
+
+#ifdef SORTDRAW
+				if (optr->Is_Techno() && ((TechnoClass *)optr)->Visual_Character() != VISUAL_NORMAL) {
+					optr->Mark(MARK_CHANGE);
+				}
+#else
+				optr->Mark(MARK_CHANGE);
+#endif
+				if (optr->Next != NULL && !optr->Next->IsActive) {
+					optr->Next = NULL;
+				}
+				optr = optr->Next;
+			}
+		}
+
+#ifdef SORTDRAW
+		/*
+		**	Flag any overlapping object in this cell to be redrawn.
+		*/
+		for (int index = 0; index < ARRAY_SIZE(Overlapper); index++) {
+			if (Overlapper[index]) {
+				assert(Overlapper[index]->IsActive);
+				if (Overlapper[index]->Is_Techno() && ((TechnoClass *)Overlapper[index])->Visual_Character() != VISUAL_NORMAL) {
+					Overlapper[index]->Mark(MARK_CHANGE);
+				}
+			}
+		}
+#else
+		/*
+		**	Flag any overlapping object in this cell to be redrawn.
+		*/
+		for (int index = 0; index < ARRAY_SIZE(Overlapper); index++) {
+			if (Overlapper[index] != NULL) {
+				if (!Overlapper[index]->IsActive) {
+					Overlapper[index] = NULL;
+				} else {
+					Overlapper[index]->Mark(MARK_CHANGE);
+				}
+			}
+		}
+#endif
+	}
+}
+
+
+/***********************************************************************************************
+ * CellClass::Is_Clear_To_Build -- Determines if cell can be built upon.                       *
+ *                                                                                             *
+ *    This determines if the cell can become a proper foundation for                           *
+ *    building placement.                                                                      *
+ *                                                                                             *
+ * INPUT:   loco     -- The locomotion of the object trying to consider if this cell is        *
+ *                      generally clear. Buildings use the value of SPEED_NONE.                *
+ *                                                                                             *
+ * OUTPUT:  bool; Is this cell generally clear (usually for building purposes)?                *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/18/1994 JLB : Created.                                                                 *
+ *   06/25/1996 JLB : Handles different locomotion types.                                      *
+ *   10/05/1996 JLB : Checks for crushable walls and crushable object.                         *
+ *=============================================================================================*/
+bool CellClass::Is_Clear_To_Build(SpeedType loco) const
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+
+	/*
+	**	During scenario initialization, passability is always guaranteed.
+	*/
+	if (ScenarioInit) return(true);
+
+	/*
+	**	If there is an object there, then don't allow building.
+	*/
+	if (Cell_Object() != NULL) {
+		return(false);
+	}
+
+	/*
+	**	Prevents a building from being placed over a flag object.
+	*/
+#ifdef FIXIT_FLAG_CHECK
+	if (IsFlagged)  {
+		return(false);
+	}
+#endif
+
+	/*
+	**	Walls are always considered to block the terrain for general passability
+	**	purposes. In normal game mode, all overlays are not buildable.
+	*/
+	if (Overlay != OVERLAY_NONE && (Overlay == OVERLAY_FLAG_SPOT || !Debug_Map || OverlayTypeClass::As_Reference(Overlay).IsWall)) {
+		return(false);
+	}
+
+	/*
+	**	Building over a bib is not allowed.
+	*/
+	if (Smudge != SMUDGE_NONE && SmudgeTypeClass::As_Reference(Smudge).IsBib /* && Owner != HOUSE_NONE*/) {
+		return(false);
+	}
+
+	/*
+	**	Building on certain kinds of terrain is prohibited -- bridges in particular.
+	**	If the locomotion type is SPEED_NONE, then this check is presumed to be
+	**	for the purposes of building.
+	*/
+	if (loco == SPEED_NONE) {
+		if (Is_Bridge_Here()) {
+			return(false);
+		}
+
+		return(::Ground[Land_Type()].Build);
+
+	} else {
+
+		if (::Ground[Land_Type()].Cost[loco] == fixed(0)) {
+//		if (::Ground[Land_Type()].Cost[SPEED_TRACK] == fixed(0)) {
+			return(false);
+		}
+		return(true);
+	}
+}
+
+
+/***********************************************************************************************
+ * CellClass::Recalc_Attributes -- Recalculates the ground type attributes for the cell.       *
+ *                                                                                             *
+ *    This routine recalculates the ground type in the cell. The speeds the find path          *
+ *    algorithm and other determinations of the cell type.                                     *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/29/1994 JLB : Created.                                                                 *
+ *   06/20/1994 JLB : Knows about template pointer in cell object.                             *
+ *=============================================================================================*/
+void CellClass::Recalc_Attributes(void)
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+
+	/*
+	**	Special override for interior terrain set so that a non-template or a clear template
+	**	is equivalent to impassable rock.
+	*/
+	if (LastTheater == THEATER_INTERIOR) {
+		if (TType == TEMPLATE_NONE || TType == TEMPLATE_CLEAR1) {
+			Land = LAND_ROCK;
+			return;
+		}
+	}
+
+	/*
+	**	Check for wall effects.
+	*/
+	if (Overlay != OVERLAY_NONE) {
+		Land = OverlayTypeClass::As_Reference(Overlay).Land;
+		if (Land != LAND_CLEAR) return;
+	}
+
+	/*
+	**	If there is a template associated with this cell, then fetch the
+	**	land type given the template type and icon number.
+	*/
+	if (TType != TEMPLATE_NONE && TType != 255) {
+		TemplateTypeClass const * ttype = &TemplateTypeClass::As_Reference(TType);
+		Land = ttype->Land_Type(TIcon);
+		return;
+	}
+
+	/*
+	**	No template is the same as clear terrain.
+	*/
+	Land = LAND_CLEAR;
+}
+
+
+/***********************************************************************************************
+ * CellClass::Occupy_Down -- Flag occupation of specified cell.                                *
+ *                                                                                             *
+ *    This routine is used to mark the cell as being occupied by the specified object.         *
+ *                                                                                             *
+ * INPUT:   object   -- The object that is to occupy the cell                                  *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/18/1994 JLB : Created.                                                                 *
+ *   11/29/1994 JLB : Simplified.                                                              *
+ *=============================================================================================*/
+void CellClass::Occupy_Down(ObjectClass * object)
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+	assert(object != NULL && object->IsActive);
+
+	ObjectClass * optr;
+
+	if (object == NULL) return;
+
+	/*
+	**	Always add buildings to the end of the occupation chain. This is necessary because
+	**	the occupation chain is a single list even though buildings occupy more than one
+	**	cell. If more than one building is allowed to occupy the same cell, then this chain
+	**	logic will fail.
+	*/
+	if (object->What_Am_I() == RTTI_BUILDING && Cell_Occupier()) {
+		optr = Cell_Occupier();
+		while (optr->Next != NULL) {
+			assert(optr != object);
+			assert(optr->What_Am_I() != RTTI_BUILDING);
+			optr = optr->Next;
+		}
+		optr->Next = object;
+		object->Next = 0;
+	} else {
+		object->Next = Cell_Occupier();
+		OccupierPtr = object;
+	}
+	Map.Radar_Pixel(Cell_Number());
+
+	/*
+	**	If being placed down on a visible square, then flag this
+	**	techno object as being revealed to the player.
+	*/
+	if (IsMapped || Session.Type != GAME_NORMAL) {
+		object->Revealed(PlayerPtr);
+	}
+
+	/*
+	**	Special occupy bit set.
+	*/
+	switch (object->What_Am_I()) {
+		case RTTI_BUILDING:
+			Flag.Occupy.Building = true;
+			break;
+
+		case RTTI_VESSEL:
+		case RTTI_AIRCRAFT:
+		case RTTI_UNIT:
+			Flag.Occupy.Vehicle = true;
+			break;
+
+		case RTTI_TERRAIN:
+			Flag.Occupy.Monolith = true;
+			break;
+
+		default:
+			break;
+	}
+}
+
+
+/***********************************************************************************************
+ * CellClass::Occupy_Up -- Removes occupation flag from the specified cell.                    *
+ *                                                                                             *
+ *    This routine will lift the object from the cell and free the cell to be occupied by      *
+ *    another object. Only if the cell was previously marked with the object specified, will   *
+ *    the object be lifted off. This routine is the counterpart to Occupy_Down().              *
+ *                                                                                             *
+ * INPUT:   object   -- The object that is being lifted off.                                   *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/18/1994 JLB : Created.                                                                 *
+ *   11/29/1994 JLB : Fixed to handle next pointer in previous object.                         *
+ *=============================================================================================*/
+void CellClass::Occupy_Up(ObjectClass * object)
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+	assert(object != NULL && object->IsActive);
+
+	if (object == NULL) return;
+
+	ObjectClass * optr = Cell_Occupier();		// Working pointer to the objects in the chain.
+
+	if (optr == object) {
+		OccupierPtr = object->Next;
+		object->Next = 0;
+	} else {
+		bool found = false;
+		while (optr != NULL) {
+			if (optr->Next == object) {
+				optr->Next = object->Next;
+				object->Next = 0;
+				found = true;
+				break;
+			}
+			optr = optr->Next;
+		}
+//		assert(found);
+	}
+	Map.Radar_Pixel(Cell_Number());
+
+	/*
+	**	Special occupy bit clear.
+	*/
+	switch (object->What_Am_I()) {
+		case RTTI_BUILDING:
+			Flag.Occupy.Building = false;
+			break;
+
+		case RTTI_VESSEL:
+		case RTTI_AIRCRAFT:
+		case RTTI_UNIT:
+			Flag.Occupy.Vehicle = false;
+			break;
+
+		case RTTI_TERRAIN:
+			Flag.Occupy.Monolith = false;
+			break;
+
+		default:
+			break;
+	}
+}
+
+
+/***********************************************************************************************
+ * CellClass::Overlap_Down -- This routine is used to mark a cell as being spilled over (overla*
+ *                                                                                             *
+ *    Most game objects can often have their graphic imagery spill into more than one cell     *
+ *    even though they are considered to "occupy" only one cell. All cells overlapped are      *
+ *    flagged by this routine. Using this information it is possible to keep the tactical map  *
+ *    display correct.                                                                         *
+ *                                                                                             *
+ * INPUT:   object   -- The object to mark as overlapping this cell.                           *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/18/1994 JLB : Created.                                                                 *
+ *   07/04/1995 JLB : Ensures that buildings are always marked down.                           *
+ *=============================================================================================*/
+void CellClass::Overlap_Down(ObjectClass * object)
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+	assert(object != NULL && object->IsActive);
+
+	ObjectClass ** ptr = 0;
+
+	if (!object) return;
+
+	for (int index = 0; index < ARRAY_SIZE(Overlapper); index++) {
+		if (Overlapper[index] == object) return;
+		if (!Overlapper[index]) ptr = &Overlapper[index];
+	}
+
+	/*
+	**	Buildings must ALWAYS succeed in marking the cell as overlapped. Bump somebody
+	**	else out in this case.
+	*/
+	if (!ptr && object->What_Am_I() == RTTI_BUILDING) {
+		for (index = 0; index < ARRAY_SIZE(Overlapper); index++) {
+			switch (Overlapper[index]->What_Am_I()) {
+				case RTTI_BUILDING:
+				case RTTI_TERRAIN:
+					break;
+
+				default:
+					Overlapper[index] = object;
+					index = ARRAY_SIZE(Overlapper);
+					break;
+			}
+		}
+	}
+	if (ptr) *ptr = object;
+
+	/*
+	**	If being placed down on a visible square, then flag this
+	**	techno object as being revealed to the player.
+	*/
+	if (IsMapped) {
+		object->Revealed(PlayerPtr);
+	}
+}
+
+
+/***********************************************************************************************
+ * CellClass::Overlap_Up -- Removes overlap flag for the cell.                                 *
+ *                                                                                             *
+ *    This is the counterpart to Overlap_Down and is used to remove the overlap flag for the   *
+ *    specified unit on the cell.                                                              *
+ *                                                                                             *
+ * INPUT:   object   -- The object to remove the overlap flag for.                             *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/18/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void CellClass::Overlap_Up(ObjectClass * object)
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+	assert(object != NULL && object->IsActive);
+
+	for (int index = 0; index < ARRAY_SIZE(Overlapper); index++) {
+		if (Overlapper[index] == object) {
+			Overlapper[index] = 0;
+			break;
+		}
+	}
+}
+
+
+/***********************************************************************************************
+ * CellClass::Cell_Unit -- Returns with pointer to unit occupying cell.                        *
+ *                                                                                             *
+ *    This routine will determine if a unit is occupying the cell and if so, return a pointer  *
+ *    to it. If there is no unit occupying the cell, then NULL is returned.                    *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with pointer to unit occupying cell, else NULL.                            *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/18/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+UnitClass * CellClass::Cell_Unit(void) const
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+
+	return((UnitClass*)Cell_Find_Object(RTTI_UNIT));
+}
+
+
+/***********************************************************************************************
+ * CellClass::Cell_Vessel -- Returns with pointer to a vessel located in the cell.             *
+ *                                                                                             *
+ *    Call this routine to query and return a pointer to a vessel located in the cell. If      *
+ *    there is no vessel present, then this routine will return NULL.                          *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with a pointer to the vessel class object if one is present.               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/20/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+VesselClass * CellClass::Cell_Vessel(void) const
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+
+	return((VesselClass*)Cell_Find_Object(RTTI_VESSEL));
+}
+
+
+/***********************************************************************************************
+ * CellClass::Cell_Infantry -- Returns with pointer of first infantry unit occupying the cell. *
+ *                                                                                             *
+ *    This routine examines the cell and returns a pointer to the first infantry unit          *
+ *    that occupies it. If there is no infantry unit in the cell, then NULL is returned.       *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with pointer to infantry unit occupying the cell or NULL if none are       *
+ *          present.                                                                           *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   12/21/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+InfantryClass * CellClass::Cell_Infantry(void) const
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+
+	return((InfantryClass*)Cell_Find_Object(RTTI_INFANTRY));
+}
+
+
+#ifdef SORTDRAW
+static bool _Calc_Partial_Window(int cellx, int celly, int & drawx, int & drawy)
+{
+	int & px = WindowList[WINDOW_PARTIAL][WINDOWX];
+	int & py = WindowList[WINDOW_PARTIAL][WINDOWY];
+	int & pw = WindowList[WINDOW_PARTIAL][WINDOWWIDTH];
+	int & ph = WindowList[WINDOW_PARTIAL][WINDOWHEIGHT];
+	int & tx = WindowList[WINDOW_TACTICAL][WINDOWX];
+	int & ty = WindowList[WINDOW_TACTICAL][WINDOWY];
+	int & tw = WindowList[WINDOW_TACTICAL][WINDOWWIDTH];
+	int & th = WindowList[WINDOW_TACTICAL][WINDOWHEIGHT];
+
+	px = cellx + tx;
+	py = celly + ty;
+	pw = CELL_PIXEL_W;
+	ph = CELL_PIXEL_H;
+
+	if (px < tx) {
+		pw -= tx - px;
+		px = tx;
+	}
+	if (pw < 1) return(false);
+
+	if (py < ty) {
+		ph -= ty - py;
+		py = ty;
+	}
+	if (ph < 1) return(false);
+
+	if (px + pw > tx + tw) {
+		pw -= (px + pw) - (tx + tw);
+	}
+	if (pw < 1) return(false);
+
+	if (py + ph > ty + th) {
+		ph -= (py + ph) - (ty + th);
+	}
+	if (ph < 1) return(false);
+
+	drawx = drawx - (px-tx);
+	drawy = drawy - (py-ty);
+	return(true);
+}
+
+
+static int _ocompare(const void * left, const void * right)
+{
+	COORDINATE lcoord = (*((ObjectClass **)left))->Sort_Y();
+	COORDINATE rcoord = (*((ObjectClass **)right))->Sort_Y();
+	if (lcoord < rcoord) return(-1);
+	if (lcoord > rcoord) return(1);
+	return(0);
+}
+#endif
+
+
+/***********************************************************************************************
+ * CellClass::Draw_It -- Draws the cell imagery at the location specified.                     *
+ *                                                                                             *
+ *    This is the gruntwork cell rendering code. It draws the cell at the screen location      *
+ *    specified. This routine doesn't draw any overlapping or occupying units. It only         *
+ *    deals with the ground (cell) layer -- icon level.                                        *
+ *                                                                                             *
+ * INPUT:   x,y   -- The screen coordinates to render the cell imagery at.                     *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/18/1994 JLB : Created.                                                                 *
+ *   08/21/1994 JLB : Revised for simple template objects.                                     *
+ *   11/01/1994 BRR : Updated placement cursor; draws actual object                            *
+ *   11/14/1994 BRR : Added remapping code to show passable areas                              *
+ *   12/02/1994 BRR : Added trigger display                                                    *
+ *   12/11/1994 JLB : Mixes up clear terrain through pseudo-random table.                      *
+ *   04/25/1995 JLB : Smudges drawn BELOW overlays.                                            *
+ *   07/22/1996 JLB : Objects added to draw process.                                           *
+ *=============================================================================================*/
+void CellClass::Draw_It(int x, int y, bool objects) const
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+
+	if (!objects) {
+		BStart(BENCH_CELL);
+
+		TemplateTypeClass const * ttype = 0;
+		int	icon;		// The icon number to use from the template set.
+		CELL	cell = Cell_Number();
+		void * remap = NULL;
+	#ifdef SCENARIO_EDITOR
+		TemplateTypeClass * tptr;
+//		TriggerClass * trig;
+		int i;
+		char waypt[3];
+	#endif
+
+		CellCount++;
+
+		/*
+		**	Fetch a pointer to the template type associated with this cell.
+		*/
+		if (TType != TEMPLATE_NONE && TType != TEMPLATE_CLEAR1 && TType != 255) {
+			ttype = &TemplateTypeClass::As_Reference(TType);
+			icon = TIcon;
+		} else {
+			ttype = &TemplateTypeClass::As_Reference(TEMPLATE_CLEAR1);
+			icon = Clear_Icon();
+		}
+
+	#ifdef CHEAT_KEYS
+		/*
+		**	Draw the stamp of the template.
+		*/
+		if (Debug_Icon) {
+			LogicPage->Fill_Rect(Map.TacPixelX+x, Map.TacPixelY+y, Map.TacPixelX+x+ICON_PIXEL_W-1, Map.TacPixelY+y+ICON_PIXEL_H-1, Sim_Random_Pick(1, 254));
+			FontXSpacing -= 2;
+			Fancy_Text_Print("%02X%02X\r%d%d%d\r%d %d", Map.TacPixelX+x+(ICON_PIXEL_W>>1), Map.TacPixelY+y, &GreyScheme, TBLACK, TPF_EFNT|TPF_CENTER|TPF_BRIGHT_COLOR|TPF_FULLSHADOW,
+				Cell_Y(cell), Cell_X(cell),
+				//(CurrentObject.Count() && CurrentObject[0]->Is_Techno()) ? ((TechnoClass *)CurrentObject[0])->House->Which_Zone(cell) : -1,
+				Zones[MZONE_NORMAL],Zones[MZONE_CRUSHER],Zones[MZONE_DESTROYER],
+				Overlay, OverlayData
+				);
+			FontXSpacing += 2;
+		} else {
+	#endif
+
+	#ifdef SCENARIO_EDITOR
+			/*
+			**	Set up the remap table for this icon.
+			*/
+			if (Debug_Map && Debug_Passable) {
+				if (::Ground[Land].Cost[0] == 0 || (Cell_Occupier() != NULL &&
+					Cell_Occupier()->What_Am_I() != RTTI_INFANTRY)) {	// impassable
+					remap = DisplayClass::FadingRed;
+				} else {
+					if (::Ground[Land].Cost[0] > fixed(1, 3)) {	// pretty passable
+						remap = DisplayClass::FadingGreen;
+					} else {
+						remap = DisplayClass::FadingYellow;				// moderately passable
+					}
+				}
+			}
+	#endif
+
+			/*
+			**	This is the underlying terrain icon.
+			*/
+			if (ttype->Get_Image_Data()) {
+				LogicPage->Draw_Stamp(ttype->Get_Image_Data(), icon, x, y, NULL, WINDOW_TACTICAL);
+				if (remap) {
+					LogicPage->Remap(x+Map.TacPixelX, y+Map.TacPixelY, ICON_PIXEL_W, ICON_PIXEL_H, remap);
+				}
+			}
+
+	#ifdef SCENARIO_EDITOR
+			/*
+			**	Draw the map editor's "current" cell. This is the cell that can be
+			**	assigned attributes such as tag labels.
+			**	This must be draw before the placement cursor, but after drawing the
+			**	objects in the cell.
+			*/
+			if (Debug_Map && CurrentCell == Cell_Number()) {
+				LogicPage->Draw_Rect(x+Map.TacPixelX, y+Map.TacPixelY, Map.TacPixelX + x + CELL_PIXEL_W - 1, Map.TacPixelY + y + CELL_PIXEL_H - 1, YELLOW);
+			}
+	#endif
+
+			/*
+			**	Redraw any smudge.
+			*/
+			if (Smudge != SMUDGE_NONE) {
+				SmudgeTypeClass::As_Reference(Smudge).Draw_It(x, y, SmudgeData);
+			}
+
+			/*
+			**	Draw the overlay object.
+			*/
+			if (Overlay != OVERLAY_NONE) {
+				OverlayTypeClass const & otype = OverlayTypeClass::As_Reference(Overlay);
+				IsTheaterShape = (bool)otype.IsTheater;	//Tell Build_Frame if this overlay is theater specific
+				CC_Draw_Shape(otype.Get_Image_Data(), OverlayData, (x+(CELL_PIXEL_W>>1)), (y+(CELL_PIXEL_H>>1)), WINDOW_TACTICAL, SHAPE_CENTER|SHAPE_WIN_REL|SHAPE_GHOST, NULL, DisplayClass::UnitShadow);
+				IsTheaterShape = false;
+			}
+
+	#ifdef SCENARIO_EDITOR
+			if (Debug_Map) {
+				/*
+				**	Draw the cell's Trigger mnemonic, if it has a trigger
+				*/
+				if (Trigger.Is_Valid()) {
+					Fancy_Text_Print(Trigger->Class->IniName, x+Map.TacPixelX, y+Map.TacPixelY, &ColorRemaps[PCOLOR_RED], TBLACK, TPF_EFNT|TPF_FULLSHADOW);
+				}
+
+				/*
+				**	Draw the cell's Waypoint designation if there is one.
+				*/
+				if (IsWaypoint) {
+					for (i = 0; i < WAYPT_HOME; i++) {
+						if (Scen.Waypoint[i] == Cell_Number()) {
+							if (i < 26) {
+								waypt[0] = 'A' + i;
+								waypt[1] = 0;
+							} else {
+								waypt[0] = 'A' + (i/26)-1;
+								waypt[1] = 'A' + (i % 26);
+								waypt[2] = 0;
+							}
+							Fancy_Text_Print(waypt, Map.TacPixelX + x + CELL_PIXEL_W / 2,
+								Map.TacPixelY + y + (CELL_PIXEL_H / 2) - 3,
+								&ColorRemaps[PCOLOR_RED], TBLACK,
+								TPF_EFNT | TPF_CENTER|TPF_FULLSHADOW);
+							break;
+						}
+					}
+					if (Scen.Waypoint[WAYPT_HOME] == Cell_Number()) {
+							Fancy_Text_Print("Home", Map.TacPixelX + x, Map.TacPixelY + y + (CELL_PIXEL_H) - 7,
+							&ColorRemaps[PCOLOR_GREY], TBLACK, TPF_EFNT|TPF_FULLSHADOW);
+					}
+					if (Scen.Waypoint[WAYPT_REINF] == Cell_Number()) {
+							Fancy_Text_Print("Reinf", Map.TacPixelX + x, Map.TacPixelY + y + (CELL_PIXEL_H) - 7,
+							&ColorRemaps[PCOLOR_GREY], TBLACK, TPF_EFNT|TPF_FULLSHADOW);
+					}
+				}
+			}
+	#endif
+
+			/*
+			**	Draw the placement cursor:
+			**	- First, draw the hash-mark cursor, so it will appear underneath
+			**	  any cursor being drawn
+			**	- If the PendingObject is a template, overlay, or smudge, draw it
+			**	- Otherwise, it's up to the Display.Refresh_Map() routine to draw it
+			*/
+			if (IsCursorHere) {
+				SpeedType loco = SPEED_NONE;
+				if (Map.PendingObjectPtr) {
+					if (Map.PendingObjectPtr->What_Am_I() == RTTI_BUILDING) {
+						BuildingClass * obj = (BuildingClass *)(Map.PendingObjectPtr);
+						loco = obj->Class->Speed;
+	//					if (*obj == STRUCT_SUB_PEN || *obj == STRUCT_SHIP_YARD ||
+	//					    *obj == STRUCT_FAKE_PEN || *obj == STRUCT_FAKE_YARD) loco = SPEED_FLOAT;
+					}
+				}
+
+				/*
+				**	Draw the hash-mark cursor:
+				*/
+				if (Map.ProximityCheck && Is_Clear_To_Build(loco)) {
+					LogicPage->Draw_Stamp(DisplayClass::TransIconset, 0, x, y, NULL, WINDOW_TACTICAL);
+				} else {
+					LogicPage->Draw_Stamp(DisplayClass::TransIconset, 2, x, y, NULL, WINDOW_TACTICAL);
+				}
+
+	#ifdef SCENARIO_EDITOR
+				if (Debug_Map && Map.PendingObject) {
+
+					switch (Map.PendingObject->What_Am_I()) {
+
+						/*
+						**	Draw a template:
+						**	- Compute the icon offset of this cell for this template, using
+						**	  ZoneCell+ZoneOffset to get the upper-left corner of the placement
+						**	  cursor
+						**	- Draw the icon
+						*/
+						case RTTI_TEMPLATETYPE:
+							tptr = (TemplateTypeClass *)Map.PendingObject;
+							if (tptr->Get_Image_Data()) {
+								icon = (Cell_X(cell) - Cell_X(Map.ZoneCell + Map.ZoneOffset)) +
+									(Cell_Y(cell) - Cell_Y(Map.ZoneCell + Map.ZoneOffset)) *
+									tptr->Width;
+								LogicPage->Draw_Stamp(tptr->Get_Image_Data(), icon, x, y, NULL, WINDOW_TACTICAL);
+							}
+							break;
+
+						/*
+						**	Draw an overlay; just use the existing 'OverlayData' even though
+						**	it means nothing.
+						*/
+						case RTTI_OVERLAYTYPE:
+							OverlayTypeClass::As_Reference(((OverlayTypeClass *)Map.PendingObject)->Type).Draw_It(x, y, OverlayData);
+							break;
+
+						/*
+						**	Draw a smudge
+						*/
+						case RTTI_SMUDGETYPE:
+							SmudgeTypeClass::As_Reference(((SmudgeTypeClass *)Map.PendingObject)->Type).Draw_It(x, y, 0);
+							break;
+
+						default:
+							break;
+					}
+				}
+	#endif
+			}
+
+			/*
+			**	Draw the flag if there is one located at this cell.
+			*/
+			if (IsFlagged) {
+				void const * flag_remap = HouseClass::As_Pointer(Owner)->Remap_Table(false, REMAP_NORMAL);
+				CC_Draw_Shape(MFCD::Retrieve("FLAGFLY.SHP"), Frame % 14, x+(ICON_PIXEL_W/2), y+(ICON_PIXEL_H/2), WINDOW_TACTICAL, SHAPE_CENTER|SHAPE_GHOST|SHAPE_FADING, flag_remap, DisplayClass::UnitShadow);
+			}
+
+	#ifdef CHEAT_KEYS
+		}
+	#endif
+		BEnd(BENCH_CELL);
+	}
+
+#ifdef SORTDRAW
+	if (objects) {
+		BStart(BENCH_OBJECTS);
+
+		/*
+		**	Build a list of objects to draw into a working buffer. There is a
+		**	big presumption here -- it is presumed that if the cell is to be
+		**	redrawn, then all objects in the cell should properly be flagged to
+		**	be redrawn as well. Normally, this isn't a problem, but for subs
+		**	the IsToDisplay flag MUST REMAIN SET. This is because there is a
+		**	hack overpass after the cells are redrawn so that subs can be
+		**	redrawn separately.
+		*/
+		ObjectClass * optr[20 + ARRAY_SIZE(Overlapper)];
+		int count = 0;
+		ObjectClass * object = Cell_Occupier();
+		while (object != NULL) {
+			if (!object->IsActive) break;
+			optr[count] = object;
+			object->IsToDisplay = true;
+			object = object->Next;
+			count++;
+		}
+		for (int index = 0; index < ARRAY_SIZE(Overlapper); index++) {
+			object = Overlapper[index];
+			if (object != NULL && object->IsActive) {
+				object->IsToDisplay = true;
+				optr[count] = object;
+				count++;
+			}
+		}
+
+		/*
+		**	Sort the object list so that objects will be drawn from
+		**	back to front.
+		*/
+		switch (count) {
+
+			/*
+			**	If there are zero or one object, then sorting is
+			**	unnecessary.
+			*/
+			case 0:
+			case 1:
+				break;
+
+			/*
+			**	Two objects can be sorted with a single compare and swap.
+			*/
+			case 2:
+				if (optr[0]->Sort_Y() > optr[1]->Sort_Y()) {
+					swap(optr[0], optr[1]);
+				}
+				break;
+
+			/*
+			**	Three objects can be sorted with three compares and swaps.
+			*/
+			case 3:
+				if (optr[0]->Sort_Y() > optr[2]->Sort_Y()) {
+					swap(optr[0], optr[2]);
+				}
+				if (optr[0]->Sort_Y() > optr[1]->Sort_Y()) {
+					swap(optr[0], optr[1]);
+				}
+				if (optr[1]->Sort_Y() > optr[2]->Sort_Y()) {
+					swap(optr[1], optr[2]);
+				}
+				break;
+
+			/*
+			**	Large number of objects can be effeciently sorted by using
+			**	a quicksort.
+			*/
+			default:
+				qsort(optr, count, sizeof(optr[0]), _ocompare);
+				break;
+		}
+
+		/*
+		**	Draw any objects that happen to be in or overlapping this cell.
+		*/
+		for (index = 0; index < count; index++) {
+			object = optr[index];
+			int xx,yy;
+			if (object->IsToDisplay && (!object->Is_Techno() || ((TechnoClass *)object)->Visual_Character() == VISUAL_NORMAL) && Map.Coord_To_Pixel(object->Render_Coord(), xx, yy)) {
+				if (_Calc_Partial_Window(x, y, xx, yy)) {
+					object->Draw_It(xx, yy, WINDOW_PARTIAL);
+					if (Debug_Map) {
+						object->IsToDisplay = true;
+					} else {
+						object->IsToDisplay = false;
+					}
+				}
+				object->IsToDisplay = false;
+			}
+		}
+		BEnd(BENCH_OBJECTS);
+	}
+#endif
+
+}
+
+
+/***********************************************************************************************
+ * CellClass::Concrete_Calc -- Calculates the concrete icon to use for the cell.               *
+ *                                                                                             *
+ *    This routine examines the cells around the current one and from this, determines what    *
+ *    concrete icon shape to use (if any). The cell data is adjusted and the cell is marked    *
+ *    for redraw if the icon changed.                                                          *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/01/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void CellClass::Concrete_Calc(void)
+{
+#ifdef OBSOLETE
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+
+	static FacingType _even[5] = {FACING_N, FACING_S, FACING_SW, FACING_W, FACING_NW};
+	static FacingType _odd[5] = {FACING_N, FACING_NE, FACING_E, FACING_SE, FACING_S};
+	FacingType * ptr;		// Working pointer into adjacent cell list.
+	int	index;	// Constructed bit index.
+	int	icon;		// Icon number.
+	bool	isodd;	// Is this for the odd column?
+
+#define	OF_N	0x01
+#define	OF_NE	0x02
+#define	OF_E	0x04
+#define	OF_SE	0x08
+#define	OF_S	0x10
+
+#define	EF_N	0x01
+#define	EF_NW	0x10
+#define	EF_W	0x08
+#define	EF_SW	0x04
+#define	EF_S	0x02
+
+	/*
+	**	Determine if the even or odd row logic is necessary.
+	*/
+	isodd = ((Cell_Number() & 0x01) != 0);
+
+	/*
+	**	Fetch correct pointer depending on whether this is for an
+	**	odd or even row.
+	*/
+	ptr = (isodd) ? _odd : _even;
+
+	/*
+	**	Build an index according to the presence of concrete in the special
+	**	adjacent cells. This is a short list of adjacent cell flags since
+	**	only 5 adjacent cells need to be examined. The choice of which 5
+	**	depends on whether this is for an even or odd column.
+	*/
+	index = 0;
+	for (int i = 0; i < (sizeof(_even)/sizeof(_even[0])); i++) {
+		CellClass & cellptr = Adjacent_Cell(*ptr++);
+
+		if (cellptr.Overlay == OVERLAY_CONCRETE) {
+			index |= (1<<i);
+		}
+	}
+
+	/*
+	**	Special logic occurs for cells that are concrete filled.
+	*/
+	if (Overlay == OVERLAY_CONCRETE) {
+
+		/*
+		**	Process the index value and place the appropriate concrete icon
+		**	in the cell.
+		*/
+		if (isodd) {
+			switch (index) {
+				case OF_NE:
+				case OF_N|OF_NE:
+				case OF_E|OF_N:
+				case OF_E|OF_NE:
+				case OF_N|OF_NE|OF_E:
+				case OF_S|OF_N|OF_NE:
+					icon = C_RIGHT_UP;		// right - up
+					break;
+
+				case OF_SE:
+				case OF_E|OF_SE:
+				case OF_S|OF_SE:
+				case OF_S|OF_E:
+				case OF_S|OF_SE|OF_E:
+				case OF_S|OF_SE|OF_N:
+					icon = C_RIGHT_DOWN;		// right - down
+					break;
+
+				case OF_SE|OF_NE:
+				case OF_SE|OF_NE|OF_N:
+				case OF_SE|OF_NE|OF_S:
+				case OF_SE|OF_NE|OF_S|OF_N:
+				case OF_SE|OF_E|OF_N:
+				case OF_SE|OF_E|OF_NE|OF_N:
+				case OF_S|OF_E|OF_N:
+				case OF_S|OF_E|OF_NE:
+				case OF_S|OF_E|OF_NE|OF_N:
+				case OF_S|OF_SE|OF_E|OF_N:
+				case OF_S|OF_SE|OF_E|OF_NE|OF_N:
+				case OF_S|OF_SE|OF_E|OF_NE:
+					icon = C_RIGHT_UPDOWN;		// right - up - down
+					break;
+
+				default:
+					icon = C_RIGHT;		// right
+					break;
+			}
+		} else {
+			switch (index) {
+				case EF_NW:
+				case EF_NW|EF_N:
+				case EF_W|EF_N:
+				case EF_NW|EF_W|EF_N:
+				case EF_NW|EF_W:
+				case EF_NW|EF_S|EF_N:
+					icon = C_LEFT_UP;		// left - up
+					break;
+
+				case EF_SW:
+				case EF_SW|EF_S:
+				case EF_W|EF_S:
+				case EF_W|EF_SW|EF_S:
+				case EF_W|EF_SW:
+				case EF_SW|EF_S|EF_N:
+					icon = C_LEFT_DOWN;		// left - down
+					break;
+
+				case EF_NW|EF_SW:
+				case EF_NW|EF_SW|EF_N:
+				case EF_NW|EF_SW|EF_S:
+				case EF_NW|EF_SW|EF_S|EF_N:
+				case EF_W|EF_S|EF_N:
+				case EF_W|EF_SW|EF_N:
+				case EF_W|EF_SW|EF_S|EF_N:
+				case EF_NW|EF_W|EF_S:
+				case EF_NW|EF_W|EF_S|EF_N:
+				case EF_NW|EF_W|EF_SW|EF_S|EF_N:
+				case EF_NW|EF_W|EF_SW|EF_N:
+				case EF_NW|EF_W|EF_SW|EF_S:
+					icon = C_LEFT_UPDOWN;		// left - up - down
+					break;
+
+				default:
+					icon = C_LEFT;		// left
+					break;
+			}
+		}
+
+	} else {
+
+		// Presume that no concrete piece is needed.
+		icon = C_NONE;
+		if (isodd) {
+			index &= ~(OF_NE|OF_SE);		// Ignore diagonals.
+			switch (index) {
+				case OF_N|OF_E:
+					icon = C_UP_RIGHT;		// up right
+					break;
+
+				case OF_E|OF_S:
+					icon = C_DOWN_RIGHT;		// down right
+					break;
+
+				case OF_N|OF_E|OF_S:
+					icon = C_UPDOWN_RIGHT;	// up/down right
+					break;
+
+				default:
+					break;
+			}
+		} else {
+			index &= ~(EF_NW|EF_SW);		// Ignore diagonals.
+			switch (index) {
+				case EF_N|EF_W:
+					icon = C_UP_LEFT;		// up left
+					break;
+
+				case EF_W|EF_S:
+					icon = C_DOWN_LEFT;		// down left
+					break;
+
+				case EF_N|EF_W|EF_S:
+					icon = C_UPDOWN_LEFT;		// up/down left
+					break;
+
+				default:
+					break;
+			}
+		}
+
+		/*
+		**	If any kind of fixup piece is needed, then add concrete
+		**	to this location RECURSIVELY!
+		*/
+		if (icon != C_NONE) {
+			OverlayTypeClass::As_Reference(OVERLAY_CONCRETE).Create_And_Place(Cell_Number());
+			icon = C_NONE;
+		}
+
+	}
+
+	/*
+	**	Update the icon on the map.
+	*/
+	if (icon != C_NONE && OverlayData != icon) {
+		OverlayData = icon;
+		//Array[cell].Base = 0;
+		Redraw_Objects();
+	}
+#endif
+}
+
+
+/***********************************************************************************************
+ * CellClass::Wall_Update -- Updates the imagery for wall objects in cell.                     *
+ *                                                                                             *
+ *    This routine will examine the cell and the adjacent cells to determine what the wall     *
+ *    should look like with the cell. It will then update the wall's imagery value and flag    *
+ *    the cell to be redrawn if necessary. This routine should be called whenever the wall     *
+ *    or an adjacent wall is created or destroyed.                                             *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   09/19/1994 JLB : Created.                                                                 *
+ *   09/19/1994 BWG : Updated to handle partially-damaged walls.                               *
+ *=============================================================================================*/
+void CellClass::Wall_Update(void)
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+
+	static FacingType _offsets[5] = {FACING_N, FACING_E, FACING_S, FACING_W, FACING_NONE};
+
+	for (unsigned index = 0; index < (sizeof(_offsets)/sizeof(_offsets[0])); index++) {
+		CellClass & newcell = Adjacent_Cell(_offsets[index]);
+
+		if (newcell.Overlay != OVERLAY_NONE && OverlayTypeClass::As_Reference(newcell.Overlay).IsWall) {
+			int	icon = 0;
+
+			/*
+			**	Build the icon number according to walls located in the adjacent
+			**	cells.
+			*/
+			for (unsigned i = 0; i < 4; i++) {
+				if (newcell.Adjacent_Cell(_offsets[i]).Overlay == newcell.Overlay) {
+					icon |= 1 << i;
+				}
+			}
+			newcell.OverlayData = (newcell.OverlayData & 0xFFF0) | icon;
+
+			/*
+			**	Handle special cases for the incomplete damaged wall sets. If a damage stage
+			**	is calculated, but there is no artwork for it, then consider the wall to be
+			**	completely destroyed.
+			*/
+			if (newcell.Overlay == OVERLAY_BRICK_WALL && newcell.OverlayData == 48) {
+				newcell.Overlay = OVERLAY_NONE;
+				newcell.OverlayData = 0;
+				Detach_This_From_All(::As_Target(newcell.Cell_Number()), true);
+			}
+			if (newcell.Overlay == OVERLAY_SANDBAG_WALL && newcell.OverlayData == 16) {
+				newcell.Overlay = OVERLAY_NONE;
+				newcell.OverlayData = 0;
+				Detach_This_From_All(::As_Target(newcell.Cell_Number()), true);
+			}
+			if (newcell.Overlay == OVERLAY_CYCLONE_WALL && newcell.OverlayData == 32) {
+				newcell.Overlay = OVERLAY_NONE;
+				newcell.OverlayData = 0;
+				Detach_This_From_All(::As_Target(newcell.Cell_Number()), true);
+			}
+			if (newcell.Overlay == OVERLAY_FENCE && (newcell.OverlayData == 16 || newcell.OverlayData == 32)) {
+				newcell.Overlay = OVERLAY_NONE;
+				newcell.OverlayData = 0;
+				Detach_This_From_All(::As_Target(newcell.Cell_Number()), true);
+			}
+			if (newcell.Overlay == OVERLAY_BARBWIRE_WALL && newcell.OverlayData == 16) {
+				newcell.Overlay = OVERLAY_NONE;
+				newcell.OverlayData = 0;
+				Detach_This_From_All(::As_Target(newcell.Cell_Number()), true);
+			}
+
+			newcell.Recalc_Attributes();
+			newcell.Redraw_Objects();
+		}
+	}
+}
+
+
+/***********************************************************************************************
+ * CellClass::Cell_Coord -- Returns the coordinate of this cell.                               *
+ *                                                                                             *
+ *    This support function will determine the coordinate of this cell and return it.          *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with coordinate value of cell.                                             *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   09/19/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+COORDINATE CellClass::Cell_Coord(void) const
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+
+	return(::Cell_Coord(Cell_Number()));
+}
+
+
+/***********************************************************************************************
+ * CellClass::Reduce_Tiberium -- Reduces the tiberium in the cell by the amount specified.     *
+ *                                                                                             *
+ *    This routine will lower the tiberium level in the cell. It is used by the harvesting     *
+ *    process as well as by combat damage to the tiberium fields.                              *
+ *                                                                                             *
+ * INPUT:   levels   -- The number of levels to reduce the tiberium.                           *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the tiberium level reduced by at least one level?                        *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   09/19/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+int CellClass::Reduce_Tiberium(int levels)
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+
+	int reducer = 0;
+
+	if (levels > 0 && Land == LAND_TIBERIUM) {
+		if (OverlayData+1 > levels) {
+			OverlayData -= levels;
+			reducer = levels;
+		} else {
+			Overlay = OVERLAY_NONE;
+			reducer = OverlayData;
+			OverlayData = 0;
+			Recalc_Attributes();
+		}
+	}
+	return(reducer);
+}
+
+
+/***********************************************************************************************
+ * CellClass::Reduce_Wall -- Damages a wall, if damage is high enough.                         *
+ *                                                                                             *
+ *    This routine will change the wall shape used for a wall if it's damaged.                 *
+ *                                                                                             *
+ * INPUT:   damage   -- The number of damage points the wall was hit with. If this value is    *
+ *                      -1, then the entire wall at this cell will be destroyed.               *
+ *                                                                                             *
+ * OUTPUT:  bool; Was the wall destroyed?                                                      *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   03/15/1995 BWG : Created.                                                                 *
+ *   03/19/1995 JLB : Updates cell information if wall was destroyed.                          *
+ *   10/06/1996 JLB : Updates zone as necessary.                                               *
+ *=============================================================================================*/
+int CellClass::Reduce_Wall(int damage)
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+
+	if (Overlay != OVERLAY_NONE) {
+		bool destroyed = false;
+		OverlayTypeClass const & wall = OverlayTypeClass::As_Reference(Overlay);
+
+		if (wall.IsWall) {
+
+			/*
+			**	If the damage was great enough to ensure wall destruction, reduce the wall by one
+			**	level (no more). Otherwise determine wall reduction based on a percentage chance
+			**	proportional to the damage received and the wall's strength.
+			*/
+			if (damage == -1 || damage >= wall.DamagePoints) {
+				destroyed = true;
+			} else {
+				destroyed = Random_Pick(0, wall.DamagePoints) < damage;
+			}
+
+			/*
+			**	If the wall is destroyed, destroy it and check for any adjustments to
+			**	adjacent walls.
+			*/
+			if (destroyed) {
+				OverlayData+=16;
+				if (damage == -1 ||
+					(OverlayData>>4) >= wall.DamageLevels ||
+					((OverlayData>>4) == wall.DamageLevels-1 && (OverlayData & 0xF)==0)	) {
+
+					Owner = HOUSE_NONE;
+					Overlay = OVERLAY_NONE;
+					OverlayData = 0;
+					Recalc_Attributes();
+					Redraw_Objects();
+					Adjacent_Cell(FACING_N).Wall_Update();
+					Adjacent_Cell(FACING_W).Wall_Update();
+					Adjacent_Cell(FACING_S).Wall_Update();
+					Adjacent_Cell(FACING_E).Wall_Update();
+					Detach_This_From_All(As_Target());
+
+					/*
+					**	The zone calculation changes now for non-crushable zone sensitive
+					**	travellers.
+					*/
+					if (wall.IsCrushable) {
+						Map.Zone_Reset(MZONEF_NORMAL);
+					} else {
+						Map.Zone_Reset(MZONEF_CRUSHER|MZONEF_NORMAL);
+					}
+					return(true);
+				}
+			}
+		}
+	}
+	return(false);
+}
+
+
+/***********************************************************************************************
+ * CellClass::Spot_Index -- returns cell sub-coord index for given COORDINATE                  *
+ *                                                                                             *
+ * INPUT:                                                                                      *
+ *      coord      COORDINATE to compute index for                                             *
+ *                                                                                             *
+ * OUTPUT:                                                                                     *
+ *      index into StoppingCoord that's closest to this coord                                  *
+ *                                                                                             *
+ * WARNINGS:                                                                                   *
+ *      none.                                                                                  *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   11/21/1994 BR : Created.                                                                  *
+ *   12/10/1994 JLB : Uses alternate sub-position algorithm.                                   *
+ *=============================================================================================*/
+int CellClass::Spot_Index(COORDINATE coord)
+{
+	COORDINATE rel = Coord_Fraction(coord);		// Sub coordinate value within cell.
+
+	/*
+	**	If the coordinate is close enough to the center of the cell, then return
+	**	the center position index.
+	*/
+	if (Distance(rel, (COORDINATE)0x00800080L) < 60) {
+		return(0);
+	}
+
+	/*
+	**	Since the center cell position has been eliminated, a simple comparison
+	**	as related to the center of the cell can be used to determine the sub
+	**	position. Take advantage of the fact that the sub positions are organized
+	**	from left to right, top to bottom.
+	*/
+	int index = 0;
+	if (Coord_X(rel) > 0x80) index |= 0x01;
+	if (Coord_Y(rel) > 0x80) index |= 0x02;
+	return(index+1);
+}
+
+
+/***********************************************************************************************
+ * CellClass::Closest_Free_Spot -- returns free spot closest to given coord                    *
+ *                                                                                             *
+ * Similar to the CellClass::Free_Spot; this routine finds the spot in                         *
+ * the cell closest to the given coordinate, and returns the COORDINATE of                     *
+ * that spot if it's available, NULL if it's not.                                              *
+ *                                                                                             *
+ * INPUT:                                                                                      *
+ *  coord   coordinate to check (only sub cell position examined)                              *
+ *                                                                                             *
+ *          any   -- If only the closest spot is desired regardless of whether it is free or   *
+ *                   not, then this parameter will be true.                                    *
+ *                                                                                             *
+ * OUTPUT:                                                                                     *
+ *  COORDINATE of free spot, NULL if none. The coordinate return value does not alter the cell *
+ *             coordinate data portions of the coordinate passed in. Only the lower sub-cell   *
+ *             data is altered.                                                                *
+ *                                                                                             *
+ * WARNINGS:                                                                                   *
+ *  none.                                                                                      *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   11/08/1994 BR : Created.                                                                  *
+ *   12/10/1994 JLB : Picks best of closest stopping positions.                                *
+ *   12/21/1994 JLB : Adds a mix-up factor if center location is occupied.                     *
+ *=============================================================================================*/
+COORDINATE CellClass::Closest_Free_Spot(COORDINATE coord, bool any) const
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+
+	int spot_index = Spot_Index(coord);
+
+	/*
+	**	This precalculated sequence table records the closest spots to any given spot. Sequential
+	**	examination of these spots for availability ensures that the closest available one is
+	**	discovered first.
+	*/
+	static unsigned char _sequence[5][4] = {
+		{1,2,3,4},
+		{0,2,3,4},
+		{0,1,4,3},
+		{0,1,4,2},
+		{0,2,3,1}
+	};
+
+	/*
+	**	In the case of the center coordinate being requested, but is occupied, then all other
+	**	sublocations are equidistant. Instead of picking a static sequence of examination, the
+	**	order is mixed up by way of this table.
+	*/
+	static unsigned char _alternate[4][4] = {
+		{1,2,3,4},
+		{2,3,4,1},
+		{3,4,1,2},
+		{4,1,2,3},
+	};
+	coord = Coord_Whole(coord);
+
+	/*
+	**	Cells occupied by buildings or vehicles don't have any free spots.
+	*/
+	if (!any && (Flag.Occupy.Vehicle || Flag.Occupy.Monolith)) {
+		return(NULL);
+	}
+
+	/*
+	**	If just the nearest position is desired regardless of whether occupied or not,
+	**	then just return with the stopping coordinate value.
+	*/
+	if (any || Is_Spot_Free(spot_index)) {
+		return(Coord_Add(coord, StoppingCoordAbs[spot_index]));
+	}
+
+	/*
+	**	Scan through all available sub-locations in the cell in order to determine
+	**	the closest one to the coordinate requested. Use precalculated table so that
+	**	when the first free position is found, bail.
+	*/
+	unsigned char * sequence;
+	if (spot_index == 0) {
+		sequence = &_alternate[Random_Pick(0, 3)][0];
+	} else {
+		sequence = &_sequence[spot_index][0];
+	}
+	for (int index = 0; index < 4; index++) {
+		int pos = *sequence++;
+
+		if (Is_Spot_Free(pos)) {
+			return(Coord_Add(coord, StoppingCoordAbs[pos]));
+		}
+	}
+
+	/*
+	**	No free spot could be found so return a NULL coordinate.
+	*/
+	return(0x00000000L);
+}
+
+
+/***********************************************************************************************
+ * CellClass::Clear_Icon -- Calculates what the clear icon number should be.                   *
+ *                                                                                             *
+ *    This support routine will determine what the clear icon number would be for the cell.    *
+ *    The icon number is determined by converting the cell number into an index into a         *
+ *    lookup table. This yields what appears to be a randomized map without the necessity of   *
+ *    generating and recording randomized map numbers.                                         *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Returns with the icon number for clear terrain if it were displayed at the         *
+ *          cell.                                                                              *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   12/26/1994 JLB : Created.                                                                 *
+ *   06/09/1995 JLB : Uses 16 entry scramble algorithm.                                        *
+ *=============================================================================================*/
+int CellClass::Clear_Icon(void) const
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+
+	CELL cell = Cell_Number();
+	return((Cell_X(cell) & 0x03) | ((Cell_Y(cell) & 0x03) << 2));
+//	return((cell & 0x03) | ((unsigned(cell)>>5) & 0x0C));
+}
+
+
+/***********************************************************************************************
+ * CellClass::Incoming -- Causes objects in cell to "run for cover".                           *
+ *                                                                                             *
+ *    This routine is called whenever a great, but slow moving, threat is presented to the     *
+ *    occupants of a cell. The occupants will, in most cases, stop what they are doing and     *
+ *    try to get out of the way.                                                               *
+ *                                                                                             *
+ * INPUT:   threat      -- The coordinate source of the threat.                                *
+ *                                                                                             *
+ *          forced      -- If this threat is so major that the occupants should stop what      *
+ *                         they are doing, then this parameter should be set to true.          *
+ *                                                                                             *
+ *          nokidding   -- Override the scatter to also affect human controlled objects.       *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   01/10/1995 JLB : Created.                                                                 *
+ *   08/02/1996 JLB : Added the "nokidding" parameter.                                         *
+ *=============================================================================================*/
+void CellClass::Incoming(COORDINATE threat, bool forced, bool nokidding)
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+
+	ObjectClass * object = NULL;
+
+	object = Cell_Occupier();
+	while (object != NULL) {
+
+		/*
+		**	Special check to make sure that friendly units never scatter.
+		*/
+		if (nokidding || Rule.IsScatter || (object->Is_Techno() && ((TechnoClass *)object)->House->IQ >= Rule.IQScatter)) {
+			object->Scatter(threat, forced, nokidding);
+		}
+		object = object->Next;
+	}
+}
+
+
+/***********************************************************************************************
+ * CellClass::Adjacent_Cell -- Determines the adjacent cell according to facing.               *
+ *                                                                                             *
+ *    Use this routine to return a reference to the adjacent cell in the direction specified.  *
+ *                                                                                             *
+ * INPUT:   face  -- The direction to use when determining the adjacent cell.                  *
+ *                                                                                             *
+ * OUTPUT:  Returns with a reference to the adjacent cell.                                     *
+ *                                                                                             *
+ * WARNINGS:   If the facing value is invalid, then a reference to the same cell is returned.  *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   03/19/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+CellClass const & CellClass::Adjacent_Cell(FacingType face) const
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+
+	if ((unsigned)face >= FACING_COUNT) {
+		return(*this);
+	}
+
+	CellClass const * ptr = this + AdjacentCell[face];
+	if ((unsigned)ptr->Cell_Number() > MAP_CELL_TOTAL) return(*this);
+	return(*ptr);
+}
+
+
+/***************************************************************************
+ * CellClass::Adjust_Threat -- Allows adjustment of threat at cell level   *
+ *                                                                         *
+ * INPUT:                                                                  *
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   04/24/1995 PWG : Created.                                             *
+ *=========================================================================*/
+void CellClass::Adjust_Threat(HousesType house, int threat_value)
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+
+	int region = Map.Cell_Region(Cell_Number());
+
+	for (HousesType lp = HOUSE_FIRST; lp < HOUSE_COUNT; lp ++) {
+		if (lp == house) continue;
+
+		HouseClass * house_ptr = HouseClass::As_Pointer(lp);
+		if (house_ptr && (!house_ptr->IsHuman || !house_ptr->Is_Ally(house))) {
+			house_ptr->Adjust_Threat(region, threat_value);
+		}
+	}
+	if (Debug_Threat) {
+		Map.Flag_To_Redraw(true);
+	}
+}
+
+
+/***********************************************************************************************
+ * CellClass::Tiberium_Adjust -- Adjust the look of the Tiberium for smoothing purposes.       *
+ *                                                                                             *
+ *    This routine will adjust the level of the Tiberium in the cell so that it will           *
+ *    smoothly blend with the adjacent Tiberium. This routine should only be called for        *
+ *    new Tiberium cells. Existing cells that contain Tiberium follow a different growth       *
+ *    pattern.                                                                                 *
+ *                                                                                             *
+ * INPUT:   pregame  -- Is this a pregame call? Such a call will mixup the Tiberium overlay    *
+ *                      used.                                                                  *
+ *                                                                                             *
+ * OUTPUT:  Returns with the added Tiberium value that is now available for harvesting.        *
+ *                                                                                             *
+ * WARNINGS:   The return value is only valid for the initial placement. Tiberium growth will  *
+ *             increase the net worth of the existing Tiberium.                                *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/16/1995 JLB : Created.                                                                 *
+ *   02/20/1996 JLB : Takes into account the ore type.                                         *
+ *=============================================================================================*/
+long CellClass::Tiberium_Adjust(bool pregame)
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+	if (Overlay != OVERLAY_NONE) {
+		if (OverlayTypeClass::As_Reference(Overlay).Land == LAND_TIBERIUM) {
+			static int _adj[9] = {0,1,3,4,6,7,8,10,11};
+			static int _adjgem[9] = {0,0,0,1,1,1,2,2,2};
+			int	count = 0;
+
+			/*
+			**	Mixup the Tiberium overlays so that they don't look the same.
+			**	Since the type of ore is known, also record the nominal
+			**	value per step of that ore type.
+			*/
+			bool gems = false;
+			int value = 0;
+			if (pregame) {
+				switch (Overlay) {
+					case OVERLAY_GOLD1:
+					case OVERLAY_GOLD2:
+					case OVERLAY_GOLD3:
+					case OVERLAY_GOLD4:
+						value = Rule.GoldValue;
+						Overlay = Random_Pick(OVERLAY_GOLD1, OVERLAY_GOLD4);
+						break;
+
+					case OVERLAY_GEMS1:
+					case OVERLAY_GEMS2:
+					case OVERLAY_GEMS3:
+					case OVERLAY_GEMS4:
+						gems = true;
+						value = Rule.GemValue*4;
+						Overlay = Random_Pick(OVERLAY_GEMS1, OVERLAY_GEMS4);
+						break;
+
+					default:
+						break;
+				}
+			}
+
+			/*
+			**	Add up all adjacent cells that contain tiberium.
+			** (Skip those cells which aren't on the map)
+			*/
+			for (FacingType face = FACING_FIRST; face < FACING_COUNT; face++) {
+				CellClass & adj = Adjacent_Cell(face);
+
+				if (adj.Overlay != OVERLAY_NONE &&
+					OverlayTypeClass::As_Reference(adj.Overlay).Land == LAND_TIBERIUM) {
+					count++;
+				}
+			}
+
+			if (gems) {
+				OverlayData = _adjgem[count];
+				OverlayData = min(OverlayData, 2);
+			} else {
+				OverlayData = _adj[count];
+			}
+			return((OverlayData+1) * value);
+		}
+	}
+	return(0);
+}
+
+
+/***********************************************************************************************
+ * CellClass::Goodie_Check -- Performs crate discovery logic.                                  *
+ *                                                                                             *
+ *    Call this routine whenever an object enters a cell. It will check for the existence      *
+ *    of a crate and generate any "goodie" it might contain.                                   *
+ *                                                                                             *
+ * INPUT:   object   -- Pointer to the object that is triggering this crate.                   *
+ *                                                                                             *
+ * OUTPUT:  Can the object continue to enter this cell? A false return value means that the    *
+ *          cell is now occupied and must not be entered.                                      *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/22/1995 JLB : Created.                                                                 *
+ *   07/08/1995 JLB : Added a bunch of goodies to the crates.                                  *
+ *   06/17/1996 JLB : Revamped for Red Alert                                                   *
+ *=============================================================================================*/
+bool CellClass::Goodie_Check(FootClass * object)
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+
+	if (object != NULL && Overlay != OVERLAY_NONE && OverlayTypeClass::As_Reference(Overlay).IsCrate) {
+		bool force_mcv = false;
+		int force_money = 0;
+		int damage;
+		COORDINATE coord;
+
+		/*
+		**	Determine the total number of shares for all the crate powerups. This is used as
+		**	the base pool to determine the odds from.
+		*/
+		int total_shares = 0;
+		for (int index = CRATE_FIRST; index < CRATE_COUNT; index++) {
+			total_shares += CrateShares[index];
+		}
+
+		/*
+		**	Pick a random crate powerup according to the shares allotted to each powerup.
+		**	In solo play, the bonus item is dependant upon the rules control.
+		*/
+		CrateType powerup;
+		if (Session.Type == GAME_NORMAL) {
+
+			/*
+			**	Solo play has money amount determined by rules.ini file.
+			*/
+			force_money = Rule.SoloCrateMoney;
+
+			if (Overlay == OVERLAY_STEEL_CRATE) {
+				powerup = Rule.SilverCrate;
+			}
+
+			if (Overlay == OVERLAY_WOOD_CRATE) {
+				powerup = Rule.WoodCrate;
+			}
+
+			if (Overlay == OVERLAY_WATER_CRATE) {
+//Mono_Printf("%d-%s.\n", __LINE__, __FILE__);
+				powerup = Rule.WaterCrate;
+			}
+
+		} else {
+			int pick = Random_Pick(1, total_shares);
+
+			int share_count = 0;
+			for (powerup = CRATE_FIRST; powerup < CRATE_COUNT; powerup++) {
+				share_count += CrateShares[powerup];
+				if (pick <= share_count) break;
+			}
+			assert(powerup != CRATE_COUNT);
+
+			/*
+			**	Depending on what was picked, there might be an alternate goodie if the selected
+			**	goodie would have no effect.
+			*/
+			switch (powerup) {
+				case CRATE_UNIT:
+					if (object->House->CurUnits > 50) powerup = CRATE_MONEY;
+					break;
+
+				case CRATE_SQUAD:
+					if (object->House->CurInfantry > 100) powerup = CRATE_MONEY;
+					break;
+
+				case CRATE_DARKNESS:
+					if (object->House->IsGPSActive) powerup = CRATE_MONEY;
+					break;
+
+				case CRATE_ARMOR:
+					if (object->ArmorBias != 1) powerup = CRATE_MONEY;
+					break;
+
+				case CRATE_SPEED:
+					if (object->SpeedBias != 1 || object->What_Am_I() == RTTI_AIRCRAFT) powerup = CRATE_MONEY;
+					break;
+
+				case CRATE_FIREPOWER:
+					if (object->FirepowerBias != 1 || !object->Is_Weapon_Equipped()) powerup = CRATE_MONEY;
+					break;
+
+				case CRATE_REVEAL:
+					if (object->House->IsVisionary) {
+						if (object->House->IsGPSActive) {
+							powerup = CRATE_MONEY;
+						} else {
+							powerup = CRATE_DARKNESS;
+						}
+					}
+					break;
+
+				case CRATE_CLOAK:
+					if (object->IsCloakable) powerup = CRATE_MONEY;
+					break;
+
+//				case CRATE_HEAL_BASE:
+//					if (object->House->BScan == 0) powerup = CRATE_UNIT;
+
+				case CRATE_MONEY:
+					break;
+
+				case CRATE_TIMEQUAKE:
+					/*
+					** For the time quake crate, scan through and count up all the
+					** units (and infantry and ships and aircraft) and if either
+					** side has very few, allow the time quake.  Otherwise,
+					** change the crate to money or something.  Only do this for
+					** multiplay - for solo play, they get what they get.  First,
+					** check for time - the chance for getting a time quake crate
+					** should be very very low when they first start the mission,
+					** but as time goes on the chance goes up.
+					*/
+					if (Session.Type != GAME_NORMAL) {
+						int i,ucount;
+						int minunits = 1000;
+						bool found = false;
+						unsigned long minutes = (Score.ElapsedTime / TIMER_MINUTE);
+						if (minutes > 100) minutes = 100;
+						if (Random_Pick(0,100-(int)minutes) == 0) {
+							for (i=0; i < (Session.Players.Count() + Session.Options.AIPlayers); i++) {
+								ucount = 0;
+								HouseClass * hptr = Houses.Ptr(i + HOUSE_MULTI1);
+								if (hptr != NULL && !hptr->IsDefeated) {
+									int j;
+									for( j=0; j < UNIT_COUNT; j++) {
+										ucount += hptr->QuantityU(j);
+									}
+									for( j=0; j < INFANTRY_COUNT; j++) {
+										ucount += hptr->QuantityI(j);
+									}
+									for( j=0; j < AIRCRAFT_COUNT; j++) {
+										ucount += hptr->QuantityA(j);
+									}
+									for( j=0; j < VESSEL_COUNT; j++) {
+										ucount += hptr->QuantityV(j);
+									}
+									int bcount = 0;
+									for( j=0; j < STRUCT_COUNT; j++) {
+										bcount += hptr->QuantityB(j);
+									}
+									ucount += bcount/2;	// weight buildings less
+									minunits = min(minunits, ucount);
+								}
+							}
+							if (Random_Pick(0, minunits) == minunits) {
+								found = true;
+							}
+						}
+
+						if (!found) {
+							powerup = CRATE_MONEY;
+						}
+					}
+					break;
+			}
+			/*
+			**	Possibly force it to be an MCV if there is
+			**	sufficient money and no buildings left.
+			*/
+			if (	object->House->BScan == 0 &&
+					object->House->Available_Money() > ( (BuildingTypeClass::As_Reference(STRUCT_REFINERY).Cost + BuildingTypeClass::As_Reference(STRUCT_POWER).Cost) * object->House->CostBias) &&
+					Session.Options.Bases &&
+					!(object->House->UScan & UNITF_MCV)) {
+				powerup = CRATE_UNIT;
+				force_mcv = true;
+			}
+
+			/*
+			**	If the powerup is money but there is insufficient money to build a refinery but there is a construction
+			**	yard available, then force the money to be enough to rebuild the refinery.
+			*/
+			if (powerup == CRATE_MONEY && (object->House->BScan & (STRUCTF_CONST|STRUCTF_REFINERY)) == STRUCTF_CONST &&
+						object->House->Available_Money() < BuildingTypeClass::As_Reference(STRUCT_REFINERY).Cost * object->House->CostBias) {
+
+				force_money = BuildingTypeClass::As_Reference(STRUCT_REFINERY).Cost * object->House->CostBias;
+			}
+
+			/*
+			**	Special override for water crates so that illegal goodies items
+			**	won't appear.
+			*/
+			if (Overlay == OVERLAY_WATER_CRATE) {
+				switch (powerup) {
+					case CRATE_UNIT:
+					case CRATE_SQUAD:
+						powerup = CRATE_MONEY;
+						break;
+
+					default:
+						break;
+				}
+			}
+		}
+
+		/*
+		** Keep track of the number of each type of crate found
+		*/
+		if (Session.Type == GAME_INTERNET) {
+			object->House->TotalCrates->Increment_Unit_Total(powerup);
+		}
+
+		/*
+		**	Remove the crate from the map.
+		*/
+		Map.Remove_Crate(Cell_Number());
+//		Map[Cell_Number()].Overlay = OVERLAY_NONE;
+
+		if (Session.Type != GAME_NORMAL && Rule.IsMPCrates) {
+			Map.Place_Random_Crate();
+		}
+
+		/*
+		**	Generate any corresponding animation associated with this crate powerup.
+		*/
+		if (CrateAnims[powerup] != ANIM_NONE) {
+			new AnimClass(CrateAnims[powerup], Cell_Coord());
+		}
+
+		/*
+		**	Create the effect requested.
+		*/
+		bool tospeak = false;
+		switch (powerup) {
+			case CRATE_TIMEQUAKE:
+				TimeQuake = true;
+				break;
+
+			/*
+			**	Give the player money.
+			*/
+			case CRATE_MONEY:
+crate_money:
+				if (force_money > 0) {
+					object->House->Refund_Money(force_money);
+				} else {
+					object->House->Refund_Money(Random_Pick(CrateData[powerup], CrateData[powerup]+900));
+				}
+				break;
+
+			/*
+			**	Shroud the world in blackness.
+			*/
+			case CRATE_DARKNESS:
+				if (object->House == PlayerPtr) {
+					Map.Shroud_The_Map();
+				}
+				break;
+
+			/*
+			**	Reveal the entire map.
+			*/
+			case CRATE_REVEAL:
+				object->House->IsVisionary = true;
+				if (object->House == PlayerPtr) {
+					for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) {
+						Map.Map_Cell(cell, PlayerPtr);
+					}
+					Map.Flag_To_Redraw(true);
+				}
+				break;
+
+			/*
+			**	Try to create a unit where the crate was.
+			*/
+			case CRATE_UNIT: {
+				UnitTypeClass const * utp = NULL;
+
+				/*
+				**	Give the player an MCV if he has no base left but does have more than enough
+				**	money to rebuild a new base. Of course, if he already has an MCV, then don't
+				**	give him another one.
+				*/
+				if (force_mcv) {
+					utp = &UnitTypeClass::As_Reference(UNIT_MCV);
+				}
+
+				/*
+				**	If the player has a base and a refinery, but no harvester, then give him
+				**	a free one.
+				*/
+				if (utp == NULL && (object->House->BScan & STRUCTF_REFINERY) && !(object->House->UScan & UNITF_HARVESTER)) {
+					utp = &UnitTypeClass::As_Reference(UNIT_HARVESTER);
+				}
+
+				/*
+				**	Check for special unit type override value.
+				*/
+				if (Rule.UnitCrateType != UNIT_NONE) {
+					utp = &UnitTypeClass::As_Reference(Rule.UnitCrateType);
+				}
+
+				/*
+				**	If no unit type has been determined, then pick one at random.
+				*/
+				while (utp == NULL) {
+#ifdef FIXIT_ANTS
+#ifdef FIXIT_CSII	//	checked - ajw 9/28/98
+					UnitType utype = Random_Pick(UNIT_FIRST, (UnitType)(UNIT_RA_COUNT-1 -3));
+#else
+					UnitType utype = Random_Pick(UNIT_FIRST, (UnitType)(UNIT_COUNT-1 -3));
+#endif
+#else
+					UnitType utype = Random_Pick(UNIT_FIRST, (UnitType)(UNIT_COUNT-1));
+#endif
+					if (utype != UNIT_MCV || Session.Options.Bases) {
+						utp = &UnitTypeClass::As_Reference(utype);
+						if (utp->IsCrateGoodie && (utp->Ownable & (1 << HouseClass::As_Pointer(object->Owner())->ActLike))) {
+							break;
+						}
+						utp = NULL;
+					}
+				}
+
+				if (utp != NULL) {
+					UnitClass * goodie_unit = (UnitClass *)utp->Create_One_Of(object->House);
+					if (goodie_unit != NULL) {
+						if (goodie_unit->Unlimbo(Cell_Coord())) {
+							return(false);
+						}
+
+						/*
+						**	Try to place the object into a nearby cell if something is preventing
+						**	placement at the crate location.
+						*/
+						CELL cell = Map.Nearby_Location(Cell_Number(), goodie_unit->Class->Speed);
+						if (goodie_unit->Unlimbo(::Cell_Coord(cell))) {
+							return(false);
+						}
+						delete goodie_unit;
+						goto crate_money;
+					}
+				}
+			}
+			break;
+
+			/*
+			**	Create a squad of miscellaneous composition.
+			*/
+			case CRATE_SQUAD:
+				for (index = 0; index < 5; index++) {
+					static InfantryType _inf[] = {
+						INFANTRY_E1,INFANTRY_E1,INFANTRY_E1,INFANTRY_E1,INFANTRY_E1,INFANTRY_E1,
+						INFANTRY_E2,
+						INFANTRY_E3,
+						INFANTRY_RENOVATOR
+					};
+					if (!InfantryTypeClass::As_Reference(_inf[Random_Pick(0, ARRAY_SIZE(_inf)-1)]).Create_And_Place(Cell_Number(), object->Owner())) {
+						if (index == 0) {
+							goto crate_money;
+						}
+					}
+				}
+				return(false);
+
+			/*
+			**	A one para-bomb mission.
+			*/
+			case CRATE_PARA_BOMB:
+				if (object->House->SuperWeapon[SPC_PARA_BOMB].Enable(true)) {
+					if (object->IsOwnedByPlayer) {
+						Map.Add(RTTI_SPECIAL, SPC_PARA_BOMB);
+						Map.Column[1].Flag_To_Redraw();
+					}
+				}
+				break;
+
+			/*
+			**	A one time sonar pulse
+			*/
+			case CRATE_SONAR:
+				if (object->House->SuperWeapon[SPC_SONAR_PULSE].Enable(true)) {
+					if (object->IsOwnedByPlayer) {
+						Map.Add(RTTI_SPECIAL, SPC_SONAR_PULSE);
+						Map.Column[1].Flag_To_Redraw();
+					}
+				}
+				break;
+
+			/*
+			**	A group of explosions are triggered around the crate.
+			*/
+			case CRATE_EXPLOSION:
+				if (object != NULL) {
+					int d = CrateData[powerup];
+					object->Take_Damage(d, 0, WARHEAD_HE, 0, true);
+				}
+				for (index = 0; index < 5; index++) {
+					COORDINATE frag_coord = Coord_Scatter(Cell_Coord(), Random_Pick(0, 0x0200));
+					new AnimClass(ANIM_FBALL1, frag_coord);
+					damage = CrateData[powerup];
+					Explosion_Damage(frag_coord, damage, NULL, WARHEAD_HE);
+				}
+				break;
+
+			/*
+			**	A napalm blast is triggered.
+			*/
+			case CRATE_NAPALM:
+				coord = Coord_Mid(Cell_Coord(), object->Center_Coord());
+				new AnimClass(ANIM_NAPALM3, coord);
+				if (object != NULL) {
+					int d = CrateData[powerup];
+					object->Take_Damage(d, 0, WARHEAD_FIRE, 0, true);
+				}
+				damage = CrateData[powerup];
+				Explosion_Damage(coord, damage, NULL, WARHEAD_FIRE);
+				break;
+
+			/*
+			**	All objects within a certain range will gain the ability to cloak.
+			*/
+			case CRATE_CLOAK:
+				for (index = 0; index < DisplayClass::Layer[LAYER_GROUND].Count(); index++) {
+					ObjectClass * obj = DisplayClass::Layer[LAYER_GROUND][index];
+
+					if (obj && obj->Is_Techno() && Distance(Cell_Coord(), obj->Center_Coord()) < Rule.CrateRadius) {
+						((TechnoClass *)obj)->IsCloakable = true;
+					}
+				}
+				break;
+
+			/*
+			**	All of the player's objects heal up.
+			*/
+			case CRATE_HEAL_BASE:
+				if (object->IsOwnedByPlayer) {
+					Sound_Effect(VOC_HEAL, object->Center_Coord());
+				}
+				for (index = 0; index < Logic.Count(); index++) {
+					ObjectClass * obj = Logic[index];
+
+					if (obj && object->Is_Techno() && object->House->Class->House == obj->Owner()) {
+						obj->Strength = obj->Class_Of().MaxStrength;
+					}
+				}
+				break;
+
+
+			case CRATE_ICBM:
+				if (object->House->SuperWeapon[SPC_NUCLEAR_BOMB].Enable(true)) {
+					if (object->IsOwnedByPlayer) {
+						Map.Add(RTTI_SPECIAL, SPC_NUCLEAR_BOMB);
+						Map.Column[1].Flag_To_Redraw();
+					}
+				}
+				break;
+
+			case CRATE_ARMOR:
+				for (index = 0; index < DisplayClass::Layer[LAYER_GROUND].Count(); index++) {
+					ObjectClass * obj = DisplayClass::Layer[LAYER_GROUND][index];
+
+					if (obj != NULL && obj->Is_Techno() && Distance(Cell_Coord(), obj->Center_Coord()) < Rule.CrateRadius && ((TechnoClass *)obj)->ArmorBias == 1) {
+						fixed val = ((TechnoClass *)obj)->ArmorBias * Inverse(fixed(CrateData[powerup], 256));
+						((TechnoClass *)obj)->ArmorBias = val;
+						if (obj->Owner() == PlayerPtr->Class->House) tospeak = true;
+					}
+				}
+				if (tospeak) Speak(VOX_UPGRADE_ARMOR);
+				break;
+
+			case CRATE_SPEED:
+				for (index = 0; index < DisplayClass::Layer[LAYER_GROUND].Count(); index++) {
+					ObjectClass * obj = DisplayClass::Layer[LAYER_GROUND][index];
+
+					if (obj && obj->Is_Foot() && Distance(Cell_Coord(), obj->Center_Coord()) < Rule.CrateRadius && ((FootClass *)obj)->SpeedBias == 1 && obj->What_Am_I() != RTTI_AIRCRAFT) {
+						FootClass * foot = (FootClass *)obj;
+
+						fixed val = foot->SpeedBias * fixed(CrateData[powerup], 256);
+						foot->SpeedBias = val;
+						if (foot->IsOwnedByPlayer) tospeak = true;
+					}
+				}
+				if (tospeak) Speak(VOX_UPGRADE_SPEED);
+				break;
+
+			case CRATE_FIREPOWER:
+				for (index = 0; index < DisplayClass::Layer[LAYER_GROUND].Count(); index++) {
+					ObjectClass * obj = DisplayClass::Layer[LAYER_GROUND][index];
+
+					if (obj && obj->Is_Techno() && Distance(Cell_Coord(), obj->Center_Coord()) < Rule.CrateRadius && ((TechnoClass *)obj)->FirepowerBias == 1) {
+
+						fixed val = ((TechnoClass *)obj)->FirepowerBias * fixed(CrateData[powerup], 256);
+						((TechnoClass *)obj)->FirepowerBias = val;
+						if (obj->Owner() == PlayerPtr->Class->House) tospeak = true;
+					}
+				}
+				if (tospeak) Speak(VOX_UPGRADE_FIREPOWER);
+				break;
+
+			case CRATE_INVULN:
+				for (index = 0; index < DisplayClass::Layer[LAYER_GROUND].Count(); index++) {
+					ObjectClass * obj = DisplayClass::Layer[LAYER_GROUND][index];
+
+					if (obj && obj->Is_Techno() && Distance(Cell_Coord(), obj->Center_Coord()) < Rule.CrateRadius) {
+						((TechnoClass *)obj)->IronCurtainCountDown = (TICKS_PER_MINUTE * fixed(CrateData[powerup], 256));
+						obj->Mark(MARK_CHANGE);
+					}
+				}
+				break;
+
+			/*
+			** A chronal vortex appears targetted at the triggering object.
+			*/
+			case CRATE_VORTEX:
+				if ( !ChronalVortex.Is_Active()) {
+					ChronalVortex.Appear ( Cell_Coord() );
+					ChronalVortex.Set_Target ( (ObjectClass*) object );
+					Sound_Effect(VOC_TESLA_ZAP, object->Center_Coord());
+				}
+				break;
+
+			default:
+				break;
+		}
+	}
+	return(true);
+}
+
+
+/***********************************************************************************************
+ * CellClass::Flag_Place -- Places a house flag down on the cell.                              *
+ *                                                                                             *
+ *    This routine will place the house flag at this cell location.                            *
+ *                                                                                             *
+ * INPUT:   house -- The house that is having its flag placed here.                            *
+ *                                                                                             *
+ * OUTPUT:  Was the flag successfully placed here?                                             *
+ *                                                                                             *
+ * WARNINGS:   Failure to place means that the cell is impassable for some reason.             *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/23/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool CellClass::Flag_Place(HousesType house)
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+
+	if (!IsFlagged && Is_Clear_To_Move(SPEED_TRACK, false, false)) {
+		IsFlagged = true;
+		Owner = house;
+		Redraw_Objects();
+		return(true);
+	}
+	return(false);
+}
+
+
+/***********************************************************************************************
+ * CellClass::Flag_Remove -- Removes the house flag from the cell.                             *
+ *                                                                                             *
+ *    This routine will free the cell of any house flag that may be located there.             *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  Was there a flag here that was removed?                                            *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/23/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool CellClass::Flag_Remove(void)
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+
+	if (IsFlagged) {
+		IsFlagged = false;
+		Owner = HOUSE_NONE;
+		Redraw_Objects();
+		return(true);
+	}
+	return(false);
+}
+
+
+/***********************************************************************************************
+ * CellClass::Shimmer -- Causes all objects in the cell to shimmer.                            *
+ *                                                                                             *
+ *    This routine is called when some event would cause a momentary disruption in the         *
+ *    cloaking device. All objects that are cloaked in the cell will have their cloaking       *
+ *    device shimmer.                                                                          *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/29/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void CellClass::Shimmer(void)
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+
+	ObjectClass * object = Cell_Occupier();
+
+	while (object) {
+		object->Do_Shimmer();
+		object = object->Next;
+	}
+}
+
+
+/***********************************************************************************************
+ * CellClass::Is_Clear_To_Move -- Determines if the cell is generally clear for travel         *
+ *                                                                                             *
+ *    This routine is called when determining general passability for purposes of zone         *
+ *    calculation. Only blockages that cannot be circumvented are considered to make a cell    *
+ *    impassable. All other obstructions can either be destroyed or are temporary.             *
+ *                                                                                             *
+ * INPUT:   loco     -- The locomotion type to use when determining passablility.              *
+ *                                                                                             *
+ *          ignoreinfantry -- Should infantry in the cell be ignored for movement purposes?    *
+ *                                                                                             *
+ *          ignorevehicles -- If vehicles should be ignored, then this flag will be true.      *
+ *                                                                                             *
+ *          zone     -- If specified, the zone must match this value or else movement is       *
+ *                      presumed disallowed.                                                   *
+ *                                                                                             *
+ *          check    -- This specifies the zone type that this check applies to.               *
+ *                                                                                             *
+ * OUTPUT:  Is the cell generally passable to ground targeting?                                *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   09/25/1995 JLB : Created.                                                                 *
+ *   06/25/1996 JLB : Uses tracked vehicles as a basis for zone check.                         *
+ *   10/05/1996 JLB : Allows checking for crushable blockages.                                 *
+ *=============================================================================================*/
+bool CellClass::Is_Clear_To_Move(SpeedType loco, bool ignoreinfantry, bool ignorevehicles, int zone, MZoneType check) const
+{
+	assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
+
+	/*
+	**	Flying objects always consider every cell passable since they can fly over everything.
+	*/
+	if (loco == SPEED_WINGED) {
+		return(true);
+	}
+
+	/*
+	**	If a zone was specified, then see if the cell is in a legal
+	**	zone to allow movement.
+	*/
+	if (zone != -1) {
+		if (zone != Zones[check]) {
+			return(false);
+		}
+	}
+
+	/*
+	**	Check the occupy bits for passable legality. If ignore infantry is true, then
+	**	don't consider infnatry.
+	*/
+	int composite = Flag.Composite;
+	if (ignoreinfantry) {
+		composite &= 0xE0;			// Drop the infantry occupation bits.
+	}
+	if (ignorevehicles) {
+		composite &= 0x5F;			// Drop the vehicle/building bit.
+	}
+	if (composite != 0) {
+		return(false);
+	}
+
+	/*
+	**	Fetch the land type of the cell -- to be modified and used later.
+	*/
+	LandType land = Land_Type();
+
+	/*
+	**	Walls are always considered to block the terrain for general passability
+	**	purposes unless this is a wall crushing check or if the checking object
+	**	can destroy walls.
+	*/
+	OverlayTypeClass const * overlay = NULL;
+	if (Overlay != OVERLAY_NONE) {
+	 	overlay = &OverlayTypeClass::As_Reference(Overlay);
+	}
+	if (overlay != NULL && overlay->IsWall) {
+		if (check != MZONE_DESTROYER && (check != MZONE_CRUSHER || !overlay->IsCrushable)) {
+			return(false);
+		}
+
+		/*
+		**	Crushing objects consider crushable walls as clear rather than the
+		**	typical LAND_WALL setting.
+		*/
+		land = LAND_CLEAR;
+	}
+
+	/*
+	**	See if the ground type is impassable to this locomotion type and if
+	**	so, return the error condition.
+	*/
+	if (::Ground[land].Cost[loco] == 0) {
+		return(false);
+	}
+
+	/*
+	**	All checks passed, so this cell must be passable.
+	*/
+	return(true);
+}
+
+
+/***********************************************************************************************
+ * CellClass::Is_Bridge_Here -- Checks to see if this is a bridge occupied cell.               *
+ *                                                                                             *
+ *    This routine will examine this cell and if there is a bridge here, it will return        *
+ *    true.                                                                                    *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  bool; Is there a bridge located in this cell?                                      *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/30/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool CellClass::Is_Bridge_Here(void) const
+{
+	switch (TType) {
+		case TEMPLATE_BRIDGE1:
+		case TEMPLATE_BRIDGE1H:
+		case TEMPLATE_BRIDGE1D:
+		case TEMPLATE_BRIDGE2:
+		case TEMPLATE_BRIDGE2H:
+		case TEMPLATE_BRIDGE2D:
+		case TEMPLATE_BRIDGE_1A:
+		case TEMPLATE_BRIDGE_1B:
+		case TEMPLATE_BRIDGE_2A:
+		case TEMPLATE_BRIDGE_2B:
+		case TEMPLATE_BRIDGE_3A:
+		case TEMPLATE_BRIDGE_3B:
+		case TEMPLATE_BRIDGE_3C:
+		case TEMPLATE_BRIDGE_3D:
+		case TEMPLATE_BRIDGE_3E:
+		case TEMPLATE_BRIDGE_3F:
+			return(true);
+	}
+	return(false);
+}
+
+
+/***********************************************************************************************
+ * CellClass::Can_Tiberium_Grow -- Determines if Tiberium can grow in this cell.               *
+ *                                                                                             *
+ *    This checks the cell to see if Tiberium can grow at least one level in it. Tiberium can  *
+ *    grow only if there is Tiberium already present. It can only grow to a certain level      *
+ *    and then all further growth is suspended.                                                *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  bool; Can Tiberium grow in this cell?                                              *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/14/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool CellClass::Can_Tiberium_Grow(void) const
+{
+	if (!Rule.IsTGrowth) return(false);
+
+	if (Session.Type != GAME_NORMAL) {
+		if(!Session.Options.Tiberium) return(false);
+	}
+
+	if (Land_Type() != LAND_TIBERIUM) return(false);
+
+	if (OverlayData >= 11) return(false);
+
+	if (Overlay != OVERLAY_GOLD1 && Overlay != OVERLAY_GOLD2 && Overlay != OVERLAY_GOLD3 && Overlay != OVERLAY_GOLD4) return(false);
+
+	return(true);
+}
+
+
+/***********************************************************************************************
+ * CellClass::Can_Tiberium_Spread -- Determines if Tiberium can spread from this cell.         *
+ *                                                                                             *
+ *    This routine will examine the cell and determine if there is sufficient Tiberium         *
+ *    present that Tiberium spores will spread to adjacent cells. If the Tiberium level is     *
+ *    too low, spreading will not occur.                                                       *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  bool; Can Tiberium spread from this cell into adjacent cells?                      *
+ *                                                                                             *
+ * WARNINGS:   This routine does not check to see if, in fact, there are any adjacent cells    *
+ *             available to spread to.                                                         *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/14/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool CellClass::Can_Tiberium_Spread(void) const
+{
+	if (!Rule.IsTSpread) return(false);
+
+	if (Session.Type != GAME_NORMAL) {
+		if(!Session.Options.Tiberium) return(false);
+	}
+
+	if (Land_Type() != LAND_TIBERIUM) return(false);
+
+	if (OverlayData <= 6) return(false);
+
+	if (Overlay != OVERLAY_GOLD1 && Overlay != OVERLAY_GOLD2 && Overlay != OVERLAY_GOLD3 && Overlay != OVERLAY_GOLD4) return(false);
+
+	return(true);
+}
+
+
+/***********************************************************************************************
+ * CellClass::Grow_Tiberium -- Grows the tiberium in the cell.                                 *
+ *                                                                                             *
+ *    This routine will cause the tiberium to grow in the cell.                                *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  bool; Did Tiberium grow in the cell?                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/14/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool CellClass::Grow_Tiberium(void)
+{
+	if (Can_Tiberium_Grow()) {
+		OverlayData++;
+		Redraw_Objects();
+		return(true);
+	}
+	return(false);
+}
+
+
+/***********************************************************************************************
+ * CellClass::Spread_Tiberium -- Spread Tiberium from this cell to an adjacent cell.           *
+ *                                                                                             *
+ *    This routine will cause the Tiberium to spread from this cell into an adjacent (random)  *
+ *    cell.                                                                                    *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  bool; Did the Tiberium spread?                                                     *
+ *                                                                                             *
+ * WARNINGS:   If there are no adjacent cells that the tiberium can spread to, then this       *
+ *             routine will fail.                                                              *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/14/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool CellClass::Spread_Tiberium(bool forced)
+{
+	if (!forced) {
+		if (!Can_Tiberium_Spread()) return(false);
+	}
+	FacingType offset = Random_Pick(FACING_N, FACING_NW);
+	for (FacingType index = FACING_N; index < FACING_COUNT; index++) {
+		CellClass * newcell = &Adjacent_Cell(index+offset);
+
+		if (newcell != NULL && newcell->Can_Tiberium_Germinate()) {
+			new OverlayClass(Random_Pick(OVERLAY_GOLD1, OVERLAY_GOLD4), newcell->Cell_Number());
+			newcell->OverlayData = 0;
+			return(true);
+		}
+	}
+	return(false);
+}
+
+
+/***********************************************************************************************
+ * CellClass::Can_Tiberium_Germinate -- Determines if Tiberium can begin growth in the cell.   *
+ *                                                                                             *
+ *    This routine will examine the cell and determine if Tiberium can start growth in it.     *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  bool; Can Tiberium grow in this cell?                                              *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/14/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+bool CellClass::Can_Tiberium_Germinate(void) const
+{
+	if (!Map.In_Radar(Cell_Number())) return(false);
+
+	if (Is_Bridge_Here()) return(false);
+
+	/*
+	**	Don't allow Tiberium to grow on a cell with a building unless that building is
+	**	invisible. In such a case, the Tiberium must grow or else the location of the
+	**	building will be revealed.
+	*/
+	BuildingClass const * building = Cell_Building();
+	if (building != NULL && !building->Class->IsInvisible) return(false);
+
+	if (!Ground[Land_Type()].Build) return(false);
+
+	if (Overlay != OVERLAY_NONE) return(false);
+
+	return(true);
+}

+ 295 - 0
CODE/CELL.H

@@ -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 - 0
CODE/CHECKBOX.CPP

@@ -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 - 0
CODE/CHECKBOX.H

@@ -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 - 0
CODE/CHEKLIST.CPP

@@ -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 - 0
CODE/CHEKLIST.H

@@ -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 - 0
CODE/CLASS.CPP

@@ -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 - 0
CODE/CO-WC32.LNT

@@ -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 - 0
CODE/COLRLIST.CPP

@@ -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 - 0
CODE/COLRLIST.H

@@ -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 - 0
CODE/COMBAT.CPP

@@ -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 - 0
CODE/COMBUF.CPP

@@ -0,0 +1,1164 @@
+/*
+**	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.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 : COMBUF.CPP                             	*
+ *                                                                         *
+ *                   Programmer : Bill Randolph                            *
+ *                                                                         *
+ *                   Start Date : December 19, 1994                        *
+ *                                                                         *
+ *                  Last Update : October 23, 1995 [BRR]                   *
+ *                                                                         *
+ *-------------------------------------------------------------------------*
+ * Functions:                                                              *
+ *   CommBufferClass::CommBufferClass -- class constructor           		*
+ *   CommBufferClass::~CommBufferClass -- class destructor           		*
+ *   CommBufferClass::Init -- initializes this queue                       *
+ *   CommBufferClass::Init_Send_Queue -- Clears the send queue             *
+ *   CommBufferClass::Queue_Send -- queues a message for sending           *
+ *   CommBufferClass::UnQueue_Send -- removes next entry from send queue	*
+ *   CommBufferClass::Get_Send -- gets ptr to queue entry                  *
+ *   CommBufferClass::Queue_Receive -- queues a received message				*
+ *   CommBufferClass::UnQueue_Receive -- removes next entry from send queue*
+ *   CommBufferClass::Get_Receive -- gets ptr to queue entry               *
+ *   CommBufferClass::Add_Delay -- adds a new delay value for response time*
+ *   CommBufferClass::Avg_Response_Time -- returns average response time  	*
+ *   CommBufferClass::Max_Response_Time -- returns max response time  		*
+ *   CommBufferClass::Reset_Response_Time -- resets computations				*
+ *   Mono_Debug_Print -- Debug output routine                              *
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+
+#include	"function.h"
+#include <stdio.h>
+#include <mem.h>
+#include "combuf.h"
+#include "connect.h"	// for command names for debug output
+#include "wwlib32.h"	// to enable mono output
+
+
+/***************************************************************************
+ * CommBufferClass::CommBufferClass -- class constructor             		*
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		numsend		# queue entries for sending										*
+ *		numreceive	# queue entries for receiving										*
+ *		maxlen		maximum desired packet length, in bytes						*
+ *		extralen		max size of app-specific extra bytes (optional)				*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		none.																						*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   12/19/1994 BR : Created.                                              *
+ *=========================================================================*/
+CommBufferClass::CommBufferClass(int numsend, int numreceive, int maxlen,
+	int extralen)
+{
+	int i;
+
+	//------------------------------------------------------------------------
+	//	Init variables
+	//------------------------------------------------------------------------
+	MaxSend = numsend;
+	MaxReceive = numreceive;
+	MaxPacketSize = maxlen;
+	MaxExtraSize = extralen;
+
+	//------------------------------------------------------------------------
+	//	Allocate the queue entries
+	//------------------------------------------------------------------------
+	SendQueue = new SendQueueType[numsend];
+	ReceiveQueue = new ReceiveQueueType[numreceive];
+
+	SendIndex = new int[numsend];
+	ReceiveIndex = new int[numreceive];
+
+	//------------------------------------------------------------------------
+	//	Allocate queue entry buffers
+	//------------------------------------------------------------------------
+	for (i = 0; i < MaxSend; i++) {
+		SendQueue[i].Buffer = new char[maxlen];
+		if (MaxExtraSize > 0) {
+			SendQueue[i].ExtraBuffer = new char[MaxExtraSize];
+		}
+		else {
+			SendQueue[i].ExtraBuffer = NULL;
+		}
+	}
+
+	for (i = 0; i < MaxReceive; i++) {
+		ReceiveQueue[i].Buffer = new char[maxlen];
+		if (MaxExtraSize > 0) {
+			ReceiveQueue[i].ExtraBuffer = new char[MaxExtraSize];
+		}
+		else {
+			ReceiveQueue[i].ExtraBuffer = NULL;
+		}
+	}
+
+	Init();
+
+}	/* end of CommBufferClass */
+
+
+/***************************************************************************
+ * CommBufferClass::~CommBufferClass -- class destructor             		*
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		none.																						*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		none.																						*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   12/19/1994 BR : Created.                                              *
+ *=========================================================================*/
+CommBufferClass::~CommBufferClass()
+{
+	int i;
+
+	//------------------------------------------------------------------------
+	//	Free queue entry buffers
+	//------------------------------------------------------------------------
+	for (i = 0; i < MaxSend; i++) {
+		delete [] SendQueue[i].Buffer;
+		if (SendQueue[i].ExtraBuffer) {
+			delete [] SendQueue[i].ExtraBuffer;
+		}
+	}
+
+	for (i = 0; i < MaxReceive; i++) {
+		delete [] ReceiveQueue[i].Buffer;
+		if (ReceiveQueue[i].ExtraBuffer) {
+			delete [] ReceiveQueue[i].ExtraBuffer;
+		}
+	}
+
+	delete [] SendQueue;
+	delete [] ReceiveQueue;
+
+	delete [] SendIndex;
+	delete [] ReceiveIndex;
+
+}	/* end of ~CommBufferClass */
+
+
+/***************************************************************************
+ * CommBufferClass::Init -- initializes this queue                         *
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		none.																						*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		none.																						*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   01/20/1995 BR : Created.                                              *
+ *=========================================================================*/
+void CommBufferClass::Init(void)
+{
+	int i;
+
+	//------------------------------------------------------------------------
+	//	Init data members
+	//------------------------------------------------------------------------
+	SendTotal = 0L;
+	ReceiveTotal = 0L;
+
+	DelaySum = 0L;
+	NumDelay = 0L;
+	MeanDelay = 0L;
+	MaxDelay = 0L;
+
+	SendCount = 0;
+
+	ReceiveCount = 0;
+
+	//------------------------------------------------------------------------
+	//	Init the queue entries
+	//------------------------------------------------------------------------
+	for (i = 0; i < MaxSend; i++) {
+		SendQueue[i].IsActive = 0;
+		SendQueue[i].IsACK = 0;
+		SendQueue[i].FirstTime = 0L;
+		SendQueue[i].LastTime = 0L;
+		SendQueue[i].SendCount = 0L;
+		SendQueue[i].BufLen = 0;
+		SendQueue[i].ExtraLen = 0;
+
+		SendIndex[i] = 0;
+	}
+
+	for (i = 0; i < MaxReceive; i++) {
+		ReceiveQueue[i].IsActive = 0;
+		ReceiveQueue[i].IsRead = 0;
+		ReceiveQueue[i].IsACK = 0;
+		ReceiveQueue[i].BufLen = 0;
+		ReceiveQueue[i].ExtraLen = 0;
+
+		ReceiveIndex[i] = 0;
+	}
+
+	//------------------------------------------------------------------------
+	//	Init debug values
+	//------------------------------------------------------------------------
+	DebugOffset = 0;
+	DebugSize = 0;
+	DebugNames = NULL;
+	DebugNameCount = 0;
+
+}	/* end of Init */
+
+
+/***************************************************************************
+ * CommBufferClass::Init_Send_Queue -- Clears the send queue               *
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		none.																						*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		none.																						*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   10/23/1995 BRR : Created.                                             *
+ *=========================================================================*/
+void CommBufferClass::Init_Send_Queue(void)
+{
+	int i;
+
+	//------------------------------------------------------------------------
+	//	Init data members
+	//------------------------------------------------------------------------
+	SendCount = 0;
+
+	//------------------------------------------------------------------------
+	//	Init the queue entries
+	//------------------------------------------------------------------------
+	for (i = 0; i < MaxSend; i++) {
+		SendQueue[i].IsActive = 0;
+		SendQueue[i].IsACK = 0;
+		SendQueue[i].FirstTime = 0L;
+		SendQueue[i].LastTime = 0L;
+		SendQueue[i].SendCount = 0L;
+		SendQueue[i].BufLen = 0;
+		SendQueue[i].ExtraLen = 0;
+
+		SendIndex[i] = 0;
+	}
+
+}	/* end of Init_Send_Queue */
+
+
+/***************************************************************************
+ * CommBufferClass::Queue_Send -- queues a message for sending             *
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		buf			buffer containing the message										*
+ *		buflen		length of 'buf'														*
+ *		extrabuf		buffer containing extra data (optional)						*
+ *		extralen		length of extra data (optional)									*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		1 = OK, 0 = no room in the queue													*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   12/20/1994 BR : Created.                                              *
+ *=========================================================================*/
+int CommBufferClass::Queue_Send(void *buf, int buflen, void *extrabuf,
+	int extralen)
+{
+	int i;
+	int index;
+
+	//------------------------------------------------------------------------
+	//	Error if no room in the queue
+	//------------------------------------------------------------------------
+	if (SendCount==MaxSend || buflen > MaxPacketSize)
+		return(0);
+
+	//------------------------------------------------------------------------
+	//	Find an empty slot
+	//------------------------------------------------------------------------
+	index = -1;
+	for (i = 0; i < MaxSend; i++) {
+		if (SendQueue[i].IsActive==0) {
+			index = i;
+			break;
+		}
+	}
+	if (index == -1)
+		return (0);
+
+	//------------------------------------------------------------------------
+	//	Set entry flags
+	//------------------------------------------------------------------------
+	SendQueue[index].IsActive = 1;			// entry is now active
+	SendQueue[index].IsACK = 0;				// entry hasn't been ACK'd
+	SendQueue[index].FirstTime = 0L;			// filled in by Manager when sent
+	SendQueue[index].LastTime = 0L;			// filled in by Manager when sent
+	SendQueue[index].SendCount = 0L;			// filled in by Manager when sent
+	SendQueue[index].BufLen = buflen;		// save buffer size
+
+	//------------------------------------------------------------------------
+	//	Copy the packet data
+	//------------------------------------------------------------------------
+	memcpy(SendQueue[index].Buffer,buf,buflen);
+
+	//------------------------------------------------------------------------
+	//	Fill in the extra data, if there is any
+	//------------------------------------------------------------------------
+	if (extrabuf!=NULL && extralen > 0 && extralen <= MaxExtraSize) {
+		memcpy(SendQueue[index].ExtraBuffer,extrabuf,extralen);
+		SendQueue[index].ExtraLen = extralen;
+	}
+	else {
+		SendQueue[index].ExtraLen = 0;
+	}
+
+	//------------------------------------------------------------------------
+	//	Save this entry's index
+	//------------------------------------------------------------------------
+	SendIndex[SendCount] = index;
+
+	//------------------------------------------------------------------------
+	//	Increment counters & entry ptr
+	//------------------------------------------------------------------------
+	SendCount++;
+	SendTotal++;
+
+	return(1);
+
+}	/* end of Queue_Send */
+
+
+/***************************************************************************
+ * CommBufferClass::UnQueue_Send -- removes next entry from send queue		*
+ *                                                                         *
+ * Frees the given entry; the index given by the caller is the "active"		*
+ * index value (ie the "nth" active entry), not the actual index in the		*
+ * array.																						*
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		buf			buffer to store entry's data in; if NULL, it's discarded	*
+ *		buflen		filled in with length of entry retrieved						*
+ *		index			"index" of entry to un-queue										*
+ *		extrabuf		buffer for extra data (optional)									*
+ *		extralen		ptr to length of extra data (optional)							*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		1 = OK, 0 = no entry to retrieve													*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   12/20/1994 BR : Created.                                              *
+ *=========================================================================*/
+int CommBufferClass::UnQueue_Send(void *buf, int *buflen, int index,
+	void *extrabuf, int *extralen)
+{
+	int i;
+
+	//------------------------------------------------------------------------
+	//	Error if no entry to retrieve
+	//------------------------------------------------------------------------
+	if (SendCount==0 || SendQueue[SendIndex[index]].IsActive==0) {
+		return(0);
+	}
+
+	//------------------------------------------------------------------------
+	//	Copy the data from the entry
+	//------------------------------------------------------------------------
+	if (buf!=NULL) {
+		memcpy(buf,SendQueue[SendIndex[index]].Buffer,
+			SendQueue[SendIndex[index]].BufLen);
+		(*buflen) = SendQueue[SendIndex[index]].BufLen;
+	}
+
+	//------------------------------------------------------------------------
+	//	Copy the extra data
+	//------------------------------------------------------------------------
+	if (extrabuf!=NULL && extralen!=NULL) {
+		memcpy(extrabuf,SendQueue[SendIndex[index]].ExtraBuffer,
+			SendQueue[SendIndex[index]].ExtraLen);
+		(*extralen) = SendQueue[SendIndex[index]].ExtraLen;
+	}
+
+	//------------------------------------------------------------------------
+	//	Set entry flags
+	//------------------------------------------------------------------------
+	SendQueue[SendIndex[index]].IsActive = 0;
+	SendQueue[SendIndex[index]].IsACK = 0;
+	SendQueue[SendIndex[index]].FirstTime = 0L;
+	SendQueue[SendIndex[index]].LastTime = 0L;
+	SendQueue[SendIndex[index]].SendCount = 0L;
+	SendQueue[SendIndex[index]].BufLen = 0;
+	SendQueue[SendIndex[index]].ExtraLen = 0;
+
+	//------------------------------------------------------------------------
+	//	Move Indices back one
+	//------------------------------------------------------------------------
+	for (i = index; i < SendCount - 1; i++) {
+		SendIndex[i] = SendIndex[i + 1];
+	}
+	SendIndex[SendCount - 1] = 0;
+	SendCount--;
+
+	return(1);
+
+}	/* end of UnQueue_Send */
+
+
+/***************************************************************************
+ * CommBufferClass::Get_Send -- gets ptr to queue entry                    *
+ *                                                                         *
+ * This routine gets a pointer to the indicated queue entry.  The index		*
+ * value is relative to the next-accessible queue entry; 0 = get the			*
+ * next available queue entry, 1 = get the one behind that, etc.				*
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		index		index of entry to get (0 = 1st available)							*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		ptr to entry																			*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   12/21/1994 BR : Created.                                              *
+ *=========================================================================*/
+SendQueueType * CommBufferClass::Get_Send(int index)
+{
+	if (SendQueue[SendIndex[index]].IsActive==0) {
+		return(NULL);
+	}
+	else {
+		return(&SendQueue[SendIndex[index]]);
+	}
+
+}	/* end of Get_Send */
+
+
+/***************************************************************************
+ * CommBufferClass::Queue_Receive -- queues a received message					*
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		buf			buffer containing the message										*
+ *		buflen		length of 'buf'														*
+ *		extrabuf		buffer containing extra data (optional)						*
+ *		extralen		length of extra data (optional)									*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		1 = OK, 0 = no room in the queue													*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   12/20/1994 BR : Created.                                              *
+ *=========================================================================*/
+int CommBufferClass::Queue_Receive(void *buf, int buflen, void *extrabuf,
+	int extralen)
+{
+	int i;
+	int index;
+
+	//------------------------------------------------------------------------
+	//	Error if no room in the queue
+	//------------------------------------------------------------------------
+	if (ReceiveCount==MaxReceive || buflen > MaxPacketSize) {
+		return(0);
+	}
+
+	//------------------------------------------------------------------------
+	//	Find an empty slot
+	//------------------------------------------------------------------------
+	index = -1;
+	for (i = 0; i < MaxReceive; i++) {
+		if (ReceiveQueue[i].IsActive==0) {
+			index = i;
+			break;
+		}
+	}
+	if (index == -1)
+		return (0);
+
+	//------------------------------------------------------------------------
+	//	Set entry flags
+	//------------------------------------------------------------------------
+	ReceiveQueue[index].IsActive = 1;
+	ReceiveQueue[index].IsRead = 0;
+	ReceiveQueue[index].IsACK = 0;
+	ReceiveQueue[index].BufLen = buflen;
+
+	//------------------------------------------------------------------------
+	//	Copy the packet data
+	//------------------------------------------------------------------------
+	memcpy(ReceiveQueue[index].Buffer,buf,buflen);
+
+	//------------------------------------------------------------------------
+	//	Fill in the extra data, if there is any
+	//------------------------------------------------------------------------
+	if (extrabuf!=NULL && extralen > 0 && extralen <= MaxExtraSize) {
+		memcpy(ReceiveQueue[index].ExtraBuffer,extrabuf,extralen);
+		ReceiveQueue[index].ExtraLen = extralen;
+	}
+	else {
+		ReceiveQueue[index].ExtraLen = 0;
+	}
+
+	//------------------------------------------------------------------------
+	//	Save this entry's index
+	//------------------------------------------------------------------------
+	ReceiveIndex[ReceiveCount] = index;
+
+	//------------------------------------------------------------------------
+	//	Increment counters & entry ptr
+	//------------------------------------------------------------------------
+	ReceiveCount++;
+	ReceiveTotal++;
+
+	return(1);
+
+}	/* end of Queue_Receive */
+
+
+/***************************************************************************
+ * CommBufferClass::UnQueue_Receive -- removes next entry from send queue	*
+ *                                                                         *
+ * Frees the given entry; the index given by the caller is the "active"		*
+ * index value (ie the "nth" active entry), not the actual index in the		*
+ * array.																						*
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		buf			buffer to store entry's data in; if NULL, it's discarded	*
+ *		buflen		filled in with length of entry retrieved						*
+ *		index			index of entry to un-queue											*
+ *		extrabuf		buffer for extra data (optional)									*
+ *		extralen		ptr to length of extra data (optional)							*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		1 = OK, 0 = no entry to retrieve													*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   12/20/1994 BR : Created.                                              *
+ *=========================================================================*/
+int CommBufferClass::UnQueue_Receive(void *buf, int *buflen, int index,
+	void *extrabuf, int *extralen)
+{
+	int i;
+
+	//------------------------------------------------------------------------
+	//	Error if no entry to retrieve
+	//------------------------------------------------------------------------
+	if (ReceiveCount==0 || ReceiveQueue[ReceiveIndex[index]].IsActive==0) {
+		return(0);
+	}
+
+	//------------------------------------------------------------------------
+	//	Copy the data from the entry
+	//------------------------------------------------------------------------
+	if (buf!=NULL) {
+		memcpy(buf,ReceiveQueue[ReceiveIndex[index]].Buffer,
+			ReceiveQueue[ReceiveIndex[index]].BufLen);
+		(*buflen) = ReceiveQueue[ReceiveIndex[index]].BufLen;
+	}
+
+	//------------------------------------------------------------------------
+	//	Copy the extra data
+	//------------------------------------------------------------------------
+	if (extrabuf!=NULL && extralen!=NULL) {
+		memcpy(extrabuf,ReceiveQueue[ReceiveIndex[index]].ExtraBuffer,
+			ReceiveQueue[ReceiveIndex[index]].ExtraLen);
+		(*extralen) = ReceiveQueue[ReceiveIndex[index]].ExtraLen;
+	}
+
+	//------------------------------------------------------------------------
+	//	Set entry flags
+	//------------------------------------------------------------------------
+	ReceiveQueue[ReceiveIndex[index]].IsActive = 0;
+	ReceiveQueue[ReceiveIndex[index]].IsRead = 0;
+	ReceiveQueue[ReceiveIndex[index]].IsACK = 0;
+	ReceiveQueue[ReceiveIndex[index]].BufLen = 0;
+	ReceiveQueue[ReceiveIndex[index]].ExtraLen = 0;
+
+	//------------------------------------------------------------------------
+	//	Move Indices back one
+	//------------------------------------------------------------------------
+	for (i = index; i < ReceiveCount - 1; i++) {
+		ReceiveIndex[i] = ReceiveIndex[i + 1];
+	}
+	ReceiveIndex[ReceiveCount - 1] = 0;
+	ReceiveCount--;
+
+	return(1);
+
+}	/* end of UnQueue_Receive */
+
+
+/***************************************************************************
+ * CommBufferClass::Get_Receive -- gets ptr to queue entry                 *
+ *                                                                         *
+ * This routine gets a pointer to the indicated queue entry.  The index		*
+ * value is relative to the next-accessible queue entry; 0 = get the			*
+ * next available queue entry, 1 = get the one behind that, etc.				*
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		index		index of entry to get (0 = 1st available)							*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		ptr to entry																			*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   12/21/1994 BR : Created.                                              *
+ *=========================================================================*/
+ReceiveQueueType * CommBufferClass::Get_Receive(int index)
+{
+	if (ReceiveQueue[ReceiveIndex[index]].IsActive==0) {
+		return(NULL);
+	}
+	else {
+		return(&ReceiveQueue[ReceiveIndex[index]]);
+	}
+
+}	/* end of Get_Receive */
+
+
+/***************************************************************************
+ * CommBufferClass::Add_Delay -- adds a new delay value for response time  *
+ *                                                                         *
+ * This routine updates the average response time for this queue.  The		*
+ * computation is based on the average of the last 'n' delay values given,	*
+ * It computes a running total of the last n delay values, then divides 	*
+ * that by n to compute the average.													*
+ *																									*
+ * When the number of values given exceeds the max, the mean is subtracted	*
+ * off the total, then the new value is added in.  Thus, any single delay	*
+ * value will have an effect on the total that approaches 0 over time, and	*
+ * the new delay value contributes to 1/n of the mean.							*
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		delay			value to add into the response time computation				*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		none.																						*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   01/19/1995 BR : Created.                                              *
+ *=========================================================================*/
+void CommBufferClass::Add_Delay(unsigned long delay)
+{
+	int roundoff = 0;
+
+	if (NumDelay==256) {
+		DelaySum -= MeanDelay;
+		DelaySum += delay;
+		if ( (DelaySum & 0x00ff) > 127)
+			roundoff = 1;
+		MeanDelay = (DelaySum >> 8) + roundoff;
+	}
+	else {
+		NumDelay++;
+		DelaySum += delay;
+		MeanDelay = DelaySum / NumDelay;
+	}
+
+	if (delay > MaxDelay) {
+		MaxDelay = delay;
+	}
+
+}	/* end of Add_Delay */
+
+
+/***************************************************************************
+ * CommBufferClass::Avg_Response_Time -- returns average response time    	*
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		none.																						*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		latest computed average response time											*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   01/19/1995 BR : Created.                                              *
+ *=========================================================================*/
+unsigned long CommBufferClass::Avg_Response_Time(void)
+{
+	return(MeanDelay);
+
+}	/* end of Avg_Response_Time */
+
+
+/***************************************************************************
+ * CommBufferClass::Max_Response_Time -- returns max response time    		*
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		none.																						*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		latest computed average response time											*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   01/19/1995 BR : Created.                                              *
+ *=========================================================================*/
+unsigned long CommBufferClass::Max_Response_Time(void)
+{
+	return(MaxDelay);
+
+}	/* end of Max_Response_Time */
+
+
+/***************************************************************************
+ * CommBufferClass::Reset_Response_Time -- resets computations					*
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		none.																						*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		none.																						*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   01/19/1995 BR : Created.                                              *
+ *=========================================================================*/
+void CommBufferClass::Reset_Response_Time(void)
+{
+	DelaySum = 0L;
+	NumDelay = 0L;
+	MeanDelay = 0L;
+	MaxDelay = 0L;
+
+}	/* end of Reset_Response_Time */
+
+
+/***************************************************************************
+ * CommBufferClass::Configure_Debug -- sets up special debug values        *
+ *                                                                         *
+ * Mono_Debug_Print2() can look into a packet to pull out a particular		*
+ * ID, and can print both that ID and a string corresponding to				*
+ * that ID.  This routine configures these values so it can find				*
+ * and decode the ID.  This ID is used in addition to the normal				*
+ * CommHeaderType values.																	*
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		type_offset		ID's byte offset into packet									*
+ *		type_size		size of ID, in bytes; 0 if none								*
+ *		names				ptr to array of names; use ID as an index into this	*
+ *		maxnames			max # in the names array; 0 if none.						*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		none.																						*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		Names shouldn't be longer than 12 characters.								*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   05/31/1995 BRR : Created.                                             *
+ *=========================================================================*/
+void CommBufferClass::Configure_Debug(int type_offset, int type_size,
+	char **names, int namestart, int namecount)
+{
+	DebugOffset = type_offset;
+	DebugSize = type_size;
+	DebugNames = names;
+	DebugNameStart = namestart;
+	DebugNameCount = namecount;
+
+}	/* end of Configure_Debug */
+
+
+/***************************************************************************
+ * Mono_Debug_Print -- Debug output routine                                *
+ *                                                                         *
+ * This routine leaves 5 lines at the top for the caller's use.				*
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		refresh		1 = clear screen & completely refresh							*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		none.																						*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   05/02/1995 BRR : Created.                                             *
+ *=========================================================================*/
+void CommBufferClass::Mono_Debug_Print(int refresh)
+{
+#ifdef WWLIB32_H
+	int i;												// loop counter
+	static int send_col[] = {1,14,28};			// coords of send queue columns
+	static int receive_col[] = {40,54,68};		// coords of recv queue columns
+	int row,col;										// current row,col for printing
+	int num;												// max # items to print
+
+	struct CommHdr {									// this mirrors the CommHeaderType
+		unsigned short MagicNumber;
+		unsigned char Code;
+		unsigned long PacketID;
+	} *hdr;
+
+	//------------------------------------------------------------------------
+	//	If few enough entries, call the verbose debug version
+	//------------------------------------------------------------------------
+	if (MaxSend <= 16) {
+		Mono_Debug_Print2(refresh);
+		return;
+	}
+
+	//------------------------------------------------------------------------
+	//	Refresh the screen
+	//------------------------------------------------------------------------
+	if (refresh) {
+		Mono_Clear_Screen ();
+		Mono_Printf("ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿\n");
+		Mono_Printf("³                                                                             ³\n");
+		Mono_Printf("³                                                                             ³\n");
+		Mono_Printf("³                                                                             ³\n");
+		Mono_Printf("ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´\n");
+		Mono_Printf("³              Send Queue              ³             Receive Queue            ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³ ID  Ct ACK   ID  Ct ACK    ID  Ct ACK³ ID  Rd ACK    ID  Rd ACK   ID  Rd ACK³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ");
+	}
+
+	//------------------------------------------------------------------------
+	//	Print Send Queue items
+	//------------------------------------------------------------------------
+	if (MaxSend <= 48) {
+		num = MaxSend;
+	}
+	else {
+		num = 48;
+	}
+	col = 0;
+	row = 0;
+	for (i = 0; i < MaxSend; i++) {
+		Mono_Set_Cursor (send_col[col],row + 8);
+		if (SendQueue[i].IsActive) {
+			hdr = (CommHdr *)SendQueue[i].Buffer;
+			hdr->MagicNumber = hdr->MagicNumber;
+			hdr->Code = hdr->Code;
+			Mono_Printf ("%4d %2d  %d",hdr->PacketID, SendQueue[i].SendCount,
+				SendQueue[i].IsACK);
+		}
+		else {
+			Mono_Printf ("____ __  _ ");
+		}
+
+		row++;
+		if (row > 15) {
+			row = 0;
+			col++;
+		}
+	}
+
+	//------------------------------------------------------------------------
+	//	Print Receive Queue items
+	//------------------------------------------------------------------------
+	if (MaxReceive <= 48) {
+		num = MaxSend;
+	}
+	else {
+		num = 48;
+	}
+	col = 0;
+	row = 0;
+	for (i = 0; i < MaxReceive; i++) {
+		Mono_Set_Cursor (receive_col[col],row + 8);
+		if (ReceiveQueue[i].IsActive) {
+			hdr = (CommHdr *)ReceiveQueue[i].Buffer;
+			Mono_Printf ("%4d  %d  %d",hdr->PacketID, ReceiveQueue[i].IsRead,
+				ReceiveQueue[i].IsACK);
+		}
+		else {
+			Mono_Printf ("____  _  _ ");
+		}
+
+		row++;
+		if (row > 15) {
+			row = 0;
+			col++;
+		}
+	}
+
+#else
+	refresh = refresh;
+#endif
+}	/* end of Mono_Debug_Print */
+
+
+/***************************************************************************
+ * CommBufferClass::Mono_Debug_Print2 -- Debug output; alternate format    *
+ *                                                                         *
+ * This routine prints more information than the other version; it's			*
+ * called only if the number of queue entries is small enough to support	*
+ * this format.																				*
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		refresh		1 = clear screen & completely refresh							*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		none.																						*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   05/31/1995 BRR : Created.                                             *
+ *=========================================================================*/
+void CommBufferClass::Mono_Debug_Print2(int refresh)
+{
+#ifdef WWLIB32_H
+	int i;												// loop counter
+	char txt[80];
+	int val;
+
+	struct CommHdr {									// this mirrors the CommHeaderType
+		unsigned short MagicNumber;
+		unsigned char Code;
+		unsigned long PacketID;
+	} *hdr;
+
+	//------------------------------------------------------------------------
+	//	Refresh the screen
+	//------------------------------------------------------------------------
+	if (refresh) {
+		Mono_Clear_Screen ();
+		Mono_Printf("ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿\n");
+		Mono_Printf("³                                                                             ³\n");
+		Mono_Printf("³                                                                             ³\n");
+		Mono_Printf("³                                                                             ³\n");
+		Mono_Printf("ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´\n");
+		Mono_Printf("³              Send Queue              ³             Receive Queue            ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³ ID  Ct Type   Data  Name         ACK ³ ID  Rd Type   Data  Name         ACK ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ");
+	}
+
+	//------------------------------------------------------------------------
+	//	Print Send Queue items
+	//------------------------------------------------------------------------
+	for (i = 0; i < MaxSend; i++) {
+		Mono_Set_Cursor (1,8 + i);
+
+		//.....................................................................
+		//	Print an active entry
+		//.....................................................................
+		if (SendQueue[i].IsActive) {
+
+			//..................................................................
+			//	Get header info
+			//..................................................................
+			hdr = (CommHdr *)SendQueue[i].Buffer;
+			hdr->MagicNumber = hdr->MagicNumber;
+			hdr->Code = hdr->Code;
+			sprintf(txt,"%4d %2d %-5s  ",
+				hdr->PacketID,
+				SendQueue[i].SendCount,
+				ConnectionClass::Command_Name(hdr->Code));
+
+			//..................................................................
+			//	Decode app's ID & its name
+			//..................................................................
+			if (DebugSize && (DebugOffset + DebugSize) <= SendQueue[i].BufLen) {
+				if (DebugSize==1) {
+					val = *(SendQueue[i].Buffer + DebugOffset);
+
+				}
+				else if (DebugSize==2) {
+					val = *((short *)(SendQueue[i].Buffer + DebugOffset));
+
+				}
+				else if (DebugSize==4) {
+					val = *((int *)(SendQueue[i].Buffer + DebugOffset));
+				}
+				sprintf(txt + strlen(txt),"%4d  ",val);
+
+				if (DebugNameCount > 0 && val >= 0 && val < DebugNameCount) {
+					sprintf(txt + strlen(txt),"%-12s  %x",
+						DebugNames[val - DebugNameStart], SendQueue[i].IsACK);
+				}
+				else {
+					sprintf(txt + strlen(txt),"              %x",
+						SendQueue[i].IsACK);
+				}
+			}
+			else {
+				sprintf(txt + strlen(txt),"                    %x",
+					SendQueue[i].IsACK);
+			}
+
+			Mono_Printf("%s",txt);
+		}
+		else {
+
+			//..................................................................
+			//	Entry isn't active; print blanks
+			//..................................................................
+			Mono_Printf("____ __                            _");
+		}
+	}
+
+	//------------------------------------------------------------------------
+	//	Print Receive Queue items
+	//------------------------------------------------------------------------
+	for (i = 0; i < MaxReceive; i++) {
+		Mono_Set_Cursor (40,8 + i);
+
+		//.....................................................................
+		//	Print an active entry
+		//.....................................................................
+		if (ReceiveQueue[i].IsActive) {
+
+			//..................................................................
+			//	Get header info
+			//..................................................................
+			hdr = (CommHdr *)ReceiveQueue[i].Buffer;
+			hdr->MagicNumber = hdr->MagicNumber;
+			hdr->Code = hdr->Code;
+			sprintf(txt,"%4d %2d %-5s  ",
+				hdr->PacketID,
+				ReceiveQueue[i].IsRead,
+				ConnectionClass::Command_Name(hdr->Code));
+
+			//..................................................................
+			//	Decode app's ID & its name
+			//..................................................................
+			if (DebugSize && (DebugOffset + DebugSize) <= ReceiveQueue[i].BufLen) {
+				if (DebugSize==1) {
+					val = *(ReceiveQueue[i].Buffer + DebugOffset);
+
+				}
+				else if (DebugSize==2) {
+					val = *((short *)(ReceiveQueue[i].Buffer + DebugOffset));
+
+				}
+				else if (DebugSize==4) {
+					val = *((int *)(ReceiveQueue[i].Buffer + DebugOffset));
+				}
+				sprintf(txt + strlen(txt),"%4d  ",val);
+
+				if (DebugNameCount > 0 && val >= 0 && val < DebugNameCount) {
+					sprintf(txt + strlen(txt),"%-12s  %x",
+						DebugNames[val - DebugNameStart], ReceiveQueue[i].IsACK);
+				}
+				else {
+					sprintf(txt + strlen(txt),"              %x",
+						ReceiveQueue[i].IsACK);
+				}
+			}
+			else {
+				sprintf(txt + strlen(txt),"                    %x",
+					ReceiveQueue[i].IsACK);
+			}
+
+			Mono_Printf("%s",txt);
+		}
+		else {
+
+			//..................................................................
+			//	Entry isn't active; print blanks
+			//..................................................................
+			Mono_Printf("____ __                            _");
+		}
+	}
+
+#else
+	refresh = refresh;
+#endif
+}	/* end of Mono_Debug_Print2 */
+
+
+/************************** end of combuf.cpp ******************************/
+
+

+ 193 - 0
CODE/COMBUF.H

@@ -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 - 0
CODE/COMINIT.CPP

@@ -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 - 0
CODE/COMINIT.H

@@ -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 - 0
CODE/COMPAT.H

@@ -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 - 0
CODE/COMQUEUE.CPP

@@ -0,0 +1,1003 @@
+/*
+**	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.cpv   4.1   11 Apr 1996 18:28:16   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.CPP                             *
+ *                                                                         *
+ *                   Programmer : Bill Randolph                            *
+ *                                                                         *
+ *                   Start Date : December 19, 1994                        *
+ *                                                                         *
+ *                  Last Update : May 31, 1995 [BRR]                       *
+ *                                                                         *
+ *-------------------------------------------------------------------------*
+ * Functions:                                                              *
+ *   CommQueueClass::Add_Delay -- adds a new delay value for response time *
+ *   CommQueueClass::Avg_Response_Time -- returns average response time    *
+ *   CommQueueClass::CommQueueClass -- class constructor                   *
+ *   CommQueueClass::Configure_Debug -- sets up special debug values       * 
+ *   CommQueueClass::Get_Receive -- gets ptr to queue entry                *
+ *   CommQueueClass::Get_Send -- gets ptr to queue entry                   *
+ *   CommQueueClass::Init -- initializes this queue                        *
+ *   CommQueueClass::Max_Response_Time -- returns max response time        *
+ *   CommQueueClass::Mono_Debug_Print -- Debug output routine              * 
+ *   CommQueueClass::Mono_Debug_Print2 -- Debug output; alternate format   * 
+ *   CommQueueClass::Next_Receive -- gets ptr to next entry in send queue  *
+ *   CommQueueClass::Next_Send -- gets ptr to next entry in send queue     *
+ *   CommQueueClass::Queue_Receive -- queues a received message            *
+ *   CommQueueClass::Queue_Send -- queues a message for sending            *
+ *   CommQueueClass::Reset_Response_Time -- resets computations            *
+ *   CommQueueClass::UnQueue_Receive -- removes next entry from send queue *
+ *   CommQueueClass::UnQueue_Send -- removes next entry from send queue    *
+ *   CommQueueClass::~CommQueueClass -- class destructor                   *
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+#include "function.h"
+
+
+/***************************************************************************
+ * CommQueueClass::CommQueueClass -- class constructor             			*
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		numsend		# queue entries for sending										*
+ *		numreceive	# queue entries for receiving										*
+ *		maxlen		maximum desired packet length, in bytes						*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		none.																						*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   12/19/1994 BR : Created.                                              *
+ *=========================================================================*/
+CommQueueClass::CommQueueClass(int numsend, int numreceive, int maxlen)
+{
+	int i;
+
+	/*
+	**	Init variables 
+	*/
+	MaxSend = numsend;
+	MaxReceive = numreceive;
+	MaxPacketSize = maxlen;
+
+	/*
+	**	Allocate the queue entries 
+	*/
+	SendQueue = new SendQueueType[numsend];
+	ReceiveQueue = new ReceiveQueueType[numreceive];
+
+	/*
+	**	Allocate queue entry buffers 
+	*/
+	for (i = 0; i < MaxSend; i++) {
+		SendQueue[i].Buffer = new char[maxlen];
+	}
+
+	for (i = 0; i < MaxReceive; i++) {
+		ReceiveQueue[i].Buffer = new char[maxlen];
+	}
+
+	Init();
+}
+
+
+/***************************************************************************
+ * CommQueueClass::~CommQueueClass -- class destructor             			*
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		none.																						*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		none.																						*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   12/19/1994 BR : Created.                                              *
+ *=========================================================================*/
+CommQueueClass::~CommQueueClass()
+{
+	int i;
+
+	/*
+	**	Free queue entry buffers 
+	*/
+	for (i = 0; i < MaxSend; i++) {
+		delete [] SendQueue[i].Buffer;
+	}
+
+	for (i = 0; i < MaxReceive; i++) {
+		delete [] ReceiveQueue[i].Buffer;
+	}
+
+	delete [] SendQueue;
+	delete [] ReceiveQueue;
+}
+
+
+/***************************************************************************
+ * CommQueueClass::Init -- initializes this queue                          *
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		none.																						*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		none.																						*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   01/20/1995 BR : Created.                                              *
+ *=========================================================================*/
+void CommQueueClass::Init(void)
+{
+	int i;
+
+	/*
+	**	Init data members
+	*/
+	SendTotal = 0L;
+	ReceiveTotal = 0L;
+
+	DelaySum = 0L;
+	NumDelay = 0L;
+	MeanDelay = 0L;
+	MaxDelay = 0L;
+
+	SendCount = 0;
+	SendNext = 0;
+	SendEmpty = 0;
+
+	ReceiveCount = 0;
+	ReceiveNext = 0;
+	ReceiveEmpty = 0;
+
+	/*
+	**	Init the queue entries
+	*/
+	for (i = 0; i < MaxSend; i++) {
+		SendQueue[i].IsActive = 0;
+		SendQueue[i].IsACK = 0;
+		SendQueue[i].FirstTime = 0L;
+		SendQueue[i].LastTime = 0L;
+		SendQueue[i].SendCount = 0L;
+		ReceiveQueue[i].BufLen = 0;
+	}
+	for (i = 0; i < MaxReceive; i++) {
+		ReceiveQueue[i].IsActive = 0;
+		ReceiveQueue[i].IsRead = 0;
+		ReceiveQueue[i].IsACK = 0;
+		ReceiveQueue[i].BufLen = 0;
+	}
+	
+	/*
+	**	Init debug values
+	*/
+	DebugOffset = 0;
+	DebugSize = 0;
+	DebugNames = NULL;
+	DebugMaxNames = 0;
+}
+
+
+/***************************************************************************
+ * CommQueueClass::Queue_Send -- queues a message for sending              *
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		buf			buffer containing the message										*
+ *		buflen		length of 'buf'														*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		1 = OK, 0 = no room in the queue													*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   12/20/1994 BR : Created.                                              *
+ *=========================================================================*/
+int CommQueueClass::Queue_Send(void *buf, int buflen)
+{
+	/*
+	**	Error if no room in the queue
+	*/
+	if (SendCount==MaxSend || SendQueue[SendEmpty].IsActive!=0) {
+		return(0); 
+	}
+
+	/*
+	**	Set entry flags 
+	*/
+	SendQueue[SendEmpty].IsActive = 1;			// entry is now active
+	SendQueue[SendEmpty].IsACK = 0;				// entry hasn't been ACK'd
+	SendQueue[SendEmpty].FirstTime = 0L;		// filled in by Manager when sent
+	SendQueue[SendEmpty].LastTime = 0L;			// filled in by Manager when sent
+	SendQueue[SendEmpty].SendCount = 0L;		// filled in by Manager when sent
+	SendQueue[SendEmpty].BufLen = buflen;		// save buffer size
+
+	/*
+	**	Copy the packet data 
+	*/
+	memcpy(SendQueue[SendEmpty].Buffer,buf,buflen);
+
+	/*
+	**	Increment counters & entry ptr 
+	*/
+	SendCount++;
+	SendEmpty++;
+	if (SendEmpty==MaxSend) {
+		SendEmpty = 0;
+	}
+
+	SendTotal++;
+
+	return(1);
+}
+
+
+/***************************************************************************
+ * CommQueueClass::UnQueue_Send -- removes next entry from send queue		*
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		buf			buffer to store entry's data in; if NULL, it's discarded	*
+ *		buflen		filled in with length of entry retrieved						*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		1 = OK, 0 = no entry to retreive													*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   12/20/1994 BR : Created.                                              *
+ *=========================================================================*/
+int CommQueueClass::UnQueue_Send(void *buf, int *buflen)
+{
+	/*
+	**	Error if no entry to retrieve 
+	*/
+	if (SendCount==0 || SendQueue[SendNext].IsActive==0) {
+		return(0);
+	}
+
+	/*
+	**	Copy the data from the entry 
+	*/
+	if (buf!=NULL) {
+		memcpy(buf,SendQueue[SendNext].Buffer,SendQueue[SendNext].BufLen);
+		(*buflen) = SendQueue[SendNext].BufLen;
+	}
+
+	/*
+	**	Set entry flags 
+	*/
+	SendQueue[SendNext].IsActive = 0;
+	SendQueue[SendNext].IsACK = 0;
+	SendQueue[SendNext].FirstTime = 0L;
+	SendQueue[SendNext].LastTime = 0L;
+	SendQueue[SendNext].SendCount = 0L;
+	SendQueue[SendNext].BufLen = 0;
+	SendCount--;
+	SendNext++;
+	if (SendNext==MaxSend) {
+		SendNext = 0;
+	}
+
+	return(1);
+}
+
+
+/***************************************************************************
+ * CommQueueClass::Next_Send -- gets ptr to next entry in send queue       *
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		none.																						*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		ptr to entry, NULL if there is none.											*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   12/20/1994 BR : Created.                                              *
+ *=========================================================================*/
+SendQueueType * CommQueueClass::Next_Send(void)
+{
+	if (SendCount==0) {
+		return(NULL);
+	} else {
+		return(&SendQueue[SendNext]);
+	}
+}
+
+
+/***************************************************************************
+ * CommQueueClass::Get_Send -- gets ptr to queue entry                     *
+ *                                                                         *
+ * This routine gets a pointer to the indicated queue entry.  The index		*
+ * value is relative to the next-accessable queue entry; 0 = get the			*
+ * next available queue entry, 1 = get the one behind that, etc.				*
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		index		index of entry to get (0 = 1st available)							*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		ptr to entry																			*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   12/21/1994 BR : Created.                                              *
+ *=========================================================================*/
+SendQueueType * CommQueueClass::Get_Send(int index)
+{
+	int i;
+
+	i = SendNext + index;
+	if (i >= MaxSend) {
+		i -= MaxSend;
+	}
+
+	if (SendQueue[i].IsActive==0) {
+		return(NULL);
+	} else {
+		return(&SendQueue[i]);
+	}
+}
+
+
+/***************************************************************************
+ * CommQueueClass::Queue_Receive -- queues a received message					*
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		buf			buffer containing the message										*
+ *		buflen		length of 'buf'														*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		1 = OK, 0 = no room in the queue													*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   12/20/1994 BR : Created.                                              *
+ *=========================================================================*/
+int CommQueueClass::Queue_Receive(void *buf, int buflen)
+{
+	/*
+	**	Error if no room in the queue
+	*/
+	if (ReceiveCount==MaxReceive || ReceiveQueue[ReceiveEmpty].IsActive!=0) {
+		return(0); 
+	}
+
+	/*
+	**	Set entry flags
+	*/
+	ReceiveQueue[ReceiveEmpty].IsActive = 1;
+	ReceiveQueue[ReceiveEmpty].IsRead = 0;
+	ReceiveQueue[ReceiveEmpty].IsACK = 0;
+	ReceiveQueue[ReceiveEmpty].BufLen = buflen;
+
+	/*
+	**	Copy the packet data
+	*/
+	memcpy(ReceiveQueue[ReceiveEmpty].Buffer,buf,buflen);
+
+	/*
+	**	Increment counters & entry ptr 
+	*/
+	ReceiveCount++;
+	ReceiveEmpty++;
+	if (ReceiveEmpty==MaxReceive) {
+		ReceiveEmpty = 0;
+	}
+
+	ReceiveTotal++;
+
+	return(1);
+}
+
+
+/***************************************************************************
+ * CommQueueClass::UnQueue_Receive -- removes next entry from send queue	*
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		buf			buffer to store entry's data in; if NULL, it's discarded	*
+ *		buflen		filled in with length of entry retrieved						*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		1 = OK, 0 = no entry to retreive													*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   12/20/1994 BR : Created.                                              *
+ *=========================================================================*/
+int CommQueueClass::UnQueue_Receive(void *buf, int *buflen)
+{
+	/*
+	**	Error if no entry to retrieve 
+	*/
+	if (ReceiveCount==0 || ReceiveQueue[ReceiveNext].IsActive==0) {
+		return(0);
+	}
+
+	/*
+	**	Copy the data from the entry
+	*/
+	if (buf!=NULL) {
+		memcpy(buf,ReceiveQueue[ReceiveNext].Buffer,
+			ReceiveQueue[ReceiveNext].BufLen);
+		(*buflen) = ReceiveQueue[ReceiveNext].BufLen;
+	}
+
+	/*
+	**	Set entry flags
+	*/
+	ReceiveQueue[ReceiveNext].IsActive = 0;
+	ReceiveQueue[ReceiveNext].IsRead = 0;
+	ReceiveQueue[ReceiveNext].IsACK = 0;
+	ReceiveQueue[ReceiveNext].BufLen = 0;
+	ReceiveCount--;
+	ReceiveNext++;
+	if (ReceiveNext==MaxReceive) {
+		ReceiveNext = 0;
+	}
+
+	return(1);
+}
+
+
+/***************************************************************************
+ * CommQueueClass::Next_Receive -- gets ptr to next entry in send queue    *
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		none.																						*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		ptr to entry, NULL if there is none.											*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   12/20/1994 BR : Created.                                              *
+ *=========================================================================*/
+ReceiveQueueType * CommQueueClass::Next_Receive(void)
+{
+	if (ReceiveCount==0) {
+		return(NULL);
+	} else {
+		return(&ReceiveQueue[ReceiveNext]);
+	}
+}
+
+
+/***************************************************************************
+ * CommQueueClass::Get_Receive -- gets ptr to queue entry                  *
+ *                                                                         *
+ * This routine gets a pointer to the indicated queue entry.  The index		*
+ * value is relative to the next-accessable queue entry; 0 = get the			*
+ * next available queue entry, 1 = get the one behind that, etc.				*
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		index		index of entry to get (0 = 1st available)							*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		ptr to entry																			*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   12/21/1994 BR : Created.                                              *
+ *=========================================================================*/
+ReceiveQueueType * CommQueueClass::Get_Receive(int index)
+{
+	int i;
+
+	i = ReceiveNext + index;
+	if (i >= MaxReceive) {
+		i -= MaxReceive;
+	}
+
+	if (ReceiveQueue[i].IsActive==0) {
+		return(NULL);
+	} else {
+		return(&ReceiveQueue[i]);
+	}
+}
+
+
+/***************************************************************************
+ * CommQueueClass::Add_Delay -- adds a new delay value for response time   *
+ *                                                                         *
+ * This routine updates the average response time for this queue.  The		*
+ * computation is based on the average of the last 'n' delay values given,	*
+ * It computes a running total of the last n delay values, then divides 	*
+ * that by n to compute the average.													*
+ *																									*
+ * When the number of values given exceeds the max, the mean is subtracted	*
+ * off the total, then the new value is added in.  Thus, any single delay	*
+ * value will have an effect on the total that approaches 0 over time, and	*
+ * the new delay value contributes to 1/n of the mean.							*
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		delay			value to add into the response time computation				*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		none.																						*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   01/19/1995 BR : Created.                                              *
+ *=========================================================================*/
+void CommQueueClass::Add_Delay(unsigned long delay)
+{
+	int roundoff = 0;
+
+	if (NumDelay==256) {
+		DelaySum -= MeanDelay;
+		DelaySum += delay;
+		if ( (DelaySum & 0x00ff) > 127) {
+			roundoff = 1;
+		}
+		MeanDelay = (DelaySum >> 8) + roundoff;
+	} else {
+		NumDelay++;
+		DelaySum += delay;
+		MeanDelay = DelaySum / NumDelay;
+	}
+
+	if (delay > MaxDelay) {
+		MaxDelay = delay;
+	}
+}
+
+
+/***************************************************************************
+ * CommQueueClass::Avg_Response_Time -- returns average response time    	*
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		none.																						*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		latest computed average response time											*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   01/19/1995 BR : Created.                                              *
+ *=========================================================================*/
+unsigned long CommQueueClass::Avg_Response_Time(void)
+{
+	return(MeanDelay);
+}
+
+
+/***************************************************************************
+ * CommQueueClass::Max_Response_Time -- returns max response time    		*
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		none.																						*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		latest computed average response time											*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   01/19/1995 BR : Created.                                              *
+ *=========================================================================*/
+unsigned long CommQueueClass::Max_Response_Time(void)
+{
+	return(MaxDelay);
+}
+
+
+/***************************************************************************
+ * CommQueueClass::Reset_Response_Time -- resets computations					*
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		none.																						*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		none.																						*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   01/19/1995 BR : Created.                                              *
+ *=========================================================================*/
+void CommQueueClass::Reset_Response_Time(void)
+{
+	DelaySum = 0L;
+	NumDelay = 0L;
+	MeanDelay = 0L;
+	MaxDelay = 0L;
+}
+
+
+/*************************************************************************** 
+ * CommQueueClass::Configure_Debug -- sets up special debug values         * 
+ *                                                                         * 
+ * Mono_Debug_Print2() can look into a packet to pull out a particular		*
+ * ID, and can print both that ID and a string corresponding to				*
+ * that ID.  This routine configures these values so it can find				*
+ * and decode the ID.  This ID is used in addition to the normal				*
+ * CommHeaderType values.																	*
+ *                                                                         * 
+ * INPUT:                                                                  * 
+ *		offset		ID's byte offset into packet										*
+ *		size			size of ID, in bytes; 0 if none									*
+ *		names			ptr to array of names; use ID as an index into this		*
+ *		maxnames		max # in the names array; 0 if none.							*
+ *                                                                         * 
+ * OUTPUT:                                                                 * 
+ *		none.																						*
+ *                                                                         * 
+ * WARNINGS:                                                               * 
+ *		Names shouldn't be longer than 12 characters.								*
+ *                                                                         * 
+ * HISTORY:                                                                * 
+ *   05/31/1995 BRR : Created.                                             * 
+ *=========================================================================*/
+void CommQueueClass::Configure_Debug(int offset, int size, char **names, 
+	int maxnames)
+{
+	DebugOffset = offset;
+	DebugSize = size;
+	DebugNames = names;
+	DebugMaxNames = maxnames;
+}
+
+
+/*************************************************************************** 
+ * Mono_Debug_Print -- Debug output routine                                * 
+ *                                                                         * 
+ * This routine leaves 5 lines at the top for the caller's use.				*
+ *                                                                         * 
+ * INPUT:                                                                  * 
+ *		refresh		1 = clear screen & completely refresh							*
+ *                                                                         * 
+ * OUTPUT:                                                                 * 
+ *		none.																						*
+ *                                                                         * 
+ * WARNINGS:                                                               * 
+ *		none.																						*
+ *                                                                         * 
+ * HISTORY:                                                                * 
+ *   05/02/1995 BRR : Created.                                             * 
+ *=========================================================================*/
+void CommQueueClass::Mono_Debug_Print(int refresh)
+{
+#ifdef WWLIB32_H
+	int i;												// loop counter
+	static int send_col[] = {1,14,28};			// coords of send queue columns
+	static int receive_col[] = {40,54,68};		// coords of recv queue columns
+	int row,col;										// current row,col for printing
+	int num;												// max # items to print
+
+	struct CommHdr {									// this mirrors the CommHeaderType
+		unsigned short MagicNumber;
+		unsigned char Code;
+		unsigned long PacketID;
+	} *hdr;
+
+	/*
+	**	If few enough entries, call the verbose debug version
+	*/
+	if (MaxSend <= 16) {
+		Mono_Debug_Print2(refresh);
+		return;
+	}
+
+	/*
+	**	Refresh the screen
+	*/
+	if (refresh) {
+		Mono_Clear_Screen ();
+		Mono_Printf("ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿\n");
+		Mono_Printf("³                                                                             ³\n");
+		Mono_Printf("³                                                                             ³\n");
+		Mono_Printf("³                                                                             ³\n");
+		Mono_Printf("ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´\n");
+		Mono_Printf("³              Send Queue              ³             Receive Queue            ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³ ID  Ct ACK   ID  Ct ACK    ID  Ct ACK³ ID  Rd ACK    ID  Rd ACK   ID  Rd ACK³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ");
+	}
+
+	/*
+	**	Print Send Queue items
+	*/
+	if (MaxSend <= 48) {
+		num = MaxSend;
+	} else {
+		num = 48;
+	}
+	col = 0;
+	row = 0;
+	for (i = 0; i < MaxSend; i++) {
+		Mono_Set_Cursor (send_col[col],row + 8);
+		if (SendQueue[i].IsActive) {
+			hdr = (CommHdr *)SendQueue[i].Buffer;
+			hdr->MagicNumber = hdr->MagicNumber;
+			hdr->Code = hdr->Code;
+			Mono_Printf ("%4d %2d  %d",hdr->PacketID, SendQueue[i].SendCount,
+				SendQueue[i].IsACK);
+		} else {
+			Mono_Printf ("____ __  _ ");
+		}
+
+		row++;
+		if (row > 15) {
+			row = 0;
+			col++;
+		}
+	}
+
+	/*
+	**	Print Receive Queue items
+	*/
+	if (MaxReceive <= 48) {
+		num = MaxSend;
+	} else {
+		num = 48;
+	}
+	col = 0;
+	row = 0;
+	for (i = 0; i < MaxReceive; i++) {
+		Mono_Set_Cursor (receive_col[col],row + 8);
+		if (ReceiveQueue[i].IsActive) {
+			hdr = (CommHdr *)ReceiveQueue[i].Buffer;
+			Mono_Printf ("%4d  %d  %d",hdr->PacketID, ReceiveQueue[i].IsRead,
+				ReceiveQueue[i].IsACK);
+		} else {
+			Mono_Printf ("____  _  _ ");
+		}
+
+		row++;
+		if (row > 15) {
+			row = 0;
+			col++;
+		}
+	}
+
+#else
+	refresh = refresh;
+#endif	
+}
+
+
+/*************************************************************************** 
+ * CommQueueClass::Mono_Debug_Print2 -- Debug output; alternate format     * 
+ *                                                                         * 
+ * This routine prints more information than the other version; it's			*
+ * called only if the number of queue entries is small enough to support	*
+ * this format.																				*
+ *                                                                         * 
+ * INPUT:                                                                  * 
+ *		refresh		1 = clear screen & completely refresh							*
+ *                                                                         * 
+ * OUTPUT:                                                                 * 
+ *		none.																						*
+ *                                                                         * 
+ * WARNINGS:                                                               * 
+ *		none.																						*
+ *                                                                         * 
+ * HISTORY:                                                                * 
+ *   05/31/1995 BRR : Created.                                             * 
+ *=========================================================================*/
+void CommQueueClass::Mono_Debug_Print2(int refresh)
+{
+#ifdef WWLIB32_H
+	int i;												// loop counter
+	char txt[80];
+	int val;
+
+	struct CommHdr {									// this mirrors the CommHeaderType
+		unsigned short MagicNumber;
+		unsigned char Code;
+		unsigned long PacketID;
+	} *hdr;
+
+	/*
+	**	Refresh the screen
+	*/
+	if (refresh) {
+		Mono_Clear_Screen ();
+		Mono_Printf("ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿\n");
+		Mono_Printf("³                                                                             ³\n");
+		Mono_Printf("³                                                                             ³\n");
+		Mono_Printf("³                                                                             ³\n");
+		Mono_Printf("ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´\n");
+		Mono_Printf("³              Send Queue              ³             Receive Queue            ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³ ID  Ct Type   Data  Name         ACK ³ ID  Rd Type   Data  Name         ACK ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("³                                      ³                                      ³\n");
+		Mono_Printf("ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ");
+	}
+
+	/*
+	**	Print Send Queue items
+	*/
+	for (i = 0; i < MaxSend; i++) {
+		Mono_Set_Cursor (1,8 + i);
+		
+		/*
+		**	Print an active entry
+		*/
+		if (SendQueue[i].IsActive) {
+			
+			/*
+			**	Get header info
+			*/
+			hdr = (CommHdr *)SendQueue[i].Buffer;
+			hdr->MagicNumber = hdr->MagicNumber;
+			hdr->Code = hdr->Code;
+			sprintf(txt,"%4d %2d %-5s  ",
+				hdr->PacketID,
+				SendQueue[i].SendCount,
+				ConnectionClass::Command_Name(hdr->Code));
+
+			/*
+			**	Decode app's ID & its name
+			*/
+			if (DebugSize && (DebugOffset + DebugSize) <= SendQueue[i].BufLen) {
+				if (DebugSize==1) {
+					val = *(SendQueue[i].Buffer + DebugOffset);
+				} else {
+					if (DebugSize==2) {
+						val = *((short *)(SendQueue[i].Buffer + DebugOffset));
+					} else {
+						if (DebugSize==4) {
+							val = *((int *)(SendQueue[i].Buffer + DebugOffset));
+						}
+					} 
+				}
+				sprintf(txt + strlen(txt),"%4d  ",val);
+
+				if (DebugMaxNames && val > 0 && val < DebugMaxNames) {
+					sprintf(txt + strlen(txt),"%-12s  %x",
+						DebugNames[val],
+						SendQueue[i].IsACK);
+				} else {
+					sprintf(txt + strlen(txt),"              %x",SendQueue[i].IsACK);
+				}
+			}
+		} else {
+
+			/*
+			**	Entry isn't active; print blanks
+			*/
+			Mono_Printf("____ __                            _");
+		}
+	}
+
+	/*
+	**	Print Receive Queue items
+	*/
+	for (i = 0; i < MaxReceive; i++) {
+		Mono_Set_Cursor (40,8 + i);
+		
+		/*
+		**	Print an active entry
+		*/
+		if (ReceiveQueue[i].IsActive) {
+			
+			/*
+			**	Get header info
+			*/
+			hdr = (CommHdr *)ReceiveQueue[i].Buffer;
+			hdr->MagicNumber = hdr->MagicNumber;
+			hdr->Code = hdr->Code;
+			sprintf(txt,"%4d %2d %-5s  ",
+				hdr->PacketID,
+				ReceiveQueue[i].IsRead,
+				ConnectionClass::Command_Name(hdr->Code));
+			
+			/*
+			**	Decode app's ID & its name
+			*/
+			if (DebugSize && (DebugOffset + DebugSize) <= SendQueue[i].BufLen) {
+				if (DebugSize==1) {
+					val = *(ReceiveQueue[i].Buffer + DebugOffset);
+				} else {
+					if (DebugSize==2) {
+						val = *((short *)(ReceiveQueue[i].Buffer + DebugOffset));
+					} else {
+						if (DebugSize==4) {
+							val = *((int *)(ReceiveQueue[i].Buffer + DebugOffset));
+						}
+					}
+				} 
+				sprintf(txt + strlen(txt),"%4d  ",val);
+
+				if (DebugMaxNames && val > 0 && val < DebugMaxNames) {
+					sprintf(txt + strlen(txt),"%-12s  %x", DebugNames[val], ReceiveQueue[i].IsACK);
+				} else {
+					sprintf(txt + strlen(txt),"              %x",ReceiveQueue[i].IsACK);
+				}
+			}
+		} else {
+
+			/*
+			**	Entry isn't active; print blanks
+			*/
+			Mono_Printf("____ __                            _");
+		}
+	}
+
+#else
+	refresh = refresh;
+#endif	
+}
+
+

+ 193 - 0
CODE/COMQUEUE.H

@@ -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 - 0
CODE/CONFDLG.CPP

@@ -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 - 0
CODE/CONFDLG.H

@@ -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 - 0
CODE/CONNECT.CPP

@@ -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 - 0
CODE/CONNECT.CPP.BAK

@@ -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 - 0
CODE/CONNECT.H

@@ -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 - 0
CODE/CONNMGR.H

@@ -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 - 0
CODE/CONQUER.CPP

@@ -0,0 +1,5558 @@
+/*
+**	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/CONQUER.CPP 6     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 : CONQUER.CPP                                                  *
+ *                                                                                             *
+ *                   Programmer : Joe L. Bostic                                                *
+ *                                                                                             *
+ *                   Start Date : April 3, 1991                                                *
+ *                                                                                             *
+ *---------------------------------------------------------------------------------------------*
+ * Functions:                                                                                  *
+ *   CC_Draw_Shape -- Custom draw shape handler.                                               *
+ *   Call_Back -- Main game maintenance callback routine.                                      *
+ *   Color_Cycle -- Handle the general palette color cycling.                                  *
+ *   Crate_From_Name -- Given a crate name convert it to a crate type.                         *
+ *   Disk_Space_Available -- returns bytes of free disk space                                  *
+ *   Do_Record_Playback -- handles saving/loading map pos & current object                     *
+ *   Fading_Table_Name -- Builds a theater specific fading table name.                         *
+ *   Fetch_Techno_Type -- Convert type and ID into TechnoTypeClass pointer.                    *
+ *   Force_CD_Available -- Ensures that specified CD is available.                             *
+ *   Get_Radar_Icon -- Builds and alloc a radar icon from a shape file                         *
+ *   Handle_Team -- Processes team selection command.                                          *
+ *   Handle_View -- Either records or restores the tactical view.                              *
+ *   KN_To_Facing -- Converts a keyboard input number into a facing value.                     *
+ *   Keyboard_Process -- Processes the tactical map input codes.                               *
+ *   Language_Name -- Build filename for current language.                                     *
+ *   List_Copy -- Makes a copy of a cell offset list.                                          *
+ *   Main_Game -- Main game startup routine.                                                   *
+ *   Main_Loop -- This is the main game loop (as a single loop).                               *
+ *   Map_Edit_Loop -- a mini-main loop for map edit mode only                                  *
+ *   Message_Input -- allows inter-player message input processing                             *
+ *   MixFileHandler -- Handles VQ file access.                                                 *
+ *   Name_From_Source -- retrieves the name for the given SourceType                           *
+ *   Owner_From_Name -- Convert an owner name into a bitfield.                                 *
+ *   Play_Movie -- Plays a VQ movie.                                                           *
+ *   Shake_The_Screen -- Dispatcher that shakes the screen.                                    *
+ *   Shape_Dimensions -- Determine the minimum rectangle for the shape.                        *
+ *   Source_From_Name -- Converts ASCII name into SourceType.                                  *
+ *   Sync_Delay -- Forces the game into a 15 FPS rate.                                         *
+ *   Theater_From_Name -- Converts ASCII name into a theater number.                           *
+ *   Unselect_All -- Causes all selected objects to become unselected.                         *
+ *   VQ_Call_Back -- Maintenance callback used for VQ movies.                                  *
+ *   Game_Registry_Key -- Returns pointer to string containing the registry subkey for the game.
+ *   Is_Counterstrike_Installed -- Function to determine the availability of the CS expansion.
+ *   Is_Aftermath_Installed -- Function to determine the availability of the AM expansion.
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+
+#ifdef TESTCODE
+class A {
+	public:
+		enum {VAR=1};
+};
+
+template<class T>
+class B {
+	public:
+		enum {VAR2=T::VAR};  // this is the line in question.
+};
+
+B<A> test;
+#endif
+
+
+
+#include	"function.h"
+#ifdef WIN32
+#ifdef WINSOCK_IPX
+#include	"WSProto.h"
+#else	//WINSOCK_IPX
+#include	"tcpip.h"
+#endif	//WINSOCK_IPX
+#else
+#include	"fakesock.h"
+TcpipManagerClass	Winsock;
+#endif
+#include	<stdlib.h>
+#include	<stdio.h>
+#include	<string.h>
+#include	<direct.h>
+#include	<fcntl.h>
+#include	<io.h>
+#include	<dos.h>
+#include	<share.h>
+#include	"ccdde.h"
+#include	"vortex.h"
+
+#ifdef WOLAPI_INTEGRATION
+//#include "WolDebug.h"
+#include "WolStrng.h"
+#include "WolapiOb.h"
+extern WolapiObject* pWolapi;
+#define PAGE_RESPOND_KEY	KN_RETURN	//KN_COMMA
+#endif
+
+#ifdef MPEGMOVIE
+#ifdef MCIMPEG
+#include "mcimovie.h"
+#endif
+#include "movie.h"
+MPG_RESPONSE far __stdcall MpegCallback(MPG_CMD cmd, LPVOID data, LPVOID user);
+#endif
+
+#define SHAPE_TRANS		0x40
+
+void * Get_Shape_Header_Data(void * ptr);
+extern bool Spawn_WChat(bool can_launch);
+
+#ifdef FIXIT_CSII	//	checked - ajw 9/28/98
+void Enable_Secret_Units(void);
+#endif
+
+extern bool Is_Mission_Aftermath (char *file_name);
+extern bool Is_Mission_Counterstrike (char *file_name);
+
+#ifdef FIXIT_VERSION_3		//	Stalemate games.
+extern void Do_Draw(void);
+#endif
+
+#ifdef CHEAT_KEYS
+bool	bNoMovies = false;
+#endif
+
+/****************************************
+**	Function prototypes for this module **
+*****************************************/
+bool Main_Loop(void);
+void Keyboard_Process(KeyNumType & input);
+static void Message_Input(KeyNumType &input);
+static void Color_Cycle(void);
+bool Map_Edit_Loop(void);
+
+extern "C" {
+	bool UseOldShapeDraw = false;
+}
+
+#ifdef CHEAT_KEYS
+void Dump_Heap_Pointers( void );
+void Error_In_Heap_Pointers( char * string );
+#endif
+static void Do_Record_Playback(void);
+
+void Toggle_Formation(void);
+
+extern "C" {
+	extern char * __nheapbeg;
+}
+
+//
+// Special module globals for recording and playback
+//
+char TeamEvent = 0;			// 0 = no event, 1,2,3 = team event type
+char TeamNumber = 0;			// which team was selected? (1-9)
+char FormationEvent = 0;	// 0 = no event, 1 = formation was toggled
+
+
+	/* -----------------10/14/96 7:29PM------------------
+
+	 --------------------------------------------------*/
+
+#if(TEN)
+void TEN_Call_Back(void);
+#endif	// TEN
+
+#if(MPATH)
+void MPATH_Call_Back(void);
+#endif	// MPATH
+
+/***********************************************************************************************
+ * Main_Game -- Main game startup routine.                                                     *
+ *                                                                                             *
+ *    This is the first official routine of the game. It handles game initialization and       *
+ *    the main game loop control.                                                              *
+ *                                                                                             *
+ *    Initialization:                                                                          *
+ *    - Init_Game handles one-time-only inits                                                  *
+ *    - Select_Game is responsible for initializations required for each new game played       *
+ *      (these may be different depending on whether a multiplayer game is selected, and       *
+ *      other parameters)                                                                      *
+ *    - This routine performs any un-inits required, both for each game played, and one-time   *
+ *                                                                                             *
+ * INPUT:   argc  -- Number of command line arguments (including program name itself).         *
+ *                                                                                             *
+ *          argv  -- Array of command line argument pointers.                                  *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   10/01/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void Main_Game(int argc, char * argv[])
+{
+	static bool fade = true;
+
+	/*
+	**	Perform one-time-only initializations
+	*/
+	if (!Init_Game(argc, argv)) {
+		return;
+	}
+
+	/*
+	**	Game processing loop:
+	**	1) Select which game to play, or whether to exit (don't fade the palette
+	**		on the first game selection, but fade it in on subsequent calls)
+	**	2) Invoke either the main-loop routine, or the editor-loop routine,
+	**		until they indicate that the user wants to exit the scenario.
+	*/
+	while (Select_Game(fade)) {
+		fade = false;
+		ScenarioInit = 0;		// Kludge.
+
+		fade = true;
+
+		/*
+		** Initialise the color lookup tables for the chronal vortex
+		*/
+		ChronalVortex.Stop();
+		ChronalVortex.Setup_Remap_Tables(Scen.Theater);
+
+		/*
+		**	Make the game screen visible, clear the keyboard buffer of spurious
+		**	values, and then show the mouse.  This PRESUMES that Select_Game() has
+		**	told the map to draw itself.
+		*/
+		GamePalette.Set(FADE_PALETTE_MEDIUM);
+		Keyboard->Clear();
+		/*
+		** Only show the mouse if we're not playing back a recording.
+		*/
+		if (Session.Play) {
+			Hide_Mouse();
+			TeamEvent = 0;
+			TeamNumber = 0;
+			FormationEvent = 0;
+		} else {
+			Show_Mouse();
+		}
+
+#ifdef WIN32
+		if (Session.Type == GAME_INTERNET) {
+			Register_Game_Start_Time();
+			GameStatisticsPacketSent = false;
+			PacketLater = NULL;
+			ConnectionLost = false;
+		} else {
+#ifndef WOLAPI_INTEGRATION
+			DDEServer.Disable();
+#endif	//	!WOLAPI_INTEGRATION
+		}
+#endif	//WIN32
+
+#ifdef SCENARIO_EDITOR
+		/*
+		**	Scenario-editor version of main-loop processing
+		*/
+		for (;;) {
+			/*
+			**	Non-scenario-editor-mode: call the game's main loop
+			*/
+			if (!Debug_Map) {
+#ifdef FIXIT_CSII	//	checked - ajw 9/28/98
+				TimeQuake = PendingTimeQuake;
+				PendingTimeQuake = false;
+#else
+				TimeQuake = false;
+#endif
+				if (Main_Loop()) {
+					break;
+				}
+
+				if (SpecialDialog != SDLG_NONE) {
+					switch (SpecialDialog) {
+						case SDLG_SPECIAL:
+							Map.Help_Text(TXT_NONE);
+							Map.Override_Mouse_Shape(MOUSE_NORMAL, false);
+							Special_Dialog();
+							Map.Revert_Mouse_Shape();
+							SpecialDialog = SDLG_NONE;
+							break;
+
+						case SDLG_OPTIONS:
+							Map.Help_Text(TXT_NONE);
+							Map.Override_Mouse_Shape(MOUSE_NORMAL, false);
+							Options.Process();
+							Map.Revert_Mouse_Shape();
+							SpecialDialog = SDLG_NONE;
+							break;
+
+						case SDLG_SURRENDER:
+							Map.Help_Text(TXT_NONE);
+							Map.Override_Mouse_Shape(MOUSE_NORMAL, false);
+							if (Surrender_Dialog(TXT_SURRENDER)) {
+								PlayerPtr->Flag_To_Lose();
+							}
+							SpecialDialog = SDLG_NONE;
+							Map.Revert_Mouse_Shape();
+							break;
+
+						default:
+							break;
+					}
+				}
+			} else {
+
+				/*
+				**	Scenario-editor-mode: call the editor's main loop
+				*/
+				if (Map_Edit_Loop()) {
+					break;
+				}
+			}
+		}
+#else
+		/*
+		**	Non-editor version of main-loop processing
+		*/
+		for (;;) {
+#ifdef FIXIT_CSII	//	checked - ajw 9/28/98
+			TimeQuake = PendingTimeQuake;
+			PendingTimeQuake = false;
+#else
+			TimeQuake = false;
+#endif
+			/*
+			**	Call the game's main loop
+			*/
+			if (Main_Loop()) {
+				break;
+			}
+
+			/*
+			**	If the SpecialDialog flag is set, invoke the given special dialog.
+			**	This must be done outside the main loop, since the dialog will call
+			**	Main_Loop(), allowing the game to run in the background.
+			*/
+			if (SpecialDialog != SDLG_NONE) {
+				switch (SpecialDialog) {
+					case SDLG_SPECIAL:
+						Map.Help_Text(TXT_NONE);
+						Map.Override_Mouse_Shape(MOUSE_NORMAL, false);
+						Special_Dialog();
+						Map.Revert_Mouse_Shape();
+						SpecialDialog = SDLG_NONE;
+						break;
+
+					case SDLG_OPTIONS:
+						Map.Help_Text(TXT_NONE);
+						Map.Override_Mouse_Shape(MOUSE_NORMAL, false);
+						Options.Process();
+						Map.Revert_Mouse_Shape();
+						SpecialDialog = SDLG_NONE;
+						break;
+
+					case SDLG_SURRENDER:
+						Map.Help_Text(TXT_NONE);
+						Map.Override_Mouse_Shape(MOUSE_NORMAL, false);
+						if (Surrender_Dialog(TXT_SURRENDER)) {
+							OutList.Add(EventClass(EventClass::DESTRUCT));
+						}
+						SpecialDialog = SDLG_NONE;
+						Map.Revert_Mouse_Shape();
+						break;
+
+/*ifdef FIXIT_VERSION_3		//	Stalemate games.
+					case SDLG_PROPOSE_DRAW:
+						Map.Help_Text(TXT_NONE);
+						Map.Override_Mouse_Shape(MOUSE_NORMAL, false);
+						if (Surrender_Dialog(TXT_WOL_PROPOSE_DRAW)) {
+							OutList.Add(EventClass(EventClass::PROPOSE_DRAW));
+						}
+						SpecialDialog = SDLG_NONE;
+						Map.Revert_Mouse_Shape();
+						break;
+
+					case SDLG_ACCEPT_DRAW:
+						Map.Help_Text(TXT_NONE);
+						Map.Override_Mouse_Shape(MOUSE_NORMAL, false);
+						if (Surrender_Dialog(TXT_WOL_ACCEPT_DRAW)) {
+							OutList.Add(EventClass(EventClass::ACCEPT_DRAW));
+						}
+						SpecialDialog = SDLG_NONE;
+						Map.Revert_Mouse_Shape();
+						break;
+#endif
+*/
+					default:
+						break;
+				}
+			}
+		}
+#endif
+
+
+#ifdef WIN32
+		/*
+		** Send the game stats to WChat if we haven't already done so
+		*/
+		if (!GameStatisticsPacketSent && PacketLater) {
+			Send_Statistics_Packet();		//	After game sending if PacketLater set.
+		}
+#endif	//WIN32
+
+		/*
+		**	Scenario is done; fade palette to black
+		*/
+		BlackPalette.Set(FADE_PALETTE_SLOW);
+		VisiblePage.Clear();
+
+		/*
+		**	Un-initialize whatever needs it, for each game played.
+		**
+		**	Shut down either the modem or network; they'll get re-initialized if
+		**	the user selections those options again in Select_Game().  This
+		**	"re-boots" the modem & network code, which I currently feel is safer
+		**	than just letting it hang around.
+		** (Skip this step if we're in playback mode; the modem or net won't have
+		** been initialized in that case.)
+		*/
+		if (Session.Record || Session.Play) {
+			Session.RecordFile.Close();
+		}
+
+		if (Session.Type == GAME_NULL_MODEM || Session.Type == GAME_MODEM) {
+			if (!Session.Play) {
+				Modem_Signoff();
+			}
+		} else {
+			if (Session.Type == GAME_IPX) {
+				if (!Session.Play) {
+					Shutdown_Network();
+				}
+			}
+		}
+
+#if(TEN)
+
+		if (Session.Type == GAME_TEN) {
+			Shutdown_TEN();
+			//Prog_End();
+			Emergency_Exit(0);
+		}
+#endif	// TEN
+
+#if(MPATH)
+		if (Session.Type == GAME_MPATH) {
+			Shutdown_MPATH();
+			//Prog_End();
+			Emergency_Exit(0);
+		}
+#endif	// MPATH
+
+		/*
+		**	If we're playing back, the mouse will be hidden; show it.
+		** Also, set all variables back to normal, to return to the main menu.
+		*/
+		if (Session.Play) {
+			Show_Mouse();
+			Session.Type = GAME_NORMAL;
+			Session.Play = 0;
+		}
+#ifndef WOLAPI_INTEGRATION
+#ifdef WIN32
+		if (Special.IsFromWChat) {
+			Shutdown_Network();		      // Clear up the pseudo IPX stuff
+#ifndef WINSOCK_IPX
+			Winsock.Close();
+#endif	//WINSOCK_IPX
+			Special.IsFromWChat = false;
+			SpawnedFromWChat = false;
+			DDEServer.Delete_MPlayer_Game_Info();	//Make sure we dont use the same start packet twice
+			Session.Type = GAME_NORMAL;			//Have to do this or we will got straight to the multiplayer menu
+			Spawn_WChat(false);		//Will switch back to Wchat. It must be there because its been poking us
+		}
+#endif	//WIN32
+#endif	//	!WOLAPI_INTEGRATION
+	}
+
+	/*
+	**	Free the scenario description buffers
+	*/
+	Session.Free_Scenario_Descriptions();
+}
+
+
+/***********************************************************************************************
+ * Keyboard_Process -- Processes the tactical map input codes.                                 *
+ *                                                                                             *
+ *    This routine is used to process the input codes while the player                         *
+ *    has the tactical map displayed. It handles all the keys that                             *
+ *    are appropriate to that mode.                                                            *
+ *                                                                                             *
+ * INPUT:   input -- Input code as returned from Input_Num().                                  *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   01/21/1992 JLB : Created.                                                                 *
+ *   07/04/1995 JLB : Handles team and map control hotkeys.                                    *
+ *=============================================================================================*/
+void Keyboard_Process(KeyNumType & input)
+{
+	ObjectClass * obj;
+	int index;
+
+	/*
+	**	Don't do anything if there is not keyboard event.
+	*/
+	if (input == KN_NONE) {
+		return;
+	}
+	/*
+	**	For network & modem, process user input for inter-player messages.
+	*/
+	Message_Input(input);
+
+#ifdef WIN32
+	/*
+	**	The VK_BIT must be stripped from the "plain" value of the key so that a comparison to
+	**	KN_1, for example, will yield TRUE if in fact the "1" key was pressed.
+	*/
+
+	KeyNumType plain = KeyNumType(input & ~(WWKEY_SHIFT_BIT|WWKEY_ALT_BIT|WWKEY_CTRL_BIT|WWKEY_VK_BIT));
+	KeyNumType key = KeyNumType(input & ~WWKEY_VK_BIT);
+
+
+#else
+	KeyNumType plain = KeyNumType(input & ~(KN_SHIFT_BIT|KN_ALT_BIT|KN_CTRL_BIT));
+	KeyNumType key = plain;
+#endif
+
+#ifdef CHEAT_KEYS
+
+	if (Debug_Flag) {
+		HousesType h;
+
+		switch (int(input)) {
+			case int(int(KN_M) | int(KN_SHIFT_BIT)):
+			case int(int(KN_M) | int(KN_ALT_BIT)):
+			case int(int(KN_M) | int(KN_CTRL_BIT)):
+				for (h = HOUSE_FIRST; h < HOUSE_COUNT; h++) {
+					Houses.Ptr(h)->Refund_Money(10000);
+				}
+				break;
+
+			default:
+				break;
+		}
+	}
+#endif
+
+#ifdef VIRGIN_CHEAT_KEYS
+	if (Debug_Playtest && input == (KN_W|KN_ALT_BIT)) {
+		PlayerPtr->Blockage = false;
+		PlayerPtr->Flag_To_Win();
+	}
+#endif
+
+#ifdef CHEAT_KEYS
+#ifdef WIN32
+	if (Debug_Playtest && input == (KA_W|KN_ALT_BIT)) {
+#else
+	if (Debug_Playtest && input == (KN_W|KN_ALT_BIT)) {
+#endif
+		PlayerPtr->Blockage = false;
+		PlayerPtr->Flag_To_Win();
+	}
+
+	if ((Debug_Flag || Debug_Playtest) && plain == KN_F4) {
+		if (Session.Type == GAME_NORMAL) {
+			Debug_Unshroud = (Debug_Unshroud == false);
+			Map.Flag_To_Redraw(true);
+		}
+	}
+
+	if (Debug_Flag && input == KN_SLASH) {
+		if (Session.Type != GAME_NORMAL) {
+			SpecialDialog = SDLG_SPECIAL;
+			input = KN_NONE;
+		} else {
+			Special_Dialog();
+		}
+	}
+#endif
+
+	/*
+	**	Process prerecorded team selection. This will be an additive select
+	**	if the SHIFT key is held down. It will create the team if the
+	**	CTRL or ALT key is held down.
+	*/
+	int action = 0;
+#ifdef WIN32
+	if (input & WWKEY_SHIFT_BIT) action = 1;
+	if (input & WWKEY_ALT_BIT) action = 3;
+	if (input & WWKEY_CTRL_BIT) action = 2;
+#else
+	if (input & KN_SHIFT_BIT) action = 1;
+	if (input & KN_ALT_BIT) action = 3;
+	if (input & KN_CTRL_BIT) action = 2;
+#endif
+
+	/*
+	**	If the "N" key is pressed, then select the next object.
+	*/
+	if (key != 0 && key == Options.KeyNext) {
+		if (action) {
+			obj = Map.Prev_Object(CurrentObject.Count() ? CurrentObject[0] : NULL);
+		} else {
+			obj = Map.Next_Object(CurrentObject.Count() ? CurrentObject[0] : NULL);
+		}
+		if (obj != NULL) {
+			Unselect_All();
+		 	obj->Select();
+			Map.Center_Map();
+			Map.Flag_To_Redraw(true);
+		}
+		input = KN_NONE;
+	}
+	if (key != 0 && key == Options.KeyPrevious) {
+		if (action) {
+			obj = Map.Next_Object(CurrentObject.Count() ? CurrentObject[0] : NULL);
+		} else {
+			obj = Map.Prev_Object(CurrentObject.Count() ? CurrentObject[0] : NULL);
+		}
+		if (obj != NULL) {
+			Unselect_All();
+		 	obj->Select();
+			Map.Center_Map();
+			Map.Flag_To_Redraw(true);
+		}
+		input = KN_NONE;
+	}
+
+
+	/*
+	**	All selected units will go into idle mode.
+	*/
+	if (key != 0 && key == Options.KeyStop) {
+		if (CurrentObject.Count()) {
+			for (index = 0; index < CurrentObject.Count(); index++) {
+				ObjectClass const * tech = CurrentObject[index];
+
+				if (tech != NULL && (tech->Can_Player_Move() || (tech->Can_Player_Fire() && tech->What_Am_I() != RTTI_BUILDING))) {
+					OutList.Add(EventClass(EventClass::IDLE, TargetClass(tech)));
+				}
+			}
+		}
+		input = KN_NONE;
+	}
+
+	/*
+	**	All selected units will attempt to go into guard area mode.
+	*/
+	if (key != 0 && key == Options.KeyGuard) {
+		if (CurrentObject.Count()) {
+			for (index = 0; index < CurrentObject.Count(); index++) {
+				ObjectClass const * tech = CurrentObject[index];
+
+				if (tech != NULL && tech->Can_Player_Move() && tech->Can_Player_Fire()) {
+					OutList.Add(EventClass(TargetClass(tech), MISSION_GUARD_AREA));
+				}
+			}
+		}
+		input = KN_NONE;
+	}
+
+	/*
+	**	All selected units will attempt to scatter.
+	*/
+	if (key != 0 && key == Options.KeyScatter) {
+		if (CurrentObject.Count()) {
+			for (index = 0; index < CurrentObject.Count(); index++) {
+				ObjectClass const * tech = CurrentObject[index];
+
+				if (tech != NULL && tech->Can_Player_Move()) {
+					OutList.Add(EventClass(EventClass::SCATTER, TargetClass(tech)));
+				}
+			}
+		}
+		input = KN_NONE;
+	}
+
+	/*
+	**	Center the map around the currently selected objects. If no
+	**	objects are selected, then fall into the home case.
+	*/
+	if (key != 0 && (key == Options.KeyHome1 || key == Options.KeyHome2)) {
+		if (CurrentObject.Count()) {
+			Map.Center_Map();
+#ifdef WIN32
+			Map.Flag_To_Redraw(true);
+#endif
+			input = KN_NONE;
+		} else {
+			input = Options.KeyBase;
+		}
+	}
+
+	/*
+	**	Center the map about the construction yard or construction vehicle
+	**	if one is present.
+	*/
+	if (key != 0 && key == Options.KeyBase) {
+		Unselect_All();
+		if (PlayerPtr->CurBuildings) {
+			for (index = 0; index < Buildings.Count(); index++) {
+				BuildingClass * building = Buildings.Ptr(index);
+
+				if (building != NULL && !building->IsInLimbo && building->House == PlayerPtr && *building == STRUCT_CONST) {
+					Unselect_All();
+					building->Select();
+					if (building->IsLeader) break;
+				}
+			}
+		}
+		if (CurrentObject.Count() == 0 && PlayerPtr->CurUnits) {
+			for (index = 0; index < Units.Count(); index++) {
+				UnitClass * unit = Units.Ptr(index);
+
+				if (unit != NULL && !unit->IsInLimbo && unit->House == PlayerPtr && *unit == UNIT_MCV) {
+					Unselect_All();
+					unit->Select();
+					break;
+				}
+			}
+		}
+		if (CurrentObject.Count()) {
+			Map.Center_Map();
+		} else {
+			if (PlayerPtr->Center != 0) {
+				Map.Center_Map(PlayerPtr->Center);
+			}
+		}
+		Map.Flag_To_Redraw(true);
+		input = KN_NONE;
+	}
+
+	/*
+	** Toggle the status of formation for the current team
+	*/
+	if (key != 0 && key == Options.KeyFormation) {
+		Toggle_Formation();
+		input = KN_NONE;
+	}
+
+#ifdef TOFIX
+	/*
+	** For multiplayer, 'R' pops up the surrender dialog.
+	*/
+	if (input != 0 && input == Options.KeyResign) {
+		if (!PlayerLoses && /*Session.Type != GAME_NORMAL &&*/ !PlayerPtr->IsDefeated) {
+			SpecialDialog = SDLG_SURRENDER;
+			input = KN_NONE;
+		}
+		input = KN_NONE;
+	}
+#endif
+
+	/*
+	**	Handle making and breaking alliances.
+	*/
+	if (key != 0 && key == Options.KeyAlliance) {
+		if (Session.Type != GAME_NORMAL || Debug_Flag) {
+			if (CurrentObject.Count() && !PlayerPtr->IsDefeated) {
+				if (CurrentObject[0]->Owner() != PlayerPtr->Class->House) {
+					OutList.Add(EventClass(EventClass::ALLY, CurrentObject[0]->Owner()));
+				}
+			}
+		}
+		input = KN_NONE;
+	}
+
+	/*
+	**	Select all the units on the current display. This is equivalent to
+	**	drag selecting the whole view.
+	*/
+	if (key != 0 && key == Options.KeySelectView) {
+		Map.Select_These(0x00000000, XY_Coord(Map.TacLeptonWidth, Map.TacLeptonHeight));
+		input = KN_NONE;
+	}
+
+	/*
+	**	Toggles the repair state similarly to pressing the repair button.
+	*/
+	if (key != 0 && key == Options.KeyRepair) {
+		Map.Repair_Mode_Control(-1);
+		input = KN_NONE;
+	}
+
+	/*
+	**	Toggles the sell state similarly to pressing the sell button.
+	*/
+	if (key != 0 && key == Options.KeySell) {
+		Map.Sell_Mode_Control(-1);
+		input = KN_NONE;
+	}
+
+	/*
+	**	Toggles the map zoom mode similarly to pressing the map button.
+	*/
+	if (key != 0 && key == Options.KeyMap) {
+		Map.Zoom_Mode_Control();
+		input = KN_NONE;
+	}
+
+	/*
+	**	Scrolls the sidebar up one slot.
+	*/
+	if (key != 0 && key == Options.KeySidebarUp) {
+		Map.SidebarClass::Scroll(true, -1);
+		input = KN_NONE;
+	}
+
+	/*
+	**	Scrolls the sidebar down one slot.
+	*/
+	if (key != 0 && key == Options.KeySidebarDown) {
+		Map.SidebarClass::Scroll(false, -1);
+		input = KN_NONE;
+	}
+
+	/*
+	**	Brings up the options dialog box.
+	*/
+	if (key != 0 && (key == Options.KeyOption1 || key == Options.KeyOption2)) {
+		Map.Help_Text(TXT_NONE);			// Turns off help text.
+		Queue_Options();
+		input = KN_NONE;
+	}
+
+	/*
+	**	Scrolls the tactical map in the direction specified.
+	*/
+	int distance = CELL_LEPTON_W;
+	if (key != 0 && key == Options.KeyScrollLeft) {
+		Map.Scroll_Map(DIR_W, distance, true);
+		input = KN_NONE;
+	}
+	if (key != 0 && key == Options.KeyScrollRight) {
+		Map.Scroll_Map(DIR_E, distance, true);
+		input = KN_NONE;
+	}
+	if (key != 0 && key == Options.KeyScrollUp) {
+		Map.Scroll_Map(DIR_N, distance, true);
+		input = KN_NONE;
+	}
+	if (key != 0 && key == Options.KeyScrollDown) {
+		Map.Scroll_Map(DIR_S, distance, true);
+		input = KN_NONE;
+	}
+
+	/*
+	**	Teams are handled by the 10 special team keys. The manual comparison
+	**	to the KN numbers is because the Windows keyboard driver can vary
+	**	the base code number for the key depending on the shift or alt key
+	**	state!
+	*/
+	if (input != 0 && (plain == Options.KeyTeam1 || plain == KN_1)) {
+		Handle_Team(0, action);
+		input = KN_NONE;
+	}
+	if (input != 0 && (plain == Options.KeyTeam2 || plain == KN_2)) {
+		Handle_Team(1, action);
+		input = KN_NONE;
+	}
+	if (input != 0 && (plain == Options.KeyTeam3 || plain == KN_3)) {
+		Handle_Team(2, action);
+		input = KN_NONE;
+	}
+	if (input != 0 && (plain == Options.KeyTeam4 || plain == KN_4)) {
+		Handle_Team(3, action);
+		input = KN_NONE;
+	}
+	if (input != 0 && (plain == Options.KeyTeam5 || plain == KN_5)) {
+		Handle_Team(4, action);
+		input = KN_NONE;
+	}
+	if (input != 0 && (plain == Options.KeyTeam6 || plain == KN_6)) {
+		Handle_Team(5, action);
+		input = KN_NONE;
+	}
+	if (input != 0 && (plain == Options.KeyTeam7 || plain == KN_7)) {
+		Handle_Team(6, action);
+		input = KN_NONE;
+	}
+	if (input != 0 && (plain == Options.KeyTeam8 || plain == KN_8)) {
+		Handle_Team(7, action);
+		input = KN_NONE;
+	}
+	if (input != 0 && (plain == Options.KeyTeam9 || plain == KN_9)) {
+		Handle_Team(8, action);
+		input = KN_NONE;
+	}
+	if (input != 0 && (plain == Options.KeyTeam10 || plain == KN_0)) {
+		Handle_Team(9, action);
+		input = KN_NONE;
+	}
+
+	/*
+	**	Handle the bookmark hotkeys.
+	*/
+	if (input != 0 && plain == Options.KeyBookmark1 && !Debug_Map) {
+		Handle_View(0, action);
+		input = KN_NONE;
+	}
+	if (input != 0 && plain == Options.KeyBookmark2 && !Debug_Map) {
+		Handle_View(1, action);
+		input = KN_NONE;
+	}
+	if (input != 0 && plain == Options.KeyBookmark3 && !Debug_Map) {
+		Handle_View(2, action);
+		input = KN_NONE;
+	}
+	if (input != 0 && plain == Options.KeyBookmark4 && !Debug_Map) {
+		Handle_View(3, action);
+		input = KN_NONE;
+	}
+
+#ifdef CHEAT_KEYS
+	if (input != 0 && Debug_Flag && input && (input & KN_RLSE_BIT) == 0) {
+		Debug_Key(input);
+	}
+#endif
+}
+
+
+void Toggle_Formation(void) {
+	int team = -1;
+	long minx = 0x7FFFFFFFL, miny = 0x7FFFFFFFL;
+	long maxx = 0, maxy = 0;
+	int index;
+	bool setform = 0;
+
+	//
+	// Recording support
+	//
+	if (Session.Record) {
+		FormationEvent = 1;
+	}
+
+	/*
+	** Find the first selected object that is a member of a team, and
+	** register his group as the team we're using.  Once we find the team
+	** number, update the 'setform' flag to know whether we should be setting
+	** the formation's offsets, or clearing them.  If they currently have
+	** illegal offsets (as in 0x80000000), then we're setting.
+	*/
+	for (index = 0; index < Units.Count(); index++) {
+		UnitClass * obj = Units.Ptr(index);
+		if (obj && !obj->IsInLimbo && obj->House == PlayerPtr && obj->IsSelected) {
+			team = obj->Group;
+			if (team != -1) {
+				setform = obj->XFormOffset == (int)0x80000000;
+				TeamSpeed[team] = SPEED_WHEEL;
+				TeamMaxSpeed[team] = MPH_LIGHT_SPEED;
+				break;
+			}
+		}
+	}
+	if (team == -1) {
+		for (index = 0; index < Infantry.Count(); index++) {
+			InfantryClass * obj = Infantry.Ptr(index);
+			if (obj && !obj->IsInLimbo && obj->House == PlayerPtr && obj->IsSelected) {
+				team = obj->Group;
+				if (team != -1) {
+					setform = obj->XFormOffset == (int)0x80000000;
+					TeamSpeed[team] = SPEED_WHEEL;
+					TeamMaxSpeed[team] = MPH_LIGHT_SPEED;
+					break;
+				}
+			}
+		}
+	}
+
+	if (team == -1) {
+		for (index = 0; index < Vessels.Count(); index++) {
+			VesselClass * obj = Vessels.Ptr(index);
+			if (obj && !obj->IsInLimbo && obj->House == PlayerPtr && obj->IsSelected) {
+				team = obj->Group;
+				if (team != -1) {
+					setform = obj->XFormOffset == 0x80000000UL;
+					TeamSpeed[team] = SPEED_WHEEL;
+					TeamMaxSpeed[team] = MPH_LIGHT_SPEED;
+					break;
+				}
+			}
+		}
+	}
+
+	if (team == -1) return;
+	/*
+	** Now that we have a team, let's go set (or clear) the formation offsets.
+	*/
+	for (index = 0; index < Units.Count(); index++) {
+		UnitClass * obj = Units.Ptr(index);
+		if (obj && !obj->IsInLimbo && obj->House == PlayerPtr && obj->Group == team) {
+			obj->Mark(MARK_CHANGE);
+			if (setform) {
+				long xc = Cell_X(Coord_Cell(obj->Center_Coord()));
+				long yc = Cell_Y(Coord_Cell(obj->Center_Coord()));
+				if (xc < minx) minx = xc;
+				if (xc > maxx) maxx = xc;
+				if (yc < miny) miny = yc;
+				if (yc > maxy) maxy = yc;
+				if (obj->Class->MaxSpeed < TeamMaxSpeed[team]) {
+					TeamMaxSpeed[team] = obj->Class->MaxSpeed;
+					TeamSpeed[team] = obj->Class->Speed;
+				}
+			} else {
+				obj->XFormOffset = obj->YFormOffset = (int)0x80000000;
+			}
+		}
+	}
+
+	for (index = 0; index < Infantry.Count(); index++) {
+		InfantryClass * obj = Infantry.Ptr(index);
+		if (obj && !obj->IsInLimbo && obj->House == PlayerPtr && obj->Group == team) {
+			obj->Mark(MARK_CHANGE);
+			if (setform) {
+				long xc = Cell_X(Coord_Cell(obj->Center_Coord()));
+				long yc = Cell_Y(Coord_Cell(obj->Center_Coord()));
+				if (xc < minx) minx = xc;
+				if (xc > maxx) maxx = xc;
+				if (yc < miny) miny = yc;
+				if (yc > maxy) maxy = yc;
+				if (obj->Class->MaxSpeed < TeamMaxSpeed[team]) {
+					TeamMaxSpeed[team] = obj->Class->MaxSpeed;
+				}
+			} else {
+				obj->XFormOffset = obj->YFormOffset = (int)0x80000000;
+			}
+		}
+	}
+
+	for (index = 0; index < Vessels.Count(); index++) {
+		VesselClass * obj = Vessels.Ptr(index);
+		if (obj && !obj->IsInLimbo && obj->House == PlayerPtr && obj->Group == team) {
+			obj->Mark(MARK_CHANGE);
+			if (setform) {
+				long xc = Cell_X(Coord_Cell(obj->Center_Coord()));
+				long yc = Cell_Y(Coord_Cell(obj->Center_Coord()));
+				if (xc < minx) minx = xc;
+				if (xc > maxx) maxx = xc;
+				if (yc < miny) miny = yc;
+				if (yc > maxy) maxy = yc;
+				if (obj->Class->MaxSpeed < TeamMaxSpeed[team]) {
+					TeamMaxSpeed[team] = obj->Class->MaxSpeed;
+				}
+			} else {
+				obj->XFormOffset = obj->YFormOffset = 0x80000000UL;
+			}
+		}
+	}
+
+	/*
+	** All the units have been counted to find the bounding rectangle and
+	** center of the formation, or to clear their offsets.  Now, if we're to
+	** set them into formation, proceed to do so.  Otherwise, bail.
+	*/
+	if (setform) {
+		int centerx = (int)((maxx - minx)/2)+minx;
+		int centery = (int)((maxy - miny)/2)+miny;
+
+		for (index = 0; index < Units.Count(); index++) {
+			UnitClass * obj = Units.Ptr(index);
+			if (obj && !obj->IsInLimbo && obj->House == PlayerPtr && obj->Group == team) {
+				long xc = Cell_X(Coord_Cell(obj->Center_Coord()));
+				long yc = Cell_Y(Coord_Cell(obj->Center_Coord()));
+
+				obj->XFormOffset = xc - centerx;
+				obj->YFormOffset = yc - centery;
+			}
+		}
+
+		for (index = 0; index < Infantry.Count(); index++) {
+			InfantryClass * obj = Infantry.Ptr(index);
+			if (obj && !obj->IsInLimbo && obj->House == PlayerPtr && obj->Group == team ) {
+				long xc = Cell_X(Coord_Cell(obj->Center_Coord()));
+				long yc = Cell_Y(Coord_Cell(obj->Center_Coord()));
+
+				obj->XFormOffset = xc - centerx;
+				obj->YFormOffset = yc - centery;
+			}
+		}
+
+		for (index = 0; index < Vessels.Count(); index++) {
+			VesselClass * obj = Vessels.Ptr(index);
+			if (obj && !obj->IsInLimbo && obj->House == PlayerPtr && obj->Group == team ) {
+				long xc = Cell_X(Coord_Cell(obj->Center_Coord()));
+				long yc = Cell_Y(Coord_Cell(obj->Center_Coord()));
+
+				obj->XFormOffset = xc - centerx;
+				obj->YFormOffset = yc - centery;
+			}
+		}
+	}
+}
+
+
+/***********************************************************************************************
+ * Message_Input -- allows inter-player message input processing                               *
+ *                                                                                             *
+ * INPUT:                                                                                      *
+ *		input		key value																							  *
+ *                                                                                             *
+ * OUTPUT:                                                                                     *
+ *		none.																												  *
+ *                                                                                             *
+ * WARNINGS:                                                                                   *
+ *		none.																												  *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/22/1995 BRR : Created.                                                                 *
+ *=============================================================================================*/
+#pragma off (unreferenced)
+static void Message_Input(KeyNumType &input)
+{
+	int rc;
+	char txt[MAX_MESSAGE_LENGTH+32];
+	int id;
+	SerialPacketType * serial_packet;
+	int i;
+	KeyNumType copy_input;
+	//char *msg;
+
+	/*
+	**	Check keyboard input for a request to send a message.
+	**	The 'to' argument for Add_Edit is prefixed to the message buffer; the
+	**	message buffer is big enough for the 'to' field plus MAX_MESSAGE_LENGTH.
+	**	To send the message, calling Get_Edit_Buf retrieves the buffer minus the
+	**	'to' portion.  At the other end, the buffer allocated to display the
+	**	message must be MAX_MESSAGE_LENGTH plus the size of "From: xxx (house)".
+	*/
+#ifdef WOLAPI_INTEGRATION
+	if (Session.Type != GAME_NORMAL && Session.Type != GAME_SKIRMISH && 
+		( ( input >= KN_F1 && input < (KN_F1 + Session.MaxPlayers) ) || input == PAGE_RESPOND_KEY ) && 
+		!Session.Messages.Is_Edit()) {
+#else
+	if (Session.Type != GAME_NORMAL && Session.Type != GAME_SKIRMISH && input >= KN_F1 && input < (KN_F1 + Session.MaxPlayers) && !Session.Messages.Is_Edit()) {
+#endif
+		memset (txt, 0, 40);
+
+		/*
+		**	For a serial game, send a message on F1 or F4; set 'txt' to the
+		**	"Message:" string & add an editable message to the list.
+		*/
+		if (Session.Type==GAME_NULL_MODEM || Session.Type==GAME_MODEM) {
+			if (input==KN_F1 || input==(KN_F1 + Session.MaxPlayers - 1)) {
+
+				strcpy(txt, Text_String(TXT_MESSAGE));	// "Message:"
+
+				Session.Messages.Add_Edit (Session.ColorIdx,
+					TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW, txt, 0, 232 * RESFACTOR);
+
+				Map.Flag_To_Redraw(false);
+			}
+		} else if ((Session.Type == GAME_IPX || Session.Type == GAME_INTERNET) && !Session.Messages.Is_Edit()) {
+		/*
+		**	For a network game:
+		**	F1-F7 = "To <name> (house):" (only allowed if we're not in ObiWan mode)
+		**	F8 = "To All:"
+		*/
+			if (input==(KN_F1 + Session.MaxPlayers - 1)) {
+
+				Session.MessageAddress = IPXAddressClass();		// set to broadcast
+				strcpy(txt, Text_String(TXT_TO_ALL));	// "To All:"
+
+				Session.Messages.Add_Edit(Session.ColorIdx,
+					TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW, txt, 0, 232 * RESFACTOR);
+
+				Map.Flag_To_Redraw(false);
+
+#ifdef WOLAPI_INTEGRATION
+			} else if ((input - KN_F1) < Ipx.Num_Connections() && !Session.ObiWan && input != PAGE_RESPOND_KEY ) {
+#else
+			} else if ((input - KN_F1) < Ipx.Num_Connections() && !Session.ObiWan) {
+#endif
+				id = Ipx.Connection_ID(input - KN_F1);
+				Session.MessageAddress = (*(Ipx.Connection_Address (id)));
+				sprintf(txt, Text_String(TXT_TO), Ipx.Connection_Name(id));
+
+				Session.Messages.Add_Edit(Session.ColorIdx,
+					TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW, txt, 0, 232 * RESFACTOR);
+
+				Map.Flag_To_Redraw(false);
+			}
+#ifdef WOLAPI_INTEGRATION
+			else if( Session.Type == GAME_INTERNET && pWolapi && !pWolapi->bConnectionDown && input == PAGE_RESPOND_KEY )
+			{
+				if( *pWolapi->szExternalPager )
+				{
+					//	Respond to a page from external ww online user that paged me.
+					//	Set MessageAddress to all zeroes, as a flag to ourselves later on.
+					NetNumType blip;
+					NetNodeType blop;
+					memset( blip, 0, 4 );
+					memset( blop, 0, 6 );
+					Session.MessageAddress = IPXAddressClass( blip, blop );
+
+					//	Tell pWolapi not to reset szExternalPager for the time being.
+					pWolapi->bFreezeExternalPager = true;
+
+					sprintf( txt, Text_String( TXT_TO ), pWolapi->szExternalPager );
+
+					Session.Messages.Add_Edit(Session.ColorIdx,
+						TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW, txt, 0, 232 * RESFACTOR);
+
+					Map.Flag_To_Redraw(false);
+
+					Keyboard->Clear();
+				}
+				else
+				{
+					Session.Messages.Add_Message( NULL, 0, TXT_WOL_NOTPAGED, PCOLOR_GOLD, TPF_6PT_GRAD|TPF_USE_GRAD_PAL|TPF_FULLSHADOW, Rule.MessageDelay * TICKS_PER_MINUTE );
+					Sound_Effect( VOC_SYS_ERROR );
+				}
+			}
+#endif
+		}
+#if(TEN)
+		/*
+		**	For a TEN game:
+		**	F1-F7 = "To <name> (house):" (only allowed if we're not in ObiWan mode)
+		**	F8 = "To All:"
+		*/
+		else if (Session.Type == GAME_TEN && !Session.Messages.Is_Edit()) {
+			if (input==(KN_F1 + Session.MaxPlayers - 1)) {
+
+				Session.TenMessageAddress = -1;		// set to broadcast
+				strcpy(txt,Text_String(TXT_TO_ALL));	// "To All:"
+
+				Session.Messages.Add_Edit(Session.ColorIdx,
+					TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW, txt, 0, 232 * RESFACTOR);
+
+				Map.Flag_To_Redraw(false);
+
+			}  else if ((input - KN_F1) < Ten->Num_Connections() && !Session.ObiWan) {
+
+				id = Ten->Connection_ID(input - KN_F1);
+				Session.TenMessageAddress = Ten->Connection_Address(id);
+				sprintf(txt,Text_String(TXT_TO),Ten->Connection_Name(id));
+
+				Session.Messages.Add_Edit(Session.ColorIdx,
+					TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW, txt, 0, 232 * RESFACTOR);
+
+				Map.Flag_To_Redraw(false);
+			}
+		}
+#endif	// TEN
+#if(MPATH)
+		/*
+		**	For a MPATH game:
+		**	F1-F7 = "To <name> (house):" (only allowed if we're not in ObiWan mode)
+		**	F8 = "To All:"
+		*/
+		else if (Session.Type == GAME_MPATH && !Session.Messages.Is_Edit()) {
+			if (input==(KN_F1 + Session.MaxPlayers - 1)) {
+
+				Session.MPathMessageAddress = 0;			// set to broadcast
+				strcpy(txt,Text_String(TXT_TO_ALL));	// "To All:"
+
+				Session.Messages.Add_Edit(Session.ColorIdx,
+					TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW, txt, 0, 232 * RESFACTOR);
+
+				Map.Flag_To_Redraw(false);
+
+			}  else if ((input - KN_F1) < MPath->Num_Connections() && !Session.ObiWan) {
+
+				id = MPath->Connection_ID(input - KN_F1);
+				Session.MPathMessageAddress = MPath->Connection_Address(id);
+				sprintf(txt,Text_String(TXT_TO),MPath->Connection_Name(id));
+
+				Session.Messages.Add_Edit(Session.ColorIdx,
+					TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW, txt, 0, 232 * RESFACTOR);
+
+				Map.Flag_To_Redraw(false);
+			}
+		}
+#endif	// MPATH
+	}
+
+	/*
+	**	Process message-system input; send the message out if RETURN is hit.
+	*/
+	copy_input = input;
+	rc = Session.Messages.Input(input);
+
+	/*
+	**	If a single character has been added to an edit buffer, update the display.
+	*/
+	if (rc == 1 && Session.Type != GAME_NORMAL) {
+		Map.Flag_To_Redraw(false);
+	}
+
+	/*
+	**	If backspace was hit, redraw the map.  If the edit message was removed,
+	** the map must be force-drawn, since it won't be able to compute the
+	** cells to redraw; otherwise, let the map compute the cells to redraw,
+	** by not force-drawing it, but just setting the IsToRedraw bit.
+	*/
+	if (rc==2 && Session.Type != GAME_NORMAL) {
+		if (copy_input==KN_ESC) {
+			Map.Flag_To_Redraw(true);
+#ifdef WOLAPI_INTEGRATION
+			if( pWolapi )
+				//	Just in case user was responding to a page from outside the game, and we had frozen the "szExternalPager".
+				pWolapi->bFreezeExternalPager = false;
+#endif
+		} else {
+			Map.Flag_To_Redraw(false);
+		}
+		Map.DisplayClass::IsToRedraw = true;
+	}
+
+	/*
+	**	Send a message
+	*/
+	if ((rc==3 || rc==4) && Session.Type != GAME_NORMAL && Session.Type != GAME_SKIRMISH) {
+		/*
+		**	Serial game: fill in a SerialPacketType & send it.
+		**	(Note: The size of the SerialPacketType.Command must be the same as
+		**	the EventClass.Type!)
+		*/
+		if (Session.Type==GAME_NULL_MODEM || Session.Type==GAME_MODEM) {
+			serial_packet = (SerialPacketType *)NullModem.BuildBuf;
+
+			serial_packet->Command = SERIAL_MESSAGE;
+			strcpy (serial_packet->Name, Session.Players[0]->Name);
+			serial_packet->ID = Session.ColorIdx;
+
+			if (rc==3) {
+				strcpy (serial_packet->Message.Message, Session.Messages.Get_Edit_Buf());
+			} else {
+				strcpy (serial_packet->Message.Message, Session.Messages.Get_Overflow_Buf());
+				Session.Messages.Clear_Overflow_Buf();
+			}
+
+			/*
+			** Send the message, and store this message in our LastMessage
+			** buffer; the computer may send us a version of it later.
+			*/
+			NullModem.Send_Message(NullModem.BuildBuf,
+				sizeof(SerialPacketType), 1);
+
+#ifdef FIXIT_CSII	//	checked - ajw 9/28/98
+	char *ptr = &serial_packet->Message.Message[0];
+	if (!strncmp(ptr,"SECRET UNITS ON ",15) && NewUnitsEnabled) {
+		Enable_Secret_Units();
+	}
+#endif
+			strcpy(Session.LastMessage, serial_packet->Message.Message);
+		} else if (Session.Type == GAME_IPX || Session.Type == GAME_INTERNET) {
+#ifdef WOLAPI_INTEGRATION
+			NetNumType blip;
+			NetNodeType blop;
+			Session.MessageAddress.Get_Address( blip, blop );
+			if(	blip[0] + blip[1] + blip[2] + blip[3] + blop[0] + blop[1] + blop[2] + blop[3] + blop[4] + blop[5] == 0 )
+			{
+				//	This message is a response to the last person that paged me.
+				if( pWolapi && !pWolapi->bConnectionDown )		//	(As connection may have gone down.)
+				{
+					pWolapi->Page( pWolapi->szExternalPager, Session.Messages.Get_Edit_Buf(), false );
+					pWolapi->bFreezeExternalPager = false;
+				}
+			}
+			else
+#endif
+			{
+
+			/*
+			**	Network game: fill in a GlobalPacketType & send it.
+			*/
+				Session.GPacket.Command = NET_MESSAGE;
+				strcpy (Session.GPacket.Name, Session.Players[0]->Name);
+				Session.GPacket.Message.Color = Session.ColorIdx;
+				Session.GPacket.Message.NameCRC = Compute_Name_CRC(Session.GameName);
+
+				if (rc==3) {
+					strcpy (Session.GPacket.Message.Buf, Session.Messages.Get_Edit_Buf());
+				} else {
+					strcpy (Session.GPacket.Message.Buf,
+						Session.Messages.Get_Overflow_Buf());
+					Session.Messages.Clear_Overflow_Buf();
+				}
+
+				/*
+				**	If 'F4' was hit, MessageAddress will be a broadcast address; send
+				**	the message to every player we have a connection with.
+				*/
+				if (Session.MessageAddress.Is_Broadcast()) {
+	#ifdef FIXIT_CSII	//	checked - ajw 9/28/98
+		char *ptr = &Session.GPacket.Message.Buf[0];
+		if (!strncmp(ptr,"SECRET UNITS ON ",15) && NewUnitsEnabled) {
+			*ptr = 'X';		// force it to an odd hack so we know it was broadcast.
+			Enable_Secret_Units();
+		}
+	#endif
+					for (i = 0; i < Ipx.Num_Connections(); i++) {
+						Ipx.Send_Global_Message(&Session.GPacket,
+							sizeof(GlobalPacketType), 1,
+							Ipx.Connection_Address(Ipx.Connection_ID(i)));
+						Ipx.Service();
+					}
+				} else {
+
+					/*
+					**	Otherwise, MessageAddress contains the exact address to send to.
+					**	Send to that address only.
+					*/
+					Ipx.Send_Global_Message(&Session.GPacket,
+						sizeof(GlobalPacketType), 1,
+						&Session.MessageAddress);
+					Ipx.Service();
+
+				}
+
+				/*
+				**	Store this message in our LastMessage buffer; the computer may send
+				**	us a version of it later.
+				*/
+				strcpy(Session.LastMessage, Session.GPacket.Message.Buf);
+			}
+		}
+
+#if(TEN)
+		/*
+		**	TEN game: fill in a GlobalPacketType & send it.
+		*/
+		else if (Session.Type == GAME_TEN) {
+			Session.GPacket.Command = NET_MESSAGE;
+			strcpy (Session.GPacket.Name, Session.Players[0]->Name);
+			Session.GPacket.Message.Color = Session.ColorIdx;
+			Session.GPacket.Message.NameCRC = Compute_Name_CRC(Session.GameName);
+
+			if (rc==3) {
+				strcpy (Session.GPacket.Message.Buf, Session.Messages.Get_Edit_Buf());
+			} else {
+				strcpy (Session.GPacket.Message.Buf,
+					Session.Messages.Get_Overflow_Buf());
+				Session.Messages.Clear_Overflow_Buf();
+			}
+
+			Ten->Send_Global_Message(&Session.GPacket, sizeof(GlobalPacketType),
+				1, Session.TenMessageAddress);
+		}
+#endif	// TEN
+
+#if(MPATH)
+		/*
+		**	MPATH game: fill in a GlobalPacketType & send it.
+		*/
+		else if (Session.Type == GAME_MPATH) {
+			Session.GPacket.Command = NET_MESSAGE;
+			strcpy (Session.GPacket.Name, Session.Players[0]->Name);
+			Session.GPacket.Message.Color = Session.ColorIdx;
+			Session.GPacket.Message.NameCRC = Compute_Name_CRC(Session.GameName);
+
+			if (rc==3) {
+				strcpy (Session.GPacket.Message.Buf, Session.Messages.Get_Edit_Buf());
+			} else {
+				strcpy (Session.GPacket.Message.Buf,
+					Session.Messages.Get_Overflow_Buf());
+				Session.Messages.Clear_Overflow_Buf();
+			}
+
+			MPath->Send_Global_Message(&Session.GPacket, sizeof(GlobalPacketType),
+				1, Session.MPathMessageAddress);
+		}
+#endif	// MPATH
+
+		/*
+		**	Tell the map to completely update itself, since a message is now missing.
+		*/
+		Map.Flag_To_Redraw(true);
+	}
+}
+#pragma on (unreferenced)
+
+
+/***********************************************************************************************
+ * Color_Cycle -- Handle the general palette color cycling.                                    *
+ *                                                                                             *
+ *    This is a maintenance routine that handles the color cycling. It should be called as     *
+ *    often as necessary to achieve smooth color cycling effects -- at least 8 times a second. *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/31/1994 JLB : Created.                                                                 *
+ *   06/10/1994 JLB : Uses new cycle color values.                                             *
+ *   12/21/1994 JLB : Handles text fade color.                                                 *
+ *   07/16/1996 JLB : Faster pulsing of white color.                                           *
+ *=============================================================================================*/
+void Color_Cycle(void)
+{
+	static CDTimerClass<SystemTimerClass> _timer;
+	static CDTimerClass<SystemTimerClass> _ftimer;
+	static bool _up = false;
+	static int val = 255;
+	bool changed = false;
+
+	if (Options.IsPaletteScroll) {
+		/*
+		**	Process the fading white color. It is used for the radar box and other glowing
+		**	game interface elements.
+		*/
+		if (!_ftimer) {
+			_ftimer = TIMER_SECOND/6;
+
+			#define	STEP_RATE	20
+			if (_up) {
+				val += STEP_RATE;
+				if (val > 150) {
+					val = 150;
+					_up = false;
+				}
+			} else {
+				val -= STEP_RATE;
+				if (val < 0x20) {
+					val = 0x20;
+					_up = true;
+				}
+			}
+
+			/*
+			**	Set the pulse color as the proportional value between white and the
+			**	minimum value for pulsing.
+			*/
+			InGamePalette[CC_PULSE_COLOR] = GamePalette[WHITE];
+			InGamePalette[CC_PULSE_COLOR].Adjust(val, BlackColor);
+
+			/*
+			**	Pulse the glowing embers between medium and dark red.
+			*/
+			InGamePalette[CC_EMBER_COLOR] = RGBClass(255, 80, 80);
+			InGamePalette[CC_EMBER_COLOR].Adjust(val, BlackColor);
+
+			changed = true;
+		}
+
+		/*
+		**	Process the color cycling effects -- water.
+		*/
+		if (!_timer) {
+			_timer = TIMER_SECOND/4;
+
+			RGBClass first = InGamePalette[CYCLE_COLOR_START+CYCLE_COLOR_COUNT-1];
+			for (int index = CYCLE_COLOR_START+CYCLE_COLOR_COUNT-1; index >= CYCLE_COLOR_START; index--) {
+				InGamePalette[index] = InGamePalette[index-1];
+			}
+			InGamePalette[CYCLE_COLOR_START] = first;
+
+			changed = true;
+		}
+
+		/*
+		**	If any of the processing functions changed the palette, then this palette must be
+		**	passed to the system.
+		*/
+		if (changed) {
+			BStart(BENCH_PALETTE);
+			InGamePalette.Set();
+//			Set_Palette(InGamePalette);
+			BEnd(BENCH_PALETTE);
+		}
+	}
+}
+
+
+/***********************************************************************************************
+ * Call_Back -- Main game maintenance callback routine.                                        *
+ *                                                                                             *
+ *    This routine handles all the "real time" processing that needs to                        *
+ *    occur. This includes palette fading and sound updating. It needs                         *
+ *    to be called as often as possible.                                                       *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   10/07/1992 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void Call_Back(void)
+{
+	/*
+	**	Music and speech maintenance
+	*/
+	if (SampleType) {
+		Sound_Callback();
+		Theme.AI();
+		Speak_AI();
+	}
+
+	/*
+	**	Network maintenance.
+	*/
+	if (Session.Type == GAME_IPX || Session.Type == GAME_INTERNET) {
+		IPX_Call_Back();
+	}
+
+	/*
+	**	Serial game maintenance.
+	*/
+	if (Session.Type == GAME_NULL_MODEM || ((Session.Type == GAME_MODEM) && Session.ModemService)) {
+		NullModem.Service();
+	}
+
+#ifdef WOLAPI_INTEGRATION
+	//	Wolapi maintenance.
+	if( pWolapi )
+	{
+		if( pWolapi->bInGame )
+		{
+			if( !pWolapi->bConnectionDown && ::timeGetTime() > pWolapi->dwTimeNextWolapiPump )
+			{
+				pWolapi->pChat->PumpMessages();
+				pWolapi->pNetUtil->PumpMessages();
+				pWolapi->dwTimeNextWolapiPump = ::timeGetTime() + WOLAPIPUMPWAIT + 700;		//	Slower pump during games.
+				if( pWolapi->bConnectionDown )
+				{
+					//	Connection to server lost.
+					Session.Messages.Add_Message( NULL, 0, TXT_WOL_WOLAPIGONE, PCOLOR_GOLD, TPF_6PT_GRAD|TPF_USE_GRAD_PAL|TPF_FULLSHADOW, Rule.MessageDelay * TICKS_PER_MINUTE );
+					Sound_Effect( WOLSOUND_LOGOUT );
+//	ajw (Wolapi object is now left around, so we can try to send game results.)
+//					//	Kill wolapi.
+//					pWolapi->UnsetupCOMStuff();
+//					delete pWolapi;
+//					pWolapi = NULL;
+				}
+			}
+		}
+		else
+		{
+			//	When showing a modal dialog during chat, this pumping is turned on. It's turned off immediately following.
+			if( pWolapi->bPump_In_Call_Back && ( ::timeGetTime() > pWolapi->dwTimeNextWolapiPump ) )
+			{
+				pWolapi->pChat->PumpMessages();
+				pWolapi->pNetUtil->PumpMessages();
+				pWolapi->dwTimeNextWolapiPump = ::timeGetTime() + WOLAPIPUMPWAIT;
+			}
+		}
+	}
+#endif
+
+#if(TEN)
+	if (Session.Type == GAME_TEN) {
+		TEN_Call_Back();
+	}
+#endif	// TEN
+
+#if(MPATH)
+	if (Session.Type == GAME_MPATH) {
+		MPATH_Call_Back();
+	}
+#endif	// MPATH
+}
+
+
+void IPX_Call_Back(void)
+{
+	Ipx.Service();
+
+	/*
+	** Read packets only if the game is "closed", so we don't steal global
+	** messages from the connection dialogs.
+	*/
+	if (!Session.NetOpen) {
+		if (Ipx.Get_Global_Message (&Session.GPacket, &Session.GPacketlen, &Session.GAddress, &Session.GProductID)) {
+
+			if (Session.GProductID == IPXGlobalConnClass::COMMAND_AND_CONQUER0) {
+
+				/*
+				**	If this is another player signing off, remove the connection &
+				**	mark that player's house as non-human, so the computer will take
+				**	it over.
+				*/
+				if (Session.GPacket.Command == NET_SIGN_OFF) {
+					for (int i = 0; i < Ipx.Num_Connections(); i++) {
+
+						int id = Ipx.Connection_ID(i);
+
+						if (Session.GAddress == (*Ipx.Connection_Address(id))) {
+							Destroy_Connection(id, 0);
+						}
+					}
+				} else {
+
+					/*
+					**	Process a message from another user.
+					*/
+					if (Session.GPacket.Command == NET_MESSAGE) {
+						bool msg_ok = false;
+
+						/*
+						** If NetProtect is set, make sure this message came from within
+						** this game.
+						*/
+						if (!Session.NetProtect) {
+							msg_ok = true;
+						} else {
+							if (Session.GPacket.Message.NameCRC ==
+								Compute_Name_CRC(Session.GameName)) {
+								msg_ok = true;
+							} else {
+								msg_ok = false;
+							}
+						}
+
+						if (msg_ok) {
+							if (!Session.Messages.Concat_Message(Session.GPacket.Name,
+								Session.GPacket.Message.Color,
+								Session.GPacket.Message.Buf, Rule.MessageDelay * TICKS_PER_MINUTE)) {
+#ifdef FIXIT_CSII	//	checked - ajw 9/28/98
+	if (NewUnitsEnabled && !strncmp(Session.GPacket.Message.Buf,"XECRET UNITS ON ",15)) {
+		Session.GPacket.Message.Buf[0]='S';
+		Enable_Secret_Units();
+	}
+#endif
+								Session.Messages.Add_Message (Session.GPacket.Name,
+									Session.GPacket.Message.Color,
+									Session.GPacket.Message.Buf,
+									Session.GPacket.Message.Color,
+									TPF_6PT_GRAD | TPF_USE_GRAD_PAL |
+									TPF_FULLSHADOW, Rule.MessageDelay * TICKS_PER_MINUTE);
+
+								Sound_Effect(VOC_INCOMING_MESSAGE);
+							}
+
+							/*
+							**	Tell the map to do a partial update (just to force the messages
+							**	to redraw).
+							*/
+							Map.Flag_To_Redraw(true);
+
+							/*
+							**	Save this message in our last-message buffer
+							*/
+							strcpy(Session.LastMessage, Session.GPacket.Message.Buf);
+						}
+					} else {
+						Process_Global_Packet(&Session.GPacket, &Session.GAddress);
+					}
+				}
+			}
+		}
+	}
+
+}
+
+
+#if(TEN)
+void TEN_Call_Back(void)
+{
+	int id;
+
+	Ten->Service();
+
+	if (Ten->Get_Global_Message (&Session.GPacket, &Session.GPacketlen,
+		&Session.TenAddress)) {
+
+		//
+		//	If this is another player signing off, remove the connection &
+		//	mark that player's house as non-human, so the computer will take
+		//	it over.
+		//
+		if (Session.GPacket.Command == NET_SIGN_OFF) {
+			for (int i = 0; i < Ten->Num_Connections(); i++) {
+
+				id = Ten->Connection_ID(i);
+
+				if (Session.TenAddress == Ten->Connection_Address(id)) {
+					Destroy_TEN_Connection(id, 0);
+				}
+			}
+		}
+
+		//
+		//	Process a message from another user.
+		//
+		else if (Session.GPacket.Command == NET_MESSAGE) {
+			if (!Session.Messages.Concat_Message(Session.GPacket.Name,
+				Session.GPacket.Message.Color,
+				Session.GPacket.Message.Buf, Rule.MessageDelay * TICKS_PER_MINUTE)) {
+
+				Session.Messages.Add_Message (Session.GPacket.Name,
+					Session.GPacket.Message.Color,
+					Session.GPacket.Message.Buf,
+					Session.GPacket.Message.Color,
+					TPF_6PT_GRAD | TPF_USE_GRAD_PAL |
+					TPF_FULLSHADOW, Rule.MessageDelay * TICKS_PER_MINUTE);
+
+				Sound_Effect(VOC_INCOMING_MESSAGE);
+
+				/*
+				**	Tell the map to do a partial update (just to force the messages
+				**	to redraw).
+				*/
+				Map.Flag_To_Redraw(true);
+
+				/*
+				**	Save this message in our last-message buffer
+				*/
+				strcpy(Session.LastMessage, Session.GPacket.Message.Buf);
+			}
+		}
+	}
+}
+#endif	// TEN
+
+
+#if(MPATH)
+void MPATH_Call_Back(void)
+{
+	int id;
+
+	MPath->Service();
+
+	if (MPath->Get_Global_Message (&Session.GPacket, &Session.GPacketlen,
+		&Session.MPathAddress)) {
+
+		//
+		//	If this is another player signing off, remove the connection &
+		//	mark that player's house as non-human, so the computer will take
+		//	it over.
+		//
+		if (Session.GPacket.Command == NET_SIGN_OFF) {
+			for (int i = 0; i < MPath->Num_Connections(); i++) {
+
+				id = MPath->Connection_ID(i);
+
+				if (Session.MPathAddress == MPath->Connection_Address(id)) {
+					Destroy_MPATH_Connection(id, 0);
+				}
+			}
+		}
+
+		//
+		//	Process a message from another user.
+		//
+		else if (Session.GPacket.Command == NET_MESSAGE) {
+			if (!Session.Messages.Concat_Message(Session.GPacket.Name,
+				Session.GPacket.Message.Color,
+				Session.GPacket.Message.Buf, Rule.MessageDelay * TICKS_PER_MINUTE)) {
+
+				Session.Messages.Add_Message (Session.GPacket.Name,
+					Session.GPacket.Message.Color,
+					Session.GPacket.Message.Buf,
+					Session.GPacket.Message.Color,
+					TPF_6PT_GRAD | TPF_USE_GRAD_PAL |
+					TPF_FULLSHADOW, Rule.MessageDelay * TICKS_PER_MINUTE);
+
+				Sound_Effect(VOC_INCOMING_MESSAGE);
+
+				/*
+				**	Tell the map to do a partial update (just to force the messages
+				**	to redraw).
+				*/
+				Map.Flag_To_Redraw(true);
+
+				/*
+				**	Save this message in our last-message buffer
+				*/
+				strcpy(Session.LastMessage, Session.GPacket.Message.Buf);
+			}
+		}
+	}
+}
+#endif	// MPATH
+
+
+/***********************************************************************************************
+ * Language_Name -- Build filename for current language.                                       *
+ *                                                                                             *
+ *    This routine attaches a language specific suffix to the base                             *
+ *    filename provided. Typical use of this is when loading language                          *
+ *    specific files at game initialization time.                                              *
+ *                                                                                             *
+ * INPUT:   basename -- Base name to append language specific                                  *
+ *                      extension to.                                                          *
+ *                                                                                             *
+ * OUTPUT:  Returns with pointer to completed filename.                                        *
+ *                                                                                             *
+ * WARNINGS:   The return pointer value is valid only until the next time                      *
+ *             this routine is called.                                                         *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   10/07/1992 JLB : Created.                                                                 *
+ *=============================================================================================*/
+char const * Language_Name(char const * basename)
+{
+	static char _fullname[_MAX_FNAME+_MAX_EXT];
+
+	if (!basename) return(NULL);
+
+	sprintf(_fullname, "%s.ENG", basename);
+	return(_fullname);
+}
+
+
+/***********************************************************************************************
+ * Source_From_Name -- Converts ASCII name into SourceType.                                    *
+ *                                                                                             *
+ *    This routine is used to convert an ASCII name representing a                             *
+ *    SourceType into the actual SourceType value. Typically, this is                          *
+ *    used when processing the scenario INI file.                                              *
+ *                                                                                             *
+ * INPUT:   name  -- The ASCII source name to process.                                         *
+ *                                                                                             *
+ * OUTPUT:  Returns with the SourceType represented by the name                                *
+ *          specified.                                                                         *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   04/17/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+SourceType Source_From_Name(char const * name)
+{
+	if (name) {
+		for (SourceType source = SOURCE_FIRST; source < SOURCE_COUNT; source++) {
+			if (stricmp(SourceName[source], name) == 0) {
+				return(source);
+			}
+		}
+	}
+	return(SOURCE_NONE);
+}
+
+
+/***********************************************************************************************
+ * Name_From_Source -- retrieves the name for the given SourceType         						  *
+ *                                                                         						  *
+ * INPUT:                                                                  						  *
+ *		source		SourceType to get the name for															  *
+ *                                                                         						  *
+ * OUTPUT:                                                                 						  *
+ *		name of SourceType																							  *
+ *                                                                         						  *
+ * WARNINGS:                                                               						  *
+ *		none.																												  *
+ *                                                                         						  *
+ * HISTORY:                                                                						  *
+ *   11/15/1994 BR : Created.                                              						  *
+ *=============================================================================================*/
+char const * Name_From_Source(SourceType source)
+{
+	if ((unsigned)source < SOURCE_COUNT) {
+		return(SourceName[source]);
+	}
+	return("None");
+}
+
+
+/***********************************************************************************************
+ * Theater_From_Name -- Converts ASCII name into a theater number.                             *
+ *                                                                                             *
+ *    This routine converts an ASCII representation of a theater and converts it into a        *
+ *    matching theater number. If no match was found, then THEATER_NONE is returned.           *
+ *                                                                                             *
+ * INPUT:   name  -- Pointer to ASCII name to convert.                                         *
+ *                                                                                             *
+ * OUTPUT:  Returns with the name converted into a theater number.                             *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   10/01/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+TheaterType Theater_From_Name(char const * name)
+{
+	TheaterType	index;
+
+	if (name) {
+		for (index = THEATER_FIRST; index < THEATER_COUNT; index++) {
+			if (stricmp(name, Theaters[index].Name) == 0) {
+				return(index);
+			}
+		}
+	}
+	return(THEATER_NONE);
+}
+
+
+/***********************************************************************************************
+ * KN_To_Facing -- Converts a keyboard input number into a facing value.                       *
+ *                                                                                             *
+ *    This routine determine which compass direction is represented by the keyboard value      *
+ *    provided. It is used for map scrolling and other directional control operations from     *
+ *    the keyboard.                                                                            *
+ *                                                                                             *
+ * INPUT:   input -- The KN number to convert.                                                 *
+ *                                                                                             *
+ * OUTPUT:  Returns with the facing type that the keyboard number represents. If it could      *
+ *          not be translated, then FACING_NONE is returned.                                   *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/28/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+FacingType KN_To_Facing(int input)
+{
+	input &= ~(KN_ALT_BIT|KN_SHIFT_BIT|KN_CTRL_BIT);
+	switch (input) {
+		case KN_LEFT:
+			return(FACING_W);
+
+		case KN_RIGHT:
+			return(FACING_E);
+
+		case KN_UP:
+			return(FACING_N);
+
+		case KN_DOWN:
+			return(FACING_S);
+
+		case KN_UPLEFT:
+			return(FACING_NW);
+
+		case KN_UPRIGHT:
+			return(FACING_NE);
+
+		case KN_DOWNLEFT:
+			return(FACING_SW);
+
+		case KN_DOWNRIGHT:
+			return(FACING_SE);
+
+		default:
+			break;
+	}
+	return(FACING_NONE);
+}
+
+
+/***********************************************************************************************
+ * Sync_Delay -- Forces the game into a 15 FPS rate.                                           *
+ *                                                                                             *
+ *    This routine will wait until the timer for the current frame has expired before          *
+ *    returning. It is called at the end of every game loop in order to force the game loop    *
+ *    to run at a fixed rate.                                                                  *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   This routine will delay an amount of time according to the game speed setting.  *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   01/04/1995 JLB : Created.                                                                 *
+ *   03/06/1995 JLB : Fixed.                                                                   *
+ *=============================================================================================*/
+static void Sync_Delay(void)
+{
+	/*
+	**	Accumulate the number of 'spare' ticks that are frittered away here.
+	*/
+	SpareTicks += FrameTimer;
+
+	/*
+	**	Delay until the frame timer expires. This forces the game loop to be regulated to a
+	**	speed controlled by the game options slider.
+	*/
+	while (FrameTimer) {
+		Color_Cycle();
+		Call_Back();
+
+		if (SpecialDialog == SDLG_NONE) {
+#ifdef WIN32
+			WWMouse->Erase_Mouse(&HidPage, TRUE);
+#endif	//WIN32
+			KeyNumType input = KN_NONE;
+			int x, y;
+			Map.Input(input, x, y);
+			if (input) {
+				Keyboard_Process(input);
+			}
+			Map.Render();
+		}
+	}
+	Color_Cycle();
+	Call_Back();
+}
+
+
+/***********************************************************************************************
+ * Main_Loop -- This is the main game loop (as a single loop).                                 *
+ *                                                                                             *
+ *    This function will perform one game loop.                                                *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  bool; Should the game end?                                                         *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   10/01/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+#ifdef WIN32
+extern void Check_For_Focus_Loss(void);
+void Reallocate_Big_Shape_Buffer(void);
+#endif	//WIN32
+
+
+bool Main_Loop()
+{
+	KeyNumType	input;					// Player input.
+	int x;
+	int y;
+	int framedelay;
+
+Mono_Set_Cursor(0,0);
+
+	if (!GameActive) return(!GameActive);
+
+#ifdef WIN32
+	/*
+	** Call the focus loss handler
+	*/
+	Check_For_Focus_Loss();
+
+	/*
+	** Allocate extra memory for uncompressed shapes as needed
+	*/
+	Reallocate_Big_Shape_Buffer();
+#endif
+
+	/*
+	** Sync-bug trapping code
+	*/
+	if (Frame >= Session.TrapFrame) {
+		Session.Trap_Object();
+	}
+
+	//
+	// Initialize our AI processing timer
+	//
+	Session.ProcessTimer = TickCount;
+
+#if 1
+	if (Session.TrapCheckHeap) {
+		Debug_Trap_Check_Heap = true;
+	}
+#endif
+
+#ifdef CHEAT_KEYS
+
+	/*
+	**	Update the running status debug display.
+	*/
+	Self_Regulate();
+#endif
+
+	BStart(BENCH_GAME_FRAME);
+
+	/*
+	**	If there is no theme playing, but it looks like one is required, then start one
+	**	playing. This is usually the symptom of there being no transition score.
+	*/
+	if (SampleType && Theme.What_Is_Playing() == THEME_NONE) {
+		Theme.Queue_Song(THEME_PICK_ANOTHER);
+	}
+
+	/*
+	**	Setup the timer so that the Main_Loop function processes at the correct rate.
+	*/
+	if (Session.Type != GAME_NORMAL && Session.Type != GAME_SKIRMISH &&
+		Session.CommProtocol == COMM_PROTOCOL_MULTI_E_COMP) {
+
+		//
+		// In playback mode, run as fast as possible.
+		//
+		if (Session.Play) {
+			FrameTimer = 0;
+		} else {
+#ifdef FIXIT_VERSION_3
+			if( !Session.DesiredFrameRate )
+				Session.DesiredFrameRate = 60;		//	A division by zero was happening (very rare).
+#endif
+			framedelay = TIMER_SECOND / Session.DesiredFrameRate;
+			FrameTimer = framedelay;
+		}
+	} else {
+		if (Options.GameSpeed != 0) {
+			FrameTimer = Options.GameSpeed +
+				(PlayerPtr->Difficulty == DIFF_EASY ? 1 : 0) -
+				(PlayerPtr->Difficulty == DIFF_HARD ? 1 : 0);
+		} else {
+			FrameTimer = Options.GameSpeed + (PlayerPtr->Difficulty == DIFF_EASY ? 1 : 0);
+		}
+	}
+
+	/*
+	**	Update the display, unless we're inside a dialog.
+	*/
+	if (!Session.Play) {
+#ifdef WIN32
+		if (SpecialDialog == SDLG_NONE && GameInFocus) {
+			WWMouse->Erase_Mouse(&HidPage, TRUE);
+#else
+		if (SpecialDialog == SDLG_NONE) {
+#endif
+			Map.Input(input, x, y);
+			if (input) {
+				Keyboard_Process(input);
+			}
+			Map.Render();
+		}
+	}
+
+	/*
+	** Save map's position & selected objects, if we're recording the game.
+	*/
+	if (Session.Record || Session.Play) {
+		Do_Record_Playback();
+	}
+
+#ifndef SORTDRAW
+	/*
+	** Sort the map's ground layer by y-coordinate value.  This is done
+	** outside the IsToRedraw check, for the purposes of game sync'ing
+	** between machines; this way, all machines will sort the Map's
+	** layer in the same way, and any processing done that's based on
+	** the order of this layer will remain in sync.
+	*/
+	DisplayClass::Layer[LAYER_GROUND].Sort();
+#endif
+
+	/*
+	**	AI logic operations are performed here.
+	*/
+	Logic.AI();
+	TimeQuake = false;
+#ifdef FIXIT_CSII	//	checked - ajw 9/28/98
+	if (!PendingTimeQuake) {
+		TimeQuakeCenter = 0;
+	}
+#endif
+
+	/*
+	**	Manage the inter-player message list.  If Manage() returns true, it means
+	**	a message has expired & been removed, and the entire map must be updated.
+	*/
+	if (Session.Messages.Manage()) {
+#ifdef WIN32
+		HiddenPage.Clear();
+#else	//WIN32
+		HidPage.Clear();
+#endif	//WIN32
+		Map.Flag_To_Redraw(true);
+	}
+
+	//
+	// Measure how long it took to process the AI
+	//
+	Session.ProcessTicks += (TickCount - Session.ProcessTimer);
+	Session.ProcessFrames++;
+
+	/*
+	**	Process all commands that are ready to be processed.
+	*/
+	Queue_AI();
+
+	/*
+	**	Keep track of elapsed time in the game.
+	*/
+	Score.ElapsedTime += TIMER_SECOND / TICKS_PER_SECOND;
+
+	Call_Back();
+
+	/*
+	**	Check for player wins or loses according to global event flag.
+	*/
+	if (PlayerWins) {
+
+#ifdef WIN32
+
+		/*
+		** Send the game statistics to WChat.
+		*/
+		if (Session.Type == GAME_INTERNET && !GameStatisticsPacketSent) {
+			Register_Game_End_Time();
+			Send_Statistics_Packet();		//	Player just won.
+		}
+
+		WWMouse->Erase_Mouse(&HidPage, TRUE);
+#endif	//WIN32
+		PlayerLoses = false;
+		PlayerWins = false;
+		PlayerRestarts = false;
+		Map.Help_Text(TXT_NONE);
+		Do_Win();
+		return(!GameActive);
+	}
+	if (PlayerLoses) {
+#ifdef WIN32
+		/*
+		** Send the game statistics to WChat.
+		*/
+		if (Session.Type == GAME_INTERNET && !GameStatisticsPacketSent) {
+			Register_Game_End_Time();
+			Send_Statistics_Packet();		//	Player just lost.
+		}
+
+		WWMouse->Erase_Mouse(&HidPage, TRUE);
+#endif	//WIN32
+		PlayerWins = false;
+		PlayerLoses = false;
+		PlayerRestarts = false;
+		Map.Help_Text(TXT_NONE);
+		Do_Lose();
+		return(!GameActive);
+	}
+	if (PlayerRestarts) {
+#ifdef WIN32
+		WWMouse->Erase_Mouse(&HidPage, TRUE);
+#endif	//WIN32
+		PlayerWins = false;
+		PlayerLoses = false;
+		PlayerRestarts = false;
+		Map.Help_Text(TXT_NONE);
+		Do_Restart();
+		return(!GameActive);
+	}
+
+#ifdef FIXIT_VERSION_3		//	Stalemate games.
+	if( Session.Type != GAME_NORMAL && Session.Type != GAME_SKIRMISH && Session.Players.Count() == 2 &&
+		Scen.bLocalProposesDraw && Scen.bOtherProposesDraw )
+	{
+		//	End game in a draw.
+		if (Session.Type == GAME_INTERNET && !GameStatisticsPacketSent) {
+			Register_Game_End_Time();
+			Send_Statistics_Packet();
+		}
+		WWMouse->Erase_Mouse(&HidPage, TRUE);
+		Map.Help_Text(TXT_NONE);
+		Do_Draw();
+		return(!GameActive);
+	}
+#endif
+
+	/*
+	**	The frame logic has been completed. Increment the frame
+	**	counter.
+	*/
+	Frame++;
+
+	/*
+	** Is there a memory trasher altering the map??
+	*/
+	if (Debug_Check_Map) {
+		if (!Map.Validate()) {
+			if (WWMessageBox().Process (TEXT_MAP_ERROR, TEXT_STOP, TEXT_CONTINUE)==0) {
+				GameActive = 0;
+			}
+			Map.Validate();		// give debugger a chance to catch it
+		}
+	}
+
+
+
+#ifdef WIN32
+	if (Debug_MotionCapture) {
+		static void ** _array = 0;
+		static int _sequence = 0;
+		static int _seqsize = Rule.MovieTime * TICKS_PER_MINUTE;
+
+		if (_array == NULL) {
+			_array = new void * [_seqsize];
+			memset(_array, '\0', _seqsize * sizeof(void*));
+		}
+
+		if (_array == NULL) {
+			Debug_MotionCapture = false;
+		}
+
+		static GraphicBufferClass temp_page(	SeenBuff.Get_Width(),
+													SeenBuff.Get_Height(),
+													NULL,
+													SeenBuff.Get_Width() * SeenBuff.Get_Height());
+
+		int size = SeenBuff.Get_Width() * SeenBuff.Get_Height();
+
+		if (_sequence < _seqsize) {
+			if (_array[_sequence] == NULL) {
+				_array[_sequence] = new char[size];
+			}
+
+			if (_array[_sequence] != NULL) {
+				SeenBuff.Blit(temp_page);
+				memmove(_array[_sequence], temp_page.Get_Buffer(), size);
+			}
+			_sequence++;
+
+		} else {
+			Debug_MotionCapture = false;
+
+			CDFileClass file;
+			file.Cache(200000);
+			char filename[30];
+
+			for (int index = 0; index < _sequence; index++) {
+				memmove(temp_page.Get_Buffer(), _array[index], size);
+				sprintf(filename, "cap%04d.pcx", index);
+				file.Set_Name(filename);
+
+				Write_PCX_File(file, temp_page, & GamePalette);
+			}
+
+			_sequence = 0;
+		}
+	}
+#endif
+
+	BEnd(BENCH_GAME_FRAME);
+
+	Sync_Delay();
+	return(!GameActive);
+}
+
+
+#ifdef SCENARIO_EDITOR
+/***************************************************************************
+ * Map_Edit_Loop -- a mini-main loop for map edit mode only                *
+ *                                                                         *
+ * INPUT:                                                                  *
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   10/19/1994 BR : Created.                                              *
+ *=========================================================================*/
+bool Map_Edit_Loop(void)
+{
+	/*
+	**	Redraw the map.
+	*/
+	Map.Render();
+
+	/*
+	**	Get user input (keys, mouse clicks).
+	*/
+	KeyNumType input;
+
+#ifdef WIN32
+	WWMouse->Erase_Mouse(&HidPage, TRUE);
+#endif	//WIN32
+
+	int x;
+	int y;
+	Map.Input(input, x, y);
+
+	/*
+	**	Process keypress.
+	*/
+	if (input) {
+		Keyboard_Process(input);
+	}
+
+	Call_Back();								// maintains Theme.AI() for music
+	Color_Cycle();
+
+	return(!GameActive);
+}
+
+
+/***************************************************************************
+ * Go_Editor -- Enables/disables the map editor										*
+ *                                                                         *
+ * INPUT:                                                                  *
+ *		flag		true = go into editor mode; false = go into game mode			*
+ *                                                                         *
+ * OUTPUT:                                                                 *
+ *		none.																						*
+ *                                                                         *
+ * WARNINGS:                                                               *
+ *		none.																						*
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   10/19/1994 BR : Created.                                              *
+ *=========================================================================*/
+void Go_Editor(bool flag)
+{
+	/*
+	**	Go into Scenario Editor mode
+	*/
+	if (flag) {
+		Debug_Map = true;
+		Debug_Unshroud = true;
+
+		/*
+		** Un-select any selected objects
+		*/
+		Unselect_All();
+
+		/*
+		** Turn off the sidebar if it's on
+		*/
+		Map.Activate(0);
+
+		/*
+		** Reset the map's Button list for the new mode
+		*/
+		Map.Init_IO();
+
+		/*
+		** Force a complete redraw of the screen
+		*/
+#ifdef WIN32
+		HiddenPage.Clear();
+#else
+		HidPage.Clear();
+#endif
+		Map.Flag_To_Redraw(true);
+		Map.Render();
+
+	} else {
+
+		/*
+		**	Go into normal game mode
+		*/
+		Debug_Map = false;
+		Debug_Unshroud = false;
+
+		/*
+		** Un-select any selected objects
+		*/
+		Unselect_All();
+
+		/*
+		** Reset the map's Button list for the new mode
+		*/
+		Map.Init_IO();
+
+		/*
+		** Force a complete redraw of the screen
+		*/
+		HidPage.Clear();
+		Map.Flag_To_Redraw(true);
+		Map.Render();
+	}
+}
+
+#endif
+
+
+/***********************************************************************************************
+ * MixFileHandler -- Handles VQ file access.                                                   *
+ *                                                                                             *
+ *    This routine is called from the VQ player when it needs to access the source file. By    *
+ *    using this routine it is possible to virtualize the file system.                         *
+ *                                                                                             *
+ * INPUT:   vqa   -- Pointer to the VQA handle for this animation.                             *
+ *                                                                                             *
+ *          action-- The requested action to perform.                                          *
+ *                                                                                             *
+ *          buffer-- Optional buffer pointer as needed by the type of action.                  *
+ *                                                                                             *
+ *          nbytes-- The number of bytes (if needed) for this operation.                       *
+ *                                                                                             *
+ * OUTPUT:  Returns a value consistent with the action requested.                              *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/04/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+long MixFileHandler(VQAHandle * vqa, long action, void * buffer, long nbytes)
+{
+	CCFileClass * file;
+	long        error;
+
+	file = (CCFileClass *)vqa->VQAio;
+
+	/*
+	**	Perform the action specified by the stream command.
+	*/
+	switch (action) {
+
+		/*
+		** VQACMD_READ means read NBytes from the stream and place it in the
+		** memory pointed to by Buffer.
+		**
+		** Any error code returned will be remapped by VQA library into
+		** VQAERR_READ.
+		*/
+		case VQACMD_READ:
+			error = (file->Read(buffer, (unsigned short)nbytes) != (unsigned short)nbytes);
+			break;
+
+		/*
+		**	VQACMD_WRITE is analogous to VQACMD_READ.
+		**
+		** Writing is not allowed to the VQA file, VQA library will remap the
+		** error into VQAERR_WRITE.
+		*/
+		case VQACMD_WRITE:
+			error = 1;
+			break;
+
+		/*
+		**	VQACMD_SEEK asks that you perform a seek relative to the current
+		** position. NBytes is a signed number, indicating seek direction
+		** (positive for forward, negative for backward). Buffer has no meaning
+		** here.
+		**
+		** Any error code returned will be remapped by VQA library into
+		** VQAERR_SEEK.
+		*/
+		case VQACMD_SEEK:
+			error = (file->Seek(nbytes, SEEK_CUR) == -1);
+			break;
+
+		/*
+		**	VQACMD_OPEN asks that you open your stream for access.
+		*/
+		case VQACMD_OPEN:
+			file = new CCFileClass((char *)buffer);
+
+			if (file != NULL && file->Is_Available()) {
+				error = file->Open((char *)buffer, READ);
+
+				if (error != -1) {
+					vqa->VQAio = (unsigned long)file;
+					error = 0;
+				} else {
+					delete file;
+					file = 0;
+					error = 1;
+				}
+			} else {
+				error = 1;
+			}
+			break;
+
+		case VQACMD_CLOSE:
+			file->Close();
+			delete file;
+			file = 0;
+			vqa->VQAio = 0;
+			error = 0;
+			break;
+
+		/*
+		**	VQACMD_INIT means to prepare your stream for reading. This is used for
+		** certain streams that can't be read immediately upon opening, and need
+		** further preparation. This operation is allowed to fail; the error code
+		** will be returned directly to the client.
+		*/
+		case VQACMD_INIT:
+
+		/*
+		**	IFFCMD_CLEANUP means to terminate the transaction with the associated
+		** stream. This is used for streams that can't simply be closed. This
+		** operation is not allowed to fail; any error returned will be ignored.
+		*/
+		case VQACMD_CLEANUP:
+			error = 0;
+			break;
+
+		default:
+			error = 0;
+			break;
+	}
+
+	return(error);
+}
+
+
+void Rebuild_Interpolated_Palette(unsigned char * interpal)
+{
+	for (int y=0; y<255; y++) {
+		for (int x=y+1; x<256; x++) {
+			*(interpal + (y*256+x)) = *(interpal + (x*256+y));
+		}
+	}
+}
+
+
+unsigned char 	* InterpolatedPalettes[100];
+BOOL				PalettesRead;
+unsigned			PaletteCounter;
+
+
+/***********************************************************************************************
+ * Load_Interpolated_Palettes -- Loads in any precalculated palettes for hires VQs             *
+ *                                                                                             *
+ *                                                                                             *
+ *                                                                                             *
+ * INPUT:    Name of palette file                                                              *
+ *                                                                                             *
+ * OUTPUT:   Number of palettes loaded                                                         *
+ *                                                                                             *
+ * WARNINGS: None                                                                              *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *    5/7/96 9:49AM ST : Created                                                               *
+ *=============================================================================================*/
+int Load_Interpolated_Palettes(char const * filename, BOOL add)
+{
+	int	num_palettes=0;
+	int	i;
+	int 	start_palette;
+
+	PalettesRead = FALSE;
+	CCFileClass	file(filename);
+
+	if (!add) {
+		for (i=0; i < ARRAY_SIZE(InterpolatedPalettes); i++) {
+			InterpolatedPalettes[i]=NULL;
+		}
+		start_palette=0;
+	} else {
+		for (start_palette = 0; start_palette < ARRAY_SIZE(InterpolatedPalettes); start_palette++) {
+			if (!InterpolatedPalettes[start_palette]) break;
+		}
+	}
+
+	/*
+	**	Hack another interpolated palette if the requested one is
+	**	not present.
+	*/
+	if (!file.Is_Available()) {
+		file.Set_Name("AAGUN.VQP");
+	}
+
+	if (file.Is_Available()) {
+
+		file.Open(READ);
+		file.Read(&num_palettes , 4);
+
+		for (i=0; i < num_palettes; i++) {
+			InterpolatedPalettes[i+start_palette] = (unsigned char *)malloc (65536);
+			memset (InterpolatedPalettes[i+start_palette], 0, 65536);
+			for (int y = 0; y < 256; y++) {
+				file.Read (InterpolatedPalettes[i+start_palette] + y*256 , y+1);
+			}
+
+			Rebuild_Interpolated_Palette(InterpolatedPalettes[i+start_palette]);
+		}
+
+		PalettesRead = TRUE;
+		file.Close();
+	}
+	PaletteCounter = 0;
+	return (num_palettes);
+}
+
+
+void Free_Interpolated_Palettes(void)
+{
+	for (int i = 0; i < ARRAY_SIZE(InterpolatedPalettes) ;i++) {
+		if (InterpolatedPalettes[i]) {
+			free(InterpolatedPalettes[i]);
+			InterpolatedPalettes[i]=NULL;
+		}
+	}
+}
+
+
+/***********************************************************************************************
+ * Play_Movie -- Plays a VQ movie.                                                             *
+ *                                                                                             *
+ *    Use this routine to play a VQ movie. It will dispatch the specified movie to the         *
+ *    VQ player. The routine will not return until the movie has finished playing.             *
+ *                                                                                             *
+ * INPUT:   name  -- The name of the movie file (sans ".VQA").                                 *
+ *                                                                                             *
+ *          theme -- The identifier for an optional theme that should be played in the         *
+ *                   background while this VQ plays.                                           *
+ *                                                                                             *
+ *          clrscrn -- 'true' if to clear the screen when the movie is over                    *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   12/19/1994 JLB : Created.                                                                 *
+ *=============================================================================================*/
+#ifdef WIN32
+extern void Suspend_Audio_Thread(void);
+extern void Resume_Audio_Thread(void);
+
+#ifdef MOVIE640
+extern GraphicBufferClass VQ640;
+#endif
+#endif
+void Play_Movie(char const * name, ThemeType theme, bool clrscrn)
+	{
+	#ifdef MPEGMOVIE
+	//theme = theme;
+	//clrscrn = clrscrn;
+	if( Using_DVD() )
+	{
+		if (PlayMpegMovie(name))
+			return;
+	}
+	#endif
+
+	#ifdef CHEAT_KEYS
+	//	Mono_Printf("Movie: %s\n", name);
+	#endif	//CHEAT_KEYS
+	/*
+	** Don't play movies in editor mode
+	*/
+	if (Debug_Map) {
+		return;
+	}
+	#ifdef CHEAT_KEYS
+	//	Mono_Printf("A\n");
+	#endif	//CHEAT_KEYS
+	/*
+	** Don't play movies in multiplayer mode
+	*/
+	if (Session.Type != GAME_NORMAL) {
+		return;
+	}
+	#ifdef CHEAT_KEYS
+	//Mono_Printf("b\n");
+	#endif	//CHEAT_KEYS
+
+	if (name) {
+		char fullname[_MAX_FNAME+_MAX_EXT];
+		_makepath(fullname, NULL, NULL, name, ".VQA");
+		#ifdef WIN32
+		char palname [_MAX_FNAME+_MAX_EXT];
+		_makepath(palname , NULL, NULL, name, ".VQP");
+		#endif	//WIN32
+		#ifdef CHEAT_KEYS
+		//			Mono_Set_Cursor(0, 0);Mono_Printf("[%s]", fullname);
+		#endif
+
+		if (!CCFileClass(fullname).Is_Available()){
+			#ifdef CHEAT_KEYS
+			//		 Mono_Printf("fullname: %s\n", fullname);
+			#endif	//CHEAT_KEYS
+		 return;
+		}
+		/*
+		**	Reset the anim control structure.
+		*/
+		Anim_Init();
+
+		/*
+		**	Prepare to play a movie. First hide the mouse and stop any score that is playing.
+		**	While the score (if any) is fading to silence, fade the palette to black as well.
+		**	When the palette has finished fading, wait until the score has finished fading
+		**	before launching the movie.
+		*/
+		Hide_Mouse();
+		Theme.Queue_Song(theme);
+		if (PreserveVQAScreen == 0 && !clrscrn) {
+			BlackPalette.Set(FADE_PALETTE_MEDIUM);
+			VisiblePage.Clear();
+			BlackPalette.Adjust(0x08, WhitePalette);
+			BlackPalette.Set();
+			BlackPalette.Adjust(0xFF);
+			BlackPalette.Set();
+		}
+		PreserveVQAScreen = 0;
+		Keyboard->Clear();
+
+		VQAHandle * vqa = NULL;
+
+
+		#ifdef WIN32
+		#ifdef MOVIE640
+		if(IsVQ640) {
+			AnimControl.ImageWidth = 640;
+			AnimControl.ImageHeight = 400;
+			AnimControl.ImageBuf = (unsigned char *)VQ640.Get_Offset();
+		} else {
+			AnimControl.ImageWidth = 320;
+			AnimControl.ImageHeight = 200;
+			AnimControl.ImageBuf = (unsigned char *)SysMemPage.Get_Offset();
+		}
+		#endif
+		#endif
+
+		if (!Debug_Quiet && Get_Digi_Handle() != -1) {
+			AnimControl.OptionFlags |= VQAOPTF_AUDIO;
+		} else {
+			AnimControl.OptionFlags &= ~VQAOPTF_AUDIO;
+		}
+
+		if ((vqa = VQA_Alloc()) != NULL) {
+			VQA_Init(vqa, MixFileHandler);
+
+			if (VQA_Open(vqa, fullname, &AnimControl) == 0) {
+				Brokeout = false;
+				#ifdef WIN32
+				//Suspend_Audio_Thread();
+				#ifdef MOVIE640
+				if(!IsVQ640) {
+					Load_Interpolated_Palettes(palname);
+				}
+				#else
+				Load_Interpolated_Palettes(palname);
+				#endif
+				//Set_Palette(BlackPalette);
+				SysMemPage.Clear();
+				InMovie = true;
+				#endif	//WIN32
+				VQA_Play(vqa, VQAMODE_RUN);
+				VQA_Close(vqa);
+				#ifdef WIN32
+				//Resume_Audio_Thread();
+				InMovie = FALSE;
+				#ifdef MOVIE640
+				if(!IsVQ640) {
+					Free_Interpolated_Palettes();
+				}
+				#else
+				Free_Interpolated_Palettes();
+				#endif
+				IsVQ640 = false;
+				Set_Primary_Buffer_Format();
+				#endif	//WIN32
+
+				/*
+				**	Any movie that ends prematurely must have the screen
+				**	cleared to avoid any unexpected palette glitches.
+				*/
+				if (Brokeout) {
+					clrscrn = true;
+					VisiblePage.Clear();
+					Brokeout = false;
+				}
+			} else {
+				#ifndef NDEBUG
+				bool error = true;
+				assert(error);
+				#endif
+			}
+
+			VQA_Free(vqa);
+		} else {
+			assert(vqa != NULL);
+		}
+		#ifdef CHEAT_KEYS
+		//Mono_Printf("d");
+		#endif	//CHEAT_KEYS
+		/*
+		**	Presume that the screen is left in a garbage state as well as the palette
+		**	being in an unknown condition. Recover from this by clearing the screen and
+		**	forcing the palette to black.
+		*/
+		if (clrscrn) {
+			VisiblePage.Clear();
+			BlackPalette.Adjust(0x08, WhitePalette);
+			BlackPalette.Set();
+			BlackPalette.Adjust(0xFF);
+			BlackPalette.Set();
+		}
+		Show_Mouse();
+	}
+}
+
+
+void Play_Movie(VQType name, ThemeType theme, bool clrscrn)
+{
+	if (name != VQ_NONE) {
+		if (name == VQ_REDINTRO) {
+			IsVQ640 = true;
+		}
+		Play_Movie(VQName[name], theme, clrscrn);
+		IsVQ640 = false;
+	}
+}
+
+
+// Denzil 5/18/98 - Mpeg movie playback
+#ifdef MPEGMOVIE
+extern LPDIRECTDRAWPALETTE PalettePtr;
+
+bool PlayMpegMovie(const char* name)
+	{
+	char path[MAX_PATH];
+	CCFileClass file;
+	const char* filename;
+
+#ifdef CHEAT_KEYS
+	if( bNoMovies )
+		return true;
+#endif
+
+	sprintf(path, "movies\\%.8s.%.3s", name, "mpg");
+	filename = file.Set_Name(path);
+	
+	if (!file.Is_Available())
+		{
+		#if(1)
+		VisiblePage.Clear();
+		GamePalette.Set();
+		Show_Mouse();
+		sprintf(path, "Couldn't find %s\n", filename);
+		WWMessageBox().Process(path);
+		#endif
+		return false;
+		}
+
+	// Stop theme music
+	if (Misc_Focus_Loss_Function)
+		Misc_Focus_Loss_Function();
+
+	// Release primary surface
+	VisiblePage.Un_Init();
+
+	#ifdef MCIMPEG
+	if (MciMovie && MpgSettings && (MpgSettings->GetDeviceName() != NULL))
+		{
+		DirectDrawObject->SetCooperativeLevel(MainWindow, DDSCL_NORMAL);
+
+		if (!MciMovie->Open(filename, MpgSettings->GetDeviceName()))
+			{
+			WWMessageBox().Process("Couldn't open movie.\n");
+			}
+		else if (!MciMovie->Play(MainWindow))
+			{
+			WWMessageBox().Process("Couldn't play movie.\n");
+			}
+
+		DirectDrawObject->SetCooperativeLevel(MainWindow, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
+		}
+	else
+	#endif
+		{
+		DDSURFACEDESC ddsd;
+		IDirectDrawSurface* primary = NULL;
+		bool modeChange = false;
+		RECT rect;
+	
+		if (FAILED(DirectDrawObject->SetDisplayMode(ScreenWidth, ScreenHeight, 16)))
+			{
+			WWMessageBox().Process("Couldn't change display mode.\n");
+			}
+		else
+			{
+			// Create primary surface reference
+			memset(&ddsd, 0, sizeof(ddsd));
+			ddsd.dwSize = sizeof(ddsd);
+			ddsd.dwFlags = DDSD_CAPS;
+			ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+
+			if (FAILED(DirectDrawObject->CreateSurface(&ddsd, &primary, NULL)))
+				{
+				WWMessageBox().Process("Couldn't create primary movie surface.\n");
+				}
+			else
+				{
+				rect.top = rect.left = 0;
+				rect.bottom = ScreenHeight;
+				rect.right = ScreenWidth;
+		
+				MpgSetCallback(MpegCallback, NULL);
+				MpgPlay(filename, DirectDrawObject, primary, &rect);
+
+				if (primary)
+					primary->Release();
+
+				}
+
+			DirectDrawObject->SetDisplayMode(ScreenWidth, ScreenHeight, 8);
+			}
+		}
+
+	// Restore surfaces
+	VisiblePage.Init(ScreenWidth, ScreenHeight, NULL, 0, (GBC_Enum)(GBC_VISIBLE|GBC_VIDEOMEM));
+	PaletteSurface->SetPalette(PalettePtr);
+	AllSurfaces.Set_Surface_Focus(true);
+	AllSurfaces.Restore_Surfaces();
+	return true;
+	}
+
+
+MPG_RESPONSE far __stdcall MpegCallback(MPG_CMD cmd, LPVOID data, LPVOID user)
+	{
+	static IDirectDrawPalette* _palette = NULL;
+
+	user = user;
+
+	switch (cmd)
+		{
+		case MPGCMD_ERROR:
+			WWMessageBox().Process((char const *)data);
+		break;
+
+		case MPGCMD_INIT:
+			VisiblePage.Clear();
+		break;
+
+		case MPGCMD_CLEANUP:
+			VisiblePage.Clear();
+
+			if (_palette != NULL)
+				{
+				PaletteSurface->SetPalette(_palette);
+				_palette->Release();
+				_palette = NULL;
+				}
+		break;
+		
+		case MPGCMD_PALETTE:
+			if (FAILED(PaletteSurface->GetPalette(&_palette)))
+				{
+				WWMessageBox().Process("Couldn't get primary palette.\n");
+				}
+			else
+				{
+				if (FAILED(PaletteSurface->SetPalette((IDirectDrawPalette*)data)))
+					{
+					WWMessageBox().Process("Couldn't set movie palette.\n");
+					}
+				}
+		break;
+		
+		case MPGCMD_UPDATE:
+			if ((BreakoutAllowed || Debug_Flag) && Keyboard->Check())
+				{
+				if (Keyboard->Get() == KN_ESC)
+					{
+					Keyboard->Clear();
+					return MPGRES_QUIT;
+					}
+
+				Keyboard->Clear();
+				}
+
+			if (!GameInFocus)
+				{
+				MpgPause();
+
+				while (!GameInFocus)
+					{
+					Check_For_Focus_Loss();
+					}
+
+				MpgResume();
+				return MPGRES_LOSTFOCUS;
+				}
+		break;
+
+		default:
+		break;
+		}
+
+	return MPGRES_CONTINUE;
+	}
+#endif
+
+/***********************************************************************************************
+ * Unselect_All -- Causes all selected objects to become unselected.                           *
+ *                                                                                             *
+ *    This routine will unselect all objects that are currently selected.                      *
+ *                                                                                             *
+ * INPUT:   none                                                                               *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   01/19/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void Unselect_All(void)
+{
+	while (CurrentObject.Count()) {
+		CurrentObject[0]->Unselect();
+	}
+}
+
+
+/***********************************************************************************************
+ * Fading_Table_Name -- Builds a theater specific fading table name.                           *
+ *                                                                                             *
+ *    This routine builds a standard fading table name. This name is dependant on the theater  *
+ *    being played, since each theater has its own palette.                                    *
+ *                                                                                             *
+ * INPUT:   base  -- The base name of this fading table. The base name can be no longer than   *
+ *                   seven characters.                                                         *
+ *                                                                                             *
+ *          theater  -- The theater that this fading table is specific to.                     *
+ *                                                                                             *
+ * OUTPUT:  Returns with a pointer to the constructed fading table filename. This pointer is   *
+ *          valid until this function is called again.                                         *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   01/19/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+char const * Fading_Table_Name(char const * base, TheaterType theater)
+{
+	static char _buffer[_MAX_FNAME+_MAX_EXT];
+	char root[_MAX_FNAME];
+
+	sprintf(root, "%1.1s%s", Theaters[theater].Root, base);
+	_makepath(_buffer, NULL, NULL, root, ".MRF");
+	return(_buffer);
+}
+
+
+/***********************************************************************************************
+ * Get_Radar_Icon -- Builds and alloc a radar icon from a shape file                           *
+ *                                                                                             *
+ * INPUT:      void const * shapefile - pointer to a key framed shapefile                      *
+ *             int shapenum          - shape to extract from shapefile                         *
+ *                                                                                             *
+ * OUTPUT:     void const *           - 3/3 icon set of shape from file                        *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   04/12/1995 PWG : Created.                                                                 *
+ *   05/10/1995 JLB : Handles a null shapefile pointer.                                        *
+ *=============================================================================================*/
+void const * Get_Radar_Icon(void const * shapefile, int shapenum, int frames, int zoomfactor)
+{
+	static int _offx[]={	0, 0,  -1,  1, 0, -1, 1, -1, 1};
+	static int _offy[]={	0, 0,  -1,  1, 0, -1, 1, -1, 1};
+	int lp,framelp;
+	char pixel;
+
+	char * retval = NULL;
+	char * buffer = NULL;
+
+	/*
+	**	If there is no shape file, then there can be no radar icon imagery.
+	*/
+	if (!shapefile) return(NULL);
+
+#if (0)
+	CCPalette.Set();
+	Set_Logic_Page(SeenBuff);
+	CC_Draw_Shape(shapefile, shapenum, 64, 64, WINDOW_MAIN, SHAPE_WIN_REL);
+#endif
+
+	/*
+	** Get the pixel width and height of the frame we built.  This will
+	** be used to extract icons and build pixels.
+	*/
+	int pixel_width  = Get_Build_Frame_Width( shapefile );
+	int pixel_height = Get_Build_Frame_Height( shapefile );
+
+	/*
+	** Find the width and height in icons, adjust these by half an
+	** icon because the artists may be sloppy and miss the edge of an
+	** icon one way or the other.
+	*/
+	int icon_width	 = (pixel_width + 12) / 24;
+	int icon_height = (pixel_height + 12) / 24;
+
+	/*
+	** If we have been told to build as many frames as possible, then
+	** find out how many frames there are to build.
+	*/
+	if (frames == -1) frames = Get_Build_Frame_Count( shapefile );
+
+	/*
+	** Allocate a position to store our icons.  If the alloc fails then
+	** we don't add these icons to the set.
+	**/
+	buffer = new char[(icon_width * icon_height * 9 * frames)+2];
+	if (!buffer) return(NULL);
+
+	/*
+	** Save off the return value so that we can return it to the calling
+	** function.
+	*/
+	retval	 = (char *)buffer;
+	*buffer++ = (char)icon_width;
+	*buffer++ = (char)icon_height;
+	int val = 24/zoomfactor;
+
+	for (framelp = 0; framelp < frames; framelp ++) {
+		/*
+		** Build the current frame.  If the frame can not be built then we
+		** just need to skip past this set of icons and try to build the
+		** next frame.
+		*/
+#ifdef WIN32
+		void * ptr;
+		if ((ptr = (void *)(Build_Frame(shapefile, shapenum + framelp, SysMemPage.Get_Buffer()))) != NULL) {
+			ptr = Get_Shape_Header_Data(ptr);
+#else	//WIN#@
+		if (Build_Frame(shapefile, shapenum + framelp, HidPage.Get_Buffer()) <= (unsigned long)HidPage.Get_Size() ) {
+#endif	//WIN32
+
+			/*
+			** Loop through the icon width and the icon height building icons
+			** into the buffer pointer.  When the getx or gety falls outside of
+			** the width and height of the shape, just insert transparent pixels.
+			*/
+			for (int icony = 0; icony < icon_height; icony ++) {
+				for (int iconx = 0; iconx < icon_width; iconx ++) {
+#ifdef WIN32
+
+					for (int y = 0; y < zoomfactor; y++) {
+						for (int x = 0; x < zoomfactor; x++) {
+							int getx = (iconx * 24) + (x * val) + (zoomfactor / 2);
+							int gety = (icony * 24) + (y * val) + (zoomfactor / 2);
+							if ((getx < pixel_width) && (gety < pixel_height)) {
+								for (lp = 0; lp < 9; lp ++) {
+									pixel	= *(char *)((char *)ptr + ((gety - _offy[lp]) * pixel_width) + getx-_offx[lp]);
+
+#else	//WIN32
+					for (int y = 0; y < 3; y++) {
+						for (int x = 0; x < 3; x++) {
+							int getx = (iconx * 24) + (x << 3) + 4;
+							int gety = (icony * 24) + (y << 3) + 4;
+							if ((getx < pixel_width) && (gety < pixel_height)) {
+								for (lp = 0; lp < 9; lp ++) {
+									pixel	= *(char *)((char *)HidPage.Get_Buffer(), ((gety - _offy[lp]) * pixel_width) + getx-_offx[lp]);
+#endif	//WIN32
+									if (pixel == LTGREEN) pixel = 0;
+									if (pixel) {
+										break;
+									}
+								}
+								*buffer++ = pixel;
+							} else {
+								*buffer++ = 0;
+							}
+						}
+					}
+				}
+			}
+		} else {
+			buffer += icon_width * icon_height * 9;
+		}
+	}
+	return(retval);
+}
+
+
+/***********************************************************************************************
+ * CC_Draw_Shape -- Custom draw shape handler.                                                 *
+ *                                                                                             *
+ *    All draw shape calls will route through this function. It handles all draws for          *
+ *    C&C. Such draws always occur to the logical page and assume certain things about         *
+ *    the parameters passed.                                                                   *
+ *                                                                                             *
+ * INPUT:   shapefile   -- Pointer to the shape data file. This data file contains all the     *
+ *                         embedded shapes.                                                    *
+ *                                                                                             *
+ *          shapenum    -- The shape number within the shapefile that will be drawn.           *
+ *                                                                                             *
+ *          x,y         -- The pixel coordinates to draw the shape.                            *
+ *                                                                                             *
+ *          window      -- The clipping window to use.                                         *
+ *                                                                                             *
+ *          flags       -- The custom draw shape flags. This controls how the parameters       *
+ *                         are used (if any).                                                  *
+ *                                                                                             *
+ *          fadingdata  -- If SHAPE_FADING is desired, then this points to the fading          *
+ *                         data table.                                                         *
+ *                                                                                             *
+ *          ghostdata   -- If SHAPE_GHOST is desired, then this points to the ghost remap      *
+ *                         table.                                                              *
+ *                                                                                             *
+ *          rotation    -- Rotation to apply to the shape (DIR_N = no rotation at all).        *
+ *                                                                                             *
+ *          scale       -- 24.8 fixed point scale factor.                                      *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   02/21/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void CC_Draw_Shape(void const * shapefile, int shapenum, int x, int y, WindowNumberType window, ShapeFlags_Type flags, void const * fadingdata, void const * ghostdata, DirType rotation, long scale)
+{
+	int predoffset;
+#ifdef WIN32
+	unsigned	long	shape_pointer;
+#endif	//WIN32
+
+
+	/*
+	** Special kludge for E3 to prevent crashes
+	*/
+	if ((flags & SHAPE_GHOST) && (!ghostdata)) {
+		ghostdata = DisplayClass::SpecialGhost;
+	}
+	if ((flags & SHAPE_FADING) && (!fadingdata)) {
+		fadingdata = DisplayClass::FadingShade;
+	}
+
+	static unsigned char * _xbuffer = 0;
+
+	if (!_xbuffer) {
+		_xbuffer = new unsigned char[SHAPE_BUFFER_SIZE];
+	}
+
+	if (shapefile != NULL && shapenum != -1) {
+
+		int width = Get_Build_Frame_Width(shapefile);
+		int height = Get_Build_Frame_Height(shapefile);
+
+#ifdef NEVER
+		/*
+		**	Perform a quick clip check against the destination rectangle.
+		*/
+		if (flags & SHAPE_CENTER) {
+			if (x-width/2 >= WindowList[window][WINDOWWIDTH]) return;
+			if (y-width/2 >= WindowList[window][WINDOWHEIGHT]) return;
+			if (x+width/2 < 0) return;
+			if (y+height/2 < 0) return;
+
+		} else {
+			if (x >= WindowList[window][WINDOWWIDTH]) return;
+			if (y >= WindowList[window][WINDOWHEIGHT]) return;
+			if (x+width < 0) return;
+			if (y+height < 0) return;
+		}
+#endif
+
+
+#ifdef WIN32
+		/*
+		** In WIn95, build shape returns a pointer to the shape not its size
+		*/
+		shape_pointer = Build_Frame(shapefile, shapenum, _ShapeBuffer);
+		if (shape_pointer) {
+			GraphicViewPortClass draw_window(LogicPage->Get_Graphic_Buffer(),
+														WindowList[window][WINDOWX] + LogicPage->Get_XPos(),
+														WindowList[window][WINDOWY] + LogicPage->Get_YPos(),
+														WindowList[window][WINDOWWIDTH],
+														WindowList[window][WINDOWHEIGHT]);
+			unsigned char * buffer = (unsigned char *) shape_pointer;	//Get_Shape_Header_Data((void*)shape_pointer);
+
+#else	//WIN32
+		if ( Build_Frame(shapefile, shapenum, _ShapeBuffer ) <= (unsigned long)_ShapeBufferSize) {
+			GraphicViewPortClass draw_window(LogicPage,
+														WindowList[window][WINDOWX],
+														WindowList[window][WINDOWY],
+														WindowList[window][WINDOWWIDTH],
+														WindowList[window][WINDOWHEIGHT]);
+			unsigned char * buffer = (unsigned char *)_ShapeBuffer;
+#endif	//WIN32
+
+			UseOldShapeDraw = false;
+			/*
+			**	Rotation and scale handler.
+			*/
+			if (rotation != DIR_N || scale != 0x0100) {
+
+				/*
+				** Get the raw shape data without the new header and flag to use the old shape drawing
+				*/
+				UseOldShapeDraw = true;
+#ifdef WIN32
+				buffer = (unsigned char *) Get_Shape_Header_Data((void*)shape_pointer);
+#endif
+
+				if (Debug_Rotate) {
+
+					GraphicBufferClass src(width, height, buffer);
+					width *= 2;
+					height *= 2;
+					memset(_xbuffer, '\0', SHAPE_BUFFER_SIZE);
+					GraphicBufferClass dst(width, height, _xbuffer);
+					Rotate_Bitmap(&src, &dst, rotation);
+					buffer = _xbuffer;
+
+				} else {
+
+					BitmapClass bm(width, height, buffer);
+					width *= 2;
+					height *= 2;
+					memset(_xbuffer, '\0', SHAPE_BUFFER_SIZE);
+					GraphicBufferClass gb(width, height, _xbuffer);
+					TPoint2D pt(width/2, height/2);
+
+					gb.Scale_Rotate(bm, pt, scale, (256-(rotation-64)));
+					buffer = _xbuffer;
+				}
+			}
+
+			/*
+			**	Special shadow drawing code (used for aircraft and bullets).
+			*/
+			if ((flags & (SHAPE_FADING|SHAPE_PREDATOR)) == (SHAPE_FADING|SHAPE_PREDATOR)) {
+				flags = flags & ~(SHAPE_FADING|SHAPE_PREDATOR);
+				flags = flags | SHAPE_GHOST;
+				ghostdata = DisplayClass::SpecialGhost;
+			}
+
+			predoffset = Frame;
+
+			if (x > ( WindowList[window][WINDOWWIDTH] << 2)) {
+				predoffset = -predoffset;
+			}
+
+			if (draw_window.Lock()) {
+				if ((flags & (SHAPE_GHOST|SHAPE_FADING)) == (SHAPE_GHOST|SHAPE_FADING)) {
+					Buffer_Frame_To_Page(x, y, width, height, buffer, draw_window, flags | SHAPE_TRANS, ghostdata, fadingdata, 1, predoffset);
+				} else {
+					if (flags & SHAPE_FADING) {
+						Buffer_Frame_To_Page(x, y, width, height, buffer, draw_window, flags | SHAPE_TRANS, fadingdata, 1, predoffset);
+					} else {
+						if (flags & SHAPE_PREDATOR) {
+							Buffer_Frame_To_Page(x, y, width, height, buffer, draw_window, flags | SHAPE_TRANS, predoffset);
+						} else {
+							Buffer_Frame_To_Page(x, y, width, height, buffer, draw_window, flags | SHAPE_TRANS, ghostdata, predoffset);
+						}
+					}
+				}
+				draw_window.Unlock();
+			}
+		}
+	}
+}
+
+
+/***********************************************************************************************
+ * Shape_Dimensions -- Determine the minimum rectangle for the shape.                          *
+ *                                                                                             *
+ *    This routine will calculate (using brute forced) the minimum rectangle that will         *
+ *    enclose the pixels of the shape. This rectangle will be relative to the upper left       *
+ *    corner of the maximum shape size. By using this minimum rectangle, it is possible to     *
+ *    greatly optimize the map 'dirty rectangle' logic.                                        *
+ *                                                                                             *
+ * INPUT:   shapedata   -- Pointer to the shape data block.                                    *
+ *                                                                                             *
+ *          shapenum    -- The shape number to examine. Each shape would have a different      *
+ *                         dimension rectangle.                                                *
+ *                                                                                             *
+ * OUTPUT:  Returns with the rectangle that encloses the shape.                                *
+ *                                                                                             *
+ * WARNINGS:   This routine uses brute force and is slow. It is presumed that the results      *
+ *             will be cached for subsiquent reuse.                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/22/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+Rect const Shape_Dimensions(void const * shapedata, int shapenum)
+{
+	Rect rect;
+
+	if (shapedata == NULL || shapenum < 0 || shapenum > Get_Build_Frame_Count(shapedata)) {
+		return(rect);
+	}
+
+	char * shape;
+#ifdef WIN32
+	void * sh = (void *)Build_Frame(shapedata, shapenum, _ShapeBuffer);
+	if (sh == NULL) return(rect);
+//	shape = (char *)sh;
+	shape = (char *)Get_Shape_Header_Data(sh);
+#else
+	Build_Frame(shapedata, shapenum, _ShapeBuffer);
+	shape = (char *)_ShapeBuffer;
+#endif
+
+	int width = Get_Build_Frame_Width(shapedata);
+	int height = Get_Build_Frame_Height(shapedata);
+
+	rect.X = 0;
+	rect.Y = 0;
+	int xlimit = width-1;
+	int ylimit = height-1;
+
+	/*
+	**	Find top edge of the shape.
+	*/
+	for (int y = 0; y <= ylimit; y++) {
+		for (int x = 0; x <= xlimit; x++) {
+			if (shape[y*width + x] != 0) {
+				rect.Y = y;
+				rect.X = x;
+				y = ylimit+1;
+				break;
+			}
+		}
+	}
+
+	/*
+	**	Find bottom edge of the shape.
+	*/
+	for (y = ylimit; y >= rect.Y; y--) {
+		for (int x = xlimit; x >= 0; x--) {
+			if (shape[y*width + x] != 0) {
+				rect.Height = (y-rect.Y)+1;
+				xlimit = x;
+				y = rect.Y-1;
+				break;
+			}
+		}
+	}
+
+	/*
+	**	Find left edge of the shape.
+	*/
+	for (int x = 0; x < rect.X; x++) {
+		for (y = rect.Y; y < rect.Y+rect.Height; y++) {
+			if (shape[y*width + x] != 0) {
+				rect.X = x;
+				x = rect.X;
+				break;
+			}
+		}
+	}
+
+	/*
+	**	Find the right edge of the shape.
+	*/
+	for (x = width-1; x >= xlimit; x--) {
+		for (y = rect.Y; y < rect.Y+rect.Height; y++) {
+			if (shape[y*width + x] != 0) {
+				rect.Width = (x-rect.X)+1;
+				x = xlimit-1;
+				break;
+			}
+		}
+	}
+
+	/*
+	**	Normalize the rectangle around the center of the shape.
+	*/
+	rect.X -= width / 2;
+	rect.Y -= height / 2;
+
+	/*
+	**	Return with the minimum rectangle that encloses the shape.
+	*/
+	return(rect);
+}
+
+
+/***********************************************************************************************
+ * Fetch_Techno_Type -- Convert type and ID into TechnoTypeClass pointer.                      *
+ *                                                                                             *
+ *    This routine will convert the supplied RTTI type number and the ID value into a valid    *
+ *    TechnoTypeClass pointer. If there is an error in conversion, then NULL is returned.      *
+ *                                                                                             *
+ * INPUT:   type  -- RTTI type of the techno class object.                                     *
+ *                                                                                             *
+ *          id    -- Integer representation of the techno sub type number.                     *
+ *                                                                                             *
+ * OUTPUT:  Returns with a pointer to the techno type class object specified or NULL if the    *
+ *          conversion could not occur.                                                        *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   05/08/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+TechnoTypeClass const * Fetch_Techno_Type(RTTIType type, int id)
+{
+	switch (type) {
+		case RTTI_UNITTYPE:
+		case RTTI_UNIT:
+			return(&UnitTypeClass::As_Reference(UnitType(id)));
+
+		case RTTI_VESSELTYPE:
+		case RTTI_VESSEL:
+			return(&VesselTypeClass::As_Reference(VesselType(id)));
+
+		case RTTI_BUILDINGTYPE:
+		case RTTI_BUILDING:
+			return(&BuildingTypeClass::As_Reference(StructType(id)));
+
+		case RTTI_INFANTRYTYPE:
+		case RTTI_INFANTRY:
+			return(&InfantryTypeClass::As_Reference(InfantryType(id)));
+
+		case RTTI_AIRCRAFTTYPE:
+		case RTTI_AIRCRAFT:
+			return(&AircraftTypeClass::As_Reference(AircraftType(id)));
+
+		default:
+			break;
+	}
+	return(NULL);
+}
+
+
+/***********************************************************************************************
+ * VQ_Call_Back -- Maintenance callback used for VQ movies.                                    *
+ *                                                                                             *
+ *    This routine is called every frame of the VQ movie as it is being played. If this        *
+ *    routine returns non-zero, then the movie will stop.                                      *
+ *                                                                                             *
+ * INPUT:   buffer   -- Pointer to the image buffer for the current frame.                     *
+ *                                                                                             *
+ *          frame    -- The frame number about to be displayed.                                *
+ *                                                                                             *
+ * OUTPUT:  Should the movie be stopped?                                                       *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/24/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+#ifdef WIN32
+void VQA_PauseAudio(void);
+void Check_VQ_Palette_Set(void);
+
+extern GraphicBufferClass VQ640;
+extern bool IsVQ640;
+long VQ_Call_Back(unsigned char *, long )
+{
+	int key = 0;
+	if (Keyboard->Check()) {
+		key = Keyboard->Get();
+		Keyboard->Clear();
+	}
+	Check_VQ_Palette_Set();
+#ifdef MOVIE640
+	if(IsVQ640) {
+		VQ640.Blit(SeenBuff);
+	} else {
+		Interpolate_2X_Scale(&SysMemPage, &SeenBuff, NULL);
+	}
+#else
+	Interpolate_2X_Scale(&SysMemPage, &SeenBuff, NULL);
+#endif
+	//Call_Back();
+
+	if ((BreakoutAllowed || Debug_Flag) && key == KN_ESC) {
+		Keyboard->Clear();
+		Brokeout = true;
+		return(true);
+	}
+
+	if (!GameInFocus) {
+		VQA_PauseAudio();
+		while (!GameInFocus) {
+			Check_For_Focus_Loss();
+		}
+	}
+	return(false);
+}
+
+#else	//WIN32
+
+long VQ_Call_Back(unsigned char *, long )
+{
+	Call_Back();
+	if ((BreakoutAllowed || Debug_Flag) && Keyboard->Check()) {
+		if (Keyboard->Get() == KN_ESC) {
+			Keyboard->Clear();
+			Brokeout = true;
+			return(true);
+		}
+		Keyboard->Clear();
+	}
+	return(false);
+}
+#endif	//WIN32
+
+
+/***********************************************************************************************
+ * Handle_Team -- Processes team selection command.                                            *
+ *                                                                                             *
+ *    This routine will handle creation and selection of pseudo teams that the player can      *
+ *    create or control. A team in this sense is an arbitrary grouping of units such that      *
+ *    rapid selection control is allowed.                                                      *
+ *                                                                                             *
+ * INPUT:   team  -- The logical team number to process.                                       *
+ *                                                                                             *
+ *          action-- The action to perform on this team:                                       *
+ *                   0 - Toggle the select state for all members of this team.                 *
+ *                   1 - Select the members of this team.                                      *
+ *                   2 - Make all selected objects members of this team.                       *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   06/27/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void Handle_Team(int team, int action)
+{
+	int index;
+
+	//
+	// Recording support
+	//
+	if (Session.Record) {
+		TeamNumber = (char)team;
+		TeamEvent = (char)action + 1;
+	}
+
+	AllowVoice = true;
+	switch (action) {
+
+		/*
+		**	Toggle the team selection. If the team is selected, then merely unselect it. If the
+		**	team is not selected, then unselect all others before selecting this team.
+		*/
+		case 3:
+		case 0:
+
+			/*
+			**	If a non team member is currently selected, then deselect all objects
+			**	before selecting this team.
+			*/
+			if (CurrentObject.Count()) {
+				if (CurrentObject[0]->Is_Foot() && ((FootClass *)CurrentObject[0])->Group != team) {
+					Unselect_All();
+				}
+			}
+			for (index = 0; index < Vessels.Count(); index++) {
+				VesselClass * obj = Vessels.Ptr(index);
+				if (obj && !obj->IsInLimbo && obj->Group == team && obj->House->IsPlayerControl) {
+					if (!obj->IsSelected) {
+						obj->Select();
+						AllowVoice = false;
+					}
+				}
+			}
+			for (index = 0; index < Units.Count(); index++) {
+				UnitClass * obj = Units.Ptr(index);
+				if (obj && !obj->IsInLimbo && obj->Group == team && obj->House->IsPlayerControl) {
+					if (!obj->IsSelected) {
+						obj->Select();
+						AllowVoice = false;
+					}
+				}
+			}
+			for (index = 0; index < Infantry.Count(); index++) {
+				InfantryClass * obj = Infantry.Ptr(index);
+				if (obj && !obj->IsInLimbo && obj->Group == team && obj->House->IsPlayerControl) {
+					if (!obj->IsSelected) {
+						obj->Select();
+						AllowVoice = false;
+					}
+				}
+			}
+			for (index = 0; index < Aircraft.Count(); index++) {
+				AircraftClass * obj = Aircraft.Ptr(index);
+				if (obj && !obj->IsInLimbo && obj->Group == team && obj->House->IsPlayerControl) {
+					if (!obj->IsSelected) {
+						obj->Select();
+						AllowVoice = false;
+					}
+				}
+			}
+
+			/*
+			**	Center the map around the team if the ALT key was pressed too.
+			*/
+			if (action == 3) {
+				Map.Center_Map();
+#ifdef WIN32
+				Map.Flag_To_Redraw(true);
+#endif	//WIn32
+			}
+			break;
+
+		/*
+		**	Additive selection of team.
+		*/
+		case 1:
+			for (index = 0; index < Units.Count(); index++) {
+				UnitClass * obj = Units.Ptr(index);
+				if (obj && !obj->IsInLimbo && obj->Group == team && obj->House->IsPlayerControl) {
+					if (!obj->IsSelected) {
+						obj->Select();
+						AllowVoice = false;
+					}
+				}
+			}
+			for (index = 0; index < Vessels.Count(); index++) {
+				VesselClass * obj = Vessels.Ptr(index);
+				if (obj && !obj->IsInLimbo && obj->Group == team && obj->House->IsPlayerControl) {
+					if (!obj->IsSelected) {
+						obj->Select();
+						AllowVoice = false;
+					}
+				}
+			}
+			for (index = 0; index < Infantry.Count(); index++) {
+				InfantryClass * obj = Infantry.Ptr(index);
+				if (obj && !obj->IsInLimbo && obj->Group == team && obj->House->IsPlayerControl) {
+					if (!obj->IsSelected) {
+						obj->Select();
+						AllowVoice = false;
+					}
+				}
+			}
+			for (index = 0; index < Aircraft.Count(); index++) {
+				AircraftClass * obj = Aircraft.Ptr(index);
+				if (obj && !obj->IsInLimbo && obj->Group == team && obj->House->IsPlayerControl) {
+					if (!obj->IsSelected) {
+						obj->Select();
+						AllowVoice = false;
+					}
+				}
+			}
+			break;
+
+		/*
+		**	Create the team.
+		*/
+		case 2: {
+			long minx = 0x7FFFFFFFL, miny = 0x7FFFFFFFL;
+			long maxx = 0, maxy = 0;
+			TeamSpeed[team] = SPEED_WHEEL;
+			TeamMaxSpeed[team] = MPH_LIGHT_SPEED;
+			for (index = 0; index < Units.Count(); index++) {
+				UnitClass * obj = Units.Ptr(index);
+				if (obj && !obj->IsInLimbo && obj->House->IsPlayerControl) {
+				 	if (obj->Group == team) obj->Group = 0xFF;
+					if (obj->IsSelected) {
+						obj->Group = team;
+						obj->Mark(MARK_CHANGE);
+						long xc = Cell_X(Coord_Cell(obj->Center_Coord()));
+						long yc = Cell_Y(Coord_Cell(obj->Center_Coord()));
+						if (xc < minx) minx = xc;
+						if (xc > maxx) maxx = xc;
+						if (yc < miny) miny = yc;
+						if (yc > maxy) maxy = yc;
+						if (obj->Class->MaxSpeed < TeamMaxSpeed[team]) {
+							TeamMaxSpeed[team] = obj->Class->MaxSpeed;
+							TeamSpeed[team] = obj->Class->Speed;
+						}
+					}
+				}
+			}
+
+			for (index = 0; index < Vessels.Count(); index++) {
+				VesselClass * obj = Vessels.Ptr(index);
+				if (obj && !obj->IsInLimbo && obj->House->IsPlayerControl) {
+				 	if (obj->Group == team) obj->Group = -1;
+					if (obj->IsSelected) {
+						obj->Group = team;
+						obj->Mark(MARK_CHANGE);
+						long xc = Cell_X(Coord_Cell(obj->Center_Coord()));
+						long yc = Cell_Y(Coord_Cell(obj->Center_Coord()));
+						if (xc < minx) minx = xc;
+						if (xc > maxx) maxx = xc;
+						if (yc < miny) miny = yc;
+						if (yc > maxy) maxy = yc;
+						if (obj->Class->MaxSpeed < TeamMaxSpeed[team]) {
+							TeamMaxSpeed[team] = obj->Class->MaxSpeed;
+							TeamSpeed[team] = obj->Class->Speed;
+						}
+					}
+				}
+			}
+
+			for (index = 0; index < Infantry.Count(); index++) {
+				InfantryClass * obj = Infantry.Ptr(index);
+				if (obj && !obj->IsInLimbo && obj->House->IsPlayerControl) {
+				 	if (obj->Group == team) obj->Group = 0xFF;
+					if (obj->IsSelected) {
+						obj->Group = team;
+						obj->Mark(MARK_CHANGE);
+						long xc = Cell_X(Coord_Cell(obj->Center_Coord()));
+						long yc = Cell_Y(Coord_Cell(obj->Center_Coord()));
+						if (xc < minx) minx = xc;
+						if (xc > maxx) maxx = xc;
+						if (yc < miny) miny = yc;
+						if (yc > maxy) maxy = yc;
+						if (obj->Class->MaxSpeed < TeamMaxSpeed[team]) {
+							TeamMaxSpeed[team] = obj->Class->MaxSpeed;
+						}
+					}
+				}
+			}
+			for (index = 0; index < Aircraft.Count(); index++) {
+				AircraftClass * obj = Aircraft.Ptr(index);
+				if (obj && !obj->IsInLimbo && obj->House->IsPlayerControl) {
+				 	if (obj->Group == team) obj->Group = 0xFF;
+					if (obj->IsSelected) {
+						obj->Group = team;
+						obj->Mark(MARK_CHANGE);
+					}
+				}
+			}
+
+			for (index = 0; index < Units.Count(); index++) {
+				UnitClass * obj = Units.Ptr(index);
+				if (obj && !obj->IsInLimbo && obj->House->IsPlayerControl &&
+				 	(obj->Group == team) && (obj->IsSelected) ) {
+
+					/*
+					** When a team is first created, they're created without a
+					** formation offset, so they will not be created in
+					** formation.  Later, if they're assigned a formation, the
+					** XFormOffset & YFormOffset numbers will change to valid
+					** offsets, and they'll be formationed.
+					*/
+#if(1)
+					obj->XFormOffset = obj->YFormOffset = (int)0x80000000;
+#else
+#if(1)
+// Old always-north formation stuff
+						long xc = Cell_X(Coord_Cell(obj->Center_Coord()));
+						long yc = Cell_Y(Coord_Cell(obj->Center_Coord()));
+
+						obj->XFormOffset = xc - centerx;
+						obj->YFormOffset = yc - centery;
+#else
+// New method: save direction and distance rather than x & y offset
+						obj->XFormOffset = ::Direction(As_Coord(center), obj->Center_Coord());
+						obj->YFormOffset = ::Distance (As_Coord(center), obj->Center_Coord());
+#endif
+#endif
+				}
+			}
+
+			for (index = 0; index < Infantry.Count(); index++) {
+				InfantryClass * obj = Infantry.Ptr(index);
+				if (obj && !obj->IsInLimbo && obj->House->IsPlayerControl) {
+				 	if (obj->Group == team) obj->Group = 0xFF;
+					if (obj->IsSelected) obj->Group = team;
+					if (obj->Group == team  && obj->IsSelected) {
+#if(1)
+						obj->XFormOffset = obj->YFormOffset = (int)0x80000000;
+#else
+#if(1)
+// Old always-north formation stuff
+						long xc = Cell_X(Coord_Cell(obj->Center_Coord()));
+						long yc = Cell_Y(Coord_Cell(obj->Center_Coord()));
+
+						obj->XFormOffset = xc - centerx;
+						obj->YFormOffset = yc - centery;
+#else
+// New method: save direction and distance rather than x & y offset
+						obj->XFormOffset = ::Direction(As_Coord(center), obj->Center_Coord());
+						obj->YFormOffset = ::Distance (As_Coord(center), obj->Center_Coord());
+#endif
+#endif
+					}
+				}
+			}
+			break;
+		}
+
+		default:
+			break;
+	}
+	AllowVoice = true;
+}
+
+
+/***********************************************************************************************
+ * Handle_View -- Either records or restores the tactical view.                                *
+ *                                                                                             *
+ *    This routine is used to record or restore the current map tactical view.                 *
+ *                                                                                             *
+ * INPUT:   view  -- The view number to work with.                                             *
+ *                                                                                             *
+ *          action-- The action to perform with this view number.                              *
+ *                   0  =  Restore the view to this previously remembered location.            *
+ *                   1  =  Record the current view location.                                   *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/04/1995 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void Handle_View(int view, int action)
+{
+	if ((unsigned)view < ARRAY_SIZE(Scen.Views)) {
+		if (action == 0) {
+
+			Map.Set_Tactical_Position(Coord_Whole(Cell_Coord(Scen.Views[view] - (MAP_CELL_W * 4 * RESFACTOR) - (5*RESFACTOR))));
+
+#ifdef WIN32
+			/*
+			** Win95 scrolling logic cant handle just jumps in screen position so redraw the lot.
+			*/
+			Map.Flag_To_Redraw (true);
+#endif	//WIN32
+		} else {
+			Scen.Views[view] = Coord_Cell(Map.TacticalCoord) + (MAP_CELL_W*4*RESFACTOR) + (5*RESFACTOR);
+		}
+	}
+}
+
+
+#ifndef ROR_NOT_READY
+#define ROR_NOT_READY 21
+#endif
+
+static char * _CD_Volume_Label[] = {
+	"CD1",
+	"CD2",
+	"CD3",
+	"CD4",
+	// Denzil 4/15/98
+	#ifdef DVD
+	"CD1",		//	ajw - Pushes RADVD to position 5, to match enum in Force_CD_Available(). 4 will never be returned here.
+	"RADVD",
+	#endif
+};
+static int _Num_Volumes = ARRAY_SIZE(_CD_Volume_Label);
+
+
+#ifdef WIN32
+/***********************************************************************************************
+ * Get_CD_Index -- returns the volume type of the CD in the given drive                        *
+ *                                                                                             *
+ *                                                                                             *
+ *                                                                                             *
+ * INPUT:    drive number                                                                      *
+ *           timeout                                                                           *
+ *                                                                                             *
+ * OUTPUT:   0 = gdi                                                                           *
+ *           1 = nod                                                                           *
+ *           2 = covert or CS                                                                       *
+ *           3 = Aftermath
+ *           5 = DVD
+ *          -1 = non C&C                                                                       *
+ *                                                                                             *
+ * WARNINGS: None                                                                              *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *    5/21/96 5:27PM ST : Created                                                              *
+ *    01/20/97 V.Grippi added CS support											       *
+ *=============================================================================================*/
+int Get_CD_Index (int cd_drive, int timeout)
+	{
+	char		volume_name[128];
+	char		buffer[128];
+	unsigned	filename_length;
+	unsigned	misc_dword;
+	int		count = 0;
+
+	CountDownTimerClass timer;
+
+	timer.Set(timeout);
+
+	/*
+	** Get the volume label. If we get a 'not ready' error then retry for the timeout
+	** period.
+	*/
+	for (;;)
+		{
+		sprintf(buffer, "%c:\\", 'A' + cd_drive);
+
+		if (GetVolumeInformation ((char const *)buffer, &volume_name[0] ,
+				(unsigned long)sizeof(volume_name), (unsigned long *)NULL ,
+				(unsigned long *)&filename_length, (unsigned long *)&misc_dword,
+				(char *)NULL, (unsigned long)0))
+			{
+			/*
+			** Try opening 'movies.mix' to verify that the CD is really there and is what
+			** it says it is.
+			*/
+			sprintf(buffer, "%c:\\main.mix", 'A' + cd_drive);
+
+			HANDLE handle = CreateFile(buffer, GENERIC_READ, FILE_SHARE_READ,NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+			if (handle != INVALID_HANDLE_VALUE)
+				{
+				CloseHandle(handle);
+
+				/*
+				** Match the volume label to the list of known C&C volume labels.
+				*/
+				for (int i = 0 ; i < _Num_Volumes; i++)
+					{
+					if (!stricmp(_CD_Volume_Label[i], volume_name))
+						return(i);
+					}
+				}
+			else
+				{
+				if (!count)
+					count++;
+				else
+					return -1;
+				}
+			}
+		else
+			{
+			/*
+			** Failed to get the volume label on a known CD drive.
+			** If this is a CD changer it may require time to swap the disks so dont return
+			** immediately if the error is ROR_NOT_READY
+			*/
+			if (!timer.Time())
+				return -1;
+				
+			int val = GetLastError();
+			
+			if (val != ROR_NOT_READY)
+				return -1;
+			}	
+		}
+	}
+#else
+int Get_CD_Index(int cd_drive, int)
+	{
+	char buffer[128];
+
+	/*
+	** We need to do this twice because of the possibilities of a directory
+	** being cached.  If this is so, it will only be discovered when we
+	** actually attempt to read a file from the drive.
+	*/
+	if(cd_drive) for (int count = 0; count < 2; count ++)
+		{
+		struct find_t ft;
+		int file;
+		int open_failed;
+
+		/*
+		** Create a path for the cd drive and attempt to read the volume label from
+		** it.
+		*/
+		sprintf(buffer, "%c:\\", 'A' + cd_drive);
+
+		/*
+		** If we are able to read the volume label, this is good but not enough.
+		** Further verification must be done.
+		*/
+		if (!_dos_findfirst(buffer, _A_VOLID, &ft))
+			{
+			/*
+			** Since some versions of disk cacheing software will cache the CD's
+			** directory tracks, we may think the CD is in the drive when it is
+			** actually not.  To resolve this we must attempt to open a file on
+			** the cd.  Opening a file will always update the directory tracks
+			** (suposedly).
+			*/
+			sprintf(buffer, "%c:\\main.mix", 'A' + cd_drive);
+			open_failed = _dos_open(buffer, O_RDONLY|SH_DENYNO, &file);
+
+			if (!open_failed)
+				{
+				_dos_close(file);
+
+				/*
+				** Hey some times the stupid dos driver appends a period to the
+				** name if it is eight characters long.  If the last char is a
+				** period then erase it.
+				*/
+				if (ft.name[strlen(ft.name)-1] == '.')
+					{
+					ft.name[strlen(ft.name)-1] = 0;
+					}
+
+				/*
+				** Match the volume label to the list of known C&C volume labels.
+				*/
+				for (int i = 0 ; i < _Num_Volumes; i++)
+					{
+					if (!stricmp(_CD_Volume_Label[i], ft.name))
+						return (i);
+					}
+				}
+			}
+		}
+
+	return -1;
+	}
+#endif
+
+
+/***********************************************************************************************
+ * Force_CD_Available -- Ensures that specified CD is available.                               *
+ *                                                                                             *
+ *    Call this routine when you need to ensure that the specified CD is actually in the       *
+ *    CD-ROM drive.                                                                            *
+ *                                                                                             *
+ * INPUT:   cd    -- The CD that must be available. This will either be "0" for the GDI CD, or *
+ *                   "1" for the Nod CD. If either CD will qualify, then pass in "-1".         *
+ *                0  = CD1
+ *                1  = CD2
+ *                2  = Counterstrike
+ *                3  = Aftermath
+ *                4  = Counterstrike or Aftermath
+ *                5  = DVD
+ *                -1 = Any CD
+ *                -2 = Local Harddisk
+ *                                                                                             *
+ * OUTPUT:  Is the CD inserted and available? If false is returned, then this indicates that   *
+ *          the player pressed <CANCEL>.                                                       *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   07/11/1995 JLB : Created.                                                                 *
+ *   05/22/1996  ST : Handles multiple CD drives / CD changers                                 *
+ *   01/20/1997 V.Grippi added expansion cd message
+ *=============================================================================================*/
+
+typedef enum {
+	CD_LOCAL = -2,
+	CD_ANY = -1,
+	CD_SOVIET = 0,
+	CD_ALLIED,
+	CD_COUNTERSTRIKE,
+	CD_AFTERMATH,
+	CD_CS_OR_AM,
+	CD_DVD
+} CD_VOLUME;
+
+#ifdef FIXIT_VERSION_3
+
+#ifndef DVD
+#error DVD must be defined!
+#endif
+
+bool Force_CD_Available( int cd_desired )				//	ajw
+{
+	static int _last = -1;
+	static void *font;
+#ifdef FRENCH
+	static char * _cd_name[] = {
+		"ALERTE ROUGE CD1",
+		"ALERTE ROUGE CD2",
+		"CD Missions Taiga",
+		"CD Missions M.A.D.",
+		"ALERTE ROUGE DVD",
+};
+#endif
+#ifdef GERMAN
+	static char * _cd_name[] = {
+		"ALARMSTUFE ROT CD1",
+		"ALARMSTUFE ROT CD2",
+		"CD Gegenangriff einlegen",
+		"CD TRANS einlegen",
+		"ALARMSTUFE ROT DVD",
+	};
+#endif
+#ifdef ENGLISH
+	static char * _cd_name[] = {
+		"RED ALERT DISK 1",
+		"RED ALERT DISK 2",
+		"CounterStrike CD",
+		"Aftermath CD",
+		"RED ALERT DVD",
+	};
+#endif
+
+	int new_cd_drive = 0;
+	int cd_current;
+	int current_drive;
+
+	ThemeType theme_playing = THEME_NONE;
+
+	/*
+	** If the required CD is set to -2 then it means that the file is present
+	** on the local hard drive and we shouldn't have to worry about it.
+	*/
+	if (cd_desired == CD_LOCAL) return(true);
+
+	/*
+	** Find out if the CD in the current drive is the one we are looking for
+ 	*/
+	current_drive = CCFileClass::Get_CD_Drive();
+	cd_current = Get_CD_Index(current_drive, 1*60);
+
+//	debugprint("Get_CD_Index just returned %d\n", cd_current);
+//	debugprint("We are checking for %d\n", cd_desired);
+//	debugprint("current_drive = %d\n", current_drive);
+
+	if( Using_DVD() )
+	{
+		//	All requested cd indexes get rerouted to the DVD.
+		cd_desired = CD_DVD;
+//		if( RequiredCD != -1 )
+//			RequiredCD = CD_DVD;		//	Just seems like a good idea. Not sure if necessary.	ajw
+	}
+
+	if (cd_current >= 0 )
+	{
+		if( cd_desired == CD_CS_OR_AM )
+		{
+			// If the current cd is CS or AM then change request to whatever
+			// is present.
+			if( cd_current == CD_COUNTERSTRIKE || cd_current == CD_AFTERMATH )
+				cd_desired = cd_current;
+		}
+		// If the current CD is requested or any CD will work
+		if( cd_desired == cd_current || cd_desired == CD_ANY )
+		{
+			/*
+			** The required CD is still in the CD drive we used last time
+			*/
+			new_cd_drive = current_drive;
+		}
+	}
+
+	/*
+	** Flag that we will have to restart the theme
+	*/
+	theme_playing = Theme.What_Is_Playing();
+	Theme.Stop();
+
+	// Check the last drive
+	if (!new_cd_drive)
+	{
+		/*
+		** Check the last CD drive we used if it's different from the current one
+		*/
+		int last_drive = CCFileClass::Get_Last_CD_Drive();
+
+		/*
+		** Make sure the last drive is valid and it isn't the current drive
+		*/
+		if (last_drive && last_drive != CCFileClass::Get_CD_Drive())		//	Else we have already checked this cd.
+		{
+			/*
+			** Find out if there is a C&C cd in the last drive and if so is it the one we are looking for
+			** Give it a nice big timeout so the CD changer has time to swap the discs
+			*/
+			cd_current = Get_CD_Index(last_drive, 10*60);
+
+			if (cd_current >= 0 )
+			{
+				if( cd_desired == CD_CS_OR_AM )
+				{
+					// If the cd is CS or AM then change request to whatever
+					// is present.
+					if( cd_current == CD_COUNTERSTRIKE || cd_current == CD_AFTERMATH )
+						cd_desired = cd_current;
+				}
+				// If the cd is present or any cd will work
+				if( cd_desired == cd_current || cd_desired == CD_ANY )
+				{
+					/*
+					** The required CD is in the CD drive we used last time
+					*/
+					new_cd_drive = last_drive;
+				}
+			}
+		}
+	}
+
+	/*
+	** Lordy.  No sign of that blimming CD anywhere. Search all the CD drives
+	** then if we still can't find it prompt the user to insert it.
+	*/
+	if (!new_cd_drive)
+	{
+		/*
+		** Small timeout for the first pass through the drives
+		*/
+		int drive_search_timeout = 2*60;
+
+		for (;;)
+		{
+			char buffer[128];
+			/*
+			** Search all present CD drives for the required disc.
+			*/
+			for (int i = 0 ; i < CDList.Get_Number_Of_Drives(); i++)
+			{
+				int cd_drive = CDList.Get_Next_CD_Drive();
+				cd_current = Get_CD_Index(cd_drive, drive_search_timeout);
+
+				if (cd_current >= 0)
+				{
+					/*
+					** We found a C&C cd - lets see if it was the one we were looking for
+					*/
+					// Require CS or AM
+					if( cd_desired == CD_CS_OR_AM )
+					{
+						// If the cd is CS or AM then change request to whatever
+						// is present.
+						if( cd_current == CD_COUNTERSTRIKE || cd_current == CD_AFTERMATH )
+							cd_desired = cd_current;
+					}
+					
+					if( cd_desired == cd_current || cd_desired == CD_ANY )
+					{
+						/*
+						** Woohoo! The disk was in a different cd drive. Refresh the search path list
+				 		* and return.
+						*/
+						new_cd_drive = cd_drive;
+						break;
+					}
+				}
+			}
+
+			/*
+			** A new disc has become available so break
+			*/
+			if (new_cd_drive) break;
+
+			/*
+			** Increase the timeout for subsequent drive searches.
+			*/
+			drive_search_timeout = 5*60;
+
+			/*
+			**	Prompt to insert the CD into the drive.
+			*/
+			//V.Grippi
+			if( cd_desired == CD_CS_OR_AM )
+				cd_desired = CD_AFTERMATH;
+			
+			if( cd_desired == CD_DVD )
+			{
+				#ifdef FRENCH
+			   	sprintf(buffer, "InsŠrez le %s",  _cd_name[4]);
+				#else
+				#ifdef GERMAN
+				sprintf(buffer, "Bitte %s",  _cd_name[4]);
+				#else
+				sprintf(buffer, "Please insert the %s",  _cd_name[4]);
+				#endif
+				#endif
+			}
+			else if( cd_desired == CD_COUNTERSTRIKE || cd_desired == CD_AFTERMATH )
+			{
+				#ifdef FRENCH
+			   	sprintf(buffer, "InsŠrez le %s",  _cd_name[cd_desired]);
+				#else
+				#ifdef GERMAN
+				sprintf(buffer, "Bitte %s",  _cd_name[cd_desired]);
+				#else
+				sprintf(buffer, "Please insert the %s",  _cd_name[cd_desired]);
+				#endif
+				#endif
+			}
+			else if( cd_desired == CD_ANY )
+			{
+				sprintf(buffer, Text_String(TXT_CD_DIALOG_1), cd_desired+1, _cd_name[cd_desired]);
+			}
+			else		//	0 or 1
+			{
+				sprintf(buffer, Text_String(TXT_CD_DIALOG_2), cd_desired+1, _cd_name[cd_desired]);
+			}
+
+			GraphicViewPortClass * oldpage = Set_Logic_Page(SeenBuff);
+			theme_playing = Theme.What_Is_Playing();
+			Theme.Stop();
+			int hidden = Get_Mouse_State();
+			font = (void *)FontPtr;
+
+			/*
+			**	Only set the palette if necessary.
+			*/
+			if (PaletteClass::CurrentPalette[1].Red_Component() +
+					PaletteClass::CurrentPalette[1].Blue_Component() +
+					PaletteClass::CurrentPalette[1].Green_Component() == 0)
+			{
+				GamePalette.Set();
+			}
+
+			Keyboard->Clear();
+
+			while (Get_Mouse_State()) Show_Mouse();
+
+			if (WWMessageBox().Process(buffer, TXT_OK, TXT_CANCEL, TXT_NONE, TRUE) == 1)
+			{
+				Set_Logic_Page(oldpage);
+#ifdef FIXIT_VERSION_3
+				while (hidden--) Hide_Mouse();
+#else
+				Hide_Mouse();
+#endif
+				return(false);
+			}
+
+			while (hidden--) Hide_Mouse();
+			Set_Font(font);
+			Set_Logic_Page(oldpage);
+		}
+	}
+
+	CurrentCD = cd_current;
+
+	CCFileClass::Set_CD_Drive(new_cd_drive);
+	CCFileClass::Refresh_Search_Drives();
+
+	/*
+	**	If it broke out of the query for CD-ROM loop, then this means that the
+	**	CD-ROM has been inserted.
+	*/
+	if (cd_desired == 4) cd_desired--;
+
+	//	ajw - Added condition of cd_desired != 5 to the following if.
+	//	Reason: This was triggering before Init_Secondary_Mixfiles(), which was screwing up the mixfile system somehow.
+	//
+	//	Since the DVD is the only disk that can possibly be required when Using_DVD(), I never have to reload the mix
+	//	files here, because no other disk could ever have been asked for. And if not Using_DVD(), cd_desired will never
+	//	be equal to 5. So this is safe.
+	if (cd_desired > -1 && _last != cd_desired && cd_desired != 5)
+	{
+		_last = cd_desired;
+
+		Theme.Stop();
+
+//		if (ConquerMix) delete ConquerMix;
+		if (MoviesMix) delete MoviesMix;
+		if (GeneralMix) delete GeneralMix;
+		if (ScoreMix) delete ScoreMix;
+		if (MainMix) delete MainMix;
+
+		MainMix = new MFCD("MAIN.MIX", &FastKey);
+		assert(MainMix != NULL);
+//		ConquerMix = new MFCD("CONQUER.MIX", &FastKey);
+		if (CCFileClass("MOVIES1.MIX").Is_Available())
+			MoviesMix = new MFCD("MOVIES1.MIX", &FastKey);
+		else
+			MoviesMix = new MFCD("MOVIES2.MIX", &FastKey);
+		assert(MoviesMix != NULL);
+		GeneralMix = new MFCD("GENERAL.MIX", &FastKey);
+		ScoreMix = new MFCD("SCORES.MIX", &FastKey);
+		ThemeClass::Scan();
+	}
+
+	return(true);
+}
+
+#else		//	FIXIT_VERSION_3 not defined
+
+bool Force_CD_Available(int cd)
+{
+	static int _last = -1;
+//	static char _palette[768];
+//	static char _hold[256];
+	static void *font;
+#ifdef FRENCH
+	static char * _cd_name[] = {
+		"ALERTE ROUGE CD1",
+		"ALERTE ROUGE CD2",
+		"CD Missions Taiga",
+		"CD Missions M.A.D.",
+
+		// Denzil 4/15/98
+		#ifdef DVD
+		"ALERTE ROUGE DVD",
+		#endif
+};
+
+#endif
+#ifdef GERMAN
+	static char * _cd_name[] = {
+		"ALARMSTUFE ROT CD1 einlegen",
+		"ALARMSTUFE ROT CD2 einlegen",
+		"CD Gegenangriff einlegen",
+		"CD TRANS einlegen",
+
+		// Denzil 4/15/98
+		#ifdef DVD
+		"ALARMSTUFE ROT DVD einlegen",
+		#endif
+	};
+#endif
+#ifdef ENGLISH
+	static char * _cd_name[] = {
+		"RED ALERT DISK 1",
+		"RED ALERT DISK 2",
+		"CounterStrike CD",
+		"Aftermath CD",
+
+		// Denzil 4/15/98
+		#ifdef DVD
+		"RED ALERT DVD",
+		#endif
+	};
+#endif
+
+	int new_cd_drive = 0;
+	int cd_index;
+	char buffer[128];
+	int cd_drive;
+	int current_drive;
+	int drive_search_timeout;
+
+	ThemeType theme_playing = THEME_NONE;
+
+//#ifdef FIXIT_ANTS
+//	if(Scen.ScenarioName[2] == 'A')
+//	   cd = 2;
+//#endif
+	/*
+	** If the required CD is set to -2 then it means that the file is present
+	** on the local hard drive and we shouldn't have to worry about it.
+	*/
+	if (cd == CD_LOCAL) return(true);
+
+	/*
+	** Find out if the CD in the current drive is the one we are looking for
+ 	*/
+	current_drive = CCFileClass::Get_CD_Drive();
+	cd_index = Get_CD_Index(current_drive, 1*60);
+
+	#ifdef CHEAT_KEYS
+	//	Mono_Printf("Get_CD_Index just returned %d\n", cd_index);
+	//	Mono_Printf("We are checking for %d\n", cd);
+	//	Mono_Printf("current_drive = %d\n", current_drive);
+	#endif	//CHEAT_KEYS
+
+	#ifdef DVD // Denzil
+	// CD1 and CD2 are ignored, force the DVD
+	if (cd_index == 0 || cd_index == 1)
+		cd_index = -1;
+	#endif
+	
+	if (cd_index >= 0 )
+		{
+		#ifdef FIXIT_CSII	//	checked - ajw 9/28/98
+		// Require CS or AM
+		if (cd == CD_CS_OR_AM)
+			{
+			// If the current cd is CS or AM then change request to whatever
+			// is present.
+			if (cd_index == 2 || cd_index == 3)
+				{
+				cd = cd_index;
+				}
+			}
+		#endif
+
+		#ifdef DVD // Denzil
+		// If the current drive is the DVD then requests for CD1 and CD2 are okay
+		if (cd_index == 4)
+			{
+			// CD1, CD2 & DVD requests
+			if (cd == 0 || cd == 1 || cd == 5)
+				{
+				cd_index = cd;
+				}
+			}
+		#endif
+		
+		// If the current CD is requested or any CD will work
+		if (cd == cd_index || cd == -1 )
+			{
+			/*
+			** The required CD is still in the CD drive we used last time
+			*/
+			new_cd_drive = current_drive;
+			}
+		}
+
+	/*
+	** Flag that we will have to restart the theme
+	*/
+	theme_playing = Theme.What_Is_Playing();
+	Theme.Stop();
+
+	// Check the last drive
+	if (!new_cd_drive)
+		{
+		/*
+		** Check the last CD drive we used if it's different from the current one
+		*/
+		int last_drive = CCFileClass::Get_Last_CD_Drive();
+
+		/*
+		** Make sure the last drive is valid and it isn't the current drive
+		*/
+		if (last_drive && last_drive != CCFileClass::Get_CD_Drive())
+			{
+			/*
+			** Find out if there is a C&C cd in the last drive and if so is it the one we are looking for
+			** Give it a nice big timeout so the CD changer has time to swap the discs
+			*/
+			cd_index = Get_CD_Index(last_drive, 10*60);
+
+			#ifdef DVD // Denzil
+			// Ignore CD1 and CD2 disks, force DVD
+			if (cd_index == 0 || cd_index == 1)
+				cd_index = -1;
+			#endif
+			
+			if (cd_index >= 0 )
+				{
+				#ifdef FIXIT_CSII	//	checked - ajw 9/28/98
+				// Require CS or AM
+				if (cd == 4)
+					{
+					// If CS or AM was the last drive then use it
+					if (cd_index == 2 || cd_index == 3)
+						{
+						cd = cd_index;
+						}
+					}
+				#endif
+
+				#ifdef DVD // Denzil
+				// If DVD is in drive
+				if (cd_index == 4)
+					{
+					// CD1, CD2 and DVD requests are all on the DVD 
+					if ((cd == 0) || (cd == 1) || (cd == 5))
+						{
+						cd_index = cd;
+						}
+					}
+				#endif
+
+				// If the cd is present or any cd will work
+				if (cd == cd_index || cd == -1 )
+					{
+					/*
+					** The required CD is in the CD drive we used last time
+					*/
+					new_cd_drive = last_drive;
+					}
+				}
+			}
+		}
+
+	/*
+	** Lordy.  No sign of that blimming CD anywhere. Search all the CD drives
+	** then if we still can't find it prompt the user to insert it.
+	*/
+	if (!new_cd_drive)
+		{
+		/*
+		** Small timeout for the first pass through the drives
+		*/
+		drive_search_timeout = 2*60;
+
+		for (;;)
+			{
+			/*
+			** Search all present CD drives for the required disc.
+			*/
+			for (int i = 0 ; i < CDList.Get_Number_Of_Drives(); i++)
+				{
+				cd_drive = CDList.Get_Next_CD_Drive();
+				cd_index = Get_CD_Index(cd_drive, drive_search_timeout);
+
+				#ifdef DVD // Denzil
+				// Ignore CD1 and CD2, force the DVD
+				if (cd_index == 0 || cd_index == 1)
+					cd_index = -1;
+				#endif
+				
+				if (cd_index >= 0)
+					{
+					/*
+					** We found a C&C cd - lets see if it was the one we were looking for
+					*/
+					#ifdef FIXIT_CSII	//	checked - ajw 9/28/98
+					// Require CS or AM
+					if (cd == 4)
+						{
+						// If the disk is CS or AM then request it
+						if (cd_index == 2 || cd_index == 3)
+							{
+							cd = cd_index;
+							}
+						}
+					#endif
+
+					#ifdef DVD // Denzil
+					if (cd_index == 4)
+						{
+						if ((cd == 0) || (cd == 1) || (cd == 5))
+							{
+							cd_index = cd;
+							}
+						}
+					#endif
+					
+					if (cd == cd_index || cd == -1 || cd == -2 )
+						{
+						/*
+						** Woohoo! The disk was in a different cd drive. Refresh the search path list
+				 		* and return.
+						*/
+						new_cd_drive = cd_drive;
+						break;
+						}
+					}
+				}
+
+			/*
+			** A new disc has become available so break
+			*/
+			if (new_cd_drive) break;
+
+			/*
+			** Increase the timeout for subsequent drive searches.
+			*/
+			drive_search_timeout = 5*60;
+
+			/*
+			**	Prompt to insert the CD into the drive.
+			*/
+			//V.Grippi
+			#ifdef FIXIT_CSII	//	checked - ajw 9/28/98
+			if(cd == 4) cd--;
+			
+			// CS or AM
+			if(cd == 2 || cd == 3)
+				{
+			#else
+			if(cd == 2)
+		   		{
+			#endif
+
+				#ifdef FRENCH
+			   	sprintf(buffer, "InsŠrez le %s",  _cd_name[cd]);
+				#else
+				#ifdef GERMAN
+				sprintf(buffer, "Bitte %s",  _cd_name[cd]);
+				#else
+				sprintf(buffer, "Please insert the %s",  _cd_name[cd]);
+				#endif
+				#endif
+				}
+			else
+				{
+				#ifdef DVD
+				#ifdef FRENCH
+			   	sprintf(buffer, "InsŠrez le %s", _cd_name[4]);
+				#else
+				#ifdef GERMAN 
+				sprintf(buffer, "Bitte %s", _cd_name[4]);
+				#else
+				sprintf(buffer, "Please insert the %s", _cd_name[4]);
+				#endif
+				#endif
+				#else
+				if (cd == -1 )
+					{
+					sprintf(buffer, Text_String(TXT_CD_DIALOG_1), cd+1, _cd_name[cd]);
+					}
+				else
+					{
+					sprintf(buffer, Text_String(TXT_CD_DIALOG_2), cd+1, _cd_name[cd]);
+					}
+				#endif
+				}
+
+			#ifdef WIN32
+			GraphicViewPortClass * oldpage = Set_Logic_Page(SeenBuff);
+			#else
+			GraphicBufferClass * oldpage = Set_Logic_Page(SeenBuff);
+			#endif
+			theme_playing = Theme.What_Is_Playing();
+			Theme.Stop();
+			int hidden = Get_Mouse_State();
+			font = (void *)FontPtr;
+
+			/*
+			**	Only set the palette if necessary.
+			*/
+			if (PaletteClass::CurrentPalette[1].Red_Component() +
+					PaletteClass::CurrentPalette[1].Blue_Component() +
+					PaletteClass::CurrentPalette[1].Green_Component() == 0)
+				{
+				GamePalette.Set();
+				}
+
+			Keyboard->Clear();
+
+			while (Get_Mouse_State()) Show_Mouse();
+
+			if (WWMessageBox().Process(buffer, TXT_OK, TXT_CANCEL, TXT_NONE, TRUE) == 1)
+				{
+				Set_Logic_Page(oldpage);
+				Hide_Mouse();
+				return(false);
+				}
+
+			while (hidden--) Hide_Mouse();
+			Set_Font(font);
+			Set_Logic_Page(oldpage);
+			}
+		}
+
+	CurrentCD = cd_index;
+
+	CCFileClass::Set_CD_Drive(new_cd_drive);
+	CCFileClass::Refresh_Search_Drives();
+
+	/*
+	**	If it broke out of the query for CD-ROM loop, then this means that the
+	**	CD-ROM has been inserted.
+	*/
+	#ifdef FIXIT_CSII	//	checked - ajw 9/28/98
+	if (cd == 4) cd--;
+	#endif
+//	if (cd > -3 && _last != cd) {
+	if (cd > -1 && _last != cd)
+		{
+		_last = cd;
+
+		Theme.Stop();
+
+//		if (ConquerMix) delete ConquerMix;
+		if (MoviesMix) delete MoviesMix;
+		if (GeneralMix) delete GeneralMix;
+		if (ScoreMix) delete ScoreMix;
+		if (MainMix) delete MainMix;
+
+		MainMix = new MFCD("MAIN.MIX", &FastKey);
+		
+		assert(MainMix != NULL);
+//		ConquerMix = new MFCD("CONQUER.MIX", &FastKey);
+
+		if (CCFileClass("MOVIES1.MIX").Is_Available())
+			{
+			MoviesMix = new MFCD("MOVIES1.MIX", &FastKey);
+			}
+		else
+			{
+			MoviesMix = new MFCD("MOVIES2.MIX", &FastKey);
+			}
+		assert(MoviesMix != NULL);
+		GeneralMix = new MFCD("GENERAL.MIX", &FastKey);
+		ScoreMix = new MFCD("SCORES.MIX", &FastKey);
+		ThemeClass::Scan();
+		}
+
+	if (theme_playing != THEME_NONE)
+		{
+		Theme.Queue_Song(theme_playing);
+		}
+
+	return(true);
+	}
+
+
+#endif	//	FIXIT_VERSION_3
+
+/***************************************************************************
+ * DISK_SPACE_AVAILABLE -- returns bytes of free disk space                *
+ *                                                                         *
+ * INPUT:		none                                                        *
+ *                                                                         *
+ * OUTPUT:     returns amount of free disk space                           *
+ *                                                                         *
+ * HISTORY:                                                                *
+ *   08/11/1995 PWG : Created.                                             *
+ *=========================================================================*/
+unsigned long Disk_Space_Available(void)
+{
+	struct diskfree_t diskdata;
+	unsigned drive;
+
+	_dos_getdrive(&drive);
+	_dos_getdiskfree(drive, &diskdata);
+
+	return(diskdata.avail_clusters * diskdata.sectors_per_cluster * diskdata.bytes_per_sector);
+}
+
+
+/***********************************************************************************************
+ * Do_Record_Playback -- handles saving/loading map pos & current object                       *
+ *                                                                                             *
+ * INPUT:                                                                                      *
+ *		none.																												  *
+ *                                                                                             *
+ * OUTPUT:                                                                                     *
+ *		none.																												  *
+ *                                                                                             *
+ * WARNINGS:                                                                                   *
+ *		none.																												  *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/15/1995 BRR : Created.                                                                 *
+ *=============================================================================================*/
+static void Do_Record_Playback(void)
+{
+	int count;
+	TARGET tgt;
+	int i;
+	COORDINATE coord;
+	ObjectClass * obj;
+	unsigned long sum;
+	unsigned long sum2;
+	unsigned long ltgt;
+
+	/*
+	**	Record a game
+	*/
+	if (Session.Record) {
+
+		/*
+		**	Save the map's location
+		*/
+		Session.RecordFile.Write(&Map.DesiredTacticalCoord,
+			sizeof (Map.DesiredTacticalCoord));
+
+		/*
+		**	Save the current object list count
+		*/
+		count = CurrentObject.Count();
+		Session.RecordFile.Write(&count, sizeof(count));
+
+		/*
+		**	Save a CRC of the selected-object list.
+		*/
+		sum = 0;
+		for (i = 0; i < count; i++) {
+			ltgt = (unsigned long)(CurrentObject[i]->As_Target());
+			sum += ltgt;
+		}
+		Session.RecordFile.Write (&sum, sizeof(sum));
+
+		/*
+		**	Save all selected objects.
+		*/
+		for (i = 0; i < count; i++) {
+			tgt = CurrentObject[i]->As_Target();
+			Session.RecordFile.Write (&tgt, sizeof(tgt));
+		}
+
+		//
+		// Save team-selection and formation events
+		//
+		Session.RecordFile.Write (&TeamEvent, sizeof(TeamEvent));
+		Session.RecordFile.Write (&TeamNumber, sizeof(TeamNumber));
+		Session.RecordFile.Write (&FormationEvent, sizeof(FormationEvent));
+		Session.RecordFile.Write (TeamMaxSpeed, sizeof(TeamMaxSpeed));
+		Session.RecordFile.Write (TeamSpeed, sizeof(TeamSpeed));
+		Session.RecordFile.Write (&FormMove, sizeof(FormMove));
+		Session.RecordFile.Write (&FormSpeed, sizeof(FormSpeed));
+		Session.RecordFile.Write (&FormMaxSpeed, sizeof(FormMaxSpeed));
+		TeamEvent = 0;
+		TeamNumber = 0;
+		FormationEvent = 0;
+	}
+
+	/*
+	**	Play back a game ("attract" mode)
+	*/
+	if (Session.Play) {
+
+		/*
+		**	Read & set the map's location.
+		*/
+		if (Session.RecordFile.Read(&coord, sizeof(coord))==sizeof(coord)) {
+			if (coord != Map.DesiredTacticalCoord) {
+				Map.Set_Tactical_Position(coord);
+			}
+		}
+
+		if (Session.RecordFile.Read(&count, sizeof(count))==sizeof(count)) {
+			/*
+			**	Compute a CRC of the current object-selection list.
+			*/
+			sum = 0;
+			for (i = 0; i < CurrentObject.Count(); i++) {
+				ltgt = (unsigned long)(CurrentObject[i]->As_Target());
+				sum += ltgt;
+			}
+
+			/*
+			**	Load the CRC of the objects on disk; if it doesn't match, select
+			**	all objects as they're loaded.
+			*/
+			Session.RecordFile.Read (&sum2, sizeof(sum2));
+			if (sum2 != sum) {
+				Unselect_All();
+			}
+
+			AllowVoice = true;
+
+			for (i = 0; i < count; i++) {
+				if (Session.RecordFile.Read (&tgt, sizeof(tgt))==sizeof(tgt)) {
+					obj = As_Object(tgt);
+					if (obj && (sum2 != sum)) {
+						obj->Select();
+						AllowVoice = false;
+					}
+				}
+			}
+
+			AllowVoice = true;
+
+		}
+
+		//
+		// Save team-selection and formation events
+		//
+		Session.RecordFile.Read (&TeamEvent, sizeof(TeamEvent));
+		Session.RecordFile.Read (&TeamNumber, sizeof(TeamNumber));
+		Session.RecordFile.Read (&FormationEvent, sizeof(FormationEvent));
+		if (TeamEvent) {
+			Handle_Team(TeamNumber, TeamEvent - 1);
+		}
+		if (FormationEvent) {
+			Toggle_Formation();
+		}
+
+Session.RecordFile.Read (TeamMaxSpeed, sizeof(TeamMaxSpeed));
+Session.RecordFile.Read (TeamSpeed, sizeof(TeamSpeed));
+Session.RecordFile.Read (&FormMove, sizeof(FormMove));
+Session.RecordFile.Read (&FormSpeed, sizeof(FormSpeed));
+Session.RecordFile.Read (&FormMaxSpeed, sizeof(FormMaxSpeed));
+		/*
+		**	The map isn't drawn in playback mode, so draw it here.
+		*/
+		Map.Render();
+	}
+}
+
+
+/***********************************************************************************************
+ * Hires_Load -- Allocates memory for, and loads, a resolution dependant file.                 *
+ *                                                                                             *
+ *                                                                                             *
+ *                                                                                             *
+ * INPUT:    Name of file to load                                                              *
+ *                                                                                             *
+ * OUTPUT:   Ptr to loaded file                                                                *
+ *                                                                                             *
+ * WARNINGS: Caller is responsible for releasing the memory allocated                          *
+ *                                                                                             *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *    5/13/96 3:20PM ST : Created                                                              *
+ *=============================================================================================*/
+void * Hires_Load(char * name)
+{
+	char 	filename[30];
+	int 	length;
+	void * return_ptr;
+
+#ifdef WIN32
+	sprintf(filename, "H%s", name);
+#else
+   strcpy(filename, name);
+#endif
+	CCFileClass file (filename);
+
+	if (file.Is_Available()) {
+
+		length = file.Size();
+		return_ptr = new char[length];
+		file.Read(return_ptr, length);
+		return (return_ptr);
+
+	} else {
+		return (NULL);
+	}
+}
+
+
+/***********************************************************************************************
+ * Crate_From_Name -- Given a crate name convert it to a crate type.                           *
+ *                                                                                             *
+ *    Use this routine to convert an ASCII crate name into a crate type. If no match could     *
+ *    be found, then CRATE_MONEY is assumed.                                                   *
+ *                                                                                             *
+ * INPUT:   name  -- Pointer to the crate name text to convert into a crate type.              *
+ *                                                                                             *
+ * OUTPUT:  Returns with the crate name converted into a crate type.                           *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/12/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+CrateType Crate_From_Name(char const * name)
+{
+	if (name != NULL) {
+		for (CrateType crate = CRATE_FIRST; crate < CRATE_COUNT; crate++) {
+			if (stricmp(name, CrateNames[crate]) == 0) return(crate);
+		}
+	}
+	return(CRATE_MONEY);
+}
+
+
+/***********************************************************************************************
+ * Owner_From_Name -- Convert an owner name into a bitfield.                                   *
+ *                                                                                             *
+ *    This will take an owner specification and convert it into a bitfield that represents     *
+ *    it. Sometimes this will be just a single house bit, but other times it could be          *
+ *    all the allies or soviet house bits combined.                                            *
+ *                                                                                             *
+ * INPUT:   text  -- Pointer to the text to convert into a house bitfield.                     *
+ *                                                                                             *
+ * OUTPUT:  Returns with the houses specified. The value is in the form of a bit field with    *
+ *          one bit per house type.                                                            *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   08/12/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+int Owner_From_Name(char const * text)
+{
+	int ownable = 0;
+	if (stricmp(text, "soviet") == 0) {
+		ownable |= HOUSEF_SOVIET;
+	} else {
+		if (stricmp(text, "allies") == 0 || stricmp(text, "allied") == 0) {
+			ownable |= HOUSEF_ALLIES;
+		} else {
+			HousesType h = HouseTypeClass::From_Name(text);
+			if (h != HOUSE_NONE && (h < HOUSE_MULTI1 || h > HOUSE_MULTI8)) {
+				ownable |= (1 << h);
+			}
+		}
+	}
+	return(ownable);
+}
+
+
+/***********************************************************************************************
+ * Shake_The_Screen -- Dispatcher that shakes the screen.                                      *
+ *                                                                                             *
+ *    This routine will shake the game screen the number of shakes requested.                  *
+ *                                                                                             *
+ * INPUT:   shakes   -- The number of shakes to shake the screen.                              *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   none                                                                            *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   09/04/1996 BWG : Created.                                                                 *
+ *=============================================================================================*/
+void Shake_The_Screen(int shakes)
+{
+#ifdef WIN32
+	shakes += shakes;
+
+	Hide_Mouse();
+	SeenPage.Blit(HidPage);
+	int oldyoff = 0;
+	int newyoff = 0;
+	while(shakes--) {
+		int x = TickCount;
+//		CountDownTimer = 1;
+		do {
+			newyoff = Sim_Random_Pick(0,2) - 1;
+		} while (newyoff == oldyoff);
+		switch (newyoff) {
+			case -1:
+				HidPage.Blit(SeenPage, 0,2, 0,0, 640,398);
+				break;
+			case 0:
+				HidPage.Blit(SeenPage);
+				break;
+			case 1:
+				HidPage.Blit(SeenPage, 0,0, 0,2, 640,398);
+				break;
+		} while (x == TickCount);
+//		} while (CountDownTimer != 0) ;
+	}
+	HidPage.Blit(SeenPage);
+	Show_Mouse();
+#else
+	Shake_Screen(shakes);
+#endif
+}
+
+
+/***********************************************************************************************
+ * List_Copy -- Makes a copy of a cell offset list.                                            *
+ *                                                                                             *
+ *    This routine will make a copy of a cell offset list. It will only copy the significant   *
+ *    elements of the list limited by the maximum length specified.                            *
+ *                                                                                             *
+ * INPUT:   source   -- Pointer to a cell offset list.                                         *
+ *                                                                                             *
+ *          len      -- The maximum number of cell offset elements to store in to the          *
+ *                      destination list pointer.                                              *
+ *                                                                                             *
+ *          dest     -- Pointer to the destination list to store the copy into.                *
+ *                                                                                             *
+ * OUTPUT:  none                                                                               *
+ *                                                                                             *
+ * WARNINGS:   Ensure that the destination list is large enough to hold the list copy.         *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *   09/04/1996 JLB : Created.                                                                 *
+ *=============================================================================================*/
+void List_Copy(short const * source, int len, short * dest)
+{
+	if (dest == NULL || dest == NULL) {
+		return;
+	}
+
+	while (len > 0) {
+		*dest = *source;
+		if (*dest == REFRESH_EOL) break;
+		dest++;
+		source++;
+		len--;
+	}
+}
+
+
+
+#if 0
+//
+// Boy, this function sure is crummy
+//
+void Crummy(int crumb1, int crumb2)
+{
+	if (Debug_Check_Map && Debug_Heap_Dump) {
+		Mono_Printf("Hi, I'm Crummy.  And so are these: %d, %d\n",crumb1,crumb2);
+	}
+}
+#endif
+
+
+
+/***********************************************************************************************
+ * Game_Registry_Key -- Returns pointer to string containing the registry subkey for the game.
+ *                      This is located under HKEY_LOCAL_MACHINE.
+ * HISTORY:
+ *    11/19/98 ajw : Created
+ *=============================================================================================*/
+const char* Game_Registry_Key()
+{
+#ifdef ENGLISH
+	static char szKey[] = "SOFTWARE\\Westwood\\Red Alert Windows 95 Edition";
+#else
+#ifdef GERMAN
+	static char szKey[] = "SOFTWARE\\Westwood\\Alarmstufe Rot Windows 95 Edition";
+#else
+	static char szKey[] = "SOFTWARE\\Westwood\\Alerte Rouge version Windows 95";
+#endif
+#endif
+	return szKey;
+}
+
+
+/***********************************************************************************************
+ * Is_Counterstrike_Installed -- Function to determine the availability of the CS expansion    *
+ *                                                                                             *
+ *                                                                                             *
+ *                                                                                             *
+ * INPUT:    Nothing                                                                           *
+ *                                                                                             *
+ * OUTPUT:   true if Counterstrike is present                                                  *
+ *                                                                                             *
+ * WARNINGS: None                                                                              *
+ *                                                                                             *
+ * HISTORY:                                                                                    *
+ *    4/1/97 11:39PM ST : Created                                                              *
+ *=============================================================================================*/
+bool Is_Counterstrike_Installed (void)
+{
+	//	ajw 9/29/98
+	static bool	bAlreadyChecked = false;
+	static bool bInstalled = false;
+
+	if( !bAlreadyChecked )
+	{
+		HKEY hKey;
+		if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, Game_Registry_Key(), 0, KEY_READ, &hKey ) != ERROR_SUCCESS )
+			return false;
+		DWORD dwValue;
+		DWORD dwBufSize = sizeof( DWORD );
+		if( RegQueryValueEx( hKey, "CStrikeInstalled", 0, NULL, (LPBYTE)&dwValue, &dwBufSize ) != ERROR_SUCCESS )
+			bInstalled = false;
+		else
+			bInstalled = (bool)dwValue;			//	(Presumably true, if it's there...)
+
+		RegCloseKey( hKey );
+		bAlreadyChecked = true;
+	}
+	return bInstalled;
+
+//	RawFileClass file("EXPAND.MIX");
+//	return(file.Is_Available());
+}
+
+#ifdef FIXIT_CSII	//	checked - ajw 9/28/98
+/***********************************************************************************************
+ *=============================================================================================*/
+bool Is_Aftermath_Installed (void)
+{
+	//	ajw 9/29/98
+	static bool	bAlreadyChecked = false;
+	static bool bInstalled = false;
+
+	if( !bAlreadyChecked )
+	{
+		HKEY hKey;
+		if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, Game_Registry_Key(), 0, KEY_READ, &hKey ) != ERROR_SUCCESS )
+			return false;
+		DWORD dwValue;
+		DWORD dwBufSize = sizeof( DWORD );
+		if( RegQueryValueEx( hKey, "AftermathInstalled", 0, NULL, (LPBYTE)&dwValue, &dwBufSize ) != ERROR_SUCCESS )
+			bInstalled = false;
+		else
+			bInstalled = (bool)dwValue;			//	(Presumably true, if it's there...)
+
+		RegCloseKey( hKey );
+		bAlreadyChecked = true;
+	}
+	return bInstalled;
+
+//	RawFileClass file("EXPAND2.MIX");
+//	return(file.Is_Available());
+}
+#endif
+
+#ifdef FIXIT_CSII	//	checked - ajw 9/28/98
+void Enable_Secret_Units(void)
+{
+#if 0
+	SecretUnitsEnabled=true;
+	UnitTypeClass::As_Reference(UNIT_PHASE).Level=10;
+	VesselTypeClass::As_Reference(VESSEL_CARRIER).Level=10;
+	for (int index = 0; index < Buildings.Count(); index++) {
+		Buildings.Ptr(index)->Update_Buildables();
+	}
+#endif
+}
+#endif
+
+#ifdef FIXIT_VERSION_3
+bool Force_Scenario_Available( const char* szName )
+{
+	//	Calls Force_CD_Available based on type of scenario. szName is assumed to be an official scenario here.
+	if( Is_Mission_Counterstrike( (char*)szName ) )
+	{
+//		debugprint( "Force_Scenario_Available requiring disk 4...\n" );
+		return Force_CD_Available( 4 );
+	}
+	else if( Is_Mission_Aftermath( (char*)szName ) )
+	{
+//		debugprint( "Force_Scenario_Available requiring disk 3...\n" );
+		return Force_CD_Available( 3 );
+	}
+	return true;
+}
+#endif

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