mirror of
https://github.com/electronicarts/CnC_Red_Alert.git
synced 2025-12-15 23:21:40 -05:00
Initial commit of Command & Conquer Red Alert source code.
This commit is contained in:
594
LAUNCH/LAUNCH.ASM
Normal file
594
LAUNCH/LAUNCH.ASM
Normal file
@@ -0,0 +1,594 @@
|
||||
;
|
||||
; 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 -- launcher program *
|
||||
;* *
|
||||
;* File Name : launch.asm *
|
||||
;* *
|
||||
;* Programmer : Steve Tall *
|
||||
;* *
|
||||
;* Start Date : August 19, 1995 *
|
||||
;* *
|
||||
;* Last Update : Modified for RA, October 14th, 1996 [ST] *
|
||||
;* *
|
||||
;* Build : Compile and link with MASM 6 *
|
||||
;* Note that masm will complain there is no stack because *
|
||||
;* we are not using a simplified segment model *
|
||||
;* *
|
||||
;*---------------------------------------------------------------------------------------------*
|
||||
;* Functions: *
|
||||
;* Start -- Program entry point *
|
||||
;* Mem_Error -- report an out of memory error (not a function) *
|
||||
;* Disc_Error -- report an out of disk space error (not a function) *
|
||||
;* Delete_Swaps -- Deletes old swap files from the game directory *
|
||||
;* Setup_Environment -- Adds environment strings required for DOS4G professional *
|
||||
;* *
|
||||
;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *
|
||||
|
||||
|
||||
|
||||
|
||||
TITLE "Red Alert launcher"
|
||||
|
||||
.386
|
||||
|
||||
|
||||
;----------------------------------------------------------------------------------------------
|
||||
; Defines for DOS system functions.
|
||||
;
|
||||
DOS_LOAD_AND_EXEC =4B00H
|
||||
DOS_ALLOC =48H
|
||||
DOS_FREE =49h
|
||||
DOS_GET_FREE_DISC_SPACE =36H
|
||||
DOS_SET_DIRECTORY =3BH
|
||||
DOS =21H
|
||||
DOS_SET_DTA =1AH
|
||||
DOS_FIND_FIRST =4EH
|
||||
DOS_FIND_NEXT =4FH
|
||||
DOS_DELETE_FILE =41H
|
||||
DOS_SET_ATTRIBUTES =43H
|
||||
DOS_SET_DRIVE =0EH
|
||||
DOS_RESIZE_ALLOCATION =4Ah
|
||||
DOS_EXIT =4ch
|
||||
DOS_PRINT_STRING =9
|
||||
|
||||
|
||||
;----------------------------------------------------------------------------------------------
|
||||
; Defines for keyboard BIOS functions
|
||||
;
|
||||
KEYBOARD_BIOS =16h
|
||||
BIOS_CHECK_KEYBOARD =11h
|
||||
BIOS_GET_KEYSTROKE =10h
|
||||
|
||||
|
||||
;----------------------------------------------------------------------------------------------
|
||||
; Defines for video bios functions
|
||||
;
|
||||
VIDEO_BIOS =10h
|
||||
BIOS_SET_VIDEO_MODE_3 =0003h
|
||||
|
||||
|
||||
;----------------------------------------------------------------------------------------------
|
||||
; Misc defines
|
||||
;
|
||||
MEM_REQUIRED =1024 * 400 ;Check for 400k low memory
|
||||
INIT_FREE_DISK_SPACE =15*1024*1024 ;C&C requirement for disc space
|
||||
|
||||
MY_ALLOCATION =1536/16 ;only allow myself 1.5k to run in incl. psp and stack
|
||||
;you can find out how much space the program needs
|
||||
;by running WDISASM LAUNCH.OBJ
|
||||
;dont forget to add 256 bytes on for the psp
|
||||
|
||||
|
||||
include <pcmacro.16>
|
||||
|
||||
|
||||
;----------------------------------------------------------------------------------------------
|
||||
; Simplified segment models are for wimmin
|
||||
;
|
||||
; We want 32 bit instructions in a 16 bit segment
|
||||
;
|
||||
|
||||
_code segment para public use16 'code'
|
||||
|
||||
assume ds:_data
|
||||
assume es:_data
|
||||
assume ss:_data
|
||||
assume cs:_code
|
||||
|
||||
|
||||
|
||||
;*************************************************************************************************
|
||||
;* Start -- Program entry point *
|
||||
;* *
|
||||
;* *
|
||||
;* INPUT: nothing *
|
||||
;* *
|
||||
;* OUTPUT: DOS return code from spawning the game *
|
||||
;* *
|
||||
;* HISTORY: *
|
||||
;* 08/19/95 ST: Created. *
|
||||
;*===============================================================================================*
|
||||
|
||||
Start: ;
|
||||
; Set up the segments and the stack pointer
|
||||
;
|
||||
cli
|
||||
mov ax,_data
|
||||
mov ds,ax
|
||||
mov [Psp],es
|
||||
mov ss,ax
|
||||
mov sp,offset MyStack
|
||||
sti
|
||||
|
||||
;
|
||||
; Modify the starting memory allocation to free enough for the game proper
|
||||
;
|
||||
save ax
|
||||
mov bx,MY_ALLOCATION
|
||||
mov ah,DOS_RESIZE_ALLOCATION
|
||||
int DOS
|
||||
restore ax
|
||||
bcs Mem_Error
|
||||
|
||||
;
|
||||
; See if we have enough free memory to launch
|
||||
;
|
||||
mov ah,DOS_ALLOC
|
||||
mov bx,-1 ;I want it all! hahaha
|
||||
int DOS
|
||||
jnc Mem_Error ;shouldnt ever succeed but...
|
||||
cmp ax,8
|
||||
jnz Mem_Error
|
||||
cmp bx,(MEM_REQUIRED/16)-MY_ALLOCATION
|
||||
bls Mem_Error ;oh dear
|
||||
|
||||
;
|
||||
; See if there is enough free disc space to launch
|
||||
;
|
||||
xor dl,dl
|
||||
mov ah,DOS_GET_FREE_DISC_SPACE
|
||||
int DOS
|
||||
|
||||
; dos get free disc space returns with the following
|
||||
; ax - sectors per cluster
|
||||
; bx - number of available clusters
|
||||
; cx - bytes per sector
|
||||
; dx - cluster on the drive
|
||||
|
||||
mul bx ;clusters avail*sectors per cluster
|
||||
shl edx,16
|
||||
mov dx,ax
|
||||
mov eax,edx
|
||||
and ecx,65535
|
||||
mul ecx ;*bytes per sector
|
||||
cmp eax,INIT_FREE_DISK_SPACE
|
||||
blo Disc_Error
|
||||
|
||||
;
|
||||
; Get the directory we were run from and cd to it
|
||||
;
|
||||
mov es,[Psp]
|
||||
mov bx,2ch
|
||||
mov es,es:[bx] ;es points to env
|
||||
xor di,di
|
||||
xor al,al
|
||||
mov cx,-1
|
||||
|
||||
;
|
||||
; Search for 0,0 as that aways terminates the environment block
|
||||
;
|
||||
@@again: repnz scasb
|
||||
cmp_b es:[di],al
|
||||
jnz @@again
|
||||
lea si,[di+3] ;skip length word and second zero
|
||||
|
||||
;
|
||||
; Copy the directory name to temporary workspace
|
||||
;
|
||||
mov di,si
|
||||
mov cx,-1
|
||||
repnz scasb
|
||||
neg cx
|
||||
mov bx,cx
|
||||
mov cx,-1
|
||||
std
|
||||
mov al,'\'
|
||||
repnz scasb
|
||||
neg cx
|
||||
sub bx,cx
|
||||
mov cx,bx
|
||||
inc cx
|
||||
cld
|
||||
|
||||
mov di,offset Dta
|
||||
push ds
|
||||
mov ax,es
|
||||
mov bx,ds
|
||||
mov es,bx
|
||||
mov ds,ax
|
||||
rep movsb
|
||||
xor al,al
|
||||
stosb
|
||||
pop ds
|
||||
|
||||
;
|
||||
; Actually set the drive and path
|
||||
;
|
||||
mov dl,[Dta]
|
||||
sub dl,'A'
|
||||
mov ah,DOS_SET_DRIVE
|
||||
int DOS
|
||||
|
||||
mov dx,offset Dta
|
||||
mov ah,DOS_SET_DIRECTORY
|
||||
int DOS
|
||||
|
||||
;
|
||||
; Delete all the old swap files
|
||||
;
|
||||
mov dx,offset Dta
|
||||
mov ah,DOS_SET_DTA
|
||||
int DOS
|
||||
call Delete_Swaps
|
||||
|
||||
;
|
||||
; Add in the environment strings required for DOS4G professional
|
||||
;
|
||||
call Setup_Environment
|
||||
|
||||
;
|
||||
; Set up the parameters to launch c&c
|
||||
;
|
||||
mov es,[Psp]
|
||||
mov dx,offset GameName
|
||||
mov bx,offset GameParameterBlock
|
||||
|
||||
mov ax,[EnvironmentSegment] ;Initialised by Setup_Environment
|
||||
mov_w [bx],ax ;ptr to environment
|
||||
|
||||
;
|
||||
; just pass the command tail we got straight through
|
||||
;
|
||||
mov ax,80h
|
||||
mov [bx+2],ax ;offset of command tail
|
||||
mov ax,[Psp]
|
||||
mov [bx+4],ax ;segment of command tail
|
||||
|
||||
mov es,ax
|
||||
mov ax,es:[2ch]
|
||||
mov [bx+8],ax ;segment of first fcb
|
||||
mov [bx+12],ax ;segment of second fcb
|
||||
|
||||
mov ax,_data
|
||||
mov es,ax
|
||||
|
||||
;
|
||||
; Run the main game program
|
||||
;
|
||||
mov ax,DOS_LOAD_AND_EXEC ;load and execute program
|
||||
int DOS
|
||||
|
||||
|
||||
;
|
||||
; Restore teh environment memory
|
||||
;
|
||||
mov ax,[EnvironmentSegment]
|
||||
test ax,ax
|
||||
jz @@no_free
|
||||
mov es,ax
|
||||
mov ah,DOS_FREE
|
||||
int DOS
|
||||
|
||||
|
||||
@@no_free: ;
|
||||
; Quit to DOS
|
||||
;
|
||||
mov ah,DOS_EXIT
|
||||
int DOS
|
||||
|
||||
|
||||
|
||||
|
||||
;*************************************************************************************************
|
||||
;* Mem_Error -- Print a memory error message and quit *
|
||||
;* *
|
||||
;* *
|
||||
;* INPUT: nothing *
|
||||
;* *
|
||||
;* OUTPUT: undefined *
|
||||
;* *
|
||||
;* HISTORY: *
|
||||
;* 08/19/95 ST: Created. *
|
||||
;*===============================================================================================*
|
||||
Mem_Error: mov ax,BIOS_SET_VIDEO_MODE_3
|
||||
int VIDEO_BIOS
|
||||
mov dx,offset MemErrorTxt
|
||||
mov ah,DOS_PRINT_STRING
|
||||
int DOS
|
||||
|
||||
mov dx,offset MoreInfoTxt
|
||||
Error_In: mov ah,DOS_PRINT_STRING
|
||||
int DOS
|
||||
|
||||
;
|
||||
; wait for keypress
|
||||
;
|
||||
|
||||
nochar: mov ah,BIOS_CHECK_KEYBOARD
|
||||
int KEYBOARD_BIOS
|
||||
beq nochar
|
||||
|
||||
;
|
||||
; get the ket out of the buffer
|
||||
;
|
||||
mov ah,BIOS_GET_KEYSTROKE
|
||||
int KEYBOARD_BIOS
|
||||
|
||||
;
|
||||
; Quit to DOS
|
||||
;
|
||||
mov ah,DOS_EXIT
|
||||
int DOS
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
;*************************************************************************************************
|
||||
;* Disc_Error -- Prints a disk error message and exits *
|
||||
;* *
|
||||
;* *
|
||||
;* INPUT: nothing *
|
||||
;* *
|
||||
;* OUTPUT: DOS return code from spawning the game *
|
||||
;* *
|
||||
;* HISTORY: *
|
||||
;* 08/19/95 ST: Created. *
|
||||
;*===============================================================================================*
|
||||
Disc_Error: mov ax,BIOS_SET_VIDEO_MODE_3
|
||||
int VIDEO_BIOS
|
||||
mov dx,offset DiscErrorTxt
|
||||
jmp Error_In
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
;*************************************************************************************************
|
||||
;* Setup_Environment -- Create a new environment block with the set DOS4GVM= stuff *
|
||||
;* *
|
||||
;* *
|
||||
;* INPUT: nothing *
|
||||
;* *
|
||||
;* OUTPUT: nothing *
|
||||
;* *
|
||||
;* Note: Modifies the global variable 'EnvironmentStrings' to point to the start of our new *
|
||||
;* environment block. This memory will need to be freed later. *
|
||||
;* *
|
||||
;* HISTORY: *
|
||||
;* 10/14/96 ST: Created. *
|
||||
;*===============================================================================================*
|
||||
Setup_Environment proc near
|
||||
|
||||
;
|
||||
; Point to default environment.
|
||||
;
|
||||
mov [EnvironmentSegment],0
|
||||
|
||||
;
|
||||
; Get the address of our environment block into es
|
||||
;
|
||||
mov es,[Psp]
|
||||
mov bx,2ch
|
||||
mov es,es:[bx] ;es points to env
|
||||
|
||||
;
|
||||
; Search for the end of the block to get its length
|
||||
;
|
||||
xor di,di
|
||||
xor al,al
|
||||
mov cx,-1
|
||||
|
||||
@@search: repnz scasb
|
||||
cmp_b es:[di],al
|
||||
jnz @@search
|
||||
|
||||
;
|
||||
; di is length of environment block
|
||||
;
|
||||
lea bx,[di+256] ; a little extra to be sure.
|
||||
|
||||
;
|
||||
; Allocate memory for a copy of the environment.
|
||||
;
|
||||
push di
|
||||
mov ah,DOS_ALLOC
|
||||
shr bx,4 ;needs to be number of paragraphs
|
||||
int DOS
|
||||
jnc @@ok
|
||||
|
||||
;
|
||||
; Oops. Not enough memory. We are screwed so just exit.
|
||||
;
|
||||
pop di
|
||||
jmp @@out
|
||||
|
||||
@@ok: ;
|
||||
; Save the pointer to our new environment
|
||||
; We can also use this to free the memory later
|
||||
;
|
||||
mov [EnvironmentSegment],ax
|
||||
|
||||
;
|
||||
; Copy the original environment to the newly alloced memory
|
||||
;
|
||||
mov es,ax
|
||||
pop cx ; size to copy
|
||||
|
||||
push ds
|
||||
mov ds,[Psp]
|
||||
mov bx,2ch
|
||||
mov ds,ds:[bx] ;ds points to original environment
|
||||
|
||||
xor si,si
|
||||
xor di,di
|
||||
rep movsb
|
||||
pop ds
|
||||
|
||||
mov si,offset Dos4gEnvironment
|
||||
|
||||
@@copy_loop: lodsb
|
||||
stosb
|
||||
test al,al
|
||||
jnz @@copy_loop
|
||||
|
||||
;
|
||||
; Copy the final zero. The environment must be terminated by 2 zeros.
|
||||
;
|
||||
movsb
|
||||
|
||||
@@out: ret
|
||||
|
||||
Setup_Environment endp
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
;*************************************************************************************************
|
||||
;* Delete_Swaps -- Delete any swap files left over from a previous game *
|
||||
;* *
|
||||
;* *
|
||||
;* INPUT: nothing *
|
||||
;* *
|
||||
;* OUTPUT: nothing *
|
||||
;* *
|
||||
;* HISTORY: *
|
||||
;* 08/19/95 ST: Created. *
|
||||
;*===============================================================================================*
|
||||
Delete_Swaps proc near
|
||||
|
||||
;
|
||||
; Use 'Find first/next' to find the swap files
|
||||
;
|
||||
mov dx,offset SwapName
|
||||
mov cx,7 ;attributes
|
||||
mov ah,DOS_FIND_FIRST
|
||||
int DOS
|
||||
bcs @@out ;no matching files
|
||||
|
||||
;
|
||||
; Make sure it isn't read only
|
||||
;
|
||||
@@loop: mov dx,offset Dta+1eh
|
||||
mov ah,DOS_SET_ATTRIBUTES
|
||||
mov al,1
|
||||
xor cx,cx ;attributes
|
||||
int DOS
|
||||
|
||||
;
|
||||
; Delete the file
|
||||
;
|
||||
mov dx,offset Dta+1eh
|
||||
mov ah,DOS_DELETE_FILE
|
||||
int DOS
|
||||
|
||||
;
|
||||
; Find the next one
|
||||
;
|
||||
mov ah,DOS_FIND_NEXT
|
||||
int DOS
|
||||
bcc @@loop
|
||||
|
||||
@@out: ret
|
||||
|
||||
Delete_Swaps endp
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_code ends ;end of code segment
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
;----------------------------------------------------------------------------------------------
|
||||
;
|
||||
; Complex data segment
|
||||
;
|
||||
;
|
||||
|
||||
_data segment dword public use16 'data'
|
||||
|
||||
|
||||
EnvironmentSegment dw 0 ;ptr to environment to pass to child process
|
||||
Psp dw 0 ;segment addr of program segment prefix
|
||||
GameParameterBlock db 16h dup (0) ;required parameters for DOS launch
|
||||
|
||||
GameName db "GAME.DAT",0 ;this is the name of the app to be spawned
|
||||
SwapName db "*.SWP",0 ;swap files always have a .SWP extension
|
||||
|
||||
;
|
||||
; Environment to be set for DOS4G professional
|
||||
;
|
||||
Dos4gEnvironment db "DOS4GVM=SwapMin:12M,SwapInc:0",0,0
|
||||
|
||||
;
|
||||
; Error and warning messages
|
||||
;
|
||||
MemErrorTxt db "Warning - There is very little free conventional DOS memory in the system.",13,10,"$"
|
||||
|
||||
DiscErrorTxt db "Error - insufficient disk space to run Red Alert."
|
||||
db 13,10,"Red Alert requires 15,728,640 bytes of free disk space.",13,10 ;this string will
|
||||
;run into the next because
|
||||
;there is no '$'
|
||||
MoreInfoTxt db "Please read the Red Alert manual for more information.",13,10,13,10
|
||||
db "Press a key to continue.",13,10,"$"
|
||||
|
||||
|
||||
Dta db 128 dup (0) ;enough for complete path
|
||||
|
||||
|
||||
;*************************************************************
|
||||
;
|
||||
; The stack
|
||||
;
|
||||
|
||||
StackSpace db 256 dup (0) ;256 byte stack!
|
||||
MyStack label byte ;The stack starts here and grows down.
|
||||
|
||||
EndCode label byte ;The end of the data segment
|
||||
|
||||
|
||||
_data ends
|
||||
|
||||
end Start
|
||||
Reference in New Issue
Block a user