Repository: electronicarts/CnC_Red_Alert
Branch: main
Commit: 0dc09bb1d618
Files: 2066
Total size: 28.0 MB
Directory structure:
gitextract_rc2spqh1/
├── CODE/
│ ├── 2KEYFBUF.ASM
│ ├── 2KEYFRAM.CPP
│ ├── 2SUPPORT.ASM
│ ├── 2TXTPRNT.ASM
│ ├── AADATA.CPP
│ ├── ABSTRACT.CPP
│ ├── ABSTRACT.H
│ ├── ADAMTEMP.MAK
│ ├── ADATA.CPP
│ ├── ADPCM.CPP
│ ├── AIRCRAFT.CPP
│ ├── AIRCRAFT.H
│ ├── ALLOC.CPP
│ ├── ANIM.CPP
│ ├── ANIM.CPP.BAK
│ ├── ANIM.H
│ ├── AUDIO.CPP
│ ├── AUDIO.CPP.BAK
│ ├── AUDIO.H
│ ├── B64PIPE.CPP
│ ├── B64PIPE.H
│ ├── B64STRAW.CPP
│ ├── B64STRAW.H
│ ├── BAR.CPP
│ ├── BAR.H
│ ├── BASE.CPP
│ ├── BASE.H
│ ├── BASE64.CPP
│ ├── BASE64.H
│ ├── BBDATA.CPP
│ ├── BDATA.CPP
│ ├── BENCH.CPP
│ ├── BENCH.H
│ ├── BFILE.MAK
│ ├── BFILE2.MAK
│ ├── BFIOFILE.CPP
│ ├── BFIOFILE.H
│ ├── BIGCHECK.CPP
│ ├── BIGCHECK.H
│ ├── BLOWFISH.CPP
│ ├── BLOWFISH.H
│ ├── BLOWPIPE.CPP
│ ├── BLOWPIPE.H
│ ├── BLWSTRAW.CPP
│ ├── BLWSTRAW.H
│ ├── BMP8.CPP
│ ├── BMP8.H
│ ├── BUFF.CPP
│ ├── BUFF.H
│ ├── BUFFERX.H
│ ├── BUGS.TXT
│ ├── BUILDING.CPP
│ ├── BUILDING.H
│ ├── BULLET.CPP
│ ├── BULLET.H
│ ├── C&CZERO.PJT
│ ├── CARGO.CPP
│ ├── CARGO.H
│ ├── CARRY.CPP
│ ├── CARRY.H
│ ├── CCDDE.CPP
│ ├── CCDDE.H
│ ├── CCFILE.CPP
│ ├── CCFILE.H
│ ├── CCINI.CPP
│ ├── CCINI.H
│ ├── CCMPATH.CPP
│ ├── CCPTR.CPP
│ ├── CCPTR.H
│ ├── CCTEN.CPP
│ ├── CC_ICON.RC
│ ├── CC_ICON.RH
│ ├── CDATA.CPP
│ ├── CDFILE.CPP
│ ├── CDFILE.H
│ ├── CELL.CPP
│ ├── CELL.H
│ ├── CHECKBOX.CPP
│ ├── CHECKBOX.H
│ ├── CHEKLIST.CPP
│ ├── CHEKLIST.H
│ ├── CLASS.CPP
│ ├── CO-WC32.LNT
│ ├── COLRLIST.CPP
│ ├── COLRLIST.H
│ ├── COMBAT.CPP
│ ├── COMBUF.CPP
│ ├── COMBUF.H
│ ├── COMINIT.CPP
│ ├── COMINIT.H
│ ├── COMPAT.H
│ ├── COMQUEUE.CPP
│ ├── COMQUEUE.H
│ ├── CONFDLG.CPP
│ ├── CONFDLG.H
│ ├── CONNECT.CPP
│ ├── CONNECT.CPP.BAK
│ ├── CONNECT.H
│ ├── CONNMGR.H
│ ├── CONQUER.CPP
│ ├── CONQUER.CPP.BAK
│ ├── CONQUER.H
│ ├── CONQUER.IDE
│ ├── CONQUER.LNT
│ ├── CONST.CPP
│ ├── CONTROL.CPP
│ ├── CONTROL.H
│ ├── COORD.CPP
│ ├── COORDA.ASM
│ ├── CPUID.ASM
│ ├── CRATE.CPP
│ ├── CRATE.H
│ ├── CRC.CPP
│ ├── CRC.H
│ ├── CRCPIPE.CPP
│ ├── CRCPIPE.H
│ ├── CRCSTRAW.CPP
│ ├── CRCSTRAW.H
│ ├── CREDITS.CPP
│ ├── CREDITS.H
│ ├── CREW.CPP
│ ├── CREW.H
│ ├── CSTRAW.CPP
│ ├── CSTRAW.H
│ ├── CWSTUB.C
│ ├── DDE.CPP
│ ├── DDE.H
│ ├── DEBUG.CPP
│ ├── DEBUG.H
│ ├── DEFINES.H
│ ├── DESCDLG.CPP
│ ├── DESCDLG.H
│ ├── DIAL8.CPP
│ ├── DIAL8.H
│ ├── DIALOG.CPP
│ ├── DIBAPI.H
│ ├── DIBFILE.CPP
│ ├── DIBUTIL.CPP
│ ├── DIBUTIL.H
│ ├── DISPLAY.CPP
│ ├── DISPLAY.H
│ ├── DOOR.CPP
│ ├── DOOR.H
│ ├── DPMI.CPP
│ ├── DPMI.H
│ ├── DRIVE.CPP
│ ├── DRIVE.H
│ ├── DROP.CPP
│ ├── DROP.H
│ ├── DTABLE.CPP
│ ├── DYNAVEC.CPP
│ ├── EDIT.CPP
│ ├── EDIT.H
│ ├── EGOS.CPP
│ ├── EGOS.H
│ ├── ENDING.CPP
│ ├── ENDING.H
│ ├── ENG/
│ │ ├── CONQUER.BAK
│ │ ├── CONQUER.TXT
│ │ ├── CREDITS.BAK
│ │ ├── CREDITS.TXT
│ │ ├── DEBUG.BAK
│ │ ├── DEBUG.TXT
│ │ ├── ENG/
│ │ │ ├── CONQUER.TXT
│ │ │ └── CREDITS.TXT
│ │ ├── FRE/
│ │ │ ├── CONQUER.TXT
│ │ │ └── CREDITS.TXT
│ │ ├── GER/
│ │ │ ├── CONQUER.TXT
│ │ │ └── CREDITS.TXT
│ │ └── MESSAGE.TXT
│ ├── EVENT.CPP
│ ├── EVENT.H
│ ├── EXPAND.CPP
│ ├── EXTERNS.H
│ ├── FACE.CPP
│ ├── FACE.H
│ ├── FACING.CPP
│ ├── FACING.H
│ ├── FACTORY.CPP
│ ├── FACTORY.H
│ ├── FAKESOCK.H
│ ├── FIELD.CPP
│ ├── FIELD.H
│ ├── FILE.CPP
│ ├── FILEPCX.H
│ ├── FINDPATH.CPP
│ ├── FIXED.CPP
│ ├── FIXED.H
│ ├── FLASHER.CPP
│ ├── FLASHER.H
│ ├── FLY.CPP
│ ├── FLY.H
│ ├── FOOT.CPP
│ ├── FOOT.H
│ ├── FOREIGN.TXT
│ ├── FTIMER.H
│ ├── FUNCTION.H
│ ├── FUNCTION.I
│ ├── FUSE.CPP
│ ├── FUSE.H
│ ├── GADGET.CPP
│ ├── GADGET.H
│ ├── GAMEDLG.CPP
│ ├── GAMEDLG.H
│ ├── GAUGE.CPP
│ ├── GAUGE.H
│ ├── GETCPU.CPP
│ ├── GLOBALS.CPP
│ ├── GOPTIONS.CPP
│ ├── GOPTIONS.H
│ ├── GSCREEN.CPP
│ ├── GSCREEN.H
│ ├── HDATA.CPP
│ ├── HEADER.MAC
│ ├── HEAP.CPP
│ ├── HEAP.H
│ ├── HELP.CPP
│ ├── HELP.H
│ ├── HOUSE.CPP
│ ├── HOUSE.H
│ ├── HSV.CPP
│ ├── HSV.H
│ ├── ICONLIST.CPP
│ ├── ICONLIST.H
│ ├── IDATA.CPP
│ ├── INFANTRY.CPP
│ ├── INFANTRY.H
│ ├── INI.CPP
│ ├── INI.H
│ ├── INIBIN.CPP
│ ├── INICODE.CPP
│ ├── INIT.CPP
│ ├── INIT.CPP.BAK
│ ├── INLINE.H
│ ├── INT.CPP
│ ├── INT.H
│ ├── INTERNET.CPP
│ ├── INTERNET.H
│ ├── INTERPAL.CPP
│ ├── INTRO.CPP
│ ├── INTRO.H
│ ├── IOMAP.CPP
│ ├── IOOBJ.CPP
│ ├── IPX.CPP
│ ├── IPX.H
│ ├── IPX95.CPP
│ ├── IPX95.H
│ ├── IPXADDR.CPP
│ ├── IPXADDR.H
│ ├── IPXCONN.CPP
│ ├── IPXCONN.H
│ ├── IPXGCONN.CPP
│ ├── IPXGCONN.H
│ ├── IPXMGR.CPP
│ ├── IPXMGR.H
│ ├── IPXPROT.ASM
│ ├── IPXREAL.ASM
│ ├── ITABLE.CPP
│ ├── JOEMAKE.BAT
│ ├── JSHELL.CPP
│ ├── JSHELL.H
│ ├── KEY.CPP
│ ├── KEY.H
│ ├── KEYBOARD.CPP
│ ├── KEYBOARD.H
│ ├── KEYFBUFF.ASM
│ ├── KEYFBUFF.ASM.BAK
│ ├── KEYFRAME.CPP
│ ├── LANGUAGE.H
│ ├── LAYER.CPP
│ ├── LAYER.H
│ ├── LCW.CPP
│ ├── LCW.H
│ ├── LCWCOMP.ASM
│ ├── LCWPIPE.CPP
│ ├── LCWPIPE.H
│ ├── LCWSTRAW.CPP
│ ├── LCWSTRAW.H
│ ├── LCWUNCMP.CPP
│ ├── LED.H
│ ├── LIBRARY.TXT
│ ├── LINK.CPP
│ ├── LINK.H
│ ├── LINT.H
│ ├── LIST.CPP
│ ├── LIST.H
│ ├── LISTNODE.H
│ ├── LOADDLG.CPP
│ ├── LOADDLG.H
│ ├── LOGIC.CPP
│ ├── LOGIC.H
│ ├── LZO.H
│ ├── LZO1X.H
│ ├── LZO1X_C.CPP
│ ├── LZO1X_D.CPP
│ ├── LZOCONF.H
│ ├── LZOPIPE.CPP
│ ├── LZOPIPE.H
│ ├── LZOSTRAW.CPP
│ ├── LZOSTRAW.H
│ ├── LZO_CONF.H
│ ├── LZW.CPP
│ ├── LZW.H
│ ├── LZWOTRAW.CPP
│ ├── LZWPIPE.CPP
│ ├── LZWPIPE.H
│ ├── LZWSTRAW.CPP
│ ├── LZWSTRAW.H
│ ├── MAKEFILE
│ ├── MAKE_ALL.BAT
│ ├── MAP.CPP
│ ├── MAP.H
│ ├── MAPEDDLG.CPP
│ ├── MAPEDIT.CPP
│ ├── MAPEDIT.H
│ ├── MAPEDPLC.CPP
│ ├── MAPEDSEL.CPP
│ ├── MAPEDTM.CPP
│ ├── MAPSEL.CPP
│ ├── MCI.CPP
│ ├── MCI.H
│ ├── MCIMOVIE.CPP
│ ├── MCIMOVIE.H
│ ├── MEMCHECK.H
│ ├── MENUS.CPP
│ ├── MESSAGE.H
│ ├── MISSION.CPP
│ ├── MISSION.H
│ ├── MIXFILE.CPP
│ ├── MIXFILE.H
│ ├── MONOC.CPP
│ ├── MONOC.H
│ ├── MOUSE.CPP
│ ├── MOUSE.H
│ ├── MOVIE.H
│ ├── MP.CPP
│ ├── MP.H
│ ├── MPGSET.CPP
│ ├── MPGSET.H
│ ├── MPLAYER.CPP
│ ├── MPLIB.CPP
│ ├── MPLPC.CPP
│ ├── MPMGRD.CPP
│ ├── MPMGRD.H
│ ├── MPMGRW.CPP
│ ├── MPMGRW.H
│ ├── MPU.CPP
│ ├── MPU.H
│ ├── MSGBOX.CPP
│ ├── MSGBOX.CPP.BAK
│ ├── MSGBOX.H
│ ├── MSGLIST.CPP
│ ├── MSGLIST.H
│ ├── NETDLG.CPP
│ ├── NOSEQCON.CPP
│ ├── NOSEQCON.H
│ ├── NULLCONN.CPP
│ ├── NULLCONN.H
│ ├── NULLDLG.CPP
│ ├── NULLMGR.CPP
│ ├── NULLMGR.H
│ ├── NUMBER.CPP
│ ├── OBJECT.CPP
│ ├── OBJECT.H
│ ├── ODATA.CPP
│ ├── OPTIONS.CPP
│ ├── OPTIONS.H
│ ├── OPTIONS.LNT
│ ├── OVERLAY.CPP
│ ├── OVERLAY.H
│ ├── PACKET.CPP
│ ├── PACKET.H
│ ├── PIPE.CPP
│ ├── PIPE.H
│ ├── PK.CPP
│ ├── PK.H
│ ├── PKPIPE.CPP
│ ├── PKPIPE.H
│ ├── PKSTRAW.CPP
│ ├── PKSTRAW.H
│ ├── POWER.CPP
│ ├── POWER.H
│ ├── PROFILE.CPP
│ ├── PROFILE.DEF
│ ├── QUEUE.CPP
│ ├── QUEUE.H
│ ├── RA-HDOS.PJT
│ ├── RA-HOME.PJT
│ ├── RA95.PJT
│ ├── RADAR.CPP
│ ├── RADAR.H
│ ├── RADIO.CPP
│ ├── RADIO.H
│ ├── RADOS.PJT
│ ├── RAMFILE.CPP
│ ├── RAMFILE.H
│ ├── RAND.CPP
│ ├── RANDOM.CPP
│ ├── RANDOM.H
│ ├── RAWFILE.CPP
│ ├── RAWFILE.H
│ ├── RAWOLAPI.CPP
│ ├── RAWOLAPI.H
│ ├── READLINE.CPP
│ ├── READLINE.H
│ ├── RECT.CPP
│ ├── RECT.H
│ ├── REDALERT.IDE
│ ├── REGION.H
│ ├── REINF.CPP
│ ├── RGB.CPP
│ ├── RGB.H
│ ├── RNDSTRAW.CPP
│ ├── RNDSTRAW.H
│ ├── RNG.H
│ ├── ROTBMP.CPP
│ ├── ROTBMP.H
│ ├── RULES.CPP
│ ├── RULES.H
│ ├── RULES.MAK
│ ├── SAVEDLG.H
│ ├── SAVELOAD.CPP
│ ├── SCENARIO.CPP
│ ├── SCENARIO.H
│ ├── SCORE.CPP
│ ├── SCORE.H
│ ├── SCREEN.H
│ ├── SCROLL.CPP
│ ├── SCROLL.H
│ ├── SDATA.CPP
│ ├── SEARCH.H
│ ├── SEDITDLG.CPP
│ ├── SEDITDLG.H
│ ├── SENDFILE.CPP
│ ├── SEQCONN.CPP
│ ├── SEQCONN.H
│ ├── SESSION.CPP
│ ├── SESSION.H
│ ├── SHA.CPP
│ ├── SHA.H
│ ├── SHAPEBTN.CPP
│ ├── SHAPEBTN.H
│ ├── SHAPIPE.CPP
│ ├── SHAPIPE.H
│ ├── SHASTRAW.CPP
│ ├── SHASTRAW.H
│ ├── SIDEBAR.CPP
│ ├── SIDEBAR.H
│ ├── SLIDER.CPP
│ ├── SLIDER.H
│ ├── SMUDGE.CPP
│ ├── SMUDGE.H
│ ├── SOUNDDLG.CPP
│ ├── SOUNDDLG.H
│ ├── SPECIAL.CPP
│ ├── SPECIAL.H
│ ├── SPRITE.CPP
│ ├── STAGE.H
│ ├── STARTUP.CPP
│ ├── STATBTN.CPP
│ ├── STATBTN.H
│ ├── STATS.CPP
│ ├── STD.LNT
│ ├── STRAW.CPP
│ ├── STRAW.H
│ ├── STUB.CPP
│ ├── STUFF.TXT
│ ├── STYLE.H
│ ├── SUPER.CPP
│ ├── SUPER.H
│ ├── SUPPORT.ASM
│ ├── SURFACE.CPP
│ ├── SURFACE.H
│ ├── TAB.CPP
│ ├── TAB.H
│ ├── TACTION.CPP
│ ├── TACTION.H
│ ├── TARCOM.CPP
│ ├── TARCOM.H
│ ├── TARGET.CPP
│ ├── TARGET.H
│ ├── TASM.CFG
│ ├── TCPIP.CPP
│ ├── TCPIP.H
│ ├── TDATA.CPP
│ ├── TEAM.CPP
│ ├── TEAM.H
│ ├── TEAMTYPE.CPP
│ ├── TEAMTYPE.H
│ ├── TECHNO.CPP
│ ├── TECHNO.H
│ ├── TEMP.CPP
│ ├── TEMPLATE.CPP
│ ├── TEMPLATE.H
│ ├── TENMGR.CPP
│ ├── TENMGR.H
│ ├── TERRAIN.CPP
│ ├── TERRAIN.H
│ ├── TEVENT.CPP
│ ├── TEVENT.H
│ ├── TEXTBTN.CPP
│ ├── TEXTBTN.H
│ ├── THEME.CPP
│ ├── THEME.H
│ ├── TLINK.CFG
│ ├── TODO.TXT
│ ├── TOGGLE.CPP
│ ├── TOGGLE.H
│ ├── TOOLTIP.CPP
│ ├── TOOLTIP.H
│ ├── TRACKER.CPP
│ ├── TRIGGER.CPP
│ ├── TRIGGER.H
│ ├── TRIGTYPE.CPP
│ ├── TRIGTYPE.H
│ ├── TURBOC.CFG
│ ├── TURRET.CPP
│ ├── TURRET.H
│ ├── TXTLABEL.CPP
│ ├── TXTLABEL.H
│ ├── TXTPRNT.ASM
│ ├── TYPE.H
│ ├── UDATA.CPP
│ ├── UDPADDR.CPP
│ ├── UNIT.CPP
│ ├── UNIT.H
│ ├── UTRACKER.CPP
│ ├── UTRACKER.H
│ ├── VDATA.CPP
│ ├── VECTOR.CPP
│ ├── VECTOR.H
│ ├── VERSION.CPP
│ ├── VERSION.H
│ ├── VER_FUNC.TXT
│ ├── VESSEL.CPP
│ ├── VESSEL.H
│ ├── VISUDLG.CPP
│ ├── VISUDLG.H
│ ├── VORTEX.CPP
│ ├── VORTEX.H
│ ├── W95TRACE.CPP
│ ├── W95TRACE.H
│ ├── WARHEAD.CPP
│ ├── WARHEAD.H
│ ├── WATCOM.H
│ ├── WEAPON.CPP
│ ├── WEAPON.H
│ ├── WIDEFUNC.MAC
│ ├── WIDEHDR.MAC
│ ├── WINASM.ASM
│ ├── WINSTUB.CPP
│ ├── WOLAPI/
│ │ ├── CHATDEFS.H
│ │ ├── DOWNLOADDEFS.H
│ │ ├── FTPDEFS.H
│ │ ├── NETUTILDEFS.H
│ │ ├── WOLAPI.H
│ │ └── WOLAPI_I.C
│ ├── WOLAPIOB.CPP
│ ├── WOLAPIOB.H
│ ├── WOLDEBUG.H
│ ├── WOLEDIT.CPP
│ ├── WOLEDIT.H
│ ├── WOLSTRNG.CPP
│ ├── WOLSTRNG.H
│ ├── WOL_CGAM.CPP
│ ├── WOL_CHAT.CPP
│ ├── WOL_DNLD.CPP
│ ├── WOL_GSUP.CPP
│ ├── WOL_GSUP.H
│ ├── WOL_LOGN.CPP
│ ├── WOL_MAIN.CPP
│ ├── WOL_OPT.CPP
│ ├── WRITEPCX.CPP
│ ├── WSPIPX.CPP
│ ├── WSPIPX.H
│ ├── WSPROTO.CPP
│ ├── WSPROTO.H
│ ├── WSPUDP.CPP
│ ├── WSPUDP.H
│ ├── WWALLOC.H
│ ├── WWFILE.H
│ ├── XPIPE.CPP
│ ├── XPIPE.H
│ ├── XSTRAW.CPP
│ ├── XSTRAW.H
│ ├── _WSPROTO.CPP
│ └── _WSPROTO.H
├── IPX/
│ ├── FIXTHUNK.CPP
│ ├── IPX.RC
│ ├── IPX16.ASM
│ ├── IPX16.BAK
│ ├── IPX16.H
│ ├── IPX16A.ASM
│ ├── IPX16C.CPP
│ ├── IPXTEST.CPP
│ ├── MAKE.BAK
│ ├── MAKE.BAT
│ ├── MAKEFILE
│ ├── MAKETH16.BAK
│ ├── MAKETH16.BAT
│ ├── MAKETH32.BAK
│ ├── MAKETH32.BAT
│ ├── OK/
│ │ ├── FIXTHUNK.CPP
│ │ ├── IPX.RC
│ │ ├── IPX16.ASM
│ │ ├── IPX16.BAK
│ │ ├── IPX16.H
│ │ ├── IPX16A.ASM
│ │ ├── IPX16C.CPP
│ │ ├── IPXTEST.CPP
│ │ ├── MAKE.BAK
│ │ ├── MAKE.BAT
│ │ ├── MAKETH16.BAK
│ │ ├── MAKETH16.BAT
│ │ ├── MAKETH32.BAK
│ │ ├── MAKETH32.BAT
│ │ ├── OLTHIPX.ASM
│ │ ├── PCMACRO.16
│ │ ├── THIPX.ASM
│ │ ├── THIPX.BAK
│ │ ├── THIPX.THK
│ │ ├── THIPX16C.CPP
│ │ ├── THIPX32C.CPP
│ │ ├── THMAP16.ASM
│ │ ├── THMAP32.ASM
│ │ ├── WWIPX.ASM
│ │ └── WWIPX16.ASM
│ ├── OLD/
│ │ └── IPX16A.ASM
│ ├── OLTHIPX.ASM
│ ├── PCMACRO.16
│ ├── THIPX.ASM
│ ├── THIPX.BAK
│ ├── THIPX.THK
│ ├── THIPX16C.CPP
│ ├── THIPX32C.CPP
│ ├── THMAP16.ASM
│ ├── THMAP32.ASM
│ ├── WWIPX.ASM
│ └── WWIPX16.ASM
├── LAUNCH/
│ ├── LAUNCH.ASM
│ └── PCMACRO.16
├── LAUNCHER/
│ ├── 256BMP.C
│ ├── BITMAP.CPP
│ ├── CONFIGFILE.CPP
│ ├── CONFIGFILE.H
│ ├── DIALOG.CPP
│ ├── DIALOG.H
│ ├── DICTIONARY.H
│ ├── FILED.H
│ ├── FINDPATCH.CPP
│ ├── FINDPATCH.H
│ ├── LAUNCHER.DSP
│ ├── LAUNCHER.DSW
│ ├── LAUNCHER1.RC
│ ├── LOADBMP.CPP
│ ├── LOADBMP.H
│ ├── MAIN.CPP
│ ├── MONOD.CPP
│ ├── MONOD.H
│ ├── ODEVICE.H
│ ├── PATCH.CPP
│ ├── PATCH.H
│ ├── PROCESS.CPP
│ ├── PROCESS.H
│ ├── RESOURCE.H
│ ├── STREAMER.CPP
│ ├── STREAMER.H
│ ├── UTIL/
│ │ ├── FILED.H
│ │ ├── MBOXD.H
│ │ ├── MONOD.CPP
│ │ ├── MONOD.H
│ │ ├── ODEVICE.H
│ │ ├── STDERRD.H
│ │ ├── STDOUTD.H
│ │ ├── STREAMER.CPP
│ │ ├── STREAMER.H
│ │ ├── SYSLOGD.CPP
│ │ ├── SYSLOGD.H
│ │ ├── WDEBUG.CPP
│ │ └── WDEBUG.H
│ ├── WDEBUG.CPP
│ ├── WDEBUG.H
│ ├── WINBLOWS.CPP
│ ├── WINBLOWS.H
│ ├── WSTRING.CPP
│ ├── WSTRING.H
│ └── WSTYPES.H
├── LICENSE.md
├── README.md
├── TOOLS/
│ ├── ANIMATE.EXE.OLD
│ ├── AUDIOMAK/
│ │ ├── AUDIOMAK.CPP
│ │ ├── AUDIOMAK.PJT
│ │ ├── MAKEFILE
│ │ ├── SCODE.ASM
│ │ ├── TASM.CFG
│ │ ├── TLINK.CFG
│ │ └── TURBOC.CFG
│ └── MIX/
│ ├── MIXFILE.CPP
│ ├── MIXFILE.IDE
│ └── MIXFILE.IDE.BAK
├── VQ/
│ ├── INCLUDE/
│ │ ├── HMI32/
│ │ │ ├── SOS.H
│ │ │ ├── SOSDATA.H
│ │ │ ├── SOSDEFS.H
│ │ │ ├── SOSFNCT.H
│ │ │ └── SOSRES.H
│ │ ├── VOCFILE.H
│ │ ├── VQ.H
│ │ ├── VQA32/
│ │ │ ├── VQAFILE.H
│ │ │ ├── VQAPLAY.BAK
│ │ │ └── VQAPLAY.H
│ │ ├── VQM32/
│ │ │ ├── ALL.H
│ │ │ ├── CAPTOKEN.H
│ │ │ ├── COMPRESS.H
│ │ │ ├── CRC.H
│ │ │ ├── FONT.H
│ │ │ ├── GRAPHICS.H
│ │ │ ├── HUFFMAN.H
│ │ │ ├── IFF.H
│ │ │ ├── MEM.H
│ │ │ ├── MIXFILE.H
│ │ │ ├── MONO.H
│ │ │ ├── PALETTE.H
│ │ │ ├── PORTIO.H
│ │ │ ├── PROFILE.H
│ │ │ ├── REALMODE.H
│ │ │ ├── SOSCOMP.H
│ │ │ ├── TARGA.H
│ │ │ ├── TEXT.H
│ │ │ ├── VESABLIT.H
│ │ │ ├── VESAVID.H
│ │ │ ├── VESAVID.I
│ │ │ ├── VGA.I
│ │ │ ├── VIDEO.H
│ │ │ └── VIDEO.I
│ │ ├── WAVEFILE.H
│ │ ├── WWLIB32/
│ │ │ ├── AUDIO.H
│ │ │ ├── BUFFER.H
│ │ │ ├── DESCMGMT.H
│ │ │ ├── DIPTHONG.H
│ │ │ ├── FILE.H
│ │ │ ├── FILETEMP.H
│ │ │ ├── FONT.H
│ │ │ ├── FUNCTION.H
│ │ │ ├── GBUFFER.H
│ │ │ ├── GBUFFER.INC
│ │ │ ├── IFF.H
│ │ │ ├── KEYBOARD.H
│ │ │ ├── KEYBOARD.INC
│ │ │ ├── KEYSTRUC.INC
│ │ │ ├── MCGAPRIM.H
│ │ │ ├── MCGAPRIM.INC
│ │ │ ├── MEMFLAG.H
│ │ │ ├── MISC.H
│ │ │ ├── MONO.H
│ │ │ ├── PALETTE.H
│ │ │ ├── PLAYCD.H
│ │ │ ├── SHAPE.H
│ │ │ ├── SHAPE.INC
│ │ │ ├── SOS.H
│ │ │ ├── SOSCOMP.H
│ │ │ ├── SOSDATA.H
│ │ │ ├── SOSDEFS.H
│ │ │ ├── SOSFNCT.H
│ │ │ ├── SOSRES.H
│ │ │ ├── SOUND.H
│ │ │ ├── STAMP.INC
│ │ │ ├── SVGAPRIM.INC
│ │ │ ├── TILE.H
│ │ │ ├── TIMER.H
│ │ │ ├── VBUFFER.H
│ │ │ ├── VIDEO.H
│ │ │ ├── WINDOWS.H
│ │ │ ├── WSA.H
│ │ │ ├── WWLIB32.H
│ │ │ ├── WWMEM.H
│ │ │ ├── WWMEM.INC
│ │ │ ├── WWSTD.H
│ │ │ └── _FILE.H
│ │ └── WWTYPES.H
│ ├── LIB/
│ │ └── README.TXT
│ ├── VQA32/
│ │ ├── AUDIO.BAK1
│ │ ├── AUDIO.BAK2
│ │ ├── AUDIO.CPP
│ │ ├── BCC32.CFG
│ │ ├── CAPTION.CPP
│ │ ├── CAPTION.H
│ │ ├── CONFIG.CPP
│ │ ├── DRAWER.BAK
│ │ ├── DRAWER.CPP
│ │ ├── DSTREAM.CPP
│ │ ├── LOADER.BAK
│ │ ├── LOADER.CPP
│ │ ├── MAKEFILE
│ │ ├── MAKEFILE.BAK
│ │ ├── MAKEFILE.BOR
│ │ ├── MAKEFILE.WAT
│ │ ├── MONODISP.BAK
│ │ ├── MONODISP.CPP
│ │ ├── SOS.H
│ │ ├── SOSDATA.H
│ │ ├── SOSDEFS.H
│ │ ├── SOSFNCT.H
│ │ ├── SOSRES.H
│ │ ├── TASK.CPP
│ │ ├── TASM32.CFG
│ │ ├── TLIB.CFG
│ │ ├── TLINK32.CFG
│ │ ├── UNVQ.H
│ │ ├── UNVQBUFF.ASM
│ │ ├── UNVQVESA.ASM
│ │ ├── UNVQXMDE.ASM
│ │ ├── UNVQXMDE.ASM.BAK
│ │ ├── VERTAG.CPP
│ │ ├── VQAFILE.H
│ │ ├── VQAPLAY.BAK
│ │ ├── VQAPLAY.H
│ │ ├── VQAPLAY.I
│ │ └── VQAPLAYP.H
│ └── VQM32/
│ ├── ALL.H
│ ├── AUDUNZAP.ASM
│ ├── AUDZAP.CPP
│ ├── BCC32.CFG
│ ├── CAPTOKEN.CPP
│ ├── CAPTOKEN.H
│ ├── CHRWIDTH.CPP
│ ├── COMPRESS.H
│ ├── CRC.ASM
│ ├── CRC.H
│ ├── DRAWCHAR.ASM
│ ├── FILLRECT.ASM
│ ├── FONT.CPP
│ ├── FONT.H
│ ├── GRAPHICS.H
│ ├── HUFFCMP.CPP
│ ├── HUFFDCMP.ASM
│ ├── HUFFMAN.H
│ ├── IFF.CPP
│ ├── IFF.H
│ ├── LCWCOMP.ASM
│ ├── LCWUNCMP.ASM
│ ├── MAKEFILE
│ ├── MAKEFILE.BAK
│ ├── MAKEFILE.BOR
│ ├── MAKEFILE.WAT
│ ├── MCGABUF.ASM
│ ├── MEM.CPP
│ ├── MEM.H
│ ├── MIXFILE.CPP
│ ├── MIXFILE.H
│ ├── MONO.ASM
│ ├── MONO.H
│ ├── PALETTE.ASM
│ ├── PALETTE.H
│ ├── PORTIO.ASM
│ ├── PORTIO.H
│ ├── PROFILE.CPP
│ ├── PROFILE.H
│ ├── REALMODE.H
│ ├── SORTPAL.CPP
│ ├── SOSCODEC.ASM
│ ├── SOSCOMP.H
│ ├── TARGA.CPP
│ ├── TARGA.H
│ ├── TASM32.CFG
│ ├── TESTVB.CPP
│ ├── TEXT.H
│ ├── TEXTPRNT.ASM
│ ├── TLIB.CFG
│ ├── TLINK32.CFG
│ ├── VB.ASM
│ ├── VERTAG.CPP
│ ├── VESABLIT.CPP
│ ├── VESABLIT.H
│ ├── VESABUF.ASM
│ ├── VESAVID.CPP
│ ├── VESAVID.H
│ ├── VESAVID.I
│ ├── VGA.I
│ ├── VIDEO.CPP
│ ├── VIDEO.H
│ ├── VIDEO.I
│ ├── XMODE.ASM
│ └── XMODEPG.CPP
├── WIN32LIB/
│ ├── AUDIO/
│ │ ├── AUDIO.H
│ │ ├── AUDIO.IDE
│ │ ├── AUDUNCMP.ASM
│ │ ├── DIFFTB.INC
│ │ ├── FUNCTION.H
│ │ ├── INDEXTB.INC
│ │ ├── MAKEFILE
│ │ ├── MAKEFILE.BOR
│ │ ├── NYBBTB.INC
│ │ ├── OLD/
│ │ │ ├── AUDIO.H
│ │ │ ├── AUDIO.IDE
│ │ │ ├── AUDUNCMP.ASM
│ │ │ ├── DIFFTB.INC
│ │ │ ├── FUNCTION.H
│ │ │ ├── INDEXTB.INC
│ │ │ ├── MAKEFILE
│ │ │ ├── MAKEFILE.BOR
│ │ │ ├── MAKEFILE.WAT
│ │ │ ├── NYBBTB.INC
│ │ │ ├── OLSOSDEC.ASM
│ │ │ ├── SOS.H
│ │ │ ├── SOSCODEC.ASM
│ │ │ ├── SOSCOMP.H
│ │ │ ├── SOSDATA.H
│ │ │ ├── SOSDEFS.H
│ │ │ ├── SOSFNCT.H
│ │ │ ├── SOSRES.H
│ │ │ ├── SOUND.H
│ │ │ ├── SOUNDINT.CPP
│ │ │ ├── SOUNDINT.H
│ │ │ ├── SOUNDIO.CPP
│ │ │ ├── SOUNDLCK.CPP
│ │ │ ├── TEST.CPP
│ │ │ └── TST.CPP
│ │ ├── OLSOSDEC.ASM
│ │ ├── SOS.H
│ │ ├── SOSCODEC.ASM
│ │ ├── SOSCOMP.H
│ │ ├── SOSDATA.H
│ │ ├── SOSDEFS.H
│ │ ├── SOSFNCT.H
│ │ ├── SOSRES.H
│ │ ├── SOUND.H
│ │ ├── SOUNDINT.CPP
│ │ ├── SOUNDINT.H
│ │ ├── SOUNDIO.CPP
│ │ ├── SOUNDLCK.CPP
│ │ ├── TEST.CPP
│ │ └── TST.CPP
│ ├── DIPTHONG/
│ │ ├── DIPTHONG.CPP
│ │ ├── DIPTHONG.H
│ │ ├── MAKEFILE
│ │ ├── MAKEFILE.BOR
│ │ ├── MAKEFILE.WAT
│ │ └── _DIPTABL.CPP
│ ├── DRAWBUFF/
│ │ ├── BITBLIT.ASM
│ │ ├── BUFFER.CPP
│ │ ├── BUFFER.H
│ │ ├── BUFFGLBL.CPP
│ │ ├── CLEAR.ASM
│ │ ├── DRAWBUFF.H
│ │ ├── DRAWBUFF.INC
│ │ ├── DRAWLINE.ASM
│ │ ├── DRAWRECT.CPP
│ │ ├── FILLQUAD.ASM
│ │ ├── FILLRECT.ASM
│ │ ├── FTPUTPIX.ASM
│ │ ├── GBUFFER.CPP
│ │ ├── GBUFFER.H
│ │ ├── GBUFFER.INC
│ │ ├── GETCLIP.ASM
│ │ ├── GETPIX.ASM
│ │ ├── ICONCACH.CPP
│ │ ├── ICONCACH.H
│ │ ├── MAKEFILE
│ │ ├── MAKEFILE.BOR
│ │ ├── PUTPIX.ASM
│ │ ├── REGIONSZ.CPP
│ │ ├── REMAP.ASM
│ │ ├── SCALE.ASM
│ │ ├── SHADOW.ASM
│ │ ├── STAMP.ASM
│ │ ├── STAMP.INC
│ │ ├── STMPCACH.ASM
│ │ ├── SZREGION.ASM
│ │ ├── TEST/
│ │ │ ├── HOLD.DEF
│ │ │ ├── MAKEFILE
│ │ │ ├── MAKEFILE.BOR
│ │ │ ├── MAKEFILE.WAT
│ │ │ ├── TEST/
│ │ │ │ └── TEST.CPP
│ │ │ ├── TEST.BAK
│ │ │ ├── TEST.CPP
│ │ │ ├── TEST.DEF
│ │ │ └── TESTASM.ASM
│ │ ├── TOBUFF.ASM
│ │ ├── TOPAGE.ASM
│ │ └── TXTPRNT.ASM
│ ├── EXAMPLE/
│ │ ├── DEFINES.H
│ │ ├── EXTERNS.H
│ │ ├── FUNCTION.H
│ │ ├── GLOBALS.CPP
│ │ ├── MAIN.CPP
│ │ ├── MAKEFILE
│ │ ├── MAKEFILE.BOR
│ │ ├── MAKEFILE.WAT
│ │ ├── STARTUP.CPP
│ │ ├── STRUCTS.H
│ │ └── WWLIB32.H
│ ├── FONT/
│ │ ├── FONT.CPP
│ │ ├── FONT.H
│ │ ├── LOADFONT.CPP
│ │ ├── MAKEFILE
│ │ ├── MAKEFILE.BOR
│ │ ├── SETFPAL.ASM
│ │ ├── SET_FONT.CPP
│ │ └── TEXTPRNT.ASM
│ ├── IFF/
│ │ ├── FILEPCX.H
│ │ ├── IFF.CPP
│ │ ├── IFF.H
│ │ ├── LCWCOMP.ASM
│ │ ├── LCWUNCMP.ASM
│ │ ├── LOAD.CPP
│ │ ├── LOADPCX.CPP
│ │ ├── LOADPICT.CPP
│ │ ├── MAKEFILE
│ │ ├── MAKEFILE.BOR
│ │ ├── MAKEFILE.WAT
│ │ ├── PACK2PLN.ASM
│ │ ├── WRITELBM.CPP
│ │ └── WRITEPCX.CPP
│ ├── INCLUDE/
│ │ ├── AUDIO.H
│ │ ├── BUFFER.H
│ │ ├── DEFINES.H
│ │ ├── DESCMGMT.H
│ │ ├── DIFFTB.INC
│ │ ├── DIPTHONG.H
│ │ ├── DRAWBUFF.H
│ │ ├── DRAWBUFF.INC
│ │ ├── EXTERNS.H
│ │ ├── FILE.H
│ │ ├── FILEPCX.H
│ │ ├── FILETEMP.H
│ │ ├── FONT.H
│ │ ├── FUNCTION.H
│ │ ├── GBUFFER.H
│ │ ├── GBUFFER.INC
│ │ ├── ICONCACH.H
│ │ ├── IFF.H
│ │ ├── INDEXTB.INC
│ │ ├── KEYBOARD.H
│ │ ├── KEYBOARD.INC
│ │ ├── KEYSTRUC.INC
│ │ ├── MCGAPRIM.INC
│ │ ├── MEMFLAG.H
│ │ ├── MISC.H
│ │ ├── MODEMREG.H
│ │ ├── MONO.H
│ │ ├── MOUSE.H
│ │ ├── MOUSE.INC
│ │ ├── NYBBTB.INC
│ │ ├── PALETTE.H
│ │ ├── PLAYCD.H
│ │ ├── PROFILE.H
│ │ ├── PROFILE.INC
│ │ ├── RAWFILE.H
│ │ ├── SHAPE.H
│ │ ├── SHAPE.INC
│ │ ├── SOS.H
│ │ ├── SOSCOMP.H
│ │ ├── SOSDATA.H
│ │ ├── SOSDEFS.H
│ │ ├── SOSFNCT.H
│ │ ├── SOSRES.H
│ │ ├── SOUND.H
│ │ ├── SOUNDINT.H
│ │ ├── STAMP.INC
│ │ ├── STRUCTS.H
│ │ ├── SVGAPRIM.INC
│ │ ├── TILE.H
│ │ ├── TIMER.H
│ │ ├── VIDEO.H
│ │ ├── WINCOMM.H
│ │ ├── WSA.H
│ │ ├── WWFILE.H
│ │ ├── WWLIB32.H
│ │ ├── WWMEM.H
│ │ ├── WWMEM.INC
│ │ ├── WWSTD.H
│ │ ├── WW_WIN.H
│ │ └── _FILE.H
│ ├── KEYBOARD/
│ │ ├── KEYBOARD.CPP
│ │ ├── KEYBOARD.H
│ │ ├── MAKEFILE
│ │ ├── MAKEFILE.BOR
│ │ ├── MAKEFILE.WAT
│ │ ├── MOUSE.CPP
│ │ ├── MOUSE.H
│ │ ├── MOUSE.INC
│ │ ├── OLD/
│ │ │ ├── KEYBOARD.ASM
│ │ │ ├── KEYBOARD.BAK
│ │ │ ├── KEYBOARD.CPP
│ │ │ ├── KEYBOARD.H
│ │ │ ├── KEYBOARD.INC
│ │ │ ├── KEYIPROT.ASM
│ │ │ ├── KEYIREAL.ASM
│ │ │ ├── KEYIREAL.IBN
│ │ │ ├── KEYSTRUC.INC
│ │ │ ├── MAKEFILE
│ │ │ ├── MAKEFILE.BAK
│ │ │ ├── MAKEFILE.BOR
│ │ │ ├── MAKEFILE.WAT
│ │ │ ├── MOUSE.ASM
│ │ │ ├── MOUSE.CPP
│ │ │ ├── MOUSE.CPP.BAK
│ │ │ ├── MOUSE.H
│ │ │ ├── MOUSE.INC
│ │ │ ├── PAGFAULT.ASM
│ │ │ ├── WWMOUSE.ASM
│ │ │ └── WWMOUSE.ASM.BAK
│ │ ├── OLDTEST/
│ │ │ ├── KEYBOARD.CPP
│ │ │ ├── KEYBOARD.H
│ │ │ ├── MAKEFILE
│ │ │ ├── MAKEFILE.BOR
│ │ │ ├── MAKEFILE.WAT
│ │ │ ├── TEST.CPP
│ │ │ └── TEST.DEF
│ │ ├── TEST/
│ │ │ ├── HOLD.DEF
│ │ │ ├── KEYBOARD.CPP
│ │ │ ├── KEYBOARD.H
│ │ │ ├── MAKEFILE
│ │ │ ├── MAKEFILE.BOR
│ │ │ ├── MAKEFILE.WAT
│ │ │ ├── TEST.CPP
│ │ │ ├── TEST.DEF
│ │ │ └── TESTASM.ASM
│ │ └── WWMOUSE.ASM
│ ├── MAKE.BAT
│ ├── MAKEFILE
│ ├── MAKEFILE.BOR
│ ├── MAKE_EXE.MAK
│ ├── MAKE_LIB.MAK
│ ├── MEM/
│ │ ├── ALLOC.CPP
│ │ ├── MAKEFILE
│ │ ├── MAKEFILE.BOR
│ │ ├── MAKEFILE.WAT
│ │ ├── MEM.CPP
│ │ ├── MEMFLAG.H
│ │ ├── MEM_COPY.ASM
│ │ ├── MSVC/
│ │ │ ├── ALLOC.CPP
│ │ │ ├── MAKEFILE
│ │ │ ├── MAKEFILE.BOR
│ │ │ ├── MAKEFILE.WAT
│ │ │ ├── MEM.CPP
│ │ │ ├── MEM.MAK
│ │ │ ├── MEMFLAG.H
│ │ │ ├── MEM_COPY.ASM
│ │ │ ├── NEWDEL.CPP
│ │ │ ├── WWMEM.H
│ │ │ └── WWMEM.INC
│ │ ├── NEWDEL.CPP
│ │ ├── OLDMEM/
│ │ │ ├── ALLOC.CPP
│ │ │ ├── MAKEFILE
│ │ │ ├── MAKEFILE.BOR
│ │ │ ├── MAKEFILE.WAT
│ │ │ ├── MEM.CPP
│ │ │ ├── MEMFLAG.H
│ │ │ ├── MEM_COPY.ASM
│ │ │ ├── NEWDEL.CPP
│ │ │ ├── WWMEM.H
│ │ │ └── WWMEM.INC
│ │ ├── VMPAGEIN.ASM
│ │ ├── WWMEM.H
│ │ └── WWMEM.INC
│ ├── MISC/
│ │ ├── CLIPRECT.ASM
│ │ ├── CRC.ASM
│ │ ├── DDRAW.CPP
│ │ ├── DELAY.CPP
│ │ ├── DETPROC.ASM
│ │ ├── EXIT.CPP
│ │ ├── FACING16.ASM
│ │ ├── FACING8.ASM
│ │ ├── FACINGFF.ASM
│ │ ├── FADING.ASM
│ │ ├── FINDARGV.CPP
│ │ ├── IRANDOM.CPP
│ │ ├── LIB.CPP
│ │ ├── MAKEFILE
│ │ ├── MAKEFILE.BOR
│ │ ├── MAKEFILE.WAT
│ │ ├── MISC.H
│ │ ├── OPSYS.ASM
│ │ ├── RANDOM.ASM
│ │ ├── REVERSE.ASM
│ │ ├── SHAKESCR.ASM
│ │ ├── VERSION.CPP
│ │ ├── WWLIB32.H
│ │ └── WWSTD.H
│ ├── MONO/
│ │ ├── MAKEFILE
│ │ ├── MAKEFILE.BOR
│ │ ├── MAKEFILE.WAT
│ │ ├── MONO.CPP
│ │ └── MONO.H
│ ├── MOVIE/
│ │ ├── MAKE.BAT
│ │ ├── MAKEFILE
│ │ ├── MOVIE.CPP
│ │ └── MOVIE.H
│ ├── PALETTE/
│ │ ├── LOADPAL.CPP
│ │ ├── MAKEFILE
│ │ ├── MAKEFILE.BOR
│ │ ├── MORPHPAL.CPP
│ │ ├── PAL.ASM
│ │ ├── PALETTE.CPP
│ │ └── PALETTE.H
│ ├── PLAYCD/
│ │ ├── GETCD.CPP
│ │ ├── MAKEFILE
│ │ ├── MAKEFILE.BOR
│ │ ├── MAKEFILE.WAT
│ │ ├── PLAYCD.ASM
│ │ ├── PLAYCD.H
│ │ └── REDBOOK.CPP
│ ├── PROFILE/
│ │ ├── APROFILE.ASM
│ │ ├── MAKEFILE
│ │ ├── PROFILE.CPP
│ │ ├── PROFILE.H
│ │ ├── PROFILE.INC
│ │ ├── UTIL/
│ │ │ └── PROFILE.CPP
│ │ └── WPROFILE.CPP
│ ├── PROJECT.CFG
│ ├── RAWFILE/
│ │ ├── CCFILE.CPP
│ │ ├── FILE.H
│ │ ├── FILETEMP.H
│ │ ├── MAKEFILE
│ │ ├── MAKEFILE.BOR
│ │ ├── MAKEFILE.WAT
│ │ ├── RAWFILE.CPP
│ │ ├── RAWFILE.H
│ │ └── WWFILE.H
│ ├── REBUILD.BAT
│ ├── SHAPE/
│ │ ├── DRAWSHP.ASM
│ │ ├── DS_DN.ASM
│ │ ├── DS_DR.ASM
│ │ ├── DS_DS.ASM
│ │ ├── DS_DSR.ASM
│ │ ├── DS_LRS.ASM
│ │ ├── DS_LS.ASM
│ │ ├── DS_LSRS.ASM
│ │ ├── DS_LSS.ASM
│ │ ├── DS_RRS.ASM
│ │ ├── DS_RS.ASM
│ │ ├── DS_RSRS.ASM
│ │ ├── DS_RSS.ASM
│ │ ├── DS_TABLE.ASM
│ │ ├── GETSHAPE.CPP
│ │ ├── MAKEFILE
│ │ ├── MAKEFILE.BOR
│ │ ├── MAKEFILE.WAT
│ │ ├── PRIOINIT.CPP
│ │ ├── SETSHAPE.ASM
│ │ ├── SHAPE.ASM
│ │ ├── SHAPE.H
│ │ └── SHAPE.INC
│ ├── SRCDEBUG/
│ │ ├── ALLOC.CPP
│ │ ├── APROFILE.ASM
│ │ ├── AUDUNCMP.ASM
│ │ ├── BITBLIT.ASM
│ │ ├── BUFFER.CPP
│ │ ├── BUFFGLBL.CPP
│ │ ├── CCFILE.CPP
│ │ ├── CLEAR.ASM
│ │ ├── CLIPRECT.ASM
│ │ ├── CRC.ASM
│ │ ├── DDRAW.CPP
│ │ ├── DELAY.CPP
│ │ ├── DESCMGMT.CPP
│ │ ├── DETPROC.ASM
│ │ ├── DEVICES.ASM
│ │ ├── DEVTABLE.ASM
│ │ ├── DIPTHONG.CPP
│ │ ├── DRAWLINE.ASM
│ │ ├── DRAWRECT.CPP
│ │ ├── DRAWSHP.ASM
│ │ ├── DS_DN.ASM
│ │ ├── DS_DR.ASM
│ │ ├── DS_DS.ASM
│ │ ├── DS_DSR.ASM
│ │ ├── DS_LRS.ASM
│ │ ├── DS_LS.ASM
│ │ ├── DS_LSRS.ASM
│ │ ├── DS_LSS.ASM
│ │ ├── DS_RRS.ASM
│ │ ├── DS_RS.ASM
│ │ ├── DS_RSRS.ASM
│ │ ├── DS_RSS.ASM
│ │ ├── DS_TABLE.ASM
│ │ ├── EXIT.CPP
│ │ ├── FACING16.ASM
│ │ ├── FACING8.ASM
│ │ ├── FACINGFF.ASM
│ │ ├── FADING.ASM
│ │ ├── FFIRST.ASM
│ │ ├── FFIXSEL.ASM
│ │ ├── FGETCS.ASM
│ │ ├── FGETDS.ASM
│ │ ├── FGETSEL.ASM
│ │ ├── FGLOB2.CPP
│ │ ├── FILE.CPP
│ │ ├── FILECACH.CPP
│ │ ├── FILECHNG.CPP
│ │ ├── FILEDATA.CPP
│ │ ├── FILEGLOB.CPP
│ │ ├── FILEINFO.CPP
│ │ ├── FILEINIT.CPP
│ │ ├── FILEIO.CPP
│ │ ├── FILELIB.CPP
│ │ ├── FILESTUB.CPP
│ │ ├── FILLQUAD.ASM
│ │ ├── FILLRECT.ASM
│ │ ├── FINDARGV.CPP
│ │ ├── FINDFILE.CPP
│ │ ├── FONT.CPP
│ │ ├── FTPUTPIX.ASM
│ │ ├── GBUFFER.CPP
│ │ ├── GETCD.CPP
│ │ ├── GETCLIP.ASM
│ │ ├── GETPIX.ASM
│ │ ├── GETSHAPE.CPP
│ │ ├── HARDERR.ASM
│ │ ├── ICONCACH.CPP
│ │ ├── ICONSET.CPP
│ │ ├── IFF.CPP
│ │ ├── INITDLAY.CPP
│ │ ├── INITMONO.CPP
│ │ ├── IRANDOM.CPP
│ │ ├── KEYBOARD.ASM
│ │ ├── KEYBOARD.CPP
│ │ ├── KEYIPROT.ASM
│ │ ├── KEYIREAL.ASM
│ │ ├── LCWCOMP.ASM
│ │ ├── LCWUNCMP.ASM
│ │ ├── LIB.CPP
│ │ ├── LOAD.CPP
│ │ ├── LOADFONT.CPP
│ │ ├── LOADPAL.CPP
│ │ ├── LOADPCX.CPP
│ │ ├── LOADPICT.CPP
│ │ ├── MEM.CPP
│ │ ├── MEM_COPY.ASM
│ │ ├── MODEMREG.CPP
│ │ ├── MONO.ASM
│ │ ├── MONO.CPP
│ │ ├── MONOPRNT.CPP
│ │ ├── MORPHPAL.CPP
│ │ ├── MOUSE.ASM
│ │ ├── MOUSE.CPP
│ │ ├── NEWDEL.CPP
│ │ ├── OLSOSDEC.ASM
│ │ ├── OPSYS.ASM
│ │ ├── PACK2PLN.ASM
│ │ ├── PAGFAULT.ASM
│ │ ├── PAL.ASM
│ │ ├── PALETTE.CPP
│ │ ├── PLAYCD.ASM
│ │ ├── PRIOINIT.CPP
│ │ ├── PROFILE.CPP
│ │ ├── PUTPIX.ASM
│ │ ├── RANDOM.ASM
│ │ ├── RAWFILE.CPP
│ │ ├── REDBOOK.CPP
│ │ ├── REGIONSZ.CPP
│ │ ├── REMAP.ASM
│ │ ├── REVERSE.ASM
│ │ ├── SCALE.ASM
│ │ ├── SETFPAL.ASM
│ │ ├── SETSHAPE.ASM
│ │ ├── SET_FONT.CPP
│ │ ├── SHADOW.ASM
│ │ ├── SHAKESCR.ASM
│ │ ├── SHAPE.ASM
│ │ ├── SOSCODEC.ASM
│ │ ├── SOUNDINT.CPP
│ │ ├── SOUNDIO.CPP
│ │ ├── SOUNDLCK.CPP
│ │ ├── STAMP.ASM
│ │ ├── STMPCACH.ASM
│ │ ├── SZREGION.ASM
│ │ ├── TEST.CPP
│ │ ├── TEXTPRNT.ASM
│ │ ├── TIMER.CPP
│ │ ├── TIMERA.ASM
│ │ ├── TIMERDWN.CPP
│ │ ├── TIMEREAL.ASM
│ │ ├── TIMERINI.CPP
│ │ ├── TOBUFF.ASM
│ │ ├── TOPAGE.ASM
│ │ ├── TST.CPP
│ │ ├── TXTPRNT.ASM
│ │ ├── VBITBLIT.ASM
│ │ ├── VBUFFER.CPP
│ │ ├── VCLEAR.ASM
│ │ ├── VERSION.CPP
│ │ ├── VERTBLNK.ASM
│ │ ├── VESA.ASM
│ │ ├── VESAHOOK.ASM
│ │ ├── VESAINFO.CPP
│ │ ├── VESAREAL.ASM
│ │ ├── VGETPIX.ASM
│ │ ├── VIDEO.CPP
│ │ ├── VLBTOVE.ASM
│ │ ├── VMPAGEIN.ASM
│ │ ├── VPUTPIX.ASM
│ │ ├── VSCALE.ASM
│ │ ├── VSCALE.CPP
│ │ ├── VSCLTOVE.ASM
│ │ ├── VTOBUFF.ASM
│ │ ├── VTOPAGE.ASM
│ │ ├── VTXTPRNT.ASM
│ │ ├── VVBLIT.ASM
│ │ ├── VVETOLB.ASM
│ │ ├── VVETOSCL.ASM
│ │ ├── VVETOSCL.CPP
│ │ ├── WINCOMM.CPP
│ │ ├── WINDOWS.CPP
│ │ ├── WINHIDE.CPP
│ │ ├── WPROFILE.CPP
│ │ ├── WRITELBM.CPP
│ │ ├── WRITEPCX.CPP
│ │ ├── WSA.CPP
│ │ ├── WWMOUSE.ASM
│ │ ├── XORDELTA.ASM
│ │ └── _DIPTABL.CPP
│ ├── TILE/
│ │ ├── ICONSET.CPP
│ │ ├── MAKEFILE
│ │ ├── MAKEFILE.BOR
│ │ ├── MAKEFILE.WAT
│ │ └── TILE.H
│ ├── TIMER/
│ │ ├── MAKEFILE
│ │ ├── MAKEFILE.BOR
│ │ ├── MAKEFILE.WAT
│ │ ├── TIMER.CPP
│ │ ├── TIMER.H
│ │ ├── TIMER.IDE
│ │ ├── TIMERDWN.CPP
│ │ └── TIMERINI.CPP
│ ├── WINCOMM/
│ │ ├── MAKEFILE
│ │ ├── MODEMREG.CPP
│ │ ├── MODEMREG.H
│ │ ├── WINCOMM.CPP
│ │ └── WINCOMM.H
│ ├── WSA/
│ │ ├── MAKEFILE
│ │ ├── MAKEFILE.BOR
│ │ ├── MAKEFILE.WAT
│ │ ├── WSA.CPP
│ │ ├── WSA.H
│ │ └── XORDELTA.ASM
│ └── WW_WIN/
│ ├── MAKEFILE
│ ├── MAKEFILE.BOR
│ ├── MAKEFILE.WAT
│ ├── OLD/
│ │ ├── MAKEFILE
│ │ ├── MAKEFILE.BOR
│ │ ├── MAKEFILE.WAT
│ │ ├── WINDOWS.CPP
│ │ ├── WINHIDE.CPP
│ │ └── WW_WIN.H
│ ├── WINDOWS.CPP
│ ├── WINHIDE.CPP
│ ├── WW_WIN.H
│ ├── WW_WIN.IDE
│ └── WW_WIN.IDE.BAK
├── WINVQ/
│ ├── INCLUDE/
│ │ ├── VOCFILE.H
│ │ ├── VQ.H
│ │ ├── VQA32/
│ │ │ ├── CAPTION.H
│ │ │ ├── SOS.H
│ │ │ ├── SOSDATA.H
│ │ │ ├── SOSDEFS.H
│ │ │ ├── SOSFNCT.H
│ │ │ ├── SOSRES.H
│ │ │ ├── UNVQ.H
│ │ │ ├── VQAFILE.H
│ │ │ ├── VQAPLAY.H
│ │ │ ├── VQAPLAY.H.BAK
│ │ │ └── VQAPLAYP.H
│ │ ├── VQFILE.H
│ │ ├── VQM32/
│ │ │ ├── ALL.H
│ │ │ ├── CAPTOKEN.H
│ │ │ ├── COMPRESS.H
│ │ │ ├── CRC.H
│ │ │ ├── FONT.H
│ │ │ ├── GRAPHICS.H
│ │ │ ├── HUFFMAN.H
│ │ │ ├── IFF.H
│ │ │ ├── MEM.H
│ │ │ ├── MIXFILE.H
│ │ │ ├── MONO.H
│ │ │ ├── PALETTE.H
│ │ │ ├── PORTIO.H
│ │ │ ├── PROFILE.H
│ │ │ ├── REALMODE.H
│ │ │ ├── SOSCOMP.H
│ │ │ ├── TARGA.H
│ │ │ ├── TEXT.H
│ │ │ ├── VESABLIT.H
│ │ │ ├── VESAVID.H
│ │ │ ├── VESAVID.I
│ │ │ ├── VGA.I
│ │ │ ├── VIDEO.H
│ │ │ └── VIDEO.I
│ │ ├── WAVEFILE.H
│ │ └── WWTYPES.H
│ ├── LIB/
│ │ ├── README.TXT
│ │ ├── SOSDBLC.LIB
│ │ ├── SOSDW1CR.LIB
│ │ ├── SOSDW1CS.LIB
│ │ ├── SOSDW1PR.LIB
│ │ ├── SOSDW1PS.LIB
│ │ └── SOSMBLC.LIB
│ ├── VPLAY32/
│ │ ├── BCC32.CFG
│ │ ├── CAPTION.FNT
│ │ ├── EVA.FNT
│ │ ├── MAKEFILE
│ │ ├── MAKEFILE.BOR
│ │ ├── MAKEFILE.WAT
│ │ ├── PLYVQA32.CPP
│ │ ├── TASM32.CFG
│ │ ├── TLIB.CFG
│ │ ├── TLINK32.CFG
│ │ └── VPLAYTNT.DEF
│ ├── VQA32/
│ │ ├── AUDIO.CPP
│ │ ├── BCC32.CFG
│ │ ├── CAPTION.CPP
│ │ ├── CAPTION.H
│ │ ├── CONFIG.CPP
│ │ ├── DRAWER.CPP
│ │ ├── DSTREAM.CPP
│ │ ├── LOADER.CPP
│ │ ├── MAKEFILE
│ │ ├── MAKEFILE.BAK
│ │ ├── MAKEFILE.BOR
│ │ ├── MAKEFILE.WAT
│ │ ├── MONODISP.CPP
│ │ ├── OLD/
│ │ │ ├── AUDIO.CPP
│ │ │ ├── BCC32.CFG
│ │ │ ├── CAPTION.CPP
│ │ │ ├── CAPTION.H
│ │ │ ├── CONFIG.CPP
│ │ │ ├── DRAWER.CPP
│ │ │ ├── DSTREAM.CPP
│ │ │ ├── LOADER.CPP
│ │ │ ├── MAKEFILE
│ │ │ ├── MAKEFILE.BOR
│ │ │ ├── MAKEFILE.WAT
│ │ │ ├── MONODISP.CPP
│ │ │ ├── SOS.H
│ │ │ ├── SOSDATA.H
│ │ │ ├── SOSDEFS.H
│ │ │ ├── SOSFNCT.H
│ │ │ ├── SOSRES.H
│ │ │ ├── TASK.CPP
│ │ │ ├── TASM32.CFG
│ │ │ ├── TLIB.CFG
│ │ │ ├── TLINK32.CFG
│ │ │ ├── UNVQ.H
│ │ │ ├── UNVQBUFF.ASM
│ │ │ ├── UNVQVESA.ASM
│ │ │ ├── UNVQXMDE.ASM
│ │ │ ├── VERTAG.CPP
│ │ │ ├── VQAFILE.H
│ │ │ ├── VQAPLAY.H
│ │ │ ├── VQAPLAY.I
│ │ │ └── VQAPLAYP.H
│ │ ├── SOS.H
│ │ ├── SOSDATA.H
│ │ ├── SOSDEFS.H
│ │ ├── SOSFNCT.H
│ │ ├── SOSRES.H
│ │ ├── TASK.CPP
│ │ ├── TASM32.CFG
│ │ ├── TLIB.CFG
│ │ ├── TLINK32.CFG
│ │ ├── UNVQ.H
│ │ ├── UNVQBUFF.ASM
│ │ ├── UNVQVESA.ASM
│ │ ├── UNVQXMDE.ASM
│ │ ├── VERTAG.CPP
│ │ ├── VQAFILE.H
│ │ ├── VQAPLAY.BAK
│ │ ├── VQAPLAY.H
│ │ ├── VQAPLAY.I
│ │ └── VQAPLAYP.H
│ ├── VQAVIEW/
│ │ ├── DEBUG.CPP
│ │ ├── DEBUG.RC
│ │ ├── DIALOGS.RC
│ │ ├── DIALOGS.RH
│ │ ├── GAMETIME.CPP
│ │ ├── GAMETIME.H
│ │ ├── INTERPAL.ASM
│ │ ├── MAIN.CPP
│ │ ├── MAIN.H
│ │ ├── MAINWIND.CPP
│ │ ├── MAINWIND.H
│ │ ├── MAKEFILE
│ │ ├── MENUS.RC
│ │ ├── MENUS.RH
│ │ ├── MONOCHRM.CPP
│ │ ├── MONOCHRM.H
│ │ ├── MOVIES.CPP
│ │ ├── MOVIES.H
│ │ ├── PAL.CPP
│ │ ├── PAL.H
│ │ ├── TEST.MAK
│ │ ├── VIDMODE.H
│ │ ├── VQ.CPP
│ │ ├── VQ.H
│ │ ├── VQAVIEW.IDE
│ │ ├── VQAVIEW.IDE.BAK
│ │ ├── WESTWOOD.H
│ │ ├── WM.CPP
│ │ ├── WM.H
│ │ └── WWLIB.H
│ └── VQM32/
│ ├── ALL.H
│ ├── AUDUNZAP.ASM
│ ├── AUDZAP.CPP
│ ├── BCC32.CFG
│ ├── CAPTOKEN.CPP
│ ├── CAPTOKEN.H
│ ├── CHRWIDTH.CPP
│ ├── COMPRESS.H
│ ├── CRC.ASM
│ ├── CRC.H
│ ├── DRAWCHAR.ASM
│ ├── DRAWCHAR.BAK
│ ├── FILLRECT.ASM
│ ├── FONT.CPP
│ ├── FONT.H
│ ├── GRAPHICS.H
│ ├── HUFFCMP.CPP
│ ├── HUFFDCMP.ASM
│ ├── HUFFMAN.H
│ ├── IFF.CPP
│ ├── IFF.H
│ ├── LCWCOMP.ASM
│ ├── LCWUNCMP.ASM
│ ├── MAKEFILE
│ ├── MAKEFILE.BOR
│ ├── MAKEFILE.WAT
│ ├── MCGABUF.ASM
│ ├── MEM.CPP
│ ├── MEM.H
│ ├── MIXFILE.CPP
│ ├── MIXFILE.H
│ ├── MONO.ASM
│ ├── MONO.H
│ ├── PALETTE.ASM
│ ├── PALETTE.H
│ ├── PORTIO.ASM
│ ├── PORTIO.H
│ ├── PROFILE.CPP
│ ├── PROFILE.H
│ ├── REALMODE.H
│ ├── SORTPAL.CPP
│ ├── SOSCODEC.ASM
│ ├── SOSCOMP.H
│ ├── TARGA.CPP
│ ├── TARGA.H
│ ├── TASM32.CFG
│ ├── TESTVB.CPP
│ ├── TEXT.H
│ ├── TEXTPRNT.ASM
│ ├── TLIB.CFG
│ ├── TLINK32.CFG
│ ├── VB.ASM
│ ├── VERTAG.CPP
│ ├── VESABLIT.CPP
│ ├── VESABLIT.H
│ ├── VESABUF.ASM
│ ├── VESAVID.CPP
│ ├── VESAVID.H
│ ├── VESAVID.I
│ ├── VGA.I
│ ├── VIDEO.CPP
│ ├── VIDEO.H
│ ├── VIDEO.I
│ ├── XMODE.ASM
│ └── XMODEPG.CPP
└── WWFLAT32/
├── AUDIO/
│ ├── AUDIO.BAK
│ ├── AUDIO.H
│ ├── AUDUNCMP.ASM
│ ├── DIFFTB.INC
│ ├── FUNCTION.H
│ ├── INDEXTB.INC
│ ├── MAKEFILE
│ ├── NEW/
│ │ ├── AUDIO.H
│ │ ├── AUDUNCMP.ASM
│ │ ├── DIFFTB.INC
│ │ ├── FUNCTION.H
│ │ ├── INDEXTB.INC
│ │ ├── MAKEFILE
│ │ ├── NYBBTB.INC
│ │ ├── SOS.H
│ │ ├── SOSCODEC.ASM
│ │ ├── SOSCOMP.H
│ │ ├── SOSDATA.H
│ │ ├── SOSDEFS.H
│ │ ├── SOSDW1PS.LIB
│ │ ├── SOSFNCT.H
│ │ ├── SOSRES.H
│ │ ├── SOUND.BAK
│ │ ├── SOUND.H
│ │ ├── SOUNDINT.BAK
│ │ ├── SOUNDINT.CPP
│ │ ├── SOUNDINT.H
│ │ ├── SOUNDIO.BAK
│ │ ├── SOUNDIO.CPP
│ │ └── SOUNDLCK.CPP
│ ├── NYBBTB.INC
│ ├── SOS.H
│ ├── SOSCODEC.ASM
│ ├── SOSCOMP.H
│ ├── SOSDATA.H
│ ├── SOSDEFS.H
│ ├── SOSDW1PS.LIB
│ ├── SOSFNCT.H
│ ├── SOSRES.H
│ ├── SOUND.BAK
│ ├── SOUND.H
│ ├── SOUNDINT.BAK
│ ├── SOUNDINT.CPP
│ ├── SOUNDINT.H
│ ├── SOUNDIO.BAK
│ ├── SOUNDIO.CPP
│ └── SOUNDLCK.CPP
├── DESCMGMT/
│ ├── DESCMGMT.CPP
│ ├── DESCMGMT.H
│ ├── FFIXSEL.ASM
│ ├── FGETCS.ASM
│ ├── FGETDS.ASM
│ ├── FGETSEL.ASM
│ └── MAKEFILE
├── DIPTHONG/
│ ├── DIPTHONG.CPP
│ ├── DIPTHONG.H
│ ├── MAKEFILE
│ └── _DIPTABL.CPP
├── EXAMPLE/
│ ├── DEFINES.H
│ ├── EXTERNS.H
│ ├── FUNCTION.H
│ ├── GLOBALS.CPP
│ ├── MAIN.CPP
│ ├── MAKEFILE
│ ├── STARTUP.CPP
│ ├── STRUCTS.H
│ └── WWLIB32.H
├── FILE/
│ ├── DEVICES.ASM
│ ├── DEVTABLE.ASM
│ ├── FFIRST.ASM
│ ├── FGLOB2.CPP
│ ├── FILE.BAK
│ ├── FILE.CPP
│ ├── FILE.H
│ ├── FILECACH.CPP
│ ├── FILECHNG.CPP
│ ├── FILEDATA.CPP
│ ├── FILEGLOB.CPP
│ ├── FILEINFO.CPP
│ ├── FILEINIT.CPP
│ ├── FILEIO.CPP
│ ├── FILELIB.CPP
│ ├── FILESTUB.CPP
│ ├── FILETEMP.H
│ ├── FINDFILE.BAK
│ ├── FINDFILE.CPP
│ ├── HARDERR.ASM
│ ├── MAKEFILE
│ ├── _FILE.BAK
│ └── _FILE.H
├── FONT/
│ ├── FONT.BAK
│ ├── FONT.CPP
│ ├── FONT.H
│ ├── LOADFONT.BAK
│ ├── LOADFONT.CPP
│ ├── MAKEFILE
│ ├── SETFPAL.ASM
│ ├── SET_FONT.CPP
│ ├── TEXTPRNT.ASM
│ └── TEXTPRNT.BAK
├── IFF/
│ ├── FILEPCX.H
│ ├── IFF.BAK
│ ├── IFF.CPP
│ ├── IFF.H
│ ├── LCWCOMP.ASM
│ ├── LCWUNCMP.ASM
│ ├── LOAD.BAK
│ ├── LOAD.CPP
│ ├── LOADPCX.CPP
│ ├── LOADPICT.BAK
│ ├── LOADPICT.CPP
│ ├── MAKEFILE
│ ├── PACK2PLN.ASM
│ ├── WRITELBM.CPP
│ └── WRITEPCX.CPP
├── INCLUDE/
│ ├── AUDIO.H
│ ├── BUFFER.H
│ ├── DESCMGMT.H
│ ├── DIFFTB.INC
│ ├── DIPTHONG.H
│ ├── FILE.H
│ ├── FILEPCX.H
│ ├── FILETEMP.H
│ ├── FONT.BAK
│ ├── FONT.H
│ ├── FUNCTION.H
│ ├── GBUFFER.BAK
│ ├── GBUFFER.H
│ ├── GBUFFER.INC
│ ├── IFF.H
│ ├── INDEXTB.INC
│ ├── KEYBOARD.H
│ ├── KEYBOARD.INC
│ ├── KEYSTRUC.INC
│ ├── MCGAPRIM.H
│ ├── MCGAPRIM.INC
│ ├── MEMFLAG.H
│ ├── MISC.BAK
│ ├── MISC.H
│ ├── MONO.BAK
│ ├── MONO.H
│ ├── NYBBTB.INC
│ ├── PALETTE.BAK
│ ├── PALETTE.H
│ ├── PLAYCD.H
│ ├── SHAPE.H
│ ├── SHAPE.INC
│ ├── SOS.H
│ ├── SOSCOMP.H
│ ├── SOSDATA.H
│ ├── SOSDEFS.H
│ ├── SOSFNCT.H
│ ├── SOSRES.H
│ ├── SOUND.H
│ ├── SOUNDINT.H
│ ├── STAMP.INC
│ ├── SVGAPRIM.INC
│ ├── TILE.H
│ ├── TIMER.BAK
│ ├── TIMER.H
│ ├── VBUFFER.H
│ ├── VIDEO.H
│ ├── WINDOW.H
│ ├── WSA.H
│ ├── WWLIB32.H
│ ├── WWMEM.H
│ ├── WWMEM.INC
│ ├── WWSTD.H
│ ├── WWSTD.H.BAK
│ └── _FILE.H
├── KEYBOARD/
│ ├── KEYBOARD.ASM
│ ├── KEYBOARD.BAK
│ ├── KEYBOARD.H
│ ├── KEYBOARD.INC
│ ├── KEYIPROT.ASM
│ ├── KEYIREAL.ASM
│ ├── KEYIREAL.BAK
│ ├── KEYIREAL.IBN
│ ├── KEYSTRUC.INC
│ ├── MAKEFILE
│ ├── MOUSE.ASM
│ ├── NEW/
│ │ ├── KEYBOARD.ASM
│ │ ├── KEYBOARD.BAK
│ │ ├── KEYBOARD.H
│ │ ├── KEYBOARD.INC
│ │ ├── KEYIPROT.ASM
│ │ ├── KEYIREAL.ASM
│ │ ├── KEYIREAL.BAK
│ │ ├── KEYIREAL.IBN
│ │ ├── KEYSTRUC.INC
│ │ ├── MAKEFILE
│ │ ├── MOUSE.ASM
│ │ └── PAGFAULT.ASM
│ ├── PAGFAULT.ASM
│ └── X/
│ ├── KEYBOARD.ASM
│ ├── KEYBOARD.BAK
│ ├── KEYBOARD.H
│ ├── KEYBOARD.INC
│ ├── KEYIPROT.ASM
│ ├── KEYIREAL.ASM
│ ├── KEYIREAL.BAK
│ ├── KEYIREAL.IBN
│ ├── KEYSTRUC.INC
│ ├── MAKEFILE
│ ├── MOUSE.ASM
│ └── PAGFAULT.ASM
├── LIB/
│ └── SOSDW1PS.LIB
├── MAKEFILE
├── MAKE_EXE.MAK
├── MAKE_LIB.MAK
├── MCGAPRIM/
│ ├── BITBLIT.ASM
│ ├── BUFFER.CPP
│ ├── BUFFER.H
│ ├── BUFFGLBL.CPP
│ ├── CLEAR.ASM
│ ├── DRAWLINE.ASM
│ ├── DRAWRECT.CPP
│ ├── DRAWRECT.CPP.BAK
│ ├── FILLQUAD.ASM
│ ├── FILLRECT.ASM
│ ├── GBUFFER.CPP
│ ├── GBUFFER.CPP.BAK
│ ├── GBUFFER.H
│ ├── GBUFFER.INC
│ ├── GETCLIP.ASM
│ ├── GETPIX.ASM
│ ├── MAKEFILE
│ ├── MCGAPRIM.H
│ ├── MCGAPRIM.INC
│ ├── MCGAPRIM.PJT
│ ├── PUTPIX.ASM
│ ├── REGIONSZ.CPP
│ ├── REMAP.ASM
│ ├── SCALE.ASM
│ ├── SHADOW.ASM
│ ├── STAMP.ASM
│ ├── STAMP.BAK
│ ├── STAMP.INC
│ ├── SZREGION.ASM
│ ├── TOBUFF.ASM
│ ├── TOPAGE.ASM
│ ├── TXTPRNT.ASM
│ ├── VBITBLIT.ASM
│ ├── VBUFFER.CPP
│ ├── VBUFFER.H
│ ├── VCLEAR.ASM
│ ├── VESA.ASM
│ ├── VGETPIX.ASM
│ ├── VLBTOVE.ASM
│ ├── VPUTPIX.ASM
│ ├── VSCALE.ASM
│ ├── VSCLTOVE.ASM
│ ├── VTOBUFF.ASM
│ ├── VTOPAGE.ASM
│ ├── VTXTPRNT.ASM
│ ├── VVBLIT.ASM
│ ├── VVETOLB.ASM
│ └── VVETOSCL.ASM
├── MEM/
│ ├── ALLOC.CPP
│ ├── ALLOC.CPP.BAK
│ ├── MAKEFILE
│ ├── MEM.CPP
│ ├── MEM.CPP.BAK
│ ├── MEMFLAG.H
│ ├── MEM_COPY.ASM
│ ├── NEWDEL.CPP
│ ├── OLD/
│ │ ├── ALLOC.CPP
│ │ ├── MAKEFILE
│ │ ├── MEM.CPP
│ │ ├── MEMFLAG.H
│ │ ├── MEM_COPY.ASM
│ │ ├── NEWDEL.CPP
│ │ ├── WWMEM.H
│ │ └── WWMEM.INC
│ ├── WWMEM.H
│ └── WWMEM.INC
├── MISC/
│ ├── ASM.ASM
│ ├── ASM.ASM.BAK
│ ├── CLIPRECT.ASM
│ ├── CRC.ASM
│ ├── CRC.IDE
│ ├── DELAY.CPP
│ ├── DETPROC.ASM
│ ├── EXIT.CPP
│ ├── FACING16.ASM
│ ├── FACING8.ASM
│ ├── FACINGFF.ASM
│ ├── FADING.ASM
│ ├── FINDARGV.CPP
│ ├── IRANDOM.CPP
│ ├── KEYCODE.CPP
│ ├── KEYCODE.CPP.BAK
│ ├── LIB.CPP
│ ├── MAKEFILE
│ ├── MISC.H
│ ├── OPSYS.ASM
│ ├── PROC.ASM
│ ├── RANDOM.ASM
│ ├── REVERSE.ASM
│ ├── SHAKESCR.ASM
│ ├── VERSION.CPP
│ ├── WWLIB32.H
│ └── WWSTD.H
├── MONO/
│ ├── INITMONO.CPP
│ ├── MAKEFILE
│ ├── MONO.ASM
│ ├── MONO.H
│ └── MONOPRNT.CPP
├── PALETTE/
│ ├── LOADPAL.CPP
│ ├── MAKEFILE
│ ├── MORPHPAL.CPP
│ ├── PAL.ASM
│ ├── PALETTE.CPP
│ └── PALETTE.H
├── PLAYCD/
│ ├── GETCD.CPP
│ ├── GETCD.CPP.BAK
│ ├── MAKEFILE
│ ├── PLAYCD.ASM
│ ├── PLAYCD.H
│ ├── PLAYCD.H.BAK
│ └── REDBOOK.CPP
├── PROJECT.CFG
├── SHAPE/
│ ├── DRAWSHP.ASM
│ ├── DS_DN.ASM
│ ├── DS_DR.ASM
│ ├── DS_DS.ASM
│ ├── DS_DSR.ASM
│ ├── DS_LRS.ASM
│ ├── DS_LS.ASM
│ ├── DS_LSRS.ASM
│ ├── DS_LSS.ASM
│ ├── DS_RRS.ASM
│ ├── DS_RS.ASM
│ ├── DS_RSRS.ASM
│ ├── DS_RSS.ASM
│ ├── DS_TABLE.ASM
│ ├── GETSHAPE.CPP
│ ├── MAKEFILE
│ ├── PRIOINIT.CPP
│ ├── SETSHAPE.ASM
│ ├── SHAPE.H
│ └── SHAPE.INC
├── SRCDEBUG/
│ ├── ALLOC.CPP
│ ├── KEYBOARD.ASM
│ ├── KEYIPROT.ASM
│ ├── KEYIREAL.ASM
│ ├── MEM.CPP
│ ├── MEM_COPY.ASM
│ ├── MOUSE.ASM
│ ├── NEWDEL.CPP
│ └── PAGFAULT.ASM
├── SVGAPRIM/
│ ├── MAKEFILE
│ ├── SVGAPRIM.INC
│ ├── VCLEAR.ASM
│ ├── VESA.ASM
│ ├── VGETPIX.ASM
│ ├── VLBTOVE.ASM
│ ├── VPUTPIX.ASM
│ ├── VSCALE.CPP
│ ├── VSCLTOVE.ASM
│ ├── VTOBUFF.ASM
│ ├── VTOPAGE.ASM
│ ├── VTXTPRNT.ASM
│ ├── VVBLIT.ASM
│ ├── VVETOLB.ASM
│ └── VVETOSCL.CPP
├── TILE/
│ ├── ICONSET.BAK
│ ├── ICONSET.CPP
│ ├── MAKEFILE
│ ├── TILE.H
│ └── TILE.H.BAK
├── TIMER/
│ ├── MAKEFILE
│ ├── TIMER.CPP
│ ├── TIMER.H
│ ├── TIMERA.ASM
│ ├── TIMERA.BAK
│ ├── TIMERDWN.CPP
│ ├── TIMEREAL.ASM
│ ├── TIMEREAL.IBN
│ └── TIMERINI.CPP
├── VIDEO/
│ ├── INITDLAY.CPP
│ ├── MAKEFILE
│ ├── VERTBLNK.ASM
│ ├── VESAHOOK.ASM
│ ├── VESAINFO.CPP
│ ├── VESAREAL.ASM
│ ├── VESAREAL.IBN
│ ├── VIDEO.CPP
│ └── VIDEO.H
├── WINDOWS/
│ ├── MAKEFILE
│ ├── WINDOW.H
│ ├── WINDOWS.CPP
│ ├── WINDOWS.CPP.BAK
│ ├── WINDOWS.H
│ ├── WINHIDE.CPP
│ └── WINHIDE.CPP.BAK
└── WSA/
├── MAKEFILE
├── WSA.CPP
├── WSA.H
└── XORDELTA.ASM
================================================
FILE CONTENTS
================================================
================================================
FILE: CODE/2KEYFBUF.ASM
================================================
;
; 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 .
;
;***************************************************************************
;** 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
; 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
USE BF_Copy, BufferFrameTable
WANT equ
USE BF_Trans
WANT equ
USE BF_Ghost
WANT equ
USE BF_Ghost_Trans
WANT equ
USE BF_Fading
WANT equ
USE BF_Fading_Trans
WANT equ
USE BF_Ghost_Fading
WANT equ
USE BF_Ghost_Fading_Trans
WANT equ
USE BF_Predator
WANT equ
USE BF_Predator_Trans
WANT equ
USE BF_Predator_Ghost
WANT equ
USE BF_Predator_Ghost_Trans
WANT equ
USE BF_Predator_Fading
WANT equ
USE BF_Predator_Fading_Trans
WANT equ
USE BF_Predator_Ghost_Fading
WANT equ
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
================================================
FILE: CODE/2KEYFRAM.CPP
================================================
/*
** 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 .
*/
/* $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 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);
}
================================================
FILE: CODE/2SUPPORT.ASM
================================================
;
; 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 .
;
; $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
================================================
FILE: CODE/2TXTPRNT.ASM
================================================
;
; 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 .
;
;***************************************************************************
;** 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 or was specified. = left margin
; = 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
================================================
FILE: CODE/AADATA.CPP
================================================
/*
** 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 .
*/
/* $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));
}
================================================
FILE: CODE/ABSTRACT.CPP
================================================
/*
** 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 .
*/
/* $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);
}
================================================
FILE: CODE/ABSTRACT.H
================================================
/*
** 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 .
*/
/* $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
================================================
FILE: CODE/ADAMTEMP.MAK
================================================
#
# 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 .
#
# $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
================================================
FILE: CODE/ADATA.CPP
================================================
/*
** 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 .
*/
/* $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));
}
================================================
FILE: CODE/ADPCM.CPP
================================================
/*
** 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 .
*/
#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);
}
}
================================================
FILE: CODE/AIRCRAFT.CPP
================================================
/*
** 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 .
*/
/* $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);
}
}
================================================
FILE: CODE/AIRCRAFT.H
================================================
/*
** 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 .
*/
/* $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 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 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
================================================
FILE: CODE/ALLOC.CPP
================================================
/*
** 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 .
*/
/***************************************************************************
** 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
#include
#include
#include
#include
#include
#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 (®s, 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, ®s, ®s, &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 (®s, 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, ®s, ®s, &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, ®s, ®s, &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 () ;
}
================================================
FILE: CODE/ANIM.CPP
================================================
/*
** 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 .
*/
/* $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
}
================================================
FILE: CODE/ANIM.CPP.BAK
================================================
/*
** 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 .
*/
/* $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);
}
}
================================================
FILE: CODE/ANIM.H
================================================
/*
** 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 .
*/
/* $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 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
================================================
FILE: CODE/AUDIO.CPP
================================================
/*
** 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 .
*/
/* $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);
}
================================================
FILE: CODE/AUDIO.CPP.BAK
================================================
/*
** 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 .
*/
/* $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);
}
================================================
FILE: CODE/AUDIO.H
================================================
/*
** 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 .
*/
/* $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
================================================
FILE: CODE/B64PIPE.CPP
================================================
/*
** 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 .
*/
/* $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
/***********************************************************************************************
* 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);
}
================================================
FILE: CODE/B64PIPE.H
================================================
/*
** 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 .
*/
/* $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
================================================
FILE: CODE/B64STRAW.CPP
================================================
/*
** 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 .
*/
/* $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
/***********************************************************************************************
* 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);
}
================================================
FILE: CODE/B64STRAW.H
================================================
/*
** 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 .
*/
/* $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
================================================
FILE: CODE/BAR.CPP
================================================
/*
** 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 .
*/
/* $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;
}
================================================
FILE: CODE/BAR.H
================================================
/*
** 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 .
*/
/* $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
================================================
FILE: CODE/BASE.CPP
================================================
/*
** 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 .
*/
/* $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);
}
}
}
================================================
FILE: CODE/BASE.H
================================================
/*
** 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 .
*/
/* $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 Nodes;
/*
** This is the house this base belongs to.
*/
HousesType House;
};
#endif
================================================
FILE: CODE/BASE64.CPP
================================================
/*
** 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 .
*/
/* $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
/*
** 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.
*/
================================================
FILE: CODE/BASE64.H
================================================
/*
** 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 .
*/
/* $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);
================================================
FILE: CODE/BBDATA.CPP
================================================
/*
** 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 .
*/
/* $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);
}
================================================
FILE: CODE/BDATA.CPP
================================================
/*
** 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 .
*/
/* $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);
}
================================================
FILE: CODE/BENCH.CPP
================================================
/*
** 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 .
*/
/* $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);
}
================================================
FILE: CODE/BENCH.H
================================================
/*
** 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 .
*/
/* $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 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
================================================
FILE: CODE/BFILE.MAK
================================================
#
# 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 .
#
# $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
================================================
FILE: CODE/BFILE2.MAK
================================================
#
# 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 .
#
# $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
================================================
FILE: CODE/BFIOFILE.CPP
================================================
/*
** 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 .
*/
/* $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
/***********************************************************************************************
* 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();
}
}
================================================
FILE: CODE/BFIOFILE.H
================================================
/*
** 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 .
*/
/* $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
================================================
FILE: CODE/BIGCHECK.CPP
================================================
/*
** 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 .
*/
// 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
================================================
FILE: CODE/BIGCHECK.H
================================================
/*
** 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 .
*/
// 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
================================================
FILE: CODE/BLOWFISH.CPP
================================================
/*
** 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 .
*/
/* $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
#include
/*
** 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
}
};
================================================
FILE: CODE/BLOWFISH.H
================================================
/*
** 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 .
*/
/* $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
/*
** 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
================================================
FILE: CODE/BLOWPIPE.CPP
================================================
/*
** 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 .
*/
/* $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
#include
/***********************************************************************************************
* 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);
}
}
================================================
FILE: CODE/BLOWPIPE.H
================================================
/*
** 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 .
*/
/* $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
================================================
FILE: CODE/BLWSTRAW.CPP
================================================
/*
** 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 .
*/
/* $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
#include
/***********************************************************************************************
* 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);
}
}
================================================
FILE: CODE/BLWSTRAW.H
================================================
/*
** 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 .
*/
/* $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
================================================
FILE: CODE/BMP8.CPP
================================================
/*
** 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 .
*/
#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<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<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);
}
================================================
FILE: CODE/BMP8.H
================================================
/*
** 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 .
*/
#ifndef BMP8_H
#define BMP8_H
//#include
//#include
//#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
================================================
FILE: CODE/BUFF.CPP
================================================
/*
** 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 .
*/
/* $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
/***********************************************************************************************
* 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;
}
================================================
FILE: CODE/BUFF.H
================================================
/*
** 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 .
*/
/* $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
================================================
FILE: CODE/BUFFERX.H
================================================
/*
** 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 .
*/
/* $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
================================================
FILE: CODE/BUGS.TXT
================================================
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
================================================
FILE: CODE/BUILDING.CPP
================================================
/*
** 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 .
*/
/* $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));
}
================================================
FILE: CODE/BUILDING.H
================================================
/*
** 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 .
*/
/* $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 Class;
/*
** If this building is in the process of producing something, then this
** will point to the factory manager.
*/
CCPtr 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 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 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
================================================
FILE: CODE/BULLET.CPP
================================================
/*
** 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 .
*/
/* $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;
}
}
================================================
FILE: CODE/BULLET.H
================================================
/*
** 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 .
*/
/* $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 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
================================================
FILE: CODE/C&CZERO.PJT
================================================
;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'
================================================
FILE: CODE/CARGO.CPP
================================================
/*
** 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 .
*/
/* $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);
}
================================================
FILE: CODE/CARGO.H
================================================
/*
** 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 .
*/
/* $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
================================================
FILE: CODE/CARRY.CPP
================================================
/*
** 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 .
*/
/* $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);
}
================================================
FILE: CODE/CARRY.H
================================================
/*
** 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 .
*/
/* $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
================================================
FILE: CODE/CCDDE.CPP
================================================
/*
** 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 .
*/
/***********************************************************************************************
*** 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
#include "ccdde.h"
#include
#include
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
================================================
FILE: CODE/CCDDE.H
================================================
/*
** 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 .
*/
/***********************************************************************************************
*** 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
================================================
FILE: CODE/CCFILE.CPP
================================================
/*
** 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 .
*/
/* $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
#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)
{
}
================================================
FILE: CODE/CCFILE.H
================================================
/*
** 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 .
*/
/* $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
#include
#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;
#endif
================================================
FILE: CODE/CCINI.CPP
================================================
/*
** 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 .
*/
/* $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, ""));
}
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, ""));
}
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 = "";
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, ""));
}
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, ""));
}
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, ""));
}
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, ""));
}
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, ""));
}
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;
}
================================================
FILE: CODE/CCINI.H
================================================
/*
** 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 .
*/
/* $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
================================================
FILE: CODE/CCMPATH.CPP
================================================
/*
** 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 .
*/
/***************************************************************************
* *
* 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 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 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 **************************/
================================================
FILE: CODE/CCPTR.CPP
================================================
/*
** 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 .
*/
/* $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::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
CCPtr::CCPtr(T * ptr) : ID(-1)
{
if (ptr != NULL) {
ID = ptr->ID;
}
}
/***********************************************************************************************
* CCPtr::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
bool CCPtr::operator > (CCPtr const & rvalue) const
{
return (stricmp((*this)->Name(), rvalue->Name()) > 0);
}
================================================
FILE: CODE/CCPTR.H
================================================
/*
** 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 .
*/
/* $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 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 const & rvalue) const {return(ID == rvalue.ID);}
bool operator != (CCPtr const & rvalue) const {return(ID != rvalue.ID);}
bool operator > (CCPtr const & rvalue) const;
bool operator <= (CCPtr const & rvalue) const {return (rvalue > *this);}
bool operator < (CCPtr const & rvalue) const {return (*this != rvalue && rvalue > *this);}
bool operator >= (CCPtr 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
int operator == (CCPtr & lvalue, T * rvalue)
{
return((T*)lvalue == rvalue);
}
template
int operator == (T * lvalue, CCPtr & rvalue)
{
return(lvalue == (T*)rvalue);
}
#endif
================================================
FILE: CODE/CCTEN.CPP
================================================
/*
** 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 .
*/
/***************************************************************************
* *
* 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 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 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;iNum_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 *****************************/
================================================
FILE: CODE/CC_ICON.RC
================================================
#define ICON_1 1
ICON_1 ICON "redalert.ico"
================================================
FILE: CODE/CC_ICON.RH
================================================
#define ICON_1 1
================================================
FILE: CODE/CDATA.CPP
================================================
/*
** 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 .
*/
/* $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< 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);
}
================================================
FILE: CODE/CDFILE.CPP
================================================
/*
** 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 .
*/
/* $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
#include
#ifndef WIN32
#include
#include
#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, ®s, ®s);
if (regs.w.bx == 0xADAD) {
return(index);
}
}
return(0);
#else
GetCDClass temp;
return(temp.GetCDDrive());
#endif
#endif
}
#endif
================================================
FILE: CODE/CDFILE.H
================================================
/*
** 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 .
*/
/* $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
#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
================================================
FILE: CODE/CELL.CPP
================================================
/*
** 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 .
*/
/* $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< 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);
}
================================================
FILE: CODE/CELL.H
================================================
/*
** 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 .
*/
/* $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 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
================================================
FILE: CODE/CHECKBOX.CPP
================================================
/*
** 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 .
*/
/* $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));
}
================================================
FILE: CODE/CHECKBOX.H
================================================
/*
** 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 .
*/
/* $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
================================================
FILE: CODE/CHEKLIST.CPP
================================================
/*
** 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 .
*/
/* $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);
}
}
================================================
FILE: CODE/CHEKLIST.H
================================================
/*
** 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 .
*/
/* $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
================================================
FILE: CODE/CLASS.CPP
================================================
/*
** 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 .
*/
================================================
FILE: CODE/CO-WC32.LNT
================================================
// 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)
================================================
FILE: CODE/COLRLIST.CPP
================================================
/*
** 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 .
*/
/* $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;
}
}
================================================
FILE: CODE/COLRLIST.H
================================================
/*
** 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 .
*/
/* $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 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
================================================
FILE: CODE/COMBAT.CPP
================================================
/*
** 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 .
*/
/* $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));
}
}
}
}
================================================
FILE: CODE/COMBUF.CPP
================================================
/*
** 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 .
*/
/* $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
#include
#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 ******************************/
================================================
FILE: CODE/COMBUF.H
================================================
/*
** 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 .
*/
/* $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 ******************************/
================================================
FILE: CODE/COMINIT.CPP
================================================
/*
** 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 .
*/
//
// If you link with this it will automatically call the COM initialization stuff
//
#include "cominit.h"
//#include
//#include
//#include
#include
//#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;
================================================
FILE: CODE/COMINIT.H
================================================
/*
** 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 .
*/
#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
================================================
FILE: CODE/COMPAT.H
================================================
/*
** 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 .
*/
/* $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
================================================
FILE: CODE/COMQUEUE.CPP
================================================
/*
** 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 .
*/
/* $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
}
================================================
FILE: CODE/COMQUEUE.H
================================================
/*
** 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 .
*/
/* $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 *****************************/
================================================
FILE: CODE/CONFDLG.CPP
================================================
/*
** 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 .
*/
/* $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);
}
================================================
FILE: CODE/CONFDLG.H
================================================
/*
** 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 .
*/
/* $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
================================================
FILE: CODE/CONNECT.CPP
================================================
/*
** 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 .
*/
/* $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
#include
#include
#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 *****************************/
================================================
FILE: CODE/CONNECT.CPP.BAK
================================================
/*
** 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 .
*/
/* $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
#include
#include
#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 *****************************/
================================================
FILE: CODE/CONNECT.H
================================================
/*
** 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 .
*/
/* $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 *****************************/
================================================
FILE: CODE/CONNMGR.H
================================================
/*
** 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 .
*/
/* $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
================================================
FILE: CODE/CONQUER.CPP
================================================
/*
** 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 .
*/
/* $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 B {
public:
enum {VAR2=T::VAR}; // this is the line in question.
};
B 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
#include
#include
#include
#include
#include
#include
#include
#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 (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 (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 (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 _timer;
static CDTimerClass _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 . *
* *
* 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, "Insrez 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, "Insrez 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, "Insrez 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, "Insrez 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
================================================
FILE: CODE/CONQUER.CPP.BAK
================================================
/*
** 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 .
*/
/* $Header: F:\projects\c&c0\vcs\code\conquer.cpv 4.83 24 Oct 1996 12:55:42 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 : 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. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifdef TESTCODE
class A {
public:
enum {VAR=1};
};
template
class B {
public:
enum {VAR2=T::VAR}; // this is the line in question.
};
B test;
#endif
#include "function.h"
#ifdef WIN32
#include "tcpip.h"
#else
#include "fakesock.h"
TcpipManagerClass Winsock;
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include "ccdde.h"
#include "vortex.h"
#define SHAPE_TRANS 0x40
void * Get_Shape_Header_Data(void * ptr);
extern bool Spawn_WChat(void);
/****************************************
** 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------------------
--------------------------------------------------*/
/***********************************************************************************************
* 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 {
DDEServer.Disable();
}
#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) {
TimeQuake = false;
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 (;;) {
TimeQuake = false;
/*
**call the game's main loop
*/
//VG_MONO
Mono_Print("About to call Main Loop in Main Game/n/n");
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;
default:
break;
}
}
}
#endif
#ifdef WIN32
/*
** Send the game stats to WChat if we havnt already done so
*/
if (!GameStatisticsPacketSent && PacketLater) {
Send_Statistics_Packet();
}
#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 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;
}
#ifdef WIN32
if (Special.IsFromWChat) {
Shutdown_Network(); // Clear up the pseudo IPX stuff
Winsock.Close();
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(); //Will switch back to Wchat. It must be there because its been poking us
}
#endif //WIN32
}
/*
** 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)".
*/
if (Session.Type != GAME_NORMAL && Session.Type != GAME_SKIRMISH && input >= KN_F1 && input < (KN_F1 + Session.MaxPlayers) && !Session.Messages.Is_Edit()) {
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 (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);
} else if ((input - KN_F1) < Ipx.Num_Connections() && !Session.ObiWan) {
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);
}
}
}
/*
** 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);
} 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);
strcpy(Session.LastMessage, serial_packet->Message.Message);
} else if (Session.Type == GAME_IPX || Session.Type == GAME_INTERNET) {
/*
** 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()) {
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);
}
/*
** 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 _timer;
static CDTimerClass _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();
}
}
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)) {
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);
}
}
}
}
}
}
/***********************************************************************************************
* 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;
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 {
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;
/*
** 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();
}
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();
}
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);
}
/*
** 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[50];
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 < 50; i++) {
InterpolatedPalettes[i]=NULL;
}
start_palette=0;
} else {
for (start_palette = 0; start_palette < 50; 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 < 50 ;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)
{
/*
** Don't play movies in editor mode
*/
if (Debug_Map) {
return;
}
/*
** Don't play movies in multiplayer mode
*/
if (Session.Type != GAME_NORMAL) {
return;
}
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()) 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);
}
/*
** 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;
}
}
/***********************************************************************************************
* 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 < sizeof(Scen.Views)/sizeof(Scen.Views[0])) {
if (action == 0) {
Map.Set_Tactical_Position(Coord_Whole(Cell_Coord(Scen.Views[view])));
#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);
}
}
}
#ifndef ROR_NOT_READY
#define ROR_NOT_READY 21
#endif
static char * _CD_Volume_Label[] = {
"CD1",
"CD2",
};
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 *
* -1 = non C&C *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 5/21/96 5:27PM ST : Created *
*=============================================================================================*/
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". *
* *
* OUTPUT: Is the CD inserted and available? If false is returned, then this indicates that *
* the player pressed . *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/11/1995 JLB : Created. *
* 05/22/1996 ST : Handles multiple CD drives / CD changers *
*=============================================================================================*/
bool Force_CD_Available(int cd)
{
#ifndef DEMO
static int _last = -1;
#endif
// static char _palette[768];
// static char _hold[256];
static void *font;
static char * _cd_name[] = {
"RED ALERT DISK 1",
"RED ALERT DISK 2",
};
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;
/*
** 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 == -2) 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);
if (cd_index >= 0) {
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();
if (!new_cd_drive) {
/*
** Check the last CD drive we used if its different from the current one
*/
int last_drive = CCFileClass::Get_Last_CD_Drive();
/*
** Make sure the last drive is valid and it isnt 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);
if (cd_index >= 0) {
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 cant 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=0) {
/*
** We found a C&C cd - lets see if it was the one we were looking for
*/
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.
*/
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]);
}
#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;
#ifndef DEMO
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 > -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();
}
#endif
if (theme_playing != THEME_NONE) {
Theme.Queue_Song(theme_playing);
}
return(true);
}
/***************************************************************************
* 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
================================================
FILE: CODE/CONQUER.H
================================================
/*
** 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 .
*/
#define TXT_NONE 0 //
#define TXT_CREDIT_FORMAT 1 // %3d.%02d
#define TXT_TIME_FORMAT_HOURS 2 // Temps:%02d:%02d:%02d
#define TXT_TIME_FORMAT_NO_HOURS 3 // Temps:%02d:%02d
#define TXT_BUTTON_SELL 4 // Vente
#define TXT_SELL 5 // Vente structure
#define TXT_BUTTON_REPAIR 6 // Rparation
#define TXT_YOU 7 // Vous :
#define TXT_ENEMY 8 // Ennemi :
#define TXT_BUILD_DEST 9 // Btiments dtruits par
#define TXT_UNIT_DEST 10 // Units dtruites par
#define TXT_TIB_HARV 11 // Minerai rcolt par
#define TXT_SCORE_1 12 // Score: %d
#define TXT_YES 13 // Oui
#define TXT_NO 14 // Non
#define TXT_SCENARIO_WON 15 // Mission Accomplie
#define TXT_SCENARIO_LOST 16 // Mission Echoue
#define TXT_START_NEW_GAME 17 // Nouvelle partie
#define TXT_INTRO 18 // Intro/Preview
#define TXT_CANCEL 19 // Annuler
#define TXT_ROCK 20 // Rocher
#define TXT_CIVILIAN 21 // Civil
#define TXT_JP 22 // Equipe de confinement
#define TXT_OK 23 // OK
#define TXT_TREE 24 // Arbre
#define TXT_LEFT 25 //
#define TXT_RIGHT 26 //
#define TXT_UP 27 //
#define TXT_DOWN 28 //
#define TXT_CLEAR 29 // Effacer
#define TXT_WATER 30 // Eau
#define TXT_ROAD 31 // Route
#define TXT_SLOPE 32 // Pente
#define TXT_PATCH 33 // Patch
#define TXT_RIVER 34 // Rivire
#define TXT_LOAD_MISSION 35 // Charger Mission
#define TXT_SAVE_MISSION 36 // Sauvegarder Mission
#define TXT_DELETE_MISSION 37 // Effacer Mission
#define TXT_LOAD_BUTTON 38 // Charger
#define TXT_SAVE_BUTTON 39 // Sauvegarder
#define TXT_DELETE_BUTTON 40 // Effacer
#define TXT_GAME_CONTROLS 41 // Contrles
#define TXT_SOUND_CONTROLS 42 // Son
#define TXT_RESUME_MISSION 43 // Reprendre Mission
#define TXT_VISUAL_CONTROLS 44 // Affichage
#define TXT_QUIT_MISSION 45 // Abandonner Mission
#define TXT_EXIT_GAME 46 // Quitter le jeu
#define TXT_OPTIONS 47 // Options
#define TXT_SQUISH 48 // Dbris humains
#define TXT_CRATER 49 // Cratre
#define TXT_SCORCH 50 // Marque de brlure
#define TXT_BRIGHTNESS 51 // Luminosit :
#define TXT_MUSIC 52 // Musique
#define TXT_VOLUME 53 // Effets sonores
#define TXT_TINT 54 // Teintes :
#define TXT_CONTRAST 55 // Contraste :
#define TXT_SPEED 56 // Vitesse du jeu :
#define TXT_SCROLLRATE 57 // Vitesse dfilement :
#define TXT_COLOR 58 // Couleur :
#define TXT_RETURN_TO_GAME 59 // Revenir au jeu
#define TXT_ENEMY_SOLDIER 60 // Soldat ennemi
#define TXT_ENEMY_VEHICLE 61 // Vhicule ennemi
#define TXT_ENEMY_STRUCTURE 62 // Structure ennemie
#define TXT_LTANK 63 // Tank lger
#define TXT_MTANK 64 // Tank lourd
#define TXT_MTANK2 65 // Tank moyen
#define TXT_HTANK 66 // Tank Mammouth
#define TXT_SAM 67 // Missiles SAM
#define TXT_JEEP 68 // Ranger
#define TXT_TRANS 69 // Hlicoptre Chinook
#define TXT_HARVESTER 70 // Collecteur minerai
#define TXT_ARTY 71 // Artillerie
#define TXT_E1 72 // Mitrailleurs
#define TXT_E2 73 // Grenadiers
#define TXT_E3 74 // Bazookas
#define TXT_E4 75 // Lance-flammes
#define TXT_HELI 76 // Hlicoptre d'assaut
#define TXT_ORCA 77 // Hind
#define TXT_APC 78 // VBT
#define TXT_GUARD_TOWER 79 // Tour de garde
#define TXT_COMMAND 80 // Dme radar
#define TXT_HELIPAD 81 // Hliport
#define TXT_AIRSTRIP 82 // Piste d'atterrissage
#define TXT_STORAGE 83 // Silo minerai
#define TXT_CONST_YARD 84 // Chantier de construction
#define TXT_REFINERY 85 // Raffinerie de minerai
#define TXT_CIV1 86 // Eglise
#define TXT_CIV2 87 // Chez Hans et Gretel
#define TXT_CIV3 88 // Manoir d'Hewitt
#define TXT_CIV4 89 // Maison de Ricktor
#define TXT_CIV5 90 // Maison de Gretchin
#define TXT_CIV6 91 // La grange
#define TXT_CIV7 92 // Pub Damon
#define TXT_CIV8 93 // Maison de Fran
#define TXT_CIV9 94 // Usine d'instruments
#define TXT_CIV10 95 // Fabricant de jouets
#define TXT_CIV11 96 // Maison de Ludwig
#define TXT_CIV12 97 // Meules de foin
#define TXT_CIV13 98 // Meule de foin
#define TXT_CIV14 99 // Champ de bl
#define TXT_CIV15 100 // Champ en friche
#define TXT_CIV16 101 // Champ de mas
#define TXT_CIV17 102 // Champ de cleri
#define TXT_CIV18 103 // Champ de pommes de terre
#define TXT_CIV20 104 // Maison de Sala
#define TXT_CIV21 105 // Maison d'Abdul
#define TXT_CIV22 106 // Le Pub Barjo de Pablo
#define TXT_CIV23 107 // Puits du village
#define TXT_CIV24 108 // Marchand de chameaux
#define TXT_CIV25 109 // Eglise
#define TXT_CIV26 110 // Maison d'Ali
#define TXT_CIV27 111 // Ted le Marchand
#define TXT_CIV28 112 // Maison de Menelik
#define TXT_CIV29 113 // Maison du pasteur John
#define TXT_CIV30 114 // Puits du village
#define TXT_CIV31 115 // Hutte du gurisseur
#define TXT_CIV32 116 // Hutte de Rikitikitembo
#define TXT_CIV33 117 // Hutte de Roarke
#define TXT_CIV34 118 // Hutte de Moubasa'
#define TXT_CIV35 119 // Hutte d'Aksoum
#define TXT_CIV36 120 // Hutte de Mambo
#define TXT_CIV37 121 // Le studio
#define TXT_CIVMISS 122 // Centre technologique
#define TXT_TURRET 123 // Tourelle
#define TXT_GUNBOAT 124 // Aviso-torpilleur
#define TXT_MCV 125 // Vhicule de construction
#define TXT_POWER 126 // Centrale lectrique
#define TXT_ADVANCED_POWER 127 // Centrale lectrique avance
#define TXT_HOSPITAL 128 // Hpital
#define TXT_BARRACKS 129 // Caserne
#define TXT_PUMP 130 // Pompe
#define TXT_TANKER 131 // Ptrolier
#define TXT_SANDBAG_WALL 132 // Sacs de sable
#define TXT_CYCLONE_WALL 133 // Clture grillage
#define TXT_BRICK_WALL 134 // Mur de bton
#define TXT_BARBWIRE_WALL 135 // Clture barbele
#define TXT_WOOD_WALL 136 // Barrire de bois
#define TXT_WEAPON_FACTORY 137 // Usine d'armement
#define TXT_AGUARD_TOWER 138 // Tour de garde avance
#define TXT_BIO_LAB 139 // Laboratoire biologique
#define TXT_FIX_IT 140 // Centre de service
#define TXT_TAB_SIDEBAR 141 // Contrles
#define TXT_TAB_BUTTON_CONTROLS 142 // Options
#define TXT_TAB_BUTTON_DATABASE 143 // Base de donnes
#define TXT_SHADOW 144 // Terrain inconnu
#define TXT_OPTIONS_MENU 145 // Menu des options
#define TXT_STOP 146 // Stop
#define TXT_PLAY 147 // Lect
#define TXT_SHUFFLE 148 // Alat.
#define TXT_REPEAT 149 // Rpter
#define TXT_MUSIC_VOLUME 150 // Musique :
#define TXT_SOUND_VOLUME 151 // Effets sonores :
#define TXT_ON 152 // Oui
#define TXT_OFF 153 // Non
#define TXT_MULTIPLAYER_GAME 154 // Jeu Multijoueurs
#define TXT_NO_FILES 155 // Pas de fichiers disponibles
#define TXT_DELETE_SINGLE_FILE 156 // Voulez-vous effacer ce
#define TXT_DELETE_MULTIPLE_FILES 157 // Voulez-vous effacer %d
#define TXT_RESET_MENU 158 // Dfaut
#define TXT_CONFIRM_EXIT 159 // Voulez-vous abandonner la
#define TXT_MISSION_DESCRIPTION 160 // Description de la mission
#define TXT_C1 161 // Joe
#define TXT_C2 162 // Barry
#define TXT_C3 163 // Shelly
#define TXT_C4 164 // Maria
#define TXT_C5 165 // Karen
#define TXT_C6 166 // Steve
#define TXT_C7 167 // Phil
#define TXT_C8 168 // Dwight
#define TXT_C9 169 // Erik
#define TXT_EINSTEIN 170 // Prof. Einstein
#define TXT_BIB 171 // Cour
#define TXT_FASTER 172 // Rapide
#define TXT_SLOWER 173 // Lent
#define TXT_AIR_STRIKE 174 // Attaque arienne
#define TXT_STEEL_CRATE 175 // Caisse d'acier
#define TXT_WOOD_CRATE 176 // Caisse de bois
#define TXT_WATER_CRATE 177 // Caisse flottante
#define TXT_FLAG_SPOT 178 // Emplacement du drapeau
#define TXT_UNABLE_READ_SCENARIO 179 // Lecture scnario impossible
#define TXT_ERROR_LOADING_GAME 180 // Erreur de chargement !
#define TXT_OBSOLETE_SAVEGAME 181 // Sauvegarde obsolte
#define TXT_MUSTENTER_DESCRIPTION 182 // Vous devez entrer une
#define TXT_ERROR_SAVING_GAME 183 // Erreur de sauvegarde !
#define TXT_DELETE_FILE_QUERY 184 // Effacer ce fichier ?
#define TXT_EMPTY_SLOT 185 // [EMPLACEMENT VIDE]
#define TXT_SELECT_MPLAYER_GAME 186 // Choix du jeu Multijoueurs
#define TXT_MODEM_SERIAL 187 // Modem/Srie
#define TXT_NETWORK 188 // Rseau
#define TXT_INIT_NET_ERROR 189 // Initialisation rseau
#define TXT_JOIN_NETWORK_GAME 190 // Rejoindre jeu en rseau
#define TXT_NEW 191 // Nouveau
#define TXT_JOIN 192 // Joindre
#define TXT_SEND_MESSAGE 193 // Envoi Message
#define TXT_YOUR_NAME 194 // Votre nom :
#define TXT_SIDE_COLON 195 // Camp :
#define TXT_COLOR_COLON 196 // Couleur :
#define TXT_GAMES 197 // Parties
#define TXT_PLAYERS 198 // Joueurs
#define TXT_SCENARIO_COLON 199 // Scnario :
#define TXT_NOT_FOUND 200 // >> NON TROUVE <<
#define TXT_START_CREDITS_COLON 201 // Crdits :
#define TXT_BASES_COLON 202 // Bases :
#define TXT_TIBERIUM_COLON 203 // Minerai :
#define TXT_CRATES_COLON 204 // Caisses :
#define TXT_AI_PLAYERS_COLON 205 // Joueurs IA :
#define TXT_REQUEST_DENIED 206 // Demande refuse.
#define TXT_UNABLE_PLAY_WAAUGH 207 // Impossible de jouer,
#define TXT_NOTHING_TO_JOIN 208 // Aucune partie disponible !
#define TXT_NAME_ERROR 209 // Vous devez entrer un nom !
#define TXT_DUPENAMES_NOTALLOWED 210 // Les noms identiques ne sont
#define TXT_YOURGAME_OUTDATED 211 // La version de votre jeu est
#define TXT_DESTGAME_OUTDATED 212 // Version du jeu de
#define TXT_THATGUYS_GAME 213 // Partie de %s
#define TXT_THATGUYS_GAME_BRACKET 214 // [Partie de %s]
#define TXT_NETGAME_SETUP 215 // Configuration du jeu en
#define TXT_REJECT 216 // Rejeter
#define TXT_CANT_REJECT_SELF 217 // Vous ne pouvez pas vous
#define TXT_SELECT_PLAYER_REJECT 218 // Vous devez slectionner un
#define TXT_BASES 219 // Bases
#define TXT_CRATES 220 // Caisses
#define TXT_AI_PLAYERS 221 // Joueur IA
#define TXT_SCENARIOS 222 // Scnarios
#define TXT_CREDITS_COLON 223 // Crdits :
#define TXT_ONLY_ONE 224 // Un seul joueur ?
#define TXT_OOPS 225 // Oops !
#define TXT_TO 226 // Pour %s :
#define TXT_TO_ALL 227 // Pour tous
#define TXT_MESSAGE 228 // Message :
#define TXT_CONNECTION_LOST 229 // Perte de connexion avec %s
#define TXT_LEFT_GAME 230 // %s a quitt le jeu.
#define TXT_PLAYER_DEFEATED 231 // %s a t vaincu !
#define TXT_WAITING_CONNECT 232 // Attente de connexion...
#define TXT_NULL_CONNERR_CHECK_CABLES 233 // Erreur de connexion !
#define TXT_MODEM_CONNERR_REDIALING 234 // Erreur de connexion !
#define TXT_MODEM_CONNERR_WAITING 235 // Erreur de connexion !
#define TXT_SELECT_SERIAL_GAME 236 // Choix du jeu en srie
#define TXT_DIAL_MODEM 237 // Appel
#define TXT_ANSWER_MODEM 238 // Attente appel
#define TXT_NULL_MODEM 239 // Null Modem
#define TXT_SETTINGS 240 // Paramtres
#define TXT_PORT_COLON 241 // Port :
#define TXT_IRQ_COLON 242 // IRQ :
#define TXT_BAUD_COLON 243 // Bauds :
#define TXT_INIT_STRING 244 // Chane d'initialisation
#define TXT_CWAIT_STRING 245 // Chane d'attente d'appel
#define TXT_TONE_BUTTON 246 // Tonalit
#define TXT_PULSE_BUTTON 247 // Impulsions
#define TXT_HOST_SERIAL_GAME 248 // Hte du jeu en srie
#define TXT_OPPONENT_COLON 249 // Adversaire :
#define TXT_USER_SIGNED_OFF 250 // Utilisateur reparti !
#define TXT_JOIN_SERIAL_GAME 251 // Rejoindre jeu en srie
#define TXT_PHONE_LIST 252 // Rpertoire
#define TXT_ADD 253 // Ajouter
#define TXT_EDIT 254 // Editer
#define TXT_DIAL 255 // Appel
#define TXT_DEFAULT 256 // Dfaut
#define TXT_DEFAULT_SETTINGS 257 // Dfaut
#define TXT_CUSTOM_SETTINGS 258 // Autres paramtres
#define TXT_PHONE_LISTING 259 // Rpertoire
#define TXT_NAME_COLON 260 // Nom :
#define TXT_NUMBER_COLON 261 // Numro :
#define TXT_UNABLE_FIND_MODEM 262 // Modem non dtect. Vrifiez
#define TXT_NO_CARRIER 263 // Pas de porteuse.
#define TXT_LINE_BUSY 264 // Ligne occupe.
#define TXT_NUMBER_INVALID 265 // Numro incorrect.
#define TXT_SYSTEM_NOT_RESPONDING 266 // L'autre systme ne rpond
#define TXT_OUT_OF_SYNC 267 // Mauvaise synchronisation !
#define TXT_PACKET_TOO_LATE 268 // Paquet reu trop tard !
#define TXT_PLAYER_LEFT_GAME 269 // L'autre joueur a quitt le
#define TXT_FROM 270 // De %s:%s
#define TXT_SCORE_TIME 271 // TEMPS :
#define TXT_SCORE_LEAD 272 // COMMANDEMENT :
#define TXT_SCORE_EFFI 273 // EFFICACITE :
#define TXT_SCORE_TOTA 274 // SCORE TOTAL :
#define TXT_SCORE_CASU 275 // PERTES :
#define TXT_SCORE_NEUT 276 // NEUTRE :
#define TXT_SCORE_BUIL 277 // BATIMENTS PERDUS
#define TXT_SCORE_BUIL1 278 // BATIMENTS
#define TXT_SCORE_BUIL2 279 // PERDUS :
#define TXT_SCORE_TOP 280 // MEILLEURS SCORES
#define TXT_SCORE_ENDCRED 281 // CREDITS DE FIN :
#define TXT_SCORE_TIMEFORMAT1 282 // %dh %dm
#define TXT_SCORE_TIMEFORMAT2 283 // %dm
#define TXT_DIALING 284 // Appel...
#define TXT_DIALING_CANCELED 285 // Appel annul
#define TXT_WAITING_FOR_CALL 286 // Attente d'appel...
#define TXT_ANSWERING_CANCELED 287 // Attente d'appel annule
#define TXT_E6 288 // Ingnieurs
#define TXT_E8 289 // Espion
#define TXT_MODEM_OR_LOOPBACK 290 // Pas de cble Null Modem
#define TXT_MAP 291 // Carte
#define TXT_BLOSSOM_TREE 292 // Arbre en fleurs
#define TXT_RESTATE_MISSION 293 // Briefing
#define TXT_COMPUTER 294 // Joueur IA
#define TXT_COUNT 295 // Nombre :
#define TXT_LEVEL 296 // Niveau :
#define TXT_OPPONENT 297 // Adversaire
#define TXT_KILLS_COLON 298 // Vict.:
#define TXT_VIDEO 299 // Vido
#define TXT_C10 300 // Scientifique
#define TXT_CAPTURE_THE_FLAG 301 // Capture drapeau
#define TXT_OBJECTIVE 302 // Objectifs de mission
#define TXT_MISSION 303 // Mission
#define TXT_NO_SAVES 304 // Pas de sauvegardes
#define TXT_CIVILIAN_BUILDING 305 // Btiment civil
#define TXT_TECHNICIAN 306 // Technicien
#define TXT_NO_SAVELOAD 307 // Sauvegarde interdite en
#define TXT_DELPHI 308 // Agent Spcial 1
#define TXT_TO_REPLAY 309 // Voulez-vous recommencer
#define TXT_RECONN_TO 310 // Reconnexion vers %s.
#define TXT_PLEASE_WAIT 311 // Attendez %02d secondes.
#define TXT_SURRENDER 312 // Voulez-vous vous rendre ?
#define TXT_SEL_TRANS 313 // CHOIX DE LA TRANSMISSION
#define TXT_GAMENAME_MUSTBE_UNIQUE 314 // Les sauvegardes ne peuvent
#define TXT_GAME_IS_CLOSED 315 // Partie ferme.
#define TXT_NAME_MUSTBE_UNIQUE 316 // Les noms doivent tre tous
#define TXT_RECONNECTING_TO 317 // Reconnexion vers %s
#define TXT_WAITING_FOR_CONNECTIONS 318 // Attente de connexions...
#define TXT_TIME_ALLOWED 319 // Temps autoris : %02d
#define TXT_PRESS_ESC 320 // Appuyez sur Echap pour
#define TXT_JUST_YOU_AND_ME 321 // De l'ordinateur : Il ne
#define TXT_CAPTURE_THE_FLAG_COLON 322 // Capture du drapeau :
#define TXT_CHAN 323 // Agent Spcial 2
#define TXT_HAS_ALLIED 324 // %s s'est alli(e) avec %s
#define TXT_AT_WAR 325 // %s dclare la guerre %s
#define TXT_SEL_TARGET 326 // Choisissez un cible
#define TXT_RESIGN 327 // Abandonner
#define TXT_TIBERIUM_FAST 328 // Le minerai pousse trs
#define TXT_ANSWERING 329 // Rponse en cours...
#define TXT_INITIALIZING_MODEM 330 // Initialisation Modem...
#define TXT_SCENARIOS_DO_NOT_MATCH 331 // Les scnarios ne
#define TXT_POWER_OUTPUT 332 // Production d'nergie
#define TXT_POWER_OUTPUT_LOW 333 // Production d'nergie
#define TXT_CONTINUE 334 // Continuer
#define TXT_QUEUE_FULL 335 // Saturation des donnes
#define TXT_SPECIAL_WARNING 336 // %s a modifi les options de
#define TXT_CD_DIALOG_1 337 // Placez un CD d'Alerte Rouge
#define TXT_CD_DIALOG_2 338 // Placez le CD %d (%s) dans
#define TXT_CD_ERROR1 339 // Alerte Rouge n'a pas
#define TXT_NO_SOUND_CARD 340 // Pas de carte sonore
#define TXT_UNKNOWN 341 // INCONNU
#define TXT_OLD_GAME 342 // (ancien)
#define TXT_NO_SPACE 343 // Espace disque insuffisant
#define TXT_MUST_HAVE_SPACE 344 // Vous devez disposer de %d
#define TXT_RUN_SETUP 345 // Lancez d'abord le programme
#define TXT_WAITING_FOR_OPPONENT 346 // Attente adversaire
#define TXT_SELECT_SETTINGS 347 // Choisissez l'option
#define TXT_PRISON 348 // Prison
#define TXT_GAME_WAS_SAVED 349 // Mission sauvegarde
#define TXT_SPACE_CANT_SAVE 350 // Espace disque insuffisant
#define TXT_INVALID_PORT_ADDRESS 351 // Port/Adresse invalide. COM
#define TXT_INVALID_SETTINGS 352 // paramtres Port et/ou IRQ
#define TXT_IRQ_ALREADY_IN_USE 353 // IRQ dj utilis
#define TXT_ABORT 354 // Oui
#define TXT_RESTART 355 // Recommencer
#define TXT_RESTARTING 356 // Mission relance. Attendez
#define TXT_LOADING 357 // Chargement de la mission.
#define TXT_ERROR_IN_INITSTRING 358 // Erreur chane
#define TXT_SHADOW_COLON 359 // Ombre
#define TXT_AVMINE 360 // Mine Anti-Vhicule
#define TXT_APMINE 361 // Mine Anti-Personnel
#define TXT_NEW_MISSIONS 362 // Nouvelles missions
#define TXT_THIEF 363 // Voleur
#define TXT_MRJ 364 // Brouilleur de radar
#define TXT_GAP_GENERATOR 365 // Gnrateur d'ombre
#define TXT_PILLBOX 366 // Bunker
#define TXT_CAMOPILLBOX 367 // Bunker camoufl
#define TXT_CHRONOSPHERE 368 // Chronosphre
#define TXT_ENGLAND 369 // Roy. Uni
#define TXT_GERMANY 370 // Allemagne
#define TXT_SPAIN 371 // Espagne
#define TXT_USSR 372 // URSS
#define TXT_UKRAINE 373 // Ukraine
#define TXT_GREECE 374 // Grce
#define TXT_FRANCE 375 // France
#define TXT_TURKEY 376 // Turquie
#define TXT_SHORE 377 // Rivage
#define TXT_PLACE_OBJECT 378 // Choisir objet
#define TXT_SS 379 // Sous-marin
#define TXT_DD 380 // Contre-torpilleur
#define TXT_CA 381 // Croiseur
#define TXT_TRANSPORT 382 // Transport
#define TXT_PT 383 // Aviso-torpilleur
#define TXT_LOBBY 384 // Hall
#define TXT_CHANNEL_GAMES 385 // Parties
#define TXT_SAVING_GAME 386 // Sauvegarder partie...
#define TXT_GAME_FULL 387 // La partie est au complet.
#define TXT_MUST_SELECT_GAME 388 // Vous devez slectionner une
#define TXT_S_PLAYING_S 389 // %s joue contre %s
#define TXT_ONLY_HOST_CAN_MODIFY 390 // Seul l'hte peut modifier
#define TXT_GAME_CANCELLED 391 // La partie a t annule.
#define TXT_S_FORMED_NEW_GAME 392 // %s a initi une nouvelle
#define TXT_GAME_NOW_IN_PROGRESS 393 // La partie de %s est
#define TXT_TESLA 394 // Bobine de Tesla
#define TXT_MGG 395 // Gnrateur d'ombre mobile
#define TXT_FLAME_TURRET 396 // Tour lance-flammes
#define TXT_AAGUN 397 // Canon Anti-Avion
#define TXT_KENNEL 398 // Niche
#define TXT_SOVIET_TECH 399 // Centre Technique
#define TXT_BADGER 400 // Bombardier
#define TXT_MIG 401 // Mig
#define TXT_YAK 402 // Yak
#define TXT_FENCE 403 // Barbels
#define TXT_MEDIC 404 // Mdecin
#define TXT_SABOTEUR 405 // Saboteur
#define TXT_GENERAL 406 // Gnral
#define TXT_E7 407 // Tanya
#define TXT_PARA_BOMB 408 // Parabombes
#define TXT_PARA_INFANTRY 409 // Parachutistes
#define TXT_PARA_SABOTEUR 410 // Saboteur parachutiste
#define TXT_SHIP_YARD 411 // Chantier naval
#define TXT_SUB_PEN 412 // Port sous-marin
#define TXT_SCENARIO_OPTIONS 413 // Options Scnario
#define TXT_SPY_MISSION 414 // Avion espion
#define TXT_U2 415 // Avion espion
#define TXT_GUARD_DOG 416 // Chien d'attaque
#define TXT_SPY_INFO 417 // Info Espion
#define TXT_BUILDNGS 418 // Btiments
#define TXT_UNITS 419 // Units
#define TXT_INFANTRY 420 // Infanterie
#define TXT_AIRCRAFT 421 // Avion
#define TXT_TRUCK 422 // Camion d'approvisionnement
#define TXT_INVUL 423 // Module d'invulnrabilit
#define TXT_IRON_CURTAIN 424 // Rideau de Fer
#define TXT_ADVANCED_TECH 425 // Centre technique avanc
#define TXT_V2_LAUNCHER 426 // Lance-roquettes V2
#define TXT_FORWARD_COM 427 // Poste de commandement
#define TXT_DEMOLITIONER 428 // Bombardeur
#define TXT_MINE_LAYER 429 // Poseur de mines
#define TXT_FAKE_CONST 430 // Chantier de construction
#define TXT_FAKE_WEAP 431 // Usine d'armement leurre
#define TXT_FAKE_YARD 432 // Chantier naval leurre
#define TXT_FAKE_PEN 433 // Port sous-marin leurre
#define TXT_FAKE_RADAR 434 // Dme radar leurre
#define TXT_THEME_BIGF 435 // Bigfoot
#define TXT_THEME_CRUS 436 // La rvolte
#define TXT_THEME_FAC1 437 // A l'attaque 1
#define TXT_THEME_FAC2 438 // A l'attaque 2
#define TXT_THEME_HELL 439 // Marche de l'enfer
#define TXT_THEME_RUN1 440 // Sauve-qui-peut
#define TXT_THEME_SMSH 441 // La dbcle
#define TXT_THEME_TREN 442 // Tranches
#define TXT_THEME_WORK 443 // Les professionnels
#define TXT_THEME_AWAIT 444 // Attente
#define TXT_THEME_DENSE_R 445 // Dense
#define TXT_THEME_MAP 446 // Slection carte
#define TXT_THEME_FOGGER1A 447 // Fogger
#define TXT_THEME_MUD1A 448 // Boue
#define TXT_THEME_RADIO2 449 // Radio 2
#define TXT_THEME_ROLLOUT 450 // Laminage
#define TXT_THEME_SNAKE 451 // Serpent
#define TXT_THEME_TERMINAT 452 // Extermination
#define TXT_THEME_TWIN 453 // Jumeau
#define TXT_THEME_VECTOR1A 454 // Vecteur
#define TXT_TEAM_MEMBERS 455 // Equipiers
#define TXT_BRIDGE 456 // Pont
#define TXT_BARREL 457 // Baril
#define TXT_GOODGUY 458 // Amical
#define TXT_BADGUY 459 // Ennemi
#define TXT_GOLD 460 // Or
#define TXT_GEMS 461 // Gemmes
#define TXT_TEASER 462 // Film titre
#define TXT_MOVIES 463 // Films
#define TXT_INTERIOR 464 // Intrieur
#define TXT_SONAR_PULSE 465 // Signal sonar
#define TXT_MSLO 466 // Silo de missiles
#define TXT_GPS_SATELLITE 467 // Satellite GPS
#define TXT_NUCLEAR_BOMB 468 // Bombe atomique
#define TXT_EASY 469 // Facile
#define TXT_HARD 470 // Difficile
#define TXT_NORMAL 471 // Normal
#define TXT_DIFFICULTY 472 // Slectionnez un niveau de
#define TXT_ALLIES 473 // Allis
#define TXT_SOVIET 474 // Soviets
#define TXT_THEME_INTRO 475 // Thme Intro
#define TXT_SHADOW_REGROWS 476 // Progr. ombre
#define TXT_ORE_SPREADS 477 // Progr. minerai
#define TXT_THEME_SCORE 478 // Musiques
#define TXT_INTERNET 479 // Internet
#define TXT_ICE 480 // Glace
#define TXT_CRATE 481 // Caisses
#define TXT_SKIRMISH 482 // Escarmouche
#define TXT_CHOOSE 483 // Choisissez votre camp.
#define TXT_MINERALS 484 // Minraux prcieux
#define TXT_IGNORE 485 // Ignorer
#define TXT_ERROR_NO_RESP 486 // Erreur - le modem ne rpond
#define TXT_ERROR_NO_RESCODE 487 // Erreur - Le modem n'a pas
#define TXT_ERROR_NO_INIT 488 // Erreur - Le modem n'a pas
#define TXT_ERROR_NO_VERB 489 // Erreur - Le modem n'a pas
#define TXT_ERROR_NO_ECHO 490 // Erreur - Le modem n'a pas
#define TXT_ERROR_NO_DISABLE 491 // Erreur - Impossible de
#define TXT_ERROR_TOO_MANY 492 // Erreur - Trop d'erreurs
#define TXT_ERROR_ERROR 493 // Erreur - Le modem a
#define TXT_ERROR_TIMEOUT 494 // Erreur - Temps d'attente de
#define TXT_ACCOMPLISHED 495 // Accompli
#define TXT_CLICK_CONTINUE 496 // Cliquez pour continuer
#define TXT_RECEIVING_SCENARIO 497 // Rception du scnario de
#define TXT_SENDING_SCENARIO 498 // Envoi du scnario aux
#define TXT_NO_FLOW_CONTROL_RESPONSE 499 // Erreur - Le modem n'a pas
#define TXT_NO_COMPRESSION_RESPONSE 500 // Erreur - Le modem n'a pas
#define TXT_NO_ERROR_CORRECTION_RESPONSE 501 // Erreur - Le modem n'a pas
#define TXT_EXPLAIN_REGISTRATION 502 // Pour jouer Alerte Rouge
#define TXT_ERROR_UNABLE_TO_RUN_WCHAT 503 // Erreur - Impossible
#define TXT_REGISTER 504 // Enregistrer
#define TXT_ORE_MINE 505 // Gisement Minerai
#define TXT_NO_REGISTERED_MODEM 506 // Aucun modem configur
#define TXT_CHRONOSHIFT 507 // Dplacement chronoporte
#define TXT_UNABLE_TO_OPEN_PORT 508 // Adresse invalide ou en
#define TXT_NO_DIAL_TONE 509 // Pas de tonalit.
#define TXT_NO_EXPANSION_SCENARIO 510 // Erreur - L'autre joueur n'a
#define TXT_STAND_BY 511 // Patientez SVP...
#define TXT_THEME_CREDITS 512 // Musique du gnrique de fin
#define TXT_POWER_AAGUN 513 // Puissance faible: Canon(s)
#define TXT_POWER_TESLA 514 // Puissance faible: Bobine(s)
#define TXT_LOW_POWER 515 // Puissance Faible
#define TXT_COMMANDER 516 // Commandant:
#define TXT_BATTLES_WON 517 // Parties gagnes:
#define TXT_MISMATCH 518 // Fichier de donnes du jeu
#define TXT_SCENARIO_ERROR 519 // Votre version de jeu
#define TXT_CONNECTING 520 // Connecting
#define TXT_MODEM_INITIALISATION 521 // Initialisation du Modem
#define TXT_DATA_COMPRESSION 522 // Compression des Donnes
#define TXT_ERROR_CORRECTION 523 // Correction d'Erreur
#define TXT_HARDWARE_FLOW_CONTROL 524 // Contrle Matriel du Flux
#define TXT_ADVANCED 525 // Avanc
#define TXT_THEME_2ND_HAND 526 // Seconde main
#define TXT_THEME_ARAZOID 527 // Arazode
#define TXT_THEME_BACKSTAB 528 // Retour l'envoyeur
#define TXT_THEME_CHAOS2 529 // Chaos2
#define TXT_THEME_SHUT_IT 530 // Fermez-la !
#define TXT_THEME_TWINMIX1 531 // Visite de courtoisie
#define TXT_THEME_UNDER3 532 // A couvert
#define TXT_THEME_VR2 533 // VR2
#define TXT_ASK_EMERGENCY_SAVE_NOT_RESPONDING 534 // L'autre systme ne rpond
#define TXT_ASK_EMERGENCY_SAVE_HUNG_UP 535 // L'autre systme a
#define TXT_NO_REG_APP 536 // Alerte Rouge n'a pu
#define TXT_NO_CS_SCENARIOS 537 // Un joueur de la partie n'a
#define TXT_MISSILESUB 538 // Sous-marin MS
#define TXT_SHOCKTROOPER 539 // Electrocuteur
#define TXT_MECHANIC 540 // Mcanicien
#define TXT_CHRONOTANK 541 // Chrono Tank
#define TXT_TESLATANK 542 // Tank Tesla
#define TXT_MAD 543 // Tank M.A.D.
#define TXT_DEMOTRUCK 544 // Camion de dmolition
#define TXT_PHASETRANSPORT 545 // Transport Camlon
#define TXT_THEME_BOG 546 // Marcages
#define TXT_THEME_FLOAT_V2 547 // Volutes
#define TXT_THEME_GLOOM 548 // Tnbres
#define TXT_THEME_GRNDWIRE 549 // Terrain min
#define TXT_THEME_RPT 550 // Mcaniciens 2
#define TXT_THEME_SEARCH 551 // Battue
#define TXT_THEME_TRACTION 552 // Traction
#define TXT_THEME_WASTELND 553 // Chaos
#define TXT_CARRIER 554 // Hliport Mobile
================================================
FILE: CODE/CONQUER.LNT
================================================
// Watcom C, C++ (32 bit), -si4 -sp4,
// Standard lint options
// 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)
//------------------------------------------------------------------
-width(0,0) // don't break up message lines
// 32 bit integer and pointer size is four bytes.
-si4 -sp4
// Include directories
-ic:\projects\c&czero\code\watcom\h;..\vq\include;..\gcl510\h
================================================
FILE: CODE/CONST.CPP
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/CONST.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 : CONST.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : September 20, 1993 *
* *
* Last Update : September 20, 1993 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
/***************************************************************************
** These are the access passwords used to activate cheat mode, editor mode,
** and special game options.
*/
long const PlayCodes[] = {
0xE0792D6D, // Dwight Okahara
0x90046ECF, // Paul S. Mudra
0xC3EE9A26, // Frank Klepaki
0xED382178, // Ed Del Castillo
0L
};
long const CheatCodes[] = {
0xA0E2AB53, // Joseph Hewitt
0x00532693, // Mike Lightner
0x7DDFF824, // Joe Bostic
0x2CB5CF01, // Phil Gorrow
0xB5B63531, // Bill Randolph
0xDFABC23A, // Adam Isgreen
0x52B19A22, // Erik Yeo
0xBE79088C, // David Dettmer
0xB216AE7E, // Barry Green
0x0E07B213, // Steve Tall
0L
};
long const EditorCodes[] = {
0xA2C09326, // Erik Yeo
0x1F944BB3, // Mike Lightner
0xDE07154D, // Adam Isgreen
0x0E07B213, // Steve Tall
0x16B170B1, // Joe Bostic
0L
};
/***********************************************************************************************
** Unit order names. These names correspond to the player selectable orders
** a unit can have. The system initiated orders have no use for the ASCII name
** associated, but they are listed here for completeness sake.
*/
char const * Missions[MISSION_COUNT] = {
"Sleep",
"Attack",
"Move",
"QMove",
"Retreat",
"Guard",
"Sticky",
"Enter",
"Capture",
"Harvest",
"Area Guard",
"Return",
"Stop",
"Ambush",
"Hunt",
"Unload",
"Sabotage",
"Construction",
"Selling",
"Repair",
"Rescue",
"Missile",
"Harmless"
};
/***************************************************************************
** Special weapon names.
*/
#ifdef SCENARIO_EDITOR
char const * const SpecialWeaponName[SPC_COUNT] = {
"Sonar Pulse",
"Nuclear Missile",
"Chronosphere",
"Parachute Bomb",
"Paratroopers",
"Recon Plane",
"Iron Curtain",
"GPS Satellite"
};
#endif
int const SpecialWeaponHelp[SPC_COUNT] = {
TXT_SONAR_PULSE,
TXT_NUCLEAR_BOMB,
TXT_CHRONOSHIFT,
TXT_PARA_BOMB,
TXT_PARA_INFANTRY,
TXT_SPY_MISSION,
TXT_INVUL,
TXT_GPS_SATELLITE
};
char const * const SpecialWeaponFile[SPC_COUNT] = {
"SONR",
"ATOM",
"WARP",
"PBMB",
"PINF",
"CAM",
"INFX",
"GPSS"
};
/***************************************************************************
** Type of quarry to search out and attack. These values are used for team
** attack missions.
*/
char const * const QuarryName[QUARRY_COUNT] = {
"N/A",
"Anything",
"Buildings - any",
"Harvesters",
"Infantry",
"Vehicles - any",
"Ships - any",
"Factories",
"Base Defenses",
"Base Threats",
"Power Facilities",
"Fake Buildings"
};
/***************************************************************************
** These are the text names for the formation types.
*/
char const * const FormationName[FORMATION_COUNT] = {
"None",
"Tight",
"Loose",
"Wedge North",
"Wedge East",
"Wedge South",
"Wedge West",
"Line N/S",
"Line E/W"
};
/***************************************************************************
** These are the ASCII names for the reinforcement sources.
*/
char const * const SourceName[SOURCE_COUNT] =
{
"North",
"East",
"South",
"West",
"Air"
};
/***************************************************************************
** These are the text names for the various armor types a unit may possess.
*/
char const * const ArmorName[ARMOR_COUNT] = {
"none",
"wood",
"light",
"heavy",
"concrete"
};
// HACK ALERT! This unused text string is here to stop Watcom from crashing. There is some
// magic text heap length that causes a crash before the code executes. This dummy string
// changes the text heap length enough to stop the crash. Who knows why, but it works.
char * __test__ = "alskdfjlasdfjkajsdfkja;sldjfklasj9awutreqjfnfdkvnldzlknvadsjgflkasdjfkajsdfas";
/***************************************************************************
** The list of VQ filenames.
*/
char const * const VQName[VQ_COUNT] = {
"AAGUN",
"MIG",
"SFROZEN",
"AIRFIELD",
"BATTLE",
"BMAP",
"BOMBRUN",
"DPTHCHRG",
"GRVESTNE",
"MONTPASS",
"MTNKFACT",
"CRONTEST",
"OILDRUM",
"ALLYEND",
"RADRRAID",
"SHIPYARD",
"SHORBOMB",
"SITDUCK",
"SLNTSRVC",
"SNOWBASE",
"EXECUTE",
"REDINTRO", // low res.
"NUKESTOK",
"V2ROCKET",
"SEARCH",
"BINOC",
"ELEVATOR",
"FROZEN",
"MCV",
"SHIPSINK",
"SOVMCV",
"TRINITY",
"ALLYMORF",
"APCESCPE",
"BRDGTILT",
"CRONFAIL",
"STRAFE",
"DESTROYR",
"DOUBLE",
"FLARE",
"SNSTRAFE",
"LANDING",
"ONTHPRWL",
"OVERRUN",
"SNOWBOMB",
"SOVCEMET",
"TAKE_OFF",
"TESLA",
"SOVIET8",
"SPOTTER",
"ALLY1",
"ALLY2",
"ALLY4",
"SOVFINAL",
"ASSESS",
"SOVIET10",
"DUD",
"MCV_LAND",
"MCVBRDGE",
"PERISCOP",
"SHORBOM1",
"SHORBOM2",
"SOVBATL",
"SOVTSTAR",
"AFTRMATH",
"SOVIET11",
"MASASSLT",
"ENGLISH", // High res.
"SOVIET1",
"SOVIET2",
"SOVIET3",
"SOVIET4",
"SOVIET5",
"SOVIET6",
"SOVIET7",
"PROLOG",
"AVERTED",
"COUNTDWN",
"MOVINGIN",
"ALLY10",
"ALLY12",
"ALLY5",
"ALLY6",
"ALLY8",
"TANYA1",
"TANYA2",
"ALLY10B",
"ALLY11",
"ALLY14",
"ALLY9",
"SPY",
"TOOFAR",
"SOVIET12",
"SOVIET13",
"SOVIET9",
"BEACHEAD",
"SOVIET14",
"SIZZLE",
"SIZZLE2",
"ANTEND",
"ANTINTRO"
};
/***************************************************************************
** Relative coordinate offsets from the center of a cell for each
** of the legal positions that an object in a cell may stop at. Only infantry
** are allowed to stop at other than the center of the cell.
*/
COORDINATE const StoppingCoordAbs[5] = {
0x00800080L, // center
0x00400040L, // upper left
0x004000C0L, // upper right
0x00C00040L, // lower left
0x00C000C0L // lower right
};
/***************************************************************************
** Converts pixel values (cell relative) into the appropriate lepton (sub cell)
** value. This is used to convert pixel (screen) coordinates into the underlying
** coordinate system.
*/
unsigned char const Pixel2Lepton[24] = {
0x00,0x0B,0x15,0x20,0x2B,0x35,0x40,0x4B,
0x55,0x60,0x6B,0x75,0x80,0x8B,0x95,0xA0,
0xAB,0xB5,0xC0,0xCB,0xD5,0xE0,0xEB,0xF5
};
/***************************************************************************
** This array is used to index a facing in order to retrieve a cell
** offset that, when added to another cell, will achieve the adjacent cell
** in the indexed direction.
*/
CELL const AdjacentCell[FACING_COUNT] = {
-(MAP_CELL_W), // North
-(MAP_CELL_W-1), // North East
1, // East
MAP_CELL_W+1, // South East
MAP_CELL_W, // South
MAP_CELL_W-1, // South West
-1, // West
-(MAP_CELL_W+1) // North West
};
COORDINATE const AdjacentCoord[FACING_COUNT] = {
0xFF000000L,
0xFF000100L,
0x00000100L,
0x01000100L,
0x01000000L,
0x0100FF00L,
0x0000FF00L,
0xFF00FF00L
};
/***************************************************************************
** This specifies the odds of receiving the various random crate power
** ups. The odds are expressed as "shares" of 100 percent.
*/
int CrateShares[CRATE_COUNT] = {
50, // CRATE_MONEY
20, // CRATE_UNIT
3, // CRATE_PARA_BOMB
1, // CRATE_HEAL_BASE
3, // CRATE_CLOAK
5, // CRATE_EXPLOSION
5, // CRATE_NAPALM
20, // CRATE_SQUAD
1, // CRATE_DARKNESS
1, // CRATE_REVEAL
3, // CRATE_SONAR
10, // CRATE_ARMOR
10, // CRATE_SPEED
10, // CRATE_FIREPOWER
1, // CRATE_ICBM
1, // CRATE_TIMEQUAKE
3, // CRATE_INVULN
5 // CRATE_VORTEX
};
AnimType CrateAnims[CRATE_COUNT] = {
ANIM_NONE, // CRATE_MONEY
ANIM_NONE, // CRATE_UNIT
ANIM_NONE, // CRATE_PARA_BOMB
ANIM_NONE, // CRATE_HEAL_BASE
ANIM_NONE, // CRATE_CLOAK
ANIM_NONE, // CRATE_EXPLOSION
ANIM_NONE, // CRATE_NAPALM
ANIM_NONE, // CRATE_SQUAD
ANIM_NONE, // CRATE_DARKNESS
ANIM_NONE, // CRATE_REVEAL
ANIM_NONE, // CRATE_SONAR
ANIM_NONE, // CRATE_ARMOR
ANIM_NONE, // CRATE_SPEED
ANIM_NONE, // CRATE_FIREPOWER
ANIM_NONE, // CRATE_ICBM
ANIM_NONE, // CRATE_TIMEQUAKE
ANIM_NONE, // CRATE_INVULN
ANIM_NONE // CRATE_VORTEX
};
int CrateData[CRATE_COUNT] = {
0, // CRATE_MONEY
0, // CRATE_UNIT
0, // CRATE_PARA_BOMB
0, // CRATE_HEAL_BASE
0, // CRATE_CLOAK
0, // CRATE_EXPLOSION
0, // CRATE_NAPALM
0, // CRATE_SQUAD
0, // CRATE_DARKNESS
0, // CRATE_REVEAL
0, // CRATE_SONAR
0, // CRATE_ARMOR
0, // CRATE_SPEED
0, // CRATE_FIREPOWER
0, // CRATE_ICBM
0, // CRATE_TIMEQUAKE
0, // CRATE_INVULN
0 // CRATE_VORTEX
};
char const * const CrateNames[CRATE_COUNT] = {
"Money",
"Unit",
"ParaBomb",
"HealBase",
"Cloak",
"Explosion",
"Napalm",
"Squad",
"Darkness",
"Reveal",
"Sonar",
"Armor",
"Speed",
"Firepower",
"ICBM",
"TimeQuake",
"Invulnerability",
"ChronalVortex"
};
/***************************************************************************
** This converts 0..255 facing values into either 8, 16, or 32 facing values.
** Note: a simple shift won't suffice because 0..255 facing values should
** be converted to the CLOSEST appropriate facing, NOT rounded down to the
** nearest facing.
*/
unsigned char const Facing8[256] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
unsigned char const Facing16[256] = {
0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,
12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,
14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,0,0,0,0,0,0,0,0
};
signed char const Rotation16[256] = {
0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1,
0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1,
0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1,
0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1,
0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1,
0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1,
0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1,
0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1
};
/*
** This table incorporates a compensating factor for the distortion caused
** by 3D-Studio when it tries to render 45% angles.
*/
unsigned char const Facing32[256] = {
0,0,0,0,0,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,
3,4,4,4,4,4,4,5,5,5,5,5,5,5,6,6,6,6,6,6,6,7,7,7,7,7,7,7,8,8,8,8,
8,8,8,9,9,9,9,9,9,9,10,10,10,10,10,10,10,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,
13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,16,16,16,16,16,16,
16,16,16,16,16,17,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,18,19,19,19,19,19,19,19,19,19,
19,20,20,20,20,20,20,21,21,21,21,21,21,21,22,22,22,22,22,22,22,23,23,23,23,23,23,23,24,24,24,24,
24,24,24,25,25,25,25,25,25,25,26,26,26,26,26,26,26,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,
29,29,29,29,29,29,29,29,30,30,30,30,30,30,30,30,30,31,31,31,31,31,31,31,31,31,0,0,0,0,0,0
};
#ifdef OBSOLETE
unsigned char const Facing32[256] = {
0,0,0,0,
1,1,1,1,1,1,1,1,
2,2,2,2,2,2,2,2,
3,3,3,3,3,3,3,3,
4,4,4,4,4,4,4,4,
5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,
8,8,8,8,8,8,8,8,
9,9,9,9,9,9,9,9,
10,10,10,10,10,10,10,10,
11,11,11,11,11,11,11,11,
12,12,12,12,12,12,12,12,
13,13,13,13,13,13,13,13,
14,14,14,14,14,14,14,14,
15,15,15,15,15,15,15,15,
16,16,16,16,16,16,16,16,
17,17,17,17,17,17,17,17,
18,18,18,18,18,18,18,18,
19,19,19,19,19,19,19,19,
20,20,20,20,20,20,20,20,
21,21,21,21,21,21,21,21,
22,22,22,22,22,22,22,22,
23,23,23,23,23,23,23,23,
24,24,24,24,24,24,24,24,
25,25,25,25,25,25,25,25,
26,26,26,26,26,26,26,26,
27,27,27,27,27,27,27,27,
28,28,28,28,28,28,28,28,
29,29,29,29,29,29,29,29,
30,30,30,30,30,30,30,30,
31,31,31,31,31,31,31,31,
0,0,0,0
};
#endif
/***************************************************************************
** These are the movement costs (in ticks at fastest speed) to enter each
** of the given terrain cells.
*/
int const GroundColor[LAND_COUNT] = {
141, // "Clear" terrain.
141, // Road terrain.
172, // Water.
21, // Impassable rock.
21, // Wall (blocks movement).
158, // Tiberium field.
141, // Beach terrain.
141, // Rocky terrain.
174 // Rocky riverbed.
};
int const SnowColor[LAND_COUNT] = {
141, // "Clear" terrain.
141, // Road terrain.
172, // Water.
21, // Impassable rock.
21, // Wall (blocks movement).
158, // Tiberium field.
141, // Beach terrain.
141, // Rocky terrain.
174 // Rocky riverbed.
};
#ifdef NEVER
int const GroundColor[LAND_COUNT] = {
46, // "Clear" terrain.
44, // Road terrain.
BLUE, // Water.
DKGREY, // Impassable rock.
DKGREY, // Wall (blocks movement).
158, // Tiberium field.
64, // Beach terrain.
DKGREY, // Rocky terrain.
DKGREY // Rocky riverbed.
};
int const SnowColor[LAND_COUNT] = {
WHITE, // "Clear" terrain.
LTGRAY, // Road terrain.
BLUE, // Water.
DKGREY, // Impassable rock.
DKGREY, // Wall (blocks movement).
158, // Tiberium field.
LTGRAY, // Beach terrain.
DKGREY, // Rocky terrain.
DKGREY // Rocky riverbed.
};
#endif
GroundType Ground[LAND_COUNT];
/***************************************************************************
** These are the names of the theaters.
*/
TheaterDataType const Theaters[THEATER_COUNT] = {
{"TEMPERATE","TEMPERAT","TEM"},
{"SNOW","SNOW","SNO"},
{"INTERIOR","INTERIOR","INT"},
};
unsigned char const RemapCiv2[256] = {
0,1,2,3,4,5,6,209,8,9,10,11,12,13,12,15, // 0..15
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // 16..31
32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, // 32..47
48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, // 48..63
64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, // 64..79
80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, // 80..95
96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, // 96..111
112,113,114,115,116,117,187,188,120,121,122,123,124,125,126,127, // 112..127
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 128..143
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,209, // 144..159
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // 160..175
176,177,178,179,180,181,182,183,184,185,186,167, 13,189,190,191, // 176..191
192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, // 192..207
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, // 208..223
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // 224..239
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // 240..255
};
unsigned char const RemapCiv4[256] = {
0,1,2,3,4,5,6,187,8,9,10,11,12,13,14,15, // 0..15
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // 16..31
32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, // 32..47
48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, // 48..63
64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, // 64..79
80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, // 80..95
96,97,98,99,100,101,102,103,104,105,106,107,108,118,110,119, // 96..111
112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, // 112..127
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 128..143
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, // 144..159
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // 160..175
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, // 176..191
192,193,194,195,196,197,198,199,200,201,202,203,204,205,188,207, // 192..207
208,209,182,211,212,213,214,215,216,217,218,219,220,221,222,223, // 208..223
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // 224..239
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // 240..255
};
unsigned char const RemapCiv5[256] = {
0,1,2,3,4,5,6,109,8,9,10,11,131,13,14,15, // 0..15
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // 16..31
32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, // 32..47
48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, // 48..63
64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, // 64..79
80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, // 80..95
96,97,98,99,100,101,102,103,104,105,106,107,108,177,110,178, // 96..111
112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, // 112..127
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 128..143
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, // 144..159
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // 160..175
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, // 176..191
192,193,194,195,196,197,198,199,111,201,202,203,204,205,111,207, // 192..207
208,209,182,211,212,213,214,215,216,217,218,219,220,221,222,223, // 208..223
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // 224..239
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // 240..255
};
unsigned char const RemapCiv6[256] = {
0,1,2,3,4,5,6,120,8,9,10,11,12,13,238,15, // 0..15
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // 16..31
32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, // 32..47
48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, // 48..63
64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, // 64..79
80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, // 80..95
96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, // 96..111
112,113,114,115,116,117,236,206,120,121,122,123,124,125,126,127, // 112..127
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 128..143
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,111, // 144..159
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // 160..175
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, // 176..191
192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, // 192..207
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, // 208..223
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // 224..239
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // 240..255
};
unsigned char const RemapCiv7[256] = {
0,1,2,3,4,5,6,7,8,9,10,11,12,13,131,15, // 0..15
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // 16..31
32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, // 32..47
48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, // 48..63
64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, // 64..79
80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, // 80..95
96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, // 96..111
112,113,114,115,116,117,157,212,120,121,122,123,124,125,126,127, // 112..127
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 128..143
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,7, // 144..159
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // 160..175
176,177,178,179,180,181,182,183,184,185,186,118,119,189,190,191, // 176..191
192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, // 192..207
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, // 208..223
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // 224..239
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // 240..255
};
unsigned char const RemapCiv8[256] = {
0,1,2,3,4,5,6,182,8,9,10,11,12,13,131,15, // 0..15
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // 16..31
32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, // 32..47
48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, // 48..63
64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, // 64..79
80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, // 80..95
96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, // 96..111
112,113,114,115,116,117,215,7,120,121,122,123,124,125,126,127, // 112..127
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 128..143
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,182, // 144..159
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // 160..175
176,177,178,179,180,181,182,183,184,185,186,198,199,189,190,191, // 176..191
192,193,194,195,196,197,198,199,111,201,202,203,204,205,206,207, // 192..207
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, // 208..223
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // 224..239
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // 240..255
};
unsigned char const RemapCiv9[256] = {
0,1,2,3,4,5,6,7,8,9,10,11,12,13,7,15, // 0..15
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // 16..31
32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, // 32..47
48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, // 48..63
64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, // 64..79
80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, // 80..95
96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, // 96..111
112,113,114,115,116,117,163,165,120,121,122,123,124,125,126,127, // 112..127
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 128..143
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,200, // 144..159
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // 160..175
176,177,178,179,180,181,182,183,184,185,186,111,13,189,190,191, // 176..191
192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, // 192..207
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, // 208..223
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // 224..239
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // 240..255
};
unsigned char const RemapCiv10[256] = {
0,1,2,3,4,5,6,137,8,9,10,11,12,13,15,15, // 0..15
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // 16..31
32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, // 32..47
48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, // 48..63
64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, // 64..79
80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, // 80..95
96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, // 96..111
112,113,114,115,116,117,129,131,120,121,122,123,124,125,126,127, // 112..127
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 128..143
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,137, // 144..159
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // 160..175
176,177,178,179,180,181,182,183,184,185,186,163,165,189,190,191, // 176..191
192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, // 192..207
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, // 208..223
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // 224..239
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // 240..255
};
unsigned char const RemapEmber[256] = {
#define CEC CC_EMBER_COLOR
0,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,BLACK,CEC,CEC,CEC,
CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,
CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,
CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,
CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,
CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,
CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,
CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,
CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,
CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,
CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,
CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,
CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,
CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,
CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,
CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC,CEC
};
//char const Keys[] =
// "[PublicKey]\n"
// "1=AgkCbXo9sKMHOBk=\n"
//#ifdef CHEAT_KEYS
// "[PrivateKey]\n"
// "1=AggxFU55vc7LYQ==\n"
//#endif
// "\n";
char const Keys[] =
"[PublicKey]\n"
"1=AihRvNoIbTn85FZRYNZRcT+i6KpU+maCsEqr3Q5q+LDB5tH7Tz2qQ38V\n"
#ifdef CHEAT_KEYS
"[PrivateKey]\n"
"1=AigKVje8mROcR8QixnxUEF5b29Curkq01DNDWCdOG99XBqH79OaCiTCB\n"
#endif
"\n";
================================================
FILE: CODE/CONTROL.CPP
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/CONTROL.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 : CONTROL.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 01/15/95 *
* *
* Last Update : December 5, 1995 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* ControlClass::Action -- Normal action for control gadget objects. *
* ControlClass::ControlClass -- Constructor for control class objects. *
* ControlClass::ControlClass -- Copy constructor for control gadget. *
* ControlClass::Draw_Me -- Draw logic for the control class object. *
* ControlClass::Get_ID -- Gets the ID number for this gadget. *
* ControlClass::Make_Peer -- Assigns a peer gadget to this gadget. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
/***********************************************************************************************
* ControlClass::ControlClass -- Constructor for control class objects. *
* *
* This is the normal constructor for control class objects. At this level, it only needs *
* to record the ID number assigned to this button. *
* *
* INPUT: id -- The ID number for this gadget. If the ID number specified is 0, then *
* this tells the system that no special ID code should be returned. *
* *
* x,y -- Pixel coordinate of upper left corner of gadget's region. *
* *
* w,h -- Pixel dimensions of the gadget's region. *
* *
* flags -- The input event flags that this gadget recognizes. *
* *
* sticky-- This this a "sticky" gadget? A sticky gadget is one that takes over the *
* gadget list while the mouse button is held down, if the mouse button was *
* initially clicked over its region. This is the behavior of "normal" *
* buttons in Windows. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/15/1995 JLB : Created. *
*=============================================================================================*/
ControlClass::ControlClass(unsigned id, int x, int y, int w, int h, unsigned flags, int sticky) :
GadgetClass(x, y, w, h, flags, sticky),
ID(id),
Peer(0)
{
}
/***********************************************************************************************
* ControlClass::ControlClass -- Copy constructor for control gadget. *
* *
* This copy constructor for a control gadget is used create a duplicate gadget that *
* is functionally similar. *
* *
* INPUT: control -- Reference to the gadget that is to be copied. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/05/1995 JLB : Created. *
*=============================================================================================*/
ControlClass::ControlClass(ControlClass const & control) :
GadgetClass(control),
ID(control.ID),
Peer(control.Peer)
{
}
/***********************************************************************************************
* ControlClass::Action -- Normal action for control gadget objects. *
* *
* This function gets called when the input event that this control gadget is looking for *
* occurs. In such a case, the return key code value is changed to the gadget's ID number *
* with the special button bit flag attached. *
* *
* INPUT: flags -- The event that triggered this function call. If this value is NULL, then *
* this is a forced (probably due to the sticky flag) call and the key code *
* is not altered. *
* *
* key -- Reference to the key code that will be returned by the controlling *
* Input() function. *
* *
* OUTPUT: bool; Should further list processing be aborted? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/15/1995 JLB : Created. *
*=============================================================================================*/
int ControlClass::Action(unsigned flags, KeyNumType & key)
{
/*
** Only if the flags indicate that a recognized action has occurred, do the
** normal processing of this gadget and set return value to the gadget ID.
*/
if (flags) {
if (ID) {
key = (KeyNumType)(ID | KN_BUTTON);
} else {
key = KN_NONE;
}
}
/*
** If there is a peer link established, inform that gadget of this
** action call.
*/
if (Peer) {
Peer->Peer_To_Peer(flags, key, *this);
}
return(GadgetClass::Action(flags, key));
}
/***********************************************************************************************
* ControlClass::Make_Peer -- Assigns a peer gadget to this gadget. *
* *
* This function will assign another gadget to this one. That other gadget will receive *
* notification of any Action() call to this gadget. Presumably, this is how one gadget *
* can automatically adapt to changes in another. Say for example, a slider bar can affect *
* the list box it is attached to. *
* *
* INPUT: gadget -- The gadget to inform when any Action() function is called. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/16/1995 JLB : Created. *
*=============================================================================================*/
void ControlClass::Make_Peer(GadgetClass & gadget)
{
Peer = &gadget;
}
/***********************************************************************************************
* ControlClass::Get_ID -- Gets the ID number for this gadget. *
* *
* This function will query and return with the ID number for this gadget. It is primarily *
* used by the Extract_Gadget() function. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the ID number for this gadget. If zero is returned, this means that *
* no ID was assigned to this gadget. This is a special case since a zero value will *
* never be returned as a pseudo-key as is done with non-zero values. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/16/1995 JLB : Created. *
*=============================================================================================*/
unsigned ControlClass::Get_ID(void) const
{
return(ID);
}
/***********************************************************************************************
* ControlClass::Draw_Me -- Draw logic for the control class object. *
* *
* This is called when the control object might need to be redrawn or when redrawing is *
* necessary. Since at this level of the class hierarchy, no actual drawing occurs, this *
* routine doesn't perform any rendering. It does, however, inform any peer attached *
* object that a Draw_Me function has been called. Presumably, the attached peer gadget *
* might very well need to be redrawn as a result of some action by this gadget. Since this *
* gadget might, more than likely, be of the "sticky" variety, a normal call to Draw_Me *
* for the other gadget will not occur. It must rely on the call by this routine in order *
* to update correctly. A typical example of this would be a slider that is attached to *
* a list box. As the slider is being drug around, the attached list box must be redrawn. *
* *
* INPUT: forced -- Should the redraw be forced regardless of the redraw flag? *
* *
* OUTPUT: bool; Was the gadget redrawn? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/16/1995 JLB : Created. *
*=============================================================================================*/
int ControlClass::Draw_Me(int forced)
{
if (Peer) {
Peer->Draw_Me();
}
return(GadgetClass::Draw_Me(forced));
}
================================================
FILE: CODE/CONTROL.H
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/CONTROL.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 : CONTROL.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 01/15/95 *
* *
* Last Update : January 15, 1995 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef CONTROL_H
#define CONTROL_H
#include "gadget.h"
/***************************************************************************
* ControlClass -- Region tracking class *
* *
* INPUT: int x -- x position of gadget *
* int y -- y position of gadget *
* int w -- width of gadget *
* int h -- height of gadget *
* UWORD flags -- see enumeration choices *
* *
* OUTPUT: 0 = new scenario created, -1 = not *
* WARNINGS: This class is Abstract (cannot make an instance of it) *
* *
* HISTORY: *
* 01/03/1995 MML : Created. *
*=========================================================================*/
class ControlClass : public GadgetClass
{
public:
ControlClass(NoInitClass const & x) : GadgetClass(x) {};
ControlClass(unsigned id, int x, int y, int w, int h, unsigned flags=LEFTPRESS|RIGHTPRESS, int sticky=false);
ControlClass(ControlClass const & control);
virtual void Make_Peer(GadgetClass & gadget);
/*
** Render support function.
*/
virtual int Draw_Me(int forced=false);
/*
** This is the ID number for this control gadget. This number is used to generate
** a special pseudo-key when the gadget detects valid input.
*/
unsigned ID;
protected:
virtual unsigned Get_ID(void) const;
virtual int Action(unsigned flags, KeyNumType & key);
/*
** This points to the peer button to inform when something happens to this
** gadget.
*/
GadgetClass * Peer;
};
#endif
================================================
FILE: CODE/COORD.CPP
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/COORD.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 : COORD.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : September 10, 1993 *
* *
* Last Update : July 22, 1996 [JLB] *
* *
* Support code to handle the coordinate system is located in this module. *
* Routines here will be called QUITE frequently during play and must be *
* as efficient as possible. *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* Cardinal_To_Fixed -- Converts cardinal numbers into a fixed point number. *
* Coord_Cell -- Convert a coordinate into a cell number. *
* Coord_Move -- Moves a coordinate an arbitrary direction for an arbitrary distance *
* Coord_Scatter -- Determines a random coordinate from an anchor point. *
* Coord_Spillage_List -- Calculate a spillage list for the dirty rectangle specified. *
* Coord_Spillage_List -- Determines the offset list for cell spillage/occupation. *
* Distance -- Determines the cell distance between two cells. *
* Distance -- Determines the lepton distance between two coordinates. *
* Distance -- Fetch distance between two target values. *
* Fixed_To_Cardinal -- Converts a fixed point number into a cardinal number. *
* Normal_Move_Point -- Moves point with tilt compensation. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
/***********************************************************************************************
* Coord_Cell -- Convert a coordinate into a cell number. *
* *
* This routine will convert the specified coordinate value into a cell number. This is *
* useful to determine the map index number into the cell array that corresponds to a *
* particular coordinate. *
* *
* INPUT: coord -- The coordinate to convert into a cell number. *
* *
* OUTPUT: Returns with the cell number that corresponds to the coordinate specified. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/17/1996 JLB : Created. *
*=============================================================================================*/
CELL Coord_Cell(COORDINATE coord)
{
CELL_COMPOSITE cell;
cell.Cell = 0;
cell.Sub.X = ((COORD_COMPOSITE &)coord).Sub.X.Sub.Cell;
cell.Sub.Y = ((COORD_COMPOSITE &)coord).Sub.Y.Sub.Cell;
return(cell.Cell);
// return(XY_Cell(((COORD_COMPOSITE)coord).Sub.X, ((COORD_COMPOSITE)composite).Sub.Y));
}
/***********************************************************************************************
* Distance -- Fetch distance between two target values. *
* *
* This routine will determine the lepton distance between the two specified target *
* values. *
* *
* INPUT: target1 -- First target value. *
* *
* target2 -- Second target value. *
* *
* OUTPUT: Returns with the lepton distance between the two target values. *
* *
* WARNINGS: Be sure that the targets are legal before calling this routine. Otherwise, the *
* return value is meaningless. *
* *
* HISTORY: *
* 06/17/1996 JLB : Created. *
*=============================================================================================*/
int Distance(TARGET target1, TARGET target2)
{
return(Distance(As_Coord(target1), As_Coord(target2)));
}
/***********************************************************************************************
* Distance -- Determines the lepton distance between two coordinates. *
* *
* This routine is used to determine the distance between two coordinates. It uses the *
* Dragon Strike method of distance determination and thus it is very fast. *
* *
* INPUT: coord1 -- First coordinate. *
* *
* coord2 -- Second coordinate. *
* *
* OUTPUT: Returns the lepton distance between the two coordinates. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/27/1994 JLB : Created. *
*=============================================================================================*/
int Distance(COORDINATE coord1, COORDINATE coord2)
{
int diff1, diff2;
diff1 = Coord_Y(coord1) - Coord_Y(coord2);
if (diff1 < 0) diff1 = -diff1;
diff2 = Coord_X(coord1) - Coord_X(coord2);
if (diff2 < 0) diff2 = -diff2;
if (diff1 > diff2) {
return(diff1 + ((unsigned)diff2 / 2));
}
return(diff2 + ((unsigned)diff1 / 2));
}
/***********************************************************************************************
* Coord_Spillage_List -- Determines the offset list for cell spillage/occupation. *
* *
* This routine will take an arbitrary position and object size and return with a list of *
* cell offsets from the current cell for all cells that are overlapped by the object. The *
* first cell offset is always zero, so to just get the adjacent spill cell list, add one *
* to the return pointer. *
* *
* INPUT: coord -- The coordinate to examine. *
* *
* maxsize -- The maximum width/height of the object (pixels). *
* *
* OUTPUT: Returns with a pointer to a spillage list. *
* *
* WARNINGS: The algorithm is limited to working with a maxsize of 48 or less. Larger values *
* will generate an incomplete overlap list. *
* *
* HISTORY: *
* 11/06/1993 JLB : Created. *
* 03/25/1994 JLB : Added width optimization. *
* 04/29/1994 JLB : Converted to C. *
* 06/03/1994 JLB : Converted to general purpose spillage functionality. *
* 01/07/1995 JLB : Manually calculates spillage list for large objects. *
*=============================================================================================*/
short const * Coord_Spillage_List(COORDINATE coord, int maxsize)
{
static short const _MoveSpillage[(int)FACING_COUNT+1][5] = {
{0, -MAP_CELL_W, REFRESH_EOL, 0, 0}, // N
{0, -MAP_CELL_W, 1, -(MAP_CELL_W-1), REFRESH_EOL}, // NE
{0, 1, REFRESH_EOL, 0, 0}, // E
{0, 1, MAP_CELL_W, MAP_CELL_W+1, REFRESH_EOL}, // SE
{0, MAP_CELL_W, REFRESH_EOL, 0, 0}, // S
{0, -1, MAP_CELL_W, MAP_CELL_W-1, REFRESH_EOL}, // SW
{0, -1, REFRESH_EOL, 0, 0}, // W
{0, -1, -MAP_CELL_W, -(MAP_CELL_W+1), REFRESH_EOL}, // NW
{0, REFRESH_EOL, 0, 0, 0} // non-moving.
};
static short _manual[10];
//; 00 = on axis
//; 01 = below axis
//; 10 = above axis
//; 11 = undefined
static signed char const _SpillTable[16] = {8,6,2,-1,0,7,1,-1,4,5,3,-1,-1,-1,-1,-1};
int index=0;
int x,y;
/*
** For mondo-enourmo-gigundo objects, use a prebuilt mammoth table
** that covers a 5x5 square region.
*/
if (maxsize > ICON_PIXEL_W * 2) {
static short const _gigundo[] = {
-((2*MAP_CELL_W)-2),-((2*MAP_CELL_W)-1),-((2*MAP_CELL_W)),-((2*MAP_CELL_W)+1),-((2*MAP_CELL_W)+2),
-((1*MAP_CELL_W)-2),-((1*MAP_CELL_W)-1),-((1*MAP_CELL_W)),-((1*MAP_CELL_W)+1),-((1*MAP_CELL_W)+2),
-((0*MAP_CELL_W)-2),-((0*MAP_CELL_W)-1),-((0*MAP_CELL_W)),-((0*MAP_CELL_W)+1),-((0*MAP_CELL_W)+2),
((1*MAP_CELL_W)-2),((1*MAP_CELL_W)-1),((1*MAP_CELL_W)),((1*MAP_CELL_W)+1),((1*MAP_CELL_W)+2),
+((2*MAP_CELL_W)-2),+((2*MAP_CELL_W)-1),+((2*MAP_CELL_W)),+((2*MAP_CELL_W)+1),+((2*MAP_CELL_W)+2),
REFRESH_EOL
};
return(&_gigundo[0]);
}
/*
** For very large objects, build the overlap list by hand. This is time consuming, but
** not nearly as time consuming as drawing even a single cell unnecessarily.
*/
if (maxsize > ICON_PIXEL_W) {
maxsize = min(maxsize, (ICON_PIXEL_W*2))/2;
x = (ICON_PIXEL_W * Coord_XLepton(coord)) / ICON_LEPTON_W;
y = (ICON_PIXEL_H * Coord_YLepton(coord)) / ICON_LEPTON_H;
int left = x-maxsize;
int right = x+maxsize;
int top = y-maxsize;
int bottom = y+maxsize;
_manual[index++] = 0;
if (left < 0) _manual[index++] = -1;
if (right >= ICON_PIXEL_W) _manual[index++] = 1;
if (top < 0) _manual[index++] = -MAP_CELL_W;
if (bottom >= ICON_PIXEL_H) _manual[index++] = MAP_CELL_W;
if (left < 0 && top < 0) _manual[index++] = -(MAP_CELL_W+1);
if (right >= ICON_PIXEL_W && bottom >= ICON_PIXEL_H) _manual[index++] = MAP_CELL_W+1;
if (left < 0 && bottom >= ICON_PIXEL_H) _manual[index++] = MAP_CELL_W-1;
if (right >= ICON_PIXEL_H && top < 0) _manual[index++] = -(MAP_CELL_W-1);
_manual[index] = REFRESH_EOL;
return(&_manual[0]);
}
/*
** Determine the number of leptons "leeway" allowed this unit.
*/
int posval = Pixel2Lepton[(ICON_PIXEL_W-maxsize)/2];
x = Coord_XLepton(coord) - 0x0080;
y = Coord_YLepton(coord) - 0x0080;
if (y > posval) index |= 0x08; // Spilling South.
if (y < -posval) index |= 0x04; // Spilling North.
if (x > posval) index |= 0x02; // Spilling East.
if (x < -posval) index |= 0x01; // Spilling West.
return(&_MoveSpillage[_SpillTable[index]][0]);
}
/***********************************************************************************************
* Coord_Spillage_List -- Calculate a spillage list for the dirty rectangle specified. *
* *
* Given a center coordinate and a dirty rectangle, calcuate a cell offset list for *
* determining such things as overlap and redraw logic. Optionally, the center cell *
* location will not be part of the list. *
* *
* INPUT: coord -- The center coordinate that the dirty rectangle is based off of. *
* *
* rect -- Reference to the dirty rectangle. *
* *
* nocenter -- If true, then the center cell offset will not be part of the spillage *
* list returned. This is handy when the center cell is known to be *
* processed by some other method and it can be safely and efficiently *
* ignored by the list generated. *
* *
* OUTPUT: Returns with a pointer to the spillage list that corresponds to the data *
* specified. This is a pointer to a static buffer and as such it will only be valid *
* until the next time that this routine is called. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/22/1996 JLB : Created. *
*=============================================================================================*/
short const * Coord_Spillage_List(COORDINATE coord, Rect const & rect, bool nocenter)
{
if (!rect.Is_Valid()) {
static short const _list[] = {REFRESH_EOL};
return(_list);
}
CELL coordcell = Coord_Cell(coord);
LEPTON x = Coord_X(coord);
LEPTON y = Coord_Y(coord);
/*
** Add the rectangle values to the coordinate in order to normalize the start and end
** corners of the rectangle. The values are now absolute to the real game world rather
** than relative to the coordinate.
*/
LEPTON_COMPOSITE startx;
LEPTON_COMPOSITE starty;
LEPTON_COMPOSITE endx;
LEPTON_COMPOSITE endy;
startx.Raw = (int)x + (short)Pixel_To_Lepton(rect.X);
starty.Raw = (int)y + (short)Pixel_To_Lepton(rect.Y);
endx.Raw = startx.Raw + Pixel_To_Lepton(rect.Width-1);
endy.Raw = starty.Raw + Pixel_To_Lepton(rect.Height-1);
/*
** Determine the upper left and lower right cell indexes. This is a simple conversion from
** their lepton counterpart. These cells values are used to form the bounding box for the
** map offset list.
*/
int cellx = startx.Sub.Cell;
int cellx2 = endx.Sub.Cell;
int celly = starty.Sub.Cell;
int celly2 = endy.Sub.Cell;
/*
** Generate the spillage list by counting off the rows and colums of the cells
** that are affected. This is easy since the upper left and lower right corner cells
** are known.
*/
int count = 0;
static short _spillagelist[128];
short * ptr = _spillagelist;
for (int yy = celly; yy <= celly2; yy++) {
for (int xx = cellx; xx <= cellx2; xx++) {
short offset = (XY_Cell(xx, yy) - coordcell);
if (!nocenter || offset != 0) {
*ptr++ = offset;
count++;
if (count+2 >= ARRAY_SIZE(_spillagelist)) break;
}
}
if (count+2 >= ARRAY_SIZE(_spillagelist)) break;
}
/*
** Cap the list with the end of list marker and then return a pointer
** to the completed list.
*/
*ptr = REFRESH_EOL;
return(_spillagelist);
}
/***********************************************************************************************
* Coord_Move -- Moves a coordinate an arbitrary direction for an arbitrary distance *
* *
* This function will move a coordinate in a using SIN and COS arithmetic. *
* *
* INPUT: start -- The starting coordinate. *
* *
* dir -- The direction to move the coordinate. *
* *
* distance -- The distance to move the coordinate position (in leptons). *
* *
* OUTPUT: Returns the new coordinate position. *
* *
* WARNINGS: This routine uses multiplies -- use with caution. *
* *
* HISTORY: *
* 05/27/1994 JLB : Created. *
*=============================================================================================*/
COORDINATE Coord_Move(COORDINATE start, register DirType dir, unsigned short distance)
{
#ifdef NEVER
short x = Coord_X(start);
short y = Coord_Y(start);
Move_Point(x, y, dir, distance);
return(XY_Coord(x,y));
#endif
Move_Point(*(short *)&start, *(((short *)&start)+1), dir, distance);
return(start);
}
/***********************************************************************************************
* Coord_Scatter -- Determines a random coordinate from an anchor point. *
* *
* This routine will perform a scatter algorithm on the specified *
* anchor point in order to return with another coordinate that is *
* randomly nearby the original. Typical use of this would be for *
* missile targeting. *
* *
* INPUT: coord -- This is the anchor coordinate. *
* *
* distance -- This is the distance in pixels that the scatter *
* should fall within. *
* *
* lock -- bool; Convert the new coordinate into a center *
* cell based coordinate? *
* *
* OUTPUT: Returns with a new coordinate that is nearby the original. *
* *
* WARNINGS: Maximum pixel scatter distance is 255. *
* *
* HISTORY: *
* 02/01/1992 JLB : Created. *
* 05/13/1992 JLB : Only uses Random(). *
*=============================================================================================*/
COORDINATE Coord_Scatter(COORDINATE coord, unsigned distance, bool lock)
{
COORDINATE newcoord;
newcoord = Coord_Move(coord, Random_Pick(DIR_N, DIR_MAX), distance);
if (newcoord & HIGH_COORD_MASK) newcoord = coord;
if (lock) {
newcoord = Coord_Snap(newcoord);
}
return(newcoord);
}
extern int calcx(signed short, short distance);
#pragma aux calcx parm [ax] [bx] \
modify [eax dx] \
value [eax] = \
"imul bx" \
"shl ax,1" \
"rcl dx,1" \
"mov al,ah" \
"mov ah,dl" \
"cwd" \
// "and eax,0FFFFh";
extern int calcy(signed short, short distance);
#pragma aux calcy parm [ax] [bx] \
modify [eax dx] \
value [eax] = \
"imul bx" \
"shl ax,1" \
"rcl dx,1" \
"mov al,ah" \
"mov ah,dl" \
"cwd" \
"neg eax";
// "and eax,0FFFFh" \
void Move_Point(short &x, short &y, register DirType dir, unsigned short distance)
{
static char const CosTable[256] = {
0x00,0x03,0x06,0x09,0x0c,0x0f,0x12,0x15,
0x18,0x1b,0x1e,0x21,0x24,0x27,0x2a,0x2d,
0x30,0x33,0x36,0x39,0x3b,0x3e,0x41,0x43,
0x46,0x49,0x4b,0x4e,0x50,0x52,0x55,0x57,
0x59,0x5b,0x5e,0x60,0x62,0x64,0x65,0x67,
0x69,0x6b,0x6c,0x6e,0x6f,0x71,0x72,0x74,
0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7b,
0x7c,0x7d,0x7d,0x7e,0x7e,0x7e,0x7e,0x7e,
0x7f,0x7e,0x7e,0x7e,0x7e,0x7e,0x7d,0x7d,
0x7c,0x7b,0x7b,0x7a,0x79,0x78,0x77,0x76,
0x75,0x74,0x72,0x71,0x70,0x6e,0x6c,0x6b,
0x69,0x67,0x66,0x64,0x62,0x60,0x5e,0x5b,
0x59,0x57,0x55,0x52,0x50,0x4e,0x4b,0x49,
0x46,0x43,0x41,0x3e,0x3b,0x39,0x36,0x33,
0x30,0x2d,0x2a,0x27,0x24,0x21,0x1e,0x1b,
0x18,0x15,0x12,0x0f,0x0c,0x09,0x06,0x03,
0x00,0xfd,0xfa,0xf7,0xf4,0xf1,0xee,0xeb,
0xe8,0xe5,0xe2,0xdf,0xdc,0xd9,0xd6,0xd3,
0xd0,0xcd,0xca,0xc7,0xc5,0xc2,0xbf,0xbd,
0xba,0xb7,0xb5,0xb2,0xb0,0xae,0xab,0xa9,
0xa7,0xa5,0xa2,0xa0,0x9e,0x9c,0x9a,0x99,
0x97,0x95,0x94,0x92,0x91,0x8f,0x8e,0x8c,
0x8b,0x8a,0x89,0x88,0x87,0x86,0x85,0x85,
0x84,0x83,0x83,0x82,0x82,0x82,0x82,0x82,
0x82,0x82,0x82,0x82,0x82,0x82,0x83,0x83,
0x84,0x85,0x85,0x86,0x87,0x88,0x89,0x8a,
0x8b,0x8c,0x8e,0x8f,0x90,0x92,0x94,0x95,
0x97,0x99,0x9a,0x9c,0x9e,0xa0,0xa2,0xa5,
0xa7,0xa9,0xab,0xae,0xb0,0xb2,0xb5,0xb7,
0xba,0xbd,0xbf,0xc2,0xc5,0xc7,0xca,0xcd,
0xd0,0xd3,0xd6,0xd9,0xdc,0xdf,0xe2,0xe5,
0xe8,0xeb,0xee,0xf1,0xf4,0xf7,0xfa,0xfd,
};
static char const SinTable[256] = {
0x7f,0x7e,0x7e,0x7e,0x7e,0x7e,0x7d,0x7d,
0x7c,0x7b,0x7b,0x7a,0x79,0x78,0x77,0x76,
0x75,0x74,0x72,0x71,0x70,0x6e,0x6c,0x6b,
0x69,0x67,0x66,0x64,0x62,0x60,0x5e,0x5b,
0x59,0x57,0x55,0x52,0x50,0x4e,0x4b,0x49,
0x46,0x43,0x41,0x3e,0x3b,0x39,0x36,0x33,
0x30,0x2d,0x2a,0x27,0x24,0x21,0x1e,0x1b,
0x18,0x15,0x12,0x0f,0x0c,0x09,0x06,0x03,
0x00,0xfd,0xfa,0xf7,0xf4,0xf1,0xee,0xeb,
0xe8,0xe5,0xe2,0xdf,0xdc,0xd9,0xd6,0xd3,
0xd0,0xcd,0xca,0xc7,0xc5,0xc2,0xbf,0xbd,
0xba,0xb7,0xb5,0xb2,0xb0,0xae,0xab,0xa9,
0xa7,0xa5,0xa2,0xa0,0x9e,0x9c,0x9a,0x99,
0x97,0x95,0x94,0x92,0x91,0x8f,0x8e,0x8c,
0x8b,0x8a,0x89,0x88,0x87,0x86,0x85,0x85,
0x84,0x83,0x83,0x82,0x82,0x82,0x82,0x82,
0x82,0x82,0x82,0x82,0x82,0x82,0x83,0x83,
0x84,0x85,0x85,0x86,0x87,0x88,0x89,0x8a,
0x8b,0x8c,0x8e,0x8f,0x90,0x92,0x94,0x95,
0x97,0x99,0x9a,0x9c,0x9e,0xa0,0xa2,0xa5,
0xa7,0xa9,0xab,0xae,0xb0,0xb2,0xb5,0xb7,
0xba,0xbd,0xbf,0xc2,0xc5,0xc7,0xca,0xcd,
0xd0,0xd3,0xd6,0xd9,0xdc,0xdf,0xe2,0xe5,
0xe8,0xeb,0xee,0xf1,0xf4,0xf7,0xfa,0xfd,
0x00,0x03,0x06,0x09,0x0c,0x0f,0x12,0x15,
0x18,0x1b,0x1e,0x21,0x24,0x27,0x2a,0x2d,
0x30,0x33,0x36,0x39,0x3b,0x3e,0x41,0x43,
0x46,0x49,0x4b,0x4e,0x50,0x52,0x55,0x57,
0x59,0x5b,0x5e,0x60,0x62,0x64,0x65,0x67,
0x69,0x6b,0x6c,0x6e,0x6f,0x71,0x72,0x74,
0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7b,
0x7c,0x7d,0x7d,0x7e,0x7e,0x7e,0x7e,0x7e,
};
distance = distance; // Keep LINT quiet.
#ifdef OBSOLETE
/*
** Calculate and add in the X component of the move.
*/
_AX = CosTable[dir];
asm imul word ptr distance
asm shl ax,1
asm rcl dx,1
asm mov al,ah
asm mov ah,dl
_DX = _AX;
x += _DX;
#else
x += calcx(CosTable[dir], distance);
#endif
// asm add [word ptr start],ax
#ifdef OBSOLETE
/*
** Calculate and add in the Y component of the move.
*/
_AX = SinTable[dir];
asm imul word ptr distance
asm shl ax,1
asm rcl dx,1
asm mov al,ah
asm mov ah,dl
asm neg ax // Subtraction needed because of inverted sine table.
_DX = _AX;
y += _DX;
#else
y += calcy(SinTable[dir], distance);
#endif
// asm add [word ptr start+2],ax
}
/***********************************************************************************************
* Normal_Move_Point -- Moves point with tilt compensation. *
* *
* This routine will move the point in the direction and distance specified but it will *
* take into account the tilt of the playing field. Typical use of this routine is to *
* determine positioning as it relates to the playfield. Turrets are a good example of *
* this. *
* *
* INPUT: x,y -- References to the coordinates to adjust. *
* *
* dir -- The direction of the desired movement. *
* *
* distance -- The distance (in coordinate units) to move the point. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/19/1995 JLB : Created. *
*=============================================================================================*/
// Loss of precision in initializations (8 bits to 7 bits) warning. Hmmm.. can this be fixed?
//lint -e569
void Normal_Move_Point(short &x, short &y, register DirType dir, unsigned short distance)
{
static signed char const CosTable[256] = {
0x00,0x03,0x06,0x09,0x0c,0x0f,0x12,0x15,
0x18,0x1b,0x1e,0x21,0x24,0x27,0x2a,0x2d,
0x30,0x33,0x36,0x39,0x3b,0x3e,0x41,0x43,
0x46,0x49,0x4b,0x4e,0x50,0x52,0x55,0x57,
0x59,0x5b,0x5e,0x60,0x62,0x64,0x65,0x67,
0x69,0x6b,0x6c,0x6e,0x6f,0x71,0x72,0x74,
0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7b,
0x7c,0x7d,0x7d,0x7e,0x7e,0x7e,0x7e,0x7e,
0x7f,0x7e,0x7e,0x7e,0x7e,0x7e,0x7d,0x7d,
0x7c,0x7b,0x7b,0x7a,0x79,0x78,0x77,0x76,
0x75,0x74,0x72,0x71,0x70,0x6e,0x6c,0x6b,
0x69,0x67,0x66,0x64,0x62,0x60,0x5e,0x5b,
0x59,0x57,0x55,0x52,0x50,0x4e,0x4b,0x49,
0x46,0x43,0x41,0x3e,0x3b,0x39,0x36,0x33,
0x30,0x2d,0x2a,0x27,0x24,0x21,0x1e,0x1b,
0x18,0x15,0x12,0x0f,0x0c,0x09,0x06,0x03,
0x00,0xfd,0xfa,0xf7,0xf4,0xf1,0xee,0xeb,
0xe8,0xe5,0xe2,0xdf,0xdc,0xd9,0xd6,0xd3,
0xd0,0xcd,0xca,0xc7,0xc5,0xc2,0xbf,0xbd,
0xba,0xb7,0xb5,0xb2,0xb0,0xae,0xab,0xa9,
0xa7,0xa5,0xa2,0xa0,0x9e,0x9c,0x9a,0x99,
0x97,0x95,0x94,0x92,0x91,0x8f,0x8e,0x8c,
0x8b,0x8a,0x89,0x88,0x87,0x86,0x85,0x85,
0x84,0x83,0x83,0x82,0x82,0x82,0x82,0x82,
0x82,0x82,0x82,0x82,0x82,0x82,0x83,0x83,
0x84,0x85,0x85,0x86,0x87,0x88,0x89,0x8a,
0x8b,0x8c,0x8e,0x8f,0x90,0x92,0x94,0x95,
0x97,0x99,0x9a,0x9c,0x9e,0xa0,0xa2,0xa5,
0xa7,0xa9,0xab,0xae,0xb0,0xb2,0xb5,0xb7,
0xba,0xbd,0xbf,0xc2,0xc5,0xc7,0xca,0xcd,
0xd0,0xd3,0xd6,0xd9,0xdc,0xdf,0xe2,0xe5,
0xe8,0xeb,0xee,0xf1,0xf4,0xf7,0xfa,0xfd,
};
static signed char const SinTable[256] = {
0x7f,0x7e,0x7e,0x7e,0x7e,0x7e,0x7d,0x7d,
0x7c,0x7b,0x7b,0x7a,0x79,0x78,0x77,0x76,
0x75,0x74,0x72,0x71,0x70,0x6e,0x6c,0x6b,
0x69,0x67,0x66,0x64,0x62,0x60,0x5e,0x5b,
0x59,0x57,0x55,0x52,0x50,0x4e,0x4b,0x49,
0x46,0x43,0x41,0x3e,0x3b,0x39,0x36,0x33,
0x30,0x2d,0x2a,0x27,0x24,0x21,0x1e,0x1b,
0x18,0x15,0x12,0x0f,0x0c,0x09,0x06,0x03,
0x00,0xfd,0xfa,0xf7,0xf4,0xf1,0xee,0xeb,
0xe8,0xe5,0xe2,0xdf,0xdc,0xd9,0xd6,0xd3,
0xd0,0xcd,0xca,0xc7,0xc5,0xc2,0xbf,0xbd,
0xba,0xb7,0xb5,0xb2,0xb0,0xae,0xab,0xa9,
0xa7,0xa5,0xa2,0xa0,0x9e,0x9c,0x9a,0x99,
0x97,0x95,0x94,0x92,0x91,0x8f,0x8e,0x8c,
0x8b,0x8a,0x89,0x88,0x87,0x86,0x85,0x85,
0x84,0x83,0x83,0x82,0x82,0x82,0x82,0x82,
0x82,0x82,0x82,0x82,0x82,0x82,0x83,0x83,
0x84,0x85,0x85,0x86,0x87,0x88,0x89,0x8a,
0x8b,0x8c,0x8e,0x8f,0x90,0x92,0x94,0x95,
0x97,0x99,0x9a,0x9c,0x9e,0xa0,0xa2,0xa5,
0xa7,0xa9,0xab,0xae,0xb0,0xb2,0xb5,0xb7,
0xba,0xbd,0xbf,0xc2,0xc5,0xc7,0xca,0xcd,
0xd0,0xd3,0xd6,0xd9,0xdc,0xdf,0xe2,0xe5,
0xe8,0xeb,0xee,0xf1,0xf4,0xf7,0xfa,0xfd,
0x00,0x03,0x06,0x09,0x0c,0x0f,0x12,0x15,
0x18,0x1b,0x1e,0x21,0x24,0x27,0x2a,0x2d,
0x30,0x33,0x36,0x39,0x3b,0x3e,0x41,0x43,
0x46,0x49,0x4b,0x4e,0x50,0x52,0x55,0x57,
0x59,0x5b,0x5e,0x60,0x62,0x64,0x65,0x67,
0x69,0x6b,0x6c,0x6e,0x6f,0x71,0x72,0x74,
0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7b,
0x7c,0x7d,0x7d,0x7e,0x7e,0x7e,0x7e,0x7e,
};
distance = distance; // Keep LINT quiet.
x += calcx(CosTable[dir], distance);
y += calcy(SinTable[dir] / 2, distance);
}
================================================
FILE: CODE/COORDA.ASM
================================================
;
; 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 .
;
;***************************************************************************
;** 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 I N C **
;***************************************************************************
;* *
;* Project Name : Command & Conquer *
;* *
;* File Name : COORDA.ASM *
;* *
;* Programmer : Barry W. Green *
;* *
;* Start Date : February 17, 1995 *
;* *
;* Last Update : February 17, 1995 [BWG] *
;* *
;*-------------------------------------------------------------------------*
;* Functions: *
;* Cardinal_To_Fixed -- Converts cardinal numbers into a fixed point number. *
;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *
IDEAL
P386
MODEL USE32 FLAT
GLOBAL Cardinal_To_Fixed :NEAR
GLOBAL Fixed_To_Cardinal :NEAR
CODESEG
;***********************************************************************************************
;* Cardinal_To_Fixed -- Converts cardinal numbers into a fixed point number. *
;* *
;* This utility function will convert cardinal numbers into a fixed point fraction. The *
;* use of fixed point numbers occurs throughout the product -- since it is a convenient *
;* tool. The fixed point number is based on the formula: *
;* *
;* result = cardinal / base *
;* *
;* The accuracy of the fixed point number is limited to 1/256 as the lowest and up to *
;* 256 as the largest. *
;* *
;* INPUT: base -- The key number to base the fraction about. *
;* *
;* cardinal -- The other number (hey -- what do you call it?) *
;* *
;* OUTPUT: Returns with the fixed point number of the "cardinal" parameter as it relates *
;* to the "base" parameter. *
;* *
;* WARNINGS: none *
;* *
;* HISTORY: *
;* 02/17/1995 BWG : Created. *
;*=============================================================================================*/
;unsigned int Cardinal_To_Fixed(unsigned base, unsigned cardinal);
PROC Cardinal_To_Fixed C near
USES ebx, edx
ARG base:DWORD
ARG cardinal:DWORD
mov eax,0FFFFh ; establish default return value
mov ebx,[base]
or ebx,ebx
jz near ??retneg1 ; if base==0, return 65535
mov eax,[cardinal] ; otherwise, return (cardinal*256)/base
shl eax,8
xor edx,edx
div ebx
??retneg1:
ret
ENDP Cardinal_To_Fixed
;***********************************************************************************************
;* Fixed_To_Cardinal -- Converts a fixed point number into a cardinal number. *
;* *
;* Use this routine to convert a fixed point number into a cardinal number. *
;* *
;* INPUT: base -- The base number that the original fixed point number was created from. *
;* *
;* fixed -- The fixed point number to convert. *
;* *
;* OUTPUT: Returns with the reconverted number. *
;* *
;* WARNINGS: none *
;* *
;* HISTORY: *
;* 02/17/1995 BWG : Created. *
;*=============================================================================================*/
;unsigned int Fixed_To_Cardinal(unsigned base, unsigned fixed);
PROC Fixed_To_Cardinal C near
USES edx
ARG base:DWORD
ARG fixed:DWORD
mov eax,[base]
mul [fixed]
add eax,080h ; eax = (base * fixed) + 0x80
test eax,0FF000000h ; if high byte set, return FFFF
jnz ??rneg1
shr eax,8 ; else, return eax/256
ret
??rneg1 :
mov eax,0FFFFh ; establish default return value
ret
ENDP Fixed_To_Cardinal
END
================================================
FILE: CODE/CPUID.ASM
================================================
;
; 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 .
;
; $Header: F:\projects\c&c0\vcs\code\cpuid.asv 5.0 11 Nov 1996 09:40: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 I N C **
;***************************************************************************
;* *
;* Project Name : Command & Conquer *
;* *
;* File Name : MMX.ASM *
;* *
;* Programmer : Steve Tall *
;* *
;* Start Date : May 19th, 1996 *
;* *
;* Last Update : May 19th 1996 [ST] *
;* *
;*-------------------------------------------------------------------------*
;* Functions: *
;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *
.586
.model flat
;
; Variables externs
;
GLOBAL C CPUType:byte
;externdef C CPUType:byte
GLOBAL C VendorID:byte
;externdef C VendorID:byte
;
; Function externs
;
GLOBAL C Detect_MMX_Availability:near
;externdef C Detect_MMX_Availability:near
.code
;*********************************************************************************************
;* Detect_MMX_Availability -- Detect the presence of MMX technology. *
;* *
;* *
;* INPUT: Nothing *
;* *
;* OUTPUT: True if MMX technology is available. *
;* *
;* Warnings: *
;* *
;* Note: Based in part on CPUID32.ASM by Intel *
;* *
;* HISTORY: *
;* 05/19/96 ST : Created. *
;*===========================================================================================*
Detect_MMX_Availability proc C
local idflag:byte
local cputype:byte
;assume processor is at least 386
;
;check whether AC bit in eflags can be toggled.
;If not then processor is 386
mov [idflag],0
pushfd ;get Eflags in EAX
pop eax
mov ecx,eax ;save eflags
xor eax,40000h ;toggle AC bit in eflags
push eax ;new eflags on stack
popfd ;move new value into eflags
pushfd ;get new eflags back into eax
pop eax
xor eax,ecx ;if AC bit not toggled then CPU=386
mov [cputype],3
jz @@end_get_cpu ;cpu is 386
push ecx
popfd ;restore AC bit in eflags
;processor is at least 486
;
;Check for ability to set/clear ID flag in EFLAGS
;ID flag indicates ability of processor to execute the CPUID instruction.
;486 not guaranteed to have CPUID inst?
;
mov [cputype],4
mov eax,ecx ;original EFLAGS
xor eax,200000h ;toggle ID bit
push eax
popfd
pushfd
pop eax
xor eax,ecx ;check if still toggled
jz @@end_get_cpu
; Execute CPUID instruction to determine vendor, family,
; model and stepping.
;
mov [idflag],1 ;flag ID is available
xor eax,eax
cpuid
mov dword ptr [VendorID],ebx
mov dword ptr [VendorID+4],edx
mov dword ptr [VendorID+8],ecx
mov dword ptr [VendorID+12]," "
cmp eax,1 ;check if 1 is valid
jl @@end_get_cpu ;inp for cpuid inst.
xor eax,eax
inc eax
cpuid ;get stepping, model and family
and ax,0f00H
shr ax,08H
mov [cputype],al
@@end_get_cpu: mov al,[cputype]
mov [CPUType],al
;
; We have the CPU type in al now.
; If we arent on at least a pentium then we can assume there is no MMX
;
cmp al,5
jl @@no_mmx
mov eax,1
cpuid
test edx,00800000h
jz @@no_mmx
;
; MMX detected - return true
;
mov eax,1
ret
@@no_mmx: xor eax,eax
ret
Detect_MMX_Availability endp
.data
CPUType db 0
VendorID db "Not available",0,0,0,0,0,0
end
================================================
FILE: CODE/CRATE.CPP
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/CRATE.CPP 3 3/04/97 3:12p 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 : CRATE.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 08/26/96 *
* *
* Last Update : October 14, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* CrateClass::Create_Crate -- Create a crate in the cell specified. *
* CrateClass::Get_Crate -- Pick up a crate from the cell specified. *
* CrateClass::Put_Crate -- Generates crate overlay at cell specified. *
* CrateClass::Remove_It -- Removes the crate from wherever it is. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
/***********************************************************************************************
* CrateClass::Remove_It -- Removes the crate from wherever it is. *
* *
* This routine will remove the crate from whereever it happens to be. *
* *
* INPUT: none *
* *
* OUTPUT: bool; Was the crate found and removed? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/26/1996 JLB : Created. *
*=============================================================================================*/
bool CrateClass::Remove_It(void)
{
if (Is_Valid()) {
Get_Crate(Cell);
Make_Invalid();
return(true);
}
return(false);
}
/***********************************************************************************************
* CrateClass::Create_Crate -- Create a crate in the cell specified. *
* *
* This will create a crate in the cell specified. If the crate could not be crated there *
* then 'false' will be returned. *
* *
* INPUT: cell -- The desired cell to place the crate in. *
* *
* OUTPUT: bool; Was the crate created and placed in the cell? *
* *
* WARNINGS: It is quite possible for the crate not to have been placed. Only the most clear *
* locations are valid for crate placement. *
* *
* HISTORY: *
* 08/26/1996 JLB : Created. *
*=============================================================================================*/
bool CrateClass::Create_Crate(CELL cell)
{
/*
** Remove any existing crate that this crate class is tracking.
*/
Remove_It();
/*
** Try to place a new crate at the cell specified.
*/
if (Put_Crate(cell)) {
Cell = cell;
Timer = Random_Pick(Rule.CrateTime * (TICKS_PER_MINUTE/2), Rule.CrateTime * (TICKS_PER_MINUTE*2));
Timer.Start();
return(true);
}
return(false);
}
/***********************************************************************************************
* CrateClass::Put_Crate -- Generates crate overlay at cell specified. *
* *
* This helpter routine will examine the cell and place the appropriate crate type into *
* the cell specified. If the overlay could not be generated, then 'false' is returned. *
* *
* INPUT: cell -- The cell to generate the crate overlay in. *
* *
* OUTPUT: bool; Was the crate overlay generated? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/26/1996 JLB : Created. *
* 10/14/1996 JLB : Takes reference to cell so that tracking can occur. *
*=============================================================================================*/
bool CrateClass::Put_Crate(CELL & cell)
{
int old = ScenarioInit;
ScenarioInit = 0;
if (Map.In_Radar(cell)) {
CellClass * cellptr = &Map[cell];
while (cellptr->Overlay != OVERLAY_NONE && !cellptr->Is_Clear_To_Build(SPEED_FLOAT) && !cellptr->Is_Clear_To_Build(SPEED_FOOT)) {
cell = Map.Pick_Random_Location();
if (Percent_Chance(100 * Rule.WaterCrateChance)) {
cell = Map.Nearby_Location(cell, SPEED_FLOAT);
} else {
cell = Map.Nearby_Location(cell, SPEED_TRACK);
}
cellptr = &Map[cell];
}
if (cellptr->Is_Clear_To_Build(SPEED_FLOAT)) {
new OverlayClass(OVERLAY_WATER_CRATE, cell);
} else {
new OverlayClass(OVERLAY_WOOD_CRATE, cell);
}
ScenarioInit = old;
return(true);
}
ScenarioInit = old;
return(false);
}
/***********************************************************************************************
* CrateClass::Get_Crate -- Pick up a crate from the cell specified. *
* *
* This will remove the crate from the cell specified. *
* *
* INPUT: cell -- The cell to examine and remove any crate overlays present. *
* *
* OUTPUT: bool; Was a crate overlay found and removed? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/26/1996 JLB : Created. *
*=============================================================================================*/
bool CrateClass::Get_Crate(CELL cell)
{
if (Map.In_Radar(cell)) {
CellClass * cellptr = &Map[cell];
if (cellptr->Overlay == OVERLAY_WOOD_CRATE ||
cellptr->Overlay == OVERLAY_STEEL_CRATE ||
cellptr->Overlay == OVERLAY_WATER_CRATE) {
cellptr->Overlay = OVERLAY_NONE;
cellptr->OverlayData = 0;
cellptr->Redraw_Objects();
return(true);
}
}
return(false);
}
================================================
FILE: CODE/CRATE.H
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/CRATE.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 : CRATE.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 08/26/96 *
* *
* Last Update : August 26, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef CRATE_H
#define CRATE_H
#include "ftimer.h"
#include "jshell.h"
/*
** The "bool" integral type was defined by the C++ comittee 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
class CrateClass {
public:
CrateClass(void) : Timer(NoInitClass()), Cell(-1) {}
void Init(void) {Make_Invalid();}
bool Create_Crate(CELL cell);
bool Is_Here(CELL cell) const {return(Is_Valid() && cell == Cell);}
bool Remove_It(void);
bool Is_Expired(void) const {return(Is_Valid() && Timer == 0);}
bool Is_Valid(void) const {return(Cell != -1);}
private:
static bool Put_Crate(CELL & cell);
static bool Get_Crate(CELL cell);
void Make_Invalid(void) {Cell = -1;Timer.Stop();}
CDTimerClass Timer;
CELL Cell;
};
#endif
================================================
FILE: CODE/CRC.CPP
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/CRC.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 : CRC.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 03/02/96 *
* *
* Last Update : March 2, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* CRCEngine::operator() -- Submits one byte of data to the CRC engine. *
* CRCEngine::operator() -- Submits an arbitrary data block to the CRC engine. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "crc.h"
/***********************************************************************************************
* CRCEngine::operator() -- Submits one byte of data to the CRC engine. *
* *
* This routine will take the specified byte of data and submit it to the CRC engine *
* for processing. This routine is designed to be as fast as possible since the typical *
* use of this routine is to feed one of presumably many byte sized chunks of data to the *
* CRC engine. *
* *
* INPUT: datum -- One byte of data to submit to the CRC engine. *
* *
* OUTPUT: none *
* *
* WARNINGS: If possible, use the buffer/size operator to submit data rather than repeated *
* calls to this routine. *
* *
* HISTORY: *
* 03/02/1996 JLB : Created. *
*=============================================================================================*/
void CRCEngine::operator() (char datum)
{
StagingBuffer.Buffer[Index++] = datum;
if (Index == sizeof(long)) {
CRC = Value();
StagingBuffer.Composite = 0;
Index = 0;
}
}
/***********************************************************************************************
* CRCEngine::operator() -- Submits an arbitrary data block to the CRC engine. *
* *
* This routine will submit the specified block to the CRC engine. The block can be of *
* arbitrary length. *
* *
* INPUT: buffer -- Pointer to the buffer that contains the data. The buffer will not *
* be modified. *
* *
* length -- The length of the buffer (in bytes). *
* *
* OUTPUT: Returns with the current CRC value accumulated so far. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 03/02/1996 JLB : Created. *
*=============================================================================================*/
long CRCEngine::operator() (void const * buffer, int length)
{
if (buffer != NULL && length > 0) {
char const * dataptr = (char const *)buffer;
int bytes_left = length;
/*
** If there are any leader bytes (needed to fill the staging buffer)
** then process those by first using them to fill up the staging
** buffer. The bulk of the data block will be processed by the high
** speed longword processing loop.
*/
while (bytes_left && Buffer_Needs_Data()) {
operator()(*dataptr);
dataptr++;
bytes_left--;
}
/*
** Perform the fast 'bulk' processing by reading long word sized
** data blocks.
*/
long const * longptr = (long const *)dataptr;
int longcount = bytes_left / sizeof(long); // Whole 'long' elements remaining.
while (longcount--) {
CRC = _lrotl(CRC, 1) + *longptr++;
bytes_left -= sizeof(long);
}
/*
** If there are remainder bytes, then process these by adding them
** to the staging buffer.
*/
dataptr = (char const *)longptr;
while (bytes_left) {
operator()(*dataptr);
dataptr++;
bytes_left--;
}
}
/*
** Return the current CRC value.
*/
return(Value());
}
================================================
FILE: CODE/CRC.H
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/CRC.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 : CRC.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 03/02/96 *
* *
* Last Update : March 2, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef CRC_H
#define CRC_H
#include
/*
** The "bool" integral type was defined by the C++ comittee 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 CRC engine class. It will process submitted data and generate a CRC from it.
** Well, actually, the value returned is not a true CRC. However, it shares the same strength
** characteristic and is faster to generate than the traditional CRC. This object is treated like
** a method class. If it is called as a function (using the function operator), it will return
** the CRC value. There are other function operators to submit data for processing.
*/
class CRCEngine {
public:
// Constructor for CRC engine (it can have an override initial CRC value).
CRCEngine(long initial=0) : CRC(initial), Index(0) {
StagingBuffer.Composite = 0;
};
// Fetches CRC value.
long operator() (void) const {return(Value());};
// Submits one byte sized datum to the CRC accumulator.
void operator() (char datum);
// Submits an arbitrary buffer to the CRC accumulator.
long operator() (void const * buffer, int length);
// Implicit conversion operator so this object appears like a 'long integer'.
operator long(void) const {return(Value());};
protected:
bool Buffer_Needs_Data(void) const {
return(Index != 0);
};
long Value(void) const {
if (Buffer_Needs_Data()) {
return(_lrotl(CRC, 1) + StagingBuffer.Composite);
}
return(CRC);
};
/*
** Current accumulator of the CRC value. This value doesn't take into
** consideration any pending data in the staging buffer.
*/
long CRC;
/*
** This is the sub index into the staging buffer used to keep track of
** partial data blocks as they are submitted to the CRC engine.
*/
int Index;
/*
** This is the buffer that holds the incoming partial data. When the buffer
** is filled, the value is transformed into the CRC and the buffer is flushed
** in preparation for additional data.
*/
union {
long Composite;
char Buffer[sizeof(long)];
} StagingBuffer;
};
#endif
================================================
FILE: CODE/CRCPIPE.CPP
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/CRCPIPE.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 : CRCPIPE.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 06/30/96 *
* *
* Last Update : July 3, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* CRCPipe::Result -- Fetches the current CRC of the data. *
* CRCPipe::Put -- Retrieves the data bytes specified and calculates CRC on it. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "crcpipe.h"
/***********************************************************************************************
* CRCPipe::Put -- Retrieves the data bytes specified and calculates CRC on it. *
* *
* This routine will fetch the number of bytes requested from the straw. The data is *
* not modified by this straw segment, but it is examined by the CRC engine in order to *
* keep an accurate CRC of the data that passes through this routine. *
* *
* INPUT: source -- Pointer to the buffer that will hold the data requested. *
* *
* length -- The number of bytes requested. *
* *
* OUTPUT: Returns with the actual number of bytes stored into the buffer. If this number is *
* less than the number requested, then this indicates that the data stream has been *
* exhausted. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/03/1996 JLB : Created. *
*=============================================================================================*/
int CRCPipe::Put(void const * source, int slen)
{
CRC(source, slen);
return(Pipe::Put(source, slen));
}
/***********************************************************************************************
* CRCPipe::Result -- Fetches the current CRC of the data. *
* *
* This routine will return the CRC of the data that has passed through the pipe up to *
* this time. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the CRC value. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/03/1996 JLB : Created. *
*=============================================================================================*/
long CRCPipe::Result(void) const
{
return(CRC());
}
================================================
FILE: CODE/CRCPIPE.H
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/CRCPIPE.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 : CRCPIPE.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 06/30/96 *
* *
* Last Update : June 30, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef CRCPIPE_H
#define CRCPIPE_H
#include "pipe.h"
#include "crc.h"
/*
** This class doesn't modify the data being piped through, but it does examine it and build
** a CRC value from the data.
*/
class CRCPipe : public Pipe
{
public:
CRCPipe(void) {}
virtual int Put(void const * source, int slen);
// Fetch the CRC value.
long Result(void) const;
protected:
CRCEngine CRC;
private:
CRCPipe(CRCPipe & rvalue);
CRCPipe & operator = (CRCPipe const & pipe);
};
#endif
================================================
FILE: CODE/CRCSTRAW.CPP
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/CRCSTRAW.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 : CRCSTRAW.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 07/02/96 *
* *
* Last Update : July 3, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* CRCStraw::Get -- Fetch the data requested and calculate CRC on it. *
* CRCStraw::Result -- Returns with the CRC of all data passed through the straw. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "crcstraw.h"
/***********************************************************************************************
* CRCStraw::Get -- Fetch the data requested and calculate CRC on it. *
* *
* This routine will fetch the number of bytes requested. The data will not be modified *
* by this straw segment, but the CRC engine will examine the data so as to keep an *
* accurate CRC value. *
* *
* INPUT: source -- Pointer to the buffer to hold the data requested. *
* *
* length -- The number of bytes requested. *
* *
* OUTPUT: Returns with the actual number of bytes stored in the buffer. If this number is *
* less than that requested, then this indicates that the data stream has been *
* exhausted. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/03/1996 JLB : Created. *
*=============================================================================================*/
int CRCStraw::Get(void * source, int slen)
{
if (source == NULL || slen < 1) {
return(0);
}
int counter = Straw::Get(source, slen);
CRC(source, counter);
return(counter);
}
/***********************************************************************************************
* CRCStraw::Result -- Returns with the CRC of all data passed through the straw. *
* *
* This routine will return the CRC value of the data that has passed through this straw *
* segment. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the CRC value of the data this straw segment has seen. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/03/1996 JLB : Created. *
*=============================================================================================*/
long CRCStraw::Result(void) const
{
return(CRC());
}
================================================
FILE: CODE/CRCSTRAW.H
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/CRCSTRAW.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 : CRCSTRAW.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 07/02/96 *
* *
* Last Update : July 2, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef CRCSTRAW_H
#define CRCSTRAW_H
#include "straw.h"
#include "crc.h"
/*
** This class will build a CRC value from the data stream that is drawn through this class.
** The data is not modified, but it is examined as it passes through.
*/
class CRCStraw : public Straw
{
public:
CRCStraw(void) {}
virtual int Get(void * source, int slen);
// Calculate and return the CRC value.
long Result(void) const;
protected:
CRCEngine CRC;
private:
CRCStraw(CRCStraw & rvalue);
CRCStraw & operator = (CRCStraw const & pipe);
};
#endif
================================================
FILE: CODE/CREDITS.CPP
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/CREDITS.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 : CREDITS.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : April 17, 1994 *
* *
* Last Update : March 13, 1995 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* CreditClass::AI -- Handles updating the credit display. *
* CreditClass::CreditClass -- Default constructor for the credit class object. *
* CreditClass::Graphic_Logic -- Handles the credit redraw logic. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
/***********************************************************************************************
* CreditClass::CreditClass -- Default constructor for the credit class object. *
* *
* This is the constructor for the credit class object. It merely sets the credit display *
* state to null. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 03/13/1995 JLB : Created. *
*=============================================================================================*/
CreditClass::CreditClass(void) :
Credits(0),
Current(0),
IsToRedraw(false),
IsUp(false),
IsAudible(false),
Countdown(0)
{
}
/***********************************************************************************************
* CreditClass::Graphic_Logic -- Handles the credit redraw logic. *
* *
* This routine should be called whenever the main game screen is to be updated. It will *
* check to see if the credit display should be redrawn. If so, it will redraw it. *
* *
* INPUT: forced -- Should the credit display be redrawn regardless of whether the redraw *
* flag is set? This is typically the case when the screen needs to be *
* redrawn from scratch. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 03/13/1995 JLB : Created. *
*=============================================================================================*/
//#define XX (320-120)
//#define WW 50
void CreditClass::Graphic_Logic(bool forced)
{
if (forced || IsToRedraw) {
BStart(BENCH_TABS);
int xx = SeenBuff.Get_Width() - (120 * RESFACTOR);
/*
** Adjust the credits display to be above the sidebar for 640x400
*/
#ifdef WIN32
xx += 80 * RESFACTOR;
#endif
/*
** Play a sound effect when the money display changes, but only if a sound
** effect was requested.
*/
if (IsAudible) {
if (IsUp) {
Sound_Effect(VOC_MONEY_UP, fixed(1, 2));
} else {
Sound_Effect(VOC_MONEY_DOWN, fixed(1, 2));
}
}
/*
** Display the new current value.
*/
TabClass::Draw_Credits_Tab();
#ifdef WIN32
Fancy_Text_Print("%ld", xx, 0, &MetalScheme, TBLACK, TPF_METAL12 | TPF_CENTER | TPF_USE_GRAD_PAL, Current);
#else
Fancy_Text_Print("%ld", xx, 0, &ColorRemaps[PCOLOR_GREY], TBLACK, TPF_NOSHADOW|TPF_6PT_GRAD|TPF_CENTER|TPF_BRIGHT_COLOR, Current);
#endif //WIN32
if (Scen.MissionTimer.Is_Active()) {
long secs = Scen.MissionTimer / TICKS_PER_SECOND;
long mins = secs / 60;
long hours = mins / 60;
secs %= 60;
mins %= 60;
/*
** Speak mission timer reminders.
*/
VoxType vox = VOX_NONE;
if (Scen.MissionTimer == (1 * TICKS_PER_MINUTE)) vox = VOX_TIME_1;
if (Scen.MissionTimer == (2 * TICKS_PER_MINUTE)) vox = VOX_TIME_2;
if (Scen.MissionTimer == (3 * TICKS_PER_MINUTE)) vox = VOX_TIME_3;
if (Scen.MissionTimer == (4 * TICKS_PER_MINUTE)) vox = VOX_TIME_4;
if (Scen.MissionTimer == (5 * TICKS_PER_MINUTE)) vox = VOX_TIME_5;
if (Scen.MissionTimer == (10 * TICKS_PER_MINUTE)) vox = VOX_TIME_10;
if (Scen.MissionTimer == (20 * TICKS_PER_MINUTE)) vox = VOX_TIME_20;
if (Scen.MissionTimer == (30 * TICKS_PER_MINUTE)) vox = VOX_TIME_30;
if (Scen.MissionTimer == (40 * TICKS_PER_MINUTE)) vox = VOX_TIME_40;
if (vox != VOX_NONE) {
Speak(vox);
Map.FlasherTimer = 7;
}
#ifdef WIN32
if (hours) {
Fancy_Text_Print(TXT_TIME_FORMAT_HOURS, 200 * RESFACTOR, 0, &MetalScheme, TBLACK, TPF_METAL12|TPF_CENTER|TPF_USE_GRAD_PAL, hours, mins, secs);
} else {
Fancy_Text_Print(TXT_TIME_FORMAT_NO_HOURS, 200 * RESFACTOR, 0, &MetalScheme, TBLACK, TPF_METAL12|TPF_CENTER|TPF_USE_GRAD_PAL, mins, secs);
}
#else
if (hours) {
Fancy_Text_Print("%02d:%02d:%02d", 120 * RESFACTOR, 0, &ColorRemaps[PCOLOR_GREY], TBLACK, TPF_NOSHADOW|TPF_6PT_GRAD|TPF_CENTER|TPF_BRIGHT_COLOR, hours, mins, secs);
} else {
Fancy_Text_Print("%02d:%02d", 120 * RESFACTOR, 0, &ColorRemaps[PCOLOR_GREY], TBLACK, TPF_NOSHADOW|TPF_6PT_GRAD|TPF_CENTER|TPF_BRIGHT_COLOR, mins, secs);
}
#endif //WIN32
}
IsToRedraw = false;
IsAudible = false;
BEnd(BENCH_TABS);
}
}
/***********************************************************************************************
* CreditClass::AI -- Handles updating the credit display. *
* *
* This routine handles the logic that controls the rate of credit change in the credit *
* display. It doesn't actually redraw the credit display, but will flag it to be redrawn *
* if it detects that a change is to occur. *
* *
* INPUT: forced -- Should the credit display immediately reflect the current credit *
* total for the player? This is usually desired when initially loading *
* a scenario or saved game. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 03/13/1995 JLB : Created. *
*=============================================================================================*/
void CreditClass::AI(bool forced)
{
static int _last = 0;
if (!forced && Frame == _last) return;
_last = Frame;
Credits = PlayerPtr->Available_Money();
/*
** Make sure that the credit counter doesn't drop below zero.
*/
Credits = max(Credits, 0L);
if (Scen.MissionTimer.Is_Active() || Scen.MissionTimer) {
IsToRedraw = true;
Map.Flag_To_Redraw(false);
}
if (Current == Credits) return;
if (forced) {
IsAudible = false;
Current = Credits;
} else {
if (Countdown) Countdown--;
if (Countdown) return;
/*
** Determine the amount to change the display toward the
** desired value.
*/
int adder = Credits - Current;
if (adder > 0) {
Countdown = 1;
} else {
Countdown = 3;
}
adder = ABS(adder);
adder >>= 3;
// adder >>= 4;
// adder >>= 5;
adder = Bound(adder, 1, 71+72);
if (Current > Credits) adder = -adder;
Current += adder;
if (Current-adder != Current) {
IsAudible = true;
IsUp = (adder > 0);
}
}
IsToRedraw = true;
Map.Flag_To_Redraw(false);
}
================================================
FILE: CODE/CREDITS.H
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/CREDITS.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 : CREDIT.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : April 19, 1994 *
* *
* Last Update : April 19, 1994 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef CREDITS_H
#define CREDITS_H
/****************************************************************************
** The animating credit counter display is controlled by this class.
*/
class CreditClass {
public:
long Credits; // Value of credits trying to update display to.
/*---------------------------------------------------------------------
** Constructors, Destructors, and overloaded operators.
*/
CreditClass(void);
CreditClass(NoInitClass const & ) {};
/*---------------------------------------------------------------------
** Member function prototypes.
*/
void Update(bool forced=false, bool redraw=false);
void Graphic_Logic(bool forced=false);
void AI(bool forced=false);
long Current; // Credit value currently displayed.
unsigned IsToRedraw:1;
unsigned IsUp:1;
unsigned IsAudible:1;
private:
int Countdown; // Delay between ticks.
};
#endif
================================================
FILE: CODE/CREW.CPP
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/CREW.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 : CREW.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : April 23, 1994 *
* *
* Last Update : April 23, 1994 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
================================================
FILE: CODE/CREW.H
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/CREW.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 : CREW.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : April 23, 1994 *
* *
* Last Update : April 23, 1994 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef CREW_H
#define CREW_H
/****************************************************************************
** This class handles the basic crew logic. This includes hero tracking,
** crew bail-out, and attached object logic.
*/
class CrewClass
{
public:
/*
** This keeps track of the number of "kills" the unit as accumulated.
** When it reaches a certain point, the unit improves.
*/
unsigned short Kills;
/*
** Constructors, Destructors, and overloaded operators.
*/
CrewClass(void) : Kills(0) {};
CrewClass(NoInitClass const &) {};
~CrewClass(void) {};
int Made_A_Kill(void) {
Kills++;
return(Kills);
};
private:
};
#endif
================================================
FILE: CODE/CSTRAW.CPP
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/CSTRAW.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 : CSTRAW.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 11/10/96 *
* *
* Last Update : November 10, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* CacheStraw::Get -- Fetch data from the data source. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "cstraw.h"
#include
/***********************************************************************************************
* CacheStraw::Get -- Fetch data from the data source. *
* *
* This will supply the data quantity requested. It performs a regulating influence on the *
* data requests passed through it. The data is requested from the next straw in the *
* chain such that the data stream is requested in chunks. This serves to lessen the *
* impact of multiple small data requests. *
* *
* INPUT: source -- Pointer to the buffer to hold the data. *
* *
* slen -- The number of data bytes requested. *
* *
* OUTPUT: Returns with the number of data bytes stored into the buffer specified. If this *
* number is less than that requested, it indicates that the data source has been *
* exhausted. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/10/1996 JLB : Created. *
*=============================================================================================*/
int CacheStraw::Get(void * source, int slen)
{
int total = 0;
if (Is_Valid() && source != NULL && slen > 0) {
/*
** Keep processing the data request until there is no more data to supply or the request
** has been fulfilled.
*/
while (slen > 0) {
/*
** First try to fetch the data from data previously loaded into the buffer.
*/
if (Length > 0) {
int tocopy = (Length < slen) ? Length : slen;
memmove(source, ((char *)BufferPtr.Get_Buffer()) + Index, tocopy);
slen -= tocopy;
Index += tocopy;
total += tocopy;
Length -= tocopy;
source = (char*)source + tocopy;
}
if (slen == 0) break;
/*
** Since there is more to be fulfilled yet the holding buffer is empty,
** refill the buffer with a fresh block of data from the source.
*/
Length = Straw::Get(BufferPtr, BufferPtr.Get_Size());
Index = 0;
if (Length == 0) break;
}
}
return(total);
}
================================================
FILE: CODE/CSTRAW.H
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/CSTRAW.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 : CSTRAW.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 11/10/96 *
* *
* Last Update : November 10, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef CSTRAW_H
#define CSTRAW_H
#include "straw.h"
#include "buff.h"
/*
** This class handles transfer of data by perform regulated requests for data from the next
** class in the chain. It performs no translation on the data. By using this segment in a
** straw chain, data throughput can be regulated. This can yield great performance increases
** when dealing with a file source.
*/
class CacheStraw : public Straw
{
public:
CacheStraw(Buffer const & buffer) : BufferPtr(buffer), Index(0), Length(0) {}
CacheStraw(int length=4096) : BufferPtr(length), Index(0), Length(0) {}
virtual int Get(void * source, int slen);
private:
Buffer BufferPtr;
int Index;
int Length;
bool Is_Valid(void) {return(BufferPtr.Is_Valid());}
CacheStraw(CacheStraw & rvalue);
CacheStraw & operator = (CacheStraw const & pipe);
};
#endif
================================================
FILE: CODE/CWSTUB.C
================================================
/*
** 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 .
*/
#include
#include
#include
#include
#include
char *dos4g_path()
{
static char *paths_to_check[] = {
"DOS4GPATH",
"PATH"
};
static char fullpath[80];
char *dos4gpath;
int i;
/* If DOS4GPATH points to an executable file name, don't bother
searching any paths for DOS4GW.EXE.
*/
if (dos4gpath = getenv("DOS4GPATH")) {
strlwr(strcpy(fullpath, dos4gpath));
if (strstr(fullpath, ".exe")) {
return(fullpath);
}
}
for( i = 0; i < sizeof(paths_to_check) / sizeof(paths_to_check[0]); i++ ) {
_searchenv("dos4gw.exe", paths_to_check[i], fullpath);
if (fullpath[0]) {
return( &fullpath );
}
}
return("dos4gw.exe");
}
main( int argc, char *argv[] )
{
char *av[4];
auto char cmdline[128];
av[0] = dos4g_path(); /* Locate the DOS/4GW loader */
av[1] = argv[0]; /* name of executable to run */
av[2] = getcmd(cmdline); /* command line */
av[3] = NULL; /* end of list */
#ifdef VMM
putenv("DOS4GVM=MINMEM#2000 MAXMEM#16000 SWAPMIN#4096 SWAPINC#1024 VIRTUALSIZE#10000 SWAPFILE#CONQUER.SWP DELETESWAP @CONQUER.VMC");
#endif
#ifdef QUIET
putenv("DOS4G=QUIET"); /* disables DOS/4GW Copyright banner */
#endif
execvp(av[0], av);
perror(av[0]);
exit(1); /* indicate error */
}
================================================
FILE: CODE/DDE.CPP
================================================
/*
** 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 .
*/
/***************************************************************************
** 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 : Dynamic Data Encapsulation *
* *
* File Name : DDE.CPP *
* *
* Programmer : Steve Wetherill *
* *
* Start Date : June 1, 1996 *
* *
* Last Update : June 8, 1996 [SW] *
* *
*-------------------------------------------------------------------------*
* Functions: *
* Instance_Class::InstanceClass -- class constructor *
* Instance_Class::InstanceClass -- class destructor *
* Instance_Class::Enable_Callback -- enables local processing of pokes *
* Instance_Class::Register_Servers -- registers a local DDE DNS service *
* Instance_Class::Cleanup_App -- currently does nothing *
* Instance_Class::Test_Server_Running -- does a trial connect to remote *
* Instance_Class::Open_Poke_Connection -- pokes some data to server *
* Instance_Class::Close_Poke_Connectionp -- closes connection to remote *
* Instance_Class::Poke_Server -- sends a chunk of data to remote *
* Instance_Class::dde_callback -- processes DDE transactions *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifdef WIN32
#include
#include "dde.h"
/***************************************************************************
* These are static members of Instance_Class
*=========================================================================*/
static DWORD Instance_Class::id_inst; // instance identifier set by DdeInitialize
static BOOL Instance_Class::process_pokes; // controls response to pokes
static char Instance_Class::ascii_name[32]; // name of server
static BOOL CALLBACK (*Instance_Class::callback) (
LPBYTE pointer, // pointer to received data
long length // length of received data or advisory flag
) = NULL;
/***************************************************************************
* Instance_Class::InstanceClass -- class constructor *
* *
* INPUT: *
* name1 null terminated ASCII client name *
* name1 null terminated ASCII server name *
* *
* OUTPUT: *
* dde_error = TRUE if error occurs when initializing DDE *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 6/1/1996 SW : Created. *
*=========================================================================*/
Instance_Class::Instance_Class( LPSTR name1, LPSTR name2 )
{
dde_error = FALSE; // no errors
process_pokes = FALSE; // disable pokes in callback
id_inst = 0; // set to 0 for first time through
conv_handle = 0; // conversation handle reset
lstrcpy( ascii_name, name1 ); // keep a record of ASCII name
if ( DdeInitialize(
(LPDWORD) &id_inst, // instance identifier
dde_callback,
APPCLASS_STANDARD | // filter server messages
CBF_FAIL_SELFCONNECTIONS, // prevent from connecting with self
0) != DMLERR_NO_ERROR) { // reserved
dde_error = TRUE; // flag an error
}
local_name = DdeCreateStringHandle(
id_inst, // instance identifier
name1, // string to register
CP_WINANSI); // Windows ANSI code page
remote_name = DdeCreateStringHandle(
id_inst, // instance identifier
name2, // string to register
CP_WINANSI); // Windows ANSI code page
poke_topic = DdeCreateStringHandle(
id_inst, // instance identifier
"POKE TOPIC", // System topic
CP_WINANSI); // Windows ANSI code page
poke_item = DdeCreateStringHandle(
id_inst, // instance identifier
"POKE ITEM", // System topic
CP_WINANSI); // Windows ANSI code page
system_topic = DdeCreateStringHandle(
id_inst, // instance identifier
SZDDESYS_TOPIC, // System topic
CP_WINANSI); // Windows ANSI code page
}
/***************************************************************************
* Instance_Class::~Instance_Class -- class destructor *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 6/1/1996 SW : Created. *
*=========================================================================*/
Instance_Class::~Instance_Class()
{
DdeUninitialize( id_inst );
}
/***************************************************************************
* Instance_Class::Enable_Callback -- enables user callback *
* *
* INPUT: *
* TRUE = enable poke processing *
* FALSE = disable poke processing *
* *
* OUTPUT: *
* echos the input *
* *
* WARNINGS: *
* user callback must be explicitly enabled. Disbabled by default. *
* *
* HISTORY: *
* 6/1/1996 SW : Created. *
*=========================================================================*/
BOOL Instance_Class::Enable_Callback( BOOL flag ) // enable or disable callback
{
return (process_pokes = flag);
}
/***************************************************************************
* Instance_Class::Register_Server -- registers a local DDE DNS service *
* *
* INPUT: *
* BOOL CALLBACK ( *callback_fnc) ( LPBYTE, DWORD) = user poke callbacl *
* *
* OUTPUT: *
* TRUE == success *
* FALSE == failed *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 6/1/1996 SW : Created. *
*=========================================================================*/
BOOL Instance_Class::Register_Server( BOOL CALLBACK ( *callback_fnc) (LPBYTE, long) )
{
if (DdeNameService( id_inst, local_name, 0L, DNS_REGISTER ) != 0L) {
callback = callback_fnc;
return ( TRUE );
} else {
return ( FALSE );
}
}
/***************************************************************************
* Instance_Class::Test_Server_Running -- does a trial connect to remote *
* *
* INPUT: *
* name = HSZ string handle of server name. *
* *
* OUTPUT: *
* TRUE == successfully connected to remote *
* FALSE == failed to connect *
* *
* WARNINGS: *
* - Can be called for local or remote server but of course will *
* fail if a called for local and local server is not "up". *
* - Disconects before exiting. *
* *
* HISTORY: *
* 6/1/1996 SW : Created. *
*=========================================================================*/
BOOL Instance_Class::Test_Server_Running( HSZ name )
{
if( Open_Poke_Connection( name ) == TRUE) {
Close_Poke_Connection();
return( TRUE );
} else {
return( FALSE );
}
}
/***************************************************************************
* Instance_Class::Open_Poke_Connection -- open a connection to server *
* *
* INPUT: *
* name = HSZ server name. *
* *
* OUTPUT: *
* TRUE == successfully opened connection *
* FALSE == failed to connect *
* *
* WARNINGS: *
* Can be called for local or remote server but of course will *
* fail if a called for local and local server is not "up". *
* *
* HISTORY: *
* 6/1/1996 SW : Created. *
*=========================================================================*/
BOOL Instance_Class::Open_Poke_Connection( HSZ name )
{
conv_handle = DdeConnect(
id_inst, // instance identifier
name, // service name string handle
poke_topic, // topic string handle
(PCONVCONTEXT) NULL);// use default context
if (conv_handle == NULL) {
return FALSE;
} else {
return TRUE;
}
}
/***************************************************************************
* Instance_Class::Close_Poke_Connection -- closes poke connection *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* TRUE == successfully closed connection *
* FALSE == failed to close connection for some reason *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 6/1/1996 SW : Created. *
*=========================================================================*/
BOOL Instance_Class::Close_Poke_Connection( void )
{
if( conv_handle ) {
HCONV temp_handle = conv_handle;
conv_handle = NULL;
return( DdeDisconnect( temp_handle ));
} else {
return( TRUE );
}
}
/***************************************************************************
* Instance_Class::Poke_Server -- pokes some data to server *
* *
* INPUT: *
* poke_data points to data to send to remote *
* poke_length length of buffer to send *
* *
* OUTPUT: *
* TRUE == successfully poked the data *
* FALSE == failed to connect *
* *
* WARNINGS: *
* has a 3 second timeout (change POKE_TIMEOUT, in milliseconds) *
* *
* HISTORY: *
* 6/1/1996 SW : Created. *
*=========================================================================*/
#define POKE_TIMEOUT 60*1000 // 60 sec timeout
BOOL Instance_Class::Poke_Server( LPBYTE poke_data, DWORD poke_length )
{
if( DdeClientTransaction(
poke_data, // address of data to pass to server
poke_length, // length of data
conv_handle, // handle of conversation
poke_topic, // handle of item name string
CF_TEXT, // no special clipboard data format
XTYP_POKE, // transaction type
POKE_TIMEOUT, // time-out duration (millisecs)
(LPDWORD) NULL // address of transaction result (don't check)
) == 0) {
return( FALSE);
} else {
return( TRUE );
}
}
/***************************************************************************
* Instance_Class::dde_callback -- callback dde event handler *
* *
* INPUT: *
* dde_event transaction type *
* uFmt clipboard data format *
* hconv handle of the conversation *
* hsz1 handle of a string *
* hsz2 handle of a string *
* hdata handle of a global memory object *
* dwData1 transaction-specific data *
* dwData2 transaction-specific data *
* *
* OUTPUT: *
* context specific HDDEDATA object *
* *
* WARNINGS: *
* NOTE: declared as HDDEDATA CALLBACK which means PASCAL parameters *
* *
* HISTORY: *
* 6/1/1996 SW : Created. *
*=========================================================================*/
HDDEDATA CALLBACK Instance_Class::dde_callback(
UINT dde_event, // transaction type
UINT uFmt, // clipboard data format
HCONV , // handle of the conversation
HSZ hsz1, // handle of a string
HSZ hsz2, // handle of a string
HDDEDATA hdata, // handle of a global memory object
DWORD , // transaction-specific data
DWORD // transaction-specific data
)
{
if (!Instance_Class::callback){
return (HDDEDATA) NULL;
}
switch ( dde_event ) {
case XTYP_REGISTER:
case XTYP_UNREGISTER:
return (HDDEDATA) NULL;
case XTYP_ADVDATA:
return (HDDEDATA) DDE_FACK;
case XTYP_XACT_COMPLETE:
return (HDDEDATA) NULL;
case XTYP_DISCONNECT:
Instance_Class::callback( NULL, DDE_ADVISE_DISCONNECT);
return (HDDEDATA) NULL;
case XTYP_CONNECT: {
char buffer[32];
DdeQueryString (Instance_Class::id_inst, hsz2, buffer, sizeof (buffer), 0) ;
if (0 != strcmp (buffer, Instance_Class::ascii_name)) {
return (HDDEDATA) NULL;
}
DdeQueryString (Instance_Class::id_inst, hsz1, buffer, sizeof (buffer), 0) ;
if (0 != strcmp (buffer, "POKE TOPIC")) {
return (HDDEDATA) NULL;
}
Instance_Class::callback( NULL, DDE_ADVISE_CONNECT);
return (HDDEDATA) TRUE;
}
case XTYP_POKE:
if (Instance_Class::process_pokes == FALSE ) {
return (HDDEDATA) DDE_FNOTPROCESSED; // processing disabled
} else {
char buffer[32];
DdeQueryString (Instance_Class::id_inst, hsz1, buffer, sizeof (buffer), 0) ;
if (0 != strcmp (buffer, "POKE TOPIC")) {
return (HDDEDATA) DDE_FNOTPROCESSED;
} else if (uFmt == CF_TEXT) { // make sure it's CF_TEXT
BOOL processed;
BYTE FAR *pdata;
DWORD dw_length;
if ( (pdata = DdeAccessData( hdata, &dw_length)) == NULL ) {
return (HDDEDATA) DDE_FNOTPROCESSED;
}
processed = Instance_Class::callback((LPBYTE) pdata, dw_length);
DdeUnaccessData( hdata );
if (processed == TRUE) {
return (HDDEDATA) DDE_FACK;
} else {
return (HDDEDATA) NULL;
}
}
}
default:
return (HDDEDATA) NULL;
}
}
#endif //WIN32
================================================
FILE: CODE/DDE.H
================================================
/*
** 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 .
*/
/***************************************************************************
** 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 : Dynamic Data Encapsulation *
* *
* File Name : DDE.H *
* *
* Programmer : Steve Wetherill *
* *
* Start Date : June 1, 1996 *
* *
* Last Update : June 8, 1996 [SW] *
* *
*-------------------------------------------------------------------------*
* *
* This is the DDE (Instance_Class) which provides a simple CLIENT/SERVER *
* DDE model for data transactions between Windows applications. *
* This is a fairly naieve implementation allowing only one client/server *
* per Instance_Class object. *
* *
* Typical uses for this class are: *
* *
* i. Robust verification of whether an application is running *
* ii. Data transfer between applications *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
***************************** Class defines *****************************
*/
#ifndef __DDE_H
#define __DDE_H
#define DDE_ADVISE_CONNECT -1 // advisory "client has connected"
#define DDE_ADVISE_DISCONNECT -2 // advisory "client has disconnected"
/*
***************************** Class Declaration *****************************
*/
class Instance_Class {
/*
---------------------------- Public Interface ----------------------------
*/
public:
/*.....................................................................
Constructor:
- takes null terminated ASCII strings names for client and server
.....................................................................*/
Instance_Class( // constructor
LPSTR, // null terminated local sever name string
LPSTR // null terminated remote server name string
);
/*.....................................................................
Destructor:
.....................................................................*/
~Instance_Class(void); // the destructor
/*.....................................................................
Send data routine:
- sends an unsolicited packet of data to the remote server
.....................................................................*/
BOOL Poke_Server( LPBYTE, DWORD);
/*.....................................................................
Send data routine:
- sets up DNS for the server and registers a user callback to handle
incoming data
.....................................................................*/
BOOL Register_Server( BOOL CALLBACK (*)(LPBYTE, long));
/*.....................................................................
Does a trial connect to the remote server.
- used to determine whether server is alive or not (and thus running)
.....................................................................*/
BOOL Test_Server_Running( HSZ );
/*.....................................................................
Enables user callback (disabled by default)
.....................................................................*/
BOOL Enable_Callback( BOOL ); // enable or disable callback
/*.....................................................................
Open a connection for sending data to remote server
.....................................................................*/
BOOL Open_Poke_Connection( HSZ );
/*.....................................................................
Close connection with remote server
.....................................................................*/
BOOL Close_Poke_Connection( void );
//
// static members
//
/*.....................................................................
User callback - called upon receipt of incoming data (static member!)
.....................................................................*/
static BOOL CALLBACK (*callback) (
LPBYTE pointer, // pointer to received data
long length // if >0 length of received data
// if <0
// -1 == client connect detected
// -2 == client disconnect detected
);
/*.....................................................................
DDE callback, called when DDEML has an event for us
.....................................................................*/
static HDDEDATA CALLBACK dde_callback(
UINT uType, // transaction type
UINT uFmt, // clipboard data format
HCONV hconv, // handle of the conversation
HSZ hsz1, // handle of a string
HSZ hsz2, // handle of a string
HDDEDATA hdata, // handle of a global memory object
DWORD dwData1, // transaction-specific data
DWORD dwData2 // transaction-specific data
);
HANDLE instance; // this application's instance
HWND hwnd; // valid window handle
/*.....................................................................
member variables
.....................................................................*/
static DWORD id_inst; // instance identifier set by DdeInitialize
static BOOL process_pokes; // controls response to pokes
static char ascii_name[32]; // name of server
//
// non-static member variables
//
HSZ remote_name; // string handle for remote server name
HSZ local_name; // string handle for local server name
HSZ system_topic; // string handle for the "system" topic
HSZ poke_topic; // string handle for poking data to server topic
HSZ poke_item; // string handle for poking data to server item
HCONV conv_handle; // conversation handle
BOOL dde_error; // error flag
};
#endif
================================================
FILE: CODE/DEBUG.CPP
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/DEBUG.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 : DEBUG.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : September 10, 1993 *
* *
* Last Update : July 18, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* Self_Regulate -- Regulates the logic timer to result in smooth animation. *
* Debug_Key -- Debug mode keyboard processing. *
* Bench_Time -- Convert benchmark timer into descriptive string. *
* Benchmarks -- Display the performance tracking benchmarks. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
#include "vortex.h"
#include
#ifdef CHEAT_KEYS
static CDTimerClass DebugTimer;
int VortexFrame = -1;
/***********************************************************************************************
* Debug_Key -- Debug mode keyboard processing. *
* *
* If debugging is enabled, then this routine will be called for every keystroke that the *
* game doesn't recognize. These extra keys usually perform some debugging function. *
* *
* INPUT: input -- The key code that was pressed. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 10/07/1992 JLB : Created. *
*=============================================================================================*/
void Debug_Key(unsigned input)
{
static int map_x = -1;
static int map_y = -1;
static int map_width = -1;
static int map_height = -1;
if (!input || input & KN_BUTTON) return;
/*
** Processing of normal keystrokes.
*/
if (Debug_Flag) {
switch (input) {
case KN_BACKSPACE:
if (ChronalVortex.Is_Active()) {
ChronalVortex.Disappear();
} else {
int xxxx = Get_Mouse_X() + Map.TacPixelX;
int yyyy = Get_Mouse_Y() + Map.TacPixelY;
CELL cell = Map.DisplayClass::Click_Cell_Calc(xxxx,yyyy);
ChronalVortex.Appear ( Cell_Coord (cell) );
}
break;
#ifdef WIN32
case KN_J:
Debug_MotionCapture = true;
break;
#ifdef OBSOLETE
case KN_K:
/*
** time to create a screen shot using the PCX code (if it works)
*/
if (!Debug_MotionCapture) {
GraphicBufferClass temp_page( SeenBuff.Get_Width(),
SeenBuff.Get_Height(),
NULL,
SeenBuff.Get_Width() * SeenBuff.Get_Height());
CDFileClass file;
char filename[30];
SeenBuff.Blit(temp_page);
for (int lp = 0; lp < 99; lp ++) {
sprintf(filename, "scrsht%02d.pcx", lp);
file.Set_Name(filename);
if (!file.Is_Available()) break;
}
file.Cache(200000);
Write_PCX_File(file, temp_page, & GamePalette);
Sound_Effect(VOC_BEEP);
}
break;
#endif
#endif
case KN_P:
{
for (SpecialWeaponType spc = SPC_FIRST; spc < SPC_COUNT; spc++) {
PlayerPtr->SuperWeapon[spc].Enable(true, true);
PlayerPtr->SuperWeapon[spc].Forced_Charge(true);
Map.Add(RTTI_SPECIAL, spc);
Map.Column[1].Flag_To_Redraw();
}
}
break;
case KN_I:
{
Map.Flash_Power();
Map.Flash_Money();
}
break;
case KN_O:
{
AircraftClass * air = new AircraftClass(AIRCRAFT_HIND, PlayerPtr->Class->House);
if (air) {
air->Height = 0;
air->Unlimbo(Map.Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y()), DIR_N);
}
}
break;
case KN_B:
{
AircraftClass * air = new AircraftClass(AIRCRAFT_LONGBOW, PlayerPtr->Class->House);
if (air) {
air->Height = 0;
air->Unlimbo(Map.Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y()), DIR_N);
}
}
break;
case KN_GRAVE:
{
WarheadType warhead = Random_Pick(WARHEAD_HE, WARHEAD_FIRE);
COORDINATE coord = Map.Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y());
int damage = 1000;
new AnimClass(Combat_Anim(damage, warhead, Map[coord].Land_Type()), coord);
Explosion_Damage(coord, damage, NULL, warhead);
}
break;
case KN_C:
Debug_Cheat = (Debug_Cheat == false);
PlayerPtr->IsRecalcNeeded = true;
/*
** This placement might affect any prerequisite requirements for construction
** lists. Update the buildable options accordingly.
*/
if (!ScenarioInit) {
Map.Recalc();
for (int index = 0; index < Buildings.Count(); index++) {
Buildings.Ptr(index)->Update_Buildables();
}
}
break;
case (int)KN_Z|(int)KN_ALT_BIT:
if (map_x == -1) {
map_x = Map.MapCellX;
map_y = Map.MapCellY;
map_width = Map.MapCellWidth;
map_height = Map.MapCellHeight;
Map.MapCellX = 1;
Map.MapCellY = 1;
Map.MapCellWidth = MAP_CELL_W-2;
Map.MapCellHeight = MAP_CELL_H-2;
} else {
Map.MapCellX = map_x;
Map.MapCellY = map_y;
Map.MapCellWidth = map_width;
Map.MapCellHeight = map_height;
map_x = -1;
map_y = -1;
map_width = -1;
map_height = -1;
}
break;
case KN_M:
if (Debug_Flag) {
if (MonoClass::Is_Enabled()) {
MonoClass::Disable();
} else {
MonoClass::Enable();
}
}
break;
case (int)KN_W|(int)KN_ALT_BIT:
PlayerPtr->Flag_To_Win();
break;
case (int)KN_L|(int)KN_ALT_BIT:
PlayerPtr->Flag_To_Lose();
break;
case KN_DELETE:
if (CurrentObject.Count()) {
Map.Recalc();
//CurrentObject[0]->Detach_All();
if (CurrentObject[0]->What_Am_I() == RTTI_BUILDING) {
((BuildingClass *)CurrentObject[0])->Sell_Back(1);
} else {
ObjectClass * object = CurrentObject[0];
object->Unselect();
object->Limbo();
delete object;
}
}
break;
case (int)KN_DELETE|(int)KN_SHIFT_BIT:
if (CurrentObject.Count()) {
Map.Recalc();
int damage = 50;
CurrentObject[0]->Take_Damage(damage, 0, WARHEAD_SA);
}
break;
case KN_INSERT:
if (CurrentObject.Count()) {
Map.PendingObject = &CurrentObject[0]->Class_Of();
if (Map.PendingObject) {
Map.PendingHouse = CurrentObject[0]->Owner();
Map.PendingObjectPtr = Map.PendingObject->Create_One_Of(HouseClass::As_Pointer(Map.PendingHouse));
if (Map.PendingObjectPtr) {
Map.Set_Cursor_Pos();
Map.Set_Cursor_Shape(Map.PendingObject->Occupy_List());
}
}
}
break;
case KN_LBRACKET:
case KN_F11:
if (MonoPage == DMONO_FIRST) {
MonoPage = DMonoType(DMONO_COUNT-1);
} else {
MonoPage = DMonoType(MonoPage - 1);
}
DebugTimer = 0;
break;
case KN_RBRACKET:
case KN_F12:
MonoPage = DMonoType(MonoPage + 1);
if (MonoPage == DMONO_COUNT) {
MonoPage = DMONO_FIRST;
}
DebugTimer = 0;
break;
case KN_V:
case KN_F3:
Debug_Icon = (Debug_Icon == false);
Map.Flag_To_Redraw(true);
break;
/*
** Reveal entire map to player.
*/
// case KN_F4:
// if (Session.Type == GAME_NORMAL) {
// Debug_Unshroud = (Debug_Unshroud == false);
// Map.Flag_To_Redraw(true);
// }
// break;
/*
** Shows sight and fire range in the form of circles emanating from the currently
** selected unit. The white circle is for sight range, the red circle is for
** fire range.
*/
case KN_F7:
if (CurrentObject.Count() && CurrentObject[0]->Is_Techno()) {
TechnoTypeClass const & ttype = (TechnoTypeClass const &)CurrentObject[0]->Class_Of();
int sight = ((int)ttype.SightRange)<<8;
int weapon = 0;
if (ttype.PrimaryWeapon != NULL) weapon = ttype.PrimaryWeapon->Range;
Set_Logic_Page(SeenBuff);
COORDINATE center = CurrentObject[0]->Center_Coord();
COORDINATE center2 = CurrentObject[0]->Fire_Coord(0);
for (int r = 0; r < 255; r += 10) {
int x,y,x1,y1;
DirType r1 = (DirType)r;
DirType r2 = (DirType)((r+10) & 0xFF);
if (Map.Coord_To_Pixel(Coord_Move(center, r1, sight), x, y)) {
Map.Coord_To_Pixel(Coord_Move(center, r2, sight), x1, y1);
LogicPage->Draw_Line(x, y+8, x1, y1+8, WHITE);
}
if (Map.Coord_To_Pixel(Coord_Move(center2, r1, weapon), x, y)) {
Map.Coord_To_Pixel(Coord_Move(center2, r2, weapon), x1, y1);
LogicPage->Draw_Line(x, y+8, x1, y1+8, RED);
}
}
}
break;
case ((int)KN_F4 | (int)KN_CTRL_BIT):
Debug_Unshroud = (Debug_Unshroud == false);
Map.Flag_To_Redraw(true);
break;
default:
break;
}
}
}
/***********************************************************************************************
* Bench_Time -- Convert benchmark timer into descriptive string. *
* *
* This routine will take the values of the benchmark timer specified and build a string *
* that displays the average time each event consumed as well as the ranking of how much *
* time that event took (total) during the tracking duration (one second?). *
* *
* INPUT: btype -- The benchmark to convert to a descriptive string. *
* *
* OUTPUT: Returns with a pointer to the descriptive string of the benchmark specified. *
* *
* WARNINGS: The value returned is a pointer to a static buffer. As such, it is only valid *
* until the next time that this routine is called. *
* *
* HISTORY: *
* 07/18/1996 JLB : Created. *
*=============================================================================================*/
static char const * Bench_Time(BenchType btype)
{
static char buffer[32];
int rootcount = Benches[BENCH_GAME_FRAME].Count();
if (rootcount == 0) rootcount = 1;
int roottime = Benches[BENCH_GAME_FRAME].Value();
int count = Benches[btype].Count();
int time = Benches[btype].Value();
if (count > 0 && count * time > roottime * rootcount) time = roottime / count;
int percent = 0;
if (roottime != 0 && rootcount != 0) {
percent = ((count * time) * 99) / (roottime * rootcount);
}
if (percent > 99) percent = 99;
sprintf(buffer, "%-2d%% %7d", percent, time);
return(buffer);
}
/***********************************************************************************************
* Benchmarks -- Display the performance tracking benchmarks. *
* *
* This will display the benchmarks for the various processes that are being tracked. The *
* display will indicate the fraction that each process is consuming out of the entire *
* process time as well as the time consumed by each individual event. The total fraction *
* is useful for determing what should be optimized. The individual time is useful for *
* guaging the effectiveness of optimization changes. *
* *
* INPUT: mono -- Pointer to the monochrome screen that the display will use. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/18/1996 JLB : Created. *
*=============================================================================================*/
static void Benchmarks(MonoClass * mono)
{
static bool _first = true;
if (_first) {
_first = false;
mono->Clear();
mono->Set_Cursor(0, 0);
mono->Print(Text_String(TXT_DEBUG_PERFORMANCE));
if (Benches == NULL) {
mono->Set_Cursor(20, 15);
mono->Printf(TXT_NO_PENTIUM);
}
}
if (Benches != NULL) {
mono->Set_Cursor(1, 2);mono->Printf("%s", Bench_Time(BENCH_FINDPATH));
mono->Set_Cursor(1, 4);mono->Printf("%s", Bench_Time(BENCH_GREATEST_THREAT));
mono->Set_Cursor(1, 6);mono->Printf("%s", Bench_Time(BENCH_AI));
mono->Set_Cursor(1, 8);mono->Printf("%s", Bench_Time(BENCH_PCP));
mono->Set_Cursor(1, 10);mono->Printf("%s", Bench_Time(BENCH_EVAL_OBJECT));
mono->Set_Cursor(1, 12);mono->Printf("%s", Bench_Time(BENCH_EVAL_CELL));
mono->Set_Cursor(1, 14);mono->Printf("%s", Bench_Time(BENCH_EVAL_WALL));
mono->Set_Cursor(1, 16);mono->Printf("%s", Bench_Time(BENCH_MISSION));
mono->Set_Cursor(14, 2);mono->Printf("%s", Bench_Time(BENCH_CELL));
mono->Set_Cursor(14, 4);mono->Printf("%s", Bench_Time(BENCH_OBJECTS));
mono->Set_Cursor(14, 6);mono->Printf("%s", Bench_Time(BENCH_ANIMS));
mono->Set_Cursor(27, 2);mono->Printf("%s", Bench_Time(BENCH_PALETTE));
mono->Set_Cursor(40, 2);mono->Printf("%s", Bench_Time(BENCH_GSCREEN_RENDER));
mono->Set_Cursor(40, 4);mono->Printf("%s", Bench_Time(BENCH_SIDEBAR));
mono->Set_Cursor(40, 6);mono->Printf("%s", Bench_Time(BENCH_RADAR));
mono->Set_Cursor(40, 8);mono->Printf("%s", Bench_Time(BENCH_TACTICAL));
mono->Set_Cursor(40, 10);mono->Printf("%s", Bench_Time(BENCH_POWER));
mono->Set_Cursor(40, 12);mono->Printf("%s", Bench_Time(BENCH_SHROUD));
mono->Set_Cursor(40, 14);mono->Printf("%s", Bench_Time(BENCH_TABS));
mono->Set_Cursor(40, 16);mono->Printf("%s", Bench_Time(BENCH_BLIT_DISPLAY));
mono->Set_Cursor(66, 2);mono->Printf("%7d", Benches[BENCH_RULES].Value());
mono->Set_Cursor(66, 4);mono->Printf("%7d", Benches[BENCH_SCENARIO].Value());
for (BenchType index = BENCH_FIRST; index < BENCH_COUNT; index++) {
if (index != BENCH_RULES && index != BENCH_SCENARIO) Benches[index].Reset();
}
}
}
/***********************************************************************************************
* Self_Regulate -- Regulates the logic timer to result in smooth animation *
* *
* The self regulation process checks the number of frames displayed *
* per second and from this determines the amount of time to devote *
* to internal logic processing. By adjusting the time allotted to *
* internal processing, smooth animation can be maintained. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: In order for this routine to work properly it MUST be *
* called every display loop. *
* *
* HISTORY: *
* 07/31/1991 JLB : Created. *
* 07/05/1994 JLB : Handles new monochrome system. *
*=============================================================================================*/
#define UPDATE_INTERVAL TIMER_SECOND
void Self_Regulate(void)
{
static ObjectClass * _lastobject = 0;
static bool _first=true;
if (DebugTimer == 0) {
DebugTimer = UPDATE_INTERVAL;
if (MonoClass::Is_Enabled()) {
if (_first) {
_first = false;
for (DMonoType index = DMONO_FIRST; index < DMONO_COUNT; index++) {
MonoArray[index].Clear();
}
}
/*
** Always update the stress tracking mono display even if it
** currently isn't visible.
*/
Logic.Debug_Dump(&MonoArray[DMONO_STRESS]);
MonoClass * mono = &MonoArray[MonoPage];
mono->Set_Default_Attribute(MonoClass::NORMAL);
mono->View();
switch (MonoPage) {
case DMONO_EVENTS:
Benchmarks(mono);
break;
case DMONO_OBJECT:
mono->Clear();
/*
** Display the status of the currently selected object.
*/
if (CurrentObject.Count()) {
_lastobject = CurrentObject[0];
}
if (_lastobject && !_lastobject->IsActive) {
_lastobject = 0;
}
if (_lastobject) {
_lastobject->Debug_Dump(mono);
}
break;
case DMONO_STRESS:
#ifdef OBSOLETE
mono->Set_Cursor(0, 20);
mono->Printf(
"Heap size:%10ld \r"
"Largest: %10ld \r"
"Ttl Free: %10ld \r"
"Frag: %10ld \r",
Heap_Size(MEM_NORMAL),
Ram_Free(MEM_NORMAL),
Total_Ram_Free(MEM_NORMAL),
Total_Ram_Free(MEM_NORMAL)-Ram_Free(MEM_NORMAL)
);
#endif
break;
case DMONO_HOUSE:
mono->Clear();
if (CurrentObject.Count()) {
_lastobject = CurrentObject[0];
}
if (_lastobject && !_lastobject->IsActive) {
_lastobject = 0;
}
if (_lastobject && _lastobject->Is_Techno()) {
((TechnoClass *)_lastobject)->House->Debug_Dump(mono);
}
break;
default:
break;
}
mono->Set_Cursor(0, 0);
}
}
}
#endif
================================================
FILE: CODE/DEBUG.H
================================================
/*
** 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 .
*/
#define TXT_CLEAR_MAP 0x3e8 // Clear the map
#define TXT_INHERIT_MAP 0x3e9 // Inherit previous map
#define TXT_SPECIAL_OPTIONS 0x3ea // Select Special Options
#define TXT_VISIBLE_TARGET 0x3eb // Targeting flash visible to
#define TXT_TREE_TARGET 0x3ec // Allow targeting of trees.
#define TXT_MCV_DEPLOY 0x3ed // Allow undeploy of
#define TXT_SMART_DEFENCE 0x3ee // Employ smarter self defense
#define TXT_SLOW_BUILD 0x3ef // Moderate production speed.
#define TXT_THREE_POINT 0x3f0 // Use three point turn logic.
#define TXT_TIBERIUM_GROWTH 0x3f1 // Ore will grow.
#define TXT_TIBERIUM_SPREAD 0x3f2 // Ore will spread.
#define TXT_ROAD_PIECES 0x3f3 // Disable building "bib"
#define TXT_SCATTER 0x3f4 // Allow running from
#define TXT_SHOW_NAMES 0x3f5 // Show true object names.
#define TXT_DEFENDER_ADVANTAGE 0x3f6 // Defender has the advantage.
#define TXT_SEPARATE_HELIPAD 0x3f7 // Allow separate helipad
#define TXT_PASSWORD_CAPTION 0x3f8 // Password Request
#define TXT_PASSWORD_MESSAGE 0x3f9 // Enter Red Alert access code
#define TXT_PASSWORD_ERROR 0x3fa // Access code error detected.
#define TXT_TRY_AGAIN 0x3fb // Try Again
#define TXT_MINE_AWARE 0x3fc // Friendly units avoid
#define TXT_TRIGGER_EDITOR 0x3fd // Trigger Editor
#define TXT_TRIGGER_JUST_EVENT 0x3fe // Just This Event
#define TXT_TRIGGER_AND 0x3ff // ... and ...
#define TXT_TRIGGER_OR 0x400 // ... or ...
#define TXT_TRIGGER_LINKED 0x401 // ... linked ...
#define TXT_TRIGGER_JUST_ACTION 0x402 // Just This Action
#define TXT_TEAM_EDIT 0x403 // Team Editor
#define TXT_SELLABLE 0x404 // Sellable
#define TXT_REBUILD 0x405 // Rebuild
#define TXT_SPEED_BUILD 0x406 // Building constructin time
#define TXT_SCENARIO_ERRORx 0x407 // Scenario authentication
#define TXT_DEBUG_STRESS 0x408 // Frames:F/R:CPU:F/R:
#define TXT_DEBUG_VEHICLE 0x409 // Full
#define TXT_DEBUG_INFANTRY 0x40a // Full
#define TXT_DEBUG_SHIP 0x40b // Full
#define TXT_DEBUG_BUILDING 0x40c // Full
#define TXT_DEBUG_PERFORMANCE 0x40d // Game Objects Drawing
#define TXT_DEBUG_AIRCRAFT 0x40e // Full
#define TXT_DEBUG_HOUSE 0x40f // Full Name:Act
#define TXT_NO_PENTIUM 0x410 // ****************************
#define TXT_SIZE_MAP 0x411 // Size Map
#define TXT_TRUCK_CRATE 0x412 // Trucks drop crate when
================================================
FILE: CODE/DEFINES.H
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/DEFINES.H 4 3/07/97 9:55a 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 : DEFINES.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : September 10, 1993 *
* *
* Last Update : September 10, 1993 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef DEFINES_H
#define DEFINES_H
/**********************************************************************
** Language control: define the desired language for this build.
*/
//#define ENGLISH 1
//#define FRENCH 1
//#define GERMAN 1
//#define SPAIN 1 (never used)
// - Language define is now passed in from the makefile. -
/**********************************************************************
** Controls the nature of the game and its abilities. Only define
** one of these values.
**
** Internal version -- complete with scenario editor.
** Playtest version -- no editor but does have minimal cheat keys.
** Release version -- no editor or cheat keys -- all debugging info removed.
*/
//#define INTERNAL_VERSION
//#define PLAYTEST_VERSION
#define RELEASE_VERSION
/**********************************************************************
** ColinM
** Set this to enable dongle protection
*/
//#define DONGLE
// Enable 640x400 VQ movie capability in WIN32 mode
#define MOVIE640
//#if (GERMAN | FRENCH)
//#define BOGUSCD
//#endif
#define FIXIT_SCORE_CRASH // Fixes score screen crash
#define FIXIT_MULTI_SAVE // Fixes multiplayer save/load
#define FIXIT_NO_COMP_ALLY // Prevent ally with computer
#define FIXIT_DESTNET // Fixes -destnet parameter in Win95
#define FIXIT_RANDOM_GAME // Fixes random seed at start of multiplayer games
#define FIXIT_FORCE_CD // Forces correct CD load after scenario #1
#define FIXIT_IP_CRASH // Fixes crash if internet game aborts too quickly
#define FIXIT_IP_STATS // Fixes so vessels show up in internet stat info
#define FIXIT_NAME_OVERRIDE // Allows changing of unit names
#define FIXIT_RADAR_JAMMED // Fixes unjamming by merely starting to build a radar facility
#define FIXIT_CAPTURE_BIB // Fixes so that if fake is captured, you still can't build off of it.
#define FIXIT_BASE_ANNOUNCE // Fixes so player controlled buildings count as base when attacked.
#define FIXIT_APTIVA_MODEM // Fixes crash with Aptiva modem.
#define FIXIT_FLAG_CHECK // Disable placing building over a flag.
#define FIXIT_ANTS // Adds Ant Units
#define FIXIT_CSII // Adds Aftermath CounterStrike II units
// ajw 9/28/98 - Note about FIXIT_CSII. Changes seem to have been made for Aftermath ("Counterstrike II") that: a) were
// bug fixes that should never be rolled back, b) change the nature of the game, at least in multi-player. This meant
// that the "Red Alert" executable ( == Counterstrike executable ) could no longer be built. Apparently, at the time,
// this was justified, as it was believed that no further patches to the RA executable would ever be necessary.
// Given that Denzil's DVD changes and my WOLAPI integration are essentially a patch, we've got a problem.
// We've decided to level the field and make sure every who gets or patches to the new version of Red Alert, CS, AM, (and
// their DVD equivalent(s)) will have the same executable. So we're assuming that all of the FIXIT_CSII changes are
// permanent (as, in fact, all prior FIXIT_'s are - makes me wonder why the old non-compiling code has to hang around
// forever), and fixing the code so that the assumption "this is an Aftermath game" is no longer hard-coded, but can
// change at runtime. (Which is what should have been done when Aftermath was created.)
//
#define FIXIT_CARRIER // Adds Aftermath aircraft carrier
#define FIXIT_PHASETRANSPORT // Adds Aftermath cloaking APC
// ajw - Discovered that engineer changing fields were specifically left out of aftrmath.ini, thus this has no effect.
// Engineer changes (and other game rule changes) are in mplayer.ini, which was loaded before aftermath-only mplayer games.
#define FIXIT_ENGINEER // Adds Engineer rules.ini overrides
//#define FIXIT_FAST_LOAD // Enables faster INI loading
// These fixes will cause the game to go out of sync.
//#define FIXIT_ENGINEER_CAPTURE // If building not allied, will still capture if engineer not allied with building.
//#define FIXIT_HELI_LANDING // Fixes so new helicopters land at free helipad
//#define FIXIT_MINE_PASSABLE // Fixes units not driving onto mines
/* Turn on these changes for the 1.08 patch */
#define FIXIT_PATCH_108
#ifdef FIXIT_PATCH_108
#define STEVES_LOAD_OVERRIDE // Allows loading of CONQUER.ENG instead of from mix file.
#define FIXIT_DIFFICULTY // Fixes no difficulty level for CStrike missions
#define FIXIT_VERSION // Fixes version playability for 1.04, 1.07 & 1.08
#define FIXIT_MODEM_LOAD_CRASH // Fixes crash after loading a modem game when names are the same
#define FIXIT_PHONELIST_CRASH // Fixes crash when clicking on an empty phonelist
#endif
// Denotes changes made for version 3 - reunification of all existing versions and undoing of Aftermath divergence. - ajw
#define FIXIT_VERSION_3
#define DVD
// Define DVD to turn on RADVD additions/changes - Denzil
#ifdef DVD
//#define INTERNET_OFF
#define MPEGMOVIE
//#define MCIMPEG
#endif
// Test to see if partial object drawing is any faster.
#define PARTIAL
//#define SORTDRAW
/**********************************************************************
** If the scenario editor to to be active in this build then uncomment
** the following #define line.
*/
#ifdef INTERNAL_VERSION
#define SCENARIO_EDITOR
#endif
/**********************************************************************
** This define enables the full set of cheat keys and special
** command line options.
*/
#if defined(INTERNAL_VERSION) || defined(PLAYTEST_VERSION)
#define CHEAT_KEYS
#endif
/**********************************************************************
** If this is defined, the special Virgin limited cheat keys
** are enabled. This allows the "cheat" parameter and then only
** allows the ALT-W to win the mission.
*/
#ifdef PLAYTEST_VERSION
#define VIRGIN_CHEAT_KEYS
#endif
/**********************************************************************
** If this is defined, then the network code will be enabled.
*/
#define NETWORK
#define TIMING_FIX 1
/**********************************************************************
** Define this to 1 to enable MPath-specific code. Do not define
** TEN at the same time.
*/
#define MPATH 0
/**********************************************************************
** Define this to 1 to enable TEN-specific code. Do not define
** MPATH at the same time.
*/
#define TEN 0
/**********************************************************************
** If this is defined, the DoList is "mirrored", for memory trasher
** detection.
*/
#ifdef CHEAT_KEYS
//#define MIRROR_QUEUE
#endif
/**********************************************************************
** This define tells the Version Number class to use the date/time-based
** version numbering system. If this define is not set, the actual
** major/minor version numbers will be used.
*/
//#define DEV_VERSION
//#define DEV_VER_NAME
/**********************************************************************
** This define enables a special additional foreign-version-number
** after the other version number, for display purposes only.
*/
#if !defined(ENGLISH)
#define FOREIGN_VERSION
#define FOREIGN_VERSION_NUMBER 7
#endif
/**********************************************************************
** This is the multiplier factor to convert low resution coordinates
** into their actual resolution counterparts.
*/
#ifdef WIN32
#define RESFACTOR 2
#else
//#undef SCENARIO_EDITOR
#define RESFACTOR 1
#endif
#define SIDEBAR_WID 80
/**********************************************************************
** Optional parameter control for special options.
*/
/*
** Enable the set of limited cheat key options.
*/
#ifdef VIRGIN_CHEAT_KEYS
#define PARM_PLAYTEST 0xF7DDC227 // "PLAYTEST"
#endif
/*
** Enable the full set of cheat key options.
*/
#ifdef CHEAT_KEYS
#ifndef PARM_PLAYTEST
#define PARM_PLAYTEST 0xF7DDC227 // "PLAYTEST"
#endif
#endif
#define PARM_INSTALL 0xD95C68A2 // "FROMINSTALL"
//
// Allow normal game play in the MPath version
//
#if(MPATH)
#define PARM_ALLOW_SOLO 0xc901c9db // AllowSoloPlayOptions
#endif
//
// Allow normal game play in the TEN version
//
#if(TEN)
#define PARM_ALLOW_SOLO 0xc901c9db // AllowSoloPlayOptions
#endif
/**********************************************************************
** Defines for verifying free disk space
*/
#define INIT_FREE_DISK_SPACE 8388608
#define SAVE_GAME_DISK_SPACE (INIT_FREE_DISK_SPACE - (1024*4096))
//#define SAVE_GAME_DISK_SPACE 100000
/**********************************************************************
** This is the complete list of VQs allowed to be played in the game.
*/
typedef enum VQType {
VQ_NONE=-1,
VQ_AAGUN,
VQ_MIG,
VQ_SFROZEN,
VQ_AIRFIELD,
VQ_BATTLE,
VQ_BMAP,
VQ_BOMBRUN,
VQ_DPTHCHRG,
VQ_GRVESTNE,
VQ_MONTPASS,
VQ_MTNKFACT,
VQ_CRONTEST,
VQ_OILDRUM,
VQ_ALLYEND,
VQ_RADRRAID,
VQ_SHIPYARD,
VQ_SHORBOMB,
VQ_SITDUCK,
VQ_SLNTSRVC,
VQ_SNOWBASE,
VQ_EXECUTE,
VQ_TITLE, // Low res.
VQ_NUKESTOK,
VQ_V2ROCKET,
VQ_SEARCH,
VQ_BINOC,
VQ_ELEVATOR,
VQ_FROZEN,
VQ_MCV,
VQ_SHIPSINK,
VQ_SOVMCV,
VQ_TRINITY,
VQ_ALLYMORF,
VQ_APCESCPE,
VQ_BRDGTILT,
VQ_CRONFAIL,
VQ_STRAFE,
VQ_DESTROYR,
VQ_DOUBLE,
VQ_FLARE,
VQ_SNSTRAFE,
VQ_LANDING,
VQ_ONTHPRWL,
VQ_OVERRUN,
VQ_SNOWBOMB,
VQ_SOVCEMET,
VQ_TAKE_OFF,
VQ_TESLA,
VQ_SOVIET8,
VQ_SPOTTER,
VQ_SCENE1,
VQ_SCENE2,
VQ_SCENE4,
VQ_SOVFINAL,
VQ_ASSESS,
VQ_SOVIET10,
VQ_DUD,
VQ_MCV_LAND,
VQ_MCVBRDGE,
VQ_PERISCOP,
VQ_SHORBOM1,
VQ_SHORBOM2,
VQ_SOVBATL,
VQ_SOVTSTAR,
VQ_AFTRMATH,
VQ_SOVIET11,
VQ_MASASSLT,
VQ_REDINTRO, // High res
VQ_SOVIET1,
VQ_SOVIET2,
VQ_SOVIET3,
VQ_SOVIET4,
VQ_SOVIET5,
VQ_SOVIET6,
VQ_SOVIET7,
VQ_INTRO_MOVIE,
VQ_AVERTED,
VQ_COUNTDWN,
VQ_MOVINGIN,
VQ_ALLIED10,
VQ_ALLIED12,
VQ_ALLIED5,
VQ_ALLIED6,
VQ_ALLIED8,
VQ_TANYA1,
VQ_TANYA2,
VQ_ALLY10B,
VQ_ALLY11,
VQ_ALLY14,
VQ_ALLY9,
VQ_SPY,
VQ_TOOFAR,
VQ_SOVIET12,
VQ_SOVIET13,
VQ_SOVIET9,
VQ_BEACHEAD,
VQ_SOVIET14,
VQ_SIZZLE,
VQ_SIZZLE2,
VQ_ANTEND,
VQ_ANTINTRO,
VQ_COUNT,
VQ_FIRST=0
} VQType;
/**********************************************************************
** These enumerations are used to implement RTTI. The target system
** uses these and thus there can be no more RTTI types than can fit
** in the exponent of a target value.
*/
typedef enum RTTIType {
RTTI_NONE=0,
RTTI_AIRCRAFT,
RTTI_AIRCRAFTTYPE,
RTTI_ANIM,
RTTI_ANIMTYPE,
RTTI_BUILDING,
RTTI_BUILDINGTYPE,
RTTI_BULLET,
RTTI_BULLETTYPE,
RTTI_CELL,
RTTI_FACTORY,
RTTI_HOUSE,
RTTI_HOUSETYPE,
RTTI_INFANTRY,
RTTI_INFANTRYTYPE,
RTTI_OVERLAY,
RTTI_OVERLAYTYPE,
RTTI_SMUDGE,
RTTI_SMUDGETYPE,
RTTI_SPECIAL,
RTTI_TEAM,
RTTI_TEAMTYPE,
RTTI_TEMPLATE,
RTTI_TEMPLATETYPE,
RTTI_TERRAIN,
RTTI_TERRAINTYPE,
RTTI_TRIGGER,
RTTI_TRIGGERTYPE,
RTTI_UNIT,
RTTI_UNITTYPE,
RTTI_VESSEL,
RTTI_VESSELTYPE,
RTTI_COUNT
} RTTIType;
/**********************************************************************
** These are the difficulty settings of the game.
*/
typedef enum DiffType {
DIFF_EASY,
DIFF_NORMAL,
DIFF_HARD,
DIFF_COUNT,
DIFF_FIRST=0
} DiffType;
/**********************************************************************
** This is the size of the speech buffer. This value should be as large
** as the largest speech sample, plus a few bytes for overhead
** (16 bytes is sufficient).
*/
#define SPEECH_BUFFER_SIZE 50000L
/**********************************************************************
** The theater mixfiles are cached into a buffer of this size. Ensure
** that the size specified is at least as large as the largest
** theater mixfile data block.
*/
#define THEATER_BUFFER_SIZE 1100000L
/**********************************************************************
** This is the size of the shape buffer. This buffer is used as a staging
** buffer for the shape drawing technology. It MUST be as big as the
** largest shape (uncompressed) that will be drawn. If this value is
** changed, be sure to update the makefile and rebuild all of the shape
** data files.
*/
#define SHAPE_BUFFER_SIZE 65000L
/**********************************************************************
** Filenames of the data files it can create at run time.
*/
#define FAME_FILE_NAME "HALLFAME.DAT"
#define NET_SAVE_FILE_NAME "SAVEGAME.NET"
#define CONFIG_FILE_NAME "REDALERT.INI"
/**********************************************************************
** Map controls. The map is composed of square elements called 'cells'.
** All larger elements are build upon these.
*/
#define HIGH_COORD_MASK 0x80008000L
// Size of the map in cells.
#define MAP_CELL_W 128
#define MAP_CELL_H 128
#define MAP_CELL_TOTAL (MAP_CELL_W*MAP_CELL_H)
#define REFRESH_EOL 32767 // This number ends a refresh/occupy offset list.
#define REFRESH_SIDEBAR 32766 // This number flags that sidebar needs refreshing.
/****************************************************************************
** These are custom C&C specific types. The CELL is used for map coordinate
** with cell resolution. The COORDINATE type is used for map coordinates that
** have a lepton resolution. CELL is more efficient when indexing into the map
** and when size is critical. COORDINATE is more efficient when dealing with
** accuracy and object movement.
*/
typedef unsigned short LEPTON;
typedef union {
LEPTON Raw;
struct {
#ifdef BIG_ENDIAN
unsigned char Cell;
unsigned char Lepton;
#else
unsigned char Lepton;
unsigned char Cell;
#endif
} Sub;
} LEPTON_COMPOSITE;
typedef unsigned long COORDINATE;
typedef union {
COORDINATE Coord;
struct {
#ifdef BIG_ENDIAN
LEPTON_COMPOSITE Y;
LEPTON_COMPOSITE X;
#else
LEPTON_COMPOSITE X;
LEPTON_COMPOSITE Y;
#endif
} Sub;
} COORD_COMPOSITE;
typedef signed short CELL;
#define SLUFF_BITS (sizeof(CELL)*CHAR_BIT)-(14)
typedef union {
CELL Cell;
struct {
#ifdef BIG_ENDIAN
#if SLUFF_BITS
/*
** Unused upper bits will cause problems on a big-endian machine unless they
** are deliberately accounted for.
*/
unsigned sluff:SLUF_BITS;
#endif
unsigned Y:7;
unsigned X:7;
#else
unsigned X:7;
unsigned Y:7;
#endif
} Sub;
} CELL_COMPOSITE;
typedef int WAYPOINT;
/**********************************************************************
** This is the target composit information. Notice that with an RTTI_NONE
** and an index value of 0, the target value returned is identical with
** TARGET_NONE. This is by design and is necessary.
*/
typedef long TARGET;
#define TARGET_MANTISSA 24 // Bits of value precision.
#define TARGET_EXPONENT 8
typedef union {
TARGET Target;
struct {
#ifdef BIG_ENDIAN
unsigned Exponent:TARGET_EXPONENT;
unsigned Mantissa:TARGET_MANTISSA;
#else
unsigned Mantissa:TARGET_MANTISSA;
unsigned Exponent:TARGET_EXPONENT;
#endif
} Sub;
} TARGET_COMPOSITE;
inline TARGET Build_Target(RTTIType kind, int value)
{
TARGET_COMPOSITE target;
target.Target = 0;
target.Sub.Exponent = kind;
target.Sub.Mantissa = value;
return(target.Target);
}
#define TARGET_NONE ((TARGET)0)
/*
** The map is broken down into regions of this specified dimensions.
*/
#define REGION_WIDTH 4
#define REGION_HEIGHT 4
#define MAP_REGION_WIDTH (((MAP_CELL_W + (REGION_WIDTH -1)) / REGION_WIDTH)+2)
#define MAP_REGION_HEIGHT (((MAP_CELL_H + (REGION_WIDTH -1)) / REGION_HEIGHT)+2)
#define MAP_TOTAL_REGIONS (MAP_REGION_WIDTH * MAP_REGION_HEIGHT)
/**********************************************************************
** This enumerates the various known fear states for infantry units.
** At these stages, certain events or recovery actions are performed.
*/
typedef enum FearType {
FEAR_NONE=0, // No fear at all (default state).
FEAR_ANXIOUS=10, // Something makes them scared.
FEAR_SCARED=100, // Scared enough to take cover.
FEAR_PANIC=200, // Run away! Run away!
FEAR_MAXIMUM=255 // Scared to death.
} FearType;
/**********************************************************************
** When a moving object moves, the Per_Cell_Process function is called
** at various times during the move. Certain operations must be
** performed at different stages of the move. This enum specifies the
** different conditions under which the Per_Cell_Process function is
** called.
*/
typedef enum PCPType {
PCP_ROTATION, // When sitting in place and performing rotations.
PCP_DURING, // While moving between two cells.
PCP_END, // When the 'center' of a cell is reached during movement.
} PCPType;
/**********************************************************************
** A base is broken up into several zones. This type enumerates the
** various zones.
*/
typedef enum ZoneType {
ZONE_CORE, // Center of base.
ZONE_NORTH, // North section.
ZONE_EAST, // East section.
ZONE_SOUTH, // South section.
ZONE_WEST, // West section.
ZONE_COUNT,
ZONE_FIRST=0,
ZONE_NONE=-1
} ZoneType;
/**********************************************************************
** The map is prescanned to mark of movement zones according to certain
** movement characteristics. This enum specifies those characteristics
** and movement zones kept track of.
*/
typedef enum MZoneType {
MZONE_NORMAL, // Normal terrestrial objects (can't crush walls).
MZONE_CRUSHER, // Can crush crushable wall types.
MZONE_DESTROYER, // Can destroy walls.
MZONE_WATER, // Water based objects.
MZONE_COUNT,
MZONE_FIRST=0
} MZoneType;
#define MZONEF_NORMAL (1<APC or vehicle->Repair facility.
ACTION_SELF, // Self select special case.
ACTION_ATTACK, // Can attack or fire upon it in some fashion.
ACTION_HARVEST, // Special harvest mode.
ACTION_SELECT, // Would change selection to specified object.
ACTION_TOGGLE_SELECT,// Toggles select state of the object.
ACTION_CAPTURE, // The unit will try to capture the object.
ACTION_REPAIR, // The target object should be repaired.
ACTION_SELL, // The target building should be sold back.
ACTION_SELL_UNIT, // The target unit should be sold back.
ACTION_NO_SELL, // No sell or no repair.
ACTION_NO_REPAIR, // No sell or no repair.
ACTION_SABOTAGE, // The unit will try to sabotage/destroy the object.
ACTION_PARA_BOMB, // Parachute bomb strike.
ACTION_PARA_INFANTRY,// Parachute infantry strike.
ACTION_PARA_SABOTEUR,// Parachute saboteur strike.
ACTION_NUKE_BOMB, // That target object should be blasted.
ACTION_AIR_STRIKE, // That target object should be blasted.
ACTION_CHRONOSPHERE, // That target object should be teleported.
ACTION_CHRONO2, // Teleport it to the given coordinates now.
ACTION_IRON_CURTAIN, // That target object should be invulnerable.
ACTION_SPY_MISSION, // Photo recon mission.
ACTION_GUARD_AREA, // Guard the area/object clicked on.
ACTION_HEAL, // Heal the infantryman clicked on.
ACTION_DAMAGE, // Enter and damage building.
ACTION_GREPAIR, // Enter and complete repair building.
ACTION_NO_DEPLOY,
ACTION_NO_ENTER,
ACTION_NO_GREPAIR,
ACTION_COUNT
} ActionType;
/**********************************************************************
** When a unit gets damaged, the result of the damage is returned as
** this type. It can range from no damage taken to complete destruction.
*/
typedef enum ResultType {
RESULT_NONE, // No damage was taken by the target.
RESULT_LIGHT, // Some damage was taken, but no state change occurred.
RESULT_HALF, // Damaged to below half strength (only returned on transition).
RESULT_MAJOR, // Damaged down to 1 hit point.
RESULT_DESTROYED // Damaged to complete destruction.
} ResultType;
#ifdef OBSOLETE
/**********************************************************************
** These are the special concrete control defines. They enumerate the
** sequence order of the concrete icons in the concrete art file.
*/
// DEBUG === convert this to be zero based so that a nulled cell is the
// default cell.
enum ConcreteEnum {
C_NONE=-1,
C_LEFT=0,
C_RIGHT=1,
C_RIGHT_UPDOWN=2,
C_LEFT_UPDOWN=3,
C_UP_RIGHT=4,
C_UP_LEFT=5,
C_DOWN_RIGHT=6,
C_DOWN_LEFT=7,
C_RIGHT_DOWN=8,
C_LEFT_DOWN=9,
C_RIGHT_UP=10,
C_LEFT_UP=11,
C_UPDOWN_RIGHT=12,
C_UPDOWN_LEFT=13
};
#endif
/**********************************************************************
** Units that move can move at different speeds. These enumerate the
** different speeds that a unit can move.
*/
typedef enum MPHType{
MPH_IMMOBILE=0,
MPH_VERY_SLOW=5, // 2
MPH_KINDA_SLOW=6, // 3
MPH_SLOW=8, // 4
MPH_SLOW_ISH=10, // 5
MPH_MEDIUM_SLOW=12, // 6
MPH_MEDIUM=18, // 9
MPH_MEDIUM_FAST=30, // 12
MPH_MEDIUM_FASTER=35, // 14
MPH_FAST=40, // 16
MPH_ROCKET=60, // 24
MPH_VERY_FAST=100, // 40
MPH_LIGHT_SPEED=255 // 100
} MPHType;
/**********************************************************************
** The houses that can be played are listed here. Each has their own
** personality and strengths.
*/
typedef enum HousesType {
HOUSE_NONE=-1,
HOUSE_SPAIN, // Gold (unremapped)
HOUSE_GREECE, // LtBlue
HOUSE_USSR, // Red
HOUSE_ENGLAND, // Green
HOUSE_UKRAINE, // Orange
HOUSE_GERMANY, // Grey
HOUSE_FRANCE, // Blue
HOUSE_TURKEY, // Brown
HOUSE_GOOD, // Global Defense Initiative
HOUSE_BAD, // Brotherhood of Nod
HOUSE_NEUTRAL, // Civilians
HOUSE_JP, // Disaster Containment Team
HOUSE_MULTI1, // Multi-Player house #1
HOUSE_MULTI2, // Multi-Player house #2
HOUSE_MULTI3, // Multi-Player house #3
HOUSE_MULTI4, // Multi-Player house #4
HOUSE_MULTI5, // Multi-Player house #5
HOUSE_MULTI6, // Multi-Player house #6
HOUSE_MULTI7, // Multi-Player house #7
HOUSE_MULTI8, // Multi-Player house #8
HOUSE_COUNT,
HOUSE_FIRST=0
} HousesType;
inline HousesType operator++(HousesType &, int);
#define HOUSEF_ALLIES (HOUSEF_ENGLAND|HOUSEF_SPAIN|HOUSEF_GREECE|HOUSEF_GERMANY|HOUSEF_FRANCE|HOUSEF_TURKEY|HOUSEF_GOOD)
#define HOUSEF_SOVIET (HOUSEF_USSR|HOUSEF_UKRAINE|HOUSEF_BAD)
#define HOUSEF_OTHERS (HOUSEF_NEUTRAL|HOUSEF_JP|HOUSEF_MULTI1|HOUSEF_MULTI2|HOUSEF_MULTI3|HOUSEF_MULTI4|HOUSEF_MULTI5|HOUSEF_MULTI6|HOUSEF_MULTI7|HOUSEF_MULTI8)
#define HOUSEF_NONE 0
#define HOUSEF_ENGLAND (1L< 2 players.
*/
typedef enum ScenarioPlayerEnum
{
SCEN_PLAYER_NONE = -1,
SCEN_PLAYER_SPAIN,
SCEN_PLAYER_GREECE,
SCEN_PLAYER_USSR,
SCEN_PLAYER_JP,
SCEN_PLAYER_2PLAYER,
SCEN_PLAYER_MPLAYER,
SCEN_PLAYER_COUNT,
SCEN_PLAYER_FIRST = 0
} ScenarioPlayerType;
inline ScenarioPlayerType operator++(ScenarioPlayerType &, int);
/**********************************************************************
** These are the directional parameters for a scenario.
*/
typedef enum ScenarioDirEnum
{
SCEN_DIR_NONE = -1,
SCEN_DIR_EAST,
SCEN_DIR_WEST,
SCEN_DIR_COUNT,
SCEN_DIR_FIRST = 0
} ScenarioDirType;
inline ScenarioDirType operator++(ScenarioDirType &, int);
/**********************************************************************
** These are the random variations of a scenario.
*/
typedef enum ScenarioVarEnum
{
SCEN_VAR_NONE = -1,
SCEN_VAR_A,
SCEN_VAR_B,
SCEN_VAR_C,
SCEN_VAR_D,
SCEN_VAR_COUNT, // comes before the Lose value!
SCEN_VAR_LOSE,
SCEN_VAR_FIRST = 0
} ScenarioVarType;
inline ScenarioVarType operator++(ScenarioVarType &, int);
/**********************************************************************
** The objects to be drawn on the map are grouped into layers. These
** enumerated values specify those layers. The ground layer is sorted
** from back to front.
*/
typedef enum LayerType {
LAYER_NONE=-1,
LAYER_SURFACE, // Flat on the ground (no sorting or apparent vertical height).
LAYER_GROUND, // Touching the ground type object (units & buildings).
LAYER_AIR, // Flying above the ground (explosions & flames).
LAYER_TOP, // Topmost layer (aircraft & bullets).
LAYER_COUNT,
LAYER_FIRST=0
} LayerType;
inline LayerType operator++(LayerType &, int);
/**********************************************************************
** This enumerates the various bullet types. These types specify bullet's
** visual and explosive characteristics.
*/
typedef enum BulletType {
BULLET_NONE=-1,
BULLET_INVISIBLE,
BULLET_CANNON,
BULLET_ACK,
BULLET_TORPEDO,
BULLET_FROG,
BULLET_HEAT_SEEKER,
BULLET_LASER_GUIDED,
BULLET_LOBBED,
BULLET_BOMBLET,
BULLET_BALLISTIC,
BULLET_PARACHUTE,
BULLET_FIREBALL,
BULLET_DOG,
BULLET_CATAPULT,
BULLET_AAMISSILE,
BULLET_GPS_SATELLITE,
BULLET_NUKE_UP,
BULLET_NUKE_DOWN,
BULLET_COUNT,
BULLET_FIRST=0
} BulletType;
inline BulletType operator++(BulletType &, int);
/**********************************************************************
** All game buildings (structures) are enumerated here. This includes
** civilian structures as well.
*/
typedef enum StructType {
STRUCT_NONE=-1,
STRUCT_ADVANCED_TECH,
STRUCT_IRON_CURTAIN,
STRUCT_WEAP,
STRUCT_CHRONOSPHERE,
STRUCT_PILLBOX,
STRUCT_CAMOPILLBOX,
STRUCT_RADAR,
STRUCT_GAP,
STRUCT_TURRET,
STRUCT_AAGUN,
STRUCT_FLAME_TURRET,
STRUCT_CONST,
STRUCT_REFINERY,
STRUCT_STORAGE,
STRUCT_HELIPAD,
STRUCT_SAM,
STRUCT_AIRSTRIP,
STRUCT_POWER,
STRUCT_ADVANCED_POWER,
STRUCT_SOVIET_TECH,
STRUCT_HOSPITAL,
STRUCT_BARRACKS,
STRUCT_TENT,
STRUCT_KENNEL,
STRUCT_REPAIR,
STRUCT_BIO_LAB,
STRUCT_MISSION,
STRUCT_SHIP_YARD,
STRUCT_SUB_PEN,
STRUCT_MSLO,
STRUCT_FORWARD_COM,
STRUCT_TESLA,
/*
** All buildings that are never used as a prerequisite
** for construction, follow this point. Typically, this is
** limited to civilian structures. Also, the following
** buildings are NEVER used in the availability bit field
** record that each house maintains. i.e., STRUCTF_????
** bit checking will never occur with the following
** building types.
*/
STRUCT_FAKEWEAP,
STRUCT_FAKECONST,
STRUCT_FAKE_YARD,
STRUCT_FAKE_PEN,
STRUCT_FAKE_RADAR,
STRUCT_SANDBAG_WALL,
STRUCT_CYCLONE_WALL,
STRUCT_BRICK_WALL,
STRUCT_BARBWIRE_WALL,
STRUCT_WOOD_WALL,
STRUCT_FENCE,
STRUCT_AVMINE,
STRUCT_APMINE,
STRUCT_V01,
STRUCT_V02,
STRUCT_V03,
STRUCT_V04,
STRUCT_V05,
STRUCT_V06,
STRUCT_V07,
STRUCT_V08,
STRUCT_V09,
STRUCT_V10,
STRUCT_V11,
STRUCT_V12,
STRUCT_V13,
STRUCT_V14,
STRUCT_V15,
STRUCT_V16,
STRUCT_V17,
STRUCT_V18,
STRUCT_PUMP,
STRUCT_V20,
STRUCT_V21,
STRUCT_V22,
STRUCT_V23,
STRUCT_V24,
STRUCT_V25,
STRUCT_V26,
STRUCT_V27,
STRUCT_V28,
STRUCT_V29,
STRUCT_V30,
STRUCT_V31,
STRUCT_V32,
STRUCT_V33,
STRUCT_V34,
STRUCT_V35,
STRUCT_V36,
STRUCT_V37,
STRUCT_BARREL,
STRUCT_BARREL3,
#ifdef FIXIT_ANTS
STRUCT_QUEEN,
STRUCT_LARVA1,
STRUCT_LARVA2,
#endif
STRUCT_COUNT,
STRUCT_FIRST=0
} StructType;
inline StructType operator++(StructType &, int);
#define STRUCTF_NONE 0L
#define STRUCTF_ADVANCED_TECH (1L << STRUCT_ADVANCED_TECH)
#define STRUCTF_IRON_CURTAIN (1L << STRUCT_IRON_CURTAIN)
#define STRUCTF_WEAP (1L << STRUCT_WEAP)
#define STRUCTF_CHRONOSPHERE (1L << STRUCT_CHRONOSPHERE)
#define STRUCTF_PILLBOX (1L << STRUCT_PILLBOX)
#define STRUCTF_CAMOPILLBOX (1L << STRUCT_CAMOPILLBOX)
#define STRUCTF_RADAR (1L << STRUCT_RADAR)
#define STRUCTF_GAP (1L << STRUCT_GAP)
#define STRUCTF_TURRET (1L << STRUCT_TURRET)
#define STRUCTF_AAGUN (1L << STRUCT_AAGUN)
#define STRUCTF_FLAME_TURRET (1L << STRUCT_FLAME_TURRET)
#define STRUCTF_CONST (1L << STRUCT_CONST)
#define STRUCTF_REFINERY (1L << STRUCT_REFINERY)
#define STRUCTF_STORAGE (1L << STRUCT_STORAGE)
#define STRUCTF_HELIPAD (1L << STRUCT_HELIPAD)
#define STRUCTF_SAM (1L << STRUCT_SAM)
#define STRUCTF_AIRSTRIP (1L << STRUCT_AIRSTRIP)
#define STRUCTF_POWER (1L << STRUCT_POWER)
#define STRUCTF_ADVANCED_POWER (1L << STRUCT_ADVANCED_POWER)
#define STRUCTF_SOVIET_TECH (1L << STRUCT_SOVIET_TECH)
#define STRUCTF_HOSPITAL (1L << STRUCT_HOSPITAL)
#define STRUCTF_BARRACKS (1L << STRUCT_BARRACKS)
#define STRUCTF_TENT (1L << STRUCT_TENT)
#define STRUCTF_KENNEL (1L << STRUCT_KENNEL)
#define STRUCTF_REPAIR (1L << STRUCT_REPAIR)
#define STRUCTF_BIO_LAB (1L << STRUCT_BIO_LAB)
#define STRUCTF_MISSION (1L << STRUCT_MISSION)
#define STRUCTF_SHIP_YARD (1L << STRUCT_SHIP_YARD)
#define STRUCTF_SUB_PEN (1L << STRUCT_SUB_PEN)
#define STRUCTF_MSLO (1L << STRUCT_MSLO)
#define STRUCTF_FAKECONST (1L << STRUCT_FAKECONST)
#define STRUCTF_FAKEWEAP (1L << STRUCT_FAKEWEAP)
/**********************************************************************
** The overlays are enumerated here. An overlay functions similarly to
** a transparent icon. It is placed over the terrain but usually falls
** "under" buildings, trees, and units.
*/
typedef enum OverlayType {
OVERLAY_NONE=-1,
OVERLAY_SANDBAG_WALL, // Piled sandbags.
OVERLAY_CYCLONE_WALL, // Chain-link fence.
OVERLAY_BRICK_WALL, // Solid concrete wall.
OVERLAY_BARBWIRE_WALL, // Barbed-wire wall.
OVERLAY_WOOD_WALL, // Wooden fence.
OVERLAY_GOLD1,
OVERLAY_GOLD2,
OVERLAY_GOLD3,
OVERLAY_GOLD4,
OVERLAY_GEMS1,
OVERLAY_GEMS2,
OVERLAY_GEMS3,
OVERLAY_GEMS4,
OVERLAY_V12, // Haystacks
OVERLAY_V13, // Haystack
OVERLAY_V14, // Wheat field
OVERLAY_V15, // Fallow field
OVERLAY_V16, // Corn field
OVERLAY_V17, // Celery field
OVERLAY_V18, // Potato field
OVERLAY_FLAG_SPOT, // Flag start location.
OVERLAY_WOOD_CRATE, // Wooden goodie crate.
OVERLAY_STEEL_CRATE, // Steel goodie crate.
OVERLAY_FENCE, // New fangled fence.
OVERLAY_WATER_CRATE, // Water goodie crate.
OVERLAY_COUNT,
OVERLAY_FIRST=0
} OverlayType;
inline OverlayType operator++(OverlayType &, int);
/**********************************************************************
** This specifies the infantry in the game. The "E" designation is
** similar to the army classification of enlisted soldiers.
*/
typedef enum InfantryType{
INFANTRY_NONE=-1,
INFANTRY_E1, // Mini-gun armed.
INFANTRY_E2, // Grenade thrower.
INFANTRY_E3, // Rocket launcher.
INFANTRY_E4, // Flame thrower equipped.
INFANTRY_RENOVATOR, // Engineer.
INFANTRY_TANYA, // Saboteur.
INFANTRY_SPY, // Spy.
INFANTRY_THIEF, // Thief.
INFANTRY_MEDIC, // Field Medic.
INFANTRY_GENERAL, // Field Marshal.
INFANTRY_DOG, // Soviet attack dog
INFANTRY_C1, // Civilian
INFANTRY_C2, // Civilian
INFANTRY_C3, // Civilian
INFANTRY_C4, // Civilian
INFANTRY_C5, // Civilian
INFANTRY_C6, // Civilian
INFANTRY_C7, // Civilian
INFANTRY_C8, // Civilian
INFANTRY_C9, // Civilian
INFANTRY_C10, // Nikumba
INFANTRY_EINSTEIN, // Einstein
INFANTRY_DELPHI, // Agent "Delphi"
INFANTRY_CHAN, // Dr. Chan
#ifdef FIXIT_CSII // checked - ajw 9/28/98
// CounterStrike II only!
INFANTRY_SHOCK, // Shock Trooper
INFANTRY_MECHANIC,
#endif
INFANTRY_COUNT,
INFANTRY_FIRST=0
#ifdef FIXIT_CSII // checked - ajw 9/28/98
,
INFANTRY_RA_COUNT = INFANTRY_SHOCK
#endif
} InfantryType;
#define INFANTRYF_DOG (1L << INFANTRY_DOG)
inline InfantryType operator++(InfantryType &, int);
/**********************************************************************
** The game units are enumerated here. These include not only traditional
** vehicles, but also hovercraft and gunboats.
*/
typedef enum UnitType{
UNIT_NONE=-1,
UNIT_HTANK, // Mammoth tank.
UNIT_MTANK, // Heavy tank.
UNIT_MTANK2, // Medium tank.
UNIT_LTANK, // Light tank ('Bradly').
UNIT_APC, // APC.
UNIT_MINELAYER, // Mine-laying vehicle.
UNIT_JEEP, // 4x4 jeep replacement.
UNIT_HARVESTER, // Resource gathering vehicle.
UNIT_ARTY, // Artillery unit.
UNIT_MRJ, // Mobile Radar Jammer.
UNIT_MGG, // Mobile Gap Generator
UNIT_MCV, // Mobile construction vehicle.
UNIT_V2_LAUNCHER, // V2 rocket launcher.
UNIT_TRUCK, // Convoy truck
#ifdef FIXIT_ANTS
UNIT_ANT1, // Warrior ant.
UNIT_ANT2, // Warrior ant.
UNIT_ANT3, // Warrior ant.
#endif
#ifdef FIXIT_CSII // checked - ajw 9/28/98
// CS II ONLY!
UNIT_CHRONOTANK, // Chrono-shifting tank
UNIT_TESLATANK, // Tesla-equipped tank
UNIT_MAD, // Timequake tank
UNIT_DEMOTRUCK, // Jihad truck
#ifdef FIXIT_PHASETRANSPORT // checked - ajw 9/28/98
UNIT_PHASE, // cloaking APC for special missions
#endif
#endif
UNIT_COUNT,
UNIT_FIRST=0
#ifdef FIXIT_CSII // checked - ajw 9/28/98
,
UNIT_RA_COUNT = UNIT_CHRONOTANK
#endif
} UnitType;
inline UnitType operator++(UnitType &, int);
#define UNITF_HTANK (1L<id)
#define MAX_LOG_LEVEL 10
// Maximum number of multi players possible.
#define MAX_PLAYERS 8 // max # of players we can have
#endif
================================================
FILE: CODE/DESCDLG.CPP
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/DESCDLG.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 : DESCDLG.CPP *
* *
* Programmer : Maria del Mar McCready Legg *
* Joe L. Bostic *
* *
* Start Date : Jan 26, 1995 *
* *
* Last Update : Jan 26, 1995 [MML] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* DescriptionClass::Process -- Handles all the options graphic interface. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
#include "descdlg.h"
/***********************************************************************************************
* DescriptionClass::Process -- Handles all the options graphic interface. *
* *
* This dialog uses an edit box to "fill-out" a description. *
* *
* INPUT: char *string - return answer here. *
* OUTPUT: none *
* WARNINGS: none *
* HISTORY: 12/31/1994 MML : Created. *
*=============================================================================================*/
void DescriptionClass::Process(char * string)
{
/*
** Set up the window. Window x-coords are in bytes not pixels.
*/
Set_Window(WINDOW_EDITOR, OPTION_X, OPTION_Y, OPTION_WIDTH, OPTION_HEIGHT);
Set_Logic_Page(SeenBuff);
/*
** Create Buttons. Button coords are in pixels, but are window-relative.
*/
TextButtonClass optionsbtn(BUTTON_OPTIONS, TXT_OK, TPF_BUTTON, 0, BUTTON_Y);
TextButtonClass cancelbtn(BUTTON_CANCEL, TXT_CANCEL, TPF_BUTTON, 0, BUTTON_Y);
cancelbtn.X = OPTION_X + ((OPTION_WIDTH - optionsbtn.Width)/3)*2;
optionsbtn.X = OPTION_X + ((OPTION_WIDTH - optionsbtn.Width)/3);
optionsbtn.Add_Tail(cancelbtn);
EditClass edit(
BUTTON_EDIT,
string,
31,
TPF_6PT_GRAD,
0,
EDIT_Y,
EDIT_W);
edit.Set_Focus();
edit.X = OPTION_X + (OPTION_WIDTH - edit.Width)/2,
optionsbtn.Add_Tail(edit);
/*
** 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(OPTION_X, OPTION_Y, OPTION_WIDTH, OPTION_HEIGHT, GadgetClass::LEFTPRESS);
optionsbtn.Add_Tail(dialog);
/*
** 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_OPTIONS, 0, 0, 320, 200, GadgetClass::LEFTPRESS|GadgetClass::RIGHTPRESS);
optionsbtn.Add_Tail(background);
/*
** Main Processing Loop
*/
bool display = true;
bool process = true;
while (process) {
/*
** Invoke game callback
*/
Call_Back();
/*
** Refresh display if needed
*/
if (display) {
Window_Hide_Mouse(WINDOW_EDITOR);
/*
** Draw the background
*/
Window_Box (WINDOW_EDITOR, BOXSTYLE_BORDER); // has border, raised up
Draw_Caption(TXT_MISSION_DESCRIPTION, OPTION_X, OPTION_Y, OPTION_WIDTH);
/*
** Draw the titles
*/
optionsbtn.Draw_All();
Window_Show_Mouse();
display = false;
}
/*
** Get user input
*/
KeyNumType input = optionsbtn.Input();
/*
** Process Input
*/
switch (input) {
case KN_RETURN:
case KeyNumType(BUTTON_OPTIONS|KN_BUTTON):
strtrim(string);
process = false;
break;
case KN_ESC:
case KeyNumType(BUTTON_CANCEL|KN_BUTTON):
string[0]= NULL;
strtrim(string);
process = false;
break;
case KeyNumType(BUTTON_EDIT|KN_BUTTON):
break;
default:
break;
}
}
}
================================================
FILE: CODE/DESCDLG.H
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/DESCDLG.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 : DESCDLG.H *
* *
* Programmer : Maria del Mar McCready Legg *
* Joe L. Bostic *
* *
* Start Date : Jan 26, 1995 *
* *
* Last Update : Jan 26, 1995 [MML] *
* *
*---------------------------------------------------------------------------------------------*/
#ifndef DESCDLG_H
#define DESCDLG_H
#include "gadget.h"
class DescriptionClass
{
private:
enum DescriptionClassEnum {
OPTION_WIDTH=216, // Width of dialog box.
OPTION_HEIGHT=122, // Height of dialog box.
OPTION_X=(((320 - OPTION_WIDTH) / 2) & ~7),
OPTION_Y=((200 - OPTION_HEIGHT) / 2),
TEXT_X=OPTION_X+32, // Title's x pos
TEXT_Y=OPTION_Y+32, // Add 11 for each following line
BUTTON_OPTIONS=1, // Button number for "Ok"
BUTTON_CANCEL,
BUTTON_EDIT,
BUTTON_X=OPTION_X+63, // Options button x pos
BUTTON_Y=OPTION_Y+102, // Options button y pos
EDIT_Y =OPTION_Y+50,
EDIT_W =180 //204,
};
public:
DescriptionClass(void) {};
void Process(char *string);
};
#endif
================================================
FILE: CODE/DIAL8.CPP
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/DIAL8.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 : DIAL8.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 07/05/96 *
* *
* Last Update : July 5, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* Dial8Class::Action -- action routine for Dial8Class *
* Dial8Class::Dial8Class -- constructor for the facing dial *
* Dial8Class::Draw_Me -- render routine for Dial8Class *
* Dial8Class::Get_Direction -- retrieves direction (0-255) of dial *
* Dial8Class::Set_Direction -- sets current direction (0-255) of dial *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
/***************************************************************************
* Dial8Class::Dial8Class -- constructor for the facing dial *
* *
* INPUT: *
* id button ID *
* x,y,w,h dimensions in window-relative pixels *
* dir numerical initial facing value (0-255); this is the *
* value returned by WWLIB Desired_Facing8() *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 11/16/1994 BR : Created. *
*=========================================================================*/
Dial8Class::Dial8Class(int id, int x, int y, int w, int h, DirType dir) :
ControlClass(id, x, y, w, h, LEFTPRESS | LEFTHELD | LEFTRELEASE, true)
{
/*
** Center coordinates.
*/
FaceX = X + (Width / 2);
FaceY = Y + (Height / 2);
/*
** Init directions.
*/
Direction = dir; // 0 - 255
Facing = Dir_Facing(Direction); // 0 - 7
OldFacing = Facing; // 0 - 7
/*
** Compute the drawing dimensions: a 45-degree angle intersects a unity-
** radius circle at (.707,.707). Make the decorations 8/10 of the radius,
** and the line extend to 6/10 of the radius. Use Width/2 for x-radius,
** Height/2 for y-radius.
*/
FacePoint[0][0] = FaceX;
FacePoint[0][1] = FaceY - (h * 8 / 2) / 10;
FacePoint[1][0] = FaceX + (w * 7 * 8 / 2) / 100;
FacePoint[1][1] = FaceY - (h * 7 * 8 / 2) / 100;
FacePoint[2][0] = FaceX + (w * 8 / 2) / 10;
FacePoint[2][1] = FaceY;
FacePoint[3][0] = FaceX + (w * 7 * 8 / 2) / 100;
FacePoint[3][1] = FaceY + (h * 7 * 8 / 2) / 100;
FacePoint[4][0] = FaceX;
FacePoint[4][1] = FaceY + (h * 8 / 2) / 10;
FacePoint[5][0] = FaceX - (w * 7 * 8 / 2) / 100;
FacePoint[5][1] = FaceY + (h * 7 * 8 / 2) / 100;
FacePoint[6][0] = FaceX - (w * 8 / 2) / 10;
FacePoint[6][1] = FaceY;
FacePoint[7][0] = FaceX - (w * 7 * 8 / 2) / 100;
FacePoint[7][1] = FaceY - (h * 7 * 8 / 2) / 100;
FaceLine[0][0] = FaceX;
FaceLine[0][1] = FaceY - (h * 6 / 2) / 10;
FaceLine[1][0] = FaceX + (w * 7 * 6 / 2) / 100;
FaceLine[1][1] = FaceY - (h * 7 * 6 / 2) / 100;
FaceLine[2][0] = FaceX + (w * 6 / 2) / 10;
FaceLine[2][1] = FaceY;
FaceLine[3][0] = FaceX + (w * 7 * 6 / 2) / 100;
FaceLine[3][1] = FaceY + (h * 7 * 6 / 2) / 100;
FaceLine[4][0] = FaceX;
FaceLine[4][1] = FaceY + (h * 6 / 2) / 10;
FaceLine[5][0] = FaceX - (w * 7 * 6 / 2) / 100;
FaceLine[5][1] = FaceY + (h * 7 * 6 / 2) / 100;
FaceLine[6][0] = FaceX - (w * 6 / 2) / 10;
FaceLine[6][1] = FaceY;
FaceLine[7][0] = FaceX - (w * 7 * 6 / 2) / 100;
FaceLine[7][1] = FaceY - (h * 7 * 6 / 2) / 100;
}
/***************************************************************************
* Dial8Class::Action -- activation function for Dial8Class *
* *
* 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/06/1995 BR : Created. *
*=========================================================================*/
int Dial8Class::Action(unsigned flags, KeyNumType &key)
{
static int is_sel = 0;
/*
** We might end up clearing the event bits. Make sure that the sticky
** process is properly updated anyway.
*/
Sticky_Process(flags);
if (flags & LEFTPRESS) {
is_sel = 1;
}
/*
** If left mouse is clicked or held, and the dial has changed its direction,
** invoke the parent Action routine:
** GadgetClass::Action handles Sticky processing, & sets IsToRepaint if any
** flag bits are set.
** ControlClass::Action handles Peer_To_Peer notification, and substitutes
** 'key' with the button ID if any flags are set, or 0 if no flags are set
*/
if (flags & LEFTPRESS || ((flags & LEFTHELD) && is_sel)) {
/*
** Get new dial position (0-255)
*/
Direction = (DirType)Desired_Facing8(FaceX, FaceY, Get_Mouse_X(), Get_Mouse_Y());
/*
** Convert to Facing value (0-7).
*/
Facing = Dir_Facing(Direction);
/*
** If it's moved, redraw.
*/
if (Facing!=OldFacing) {
OldFacing = Facing;
ControlClass::Action(flags, key);
return(true);
} else {
/*
** Dial hasn't moved; kill the event & return
*/
key = KN_NONE;
ControlClass::Action(0, key);
return(true);
}
} else {
/*
** Otherwise, no events have occurred; kill the event if it's a LEFTRELEASE,
** and return
*/
if (flags & LEFTRELEASE) {
key = KN_NONE;
is_sel = 0;
}
return(ControlClass::Action(0, key));
}
}
/***************************************************************************
* Dial8Class::Draw_Me -- custom render routine for Dial8Class *
* *
* INPUT: *
* forced true = draw regardless of the current redraw flag state*
* *
* OUTPUT: *
* true = gadget was redrawn, false = wasn't *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 02/06/1995 BR : Created. *
*=========================================================================*/
int Dial8Class::Draw_Me(int forced)
{
RemapControlType * scheme = GadgetClass::Get_Color_Scheme();
/*
** Redraw if parent indicates a redraw is needed
*/
if (ControlClass::Draw_Me(forced)) {
/*
** Hide the mouse.
*/
if (LogicPage == &SeenBuff) {
Hide_Mouse();
}
/*
** Draw background & decorations.
*/
Draw_Box(X, Y, Width, Height, BOXSTYLE_DOWN, true);
for (int i=0; i<8; i++) {
Draw_Box(FacePoint[i][0] - 1, FacePoint[i][1] -1, 3, 3, BOXSTYLE_RAISED, false);
}
/*
** Draw the hand & its shadow.
*/
LogicPage->Draw_Line(FaceX+1, FaceY+1, FaceLine[Facing][0]+1, FaceLine[Facing][1]+1, scheme->Shadow);
LogicPage->Draw_Line(FaceX, FaceY, FaceLine[Facing][0], FaceLine[Facing][1], scheme->Highlight);
/*
** Restore the mouse.
*/
if (LogicPage == &SeenBuff) {
Show_Mouse();
}
return(true);
}
return(false);
}
/***************************************************************************
* Dial8Class::Get_Direction -- retrieves direction (0-255) of dial *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* DirType dial is pointing to *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 11/17/1994 BR : Created. *
*=========================================================================*/
DirType Dial8Class::Get_Direction(void) const
{
return(Direction);
}
/***************************************************************************
* Dial8Class::Set_Direction -- sets current direction (0-255) of dial *
* *
* INPUT: *
* DirType to set dial to *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 11/17/1994 BR : Created. *
*=========================================================================*/
void Dial8Class::Set_Direction(DirType dir)
{
Direction = dir;
Facing = Dir_Facing(Direction);
OldFacing = Facing;
Flag_To_Redraw();
}
================================================
FILE: CODE/DIAL8.H
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/DIAL8.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 : DIAL8.H *
* *
* Programmer : Bill Randolph *
* *
* Start Date : 02/06/95 *
* *
* Last Update : February 6, 1995 [BR] *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef DIAL8_H
#define DIAL8_H
class Dial8Class : public ControlClass
{
public:
/*
** Constructor/Destructor
*/
Dial8Class(int id, int x, int y, int w, int h, DirType dir);
/*
** Get/Set the direction the dial is currently pointing
*/
DirType Get_Direction(void) const;
void Set_Direction(DirType dir);
/*
** Overloaded draw routine
*/
virtual int Draw_Me(int forced = false);
protected:
/*
** Overloaded event processing routine
*/
virtual int Action(unsigned flags, KeyNumType &key);
private:
int FaceX; // x-coord of center of face
int FaceY; // y-coord of center of face
int FacePoint[8][2]; // coords of the little dial decorations
int FaceLine[8][2]; // coords for drawing the dial hand
DirType Direction; // 0-255 numerical direction of dial
FacingType Facing; // numerical facing direction of dial (0 - 7)
FacingType OldFacing; // previous Facing value
};
#endif
================================================
FILE: CODE/DIALOG.CPP
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/DIALOG.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 : DIALOG.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : September 10, 1993 *
* *
* Last Update : July 31, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* Clip_Text_Print -- Prints text with clipping and support. *
* Dialog_Box -- draws a dialog background box *
* Display_Place_Building -- Displays the "place building" dialog box. *
* Display_Select_Target -- Displays the "choose target" prompt. *
* Display_Status -- Display the player scenario status box. *
* Draw_Box -- Displays a highlighted box. *
* Draw_Caption -- Draws a caption on a dialog box. *
* Fancy_Text_Print -- Prints text with a drop shadow. *
* Plain_Text_Print -- Prints text without using a color scheme *
* Redraw_Needed -- Determine if sidebar needs to be redrawn. *
* Render_Bar_Graph -- Renders a specified bargraph. *
* Simple_Text_Print -- Prints text with a drop shadow. *
* Window_Box -- Draws a fancy box over the specified window. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
#include "defines.h" //VG 10/17/96
unsigned char * Font_Palette(int color);
/***********************************************************************************************
* Dialog_Box -- draws a dialog background box *
* *
* INPUT: *
* x,y,w,h the usual *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 01/26/1995 BR : Created. *
* 07/31/1996 JLB : Uses shapes to draw the box. *
*=============================================================================================*/
void Dialog_Box(int x, int y, int w, int h)
{
// Try to expand the box a little taller and a little wider to make room for
// the dialog box graphics in the DOS version.
#ifndef WIN32
x = max(0, x-4);
y = max(0, y-4);
w = min(w+8, 320-x);
h = min(h+8, 200-y);
#endif
WindowList[WINDOW_PARTIAL][WINDOWX] = x;
WindowList[WINDOW_PARTIAL][WINDOWY] = y;
WindowList[WINDOW_PARTIAL][WINDOWWIDTH] = w;
WindowList[WINDOW_PARTIAL][WINDOWHEIGHT] = h;
/*
** Always draw to the hidpage and then blit forward.
*/
#ifdef WIN32
GraphicViewPortClass * oldpage = Set_Logic_Page(HidPage);
#else
GraphicBufferClass * oldpage = Set_Logic_Page(HidPage);
#endif
/*
** Draw the background block.
*/
int cx = w/2;
int cy = h/2;
void const * shapedata = MFCD::Retrieve("DD-BKGND.SHP");
#ifdef WIN32
CC_Draw_Shape(shapedata, 0, cx-312, cy-192, WINDOW_PARTIAL, SHAPE_WIN_REL);
CC_Draw_Shape(shapedata, 1, cx, cy-192, WINDOW_PARTIAL, SHAPE_WIN_REL);
CC_Draw_Shape(shapedata, 2, cx-312, cy, WINDOW_PARTIAL, SHAPE_WIN_REL);
CC_Draw_Shape(shapedata, 3, cx, cy, WINDOW_PARTIAL, SHAPE_WIN_REL);
#else
CC_Draw_Shape(shapedata, 0, cx-156, cy-96, WINDOW_PARTIAL, SHAPE_WIN_REL);
#endif
/*
** Draw the side strips.
*/
shapedata = MFCD::Retrieve("DD-EDGE.SHP");
for (int yy = 0; yy < h; yy += 6) {
CC_Draw_Shape(shapedata, 0, 7*RESFACTOR, yy, WINDOW_PARTIAL, SHAPE_WIN_REL);
CC_Draw_Shape(shapedata, 1, w-((7+8)*RESFACTOR), yy, WINDOW_PARTIAL, SHAPE_WIN_REL);
}
/*
** Draw the border bars.
*/
shapedata = MFCD::Retrieve("DD-LEFT.SHP");
CC_Draw_Shape(shapedata, 0, 0, cy-100*RESFACTOR, WINDOW_PARTIAL, SHAPE_WIN_REL);
CC_Draw_Shape(shapedata, 0, 0, cy, WINDOW_PARTIAL, SHAPE_WIN_REL);
shapedata = MFCD::Retrieve("DD-RIGHT.SHP");
int rightx = w - (7*RESFACTOR);
#ifndef WIN32
rightx--;
#endif
CC_Draw_Shape(shapedata, 0, rightx, cy-100*RESFACTOR, WINDOW_PARTIAL, SHAPE_WIN_REL);
CC_Draw_Shape(shapedata, 0, rightx, cy, WINDOW_PARTIAL, SHAPE_WIN_REL);
shapedata = MFCD::Retrieve("DD-BOTM.SHP");
CC_Draw_Shape(shapedata, 0, cx-160*RESFACTOR, h-8*RESFACTOR, WINDOW_PARTIAL, SHAPE_WIN_REL);
CC_Draw_Shape(shapedata, 0, cx, h-8*RESFACTOR, WINDOW_PARTIAL, SHAPE_WIN_REL);
shapedata = MFCD::Retrieve("DD-TOP.SHP");
CC_Draw_Shape(shapedata, 0, cx-160*RESFACTOR, 0, WINDOW_PARTIAL, SHAPE_WIN_REL);
CC_Draw_Shape(shapedata, 0, cx, 0, WINDOW_PARTIAL, SHAPE_WIN_REL);
/*
** Draw the corner caps.
*/
shapedata = MFCD::Retrieve("DD-CRNR.SHP");
CC_Draw_Shape(shapedata, 0, 0, 0, WINDOW_PARTIAL, SHAPE_WIN_REL);
CC_Draw_Shape(shapedata, 1, w-(12*RESFACTOR-1), 0, WINDOW_PARTIAL, SHAPE_WIN_REL);
CC_Draw_Shape(shapedata, 2, 0, h-(12*RESFACTOR), WINDOW_PARTIAL, SHAPE_WIN_REL);
CC_Draw_Shape(shapedata, 3, w-(12*RESFACTOR-1), h-(12*RESFACTOR), WINDOW_PARTIAL, SHAPE_WIN_REL);
#ifdef WIN32
WWMouse->Draw_Mouse(&HidPage);
HidPage.Blit(SeenBuff, x, y, x, y, w, h, false);
WWMouse->Erase_Mouse(&HidPage, FALSE);
#else
// Shadow_Blit(0, 0, 320, 200, HidPage, SeenPage, Map.ShadowPage->Get_Buffer());
Hide_Mouse();
HidPage.Blit(SeenBuff);
Show_Mouse();
// Shadow_Blit(0, 0, 320, 200, HidPage, SeenPage, ((GraphicBufferClass*)Map.Shadow_Address())->Get_Buffer());
#endif
Set_Logic_Page(oldpage);
}
/***********************************************************************************************
* Draw_Box -- Displays a highlighted box. *
* *
* This will draw a highlighted box to the logicpage. It can *
* optionally fill the box with a color as well. This is a low level *
* function and thus, it doesn't do any graphic mode color adjustments. *
* *
* INPUT: x,y -- Upper left corner of the box to be drawn (pixels). *
* *
* w,h -- Width and height of box (in pixels). *
* *
* up -- Is the box rendered in the "up" stated? *
* *
* filled-- Is the box to be filled. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/28/1991 JLB : Created. *
* 05/30/1992 JLB : Embedded color codes. *
* 07/31/1992 JLB : Depressed option added. *
*=============================================================================================*/
void Draw_Box(int x, int y, int w, int h, BoxStyleEnum up, bool filled)
{
RemapControlType * scheme = GadgetClass::Get_Color_Scheme();
// Filler, Shadow, Hilite, Corner colors
BoxStyleType const ButtonColors[BOXSTYLE_COUNT] = {
{ scheme->Background, scheme->Highlight, scheme->Shadow, scheme->Corners}, // Down
{ scheme->Background, scheme->Shadow, scheme->Highlight, scheme->Corners}, // Raised
{ DKGREY, WHITE, BLACK, DKGREY}, // Disabled down
{ DKGREY, BLACK, LTGREY, DKGREY}, // Disabled up
{ BLACK, scheme->Box, scheme->Box, BLACK}, // List box
{ BLACK, scheme->Box, scheme->Box, BLACK}, // Dialog box
};
w--;
h--;
BoxStyleType const &style = ButtonColors[up];
if (filled) {
LogicPage->Fill_Rect( x, y, x+w, y+h, style.Filler);
}
switch (up) {
case (BOXSTYLE_BOX):
LogicPage->Draw_Rect(x, y, x+w, y+h, style.Highlight);
break;
case (BOXSTYLE_BORDER):
LogicPage->Draw_Rect(x+1, y+1, x+w-1, y+h-1, style.Highlight);
break;
default:
LogicPage->Draw_Line(x, y+h, x+w, y+h, style.Shadow);
LogicPage->Draw_Line(x+w, y, x+w, y+h, style.Shadow);
LogicPage->Draw_Line(x, y, x+w, y, style.Highlight);
LogicPage->Draw_Line(x, y, x, y+h, style.Highlight);
LogicPage->Put_Pixel(x, y+h, style.Corner);
LogicPage->Put_Pixel(x+w, y, style.Corner);
break;
}
}
/***********************************************************************************************
* Format_Window_String -- Separates a String into Lines. *
* This function will take a long string and break it up into lines *
* which are not longer then the window width. Any character < ' ' is *
* considered a new line marker and will be replaced by a NULL. *
* *
* INPUT: char *String - string to be formated. *
* int maxlinelen - Max length of any line in pixels. *
* *
* OUTPUT: int - number of lines string is. *
* *
* WARNINGS: The string passed in will be modified - NULLs will be put *
* into each position that will be a new line. *
* *
* HISTORY: *
* 03/27/1992 SB : Created. *
* 05/18/1995 JLB : Greatly revised for new font system. *
* 09/04/1996 BWG : Added '@' is treated as a carriage return for width calculations. *
*=============================================================================================*/
int Format_Window_String(char * string, int maxlinelen, int & width, int & height)
{
int linelen;
int lines = 0;
width = 0;
height = 0;
// In no string was passed in, then there are no lines.
if (!string) return(0);
// While there are more letters left divide the line up.
while (*string) {
linelen = 0;
height += FontHeight + FontYSpacing;
lines++;
/*
** Look for special line break character and force a line break when it is
** discovered.
*/
if (*string == '@') {
*string = '\r';
}
// While the current line is less then the max length...
while (linelen < maxlinelen && *string != '\r' && *string != '\0' && *string != '@') {
linelen += Char_Pixel_Width(*string++);
}
// if the line is to long...
if (linelen >= maxlinelen) {
/*
** Back up to an appropriate location to break.
*/
while (*string != ' ' && *string != '\r' && *string != '\0' && *string != '@') {
linelen -= Char_Pixel_Width(*string--);
}
}
/*
** Record the largest width of the worst case string.
*/
if (linelen > width) {
width = linelen;
}
/*
** Force a break at the end of the line.
*/
if (*string) {
*string++ = '\r';
}
}
return(lines);
}
/***********************************************************************************************
* Window_Box -- Draws a fancy box over the specified window. *
* *
* This routine will draw a fancy (shaded) box over the specified *
* window. This is the effect used to give the polished look to *
* screen rectangles without having to use art. *
* *
* INPUT: window -- Specified window to fill and border. *
* *
* style -- The style to render the window. *
* *
* OUTPUT: none *
* *
* WARNINGS: The rendering is done to the LogicPage. *
* *
* HISTORY: *
* 03/03/1992 JLB : Created. *
* 07/31/1992 JLB : Cool raised border effect. *
* 06/08/1994 JLB : Takes appropriate enumeration parameters. *
*=============================================================================================*/
void Window_Box(WindowNumberType window, BoxStyleEnum style)
{
int x = WindowList[window][WINDOWX];
int y = WindowList[window][WINDOWY];
int w = WindowList[window][WINDOWWIDTH];
int h = WindowList[window][WINDOWHEIGHT];
/*
** If it is to be rendered to the seenpage, then
** hide the mouse.
*/
if (LogicPage == (&SeenBuff)) Conditional_Hide_Mouse(x ,y, x+w, y+h);
Draw_Box(x, y, w, h, style, true);
/*
** Restore the mouse if it has been hidden and return.
*/
if (LogicPage == &SeenBuff) Conditional_Show_Mouse();
}
/***********************************************************************************************
* Simple_Text_Print -- Prints text with a drop shadow. *
* *
* This routine functions like Text_Print, but will render a drop *
* shadow (in black). *
* *
* The C&C gradient font colors are as follows: *
* 0 transparent (background) *
* 1 foreground color for mono-color fonts only *
* 2 shadow under characters ("drop shadow") *
* 3 shadow all around characters ("full shadow") *
* 4-10 unused *
* 11 top row *
* 12 next row *
* 13 next row *
* 14 next row *
* 15 bottom row *
* *
* INPUT: text -- Pointer to text to render. *
* *
* x,y -- Pixel coordinate for to print text. *
* *
* fore -- Foreground color. *
* *
* back -- Background color. *
* *
* flag -- Text print control flags. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/24/1991 JLB : Created. *
* 10/26/94 JLB : Handles font X spacing in a more friendly manner. *
*=============================================================================================*/
void Simple_Text_Print(char const * text, unsigned x, unsigned y, RemapControlType * fore, unsigned back, TextPrintType flag)
{
static int yspace=0; // Y spacing adjustment for font.
static int xspace=0; // Spacing adjustment for font.
void const * font=0; // Font to use.
int shadow; // Requested shadow value.
unsigned char fontpalette[16]; // Working font palette array.
int forecolor;
if (fore == NULL) {
fore = &ColorRemaps[PCOLOR_RED];
}
/*
** Init the font palette to the given background color
*/
memset(&fontpalette[0], back, 16);
forecolor = fore->Color;
/*
** A gradient font always requires special fixups for the palette
*/
int point = (flag & (TextPrintType)0x000F);
if (point == TPF_VCR || point == TPF_6PT_GRAD || point == TPF_METAL12 || point == TPF_EFNT || point == TPF_TYPE) {
/*
** If a gradient palette is specified, copy the remap table directly, otherwise
** use the foreground color as the entire font remap color.
*/
if (flag & TPF_USE_GRAD_PAL) {
memcpy(fontpalette, fore->FontRemap, 16);
forecolor = fore->Color;
if (point == TPF_TYPE) {
forecolor = fontpalette[1];
}
} else {
memset(&fontpalette[4], fore->Color, 12);
forecolor = fore->Color;
}
/*
** Medium color: set all font colors to a medium value. This flag
** overrides any gradient effects.
*/
if (flag & TPF_MEDIUM_COLOR) {
forecolor = fore->Color;
memset(&fontpalette[4], fore->Color, 12);
}
/*
** Bright color: set all font colors to a bright value. This flag
** overrides any gradient effects.
*/
if (flag & TPF_BRIGHT_COLOR) {
forecolor = fore->Bright;
memset(&fontpalette[4], fore->BrightColor, 12);
}
}
/*
** Change the current font if it differs from the font desired.
*/
#ifdef WIN32
xspace = 1;
#else
xspace = 0;
#endif
yspace = 0;
switch (point) {
case TPF_SCORE:
font = ScoreFontPtr;
break;
case TPF_METAL12:
font = Metal12FontPtr;
//xspace += 1;
break;
case TPF_MAP:
font = MapFontPtr;
xspace -= 1;
break;
case TPF_VCR:
font = VCRFontPtr;
break;
case TPF_6PT_GRAD:
font = GradFont6Ptr;
xspace -= 1;
break;
case TPF_3POINT:
xspace += 1;
font = Font3Ptr;
flag = flag & ~(TPF_DROPSHADOW|TPF_FULLSHADOW|TPF_NOSHADOW);
break;
case TPF_6POINT:
font = Font6Ptr;
xspace -= 1;
break;
case TPF_EFNT:
font = EditorFont;
#ifdef WIN32
yspace += 1;
xspace -= 1;
#endif
xspace -= 1;
break;
case TPF_8POINT:
font = Font8Ptr;
#ifdef WIN32
xspace -= 2;
yspace -= 4;
#else
xspace -= 1;
yspace -= 2;
#endif
break;
case TPF_LED:
#ifdef WIN32
xspace -= 4;
#else
xspace -= 2;
#endif
font = FontLEDPtr;
break;
case TPF_TYPE:
font = TypeFontPtr;
xspace -= 1;
#ifdef WOLAPI_INTEGRATION
xspace -= 2;
yspace += 2;
#else // I am implicitly assuming that TPF_TYPE was no longer being used, before I came along, despite the following. ajw
#ifdef GERMAN
yspace += 4; //VG 10/17/96
#endif
#endif
break;
default:
font = FontPtr;
break;
}
/*
** Change the current font palette according to the dropshadow flags.
*/
shadow = (flag & (TPF_NOSHADOW|TPF_DROPSHADOW|TPF_FULLSHADOW|TPF_LIGHTSHADOW));
switch (shadow) {
/*
** The text is rendered plain.
*/
case TPF_NOSHADOW:
fontpalette[2] = back;
fontpalette[3] = back;
xspace -= 1;
#ifdef WIN32
yspace -= 2;
#else
yspace -= 1;
#endif
break;
/*
** The text is rendered with a simple
** drop shadow.
*/
case TPF_DROPSHADOW:
fontpalette[2] = BLACK;
fontpalette[3] = back;
xspace -= 1;
break;
/*
** Special engraved text look for the options
** dialog system.
*/
case TPF_LIGHTSHADOW:
fontpalette[2] = ((14 * 16) + 7)+1;
fontpalette[3] = back;
xspace -= 1;
break;
/*
** Each letter is surrounded by black. This is used
** when the text will be over a non-plain background.
*/
case TPF_FULLSHADOW:
fontpalette[2] = BLACK;
fontpalette[3] = BLACK;
xspace -= 1;
break;
default:
break;
}
if (point != TPF_TYPE) {
fontpalette[0] = back;
fontpalette[1] = fore->Color;
}
/*
** Set the font and spacing according to the values they should be.
*/
FontXSpacing = xspace;
FontYSpacing = yspace;
Set_Font(font);
Set_Font_Palette(fontpalette);
/*
** Display the (centered) message if there is one.
*/
if (text && *text) {
switch (flag & (TPF_CENTER|TPF_RIGHT)) {
case TPF_CENTER:
x -= String_Pixel_Width(text)>>1;
break;
case TPF_RIGHT:
x -= String_Pixel_Width(text);
break;
default:
break;
}
if ((unsigned)x < LogicPage->Get_Width() && (unsigned)y < LogicPage->Get_Height()) {
LogicPage->Print(text, x, y, forecolor, back);
// LogicPage->Print(text, x, y, fore->Color, back);
}
}
}
/***********************************************************************************************
* Fancy_Text_Print -- Prints text with a drop shadow. *
* *
* This routine functions like Text_Print, but will render a drop *
* shadow (in black). *
* *
* INPUT: text -- Text number to print. *
* *
* x,y -- Pixel coordinate for to print text. *
* *
* fore -- Foreground color. *
* *
* back -- Background color. *
* *
* flag -- Text print control flags. *
* *
* OUTPUT: none *
* *
* WARNINGS: This routine is much slower than normal text print and *
* if rendered to the SEENPAGE, the intermediate rendering *
* steps could be visible. *
* *
* HISTORY: *
* 11/29/1994 JLB : Created *
*=============================================================================================*/
void Fancy_Text_Print(int text, unsigned x, unsigned y, RemapControlType * fore, unsigned back, TextPrintType flag, ...)
{
char buffer[512]; // Working staging buffer.
va_list arg; // Argument list var.
/*
** If the text number is valid, then process it.
*/
if (text != TXT_NONE) {
va_start(arg, flag);
/*
** The text string must be locked since the vsprintf function doesn't know
** how to handle EMS pointers.
*/
char const * tptr = Text_String(text);
vsprintf(buffer, tptr, arg);
va_end(arg);
Simple_Text_Print(buffer, x, y, fore, back, flag);
} else {
/*
** Just the flags are to be changed, since the text number is TXT_NONE.
*/
Simple_Text_Print((char const *)0, x, y, fore, back, flag);
}
}
/***********************************************************************************************
* Fancy_Text_Print -- Prints text with a drop shadow. *
* *
* This routine functions like Text_Print, but will render a drop *
* shadow (in black). *
* *
* INPUT: text -- Pointer to text to render. *
* *
* x,y -- Pixel coordinate for to print text. *
* *
* fore -- Foreground color. *
* *
* back -- Background color. *
* *
* flag -- Text print control flags. *
* *
* OUTPUT: none *
* *
* WARNINGS: This routine is much slower than normal text print and *
* if rendered to the SEENPAGE, the intermediate rendering *
* steps could be visible. *
* *
* HISTORY: *
* 12/24/1991 JLB : Created. *
* 10/26/94 JLB : Handles font X spacing in a more friendly manner. *
* 11/29/1994 JLB : Separated actual draw action. *
*=============================================================================================*/
void Fancy_Text_Print(char const * text, unsigned x, unsigned y, RemapControlType * fore, unsigned back, TextPrintType flag, ...)
{
char buffer[512]; // Working staging buffer.
va_list arg; // Argument list var.
/*
** If there is a valid text string pointer then build the final string into the
** working buffer before sending it to the simple string printing routine.
*/
if (text) {
/*
** Since vsprintf doesn't know about EMS pointers, be sure to surround this
** call with locking code.
*/
va_start(arg, flag);
vsprintf(buffer, text, arg);
va_end(arg);
Simple_Text_Print(buffer, x, y, fore, back, flag);
} else {
/*
** Just the flags are desired to be changed, so call the simple print routine with
** a NULL text pointer.
*/
Simple_Text_Print((char const *)0, x, y, fore, back, flag);
}
}
/***********************************************************************************************
* Clip_Text_Print -- Prints text with clipping and support. *
* *
* Use this routine to print text that that should be clipped at an arbitrary right margin *
* as well as possibly recognizing characters. Typical users of this routine would *
* be list boxes. *
* *
* INPUT: text -- Reference to the text to print. *
* *
* x,y -- Pixel coordinate of the upper left corner of the text position. *
* *
* fore -- The foreground color to use. *
* *
* back -- The background color to use. *
* *
* flag -- The text print flags to use. *
* *
* width -- The maximum pixel width to draw the text. Extra characters beyond this *
* point will not be printed. *
* *
* tabs -- Optional pointer to a series of pixel tabstop positions. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/21/1995 JLB : Created. *
*=============================================================================================*/
void Conquer_Clip_Text_Print(char const * text, unsigned x, unsigned y, RemapControlType * fore, unsigned back, TextPrintType flag, int width, int const * tabs)
{
char buffer[512];
if (text) {
strcpy(buffer, text);
/*
** Set the font and spacing characteristics according to the flag
** value passed in.
*/
Simple_Text_Print(TXT_NONE, 0, 0, TBLACK, TBLACK, flag);
char * source = &buffer[0];
unsigned offset = 0;
int processing = true;
while (processing && offset < width) {
char * ptr = strchr(source, '\t');
/*
** Zap the tab character. It will be processed later.
*/
if (ptr) {
*ptr = '\0';
}
if (*source) {
/*
** Scan forward until the end of the string is reached or the
** maximum width, whichever comes first.
*/
int w = 0;
char * bptr = source;
do {
w += Char_Pixel_Width(*bptr++);
} while (*bptr && offset+w < width);
/*
** If the maximum width has been exceeded, then remove the last
** character and signal that further processing is not necessary.
*/
if (offset+w >= width) {
bptr--;
w -= Char_Pixel_Width(*bptr);
*bptr = '\0';
processing = 0;
}
/*
** Print this text block and advance the offset accordingly.
*/
Simple_Text_Print(source, x+offset, y, fore, back, flag);
offset += w;
}
/*
** If a was the terminator for this text block, then advance
** to the next tabstop.
*/
if (ptr) {
if (tabs) {
while (offset > *tabs) {
tabs++;
}
offset = *tabs;
} else {
offset = ((offset+1 / 50) + 1) * 50;
}
source = ptr+1;
} else {
break;
}
}
}
}
/***************************************************************************
* Plain_Text_Print -- Prints text without using a color scheme *
* *
* INPUT: *
* text text to print *
* x,y coords to print at *
* fore desired foreground color *
* back desired background color *
* flag text print control flags *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* Do not use the gradient control flag with this routine! For *
* a gradient appearance, use Fancy_Text_Print. *
* Despite this routine's name, it is actually faster to call *
* Fancy_Text_Print than this routine. *
* *
* HISTORY: *
* 01/05/1996 BRR : Created. *
*=========================================================================*/
void Plain_Text_Print(int text, unsigned x, unsigned y, unsigned fore, unsigned back, TextPrintType flag, ...)
{
RemapControlType scheme;
memset(&scheme, 0, sizeof(RemapControlType));
memset(&(scheme.FontRemap[4]), fore, 12);
scheme.BrightColor = fore;
scheme.Color = fore;
scheme.Shadow = fore;
scheme.Background = fore;
scheme.Corners = fore;
scheme.Highlight = fore;
scheme.Box = fore;
scheme.Bright = fore;
scheme.Underline = fore;
scheme.Bar = fore;
Fancy_Text_Print(text, x, y, &scheme, back, flag);
}
/***************************************************************************
* Plain_Text_Print -- Prints text without using a color scheme *
* *
* INPUT: *
* text text to print *
* x,y coords to print at *
* fore desired foreground color *
* back desired background color *
* flag text print control flags *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* Do not use the gradient control flag with this routine! For *
* a gradient appearance, use Fancy_Text_Print. *
* Despite this routine's name, it is actually faster to call *
* Fancy_Text_Print than this routine. *
* *
* HISTORY: *
* 01/05/1996 BRR : Created. *
*=========================================================================*/
void Plain_Text_Print(char const * text, unsigned x, unsigned y, unsigned fore, unsigned back, TextPrintType flag, ...)
{
RemapControlType scheme;
memset(&scheme, 0, sizeof(RemapControlType));
memset(&(scheme.FontRemap[4]), fore, 12);
scheme.BrightColor = fore;
scheme.Color = fore;
scheme.Shadow = fore;
scheme.Background = fore;
scheme.Corners = fore;
scheme.Highlight = fore;
scheme.Box = fore;
scheme.Bright = fore;
scheme.Underline = fore;
scheme.Bar = fore;
Fancy_Text_Print(text, x, y, &scheme, back, flag);
}
unsigned char * Font_Palette(int color)
{
static unsigned char _fpalette[16];
memset(_fpalette, '\0', sizeof(_fpalette));
memset(&_fpalette[11], color, 5);
return(_fpalette);
}
/***********************************************************************************************
* Draw_Caption -- Draws a caption on a dialog box. *
* *
* This routine draws the caption text and any fancy filigree that the dialog may require. *
* *
* INPUT: text -- The text of the caption. This is the text number. *
* *
* x,y -- The dialog box X and Y pixel coordinate of the upper left corner. *
* *
* w -- The width of the dialog box (in pixels). *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/23/1995 JLB : Created. *
*=============================================================================================*/
void Draw_Caption(int text, int x, int y, int w)
{
Draw_Caption(Text_String(text), x, y, w);
}
void Draw_Caption(char const * text, int x, int y, int w)
{
/*
** Draw the caption.
*/
if (text != NULL && *text != '\0') {
if (Debug_Map) {
Fancy_Text_Print(text, w/2 + x, (2 * RESFACTOR) + y, GadgetClass::Get_Color_Scheme(), TBLACK, TPF_CENTER|TPF_EFNT|TPF_USE_GRAD_PAL|TPF_NOSHADOW);
} else {
Fancy_Text_Print(text, w/2 + x, (8 * RESFACTOR) + y, GadgetClass::Get_Color_Scheme(), TBLACK, TPF_CENTER|TPF_TEXT);
int length = String_Pixel_Width(text);
LogicPage->Draw_Line((x+(w/2))-(length/2), y+FontHeight+FontYSpacing + (8 * RESFACTOR), (x+(w/2))+(length/2),
y+FontHeight+FontYSpacing + (8 * RESFACTOR), GadgetClass::Get_Color_Scheme()->Box);
}
}
}
================================================
FILE: CODE/DIBAPI.H
================================================
/*
** 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 .
*/
#ifndef DIBAPI_H
#define DIBAPI_H
/*
* dibapi.h
*
* Copyright (c) 1991 Microsoft Corporation. All rights reserved
*
* Header file for Device-Independent Bitmap (DIB) API. Provides
* function prototypes and constants for the following functions:
*
* BitmapToDIB() - Creates a DIB from a bitmap
* ChangeBitmapFormat() - Changes a bitmap to a specified DIB format
* ChangeDIBFormat() - Changes a DIB's BPP and/or compression format
* CopyScreenToBitmap() - Copies entire screen to a standard Bitmap
* CopyScreenToDIB() - Copies entire screen to a DIB
* CopyWindowToBitmap() - Copies a window to a standard Bitmap
* CopyWindowToDIB() - Copies a window to a DIB
* CreateDIBPalette() - Creates a palette from a DIB
* CreateDIB() - Creates a new DIB
* DestroyDIB() - Deletes DIB when finished using it
* DIBError() - Displays message box with error message
* DIBHeight() - Gets the DIB height
* DIBNumColors() - Calculates number of colors in the DIB's color table
* DIBToBitmap() - Creates a bitmap from a DIB
* DIBWidth() - Gets the DIB width
* FindDIBBits() - Sets pointer to the DIB bits
* GetSystemPalette() - Gets the current palette
* LoadDIB() - Loads a DIB from a file
* PaintBitmap() - Displays standard bitmap in the specified DC
* PaintDIB() - Displays DIB in the specified DC
* PalEntriesOnDevice() - Gets the number of palette entries
* PaletteSize() - Calculates the buffer size required by a palette
* PrintDIB() - Prints the specified DIB
* PrintScreen() - Prints the entire screen
* PrintWindow() - Prints all or part of a window
* SaveDIB() - Saves the specified dib in a file
*
* See the file DIBAPI.TXT for more information about these functions.
*
* ajw added
* LoadDIB_FromMemory() - Loads a DIB from BMP file data located at a location in memory.
*
*/
/* Handle to a DIB */
#define HDIB HANDLE
/* Print Area selection */
#define PW_WINDOW 1
#define PW_CLIENT 2
/* Print Options selection */
#define PW_BESTFIT 1
#define PW_STRETCHTOPAGE 2
#define PW_SCALE 3
/* DIB Macros*/
// WIDTHBYTES performs DWORD-aligning of DIB scanlines. The "bits"
// parameter is the bit count for the scanline (biWidth * biBitCount),
// and this macro returns the number of DWORD-aligned bytes needed
// to hold those bits.
#define WIDTHBYTES(bits) (((bits) + 31) / 32 * 4)
/* Error constants */
enum {
ERR_MIN = 0, // All error #s >= this value
ERR_NOT_DIB = 0, // Tried to load a file, NOT a DIB!
ERR_MEMORY, // Not enough memory!
ERR_READ, // Error reading file!
ERR_LOCK, // Error on a GlobalLock()!
ERR_OPEN, // Error opening a file!
ERR_CREATEPAL, // Error creating palette.
ERR_GETDC, // Couldn't get a DC.
ERR_CREATEDDB, // Error create a DDB.
ERR_STRETCHBLT, // StretchBlt() returned failure.
ERR_STRETCHDIBITS, // StretchDIBits() returned failure.
ERR_SETDIBITSTODEVICE, // SetDIBitsToDevice() failed.
ERR_STARTDOC, // Error calling StartDoc().
ERR_NOGDIMODULE, // Couldn't find GDI module in memory.
ERR_SETABORTPROC, // Error calling SetAbortProc().
ERR_STARTPAGE, // Error calling StartPage().
ERR_NEWFRAME, // Error calling NEWFRAME escape.
ERR_ENDPAGE, // Error calling EndPage().
ERR_ENDDOC, // Error calling EndDoc().
ERR_SETDIBITS, // Error calling SetDIBits().
ERR_FILENOTFOUND, // Error opening file in GetDib()
ERR_INVALIDHANDLE, // Invalid Handle
ERR_DIBFUNCTION, // Error on call to DIB function
ERR_MAX // All error #s < this value
};
/* Function prototypes */
HDIB FAR BitmapToDIB (HBITMAP hBitmap, HPALETTE hPal);
HDIB FAR ChangeBitmapFormat (HBITMAP hBitmap,
WORD wBitCount,
DWORD dwCompression,
HPALETTE hPal);
HDIB FAR ChangeDIBFormat (HDIB hDIB, WORD wBitCount,
DWORD dwCompression);
HBITMAP FAR CopyScreenToBitmap (LPRECT);
HDIB FAR CopyScreenToDIB (LPRECT);
HBITMAP FAR CopyWindowToBitmap (HWND, WORD);
HDIB FAR CopyWindowToDIB (HWND, WORD);
HPALETTE FAR CreateDIBPalette (HDIB hDIB);
HDIB FAR CreateDIB(DWORD, DWORD, WORD);
WORD FAR DestroyDIB (HDIB);
void FAR DIBError (int ErrNo);
DWORD FAR DIBHeight (LPCSTR lpDIB);
WORD FAR DIBNumColors (LPCSTR lpDIB);
HBITMAP FAR DIBToBitmap (HDIB hDIB, HPALETTE hPal);
DWORD FAR DIBWidth (LPCSTR lpDIB);
LPSTR FAR FindDIBBits (LPCSTR lpDIB);
HPALETTE FAR GetSystemPalette (void);
HDIB FAR LoadDIB (LPSTR);
BOOL FAR PaintBitmap (HDC, LPRECT, HBITMAP, LPRECT, HPALETTE);
BOOL FAR PaintDIB (HDC, LPRECT, HDIB, LPRECT, HPALETTE);
int FAR PalEntriesOnDevice (HDC hDC);
WORD FAR PaletteSize (LPCSTR lpDIB);
WORD FAR PrintDIB (HDIB, WORD, WORD, WORD, LPSTR);
WORD FAR PrintScreen (LPRECT, WORD, WORD, WORD, LPSTR);
WORD FAR PrintWindow (HWND, WORD, WORD, WORD, WORD, LPSTR);
WORD FAR SaveDIB (HDIB, LPSTR);
// ajw added
HDIB LoadDIB_FromMemory( const unsigned char* pData, DWORD dwBitsSize );
#endif
================================================
FILE: CODE/DIBFILE.CPP
================================================
/*
** 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 .
*/
//*******************************************************************
//
// file.c
//
// Source file for Device-Independent Bitmap (DIB) API. Provides
// the following functions:
//
// SaveDIB() - Saves the specified dib in a file
// LoadDIB() - Loads a DIB from a file
// DestroyDIB() - Deletes DIB when finished using it
//
// Development Team: Mark Bader
// Patrick Schreiber
// Garrett McAuliffe
// Eric Flo
// Tony Claflin
//
// Written by Microsoft Product Support Services, Developer Support.
// COPYRIGHT:
//
// (C) Copyright Microsoft Corp. 1993. All rights reserved.
//
// You have a royalty-free right to use, modify, reproduce and
// distribute the Sample Files (and/or any modified version) in
// any way you find useful, provided that you agree that
// Microsoft has no warranty obligations or liability for any
// Sample Application Files which are modified.
//
//*******************************************************************
#include
#include
#include
#include
#include
#include
#include
#include "dibutil.h"
#include "dibapi.h"
//#include "WolDebug.h"
/*
* Dib Header Marker - used in writing DIBs to files
*/
#define DIB_HEADER_MARKER ((WORD) ('M' << 8) | 'B')
/*********************************************************************
*
* Local Function Prototypes
*
*********************************************************************/
HANDLE ReadDIBFile(int);
BOOL MyRead(int, LPSTR, DWORD);
BOOL SaveDIBFile(void);
BOOL WriteDIB(LPSTR, HANDLE);
DWORD PASCAL MyWrite(int, VOID FAR *, DWORD);
/*************************************************************************
*
* LoadDIB()
*
* Loads the specified DIB from a file, allocates memory for it,
* and reads the disk file into the memory.
*
*
* Parameters:
*
* LPSTR lpFileName - specifies the file to load a DIB from
*
* Returns: A handle to a DIB, or NULL if unsuccessful.
*
* NOTE: The DIB API were not written to handle OS/2 DIBs; This
* function will reject any file that is not a Windows DIB.
*
* History: Date Author Reason
* 9/15/91 Mark Bader Based on DIBVIEW
*
*************************************************************************/
HDIB FAR LoadDIB(LPSTR lpFileName)
{
HDIB hDIB;
int hFile;
OFSTRUCT ofs;
/*
* Set the cursor to a hourglass, in case the loading operation
* takes more than a sec, the user will know what's going on.
*/
SetCursor(LoadCursor(NULL, IDC_WAIT));
if ((hFile = OpenFile(lpFileName, &ofs, OF_READ)) != -1)
{
hDIB = ReadDIBFile(hFile);
_lclose(hFile);
SetCursor(LoadCursor(NULL, IDC_ARROW));
return hDIB;
}
else
{
// DIBError(ERR_FILENOTFOUND);
SetCursor(LoadCursor(NULL, IDC_ARROW));
return NULL;
}
}
/*************************************************************************
*
* SaveDIB()
*
* Saves the specified DIB into the specified file name on disk. No
* error checking is done, so if the file already exists, it will be
* written over.
*
* Parameters:
*
* HDIB hDib - Handle to the dib to save
*
* LPSTR lpFileName - pointer to full pathname to save DIB under
*
* Return value: 0 if successful, or one of:
* ERR_INVALIDHANDLE
* ERR_OPEN
* ERR_LOCK
*
* History:
*
* NOTE: The DIB API were not written to handle OS/2 DIBs, so this
* function will not save a file if it is not a Windows DIB.
*
* History: Date Author Reason
* 9/15/91 Mark Bader Taken from DIBVIEW (which was taken
* from SHOWDIB)
* 1/30/92 Mark Bader Fixed problem of writing too many
* bytes to the file
* 6/24/92 Mark Bader Added check for OS/2 DIB
*
*************************************************************************/
WORD FAR SaveDIB(HDIB hDib, LPSTR lpFileName)
{
BITMAPFILEHEADER bmfHdr; // Header for Bitmap file
LPBITMAPINFOHEADER lpBI; // Pointer to DIB info structure
int fh; // file handle for opened file
OFSTRUCT of; // OpenFile structure
DWORD dwDIBSize;
DWORD dwError; // Error return from MyWrite
if (!hDib)
return ERR_INVALIDHANDLE;
fh = OpenFile(lpFileName, &of, OF_CREATE | OF_READWRITE);
if (fh == -1)
return ERR_OPEN;
/*
* Get a pointer to the DIB memory, the first of which contains
* a BITMAPINFO structure
*/
lpBI = (LPBITMAPINFOHEADER)GlobalLock(hDib);
if (!lpBI)
return ERR_LOCK;
// Check to see if we're dealing with an OS/2 DIB. If so, don't
// save it because our functions aren't written to deal with these
// DIBs.
if (lpBI->biSize != sizeof(BITMAPINFOHEADER))
{
GlobalUnlock(hDib);
return ERR_NOT_DIB;
}
/*
* Fill in the fields of the file header
*/
/* Fill in file type (first 2 bytes must be "BM" for a bitmap) */
bmfHdr.bfType = DIB_HEADER_MARKER; // "BM"
// Calculating the size of the DIB is a bit tricky (if we want to
// do it right). The easiest way to do this is to call GlobalSize()
// on our global handle, but since the size of our global memory may have
// been padded a few bytes, we may end up writing out a few too
// many bytes to the file (which may cause problems with some apps,
// like HC 3.0).
//
// So, instead let's calculate the size manually.
//
// To do this, find size of header plus size of color table. Since the
// first DWORD in both BITMAPINFOHEADER and BITMAPCOREHEADER conains
// the size of the structure, let's use this.
dwDIBSize = *(LPDWORD)lpBI + PaletteSize((LPSTR)lpBI); // Partial Calculation
// Now calculate the size of the image
if ((lpBI->biCompression == BI_RLE8) || (lpBI->biCompression == BI_RLE4)) {
// It's an RLE bitmap, we can't calculate size, so trust the
// biSizeImage field
dwDIBSize += lpBI->biSizeImage;
}
else {
DWORD dwBmBitsSize; // Size of Bitmap Bits only
// It's not RLE, so size is Width (DWORD aligned) * Height
dwBmBitsSize = WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) * lpBI->biHeight;
dwDIBSize += dwBmBitsSize;
// Now, since we have calculated the correct size, why don't we
// fill in the biSizeImage field (this will fix any .BMP files which
// have this field incorrect).
lpBI->biSizeImage = dwBmBitsSize;
}
// Calculate the file size by adding the DIB size to sizeof(BITMAPFILEHEADER)
bmfHdr.bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER);
bmfHdr.bfReserved1 = 0;
bmfHdr.bfReserved2 = 0;
/*
* Now, calculate the offset the actual bitmap bits will be in
* the file -- It's the Bitmap file header plus the DIB header,
* plus the size of the color table.
*/
bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + lpBI->biSize +
PaletteSize((LPSTR)lpBI);
/* Write the file header */
_lwrite(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER));
/*
* Write the DIB header and the bits -- use local version of
* MyWrite, so we can write more than 32767 bytes of data
*/
dwError = MyWrite(fh, (LPSTR)lpBI, dwDIBSize);
GlobalUnlock(hDib);
_lclose(fh);
if (dwError == 0)
return ERR_OPEN; // oops, something happened in the write
else
return 0; // Success code
}
/*************************************************************************
*
* DestroyDIB ()
*
* Purpose: Frees memory associated with a DIB
*
* Returns: Nothing
*
* History: Date Author Reason
* 9/15/91 Mark Bader Created
*
*************************************************************************/
WORD FAR DestroyDIB(HDIB hDib)
{
GlobalFree(hDib);
return 0;
}
//************************************************************************
//
// Auxiliary Functions which the above procedures use
//
//************************************************************************
/*************************************************************************
*
* Function: ReadDIBFile (int)
*
* Purpose: Reads in the specified DIB file into a global chunk of
* memory.
*
* Returns: A handle to a dib (hDIB) if successful.
* NULL if an error occurs.
*
* Comments: BITMAPFILEHEADER is stripped off of the DIB. Everything
* from the end of the BITMAPFILEHEADER structure on is
* returned in the global memory handle.
*
*
* NOTE: The DIB API were not written to handle OS/2 DIBs, so this
* function will reject any file that is not a Windows DIB.
*
* History: Date Author Reason
* 9/15/91 Mark Bader Based on DIBVIEW
* 6/25/92 Mark Bader Added check for OS/2 DIB
* 7/21/92 Mark Bader Added code to deal with bfOffBits
* field in BITMAPFILEHEADER
* 9/11/92 Mark Bader Fixed Realloc Code to free original mem
*
*************************************************************************/
HANDLE ReadDIBFile(int hFile)
{
BITMAPFILEHEADER bmfHeader;
DWORD dwBitsSize;
UINT nNumColors; // Number of colors in table
HANDLE hDIB;
HANDLE hDIBtmp; // Used for GlobalRealloc() //MPB
LPBITMAPINFOHEADER lpbi;
DWORD offBits;
/*
* get length of DIB in bytes for use when reading
*/
dwBitsSize = filelength(hFile);
// Allocate memory for header & color table. We'll enlarge this
// memory as needed.
hDIB = GlobalAlloc(GMEM_MOVEABLE,
(DWORD)(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)));
if (!hDIB) return NULL;
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
if (!lpbi)
{
GlobalFree(hDIB);
return NULL;
}
// read the BITMAPFILEHEADER from our file
if (sizeof (BITMAPFILEHEADER) != _lread (hFile, (LPSTR)&bmfHeader, sizeof (BITMAPFILEHEADER)))
goto ErrExit;
if (bmfHeader.bfType != 0x4d42) /* 'BM' */
goto ErrExit;
// read the BITMAPINFOHEADER
if (sizeof(BITMAPINFOHEADER) != _lread (hFile, (LPSTR)lpbi, sizeof(BITMAPINFOHEADER)))
goto ErrExit;
// Check to see that it's a Windows DIB -- an OS/2 DIB would cause
// strange problems with the rest of the DIB API since the fields
// in the header are different and the color table entries are
// smaller.
//
// If it's not a Windows DIB (e.g. if biSize is wrong), return NULL.
if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
goto ErrExit;
// Now determine the size of the color table and read it. Since the
// bitmap bits are offset in the file by bfOffBits, we need to do some
// special processing here to make sure the bits directly follow
// the color table (because that's the format we are susposed to pass
// back)
nNumColors = (UINT)lpbi->biClrUsed;
if (!nNumColors)
{
// no color table for 24-bit, default size otherwise
if (lpbi->biBitCount != 24)
nNumColors = 1 << lpbi->biBitCount; /* standard size table */
}
// fill in some default values if they are zero
if (lpbi->biClrUsed == 0)
lpbi->biClrUsed = nNumColors;
if (lpbi->biSizeImage == 0)
{
lpbi->biSizeImage = ((((lpbi->biWidth * (DWORD)lpbi->biBitCount) + 31) & ~31) >> 3)
* lpbi->biHeight;
}
// get a proper-sized buffer for header, color table and bits
GlobalUnlock(hDIB);
hDIBtmp = GlobalReAlloc(hDIB, lpbi->biSize +
nNumColors * sizeof(RGBQUAD) +
lpbi->biSizeImage, 0);
if (!hDIBtmp) // can't resize buffer for loading
goto ErrExitNoUnlock; //MPB
else
hDIB = hDIBtmp;
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
// read the color table
_lread (hFile, (LPSTR)(lpbi) + lpbi->biSize, nNumColors * sizeof(RGBQUAD));
// offset to the bits from start of DIB header
offBits = lpbi->biSize + nNumColors * sizeof(RGBQUAD);
// If the bfOffBits field is non-zero, then the bits might *not* be
// directly following the color table in the file. Use the value in
// bfOffBits to seek the bits.
if (bmfHeader.bfOffBits != 0L)
_llseek(hFile, bmfHeader.bfOffBits, SEEK_SET);
if (MyRead(hFile, (LPSTR)lpbi + offBits, lpbi->biSizeImage))
goto OKExit;
ErrExit:
GlobalUnlock(hDIB);
ErrExitNoUnlock:
GlobalFree(hDIB);
return NULL;
OKExit:
GlobalUnlock(hDIB);
return hDIB;
}
/*************************************************************************
Function: MyRead (int, LPSTR, DWORD)
Purpose: Routine to read files greater than 64K in size.
Returns: TRUE if successful.
FALSE if an error occurs.
History: Date Author Reason
9/15/91 Mark Bader Based on DIBVIEW
*************************************************************************/
BOOL MyRead(int hFile, LPSTR lpBuffer, DWORD dwSize)
{
char huge *lpInBuf = (char huge *)lpBuffer;
int nBytes;
/*
* Read in the data in 32767 byte chunks (or a smaller amount if it's
* the last chunk of data read)
*/
while (dwSize)
{
nBytes = (int)(dwSize > (DWORD)32767 ? 32767 : LOWORD (dwSize));
if (_lread(hFile, (LPSTR)lpInBuf, nBytes) != (WORD)nBytes)
return FALSE;
dwSize -= nBytes;
lpInBuf += nBytes;
}
return TRUE;
}
/****************************************************************************
FUNCTION : MyWrite(int fh, VOID FAR *pv, DWORD ul)
PURPOSE : Writes data in steps of 32k till all the data is written.
Normal _lwrite uses a WORD as 3rd parameter, so it is
limited to 32767 bytes, but this procedure is not.
RETURNS : 0 - If write did not proceed correctly.
number of bytes written otherwise.
History: Date Author Reason
9/15/91 Mark Bader Based on DIBVIEW
****************************************************************************/
DWORD PASCAL MyWrite(int iFileHandle, VOID FAR *lpBuffer, DWORD dwBytes)
{
DWORD dwBytesTmp = dwBytes; // Save # of bytes for return value
BYTE huge *hpBuffer = (BYTE huge *)lpBuffer; // make a huge pointer to the data
/*
* Write out the data in 32767 byte chunks.
*/
while (dwBytes > 32767)
{
if (_lwrite(iFileHandle, (LPSTR)hpBuffer, (WORD)32767) != 32767)
return 0;
dwBytes -= 32767;
hpBuffer += 32767;
}
/* Write out the last chunk (which is < 32767 bytes) */
if (_lwrite(iFileHandle, (LPSTR)hpBuffer, (WORD)dwBytes) != (WORD)dwBytes)
return 0;
return dwBytesTmp;
}
// ajw added
// Added to allow "loading" from a location in memory.
// A modification of ReadDIBFile(), above.
//***********************************************************************************************
HDIB LoadDIB_FromMemory( const unsigned char* pData, DWORD dwBitsSize )
{
BITMAPFILEHEADER bmfHeader;
UINT nNumColors; // Number of colors in table
HANDLE hDIB;
HANDLE hDIBtmp; // Used for GlobalRealloc() //MPB
LPBITMAPINFOHEADER lpbi;
DWORD offBits;
const unsigned char* const pDataStart = pData;
const unsigned char* pDataEnd = pData + dwBitsSize; // One char past end of "file".
// Allocate memory for header & color table. We'll enlarge this
// memory as needed.
// debugprint( "LoadDIB_FromMemory, GlobalAlloc\n" );
hDIB = GlobalAlloc(GMEM_MOVEABLE, (DWORD)(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)));
// debugprint( "hDIB from GlobalALloc is %i\n", hDIB );
if (!hDIB)
{
// debugprint( "LoadDIB_FromMemory error: failed alloc\n" );
return NULL;
}
// debugprint( "LoadDIB_FromMemory, lpbi Lock\n" );
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
// debugprint( "lpbi is %i\n", lpbi );
if (!lpbi)
{
// debugprint( "LoadDIB_FromMemory error: failed lock\n" );
GlobalFree(hDIB);
return NULL;
}
// read the BITMAPFILEHEADER from our file
// if (sizeof (BITMAPFILEHEADER) != _lread (hFile, (LPSTR)&bmfHeader, sizeof (BITMAPFILEHEADER)))
// goto ErrExit;
if( pData + sizeof( BITMAPFILEHEADER ) >= pDataEnd )
{
// debugprint( "LoadDIB_FromMemory error: bad size\n" );
goto ErrExit;
}
// debugprint( "LoadDIB_FromMemory, memcpy BITMAPFILEHEADER %i bytes\n", sizeof( BITMAPFILEHEADER ) );
memcpy( &bmfHeader, pData, sizeof( BITMAPFILEHEADER ) );
pData += sizeof( BITMAPFILEHEADER );
if (bmfHeader.bfType != 0x4d42) /* 'BM' */
{
// debugprint( "LoadDIB_FromMemory error: no BM\n" );
goto ErrExit;
}
// read the BITMAPINFOHEADER
// if (sizeof(BITMAPINFOHEADER) != _lread (hFile, (LPSTR)lpbi, sizeof(BITMAPINFOHEADER)))
// goto ErrExit;
if( pData + sizeof( BITMAPINFOHEADER ) >= pDataEnd )
{
// debugprint( "LoadDIB_FromMemory error: bad size 2\n" );
goto ErrExit;
}
// debugprint( "LoadDIB_FromMemory, memcpy BITMAPINFOHEADER %i bytes\n", sizeof( BITMAPINFOHEADER ) );
memcpy( lpbi, pData, sizeof( BITMAPINFOHEADER ) );
pData += sizeof( BITMAPINFOHEADER );
// Check to see that it's a Windows DIB -- an OS/2 DIB would cause
// strange problems with the rest of the DIB API since the fields
// in the header are different and the color table entries are
// smaller.
//
// If it's not a Windows DIB (e.g. if biSize is wrong), return NULL.
if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
{
// debugprint( "LoadDIB_FromMemory error: lpbi->biSize bad\n" );
goto ErrExit;
}
if( lpbi->biCompression != BI_RGB )
{
// debugprint( "LoadDIB_FromMemory error: Image is compressed\n" );
goto ErrExit;
}
// Now determine the size of the color table and read it. Since the
// bitmap bits are offset in the file by bfOffBits, we need to do some
// special processing here to make sure the bits directly follow
// the color table (because that's the format we are susposed to pass
// back)
nNumColors = (UINT)lpbi->biClrUsed;
if (!nNumColors)
{
// no color table for 24-bit, default size otherwise
if (lpbi->biBitCount != 24)
nNumColors = 1 << lpbi->biBitCount; /* standard size table */
}
// fill in some default values if they are zero
if (lpbi->biClrUsed == 0)
lpbi->biClrUsed = nNumColors;
// debugprint( "biSizeImage is %i. I would say it was %i, because the bpp is %i.\n", lpbi->biSizeImage, ((((lpbi->biWidth * (DWORD)lpbi->biBitCount) + 31) & ~31) >> 3) * lpbi->biHeight, lpbi->biBitCount );
if (lpbi->biSizeImage == 0)
{
lpbi->biSizeImage = ((((lpbi->biWidth * (DWORD)lpbi->biBitCount) + 31) & ~31) >> 3) * lpbi->biHeight;
}
// get a proper-sized buffer for header, color table and bits
GlobalUnlock(hDIB);
// debugprint( "LoadDIB_FromMemory, GlobalReAlloc: lpbi->biSize=%i, nNumColors=%i, lpbi->biSizeImage=%i\n", lpbi->biSize, nNumColors,lpbi->biSizeImage );
hDIBtmp = GlobalReAlloc(hDIB, lpbi->biSize + nNumColors * sizeof(RGBQUAD) + lpbi->biSizeImage, 0);
if (!hDIBtmp) // can't resize buffer for loading
{
// debugprint( "LoadDIB_FromMemory error: realloc failed\n" );
goto ErrExitNoUnlock; //MPB
}
else
hDIB = hDIBtmp;
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
// read the color table
// _lread (hFile, (LPSTR)(lpbi) + lpbi->biSize, nNumColors * sizeof(RGBQUAD));
// debugprint( "LoadDIB_FromMemory, memcpy color table %i colors, so %i bytes\n", nNumColors, nNumColors * sizeof(RGBQUAD) );
memcpy( (LPSTR)(lpbi) + lpbi->biSize, pData, nNumColors * sizeof(RGBQUAD) );
pData += nNumColors * sizeof(RGBQUAD);
// offset to the bits from start of DIB header
offBits = lpbi->biSize + nNumColors * sizeof(RGBQUAD);
// If the bfOffBits field is non-zero, then the bits might *not* be
// directly following the color table in the file. Use the value in
// bfOffBits to seek the bits.
if (bmfHeader.bfOffBits != 0L)
// _llseek(hFile, bmfHeader.bfOffBits, SEEK_SET);
pData = pDataStart + bmfHeader.bfOffBits;
// debugprint( "bmfHeader.bfOffBits is %i\n", bmfHeader.bfOffBits );
// if (MyRead(hFile, (LPSTR)lpbi + offBits, lpbi->biSizeImage))
// goto OKExit;
// debugprint( "Checking that pData(%i) + biSizeImage(%i), which is %i, is equal to pDataEnd(%i)\n",
// pData, lpbi->biSizeImage, pData + lpbi->biSizeImage, pDataEnd );
// if( pData + lpbi->biSizeImage != pDataEnd ) condition relaxed
// {
// debugprint( "LoadDIB_FromMemory error: bad size 3\n" );
// goto ErrExit;
// }
// debugprint( "LoadDIB_FromMemory, memcpy the bits, %i bytes. Image is w %i, h.%i\n",
// lpbi->biSizeImage, lpbi->biWidth, lpbi->biHeight );
// debugprint( "Writing to lpbi (%i) + offBits (%i)\n", lpbi, offBits );
memcpy( (LPSTR)lpbi + offBits, pData, lpbi->biSizeImage );
// pData += lpbi->biSizeImage;
// if( pData != pDataEnd ) // Should end up one byte past end of data. - condition relaxed
// debugprint( "LoadDIB_FromMemory: ERROR! Ended up at %i instead of %i\n", pData, pDataEnd );
goto OKExit;
ErrExit:
GlobalUnlock(hDIB);
ErrExitNoUnlock:
GlobalFree(hDIB);
// debugprint( "LoadDIB_FromMemory Error!\n" );
return NULL;
OKExit:
GlobalUnlock(hDIB);
return hDIB;
}
================================================
FILE: CODE/DIBUTIL.CPP
================================================
/*
** 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 .
*/
//**********************************************************************
//
// dibutil.c
//
// Source file for Device-Independent Bitmap (DIB) API. Provides
// the following functions:
//
// CreateDIB() - Creates new DIB
// FindDIBBits() - Sets pointer to the DIB bits
// DIBWidth() - Gets the width of the DIB
// DIBHeight() - Gets the height of the DIB
// PaletteSize() - Calculates the buffer size required by a palette
// DIBNumColors() - Calculates number of colors in the DIB's color table
// CreateDIBPalette() - Creates a palette from a DIB
// DIBToBitmap() - Creates a bitmap from a DIB
// BitmapToDIB() - Creates a DIB from a bitmap
// PalEntriesOnDevice()- Gets the number of palette entries of a device
// GetSystemPalette() - Returns a handle to the current system palette
// AllocRoomForDIB() - Allocates memory for a DIB
// ChangeDIBFormat() - Changes a DIB's BPP and/or compression format
// ChangeBitmapFormat()- Changes a bitmap to a DIB with specified BPP and
// compression format
//
// Development Team: Mark Bader
// Patrick Schreiber
// Garrett McAuliffe
// Eric Flo
// Tony Claflin
//
// Written by Microsoft Product Support Services, Developer Support.
// COPYRIGHT:
//
// (C) Copyright Microsoft Corp. 1993. All rights reserved.
//
// You have a royalty-free right to use, modify, reproduce and
// distribute the Sample Files (and/or any modified version) in
// any way you find useful, provided that you agree that
// Microsoft has no warranty obligations or liability for any
// Sample Application Files which are modified.
//
//**********************************************************************
/* header files */
#include
#include
#include "dibapi.h"
#include "dibutil.h"
#include
/*************************************************************************
*
* CreateDIB()
*
* Parameters:
*
* DWORD dwWidth - Width for new bitmap, in pixels
* DWORD dwHeight - Height for new bitmap
* WORD wBitCount - Bit Count for new DIB (1, 4, 8, or 24)
*
* Return Value:
*
* HDIB - Handle to new DIB
*
* Description:
*
* This function allocates memory for and initializes a new DIB by
* filling in the BITMAPINFOHEADER, allocating memory for the color
* table, and allocating memory for the bitmap bits. As with all
* HDIBs, the header, colortable and bits are all in one contiguous
* memory block. This function is similar to the CreateBitmap()
* Windows API.
*
* The colortable and bitmap bits are left uninitialized (zeroed) in the
* returned HDIB.
*
*
* History: Date Author Reason
* 3/20/92 Mark Bader Created
*
************************************************************************/
HDIB FAR CreateDIB(DWORD dwWidth, DWORD dwHeight, WORD wBitCount)
{
BITMAPINFOHEADER bi; // bitmap header
LPBITMAPINFOHEADER lpbi; // pointer to BITMAPINFOHEADER
DWORD dwLen; // size of memory block
HDIB hDIB;
DWORD dwBytesPerLine; // Number of bytes per scanline
// Make sure bits per pixel is valid
if (wBitCount <= 1)
wBitCount = 1;
else if (wBitCount <= 4)
wBitCount = 4;
else if (wBitCount <= 8)
wBitCount = 8;
else if (wBitCount <= 24)
wBitCount = 24;
else
wBitCount = 4; // set default value to 4 if parameter is bogus
// initialize BITMAPINFOHEADER
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = dwWidth; // fill in width from parameter
bi.biHeight = dwHeight; // fill in height from parameter
bi.biPlanes = 1; // must be 1
bi.biBitCount = wBitCount; // from parameter
bi.biCompression = BI_RGB;
bi.biSizeImage = 0; // 0's here mean "default"
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
// calculate size of memory block required to store the DIB. This
// block should be big enough to hold the BITMAPINFOHEADER, the color
// table, and the bits
dwBytesPerLine = WIDTHBYTES(wBitCount * dwWidth);
dwLen = bi.biSize + PaletteSize((LPSTR)&bi) + (dwBytesPerLine * dwHeight);
// alloc memory block to store our bitmap
hDIB = GlobalAlloc(GHND, dwLen);
// major bummer if we couldn't get memory block
if (!hDIB)
{
return NULL;
}
// lock memory and get pointer to it
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
// use our bitmap info structure to fill in first part of
// our DIB with the BITMAPINFOHEADER
*lpbi = bi;
// Since we don't know what the colortable and bits should contain,
// just leave these blank. Unlock the DIB and return the HDIB.
GlobalUnlock(hDIB);
/* return handle to the DIB */
return hDIB;
}
/*************************************************************************
*
* FindDIBBits()
*
* Parameter:
*
* LPSTR lpDIB - pointer to packed-DIB memory block
*
* Return Value:
*
* LPSTR - pointer to the DIB bits
*
* Description:
*
* This function calculates the address of the DIB's bits and returns a
* pointer to the DIB bits.
*
* History: Date Author Reason
* 6/01/91 Garrett McAuliffe Created
* 9/15/91 Patrick Schreiber Added header and comments
*
************************************************************************/
LPSTR FAR FindDIBBits(LPCSTR lpDIB)
{
return (LPSTR)(lpDIB + *(LPDWORD)lpDIB + PaletteSize(lpDIB));
}
/*************************************************************************
*
* DIBWidth()
*
* Parameter:
*
* LPSTR lpDIB - pointer to packed-DIB memory block
*
* Return Value:
*
* DWORD - width of the DIB
*
* Description:
*
* This function gets the width of the DIB from the BITMAPINFOHEADER
* width field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER
* width field if it is an OS/2-style DIB.
*
* History: Date Author Reason
* 6/01/91 Garrett McAuliffe Created
* 9/15/91 Patrick Schreiber Added header and comments
*
************************************************************************/
DWORD FAR DIBWidth(LPCSTR lpDIB)
{
LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB
LPBITMAPCOREHEADER lpbmc; // pointer to an OS/2-style DIB
/* point to the header (whether Win 3.0 and OS/2) */
lpbmi = (LPBITMAPINFOHEADER)lpDIB;
lpbmc = (LPBITMAPCOREHEADER)lpDIB;
/* return the DIB width if it is a Win 3.0 DIB */
if (lpbmi->biSize == sizeof(BITMAPINFOHEADER))
return lpbmi->biWidth;
else /* it is an OS/2 DIB, so return its width */
return (DWORD)lpbmc->bcWidth;
}
/*************************************************************************
*
* DIBHeight()
*
* Parameter:
*
* LPSTR lpDIB - pointer to packed-DIB memory block
*
* Return Value:
*
* DWORD - height of the DIB
*
* Description:
*
* This function gets the height of the DIB from the BITMAPINFOHEADER
* height field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER
* height field if it is an OS/2-style DIB.
*
* History: Date Author Reason
* 6/01/91 Garrett McAuliffe Created
* 9/15/91 Patrick Schreiber Added header and comments
*
************************************************************************/
DWORD FAR DIBHeight(LPCSTR lpDIB)
{
LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB
LPBITMAPCOREHEADER lpbmc; // pointer to an OS/2-style DIB
/* point to the header (whether OS/2 or Win 3.0 */
lpbmi = (LPBITMAPINFOHEADER)lpDIB;
lpbmc = (LPBITMAPCOREHEADER)lpDIB;
/* return the DIB height if it is a Win 3.0 DIB */
if (lpbmi->biSize == sizeof(BITMAPINFOHEADER))
return lpbmi->biHeight;
else /* it is an OS/2 DIB, so return its height */
return (DWORD)lpbmc->bcHeight;
}
/*************************************************************************
*
* PaletteSize()
*
* Parameter:
*
* LPSTR lpDIB - pointer to packed-DIB memory block
*
* Return Value:
*
* WORD - size of the color palette of the DIB
*
* Description:
*
* This function gets the size required to store the DIB's palette by
* multiplying the number of colors by the size of an RGBQUAD (for a
* Windows 3.0-style DIB) or by the size of an RGBTRIPLE (for an OS/2-
* style DIB).
*
* History: Date Author Reason
* 6/01/91 Garrett McAuliffe Created
* 9/15/91 Patrick Schreiber Added header and comments
*
************************************************************************/
WORD FAR PaletteSize(LPCSTR lpDIB)
{
/* calculate the size required by the palette */
if (IS_WIN30_DIB (lpDIB))
return (WORD FAR)(DIBNumColors(lpDIB) * sizeof(RGBQUAD));
else
return (WORD FAR)(DIBNumColors(lpDIB) * sizeof(RGBTRIPLE));
}
/*************************************************************************
*
* DIBNumColors()
*
* Parameter:
*
* LPSTR lpDIB - pointer to packed-DIB memory block
*
* Return Value:
*
* WORD - number of colors in the color table
*
* Description:
*
* This function calculates the number of colors in the DIB's color table
* by finding the bits per pixel for the DIB (whether Win3.0 or OS/2-style
* DIB). If bits per pixel is 1: colors=2, if 4: colors=16, if 8: colors=256,
* if 24, no colors in color table.
*
* History: Date Author Reason
* 6/01/91 Garrett McAuliffe Created
* 9/15/91 Patrick Schreiber Added header and comments
*
************************************************************************/
WORD FAR DIBNumColors(LPCSTR lpDIB)
{
WORD wBitCount; // DIB bit count
/* If this is a Windows-style DIB, the number of colors in the
* color table can be less than the number of bits per pixel
* allows for (i.e. lpbi->biClrUsed can be set to some value).
* If this is the case, return the appropriate value.
*/
if (IS_WIN30_DIB(lpDIB))
{
DWORD dwClrUsed;
dwClrUsed = ((LPBITMAPINFOHEADER)lpDIB)->biClrUsed;
if (dwClrUsed)
return (WORD)dwClrUsed;
}
/* Calculate the number of colors in the color table based on
* the number of bits per pixel for the DIB.
*/
if (IS_WIN30_DIB(lpDIB))
wBitCount = ((LPBITMAPINFOHEADER)lpDIB)->biBitCount;
else
wBitCount = ((LPBITMAPCOREHEADER)lpDIB)->bcBitCount;
/* return number of colors based on bits per pixel */
switch (wBitCount)
{
case 1:
return 2;
case 4:
return 16;
case 8:
return 256;
default:
return 0;
}
}
/*************************************************************************
*
* CreateDIBPalette()
*
* Parameter:
*
* HDIB hDIB - specifies the DIB
*
* Return Value:
*
* HPALETTE - specifies the palette
*
* Description:
*
* This function creates a palette from a DIB by allocating memory for the
* logical palette, reading and storing the colors from the DIB's color table
* into the logical palette, creating a palette from this logical palette,
* and then returning the palette's handle. This allows the DIB to be
* displayed using the best possible colors (important for DIBs with 256 or
* more colors).
*
* History: Date Author Reason
* 6/01/91 Garrett McAuliffe Created
* 9/15/91 Patrick Schreiber Added header and comments
*
************************************************************************/
HPALETTE FAR CreateDIBPalette(HDIB hDIB)
{
LPLOGPALETTE lpPal; // pointer to a logical palette
HANDLE hLogPal; // handle to a logical palette
HPALETTE hPal = NULL; // handle to a palette
int i, wNumColors; // loop index, number of colors in color table
LPSTR lpbi; // pointer to packed-DIB
LPBITMAPINFO lpbmi; // pointer to BITMAPINFO structure (Win3.0)
LPBITMAPCOREINFO lpbmc; // pointer to BITMAPCOREINFO structure (OS/2)
BOOL bWinStyleDIB; // flag which signifies whether this is a Win3.0 DIB
/* if handle to DIB is invalid, return NULL */
if (!hDIB)
return NULL;
/* lock DIB memory block and get a pointer to it */
lpbi = (LPSTR)GlobalLock(hDIB);
/* get pointer to BITMAPINFO (Win 3.0) */
lpbmi = (LPBITMAPINFO)lpbi;
/* get pointer to BITMAPCOREINFO (OS/2 1.x) */
lpbmc = (LPBITMAPCOREINFO)lpbi;
/* get the number of colors in the DIB */
wNumColors = DIBNumColors(lpbi);
/* is this a Win 3.0 DIB? */
bWinStyleDIB = IS_WIN30_DIB(lpbi);
if (wNumColors)
{
/* allocate memory block for logical palette */
hLogPal = GlobalAlloc(GHND, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) *
wNumColors);
/* if not enough memory, clean up and return NULL */
if (!hLogPal)
{
GlobalUnlock(hDIB);
return NULL;
}
/* lock memory block and get pointer to it */
lpPal = (LPLOGPALETTE)GlobalLock(hLogPal);
/* set version and number of palette entries */
lpPal->palVersion = PALVERSION;
lpPal->palNumEntries = (WORD)wNumColors;
/* store RGB triples (if Win 3.0 DIB) or RGB quads (if OS/2 DIB)
* into palette
*/
for (i = 0; i < wNumColors; i++)
{
if (bWinStyleDIB)
{
lpPal->palPalEntry[i].peRed = lpbmi->bmiColors[i].rgbRed;
lpPal->palPalEntry[i].peGreen = lpbmi->bmiColors[i].rgbGreen;
lpPal->palPalEntry[i].peBlue = lpbmi->bmiColors[i].rgbBlue;
lpPal->palPalEntry[i].peFlags = 0;
}
else
{
lpPal->palPalEntry[i].peRed = lpbmc->bmciColors[i].rgbtRed;
lpPal->palPalEntry[i].peGreen = lpbmc->bmciColors[i].rgbtGreen;
lpPal->palPalEntry[i].peBlue = lpbmc->bmciColors[i].rgbtBlue;
lpPal->palPalEntry[i].peFlags = 0;
}
}
/* create the palette and get handle to it */
hPal = CreatePalette(lpPal);
/* if error getting handle to palette, clean up and return NULL */
if (!hPal)
{
GlobalUnlock(hLogPal);
GlobalFree(hLogPal);
return NULL;
}
}
/* clean up */
GlobalUnlock(hLogPal);
GlobalFree(hLogPal);
GlobalUnlock(hDIB);
/* return handle to DIB's palette */
return hPal;
}
/*************************************************************************
*
* DIBToBitmap()
*
* Parameters:
*
* HDIB hDIB - specifies the DIB to convert
*
* HPALETTE hPal - specifies the palette to use with the bitmap
*
* Return Value:
*
* HBITMAP - identifies the device-dependent bitmap
*
* Description:
*
* This function creates a bitmap from a DIB using the specified palette.
* If no palette is specified, default is used.
*
* NOTE:
*
* The bitmap returned from this funciton is always a bitmap compatible
* with the screen (e.g. same bits/pixel and color planes) rather than
* a bitmap with the same attributes as the DIB. This behavior is by
* design, and occurs because this function calls CreateDIBitmap to
* do its work, and CreateDIBitmap always creates a bitmap compatible
* with the hDC parameter passed in (because it in turn calls
* CreateCompatibleBitmap).
*
* So for instance, if your DIB is a monochrome DIB and you call this
* function, you will not get back a monochrome HBITMAP -- you will
* get an HBITMAP compatible with the screen DC, but with only 2
* colors used in the bitmap.
*
* If your application requires a monochrome HBITMAP returned for a
* monochrome DIB, use the function SetDIBits().
*
* Also, the DIBpassed in to the function is not destroyed on exit. This
* must be done later, once it is no longer needed.
*
* History: Date Author Reason
* 6/01/91 Garrett McAuliffe Created
* 9/15/91 Patrick Schreiber Added header and comments
* 3/27/92 Mark Bader Added comments about resulting
* bitmap format
*
************************************************************************/
HBITMAP FAR DIBToBitmap(HDIB hDIB, HPALETTE hPal)
{
LPSTR lpDIBHdr, lpDIBBits; // pointer to DIB header, pointer to DIB bits
HBITMAP hBitmap; // handle to device-dependent bitmap
HDC hDC; // handle to DC
HPALETTE hOldPal = NULL; // handle to a palette
/* if invalid handle, return NULL */
if (!hDIB)
return NULL;
/* lock memory block and get a pointer to it */
lpDIBHdr = (LPSTR)GlobalLock(hDIB);
/* get a pointer to the DIB bits */
lpDIBBits = FindDIBBits(lpDIBHdr);
/* get a DC */
hDC = GetDC(NULL);
if (!hDC)
{
/* clean up and return NULL */
GlobalUnlock(hDIB);
return NULL;
}
/* select and realize palette */
if (hPal)
hOldPal = SelectPalette(hDC, hPal, FALSE);
RealizePalette(hDC);
/* create bitmap from DIB info. and bits */
hBitmap = CreateDIBitmap(hDC, (LPBITMAPINFOHEADER)lpDIBHdr, CBM_INIT,
lpDIBBits, (LPBITMAPINFO)lpDIBHdr, DIB_RGB_COLORS);
/* restore previous palette */
if (hOldPal)
SelectPalette(hDC, hOldPal, FALSE);
/* clean up */
ReleaseDC(NULL, hDC);
GlobalUnlock(hDIB);
/* return handle to the bitmap */
return hBitmap;
}
/*************************************************************************
*
* BitmapToDIB()
*
* Parameters:
*
* HBITMAP hBitmap - specifies the bitmap to convert
*
* HPALETTE hPal - specifies the palette to use with the bitmap
*
* Return Value:
*
* HDIB - identifies the device-dependent bitmap
*
* Description:
*
* This function creates a DIB from a bitmap using the specified palette.
*
* History: Date Author Reason
* 6/01/91 Garrett McAuliffe Created
* 9/15/91 Patrick Schreiber Added header and comments
* 12/10/91 Patrick Schreiber Added bits per pixel validation
* and check GetObject return value
*
************************************************************************/
HDIB FAR BitmapToDIB(HBITMAP hBitmap, HPALETTE hPal)
{
BITMAP bm; // bitmap structure
BITMAPINFOHEADER bi; // bitmap header
BITMAPINFOHEADER FAR *lpbi; // pointer to BITMAPINFOHEADER
DWORD dwLen; // size of memory block
HANDLE hDIB, h; // handle to DIB, temp handle
HDC hDC; // handle to DC
WORD biBits; // bits per pixel
/* check if bitmap handle is valid */
if (!hBitmap)
return NULL;
/* fill in BITMAP structure, return NULL if it didn't work */
if (!GetObject(hBitmap, sizeof(bm), (LPSTR)&bm))
return NULL;
/* if no palette is specified, use default palette */
if (hPal == NULL)
hPal = GetStockObject(DEFAULT_PALETTE);
/* calculate bits per pixel */
biBits = (WORD)( bm.bmPlanes * bm.bmBitsPixel );
/* make sure bits per pixel is valid */
if (biBits <= 1)
biBits = 1;
else if (biBits <= 4)
biBits = 4;
else if (biBits <= 8)
biBits = 8;
else /* if greater than 8-bit, force to 24-bit */
biBits = 24;
/* initialize BITMAPINFOHEADER */
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bm.bmWidth;
bi.biHeight = bm.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = biBits;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
/* calculate size of memory block required to store BITMAPINFO */
dwLen = bi.biSize + PaletteSize((LPSTR)&bi);
/* get a DC */
hDC = GetDC(NULL);
/* select and realize our palette */
hPal = SelectPalette(hDC, hPal, FALSE);
RealizePalette(hDC);
/* alloc memory block to store our bitmap */
hDIB = GlobalAlloc(GHND, dwLen);
/* if we couldn't get memory block */
if (!hDIB)
{
/* clean up and return NULL */
SelectPalette(hDC, hPal, TRUE);
RealizePalette(hDC);
ReleaseDC(NULL, hDC);
return NULL;
}
/* lock memory and get pointer to it */
lpbi = (BITMAPINFOHEADER FAR *)GlobalLock(hDIB);
/* use our bitmap info. to fill BITMAPINFOHEADER */
*lpbi = bi;
/* call GetDIBits with a NULL lpBits param, so it will calculate the
* biSizeImage field for us
*/
GetDIBits(hDC, hBitmap, 0, (WORD)bi.biHeight, NULL, (LPBITMAPINFO)lpbi,
DIB_RGB_COLORS);
/* get the info. returned by GetDIBits and unlock memory block */
bi = *lpbi;
GlobalUnlock(hDIB);
/* if the driver did not fill in the biSizeImage field, make one up */
if (bi.biSizeImage == 0)
bi.biSizeImage = WIDTHBYTES((DWORD)bm.bmWidth * biBits) * bm.bmHeight;
/* realloc the buffer big enough to hold all the bits */
dwLen = bi.biSize + PaletteSize((LPSTR)&bi) + bi.biSizeImage;
h = GlobalReAlloc(hDIB, dwLen, 0);
if (h)
hDIB = h;
else
{
/* clean up and return NULL */
GlobalFree(hDIB);
hDIB = NULL;
SelectPalette(hDC, hPal, TRUE);
RealizePalette(hDC);
ReleaseDC(NULL, hDC);
return NULL;
}
/* lock memory block and get pointer to it */
lpbi = (BITMAPINFOHEADER FAR *)GlobalLock(hDIB);
/* call GetDIBits with a NON-NULL lpBits param, and actualy get the
* bits this time
*/
if (GetDIBits(hDC, hBitmap, 0, (WORD)bi.biHeight, (LPSTR)lpbi + (WORD)lpbi
->biSize + PaletteSize((LPSTR)lpbi), (LPBITMAPINFO)lpbi,
DIB_RGB_COLORS) == 0)
{
/* clean up and return NULL */
GlobalUnlock(hDIB);
hDIB = NULL;
SelectPalette(hDC, hPal, TRUE);
RealizePalette(hDC);
ReleaseDC(NULL, hDC);
return NULL;
}
bi = *lpbi;
/* clean up */
GlobalUnlock(hDIB);
SelectPalette(hDC, hPal, TRUE);
RealizePalette(hDC);
ReleaseDC(NULL, hDC);
/* return handle to the DIB */
return hDIB;
}
/*************************************************************************
*
* PalEntriesOnDevice()
*
* Parameter:
*
* HDC hDC - device context
*
* Return Value:
*
* int - number of palette entries on device
*
* Description:
*
* This function gets the number of palette entries on the specified device
*
* History: Date Author Reason
* 6/01/91 Garrett McAuliffe Created
* 9/15/91 Patrick Schreiber Added header and comments
*
************************************************************************/
int FAR PalEntriesOnDevice(HDC hDC)
{
int nColors; // number of colors
/* Find out the number of palette entries on this
* device.
*/
nColors = GetDeviceCaps(hDC, SIZEPALETTE);
/* For non-palette devices, we'll use the # of system
* colors for our palette size.
*/
if (!nColors)
nColors = GetDeviceCaps(hDC, NUMCOLORS);
assert(nColors);
return nColors;
}
/*************************************************************************
*
* GetSystemPalette()
*
* Parameters:
*
* None
*
* Return Value:
*
* HPALETTE - handle to a copy of the current system palette
*
* Description:
*
* This function returns a handle to a palette which represents the system
* palette. The system RGB values are copied into our logical palette using
* the GetSystemPaletteEntries function.
*
* History:
*
* Date Author Reason
* 6/01/91 Garrett McAuliffe Created
* 9/15/91 Patrick Schreiber Added header and comments
* 12/20/91 Mark Bader Added GetSystemPaletteEntries call
*
************************************************************************/
HPALETTE FAR GetSystemPalette(void)
{
HDC hDC; // handle to a DC
static HPALETTE hPal = NULL; // handle to a palette
HANDLE hLogPal; // handle to a logical palette
LPLOGPALETTE lpLogPal; // pointer to a logical palette
int nColors; // number of colors
/* Find out how many palette entries we want. */
hDC = GetDC(NULL);
if (!hDC)
return NULL;
nColors = PalEntriesOnDevice(hDC); // Number of palette entries
/* Allocate room for the palette and lock it. */
hLogPal = GlobalAlloc(GHND, sizeof(LOGPALETTE) + nColors * sizeof(
PALETTEENTRY));
/* if we didn't get a logical palette, return NULL */
if (!hLogPal)
return NULL;
/* get a pointer to the logical palette */
lpLogPal = (LPLOGPALETTE)GlobalLock(hLogPal);
/* set some important fields */
lpLogPal->palVersion = (WORD)PALVERSION;
lpLogPal->palNumEntries = (WORD)nColors;
/* Copy the current system palette into our logical palette */
GetSystemPaletteEntries(hDC, 0, nColors,
(LPPALETTEENTRY)(lpLogPal->palPalEntry));
/* Go ahead and create the palette. Once it's created,
* we no longer need the LOGPALETTE, so free it.
*/
hPal = CreatePalette(lpLogPal);
/* clean up */
GlobalUnlock(hLogPal);
GlobalFree(hLogPal);
ReleaseDC(NULL, hDC);
return hPal;
}
/*************************************************************************
*
* AllocRoomForDIB()
*
* Parameters:
*
* BITMAPINFOHEADER - bitmap info header stucture
*
* HBITMAP - handle to the bitmap
*
* Return Value:
*
* HDIB - handle to memory block
*
* Description:
*
* This routine takes a BITMAPINOHEADER, and returns a handle to global
* memory which can contain a DIB with that header. It also initializes
* the header portion of the global memory. GetDIBits() is used to determine
* the amount of room for the DIB's bits. The total amount of memory
* needed = sizeof(BITMAPINFOHEADER) + size of color table + size of bits.
*
* History: Date Author Reason
* 6/01/91 Garrett McAuliffe Created
* 12/11/91 Patrick Schreiber Added header and some comments
*
************************************************************************/
HANDLE AllocRoomForDIB(BITMAPINFOHEADER bi, HBITMAP hBitmap)
{
DWORD dwLen;
HANDLE hDIB;
HDC hDC;
LPBITMAPINFOHEADER lpbi;
HANDLE hTemp;
/* Figure out the size needed to hold the BITMAPINFO structure
* (which includes the BITMAPINFOHEADER and the color table).
*/
dwLen = bi.biSize + PaletteSize((LPSTR) &bi);
hDIB = GlobalAlloc(GHND,dwLen);
/* Check that DIB handle is valid */
if (!hDIB)
return NULL;
/* Set up the BITMAPINFOHEADER in the newly allocated global memory,
* then call GetDIBits() with lpBits = NULL to have it fill in the
* biSizeImage field for us.
*/
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
*lpbi = bi;
hDC = GetDC(NULL);
GetDIBits(hDC, hBitmap, 0, (WORD) bi.biHeight,
NULL, (LPBITMAPINFO) lpbi, DIB_RGB_COLORS);
ReleaseDC(NULL, hDC);
/* If the driver did not fill in the biSizeImage field,
* fill it in -- NOTE: this is a bug in the driver!
*/
if (lpbi->biSizeImage == 0)
lpbi->biSizeImage = WIDTHBYTES((DWORD)lpbi->biWidth * lpbi->biBitCount) *
lpbi->biHeight;
/* Get the size of the memory block we need */
dwLen = lpbi->biSize + PaletteSize((LPSTR) &bi) + lpbi->biSizeImage;
/* Unlock the memory block */
GlobalUnlock(hDIB);
/* ReAlloc the buffer big enough to hold all the bits */
hTemp = GlobalReAlloc(hDIB,dwLen,0);
if (hTemp)
return hTemp;
else
{
/* Else free memory block and return failure */
GlobalFree(hDIB);
return NULL;
}
}
/*************************************************************************
*
* ChangeDIBFormat()
*
* Parameter:
*
* HDIB - handle to packed-DIB in memory
*
* WORD - desired bits per pixel
*
* DWORD - desired compression format
*
* Return Value:
*
* HDIB - handle to the new DIB if successful, else NULL
*
* Description:
*
* This function will convert the bits per pixel and/or the compression
* format of the specified DIB. Note: If the conversion was unsuccessful,
* we return NULL. The original DIB is left alone. Don't use code like the
* following:
*
* hMyDIB = ChangeDIBFormat(hMyDIB, 8, BI_RLE4);
*
* The conversion will fail, but hMyDIB will now be NULL and the original
* DIB will now hang around in memory. We could have returned the old
* DIB, but we wanted to allow the programmer to check whether this
* conversion succeeded or failed.
*
* History:
*
* Date Author Reason
* 6/01/91 Garrett McAuliffe Created
* 12/10/91 Patrick Schreiber Modified from converting RGB to RLE8
* to converting RGB/RLE to RGB/RLE.
* Added wBitCount and dwCompression
* parameters. Also added header and
* comments.
*
************************************************************************/
HDIB FAR ChangeDIBFormat(HDIB hDIB, WORD wBitCount, DWORD dwCompression)
{
HDC hDC; // Handle to DC
HBITMAP hBitmap; // Handle to bitmap
BITMAP Bitmap; // BITMAP data structure
BITMAPINFOHEADER bi; // Bitmap info header
LPBITMAPINFOHEADER lpbi; // Pointer to bitmap info
HDIB hNewDIB = NULL; // Handle to new DIB
HPALETTE hPal, hOldPal; // Handle to palette, prev pal
WORD DIBBPP, NewBPP; // DIB bits per pixel, new bpp
DWORD DIBComp, NewComp;// DIB compression, new compression
/* Check for a valid DIB handle */
if (!hDIB)
return NULL;
/* Get the old DIB's bits per pixel and compression format */
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
DIBBPP = ((LPBITMAPINFOHEADER)lpbi)->biBitCount;
DIBComp = ((LPBITMAPINFOHEADER)lpbi)->biCompression;
GlobalUnlock(hDIB);
/* Validate wBitCount and dwCompression
* They must match correctly (i.e., BI_RLE4 and 4 BPP or
* BI_RLE8 and 8BPP, etc.) or we return failure */
if (wBitCount == 0)
{
NewBPP = DIBBPP;
if ((dwCompression == BI_RLE4 && NewBPP == 4) ||
(dwCompression == BI_RLE8 && NewBPP == 8) ||
(dwCompression == BI_RGB))
NewComp = dwCompression;
else
return NULL;
}
else if (wBitCount == 1 && dwCompression == BI_RGB)
{
NewBPP = wBitCount;
NewComp = BI_RGB;
}
else if (wBitCount == 4)
{
NewBPP = wBitCount;
if (dwCompression == BI_RGB || dwCompression == BI_RLE4)
NewComp = dwCompression;
else
return NULL;
}
else if (wBitCount == 8)
{
NewBPP = wBitCount;
if (dwCompression == BI_RGB || dwCompression == BI_RLE8)
NewComp = dwCompression;
else
return NULL;
}
else if (wBitCount == 24 && dwCompression == BI_RGB)
{
NewBPP = wBitCount;
NewComp = BI_RGB;
}
else
return NULL;
/* Save the old DIB's palette */
hPal = CreateDIBPalette(hDIB);
if (!hPal)
return NULL;
/* Convert old DIB to a bitmap */
hBitmap = DIBToBitmap(hDIB, hPal);
if (!hBitmap)
{
DeleteObject(hPal);
return NULL;
}
/* Get info about the bitmap */
GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap);
/* Fill in the BITMAPINFOHEADER appropriately */
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = Bitmap.bmWidth;
bi.biHeight = Bitmap.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = NewBPP;
bi.biCompression = NewComp;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
/* Go allocate room for the new DIB */
hNewDIB = AllocRoomForDIB(bi, hBitmap);
if (!hNewDIB)
return NULL;
/* Get a pointer to the new DIB */
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hNewDIB);
/* Get a DC and select/realize our palette in it */
hDC = GetDC(NULL);
hOldPal = SelectPalette(hDC, hPal, FALSE);
RealizePalette(hDC);
/* Call GetDIBits and get the new DIB bits */
if (!GetDIBits(hDC, hBitmap, 0, (WORD) lpbi->biHeight,
(LPSTR)lpbi + (WORD)lpbi->biSize + PaletteSize((LPSTR)lpbi),
(LPBITMAPINFO)lpbi, DIB_RGB_COLORS))
{
GlobalUnlock(hNewDIB);
GlobalFree(hNewDIB);
hNewDIB = NULL;
}
/* Clean up and return */
SelectPalette(hDC, hOldPal, TRUE);
RealizePalette(hDC);
ReleaseDC(NULL, hDC);
if (hNewDIB)
/* Unlock the new DIB's memory block */
GlobalUnlock(hNewDIB);
DeleteObject(hBitmap);
DeleteObject(hPal);
return hNewDIB;
}
/*************************************************************************
*
* ChangeBitmapFormat()
*
* Parameter:
*
* HBITMAP - handle to a bitmap
*
* WORD - desired bits per pixel
*
* DWORD - desired compression format
*
* HPALETTE - handle to palette
*
* Return Value:
*
* HDIB - handle to the new DIB if successful, else NULL
*
* Description:
*
* This function will convert a bitmap to the specified bits per pixel
* and compression format. The bitmap and it's palette will remain
* after calling this function.
*
* History:
*
* Date Author Reason
* 6/01/91 Garrett McAuliffe Created
* 12/10/91 Patrick Schreiber Modified from converting RGB to RLE8
* to converting RGB/RLE to RGB/RLE.
* Added wBitCount and dwCompression
* parameters. Also added header and
* comments.
* 12/11/91 Patrick Schreiber Destroy old DIB if conversion was
* successful.
* 12/16/91 Patrick Schreiber Modified from converting DIB to new
* DIB to bitmap to new DIB. Added palette
* parameter.
*
************************************************************************/
HDIB FAR ChangeBitmapFormat(HBITMAP hBitmap,
WORD wBitCount,
DWORD dwCompression,
HPALETTE hPal)
{
HDC hDC; // Screen DC
HDIB hNewDIB=NULL; // Handle to new DIB
BITMAP Bitmap; // BITMAP data structure
BITMAPINFOHEADER bi; // Bitmap info. header
LPBITMAPINFOHEADER lpbi; // Pointer to bitmap header
HPALETTE hOldPal=NULL; // Handle to palette
WORD NewBPP; // New bits per pixel
DWORD NewComp; // New compression format
/* Check for a valid bitmap handle */
if (!hBitmap)
return NULL;
/* Validate wBitCount and dwCompression
* They must match correctly (i.e., BI_RLE4 and 4 BPP or
* BI_RLE8 and 8BPP, etc.) or we return failure
*/
if (wBitCount == 0)
{
NewComp = dwCompression;
if (NewComp == BI_RLE4)
NewBPP = 4;
else if (NewComp == BI_RLE8)
NewBPP = 8;
else /* Not enough info */
return NULL;
}
else if (wBitCount == 1 && dwCompression == BI_RGB)
{
NewBPP = wBitCount;
NewComp = BI_RGB;
}
else if (wBitCount == 4)
{
NewBPP = wBitCount;
if (dwCompression == BI_RGB || dwCompression == BI_RLE4)
NewComp = dwCompression;
else
return NULL;
}
else if (wBitCount == 8)
{
NewBPP = wBitCount;
if (dwCompression == BI_RGB || dwCompression == BI_RLE8)
NewComp = dwCompression;
else
return NULL;
}
else if (wBitCount == 24 && dwCompression == BI_RGB)
{
NewBPP = wBitCount;
NewComp = BI_RGB;
}
else
return NULL;
/* Get info about the bitmap */
GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap);
/* Fill in the BITMAPINFOHEADER appropriately */
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = Bitmap.bmWidth;
bi.biHeight = Bitmap.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = NewBPP;
bi.biCompression = NewComp;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
/* Go allocate room for the new DIB */
hNewDIB = AllocRoomForDIB(bi, hBitmap);
if (!hNewDIB)
return NULL;
/* Get a pointer to the new DIB */
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hNewDIB);
/* If we have a palette, get a DC and select/realize it */
if (hPal)
{
hDC = GetDC(NULL);
hOldPal = SelectPalette(hDC, hPal, FALSE);
RealizePalette(hDC);
}
/* Call GetDIBits and get the new DIB bits */
if (!GetDIBits(hDC, hBitmap, 0, (WORD) lpbi->biHeight,
(LPSTR)lpbi + (WORD)lpbi->biSize + PaletteSize((LPSTR)lpbi),
(LPBITMAPINFO)lpbi, DIB_RGB_COLORS))
{
GlobalUnlock(hNewDIB);
GlobalFree(hNewDIB);
hNewDIB = NULL;
}
/* Clean up and return */
if (hOldPal)
{
SelectPalette(hDC, hOldPal, TRUE);
RealizePalette(hDC);
ReleaseDC(NULL, hDC);
}
if (hNewDIB)
{
/* Unlock the new DIB's memory block */
GlobalUnlock(hNewDIB);
}
return hNewDIB;
}
================================================
FILE: CODE/DIBUTIL.H
================================================
/*
** 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 .
*/
/*
* dibutil.h
*
* Copyright (c) 1991 Microsoft Corporation. All rights reserved.
*
* Header file for Device-Independent Bitmap (DIB) API. Provides
* function prototypes and constants for the following functions:
*
* AllocRoomForDIB() - Allocates memory for a DIB
*
*/
/* DIB constants */
#define PALVERSION 0x300
/* DIB macros */
#define IS_WIN30_DIB(lpbi) ((*(LPDWORD)(lpbi)) == sizeof(BITMAPINFOHEADER))
#define RECTWIDTH(lpRect) ((lpRect)->right - (lpRect)->left)
#define RECTHEIGHT(lpRect) ((lpRect)->bottom - (lpRect)->top)
/* function prototypes */
HANDLE AllocRoomForDIB(BITMAPINFOHEADER bi, HBITMAP hBitmap);
================================================
FILE: CODE/DISPLAY.CPP
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/DISPLAY.CPP 3 3/09/97 8:04p 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 : DISPLAY.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : September 10, 1993 *
* *
* Last Update : October 20, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* DisplayClass::Compute_Start_Pos -- Computes player's start pos from unit coords. *
* DisplayClass::AI -- Handles the maintenance tasks for the map display. *
* DisplayClass::All_To_Look -- Direct all objects to look around for the player. *
* DisplayClass::Calculated_Cell -- Fetch a map cell based on specified method. *
* DisplayClass::Cell_Object -- Determines what has been clicked on. *
* DisplayClass::Cell_Shadow -- Determine what shadow icon to use for the cell. *
* DisplayClass::Center_Map -- Centers the map about the currently selected objects *
* DisplayClass::Click_Cell_Calc -- Determines cell from screen X & Y. *
* DisplayClass::Closest_Free_Spot -- Finds the closest cell sub spot that is free. *
* DisplayClass::Coord_To_Pixel -- Determines X and Y pixel coordinates. *
* DisplayClass::Cursor_Mark -- Set or resets the cursor display flag bits. *
* DisplayClass::DisplayClass -- Default constructor for display class. *
* DisplayClass::Draw_It -- Draws the tactical map. *
* DisplayClass::Encroach_Shadow -- Causes the shadow to creep back by one cell. *
* DisplayClass::Flag_Cell -- Flag the specified cell to be redrawn. *
* DisplayClass::Flag_To_Redraw -- Flags the display so that it will be redrawn as soon as poss*
* DisplayClass::Get_Occupy_Dimensions -- computes width & height of the given occupy list *
* DisplayClass::Good_Reinforcement_Cell -- Checks cell for renforcement legality. *
* DisplayClass::In_View -- Determines if cell is visible on screen. *
* DisplayClass::Init_Clear -- Clears the display to a known state. *
* DisplayClass::Init_IO -- Creates the map's button list *
* DisplayClass::Init_Theater -- Theater-specific initialization *
* DisplayClass::Is_Spot_Free -- Determines if cell sub spot is free of occupation. *
* DisplayClass::Map_Cell -- Mark specified cell as having been mapped. *
* DisplayClass::Mouse_Left_Held -- Handles the left button held down. *
* DisplayClass::Mouse_Left_Press -- Handles the left mouse button press. *
* DisplayClass::Mouse_Left_Release -- Handles the left mouse button release. *
* DisplayClass::Mouse_Left_Up -- Handles the left mouse "cruising" over the map. *
* DisplayClass::Mouse_Right_Press -- Handles the right mouse button press. *
* DisplayClass::Next_Object -- Searches for next object on display. *
* DisplayClass::One_Time -- Performs any special one time initializations. *
* DisplayClass::Passes_Proximity_Check -- Determines if building placement is near friendly sq*
* DisplayClass::Pixel_To_Coord -- converts screen coord to COORDINATE *
* DisplayClass::Prev_Object -- Searches for the previous object on the map. *
* DisplayClass::Read_INI -- Reads map control data from INI file. *
* DisplayClass::Redraw_Icons -- Draws all terrain icons necessary. *
* DisplayClass::Redraw_Shadow -- Draw the shadow overlay. *
* DisplayClass::Refresh_Band -- Causes all cells under the rubber band to be redrawn. *
* DisplayClass::Refresh_Cells -- Redraws all cells in list. *
* DisplayClass::Remove -- Removes a game object from the rendering system. *
* DisplayClass::Repair_Mode_Control -- Controls the repair mode. *
* DisplayClass::Scroll_Map -- Scroll the tactical map in desired direction. *
* DisplayClass::Select_These -- All selectable objects in region are selected. *
* DisplayClass::Sell_Mode_Control -- Controls the sell mode. *
* DisplayClass::Set_Cursor_Pos -- Controls the display and animation of the tac cursor. *
* DisplayClass::Set_Cursor_Shape -- Changes the shape of the terrain square cursor. *
* DisplayClass::Set_Tactical_Position -- Sets the tactical view position. *
* DisplayClass::Set_View_Dimensions -- Sets the tactical display screen coordinates. *
* DisplayClass::Shroud_Cell -- Returns the specified cell into the shrouded condition. *
* DisplayClass::Submit -- Adds a game object to the map rendering system. *
* DisplayClass::TacticalClass::Action -- Processes input for the tactical map. *
* DisplayClass::Text_Overlap_List -- Creates cell overlap list for specified text string. *
* DisplayClass::Write_INI -- Write the map data to the INI file specified. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
#include "vortex.h"
/*
** These layer control elements are used to group the displayable objects
** so that proper overlap can be obtained.
*/
LayerClass DisplayClass::Layer[LAYER_COUNT];
/*
** Fading tables
*/
unsigned char DisplayClass::FadingBrighten[256];
unsigned char DisplayClass::FadingShade[256];
unsigned char DisplayClass::FadingWayDark[256];
unsigned char DisplayClass::FadingLight[256];
unsigned char DisplayClass::FadingGreen[256];
unsigned char DisplayClass::FadingYellow[256];
unsigned char DisplayClass::FadingRed[256];
unsigned char DisplayClass::TranslucentTable[(MAGIC_COL_COUNT+1)*256];
unsigned char DisplayClass::WhiteTranslucentTable[(1+1)*256];
unsigned char DisplayClass::MouseTranslucentTable[(4+1)*256];
void const * DisplayClass::TransIconset;
unsigned char DisplayClass::UnitShadow[(USHADOW_COL_COUNT+1)*256];
unsigned char DisplayClass::UnitShadowAir[(USHADOW_COL_COUNT+1)*256];
unsigned char DisplayClass::SpecialGhost[2*256];
void const * DisplayClass::ShadowShapes;
unsigned char DisplayClass::ShadowTrans[(SHADOW_COL_COUNT+1)*256];
/*
** Bit array of cell redraw flags
*/
BooleanVectorClass DisplayClass::CellRedraw;
/*
** The main button that intercepts user input to the map
*/
DisplayClass::TacticalClass DisplayClass::TacButton;
static int const TEX_X = 0;
static int const TEX_Y = 6;
static int const TEX_W = 14;
/***********************************************************************************************
* DisplayClass::DisplayClass -- Default constructor for display class. *
* *
* This constructor for the display class just initializes some of the display settings. *
* Most settings are initialized with the correct values at the time that the Init function *
* is called. There are some cases where default values are wise and this routine fills *
* those particular ones in. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/06/1994 JLB : Created. *
*=============================================================================================*/
DisplayClass::DisplayClass(void) :
TacticalCoord(0),
TacLeptonWidth(0),
TacLeptonHeight(0),
ZoneCell(0),
ZoneOffset(0),
CursorSize(0),
ProximityCheck(false),
PendingObjectPtr(0),
PendingObject(0),
PendingHouse(HOUSE_NONE),
TacPixelX(0),
TacPixelY(0),
DesiredTacticalCoord(0),
IsToRedraw(true),
IsRepairMode(false),
IsSellMode(false),
IsTargettingMode(SPC_NONE),
IsRubberBand(false),
IsTentative(false),
IsShadowPresent(false),
BandX(0),
BandY(0),
NewX(0),
NewY(0)
{
ShadowShapes = 0;
TransIconset = 0;
Set_View_Dimensions(0, 8, 320/CELL_PIXEL_W, 200/CELL_PIXEL_H);
}
/***********************************************************************************************
* DisplayClass::One_Time -- Performs any special one time initializations. *
* *
* This routine is called from the game initialization process. It is to perform any one *
* time initializations necessary for the map display system. It allocates the staging *
* buffer needed for the radar map. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: This routine must be called ONCE and only once. *
* *
* HISTORY: *
* 05/31/1994 JLB : Created. *
* 05/31/1994 JLB : Handles layer system now. *
* 06/02/1994 JLB : Takes care of misc display tables and data allocation. *
*=============================================================================================*/
void DisplayClass::One_Time(void)
{
MapClass::One_Time();
/*
** Init the CellRedraw bit array. Do not do this in the constructor, since the
** BooleanVector may not have been constructed yet.
*/
CellRedraw.Resize(MAP_CELL_TOTAL);
for (LayerType layer = LAYER_FIRST; layer < LAYER_COUNT; layer++) {
Layer[layer].One_Time();
}
/*
** Load the generic transparent icon set.
*/
TransIconset = MFCD::Retrieve("TRANS.ICN");
#ifndef NDEBUG
RawFileClass file("SHADOW.SHP");
if (file.Is_Available()) {
ShadowShapes = Load_Alloc_Data(file);
} else {
ShadowShapes = MFCD::Retrieve("SHADOW.SHP");
}
#else
ShadowShapes = MFCD::Retrieve("SHADOW.SHP");
#endif
Set_View_Dimensions(0, 8 * RESFACTOR);
}
/***********************************************************************************************
* DisplayClass::Init_Clear -- clears the display to a known state *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 03/17/1995 BRR : Created. *
*=============================================================================================*/
void DisplayClass::Init_Clear(void)
{
MapClass::Init_Clear();
/*
** Clear any object being placed
*/
PendingObjectPtr = 0;
PendingObject = 0;
PendingHouse = HOUSE_NONE;
CursorSize = 0;
IsTargettingMode = SPC_NONE;
IsRepairMode = false;
IsRubberBand = false;
IsTentative = false;
IsSellMode = false;
/*
** Empty all the display's layers
*/
for (LayerType layer = LAYER_FIRST; layer < LAYER_COUNT; layer++) {
Layer[layer].Init();
}
}
/***********************************************************************************************
* DisplayClass::Init_IO -- clears & re-builds the map's button list *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 03/17/1995 BRR : Created. *
*=============================================================================================*/
void DisplayClass::Init_IO(void)
{
MapClass::Init_IO();
/*
** Re-attach our buttons to the main map button list, only in non-edit mode.
*/
if (!Debug_Map) {
TacButton.Zap();
Add_A_Button(TacButton);
}
}
/***********************************************************************************************
* DisplayClass::Init_Theater -- Performs theater-specific initialization (mixfiles, etc) *
* *
* INPUT: *
* theater new theater *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 03/17/1995 BRR : Created. *
* 05/07/1996 JLB : Added translucent tables. *
*=============================================================================================*/
void DisplayClass::Init_Theater(TheaterType theater)
{
char fullname[16];
static TLucentType const MouseCols[4] = {
{BLACK, BLACK, 110, 0},
{WHITE, WHITE, 110, 0},
{LTGREY, LTGREY, 110, 0},
{DKGREY, DKGREY, 110, 0}
};
static TLucentType const MagicCols[MAGIC_COL_COUNT] = {
{32,32,110,0},
{33,33,110,0},
{34,34,110,0},
{35,35,110,0},
{36,36,110,0},
{37,37,110,0},
{38,38,110,0},
{39,39,110,0},
{BLACK, BLACK, 200, 0},
{WHITE, BLACK, 40, 0},
{LTGREY, BLACK, 80, 0},
{DKGREY, BLACK, 140, 0},
{LTGREEN, BLACK,130,0}
};
static TLucentType const WhiteCols[1] = {
{1, WHITE, 80, 0}
};
static TLucentType const ShadowCols[SHADOW_COL_COUNT] = {
{WHITE+1, BLACK,130,0},
{WHITE, BLACK,170,0},
{LTGRAY, BLACK,250,0},
{DKGRAY, BLACK,250,0}
};
static TLucentType const UShadowCols[USHADOW_COL_COUNT] = {
{LTGREEN, BLACK,130,0}
};
static TLucentType const UShadowColsAir[USHADOW_COL_COUNT] = {
{LTGREEN, WHITE,0,0}
};
static TLucentType const UShadowColsSnow[USHADOW_COL_COUNT] = {
{LTGREEN, BLACK,75,0}
};
/*
** Invoke parent's init routine.
*/
MapClass::Init_Theater(theater);
/*
** Save the new theater value
*/
Scen.Theater = theater;
/*
** Unload old mixfiles, and cache the new ones
*/
sprintf(fullname, "%s.MIX", Theaters[theater].Root);
#ifndef WIN32
LastTheater = THEATER_NONE;
#endif
if (Scen.Theater != LastTheater) {
if (TheaterData != NULL) {
delete TheaterData;
}
TheaterData = new MFCD(fullname, &FastKey);
assert(TheaterData != NULL);
bool theaterload = TheaterData->Cache(TheaterBuffer);
assert(theaterload);
// LastTheater = Scen.Theater;
}
/*
** Load the custom palette associated with this theater.
** The fading palettes will have to be generated as well.
*/
sprintf(fullname, "%s.PAL", Theaters[theater].Root);
PaletteClass const * ptr = (PaletteClass *)MFCD::Retrieve(fullname);
GamePalette = * ptr;
OriginalPalette = GamePalette;
Build_Fading_Table(GamePalette, FadingGreen, GREEN, 110);
Build_Fading_Table(GamePalette, FadingYellow, YELLOW, 140);
Build_Fading_Table(GamePalette, FadingRed, RED, 140);
Build_Translucent_Table(GamePalette, &MouseCols[0], 4, MouseTranslucentTable);
Build_Translucent_Table(GamePalette, &MagicCols[0], MAGIC_COL_COUNT, TranslucentTable);
Build_Translucent_Table(GamePalette, &WhiteCols[0], 1, WhiteTranslucentTable);
Build_Translucent_Table(GamePalette, &ShadowCols[0], SHADOW_COL_COUNT, ShadowTrans);
Conquer_Build_Translucent_Table(GamePalette, &UShadowColsAir[0], USHADOW_COL_COUNT, UnitShadowAir);
memcpy(&UnitShadowAir[256], ColorRemaps[PCOLOR_GOLD].RemapTable, sizeof(ColorRemaps[PCOLOR_GOLD].RemapTable));
if (theater == THEATER_SNOW) {
Conquer_Build_Translucent_Table(GamePalette, &UShadowColsSnow[0], USHADOW_COL_COUNT, UnitShadow);
} else {
Conquer_Build_Translucent_Table(GamePalette, &UShadowCols[0], USHADOW_COL_COUNT, UnitShadow);
}
if (theater == THEATER_SNOW) {
Conquer_Build_Fading_Table(GamePalette, FadingShade, BLACK, 75);
} else {
Conquer_Build_Fading_Table(GamePalette, FadingShade, BLACK, 130);
}
Conquer_Build_Fading_Table(GamePalette, FadingLight, WHITE, 85);
/*
** Create the shadow color used by aircraft.
*/
Conquer_Build_Fading_Table(GamePalette, &SpecialGhost[256], BLACK, 100);
for (int index = 0; index < 256; index++) {
SpecialGhost[index] = 0;
}
Make_Fading_Table(GamePalette, FadingBrighten, WHITE, 25);
Make_Fading_Table(GamePalette, FadingWayDark, DKGRAY, 192);
/*
** Adjust the palette according to the visual control option settings.
*/
Options.Fixup_Palette();
}
/***********************************************************************************************
* DisplayClass::Text_Overlap_List -- Creates cell overlap list for specified text string. *
* *
* This routine is used to create an overlap list that specifies all the cells that are *
* covered by the specified text string. This overlap list is used to handle map refresh *
* logic. *
* *
* INPUT: text -- Pointer to the text that would appear on the map and must have an *
* overlap list generated. *
* *
* x,y -- The coordinates that the text would appear (upper left corner). *
* *
* OUTPUT: Returns with a pointer to an overlap list that covers all cells "under" the text *
* if were displayed at the coordinates specified. The list is actually a series of *
* offsets from the display's upper left corner cell number. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/06/1994 JLB : Created. *
* 12/07/1994 JLB : Sidebar fixup. *
* 08/13/1995 JLB : Optimized for variable sized help text. *
*=============================================================================================*/
short const * DisplayClass::Text_Overlap_List(char const * text, int x, int y) const
{
static short _list[60];
int count = ARRAY_SIZE(_list);
if (text != NULL) {
short * ptr = &_list[0];
int len = String_Pixel_Width(text)+CELL_PIXEL_W;
int right = TacPixelX + Lepton_To_Pixel(TacLeptonWidth);
/*
** If the help text would spill into the sidebar, then flag this fact, but
** shorten the apparent length so that the icon list calculation will
** function correctly.
*/
if (x+len >= TacPixelX+Lepton_To_Pixel(TacLeptonWidth)) {
len = right-x;
*ptr++ = REFRESH_SIDEBAR;
count--;
}
/*
** Build the list of overlap cell offset values according to the text
** coordinate and the length.
*/
if (x <= right) {
CELL ul = Click_Cell_Calc(x, y-1);
CELL lr = Click_Cell_Calc(x+len-1, Bound(y+24, TacPixelY, TacPixelY+Lepton_To_Pixel(TacLeptonHeight) - 1));
if (ul == -1) ul = Click_Cell_Calc(x, y);
if (ul != -1 && lr != -1) {
for (int yy = Cell_Y(ul); yy <= Cell_Y(lr); yy++) {
for (int xx = Cell_X(ul); xx <= Cell_X(lr); xx++) {
*ptr++ = XY_Cell(xx, yy) - Coord_Cell(TacticalCoord);
count--;
if (count < 2) break;
}
if (count < 2) break;
}
}
}
*ptr = REFRESH_EOL;
}
return(_list);
}
/***********************************************************************************************
* DisplayClass::Set_View_Dimensions -- Sets the tactical display screen coordinates. *
* *
* Use this routine to set the tactical map screen coordinates and dimensions. This routine *
* is typically used when the screen size or position changes as a result of the sidebar *
* changing position or appearance. *
* *
* INPUT: x,y -- The X and Y pixel position on the screen for the tactical map upper left *
* corner. *
* *
* width -- The width of the tactical display (in icons). If this parameter is *
* omitted, then the width will be as wide as the screen will allow. *
* *
* height-- The height of the tactical display (in icons). If this parameter is *
* omitted, then the width will be as wide as the screen will allow. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/06/1994 JLB : Created. *
* 06/27/1995 JLB : Adjusts tactical map position if necessary. *
*=============================================================================================*/
void DisplayClass::Set_View_Dimensions(int x, int y, int width, int height)
{
if (width == -1) {
TacLeptonWidth = Pixel_To_Lepton(SeenBuff.Get_Width()-x);
} else {
TacLeptonWidth = width * CELL_LEPTON_W;
}
if (height == -1) {
height = (SeenBuff.Get_Height()-y) / CELL_PIXEL_H;
}
TacLeptonHeight = height * CELL_LEPTON_H;
/*
** Adjust the tactical cell if it is now in an invalid position
** because of the changed dimensions.
*/
int xx = Coord_X(TacticalCoord) - (MapCellX * CELL_LEPTON_W);
int yy = Coord_Y(TacticalCoord) - (MapCellY * CELL_LEPTON_H);
Confine_Rect(&xx, &yy, TacLeptonWidth, TacLeptonHeight, MapCellWidth * CELL_LEPTON_W, MapCellHeight * CELL_LEPTON_H);
Set_Tactical_Position(XY_Coord(xx + (MapCellX * CELL_LEPTON_W), yy + (MapCellY * CELL_LEPTON_H)));
TacPixelX = x;
TacPixelY = y;
WindowList[WINDOW_TACTICAL][WINDOWX] = x;
WindowList[WINDOW_TACTICAL][WINDOWY] = y;
WindowList[WINDOW_TACTICAL][WINDOWWIDTH] = Lepton_To_Pixel(TacLeptonWidth);
WindowList[WINDOW_TACTICAL][WINDOWHEIGHT] = Lepton_To_Pixel(TacLeptonHeight);
if (Window == WINDOW_TACTICAL) {
Change_Window(0);
Change_Window(Window);
}
IsToRedraw = true;
Flag_To_Redraw(false);
TacButton.X = TacPixelX;
TacButton.Y = TacPixelY;
TacButton.Width = Lepton_To_Pixel(TacLeptonWidth);
TacButton.Height = Lepton_To_Pixel(TacLeptonHeight);
}
/***********************************************************************************************
* DisplayClass::Set_Cursor_Shape -- Changes the shape of the terrain square cursor. *
* *
* This routine is used to set up the terrain cursor according to the size of the object *
* that is to be placed down. The terrain cursor looks like an arbitrary collection of *
* hatched square overlays. Typical use is when placing buildings. *
* *
* INPUT: list -- A pointer to the list that contains offsets to the cells that are to *
* be marked. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/03/1994 JLB : Created. *
* 06/26/1995 JLB : Puts placement cursor into static buffer. *
*=============================================================================================*/
void DisplayClass::Set_Cursor_Shape(short const * list)
{
if (CursorSize) {
Cursor_Mark(ZoneCell+ZoneOffset, false);
}
ZoneOffset = 0;
if (list) {
int w,h;
static short _list[50];
memcpy(_list, list, sizeof(_list));
CursorSize = _list;
Get_Occupy_Dimensions (w, h, CursorSize);
ZoneOffset = -(((h/2)*MAP_CELL_W)+(w/2));
Cursor_Mark(ZoneCell+ZoneOffset, true);
} else {
CursorSize = 0;
}
}
/***********************************************************************************************
* DisplayClass::Passes_Proximity_Check -- Determines if building placement is near friendly sq*
* *
* This routine is used by the building placement cursor logic to determine whether the *
* at the current cursor position if the building would be adjacent to another friendly *
* building. In cases where this is not true, then the building cannot be placed at all. *
* This determination is returned by the function. *
* *
* INPUT: object -- The building object that the current placement system is examining. *
* *
* house -- The house to base the proximity check upon. Typically this is the *
* player's house, but in multiplay, the computer needs to check for *
* proximity as well. *
* *
* list -- Pointer to the building's offset list. *
* *
* trycell -- The cell to base the offset list on. *
* *
* OUTPUT: bool; Can the pending building object be placed at the present cursor location *
* checking only for proximity to friendly buildings? If this isn't for a *
* building type object, then this routine always returns true. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/06/1994 JLB : Created. *
* 06/07/1994 JLB : Handles concrete check. *
* 10/11/1994 BWG : Added IsProximate check for ore refineries *
*=============================================================================================*/
bool DisplayClass::Passes_Proximity_Check(ObjectTypeClass const * object, HousesType house, short const * list, CELL trycell) const
{
short const * ptr;
int retval = -1;
bool noradar = false;
bool nomapped = false;
bool shipyard = false;
if (house == PlayerPtr->Class->House) {
PassedProximity = false;
}
/*
** In editor mode, the proximity check always passes.
*/
if (Debug_Map) {
return(true);
}
if (list == NULL || trycell == 0) {
return(true);
}
if (object == NULL || object->What_Am_I() != RTTI_BUILDINGTYPE) {
return(true);
}
BuildingTypeClass const * building = (BuildingTypeClass const *)object;
/*
** Scan through all cells that the building foundation would cover. If any adjacent
** cells to these are of friendly persuasion, then consider the proximity check to
** have been a success.
*/
ptr = list;
// ptr = CursorSize;
CELL cell = trycell;
// CELL cell = ZoneCell;
if (building->Adjacent == 1) {
while (*ptr != REFRESH_EOL && (retval == -1) ) {
cell = trycell + *ptr++;
// cell = ZoneCell + ZoneOffset + *ptr++;
if (!In_Radar(cell)) {
retval = false;
noradar = true;
break;
}
for (FacingType facing = FACING_FIRST; facing < FACING_COUNT; facing++) {
CELL newcell = Adjacent_Cell(cell, facing);
if (!In_Radar(newcell)) continue;
if (!(*this)[newcell].IsMapped) {
nomapped = true;
}
TechnoClass * base = (*this)[newcell].Cell_Techno();
/*
** The special cell ownership flag allows building adjacent
** to friendly walls and bibs even though there is no official
** building located there.
*/
//BG: Modified so only walls can be placed next to walls - buildings can't.
//JLB: Except for bibs, in which case buildings can be placed next to these.
if (building->IsWall ||
((*this)[newcell].Smudge != SMUDGE_NONE && SmudgeTypeClass::As_Reference((*this)[newcell].Smudge).IsBib)) {
if ((*this)[newcell].Owner == house) {
retval = true;
break;
}
}
// we've found a building...
if (base != NULL && base->What_Am_I() == RTTI_BUILDING && base->House->Class->House == house && ((BuildingClass *)base)->Class->IsBase) {
retval = true;
break;
}
/* BG: modifications to allow buildings one cell away from other buildings.
** This is done by scanning each cell that fails the check (hence getting
** to this point) and looking at the n/s/e/w adjacent cells to see if they
** have buildings in them. If they do, and they match us, then succeed.
*/
if (retval != -1) break;
for (FacingType newface = FACING_N; newface < FACING_COUNT; newface++) {
CELL newercell = Adjacent_Cell(newcell, newface);
if (building->IsWall ||
((*this)[newercell].Smudge != SMUDGE_NONE && SmudgeTypeClass::As_Reference((*this)[newercell].Smudge).IsBib)) {
if ((*this)[newercell].Owner == house) {
retval = true;
break;
}
}
TechnoClass * newbase = (*this)[newercell].Cell_Techno();
// we've found a building...
if (newbase != NULL && newbase->What_Am_I() == RTTI_BUILDING && newbase->House->Class->House == house && ((BuildingClass const *)newbase)->Class->IsBase) {
retval = true;
break;
}
}
if (retval != -1) break;
}
}
}
if (retval == -1) retval = false;
if (house == PlayerPtr->Class->House) {
PassedProximity = (retval != false);
}
/*
** If this object has special dispensation to be placed further than one cell from
** other regular buildings, then check for this case now. Only bother to check if
** it hasn't already been given permission to be placed down.
*/
if (!retval && !noradar && object->What_Am_I() == RTTI_BUILDINGTYPE) {
// For land mines, let's make it check proximity within 10 squares
if (building->Adjacent > 1) {
for (int index = 0; index < Buildings.Count(); index++) {
BuildingClass * obj = Buildings.Ptr(index);
if (obj != NULL && !obj->IsInLimbo && obj->House->Class->House == house && obj->Class->IsBase) {
int centdist = ::Distance(obj->Center_Coord(), Cell_Coord(cell));
centdist /= CELL_LEPTON_W;
centdist -= (obj->Class->Width() + obj->Class->Height()) / 2;
if (centdist <= building->Adjacent) {
retval = true;
break;
}
}
}
}
}
return((bool)retval);
}
/***********************************************************************************************
* DisplayClass::Set_Cursor_Pos -- Controls the display and animation of the tac cursor. *
* *
* This routine controls the location, display, and animation of the *
* tactical map cursor. *
* *
* INPUT: pos -- Position to move the cursor do. If -1 is passed then *
* the cursor will just be hidden. If the position *
* passed is the same as the last position passed in, *
* then animation could occur (based on timers). *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/22/1991 JLB : Created. *
* 06/02/1994 JLB : Converted to member function. *
* 06/08/1994 JLB : If position is -1, then follow mouse. *
* 02/28/1995 JLB : Forces placement cursor to fit on map. *
*=============================================================================================*/
CELL DisplayClass::Set_Cursor_Pos(CELL pos)
{
CELL prevpos; // Last position of cursor (for jump-back reasons).
/*
** Follow the mouse position if no cell number is provided.
*/
if (pos == -1) {
pos = Click_Cell_Calc(Get_Mouse_X(), Get_Mouse_Y());
}
if (CursorSize == NULL) {
prevpos = ZoneCell;
ZoneCell = pos;
return(prevpos);
}
/*
** Adjusts the position so that the placement cursor is never part way off the
** tactical map.
*/
int w,h;
Get_Occupy_Dimensions(w, h, CursorSize);
int x = Cell_X(pos + ZoneOffset);
int y = Cell_Y(pos + ZoneOffset);
if (x < Coord_XCell(TacticalCoord)) x = Coord_XCell(TacticalCoord);
if (y < Coord_YCell(TacticalCoord)) y = Coord_YCell(TacticalCoord);
if (x+w >= Coord_XCell(TacticalCoord) + Lepton_To_Cell(TacLeptonWidth)) x = Coord_XCell(TacticalCoord)+Lepton_To_Cell(TacLeptonWidth)-w;
if (y+h >= Coord_YCell(TacticalCoord) + Lepton_To_Cell(TacLeptonHeight)) y = Coord_YCell(TacticalCoord)+Lepton_To_Cell(TacLeptonHeight)-h;
pos = XY_Cell(x, y) - ZoneOffset;
/*
** This checks to see if NO animation or drawing is to occur and, if so,
** exits.
*/
if (pos == ZoneCell) return(pos);
prevpos = ZoneCell;
/*
** If the cursor is visible, then handle the graphic update.
** Otherwise, just update the global position of the cursor.
*/
if (CursorSize != NULL) {
/*
** Erase the old cursor (if it exists) AND the cursor is moving.
*/
if (pos != ZoneCell && ZoneCell != -1) {
Cursor_Mark(ZoneCell+ZoneOffset, false);
}
/*
** Render the cursor (could just be animation).
*/
if (pos != -1) {
Cursor_Mark(pos+ZoneOffset, true);
}
}
ZoneCell = pos;
ProximityCheck = Passes_Proximity_Check(PendingObject, PendingHouse, CursorSize, ZoneCell+ZoneOffset);
return(prevpos);
}
/***********************************************************************************************
* DisplayClass::Get_Occupy_Dimensions -- computes width & height of the given occupy list *
* *
* INPUT: *
* w ptr to fill in with height *
* h ptr to fill in with width *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 03/31/1995 BRR : Created. *
*=============================================================================================*/
void DisplayClass::Get_Occupy_Dimensions(int & w, int & h, short const * list) const
{
int min_x = MAP_CELL_W;
int max_x = -MAP_CELL_W;
int min_y = MAP_CELL_H;
int max_y = -MAP_CELL_H;
int x,y;
w = 0;
h = 0;
if (!list) {
/*
** Loop through all cell offsets, accumulating max & min x- & y-coords
*/
while (*list != REFRESH_EOL) {
/*
** Compute x & y coords of the current cell offset. We can't use Cell_X()
** & Cell_Y(), because they use shifts to compute the values, and if the
** offset is negative we'll get a bogus coordinate!
*/
x = (*list) % MAP_CELL_W;
y = (*list) / MAP_CELL_H;
max_x = max(max_x, x);
min_x = min(min_x, x);
max_y = max(max_y, y);
min_y = min(min_y, y);
list++;
}
w = max(1, max_x - min_x + 1);
h = min(1, max_y - min_y + 1);
}
}
/***********************************************************************************************
* DisplayClass::Cursor_Mark -- Set or resets the cursor display flag bits. *
* *
* This routine will clear or set the cursor display bits on the map. *
* If the bit is set, then the cursor will be rendered on that map *
* icon. *
* *
* INPUT: pos -- Position of the upper left corner of the cursor. *
* *
* on -- Should the bit be turned on? *
* *
* OUTPUT: none *
* *
* WARNINGS: Be sure that every call to set the bits is matched by a *
* corresponding call to clear the bits. *
* *
* HISTORY: *
* 09/04/1991 JLB : Created. *
* 06/02/1994 JLB : Converted to member function. *
*=============================================================================================*/
void DisplayClass::Cursor_Mark(CELL pos, bool on)
{
CELL const * ptr;
CellClass * cellptr;
if (pos == -1) return;
/*
** For every cell in the CursorSize list, invoke its Redraw_Objects and
** toggle its IsCursorHere flag
*/
ptr = CursorSize;
while (*ptr != REFRESH_EOL) {
CELL cell = pos + *ptr++;
if (In_Radar(cell)) {
cellptr = &(*this)[cell];
cellptr->Redraw_Objects();
if (on) {
cellptr->IsCursorHere = true;
} else {
cellptr->IsCursorHere = false;
}
}
}
/*
** For every cell in the PendingObjectPtr's Overlap_List, invoke its
** Redraw_Objects routine.
*/
if (PendingObjectPtr) {
ptr = PendingObjectPtr->Overlap_List();
while (*ptr != REFRESH_EOL) {
CELL cell = pos + *ptr++;
if (In_Radar(cell)) {
cellptr = &(*this)[cell];
cellptr->Redraw_Objects();
}
}
}
}
/***********************************************************************************************
* DisplayClass::AI -- Handles the maintenance tasks for the map display. *
* *
* This routine is called once per game display frame (15 times per second). It handles *
* the mouse shape tracking and map scrolling as necessary. *
* *
* INPUT: input -- The next key just fetched from the input queue. *
* *
* x,y -- Mouse coordinates. *
* *
* OUTPUT: Modifies the input code if necessary. When the input code is consumed, it gets *
* set to 0. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/01/1994 JLB : Created. *
* 06/02/1994 JLB : Filters mouse click input. *
* 06/07/1994 JLB : Fixed so template click will behave right. *
* 10/14/1994 JLB : Changing cursor shape over target. *
* 12/31/1994 JLB : Takes mouse coordinates as parameters. *
* 06/27/1995 JLB : Breaks out of rubber band mode if mouse leaves map. *
*=============================================================================================*/
void DisplayClass::AI(KeyNumType & input, int x, int y)
{
if (
IsRubberBand &&
(Get_Mouse_X() < TacPixelX ||
Get_Mouse_Y() < TacPixelY ||
Get_Mouse_X() >= (TacPixelX + Lepton_To_Pixel(TacLeptonWidth)) ||
Get_Mouse_Y() >= (TacPixelY + Lepton_To_Pixel(TacLeptonHeight)))) {
Mouse_Left_Release(-1, Get_Mouse_X(), Get_Mouse_Y(), NULL, ACTION_NONE);
}
MapClass::AI(input, x, y);
}
/***********************************************************************************************
* DisplayClass::Submit -- Adds a game object to the map rendering system. *
* *
* This routine is used to add an arbitrary (but tangible) game object to the map. It will *
* be rendered (made visible) once it is submitted to this function. This function builds *
* the list of game objects that get rendered each frame as necessary. It is possible to *
* submit the game object to different rendering layers. All objects in a layer get drawn *
* at the same time. Using this layer method it becomes possible to have objects "below" *
* other objects. *
* *
* INPUT: object -- Pointer to the object to add. *
* *
* layer -- The layer to add the object to. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/31/1994 JLB : Created. *
* 05/31/1994 JLB : Improved layer system. *
* 05/31/1994 JLB : Sorts object position if this is for the ground layer. *
*=============================================================================================*/
void DisplayClass::Submit(ObjectClass const * object, LayerType layer)
{
if (object) {
Layer[layer].Submit(object, (layer == LAYER_GROUND));
}
}
/***********************************************************************************************
* DisplayClass::Remove -- Removes a game object from the rendering system. *
* *
* Every object that is to disappear from the map must be removed from the rendering *
* system. *
* *
* INPUT: object -- The object to remove. *
* *
* layer -- The layer to remove it from. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/31/1994 JLB : Created. *
* 05/31/1994 JLB : Improved layer system. *
*=============================================================================================*/
void DisplayClass::Remove(ObjectClass const * object, LayerType layer)
{
assert(object != 0);
assert(object->IsActive);
if (object) {
Layer[layer].Delete((ObjectClass *)object);
}
}
/***********************************************************************************************
* DisplayClass::Click_Cell_Calc -- Determines cell from screen X & Y. *
* *
* This routine is used to determine the cell that is located at the *
* screen pixel coordinates given. Typical use is when the player *
* clicks with the mouse on the tactical map. *
* *
* INPUT: x,y -- Screen pixel coordinates. *
* *
* OUTPUT: Returns with cell that is under the coordinates specified. *
* If the coordinate specified is outside of the tactical *
* map, then -1 is returned. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/27/1994 JLB : Created. *
*=============================================================================================*/
CELL DisplayClass::Click_Cell_Calc(int x, int y) const
{
x -= TacPixelX;
x = Pixel_To_Lepton(x);
y -= TacPixelY;
y = Pixel_To_Lepton(y);
if ((unsigned)x < TacLeptonWidth && (unsigned)y < TacLeptonHeight) {
COORDINATE tcoord = XY_Coord(Pixel_To_Lepton(Lepton_To_Pixel(Coord_X(TacticalCoord))), Pixel_To_Lepton(Lepton_To_Pixel(Coord_Y(TacticalCoord))));
return(Coord_Cell(Coord_Add(tcoord, XY_Coord(x, y))));
}
return(-1);
}
/***********************************************************************************************
* DisplayClass::Scroll_Map -- Scroll the tactical map in desired direction. *
* *
* This routine is used to scroll the tactical map view in the desired *
* direction. It can also be used to determine if scrolling would be *
* legal without actually performing any scrolling action. *
* *
* INPUT: facing -- The direction to scroll the tactical map. *
* *
* distance -- The distance in leptons to scroll the map. *
* *
* really -- Should the map actually be scrolled? If false, *
* then only the legality of a scroll is checked. *
* *
* OUTPUT: bool; Would scrolling in the desired direction be possible? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 10/07/1992 JLB : Created. *
* 05/20/1994 JLB : Converted to member function. *
* 08/09/1995 JLB : Added distance parameter. *
* 08/10/1995 JLB : Any direction scrolling. *
*=============================================================================================*/
bool DisplayClass::Scroll_Map(DirType facing, int & distance, bool really)
{
/*
** If the distance is invalid then no further checking is required. Bail
** with a no-can-do flag.
*/
if (distance == 0) return(false);
FacingType crude = Dir_Facing(facing);
if (Coord_X(TacticalCoord) == Cell_To_Lepton(MapCellX) && crude != FACING_W) {
if (crude == FACING_SW) facing = DIR_S;
if (crude == FACING_NW) facing = DIR_N;
}
if (Coord_Y(TacticalCoord) == Cell_To_Lepton(MapCellY) && crude != FACING_N) {
if (crude == FACING_NW) facing = DIR_W;
if (crude == FACING_NE) facing = DIR_E;
}
if (Coord_X(TacticalCoord) + TacLeptonWidth == Cell_To_Lepton(MapCellX+MapCellWidth) && crude != FACING_E) {
if (crude == FACING_NE) facing = DIR_N;
if (crude == FACING_SE) facing = DIR_S;
}
if (Coord_Y(TacticalCoord) + TacLeptonHeight == Cell_To_Lepton(MapCellY+MapCellHeight) && crude != FACING_S) {
if (crude == FACING_SE) facing = DIR_E;
if (crude == FACING_SW) facing = DIR_W;
}
/*
** Determine the coordinate that it wants to scroll to.
*/
COORDINATE coord = Coord_Move(TacticalCoord, facing, distance);
/*
** Clip the new coordinate to the edges of the game world.
*/
int xx = (int)(short)Coord_X(coord) - (short)Cell_To_Lepton(MapCellX);
int yy = (int)(short)Coord_Y(coord) - (short)Cell_To_Lepton(MapCellY);
bool shifted = Confine_Rect(&xx, &yy, TacLeptonWidth, TacLeptonHeight, Cell_To_Lepton(MapCellWidth), Cell_To_Lepton(MapCellHeight));
if (xx < 0) {
xx = 0;
shifted = true;
}
if (yy < 0) {
yy = 0;
shifted = true;
}
coord = XY_Coord(xx + Cell_To_Lepton(MapCellX), yy + Cell_To_Lepton(MapCellY));
/*
** If the desired scroll was bound by the edge of the map, then adjust the distance to more accurately
** reflect the actual distance moved.
*/
if (shifted) {
distance = Distance(TacticalCoord, coord);
}
/*
** If the new coordinate is the same as the old, then no scrolling would occur.
*/
if (!distance || coord == TacticalCoord) return(false);
/*
** Since the new coordinate is different than the old one, possibly adjust the real
** tactical map accordingly.
*/
if (really) {
Set_Tactical_Position(coord);
IsToRedraw = true;
Flag_To_Redraw(false);
/*
** Scrolled map REQUIRES all top layer units to be redrawn.
*/
for (int index = 0; index < Layer[LAYER_TOP].Count(); index++) {
Layer[LAYER_TOP][index]->Mark(MARK_CHANGE);
}
for (index = 0; index < Layer[LAYER_AIR].Count(); index++) {
Layer[LAYER_AIR][index]->Mark(MARK_CHANGE);
}
}
return(true);
}
/***********************************************************************************************
* DisplayClass::Refresh_Cells -- Redraws all cells in list. *
* *
* This routine is used to flag all cells in the specified list for *
* redrawing. *
* *
* INPUT: cell -- The origin cell that the list is offset from. *
* *
* list -- Pointer to a list of offsets from the origin cell. *
* Each cell so specified is flagged for redraw. *
* *
* OUTPUT: none *
* *
* WARNINGS: This routine is rather slow (by definition). *
* *
* HISTORY: *
* 05/14/1994 JLB : Created. *
* 08/01/1994 JLB : Simplified. *
*=============================================================================================*/
void DisplayClass::Refresh_Cells(CELL cell, short const * list)
{
short tlist[36];
if (*list == REFRESH_SIDEBAR) {
list++;
}
List_Copy(list, ARRAY_SIZE(tlist), tlist);
short * tt = tlist;
while (*tt != REFRESH_EOL) {
CELL newcell = cell + *tt++;
if (In_Radar(newcell)) {
(*this)[newcell].Redraw_Objects();
}
}
}
/***********************************************************************************************
* DisplayClass::Cell_Shadow -- Determine what shadow icon to use for the cell. *
* *
* This routine will examine the specified cell and adjacent cells to *
* determine what shadow icon to use. *
* *
* INPUT: cell -- The cell to examine. *
* *
* OUTPUT: Returns with the shadow icon to use. -2= all black. *
* -1= map cell. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 03/01/1994 JLB : Created. *
* 04/04/1994 JLB : Revamped for new shadow icon method. *
* 04/30/1994 JLB : Converted to member function. *
*=============================================================================================*/
int DisplayClass::Cell_Shadow(CELL cell) const
{
static char const _shadow[256]={
-1,33, 2, 2,34,37, 2, 2,
4,26, 6, 6, 4,26, 6, 6,
35,45,17,17,38,41,17,17,
4,26, 6, 6, 4,26, 6, 6,
8,21,10,10,27,31,10,10,
12,23,14,14,12,23,14,14,
8,21,10,10,27,31,10,10,
12,23,14,14,12,23,14,14,
32,36,25,25,44,40,25,25,
19,30,20,20,19,30,20,20,
39,43,29,29,42,46,29,29,
19,30,20,20,19,30,20,20,
8,21,10,10,27,31,10,10,
12,23,14,14,12,23,14,14,
8,21,10,10,27,31,10,10,
12,23,14,14,12,23,14,14,
1, 1, 3, 3,16,16, 3, 3,
5, 5, 7, 7, 5, 5, 7, 7,
24,24,18,18,28,28,18,18,
5, 5, 7, 7, 5, 5, 7, 7,
9, 9,11,11,22,22,11,11,
13,13,-2,-2,13,13,-2,-2,
9, 9,11,11,22,22,11,11,
13,13,-2,-2,13,13,-2,-2,
1, 1, 3, 3,16,16, 3, 3,
5, 5, 7, 7, 5, 5, 7, 7,
24,24,18,18,28,28,18,18,
5, 5, 7, 7, 5, 5, 7, 7,
9, 9,11,11,22,22,11,11,
13,13,-2,-2,13,13,-2,-2,
9, 9,11,11,22,22,11,11,
13,13,-2,-2,13,13,-2,-2
};
int index = 0, value = -1;
/*
** Don't map cells that are at the top or bottom edge. This solves
** problem of accessing cells off the top or bottom of the map and into
** who-knows-what memory.
*/
#ifdef FIXIT_CSII // checked - ajw 9/28/98
if ((unsigned)(Cell_Y(cell)-1) >= MAP_CELL_H-2) return(-1);
#else
if ((unsigned)(Cell_Y(cell)-1) > MAP_CELL_H-2) return(-1);
#endif
//if ((unsigned)(Cell_Y(cell)-1) > MAP_CELL_H-2) return(-2);
CellClass const * cellptr = &(*this)[cell];
/*
** Presume solid black if that is what is here already.
*/
if (!cellptr->IsVisible && !cellptr->IsMapped) value = -2;
if (cellptr->IsMapped /*&& !cellptr->IsVisible*/) {
/*
** Build an index into the lookup table using all 8 surrounding cells.
** We're mapping a revealed cell and we only care about the existence
** of black cells. Bit numbering starts at the upper-right corner and
** goes around the cell clockwise, so 0x80 = directly north.
*/
cellptr-= MAP_CELL_W + 1;
if (!cellptr->IsMapped) index |= 0x40;
cellptr++;
if (!cellptr->IsMapped) index |= 0x80;
cellptr++;
if (!cellptr->IsMapped) index |= 0x01;
cellptr += MAP_CELL_W - 2;
if (!cellptr->IsMapped) index |= 0x20;
cellptr += 2;
if (!cellptr->IsMapped) index |= 0x02;
cellptr += MAP_CELL_W - 2;
if (!cellptr->IsMapped) index |= 0x10;
cellptr++;
if (!cellptr->IsMapped) index |= 0x08;
cellptr++;
if (!cellptr->IsMapped) index |= 0x04;
value = _shadow[index];
}
return(value);
}
/***********************************************************************************************
* DisplayClass::Map_Cell -- Mark specified cell as having been mapped. *
* *
* This routine maps the specified cell. The cell must not already *
* have been mapped and the mapping player must be the human. *
* This routine will update any adjacent cell map icon as appropriate. *
* *
* INPUT: cell -- The cell to be mapped. *
* *
* house -- The player that is doing the mapping. *
* *
* OUTPUT: bool; Was action taken to map this cell? *
* *
* WARNINGS: none. *
* *
* HISTORY: *
* 08/05/1992 JLB : Created. *
* 04/30/1994 JLB : Converted to member function. *
* 05/24/1994 JLB : Takes pointer to HouseClass. *
* 02/20/1996 JLB : Allied units reveal the map for the player. *
*=============================================================================================*/
bool DisplayClass::Map_Cell(CELL cell, HouseClass * house)
{
/*
** First check for the condition where we're spying on a house's radar
** facility, to see if his mapping is applicable to us.
*/
if (house && house != PlayerPtr) {
if (house->RadarSpied & (1<<(PlayerPtr->Class->House))) house = PlayerPtr;
if (Session.Type == GAME_NORMAL && house->Is_Ally(PlayerPtr)) house = PlayerPtr;
}
if (house != PlayerPtr || !In_Radar(cell)) return(false);
CellClass * cellptr = &(*this)[cell];
/*
** Don't bother remapping this cell if it is already mapped.
*/
if (cellptr->IsMapped) {
if (!cellptr->IsVisible) {
cellptr->Redraw_Objects();
}
return(false);
}
/*
** Mark the cell as being mapped. This must be done first because
** if the IsVisible flag must be set, then it might affect the
** adjacent cell processing.
*/
cellptr->IsMapped = true;
cellptr->Redraw_Objects();
if (Cell_Shadow(cell) == -1) {
cellptr->IsVisible = true;
}
/*
** Check out all adjacent cells to see if they need
** to be mapped as well. This is necessary because of the
** "unique" method of showing shadowed cells. Many combinations
** are not allowed, and to fix this, just map the cells until
** all is ok.
*/
for (FacingType dir = FACING_FIRST; dir < FACING_COUNT; dir++) {
int shadow;
CELL c;
c = Adjacent_Cell(cell, dir);
CellClass * cptr = &(*this)[c];
cptr->Redraw_Objects();
if (c != cell && !cptr->IsVisible) {
shadow = Cell_Shadow(c);
if (shadow == -1) {
if (!cptr->IsMapped) {
Map_Cell(c, house);
} else {
cptr->IsVisible = true;
}
} else {
if (shadow != -2 && !cptr->IsMapped) {
Map_Cell(c, house);
}
}
}
}
TechnoClass * tech = (*this)[cell].Cell_Techno();
if (tech) {
tech->Revealed(house);
}
return(true);
}
/***********************************************************************************************
* DisplayClass::Coord_To_Pixel -- Determines X and Y pixel coordinates. *
* *
* This is the routine that figures out the location on the screen for *
* a specified coordinate. It is one of the fundamental routines *
* necessary for rendering the game objects. It performs some quick *
* tests to see if the coordinate is in a visible region and returns *
* this check as a boolean value. *
* *
* INPUT: coord -- The coordinate to check. *
* *
* x,y -- Reference to the pixel coordinates that this *
* coordinate would be when rendered. *
* *
* OUTPUT: bool; Is this coordinate in a visible portion of the map? *
* *
* WARNINGS: If the coordinate is not in a visible portion of the *
* map, then this X and Y parameters are not set. *
* *
* HISTORY: *
* 05/14/1994 JLB : Created. *
* 12/15/1994 JLB : Converted to member function. *
* 01/07/1995 JLB : Uses inline functions to extract coord components. *
* 08/09/1995 JLB : Uses new coordinate system. *
*=============================================================================================*/
#define EDGE_ZONE (CELL_LEPTON_W*2)
bool DisplayClass::Coord_To_Pixel(COORDINATE coord, int &x, int &y) const
{
if (coord) {
int xtac = Pixel_To_Lepton(Lepton_To_Pixel(Coord_X(TacticalCoord)));
int xoff = Pixel_To_Lepton(Lepton_To_Pixel(Coord_X(coord)));
xoff = (xoff+EDGE_ZONE) - xtac;
if ((unsigned)xoff <= TacLeptonWidth + EDGE_ZONE*2) {
int ytac = Pixel_To_Lepton(Lepton_To_Pixel(Coord_Y(TacticalCoord)));
int yoff = Pixel_To_Lepton(Lepton_To_Pixel(Coord_Y(coord)));
yoff = (yoff+EDGE_ZONE) - ytac;
if ((unsigned)yoff <= TacLeptonHeight + EDGE_ZONE*2) {
x = Lepton_To_Pixel(xoff)-CELL_PIXEL_W*2;
y = Lepton_To_Pixel(yoff)-CELL_PIXEL_H*2;
return(true);
}
}
}
return(false);
}
/***********************************************************************************************
* DisplayClass::Push_Onto_TacMap -- Moves x & y coords to being on tactical map *
* *
* This routine expects a line to be drawn between SOURCE & DEST, so it pushes the coords to *
* be within the region bounded by TacMapX,Y - + TacMapW,H. *
* *
* INPUT: source, dest -- References to the coordinates to check. *
* *
* *
* OUTPUT: bool; Are these coordinates in a visible portion of the map? *
* Returns true if the pushed source & dest are visible, but if neither are *
* within the map, then it returns false. *
* *
* *
* HISTORY: *
* 03/27/1995 BWG : Created. *
*=============================================================================================*/
bool DisplayClass::Push_Onto_TacMap(COORDINATE & source, COORDINATE & dest)
{
if (!source || !dest) return(false);
int x1 = Coord_X(source);
int y1 = Coord_Y(source);
int x2 = Coord_X(dest);
int y2 = Coord_Y(dest);
int left = Coord_X(TacticalCoord);
int right = Coord_X(TacticalCoord) + TacLeptonWidth;
int top = Coord_Y(TacticalCoord);
int bottom = Coord_Y(TacticalCoord) + TacLeptonHeight;
if (x1 < left && x2 < left) return(false);
if (x1 > right && x2 > right) return(false);
if (y1 < top && y2 < top) return(false);
if (y1 > bottom && y2 > bottom) return(false);
x1 = Bound(x1, left, right);
x2 = Bound(x2, left, right);
y1 = Bound(y1, top, bottom);
y2 = Bound(y2, top, bottom);
source = XY_Coord(x1, y1);
dest = XY_Coord(x2, y2);
return(true);
}
/***********************************************************************************************
* DisplayClass::Cell_Object -- Determines what has been clicked on. *
* *
* This routine is used to determine what the player has clicked on. *
* It is passed the cell that the click was on and it then examines *
* the cell and returns with a pointer to the object that is there. *
* *
* INPUT: cell -- The cell that has been clicked upon. *
* *
* x,y -- Optional offsets from the upper left corner of the cell to be used in *
* determining exactly which object in the cell is desired. *
* *
* OUTPUT: Returns with a pointer to the object that is "clickable" in *
* the specified cell. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/14/1994 JLB : Created. *
*=============================================================================================*/
ObjectClass * DisplayClass::Cell_Object(CELL cell, int x, int y) const
{
return(*this)[cell].Cell_Object(x, y);
}
/***********************************************************************************************
* DisplayClass::Draw_It -- Draws the tactical map. *
* *
* This will draw the tactical map at the recorded position. This *
* routine is used whenever the tactical map moves or needs to be *
* completely redrawn. It will handle making the necessary adjustments *
* to accomodate a moving cursor. *
* *
* INPUT: forced -- bool; force redraw of the entire display? *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 04/15/1991 JLB : Created. (benchmark = 292) *
* 04/15/1991 JLB : Added _cell2meta[] reference array (206) *
* 04/15/1991 JLB : Added actual map reference for terrain (207) *
* 04/16/1991 JLB : _cell2meta converted to int (194) *
* 04/16/1991 JLB : References actual CellIcon[] array (204) *
* 04/16/1991 JLB : Cell size increased to 16 x 16 (167) *
* 04/17/1991 JLB : Cell based tactical map rendering (165) *
* 04/22/1991 JLB : Uses Draw_Stamp() for icon rendering (426) *
* 04/22/1991 JLB : Draw_Stamp uses LogicPage now (276) *
* 04/23/1991 JLB : Map active location cursor (334) *
* 05/02/1991 JLB : Added smoothing and 3 icons sets (431) *
* 05/22/1991 JLB : Broken into Draw_Map() and Refresh_Map(). *
* 09/14/1991 JLB : Uses Refresh_Cell when new cells scroll onto display. *
* 05/12/1992 JLB : Destination page support. *
* 02/14/1994 JLB : Revamped. *
* 05/01/1994 JLB : Converted to member function. *
* 12/15/1994 JLB : Updated to work with display hierarchy. *
* 12/24/1994 JLB : Examines redraw bit intelligently. *
* 12/24/1994 JLB : Combined with old Refresh_Map() function. *
* 01/10/1995 JLB : Rubber band drawing. *
*=============================================================================================*/
void DisplayClass::Draw_It(bool forced)
{
int x,y; // Working cell index values.
MapClass::Draw_It(forced);
if (IsToRedraw || forced) {
BStart(BENCH_TACTICAL);
IsToRedraw = false;
/*
** In rubber band mode, mark all cells under the "rubber band" to be
** redrawn.
*/
Refresh_Band();
/*
** Mark all cells under the vortex to be redrawn
*/
ChronalVortex.Set_Redraw();
/*
** If the multiplayer message system is displaying one or more messages,
** flag all cells covered by the messages to redraw. This will prevent
** messages from smearing the map if it scrolls.
*/
int num = Session.Messages.Num_Messages();
if (num > 0) {
for (CELL cell = Coord_Cell(TacticalCoord); cell < Coord_Cell(TacticalCoord) + Lepton_To_Cell(TacLeptonWidth)+1; cell++) {
(*this)[cell].Redraw_Objects();
}
for (cell = Coord_Cell(TacticalCoord) + MAP_CELL_W;
cell < Coord_Cell(TacticalCoord) + MAP_CELL_W + Lepton_To_Cell(TacLeptonWidth)+1; cell++) {
(*this)[cell].Redraw_Objects();
}
if (num > 1) {
for (cell = Coord_Cell(TacticalCoord) + MAP_CELL_W*2;
cell < Coord_Cell(TacticalCoord) + MAP_CELL_W*2 + Lepton_To_Cell(TacLeptonWidth)+1; cell++) {
(*this)[cell].Redraw_Objects();
}
}
if (num > 2) {
for (cell = Coord_Cell(TacticalCoord) + MAP_CELL_W*3;
cell < Coord_Cell(TacticalCoord) + MAP_CELL_W*3 + Lepton_To_Cell(TacLeptonWidth)+1; cell++) {
(*this)[cell].Redraw_Objects();
}
}
if (num > 3) {
for (cell = Coord_Cell(TacticalCoord) + MAP_CELL_W*4;
cell < Coord_Cell(TacticalCoord) + MAP_CELL_W*4 + Lepton_To_Cell(TacLeptonWidth)+1; cell++) {
(*this)[cell].Redraw_Objects();
}
}
}
/*
** Check for a movement of the tactical map. If there has been some
** movement, then part (or all) of the icons must be redrawn.
*/
if (Lepton_To_Pixel(Coord_X(DesiredTacticalCoord)) != Lepton_To_Pixel(Coord_X(TacticalCoord)) ||
Lepton_To_Pixel(Coord_Y(DesiredTacticalCoord)) != Lepton_To_Pixel(Coord_Y(TacticalCoord))) {
int xmod = Lepton_To_Pixel(Coord_X(DesiredTacticalCoord));
int ymod = Lepton_To_Pixel(Coord_Y(DesiredTacticalCoord));
int oldx = Lepton_To_Pixel(Coord_X(TacticalCoord))-xmod; // Old relative offset.
int oldy = Lepton_To_Pixel(Coord_Y(TacticalCoord))-ymod;
int oldw = Lepton_To_Pixel(TacLeptonWidth)-ABS(oldx); // Replicable width.
int oldh = Lepton_To_Pixel(TacLeptonHeight)-ABS(oldy); // Replicable height.
if (oldw < 1) forced = true;
if (oldh < 1) forced = true;
#ifdef WIN32 //For WIN32 only redraw the edges of the map that move into view
/*
** Work out which map edges need to be redrawn
*/
BOOL redraw_right = (oldx < 0) ? true : false; //Right hand edge
BOOL redraw_left = (oldx > 0) ? true : false; //Left hand edge
BOOL redraw_bottom= (oldy < 0) ? true : false; //Bottom edge
BOOL redraw_top = (oldy > 0) ? true : false; //Top edge
/*
** Blit any replicable block to avoid having to drawstamp.
*/
if (!forced && (oldw != Lepton_To_Pixel(TacLeptonWidth) || oldh != Lepton_To_Pixel(TacLeptonHeight))) {
Set_Cursor_Pos(-1);
/*
** If hid page is in video memory then blit from the seen page to avoid blitting
** an overlapped region.
*/
if (HidPage.Get_IsDirectDraw()) {
Hide_Mouse();
SeenBuff.Blit(HidPage,
((oldx < 0) ? -oldx : 0) +TacPixelX,
((oldy < 0) ? -oldy : 0) +TacPixelY,
((oldx < 0) ? 0 : oldx) +TacPixelX,
((oldy < 0) ? 0 : oldy) +TacPixelY,
oldw,
oldh);
Show_Mouse();
} else {
HidPage.Blit(HidPage,
((oldx < 0) ? -oldx : 0) +TacPixelX,
((oldy < 0) ? -oldy : 0) +TacPixelY,
((oldx < 0) ? 0 : oldx) +TacPixelX,
((oldy < 0) ? 0 : oldy) +TacPixelY,
oldw,
oldh);
}
} else {
forced = true;
}
if (oldx < 0) oldx = 0;
if (oldy < 0) oldy = 0;
/*
** Record new map position for future reference.
*/
ScenarioInit++;
Set_Tactical_Position(DesiredTacticalCoord);
ScenarioInit--;
if (!forced) {
/*
**
** Set the 'redraw stamp' bit for any cells that could not be copied.
**
*/
int startx = -Lepton_To_Pixel(Coord_XLepton(TacticalCoord));
int starty = -Lepton_To_Pixel(Coord_YLepton(TacticalCoord));
oldw -= 24;
oldh -= 24;
if (abs(oldx) < 0x25 && abs(oldy) < 0x25) {
/*
** The width of the area we redraw depends on the scroll speed
*/
int extra_x = (abs(oldx)>=16) ? 2 : 1;
int extra_y = (abs(oldy)>=16) ? 2 : 1;
/*
** Flag the cells across the top of the visible area if required
*/
if (redraw_top) {
for (y = starty; y <= starty+CELL_PIXEL_H*extra_y; y += CELL_PIXEL_H) {
for (x = startx; x <= Lepton_To_Pixel(TacLeptonWidth)+((CELL_PIXEL_W*2)); x += CELL_PIXEL_W) {
CELL c = Click_Cell_Calc(Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1) + TacPixelX,
Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1) + TacPixelY);
if (c > 0) (*this)[c].Redraw_Objects(true);
}
}
}
/*
** Flag the cells across the bottom of the visible area if required
*/
if (redraw_bottom) {
for (y = Lepton_To_Pixel(TacLeptonHeight)-CELL_PIXEL_H*(1+extra_y); y <= Lepton_To_Pixel(TacLeptonHeight)+CELL_PIXEL_H*3; y += CELL_PIXEL_H) {
for (x = startx; x <= Lepton_To_Pixel(TacLeptonWidth)+((CELL_PIXEL_W*2)); x += CELL_PIXEL_W) {
CELL c = Click_Cell_Calc(Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1) + TacPixelX,
Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1) + TacPixelY);
if (c > 0) (*this)[c].Redraw_Objects(true);
}
}
}
/*
** Flag the cells down the left of the visible area if required
*/
if (redraw_left) {
for (x = startx; x <= startx + CELL_PIXEL_W*extra_x; x += CELL_PIXEL_W) {
for (y = starty; y <= Lepton_To_Pixel(TacLeptonHeight)+((CELL_PIXEL_H*2)); y += CELL_PIXEL_H) {
CELL c = Click_Cell_Calc(Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1) + TacPixelX,
Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1) + TacPixelY);
if (c > 0) (*this)[c].Redraw_Objects(true);
}
}
}
/*
** Flag the cells down the right of the visible area if required
*/
if (redraw_right) {
for (x = Lepton_To_Pixel(TacLeptonWidth)-CELL_PIXEL_W*(extra_x+1); x <= Lepton_To_Pixel(TacLeptonWidth)+CELL_PIXEL_W*3; x += CELL_PIXEL_W) {
for (y = starty; y <= Lepton_To_Pixel(TacLeptonHeight)+((CELL_PIXEL_H*2)); y += CELL_PIXEL_H) {
CELL c = Click_Cell_Calc(Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1) + TacPixelX,
Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1) + TacPixelY);
if (c > 0) (*this)[c].Redraw_Objects(true);
}
}
}
} else {
/*
** Set the 'redraw stamp' bit for any cells that could not be copied.
*/
int startx = -Lepton_To_Pixel(Coord_XLepton(TacticalCoord));
int starty = -Lepton_To_Pixel(Coord_YLepton(TacticalCoord));
oldw -= 24;
oldh -= 24;
for (y = starty; y <= Lepton_To_Pixel(TacLeptonHeight)+((CELL_PIXEL_H*2)); y += CELL_PIXEL_H) {
for (x = startx; x <= Lepton_To_Pixel(TacLeptonWidth)+((CELL_PIXEL_W*2)); x += CELL_PIXEL_W) {
if (x <= oldx || x >= oldx+oldw || y <= oldy || y >= oldy+oldh) {
CELL c = Click_Cell_Calc(Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1) + TacPixelX,
Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1) + TacPixelY);
if (c > 0) {
(*this)[c].Redraw_Objects(true);
}
}
}
}
}
}
} else {
/*
** Set the tactical coordinate just in case the desired tactical has changed but
** not enough to result in any visible map change. This is likely to occur with very
** slow scroll rates.
*/
ScenarioInit++;
if (DesiredTacticalCoord != TacticalCoord) {
Set_Tactical_Position(DesiredTacticalCoord);
}
ScenarioInit--;
}
#else //WIN32
/*
** Blit any replicable block to avoid having to drawstamp.
*/
if (!forced && (oldw != Lepton_To_Pixel(TacLeptonWidth) || oldh != Lepton_To_Pixel(TacLeptonHeight))) {
Set_Cursor_Pos(-1);
HidPage.Blit(HidPage,
((oldx < 0) ? -oldx : 0) +TacPixelX,
((oldy < 0) ? -oldy : 0) +TacPixelY,
((oldx < 0) ? 0 : oldx) +TacPixelX,
((oldy < 0) ? 0 : oldy) +TacPixelY,
oldw,
oldh);
} else {
forced = true;
}
if (oldx < 0) oldx = 0;
if (oldy < 0) oldy = 0;
/*
** Record new map position for future reference.
*/
ScenarioInit++;
Set_Tactical_Position(DesiredTacticalCoord);
ScenarioInit--;
if (!forced) {
/*
** Set the 'redraw stamp' bit for any cells that could not be copied.
*/
int startx = -Lepton_To_Pixel(Coord_XLepton(TacticalCoord));
int starty = -Lepton_To_Pixel(Coord_YLepton(TacticalCoord));
oldw -= 24;
oldh -= 24;
for (y = starty; y <= Lepton_To_Pixel(TacLeptonHeight)+((CELL_PIXEL_H*2)); y += CELL_PIXEL_H) {
for (x = startx; x <= Lepton_To_Pixel(TacLeptonWidth)+((CELL_PIXEL_W*2)); x += CELL_PIXEL_W) {
if (x <= oldx || x >= oldx+oldw || y <= oldy || y >= oldy+oldh) {
CELL c = Click_Cell_Calc(Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1) + TacPixelX,
Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1) + TacPixelY);
if (c > 0) {
(*this)[c].Redraw_Objects(true);
}
}
}
}
}
} else {
/*
** Set the tactical coordinate just in case the desired tactical has changed but
** not enough to result in any visible map change. This is likely to occur with very
** slow scroll rates.
*/
ScenarioInit++;
if (DesiredTacticalCoord != TacticalCoord) {
Set_Tactical_Position(DesiredTacticalCoord);
}
ScenarioInit--;
}
#endif
/*
** If the entire tactical map is forced to be redrawn, then set all the redraw flags
** and let the normal processing take care of the rest.
*/
if (forced) {
CellRedraw.Set();
}
/*
** The first order of business is to redraw all the underlying icons that are
** flagged to be redrawn.
*/
if (HidPage.Lock()) {
Redraw_Icons();
/*
** Draw the infantry bodies in this special layer.
*/
// for (int index = 0; index < Anims.Count(); index++) {
// AnimClass * anim = Anims.Ptr(index);
// if (*anim >= ANIM_CORPSE1 && *anim <= ANIM_CORPSE3) {
// anim->Render(forced);
// }
// }
#ifdef SORTDRAW
Redraw_OIcons();
#endif
HidPage.Unlock();
}
#ifndef WIN32
/*
** Once the icons are drawn, duplicate the bottom line of the screen into the phantom
** area one line below the screen. This causes the predator effect to work on any
** shape drawn at the bottom of the screen.
*/
HidPage.Blit(HidPage, 0, HidPage.Get_Height()-1, 0, HidPage.Get_Height(), HidPage.Get_Width(), 1, false);
#endif
if (HidPage.Lock()) {
/*
** Draw the vortex effect over the terrain
*/
ChronalVortex.Render();
/*
** Redraw the game objects layer by layer. The layer drawing occurs on the ground layer
** first and then followed by all the layers in increasing altitude.
*/
BStart(BENCH_OBJECTS);
for (LayerType layer = LAYER_FIRST; layer < LAYER_COUNT; layer++) {
for (int index = 0; index < Layer[layer].Count(); index++) {
ObjectClass * ptr = Layer[layer][index];
#ifdef SORTDRAW
/*
** Techno objects are drawn as part of the cell redraw process since techno
** objects in the ground layer are handled by the Occupier and Overlapper
** pointer lists.
*/
if (!Debug_Map && ptr->Is_Techno() && layer == LAYER_GROUND && ((TechnoClass*)ptr)->Visual_Character() == VISUAL_NORMAL) continue;
#endif
// if (ptr->What_Am_I() == RTTI_ANIM && *((AnimClass*)ptr) >= ANIM_CORPSE1 && *((AnimClass*)ptr) <= ANIM_CORPSE3) {
// continue;
// }
assert(ptr->IsActive);
ptr->Render(forced);
}
}
BEnd(BENCH_OBJECTS);
//ChronalVortex.Render();
/*
** Finally, redraw the shadow overlay as necessary.
*/
BStart(BENCH_SHROUD);
Redraw_Shadow();
BEnd(BENCH_SHROUD);
}
HidPage.Unlock();
#ifdef SORTDRAW
for (int index = 0; index < Layer[LAYER_GROUND].Count(); index++) {
Layer[LAYER_GROUND][index]->IsToDisplay = false;
}
#endif
/*
** Draw the rubber band over the top of it all.
*/
if (IsRubberBand) {
LogicPage->Draw_Rect(BandX+TacPixelX, BandY+TacPixelY, NewX+TacPixelX, NewY+TacPixelY, WHITE);
}
/*
** Clear the redraw flags so that normal redraw flag setting can resume.
*/
CellRedraw.Reset();
#ifdef SCENARIO_EDITOR
/*
** If we're placing an object (PendingObject is non-NULL), and that object
** is NOT an icon, smudge, or overlay, draw it here.
** Terrain, Buildings & Aircraft aren't drawn at the cell's center coord;
** they're drawn at the upper left coord, so I have to AND the coord value
** with 0xFF00FF00 to strip off the lepton coordinates, but leave the
** cell coordinates.
*/
if (Debug_Map && PendingObjectPtr) {
PendingObjectPtr->Coord = PendingObjectPtr->Class_Of().Coord_Fixup(Cell_Coord(ZoneCell + ZoneOffset));
PendingObjectPtr->Render(true);
}
#endif
BEnd(BENCH_TACTICAL);
}
}
/***********************************************************************************************
* DisplayClass::Redraw_Icons -- Draws all terrain icons necessary. *
* *
* This routine will redraw all of the terrain icons that are flagged *
* to be redrawn. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none. *
* *
* HISTORY: *
* 02/14/1994 JLB : Created. *
* 05/01/1994 JLB : Converted to member function. *
* 06/20/1994 JLB : Uses cell drawing support function. *
* 12/06/1994 JLB : Scans tactical view in separate row/column loops *
* 12/24/1994 JLB : Uses the cell bit flag array to determine what to redraw. *
*=============================================================================================*/
void DisplayClass::Redraw_Icons(void)
{
IsShadowPresent = false;
for (int y = -Coord_YLepton(TacticalCoord); y <= TacLeptonHeight; y += CELL_LEPTON_H) {
for (int x = -Coord_XLepton(TacticalCoord); x <= TacLeptonWidth; x += CELL_LEPTON_W) {
COORDINATE coord = Coord_Add(TacticalCoord, XY_Coord(x, y));
CELL cell = Coord_Cell(coord);
coord = Coord_Whole(Cell_Coord(cell));
/*
** Only cells flagged to be redraw are examined.
*/
if (In_View(cell) && Is_Cell_Flagged(cell)) {
int xpixel;
int ypixel;
if (Coord_To_Pixel(coord, xpixel, ypixel)) {
CellClass * cellptr = &(*this)[coord];
/*
** If there is a portion of the underlying icon that could be visible,
** then draw it. Also draw the cell if the shroud is off.
*/
if (cellptr->IsMapped || Debug_Unshroud) {
cellptr->Draw_It(xpixel, ypixel);
}
/*
** If any cell is not fully mapped, then flag it so that the shadow drawing
** process will occur. Only draw the shadow if Debug_Unshroud is false.
*/
if (!cellptr->IsVisible && !Debug_Unshroud) {
IsShadowPresent = true;
}
}
}
}
}
}
#ifdef SORTDRAW
void DisplayClass::Redraw_OIcons(void)
{
for (int y = -Coord_YLepton(TacticalCoord); y <= TacLeptonHeight; y += CELL_LEPTON_H) {
for (int x = -Coord_XLepton(TacticalCoord); x <= TacLeptonWidth; x += CELL_LEPTON_W) {
COORDINATE coord = Coord_Add(TacticalCoord, XY_Coord(x, y));
CELL cell = Coord_Cell(coord);
coord = Coord_Whole(Cell_Coord(cell));
/*
** Only cells flagged to be redraw are examined.
*/
if (In_View(cell) && Is_Cell_Flagged(cell)) {
int xpixel;
int ypixel;
if (Coord_To_Pixel(coord, xpixel, ypixel)) {
CellClass * cellptr = &(*this)[coord];
/*
** If there is a portion of the underlying icon that could be visible,
** then draw it. Also draw the cell if the shroud is off.
*/
if (cellptr->IsMapped || Debug_Unshroud) {
cellptr->Draw_It(xpixel, ypixel, true);
}
}
}
}
}
}
#endif
/***********************************************************************************************
* DisplayClass::Redraw_Shadow -- Draw the shadow overlay. *
* *
* This routine is called after all other tactical map rendering takes place. It draws *
* the shadow map over the tactical map. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/01/1995 JLB : Created. *
* 08/06/1995 JLB : Clips the fill rect if necessary. *
*=============================================================================================*/
void DisplayClass::Redraw_Shadow(void)
{
if (IsShadowPresent) {
for (int y = -Coord_YLepton(TacticalCoord); y <= TacLeptonHeight; y += CELL_LEPTON_H) {
for (int x = -Coord_XLepton(TacticalCoord); x <= TacLeptonWidth; x += CELL_LEPTON_W) {
COORDINATE coord = Coord_Add(TacticalCoord, XY_Coord(x, y));
CELL cell = Coord_Cell(coord);
coord = Coord_Whole(Cell_Coord(cell));
/*
** Only cells flagged to be redrawn are examined.
*/
if (In_View(cell) && Is_Cell_Flagged(cell)) {
int xpixel;
int ypixel;
if (Coord_To_Pixel(coord, xpixel, ypixel)) {
CellClass * cellptr = &(*this)[coord];
if (cellptr->IsVisible) continue;
int shadow = -2;
if (cellptr->IsMapped) {
shadow = Cell_Shadow(cell);
}
if (shadow >= 0) {
CC_Draw_Shape(ShadowShapes, shadow, xpixel, ypixel, WINDOW_TACTICAL, SHAPE_GHOST, NULL, ShadowTrans);
} else {
if (shadow != -1) {
int ww = CELL_PIXEL_W;
int hh = CELL_PIXEL_H;
if (Clip_Rect(&xpixel, &ypixel, &ww, &hh, Lepton_To_Pixel(TacLeptonWidth), Lepton_To_Pixel(TacLeptonHeight)) >= 0) {
LogicPage->Fill_Rect(TacPixelX+xpixel, TacPixelY+ypixel, TacPixelX+xpixel+ww-1, TacPixelY+ypixel+hh-1, BLACK);
}
}
}
}
}
}
}
}
}
/***********************************************************************************************
* DisplayClass::Next_Object -- Searches for next object on display. *
* *
* This utility routine is used to find the "next" object from the object specified. This *
* is typically used when is pressed and the current object shifts. *
* *
* INPUT: object -- The current object to base the "next" calculation off of. *
* *
* OUTPUT: Returns with a pointer to the next object. If there is no objects available, *
* then NULL is returned. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/20/1994 JLB : Created. *
*=============================================================================================*/
ObjectClass * DisplayClass::Next_Object(ObjectClass * object) const
{
ObjectClass * firstobj = NULL;
bool foundmatch = false;
if (object == NULL) {
foundmatch = true;
}
for (unsigned uindex = 0; uindex < Layer[LAYER_GROUND].Count(); uindex++) {
ObjectClass * obj = Layer[LAYER_GROUND][uindex];
/*
** Verify that the object can be selected by and is owned by the player.
*/
if (obj != NULL && obj->Is_Players_Army()) {
if (firstobj == NULL) firstobj = obj;
if (foundmatch) return(obj);
if (object == obj) foundmatch = true;
}
}
return(firstobj);
}
/***********************************************************************************************
* DisplayClass::Prev_Object -- Searches for the previous object on the map. *
* *
* This routine will search for the previous object. Previous is defined as the one listed *
* before the specified object in the ground layer. If there is no specified object, then *
* the last object in the ground layer is returned. *
* *
* INPUT: object -- Pointer to the object that "previous" is to be defined from. *
* *
* OUTPUT: Returns with a pointer to the object previous to the specified one. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/24/1995 JLB : Created. *
*=============================================================================================*/
ObjectClass * DisplayClass::Prev_Object(ObjectClass * object) const
{
ObjectClass * firstobj = NULL;
bool foundmatch = false;
if (object == NULL) {
foundmatch = true;
}
for (int uindex = Layer[LAYER_GROUND].Count()-1; uindex >= 0; uindex--) {
ObjectClass * obj = Layer[LAYER_GROUND][uindex];
/*
** Verify that the object can be selected by and is owned by the player.
*/
if (obj != NULL && obj->Is_Players_Army()) {
if (firstobj == NULL) firstobj = obj;
if (foundmatch) return(obj);
if (object == obj) foundmatch = true;
}
}
return(firstobj);
}
/***********************************************************************************************
* DisplayClass::Pixel_To_Coord -- converts screen coord to COORDINATE *
* *
* INPUT: *
* x,y pixel coordinates to convert *
* *
* OUTPUT: *
* COORDINATE of pixel *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 11/09/1994 BR : Created. *
* 12/06/1994 JLB : Uses map dimension variables in display class. *
* 12/10/1994 JLB : Uses union to speed building coordinate value. *
*=============================================================================================*/
COORDINATE DisplayClass::Pixel_To_Coord(int x, int y) const
{
/*
** Normalize the pixel coordinates to be relative to the upper left corner
** of the tactical map. The coordinates are expressed in leptons.
*/
x -= TacPixelX;
x = Pixel_To_Lepton(x);
y -= TacPixelY;
y = Pixel_To_Lepton(y);
/*
** If pixel coordinate is over the tactical map, then translate it into a coordinate
** value. If not, then just return with NULL.
*/
if ((unsigned)x < TacLeptonWidth && (unsigned)y < TacLeptonHeight) {
return(Coord_Add(TacticalCoord, XY_Coord(x, y)));
}
return(0);
}
/***********************************************************************************************
* DisplayClass::Calculated_Cell -- Fetch a map cell based on specified method. *
* *
* Find a cell meeting the specified requirements. This function is *
* used for scenario reinforcements. *
* *
* INPUT: dir -- Method of picking a map cell. *
* *
* waypoint -- Closest waypoint to use for finding appropriate map edge. *
* *
* cell -- Cell to find closest edge to if waypoint not specified. *
* *
* loco -- The locomotion of the reinforcements that are trying to enter. *
* *
* zonecheck -- Is zone checking required? *
* *
* mzone -- The movement zone type to check against (only if zone checking). *
* *
* OUTPUT: Returns with the calculated cell. If 0, then this indicates *
* that no legal cell was found. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 10/07/1992 JLB : Created. *
* 04/11/1994 JLB : Revamped. *
* 05/18/1994 JLB : Converted to member function. *
* 12/18/1995 JLB : Handles edge preference scan. *
* 06/24/1996 JLB : Removed Dune II legacy code. *
* 06/25/1996 JLB : Rewrote and greatly simplified. *
* 10/05/1996 JLB : Checks for zone and crushable status. *
*=============================================================================================*/
CELL DisplayClass::Calculated_Cell(SourceType dir, WAYPOINT waypoint, CELL cell, SpeedType loco, bool zonecheck, MZoneType mzone) const
{
bool vert = false;
bool horz = false;
int x = 0;
int y = 0;
CELL punt = 0; // If all else fails, return this cell location.
int zone = -1; // Tentative zone for legality checking.
/*
** Waypoint edge detection for ground based reinforcements that have a waypoint origin are
** determined by finding the closest map edge to the waypoint. Reinforcement location
** scanning starts from that position.
*/
CELL trycell = -1;
if (waypoint != -1) {
trycell = Scen.Waypoint[waypoint];
}
if (trycell == -1) {
trycell = cell;
}
/*
** If zone checking is requested, then find the correct zone to use.
*/
if (zonecheck && trycell != -1) {
zone = (*this)[trycell].Zones[mzone];
}
/*
** If the cell or waypoint specified as been detected as legal, then set up the map edge
** scanning values accordingly.
*/
if (trycell != -1) {
x = Cell_X(trycell) - MapCellX;
x = min(x, (-Cell_X(trycell) + (MapCellX+MapCellWidth)));
y = Cell_Y(trycell) - MapCellY;
y = min(y, (-Cell_Y(trycell) + (MapCellY+MapCellHeight)));
if (x < y) {
vert = true;
horz = false;
if ((Cell_X(trycell)-MapCellX) < MapCellWidth/2) {
x = -1;
} else {
x = MapCellWidth;
}
y = Cell_Y(trycell) - MapCellY;
} else {
vert = false;
horz = true;
if ((Cell_Y(trycell)-MapCellY) < MapCellHeight/2) {
y = -1;
} else {
y = MapCellHeight;
}
x = Cell_X(trycell) - MapCellX;
}
}
/*
** If no map edge can be inferred from the waypoint, then go with the
** map edge specified by the edge parameter.
*/
if (!vert && !horz) {
switch (dir) {
default:
case SOURCE_NORTH:
horz = true;
y = -1;
x = Random_Pick(0, MapCellWidth-1);
break;
case SOURCE_SOUTH:
horz = true;
y = MapCellHeight;
x = Random_Pick(0, MapCellWidth-1);
break;
case SOURCE_EAST:
vert = true;
x = MapCellWidth;
y = Random_Pick(0, MapCellHeight-1);
break;
case SOURCE_WEST:
vert = true;
x = -1;
y = Random_Pick(0, MapCellHeight-1);
break;
}
}
/*
** Determine the default reinforcement cell if all else fails.
*/
punt = XY_Cell(x + MapCellX, y + MapCellY);
/*
** Scan through the vertical and horizontal edges of the map looking for
** a relatively clear cell for object placement. The cell scanned is
** from the edge position specified by the X and Y variables.
*/
if (vert) {
int modifier = (x > MapCellX) ? -1 : 1;
for (int index = 0; index < MapCellHeight; index++) {
CELL trycell = XY_Cell(x + MapCellX, ((y + index) % MapCellHeight) + MapCellY);
if (Good_Reinforcement_Cell(trycell, trycell+modifier, loco, zone, mzone)) {
return(trycell);
}
}
}
if (horz) {
int modifier = (y > MapCellY) ? -MAP_CELL_W : MAP_CELL_W;
for (int index = 0; index < MapCellWidth; index++) {
CELL trycell = XY_Cell(((x + index) % MapCellWidth) + MapCellX, y + MapCellY);
if (Good_Reinforcement_Cell(trycell, trycell+modifier, loco, zone, mzone)) {
return(trycell);
}
}
}
/*
** If there was no success in finding a suitable reinforcement edge cell, then return
** with the default 'punt' cell location.
*/
return(punt);
}
/***********************************************************************************************
* DisplayClass::Good_Reinforcement_Cell -- Checks cell for renforcement legality. *
* *
* This routine will check the secified cell (given the specified conditions) and determine *
* if that is a good cell for reinforcement purposes. It checks for passability of the cell *
* as well as zone and whether blocking walls can be crushed. *
* *
* INPUT: outcell -- The cell that is just outside the edge of the map. *
* *
* incell -- The cell that is just inside the edge of the map. *
* *
* loco -- The locomotion type of the reinforcement. *
* *
* zone -- The zone that the eventual movement destination lies. A reinforcement *
* edge must fall within the same zone. *
* *
* mzone -- The zone check type to check against (if zone checking required) *
* *
* OUTPUT: bool; Is the specified cell good for reinforcement purposes? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 10/05/1996 JLB : Created. *
*=============================================================================================*/
bool DisplayClass::Good_Reinforcement_Cell(CELL outcell, CELL incell, SpeedType loco, int zone, MZoneType mzone) const
{
/*
** If the map edge location is not clear for object placement, then this is not
** a good cell for reinforcement purposes.
*/
if (!(*this)[outcell].Is_Clear_To_Move(loco, false, false)) {
return(false);
}
/*
** If it looks like the on-map cell cannot be driven on to, then return with
** the failure code.
*/
if (!(*this)[incell].Is_Clear_To_Move(loco, false, false, zone, mzone)) {
return(false);
}
/*
** If the reinforcement cell is already occupied, then return a failure code.
*/
if ((*this)[outcell].Cell_Techno() != NULL) {
return(false);
}
if ((*this)[incell].Cell_Techno() != NULL) return(false);
/*
** All tests have passed, return with success code.
*/
//Mono_Printf("<%04X>\n", incell);Keyboard->Get();
return(true);
}
/***********************************************************************************************
* DisplayClass::Select_These -- All selectable objects in region are selected. *
* *
* Use this routine to simultaneously select all objects within the coordinate region *
* specified. This routine is used by the multi-select rubber band handler. *
* *
* INPUT: coord1 -- Coordinate of one corner of the selection region. *
* *
* coord2 -- The opposite corner of the selection region. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/19/1995 JLB : Created. *
* 04/25/1995 JLB : Limited to non-building type. *
* 03/06/1996 JLB : Allows selection of aircraft with bounding box. *
*=============================================================================================*/
void DisplayClass::Select_These(COORDINATE coord1, COORDINATE coord2)
{
COORDINATE tcoord = TacticalCoord; //Cell_Coord(TacticalCell) & 0xFF00FF00L;
coord1 = Coord_Add(tcoord, coord1);
coord2 = Coord_Add(tcoord, coord2);
int x1 = Coord_X(coord1);
int x2 = Coord_X(coord2);
int y1 = Coord_Y(coord1);
int y2 = Coord_Y(coord2);
/*
** Ensure that coordinate number one represents the upper left corner
** and coordinate number two represents the lower right corner.
*/
if (x1 > x2) {
int temp = x1;
x1 = x2;
x2 = temp;
}
if (y1 > y2) {
int temp = y1;
y1 = y2;
y2 = temp;
}
/*
** Sweep through all ground layer objects and select the ones within the
** bounding box.
*/
Unselect_All();
AllowVoice = true;
for (int index = 0; index < Layer[LAYER_GROUND].Count(); index++) {
ObjectClass * obj = Layer[LAYER_GROUND][index];
COORDINATE ocoord = obj->Center_Coord();
int x = Coord_X(ocoord);
int y = Coord_Y(ocoord);
/*
** Only try to select objects that are owned by the player, are allowed to be
** selected, and are within the bounding box.
*/
HouseClass * hptr = HouseClass::As_Pointer(obj->Owner());
if ( (hptr != NULL && hptr->IsPlayerControl) &&
obj->Class_Of().IsSelectable &&
obj->What_Am_I() != RTTI_BUILDING &&
x >= x1 && x <= x2 && y >= y1 && y <= y2) {
if (obj->Select()) {
AllowVoice = false;
}
}
}
/*
** Select any aircraft with the bounding box.
*/
for (int air_index = 0; air_index < Aircraft.Count(); air_index++) {
AircraftClass * aircraft = Aircraft.Ptr(air_index);
COORDINATE ocoord = aircraft->Center_Coord();
int x = Coord_X(ocoord);
int y = Coord_Y(ocoord);
/*
** Only try to select objects that are owned by the player, are allowed to be
** selected, and are within the bounding box.
*/
if ( aircraft->House->IsPlayerControl &&
aircraft->Class->IsSelectable &&
!aircraft->IsSelected &&
x >= x1 && x <= x2 && y >= y1 && y <= y2) {
if (aircraft->Select()) {
AllowVoice = false;
}
}
}
AllowVoice = true;
}
/***********************************************************************************************
* DisplayClass::Refresh_Band -- Causes all cells under the rubber band to be redrawn. *
* *
* Use this routine to flag all cells that are covered in some fashion by the multi-unit *
* select "rubber band" to be redrawn. This is necessary whenever the rubber band changes *
* size or is being removed. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/19/1995 JLB : Created. *
*=============================================================================================*/
void DisplayClass::Refresh_Band(void)
{
if (IsRubberBand) {
/*
** In rubber band mode, mark all cells under the "rubber band" to be
** redrawn.
*/
int x1 = BandX+TacPixelX;
int y1 = BandY+TacPixelY;
int x2 = NewX+TacPixelX;
int y2 = NewY+TacPixelY;
if (x1 > x2) {
int temp = x1;
x1 = x2;
x2 = temp;
}
if (y1 > y2) {
int temp = y1;
y1 = y2;
y2 = temp;
}
CELL cell;
for (int y = y1; y <= y2+CELL_PIXEL_H; y += CELL_PIXEL_H) {
cell = Click_Cell_Calc(x1, Bound(y, 0, TacPixelY+Lepton_To_Pixel(TacLeptonHeight)));
if (cell != -1) (*this)[cell].Redraw_Objects();
cell = Click_Cell_Calc(x2, Bound(y, 0, TacPixelY+Lepton_To_Pixel(TacLeptonHeight)));
if (cell != -1) (*this)[cell].Redraw_Objects();
}
for (int x = x1; x <= x2+CELL_PIXEL_W; x += CELL_PIXEL_W) {
cell = Click_Cell_Calc(Bound(x, 0, TacPixelX+Lepton_To_Pixel(TacLeptonWidth)), y1);
if (cell != -1) (*this)[cell].Redraw_Objects();
cell = Click_Cell_Calc(Bound(x, 0, TacPixelX+Lepton_To_Pixel(TacLeptonWidth)), y2);
if (cell != -1) (*this)[cell].Redraw_Objects();
}
/*
** Stretching the rubber band requires all objects to be redrawn.
*/
for (int index = 0; index < Layer[LAYER_TOP].Count(); index++) {
Layer[LAYER_TOP][index]->Mark(MARK_CHANGE);
}
for (index = 0; index < Layer[LAYER_AIR].Count(); index++) {
Layer[LAYER_AIR][index]->Mark(MARK_CHANGE);
}
}
}
/***********************************************************************************************
* DisplayClass::TacticalClass::Action -- Processes input for the tactical map. *
* *
* This routine handles the input directed at the tactical map. Since input, in this *
* regard, includes even the presence of the mouse over the tactical map, this routine *
* is called nearly every game frame. It handles adjusting the mouse shape as well as *
* giving orders to units. *
* *
* INPUT: flags -- The gadget event flags that triggered the call to this function. *
* *
* key -- A reference to the keyboard event (if any). *
* *
* OUTPUT: bool; Should processing be aborted on any succeeding buttons in the chain? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 02/17/1995 JLB : Created. *
*=============================================================================================*/
int DisplayClass::TacticalClass::Action(unsigned flags, KeyNumType & key)
{
int x,y; // Sub cell pixel coordinates.
bool shadow;
ObjectClass * object = 0;
ActionType action = ACTION_NONE; // Action possible with currently selected object.
/*
** Set some working variables that depend on the mouse position. For the press
** or release event, special mouse queuing storage variables are used. Other
** events must use the current mouse position globals.
*/
if (flags & (LEFTPRESS|LEFTRELEASE|RIGHTPRESS|RIGHTRELEASE)) {
x = Keyboard->MouseQX;
y = Keyboard->MouseQY;
} else {
x = Get_Mouse_X();
y = Get_Mouse_Y();
}
bool edge = (y == 0 || x == 0 || x == SeenBuff.Get_Width()-1 || y == SeenBuff.Get_Height()-1);
COORDINATE coord = Map.Pixel_To_Coord(x, y);
CELL cell = Coord_Cell(coord);
if (coord) {
shadow = (!Map[cell].IsMapped && !Debug_Unshroud);
x -= Map.TacPixelX;
y -= Map.TacPixelY;
/*
** Cause any displayed cursor to move along with the mouse cursor.
*/
if (cell != Map.ZoneCell) {
Map.Set_Cursor_Pos(cell);
}
/*
** Determine the object that the mouse is currently over.
*/
if (!shadow) {
object = Map.Close_Object(coord);
/*
** Special case check to ignore cloaked object if not owned by the player.
*/
if (object != NULL && object->Is_Techno() && !((TechnoClass *)object)->IsOwnedByPlayer && (((TechnoClass *)object)->Cloak == CLOAKED || ((TechnoClass *)object)->Techno_Type_Class()->IsInvisible)) {
object = NULL;
}
}
/*
** If there is a currently selected object, then the action to perform if
** the left mouse button were clicked must be determined.
*/
if (CurrentObject.Count()) {
if (object != NULL) {
action = CurrentObject[0]->What_Action(object);
} else {
action = CurrentObject[0]->What_Action(cell);
}
} else {
if (object && object->Class_Of().IsSelectable) {
action = ACTION_SELECT;
}
if (Map.IsRepairMode) {
if (object && object->Owner() == PlayerPtr->Class->House && object->Can_Repair()) {
action = ACTION_REPAIR;
} else {
action = ACTION_NO_REPAIR;
}
}
if (Map.IsSellMode) {
if (object && object->Owner() == PlayerPtr->Class->House && object->Can_Demolish()) {
if (object->What_Am_I() == RTTI_BUILDING) {
action = ACTION_SELL;
} else {
action = ACTION_SELL_UNIT;
}
} else {
/*
** Check to see if the cursor is over an owned wall.
*/
if (Map[cell].Overlay != OVERLAY_NONE &&
OverlayTypeClass::As_Reference(Map[cell].Overlay).IsWall &&
Map[cell].Owner == PlayerPtr->Class->House) {
action = ACTION_SELL;
} else {
action = ACTION_NO_SELL;
}
}
}
if (Map.IsTargettingMode == SPC_NUCLEAR_BOMB) {
action = ACTION_NUKE_BOMB;
}
if (Map.IsTargettingMode == SPC_PARA_BOMB) {
action = ACTION_PARA_BOMB;
}
if (Map.IsTargettingMode == SPC_PARA_INFANTRY) {
action = ACTION_PARA_INFANTRY;
}
if (Map.IsTargettingMode == SPC_SPY_MISSION) {
action = ACTION_SPY_MISSION;
}
if (Map.IsTargettingMode == SPC_IRON_CURTAIN) {
action = ACTION_IRON_CURTAIN;
}
if (Map.IsTargettingMode == SPC_CHRONOSPHERE) {
action = ACTION_CHRONOSPHERE;
}
if (Map.IsTargettingMode == SPC_CHRONO2) {
action = ACTION_CHRONO2;
if (shadow) action = ACTION_NOMOVE;
ObjectClass const * tobject = As_Object(PlayerPtr->UnitToTeleport);
/*
** Determine if the object can be teleported to the destination cell.
*/
if (tobject != NULL && tobject->Is_Techno()) {
TechnoClass const * uobject = (TechnoClass const *)tobject;
if (!uobject->Can_Teleport_Here(cell)) {
// if (((UnitClass *)As_Object(PlayerPtr->UnitToTeleport))->Can_Enter_Cell(cell, FACING_NONE) != MOVE_OK) {
action = ACTION_NOMOVE;
}
}
#ifdef FIXIT_CSII // checked - ajw 9/28/98
else { // If the object is no longer valid, cancel targetting mode.
action = ACTION_NOMOVE;
Map.IsTargettingMode = SPC_NONE;
}
#endif
}
if (Map.PendingObject) {
action = ACTION_NONE;
}
}
/*
** Move any cursor displayed.
*/
if (cell != Map.ZoneCell) {
Map.Set_Cursor_Pos(cell);
}
/*
** A right mouse button press cancels the current action or selection.
*/
if (flags & RIGHTPRESS) {
Map.Mouse_Right_Press();
}
/*
** Make sure that if the mouse button has been released and the map doesn't know about it,
** then it must be informed. Do this by faking a mouse release event.
*/
if ((flags & LEFTUP) && Map.IsRubberBand) {
flags |= LEFTRELEASE;
}
/*
** When the mouse buttons aren't pressed, only the mouse cursor shape is processed.
** The shape changes depending on what object the mouse is currently over and what
** object is currently selected.
*/
if (!edge) {
if (flags & LEFTUP) {
Map.Mouse_Left_Up(cell, shadow, object, action);
}
}
/*
** Normal actions occur when the mouse button is released. The press event is
** intercepted and possible rubber-band mode is flagged.
*/
if (flags & LEFTRELEASE) {
Map.Mouse_Left_Release(cell, x, y, object, action);
}
/*
** When the mouse is first pressed on the map, then record the mouse
** position so that a proper check before going into rubber band
** mode can be made. Rubber band mode starts when the mouse is
** held down and moved a certain minimum distance.
*/
if (!edge && (flags & LEFTPRESS)) {
Map.Mouse_Left_Up(cell, shadow, object, action);
Map.Mouse_Left_Press(x, y);
}
/*
** While the mouse is being held down, determine if rubber band mode should
** start. If rubber band mode is already active, then update the size
** and flag the map to redraw it.
*/
if (flags & LEFTHELD) {
Map.Mouse_Left_Held(x, y);
}
}
return(GadgetClass::Action(0, key));
}
/***********************************************************************************************
* DisplayClass::Mouse_Right_Press -- Handles the right mouse button press. *
* *
* This routine is called when the right mouse button is pressed. This action is supposed *
* to cancel whatever mode or process is active. If there is nothing to cancel, then it *
* will default to unselecting any units that might be currently selected. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 02/24/1995 JLB : Created. *
*=============================================================================================*/
void DisplayClass::Mouse_Right_Press(void)
{
if (PendingObjectPtr && PendingObjectPtr->Is_Techno()) {
//PendingObjectPtr->Transmit_Message(RADIO_OVER_OUT);
PendingObjectPtr = 0;
PendingObject = 0;
PendingHouse = HOUSE_NONE;
Set_Cursor_Shape(0);
} else {
if (IsRepairMode) {
IsRepairMode = false;
} else {
if (IsSellMode) {
IsSellMode = false;
} else {
if (IsTargettingMode != SPC_NONE) {
IsTargettingMode = SPC_NONE;
} else {
Unselect_All();
}
}
}
}
// If it breaks... call 228.
Set_Default_Mouse(MOUSE_NORMAL, Map.IsSmall);
}
/***********************************************************************************************
* DisplayClass::Mouse_Left_Up -- Handles the left mouse "cruising" over the map. *
* *
* This routine is called continuously while the mouse is over the tactical map but there *
* are no mouse buttons pressed. Typically, this adjusts the mouse shape and the pop-up *
* help text. *
* *
* INPUT: shadow -- Is the mouse hovering over shadowed terrain? *
* *
* object -- Pointer to the object that the mouse is currently over (may be NULL). *
* *
* action -- This is the action that the currently selected object (if any) will *
* perform if the left mouse button were clicked at this location. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 02/24/1995 JLB : Created. *
* 07/05/1995 JLB : Removed pop up help text for shadow and terrain after #3. *
*=============================================================================================*/
void DisplayClass::Mouse_Left_Up(CELL cell, bool shadow, ObjectClass * object, ActionType action, bool wsmall)
{
IsTentative = false;
TARGET target = TARGET_NONE;
if (object != NULL) {
target = object->As_Target();
} else {
if (cell != -1) {
target = As_Target(cell);
}
}
/*
** Don't allow selection of an object that is located in shadowed terrain.
** In fact, just show the normal move cursor in order to keep the shadowed
** terrain a mystery.
*/
if (shadow) {
switch (action) {
case ACTION_NO_DEPLOY:
Set_Default_Mouse(MOUSE_NO_DEPLOY, wsmall);
break;
case ACTION_NO_ENTER:
Set_Default_Mouse(MOUSE_NO_ENTER, wsmall);
break;
case ACTION_NO_GREPAIR:
Set_Default_Mouse(MOUSE_NO_GREPAIR, wsmall);
break;
case ACTION_DAMAGE:
Set_Default_Mouse(MOUSE_NORMAL, wsmall);
break;
case ACTION_GREPAIR:
Set_Default_Mouse(MOUSE_NORMAL, wsmall);
break;
case ACTION_GUARD_AREA:
Set_Default_Mouse(MOUSE_AREA_GUARD, wsmall);
break;
case ACTION_NONE:
Set_Default_Mouse(MOUSE_NORMAL, wsmall);
break;
case ACTION_NO_SELL:
case ACTION_SELL:
case ACTION_SELL_UNIT:
Set_Default_Mouse(MOUSE_NO_SELL_BACK, wsmall);
break;
case ACTION_NO_REPAIR:
case ACTION_REPAIR:
Set_Default_Mouse(MOUSE_NO_REPAIR, wsmall);
break;
case ACTION_NUKE_BOMB:
Set_Default_Mouse(MOUSE_NUCLEAR_BOMB, wsmall);
break;
case ACTION_AIR_STRIKE:
case ACTION_PARA_BOMB:
case ACTION_PARA_INFANTRY:
case ACTION_SPY_MISSION:
case ACTION_IRON_CURTAIN:
Set_Default_Mouse(MOUSE_AIR_STRIKE, wsmall);
break;
case ACTION_CHRONOSPHERE:
Set_Default_Mouse(MOUSE_CHRONO_SELECT, wsmall);
break;
case ACTION_CHRONO2:
Set_Default_Mouse(MOUSE_CHRONO_DEST, wsmall);
break;
case ACTION_HEAL:
Set_Default_Mouse(MOUSE_HEAL, wsmall);
break;
case ACTION_NOMOVE:
if (CurrentObject.Count() && CurrentObject[0]->What_Am_I() == RTTI_AIRCRAFT) {
Set_Default_Mouse(MOUSE_NO_MOVE, wsmall);
break;
}
// Fall into next case for non aircraft object types.
default:
Set_Default_Mouse(MOUSE_CAN_MOVE, wsmall);
break;
}
} else {
/*
** Change the mouse shape according to the default action that will occur
** if the mouse button were clicked at this location.
*/
switch (action) {
case ACTION_NO_DEPLOY:
Set_Default_Mouse(MOUSE_NO_DEPLOY, wsmall);
break;
case ACTION_NO_ENTER:
Set_Default_Mouse(MOUSE_NO_ENTER, wsmall);
break;
case ACTION_NO_GREPAIR:
Set_Default_Mouse(MOUSE_NO_GREPAIR, wsmall);
break;
case ACTION_DAMAGE:
Set_Default_Mouse(MOUSE_DAMAGE, wsmall);
break;
case ACTION_GREPAIR:
Set_Default_Mouse(MOUSE_GREPAIR, wsmall);
break;
case ACTION_TOGGLE_SELECT:
case ACTION_SELECT:
Set_Default_Mouse(MOUSE_CAN_SELECT, wsmall);
break;
case ACTION_MOVE:
Set_Default_Mouse(MOUSE_CAN_MOVE, wsmall);
break;
case ACTION_GUARD_AREA:
Set_Default_Mouse(MOUSE_AREA_GUARD, wsmall);
break;
case ACTION_ATTACK:
if (Target_Legal(target) && CurrentObject.Count() == 1 && CurrentObject[0]->Is_Techno() && ((TechnoClass *)CurrentObject[0])->In_Range(target, 0)) {
Set_Default_Mouse(MOUSE_STAY_ATTACK, wsmall);
break;
}
// fall into next case.
case ACTION_HARVEST:
Set_Default_Mouse(MOUSE_CAN_ATTACK, wsmall);
break;
case ACTION_SABOTAGE:
Set_Default_Mouse(MOUSE_DEMOLITIONS, wsmall);
break;
case ACTION_ENTER:
case ACTION_CAPTURE:
Set_Default_Mouse(MOUSE_ENTER, wsmall);
break;
case ACTION_NOMOVE:
Set_Default_Mouse(MOUSE_NO_MOVE, wsmall);
break;
case ACTION_NO_SELL:
Set_Default_Mouse(MOUSE_NO_SELL_BACK, wsmall);
break;
case ACTION_NO_REPAIR:
Set_Default_Mouse(MOUSE_NO_REPAIR, wsmall);
break;
case ACTION_SELF:
Set_Default_Mouse(MOUSE_DEPLOY, wsmall);
break;
case ACTION_REPAIR:
Set_Default_Mouse(MOUSE_REPAIR, wsmall);
break;
case ACTION_SELL_UNIT:
Set_Default_Mouse(MOUSE_SELL_UNIT, wsmall);
break;
case ACTION_SELL:
Set_Default_Mouse(MOUSE_SELL_BACK, wsmall);
break;
case ACTION_NUKE_BOMB:
Set_Default_Mouse(MOUSE_NUCLEAR_BOMB, wsmall);
break;
case ACTION_AIR_STRIKE:
case ACTION_PARA_BOMB:
case ACTION_PARA_INFANTRY:
case ACTION_SPY_MISSION:
case ACTION_IRON_CURTAIN:
Set_Default_Mouse(MOUSE_AIR_STRIKE, wsmall);
break;
case ACTION_CHRONOSPHERE:
Set_Default_Mouse(MOUSE_CHRONO_SELECT, wsmall);
break;
case ACTION_CHRONO2:
Set_Default_Mouse(MOUSE_CHRONO_DEST, wsmall);
break;
case ACTION_HEAL:
Set_Default_Mouse(MOUSE_HEAL, wsmall);
break;
default:
Set_Default_Mouse(MOUSE_NORMAL, wsmall);
break;
}
}
/*
** Never display help text if the mouse is held over the radar map.
*/
if (wsmall) {
return;
}
/*
** Give a generic help message when over shadow terrain.
*/
if (shadow) {
// if (Scen.Scenario < 4) {
Help_Text(TXT_SHADOW);
// } else {
// Help_Text(TXT_NONE);
// }
} else {
/*
** If the mouse is held over objects on the map, then help text may
** pop up that tells what the object is. This call informs the help
** system of the text name for the object under the mouse.
*/
if (object != NULL) {
int text;
int color = LTGREY;
/*
** Fetch the appropriate background color for help text.
*/
if (PlayerPtr->Is_Ally(object)) {
color = GREEN;
} else {
if (object->Owner() == HOUSE_NONE || object->Owner() == HOUSE_NEUTRAL) {
color = LTGREY;
} else {
color = PINK;
}
}
/*
** Fetch the name of the object. If it is an enemy object, then
** the exact identity is glossed over with a generic text.
*/
text = object->Full_Name();
if (object->Is_Techno() && !((TechnoTypeClass const &)object->Class_Of()).IsNominal) {
if (!((TechnoClass *)object)->House->Is_Ally(PlayerPtr)) {
// if (!PlayerPtr->Is_Ally(object)) {
switch (object->What_Am_I()) {
case RTTI_INFANTRY:
text = TXT_ENEMY_SOLDIER;
break;
case RTTI_UNIT:
text = TXT_ENEMY_VEHICLE;
break;
case RTTI_BUILDING:
text = TXT_ENEMY_STRUCTURE;
break;
}
}
}
if (/*Scen.Scenario > 3 ||*/ object->What_Am_I() != RTTI_TERRAIN) {
Help_Text(text, -1, -1, color);
} else {
Help_Text(TXT_NONE);
}
} else {
if ((*this)[cell].Land_Type() == LAND_TIBERIUM) {
Help_Text(TXT_MINERALS);
} else {
Help_Text(TXT_NONE);
}
}
}
}
/***********************************************************************************************
* DisplayClass::Mouse_Left_Release -- Handles the left mouse button release. *
* *
* This routine is called when the left mouse button is released over the tactical map. *
* The release event is the workhorse of the game. Most actions occur at the moment of *
* mouse release. *
* *
* INPUT: cell -- The cell that the mouse is over. *
* *
* x,y -- The mouse pixel coordinate. *
* *
* object -- Pointer to the object that the mouse is over. *
* *
* action -- The action that the currently selected object (if any) will *
* perform. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 02/24/1995 JLB : Created. *
* 03/27/1995 JLB : Handles sell and repair actions. *
*=============================================================================================*/
void DisplayClass::Mouse_Left_Release(CELL cell, int x, int y, ObjectClass * object, ActionType action, bool wsmall)
{
if (PendingObjectPtr) {
/*
** Try to place the pending object onto the map.
*/
if (ProximityCheck) {
OutList.Add(EventClass(EventClass::PLACE, PendingObjectPtr->What_Am_I(), cell + ZoneOffset));
} else {
Speak(VOX_DEPLOY);
}
} else {
if (IsRubberBand) {
Refresh_Band();
Select_These(XYP_Coord(BandX, BandY), XYP_Coord(x, y));
Set_Default_Mouse(MOUSE_NORMAL, wsmall);
IsRubberBand = false;
IsTentative = false;
Map.DisplayClass::IsToRedraw = true;
Map.Flag_To_Redraw(false);
} else {
/*
** Toggle the select state of the object.
*/
if (action == ACTION_TOGGLE_SELECT) {
if (!object || !CurrentObject.Count() || CurrentObject[0]->Owner() != PlayerPtr->Class->House) {
action = ACTION_SELECT;
} else {
if (object->IsSelected) {
object->Unselect();
} else {
object->Select();
}
}
}
/*
** Selection of other object action.
*/
if (action == ACTION_SELECT || (action == ACTION_NONE && object && object->Class_Of().IsSelectable && !object->IsSelected)) {
Unselect_All();
object->Select();
Set_Default_Mouse(MOUSE_NORMAL, wsmall);
}
/*
** If an action was detected as possible, then pass this action event
** to all selected objects.
*/
if (action != ACTION_NONE && action != ACTION_SELECT) {
/*
** Pass the action to all the selected objects. But first, redetermine
** what action that object should perform. This, seemingly redundant
** process, is necessary since multiple objects could be selected and each
** might perform a different action when the click occurs.
*/
bool doflash = true;
AllowVoice = true;
FormMove = false;
FormSpeed = SPEED_WHEEL;
FormMaxSpeed = MPH_LIGHT_SPEED;
if ( (action == ACTION_MOVE || action == ACTION_NOMOVE) && CurrentObject.Count()) {
/*
** Scan all units. If any are selected that shouldn't be, or aren't
** selected but should be, then this is not a formation move.
*/
int group = 254; // init to invalid group #
if (CurrentObject[0]->Is_Foot()) {
group = ((FootClass *)CurrentObject[0])->Group;
}
/*
** Presume this is a formation move unless something is detected
** that will prevent it.
*/
FormMove = true;
/*
** First scan through all the selected units to make sure that they
** are all of the same team and have been assigned a particular formation
*/
for (int index = 0; index < CurrentObject.Count(); index++) {
ObjectClass const * tobject = CurrentObject[index];
/*
** Only moveable (i.e., FootClass) objects can ever be in a formation
** so if a selected object isn't of a FootClass type then it can't be
** a formation move.
*/
if (tobject->Is_Foot() == false) {
FormMove = false;
break;
}
/*
** If the object is not part of the same team as the rest of the
** selected group, or it just plain has never been assigned a
** formation offset, then it can't be a formation move.
*/
FootClass const * foot = (FootClass *)tobject;
if (foot->Group != group || foot->XFormOffset == 0x80000000) {
FormMove = false;
break;
}
/*
** Determine the formation speed on the presumption that this
** will turn out to be a formation move.
*/
FormMaxSpeed = foot->Techno_Type_Class()->MaxSpeed;
FormSpeed = foot->Techno_Type_Class()->Speed;
}
/*
** Loop through all objects (that can theoretically be part of a team) and
** if there are any that are part of the currently selected team, but
** are not currently selected themselves, then this will force this move
** to NOT be a formation move.
*/
if (FormMove) {
for (index = 0; index < ::Logic.Count(); index++) {
ObjectClass const * obj = ::Logic[index];
/*
** If the object is selected, then it has already been scanned
** by the previous loop.
*/
if (obj->IsSelected) continue;
/*
** Only consider footclass objects.
*/
if (!obj->Is_Foot()) continue;
FootClass const * foot = (FootClass *)obj;
/*
** Only consider objects that are owned by the player.
*/
if (!foot->IsOwnedByPlayer) continue;
/*
** If another member of this team has been discovered and
** it isn't selected, then the formation move cannot take
** place.
*/
if (foot->Group == group) {
FormMove = false;
break;
}
}
}
}
for (int index = 0; index < CurrentObject.Count(); index++) {
ObjectClass * tobject = CurrentObject[index];
if (object != NULL) {
tobject->Active_Click_With(tobject->What_Action(object), object);
} else {
/*
** Trap for formation moves: if this unit is part of a
** formation (being part of a team qualifies) and they're
** told to move, adjust the target destination so they stay
** in formation when they arrive.
*/
CELL newmove = cell;
int whatami = tobject->What_Am_I();
if (action == ACTION_MOVE && tobject->Is_Foot()) {
int oldisform;
FootClass * foot = (FootClass *)tobject;
oldisform = foot->IsFormationMove;
foot->IsFormationMove = FormMove;
if (FormMove && foot->Group != 255 ) {
newmove = foot->Adjust_Dest(cell);
}
foot->IsFormationMove = oldisform;
}
tobject->Active_Click_With(tobject->What_Action(cell), newmove);
}
AllowVoice = false;
}
AllowVoice = true;
FormMove = false;
if (action == ACTION_REPAIR && object->What_Am_I() == RTTI_BUILDING) {
OutList.Add(EventClass(EventClass::REPAIR, TargetClass(object)));
}
if (action == ACTION_SELL_UNIT && object) {
switch (object->What_Am_I()) {
case RTTI_AIRCRAFT:
case RTTI_UNIT:
OutList.Add(EventClass(EventClass::SELL, TargetClass(object)));
break;
default:
break;
}
}
if (action == ACTION_SELL) {
if (object) {
OutList.Add(EventClass(EventClass::SELL, TargetClass(object)));
} else {
OutList.Add(EventClass(EventClass::SELLCELL, cell));
// OutList.Add(EventClass(EventClass::SELL, ::As_Target(cell)));
}
}
if (action == ACTION_NUKE_BOMB) {
OutList.Add(EventClass(EventClass::SPECIAL_PLACE, SPC_NUCLEAR_BOMB, cell));
}
if (action == ACTION_PARA_BOMB) {
OutList.Add(EventClass(EventClass::SPECIAL_PLACE, SPC_PARA_BOMB, cell));
}
if (action == ACTION_PARA_INFANTRY) {
OutList.Add(EventClass(EventClass::SPECIAL_PLACE, SPC_PARA_INFANTRY, cell));
}
if (action == ACTION_SPY_MISSION) {
OutList.Add(EventClass(EventClass::SPECIAL_PLACE, SPC_SPY_MISSION, cell));
}
if (action == ACTION_IRON_CURTAIN) {
OutList.Add(EventClass(EventClass::SPECIAL_PLACE, SPC_IRON_CURTAIN, cell));
}
if (action == ACTION_CHRONOSPHERE) {
OutList.Add(EventClass(EventClass::SPECIAL_PLACE, SPC_CHRONOSPHERE, cell));
}
if (action == ACTION_CHRONO2) {
OutList.Add(EventClass(EventClass::SPECIAL_PLACE, SPC_CHRONO2, cell));
}
}
IsTentative = false;
}
}
}
/***********************************************************************************************
* DisplayClass::Mouse_Left_Press -- Handles the left mouse button press. *
* *
* Handle the left mouse button press while over the tactical map. If it isn't is *
* repair or sell mode, then a tentative transition to rubber band mode is flagged. If the *
* mouse moves a sufficient distance from this recorded position, then rubber band mode *
* is officially started. *
* *
* INPUT: x,y -- The mouse coordinates at the time of the press. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 02/24/1995 JLB : Created. *
*=============================================================================================*/
void DisplayClass::Mouse_Left_Press(int x, int y)
{
if (!IsRepairMode && !IsSellMode && IsTargettingMode == SPC_NONE && !PendingObject) {
IsTentative = true;
BandX = x;
BandY = y;
NewX = x;
NewY = y;
}
}
/***********************************************************************************************
* DisplayClass::Mouse_Left_Held -- Handles the left button held down. *
* *
* This routine is called continuously while the left mouse button is held down over *
* the tactical map. This handles the rubber band mode detection and dragging. *
* *
* INPUT: x,y -- The mouse coordinate. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 02/24/1995 JLB : Created. *
*=============================================================================================*/
void DisplayClass::Mouse_Left_Held(int x, int y)
{
if (IsRubberBand) {
if (x != NewX || y != NewY) {
x = Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1);
y = Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1);
Refresh_Band();
NewX = x;
NewY = y;
IsToRedraw = true;
Flag_To_Redraw(false);
}
} else {
/*
** If the mouse is still held down while a tentative extended select is possible, then
** check to see if the mouse has moved a sufficient distance in order to activate
** extended select mode.
*/
if (IsTentative) {
/*
** The mouse must have moved a minimum distance before rubber band mode can be
** initiated.
*/
if (ABS(x - BandX) > 4 || ABS(y - BandY) > 4) {
IsRubberBand = true;
x = Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1);
y = Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1);
NewX = x;
NewY = y;
IsToRedraw = true;
Flag_To_Redraw(false);
/*
** Stretching the rubber band requires all objects to be redrawn.
*/
for (int index = 0; index < Layer[LAYER_TOP].Count(); index++) {
Layer[LAYER_TOP][index]->Mark(MARK_CHANGE);
}
for (index = 0; index < Layer[LAYER_AIR].Count(); index++) {
Layer[LAYER_AIR][index]->Mark(MARK_CHANGE);
}
}
}
}
}
/***********************************************************************************************
* DisplayClass::Set_Tactical_Position -- Sets the tactical view position. *
* *
* This routine is used to set the tactical view position. The requested position is *
* clipped to the map dimensions as necessary. *
* *
* INPUT: coord -- The coordinate desired for the upper left corner. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/13/1995 JLB : Created. *
*=============================================================================================*/
void DisplayClass::Set_Tactical_Position(COORDINATE coord)
{
/*
** Bound the desired location to fit the legal map edges.
*/
int xx = (int)Coord_X(coord) - (int)Cell_To_Lepton(MapCellX);
int yy = (int)Coord_Y(coord) - (int)Cell_To_Lepton(MapCellY);
Confine_Rect(&xx, &yy, TacLeptonWidth, TacLeptonHeight, Cell_To_Lepton(MapCellWidth), Cell_To_Lepton(MapCellHeight));
coord = XY_Coord(xx + Cell_To_Lepton(MapCellX), yy + Cell_To_Lepton(MapCellY));
if (ScenarioInit) {
TacticalCoord = coord;
}
DesiredTacticalCoord = coord;
IsToRedraw = true;
Flag_To_Redraw(false);
}
/***********************************************************************************************
* DisplayClass::Compute_Start_Pos -- Computes player's start pos from unit coords. *
* *
* Use this function in multiplayer games, to compute the scenario starting Tactical Pos. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 02/28/1995 JLB : Commented. *
* 06/26/1995 JLB : Fixed building loop. *
* 10/20/1996 JLB : Doesn't wrap. *
*=============================================================================================*/
void DisplayClass::Compute_Start_Pos(void)
{
/*
** Find the summation cell-x & cell-y for all the player's units, infantry,
** and buildings. Buildings are weighted so that they count 16 times more
** than units or infantry.
*/
long x = 0;
long y = 0;
long num = 0;
for (int i = 0; i < Infantry.Count(); i++) {
InfantryClass * infp = Infantry.Ptr(i);
if (!infp->IsInLimbo && infp->IsOwnedByPlayer) {
x += (long)Coord_XCell(infp->Coord);
y += (long)Coord_YCell(infp->Coord);
num++;
}
}
for (i = 0; i < Units.Count(); i++) {
UnitClass * unitp = Units.Ptr(i);
if (!unitp->IsInLimbo && unitp->IsOwnedByPlayer) {
x += (long)Coord_XCell(unitp->Coord);
y += (long)Coord_YCell(unitp->Coord);
num++;
}
}
for (i = 0; i < Buildings.Count(); i++) {
BuildingClass * bldgp = Buildings.Ptr(i);
if (!bldgp->IsInLimbo && bldgp->IsOwnedByPlayer) {
x += (((long)Coord_XCell(bldgp->Coord)) * 16);
y += (((long)Coord_YCell(bldgp->Coord)) * 16);
num += 16;
}
}
for (i = 0; i < Vessels.Count(); i++) {
VesselClass * bldgp = Vessels.Ptr(i);
if (!bldgp->IsInLimbo && bldgp->IsOwnedByPlayer) {
x += (((long)Coord_XCell(bldgp->Coord)));
y += (((long)Coord_YCell(bldgp->Coord)));
num++;
}
}
/*
** Divide each coord by 'num' to compute the average value
*/
if (num > 0) {
x /= num;
} else {
x = 0;
}
if (num > 0) {
y /= num;
} else {
y = 0;
}
/*
** Tactical position is based on the cell of the upper left corner. Make adjustments
** and bound the calculated location to the map dimensions.
*/
// x -= 5 * RESFACTOR;
// y -= 4 * RESFACTOR;
if (x < MapCellX + 5*RESFACTOR) x = MapCellX + 5*RESFACTOR;
if (y < MapCellY + 4*RESFACTOR) y = MapCellY + 4*RESFACTOR;
if (x > MapCellX+MapCellWidth - 5*RESFACTOR) x = MapCellX+MapCellWidth - 5*RESFACTOR;
if (y > MapCellY+MapCellHeight - 4*RESFACTOR) y = MapCellY+MapCellHeight - 4*RESFACTOR;
Scen.Waypoint[WAYPT_HOME] = Scen.Views[0] = Scen.Views[1] = Scen.Views[2] = Scen.Views[3] = XY_Cell(x, y);
Map.Set_Tactical_Position(Coord_Whole(Cell_Coord((Scen.Views[0] - (MAP_CELL_W * 4 * RESFACTOR)) - (5*RESFACTOR))));
// Set_Tactical_Position(Cell_Coord(XY_Cell(x, y)));
}
/***********************************************************************************************
* DisplayClass::Sell_Mode_Control -- Controls the sell mode. *
* *
* This routine will control the sell mode for the player. *
* *
* INPUT: control -- The mode to set the sell state to. *
* 0 = Turn sell mode off. *
* 1 = Turn sell mode on. *
* -1 = Toggle sell mode. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/08/1995 JLB : Created. *
*=============================================================================================*/
void DisplayClass::Sell_Mode_Control(int control)
{
bool mode = IsSellMode;
switch (control) {
case 0:
mode = false;
break;
case -1:
mode = (IsSellMode == false);
break;
case 1:
mode = true;
break;
}
if (mode != IsSellMode && !PendingObject) {
IsRepairMode = false;
if (mode && PlayerPtr->BScan) {
IsSellMode = true;
Unselect_All();
} else {
IsSellMode = false;
Revert_Mouse_Shape();
}
}
}
/***********************************************************************************************
* DisplayClass::Repair_Mode_Control -- Controls the repair mode. *
* *
* This routine is used to control the repair mode for the player. *
* *
* INPUT: control -- The mode to set the repair to. *
* 0 = Turn repair off. *
* 1 = Turn repair on. *
* -1= Toggle repair state. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/08/1995 JLB : Created. *
*=============================================================================================*/
void DisplayClass::Repair_Mode_Control(int control)
{
bool mode = IsRepairMode;
switch (control) {
case 0:
mode = false;
break;
case -1:
mode = (IsRepairMode == false);
break;
case 1:
mode = true;
break;
}
if (mode != IsRepairMode && !PendingObject) {
IsSellMode = false;
if (mode && PlayerPtr->BScan) {
IsRepairMode = true;
Unselect_All();
} else {
IsRepairMode = false;
Revert_Mouse_Shape();
}
}
}
/***********************************************************************************************
* DisplayClass::In_View -- Determines if cell is visible on screen. *
* *
* Use this routine to determine if the specified cell is visible on *
* the display. This is a useful fact, since many display operations *
* can be skipped if the cell is not visible. *
* *
* INPUT: cell -- The cell number to check. *
* *
* OUTPUT: bool; Is this cell visible on the display? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 04/30/1994 JLB : Created. *
* 04/30/1994 JLB : Converted to member function. *
*=============================================================================================*/
bool DisplayClass::In_View(register CELL cell) const
{
if (cell & 0xC000) return(false);
COORDINATE coord = Coord_Whole(Cell_Coord(cell));
COORDINATE tcoord = Coord_Whole(TacticalCoord);
if ((unsigned)(Coord_X(coord) - Coord_X(tcoord)) > TacLeptonWidth+CELL_LEPTON_W-1) return(false);
if ((unsigned)(Coord_Y(coord) - Coord_Y(tcoord)) > TacLeptonHeight+CELL_LEPTON_H-1) return(false);
return(true);
}
/***********************************************************************************************
* DisplayClass::Closest_Free_Spot -- Finds the closest cell sub spot that is free. *
* *
* Use this routine to find the sub cell spot closest to the coordinate specified that is *
* free from occupation. Typical use of this is for infantry destination calculation. *
* *
* INPUT: coord -- The coordinate to use as the starting point when finding the closest *
* free spot. *
* *
* any -- Ignore occupation and just return the closest sub cell spot? *
* *
* OUTPUT: Returns with the coordinate of the closest free (possibly) sub cell location. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/22/1995 JLB : Created. *
*=============================================================================================*/
COORDINATE DisplayClass::Closest_Free_Spot(COORDINATE coord, bool any) const
{
if (coord & HIGH_COORD_MASK) {
return(0x00800080);
}
return Map[coord].Closest_Free_Spot(coord, any);
}
/***********************************************************************************************
* DisplayClass::Is_Spot_Free -- Determines if cell sub spot is free of occupation. *
* *
* Use this routine to determine if the coordinate (rounded to the nearest sub cell *
* position) is free for placement. Typical use of this would be for infantry placement. *
* *
* INPUT: coord -- The coordinate to examine for "freeness". The coordinate is rounded to *
* the nearest free sub cell spot. *
* *
* OUTPUT: Is the sub spot indicated by the coordinate free from previous occupation? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/22/1995 JLB : Created. *
*=============================================================================================*/
bool DisplayClass::Is_Spot_Free(COORDINATE coord) const
{
if (coord & HIGH_COORD_MASK) {
return(0x00800080);
}
return Map[coord].Is_Spot_Free(CellClass::Spot_Index(coord));
}
/***********************************************************************************************
* DisplayClass::Center_Map -- Centers the map about the currently selected objects *
* *
* This routine will average the position of all the selected objects and then center *
* the map about those objects. *
* *
* INPUT: center -- The is an optional center about override coordinate. If specified, *
* then the map will be centered about that coordinate. Otherwise it *
* will center about the average location of all selected objects. *
* *
* OUTPUT: none *
* *
* WARNINGS: The map position changes by this routine. *
* *
* HISTORY: *
* 08/22/1995 JLB : Created. *
* 09/16/1996 JLB : Takes coordinate to center about (as override). *
*=============================================================================================*/
void DisplayClass::Center_Map(COORDINATE center)
{
int x = 0;
// unsigned x = 0;
int y = 0;
// unsigned y = 0;
bool centerit = false;
if (CurrentObject.Count()) {
for (int index = 0; index < CurrentObject.Count(); index++) {
COORDINATE coord = CurrentObject[index]->Center_Coord();
x += Coord_X(coord);
y += Coord_Y(coord);
}
x /= CurrentObject.Count();
y /= CurrentObject.Count();
centerit = true;
}
if (center != 0L) {
x = Coord_X(center);
y = Coord_Y(center);
centerit = true;
}
if (centerit) {
x = x - (int)TacLeptonWidth/2;
if (x < Cell_To_Lepton(MapCellX)) x = Cell_To_Lepton(MapCellX);
y = y - (int)TacLeptonHeight/2;
if (y < Cell_To_Lepton(MapCellY)) y = Cell_To_Lepton(MapCellY);
Set_Tactical_Position(XY_Coord(x, y));
}
}
/***********************************************************************************************
* DisplayClass::Encroach_Shadow -- Causes the shadow to creep back by one cell. *
* *
* This routine will cause the shadow to creep back by one cell. Multiple calls to this *
* routine will result in the shadow becoming more and more invasive until only the sight *
* range of player controlled units will keep the shadow pushed back. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 10/16/1995 JLB : Created. *
*=============================================================================================*/
void DisplayClass::Encroach_Shadow(void)
{
for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) {
if (!In_Radar(cell)) continue;
CellClass * cellptr = &(*this)[cell];
if (cellptr->IsVisible || !cellptr->IsMapped) continue;
cellptr->IsToShroud = true;
}
/*
** Mark all shadow edge cells to be fully shrouded. All adjacent mapped
** cell should become partially shrouded.
*/
for (cell = 0; cell < MAP_CELL_TOTAL; cell++) {
if (!In_Radar(cell)) continue;
if ((*this)[cell].IsToShroud) {
(*this)[cell].IsToShroud = false;
Shroud_Cell(cell);
}
}
All_To_Look();
Flag_To_Redraw(true);
}
/***********************************************************************************************
* DisplayClass::Shroud_Cell -- Returns the specified cell into the shrouded condition. *
* *
* This routine is called to add the shroud back to the cell specified. Typical of this *
* would be when the shroud is to regenerate. *
* *
* INPUT: cell -- The cell that the shroud is to be regenerated upon. *
* *
* OUTPUT: none *
* *
* WARNINGS: Adjacent cells might be affected by this routine. The affect is determined *
* according to the legality of the partial shadow artwork. In the illegal cases *
* the adjacent cell might become shrouded as well. *
* *
* HISTORY: *
* 10/17/1995 JLB : Created. *
* 06/17/1996 JLB : Modified to handle the new shadow pieces. *
*=============================================================================================*/
void DisplayClass::Shroud_Cell(CELL cell/*KO, bool shadeit*/)
{
if (PlayerPtr->IsGPSActive) {
if ( (*this)[cell].Jammed & (1 << PlayerPtr->Class->House) ) {
return;
}
}
if (!In_Radar(cell)) return;
CellClass * cellptr = &(*this)[cell];
if (cellptr->IsMapped) {
cellptr->IsMapped = false;
cellptr->IsVisible = false;
cellptr->Redraw_Objects();
/*
** Check adjacent cells. There might be some weird combination of
** shrouded cells such that more cells must be shrouded in order for
** this to work.
*/
for (FacingType dir = FACING_FIRST; dir < FACING_COUNT; dir++) {
CELL c = Adjacent_Cell(cell, dir);
CellClass * cptr = &(*this)[c];
/*
** If this adjacent cell must be completely shrouded as a result
** of the map change, yet it isn't already shrouded, then recursively
** shroud that cell.
*/
if (c != cell) {
cptr->IsVisible = false;
}
/*
** Always redraw the cell because, more than likely, the shroud
** edge will change shape because of the map change.
*/
cptr->Redraw_Objects();
}
}
}
/***********************************************************************************************
* DisplayClass::Read_INI -- Reads map control data from INI file. *
* *
* This routine is used to read the map control data from the INI *
* file. *
* *
* INPUT: buffer -- Pointer to the loaded INI file data. *
* *
* OUTPUT: none *
* *
* WARNINGS: The TriggerClass INI data must have been read before calling this function. *
* *
* HISTORY: *
* 05/27/1994 JLB : Created. *
*=============================================================================================*/
void DisplayClass::Read_INI(CCINIClass & ini)
{
/*
** Read the map dimensions.
*/
char const * const name = "Map";
int x = ini.Get_Int(name, "X", 1);
int y = ini.Get_Int(name, "Y", 1);
int w = ini.Get_Int(name, "Width", MAP_CELL_W-2);
int h = ini.Get_Int(name, "Height", MAP_CELL_H-2);
#ifndef FIXIT_VERSION_3 // Map size no longer restricted.
#ifdef FIXIT_CSII // checked - ajw
if(Session.Type >= GAME_MODEM && Session.Type <= GAME_INTERNET && PlayingAgainstVersion < VERSION_AFTERMATH_CS) {
/*
** HACK ALERT:
** Force the map to be limited to the size that 96x96 would be. If the
** size is greater (due to hacking?) then shrink it down to legal size.
** BG Note: only do this for multiplayer games against non-AfterMath.
*/
if (w * h > 96 * 96) {
h -= (((w*h) - (96*96)) / w) + 1;
}
}
#else
/*
** HACK ALERT:
** Force the map to be limited to the size that 96x96 would be. If the
** size is greater (due to hacking?) then shrink it down to legal size.
*/
if (w * h > 96 * 96) {
h -= (((w*h) - (96*96)) / w) + 1;
}
#endif
#endif // !FIXIT_VERSION_3
Set_Map_Dimensions( x, y, w, h );
/*
** The theater is determined at this point. There is specific data that
** is custom to this data. Load the custom data (as it related to terrain)
** at this point.
*/
Scen.Theater = ini.Get_TheaterType(name, "Theater", THEATER_TEMPERATE);
/*
** Remove any old theater specific uncompressed shapes
*/
#ifdef WIN32
if (Scen.Theater != LastTheater) {
Reset_Theater_Shapes();
}
#endif //WIN32
/*
** Now that the theater is known, init the entire map hierarchy
*/
Init(Scen.Theater);
/*
** Special initializations occur when the theater is known.
*/
TerrainTypeClass::Init(Scen.Theater);
TemplateTypeClass::Init(Scen.Theater);
OverlayTypeClass::Init(Scen.Theater);
UnitTypeClass::Init(Scen.Theater);
InfantryTypeClass::Init(Scen.Theater);
BuildingTypeClass::Init(Scen.Theater);
BulletTypeClass::Init(Scen.Theater);
AnimTypeClass::Init(Scen.Theater);
AircraftTypeClass::Init(Scen.Theater);
VesselTypeClass::Init(Scen.Theater);
SmudgeTypeClass::Init(Scen.Theater);
/*
** Read the Waypoint entries.
*/
for (int i = 0; i < WAYPT_COUNT; i++) {
char buf[20];
sprintf(buf, "%d", i);
Scen.Waypoint[i] = ini.Get_Int("Waypoints", buf, -1);
if (Scen.Waypoint[i] != -1) {
(*this)[Scen.Waypoint[i]].IsWaypoint = 1;
}
}
/*
** Set the starting position (do this after Init(), which clears the cells'
** IsWaypoint flags).
*/
if (Scen.Waypoint[WAYPT_HOME] == -1) {
Scen.Waypoint[WAYPT_HOME] = XY_Cell(MapCellX + 5*RESFACTOR, MapCellY + 4*RESFACTOR);
}
Scen.Views[0] = Scen.Views[1] = Scen.Views[2] = Scen.Views[3] = Scen.Waypoint[WAYPT_HOME];
Set_Tactical_Position(Cell_Coord((Scen.Waypoint[WAYPT_HOME] - (MAP_CELL_W * 4 * RESFACTOR)) - (5*RESFACTOR)));
/*
** Loop through all CellTrigger entries.
*/
int len = ini.Entry_Count("CellTriggers");
for (int index = 0; index < len; index++) {
/*
** Get a cell trigger and cell assignment.
*/
char const * cellentry = ini.Get_Entry("CellTriggers", index);
TriggerTypeClass * tp = ini.Get_TriggerType("CellTriggers", cellentry);
CELL cell = atoi(cellentry);
if (tp != NULL && !(*this)[cell].Trigger.Is_Valid()) {
TriggerClass * tt = Find_Or_Make(tp);
if (tt) {
tt->AttachCount++;
tt->Cell = cell;
(*this)[cell].Trigger = tt;
}
}
}
/*
** Read the map template data.
*/
static char const * const MAPPACK = "MapPack";
len = ini.Get_UUBlock(MAPPACK, _staging_buffer, sizeof(_staging_buffer));
BufferStraw bstraw(_staging_buffer, len);
Map.Read_Binary(bstraw);
LastTheater = Scen.Theater;
}
/***********************************************************************************************
* DisplayClass::Write_INI -- Write the map data to the INI file specified. *
* *
* This routine will output all the data of this map to the INI database specified. *
* *
* INPUT: ini -- Reference to the INI handler to store the map data to. *
* *
* OUTPUT: none *
* *
* WARNINGS: Any existing map data in the INI database will be replaced by this function. *
* *
* HISTORY: *
* 07/03/1996 JLB : Created. *
*=============================================================================================*/
void DisplayClass::Write_INI(CCINIClass & ini)
{
char entry[20];
/*
** Save the map parameters.
*/
static char const * const NAME = "Map";
ini.Clear(NAME);
ini.Put_TheaterType(NAME, "Theater", Scen.Theater);
ini.Put_Int(NAME, "X", MapCellX);
ini.Put_Int(NAME, "Y", MapCellY);
ini.Put_Int(NAME, "Width", MapCellWidth);
ini.Put_Int(NAME, "Height", MapCellHeight);
/*
** Save the Waypoint entries.
*/
static char const * const WAYNAME = "Waypoints";
ini.Clear(WAYNAME);
for (int i = 0; i < WAYPT_COUNT; i++) {
if (Scen.Waypoint[i] != -1) {
sprintf(entry, "%d", i);
ini.Put_Int(WAYNAME, entry, Scen.Waypoint[i]);
}
}
/*
** Save the cell's triggers.
*/
static char const * const CELLTRIG = "CellTriggers";
ini.Clear(CELLTRIG);
for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) {
if ((*this)[cell].Trigger.Is_Valid()) {
TriggerClass * tp = (*this)[cell].Trigger;
if (tp != NULL) {
/*
** Generate entry name.
*/
sprintf(entry, "%d", cell);
/*
** Save entry.
*/
ini.Put_TriggerType(CELLTRIG, entry, tp->Class);
}
}
}
/*
** Write the map template data out to the ini file.
*/
static char const * const MAPPACK = "MapPack";
BufferPipe bpipe(_staging_buffer, sizeof(_staging_buffer));
int len = Map.Write_Binary(bpipe);
ini.Clear(MAPPACK);
if (len) {
ini.Put_UUBlock(MAPPACK, _staging_buffer, len);
}
}
/***********************************************************************************************
* DisplayClass::All_To_Look -- Direct all objects to look around for the player. *
* *
* This routine will scan through all objects and tell them to look if they are supposed *
* to be able to reveal the map for the player. This routine may be necessary in cases *
* of gap generator reshroud logic. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/23/1996 JLB : Created. *
*=============================================================================================*/
void DisplayClass::All_To_Look(bool units_only)
{
for (int index = 0; index < Layer[LAYER_GROUND].Count(); index++) {
ObjectClass * object = Layer[LAYER_GROUND][index];
if (object != NULL && object->Is_Techno()) {
TechnoClass * tech = ((TechnoClass *)object);
if (tech->What_Am_I() == RTTI_BUILDING && units_only) continue;
if (tech->House->IsPlayerControl) {
if (tech->IsDiscoveredByPlayer) {
object->Look();
}
} else {
if (tech->What_Am_I() == RTTI_BUILDING && Rule.IsAllyReveal && tech->House->Is_Ally(PlayerPtr)) {
tech->Look();
}
}
}
}
}
void DisplayClass::Constrained_Look(COORDINATE center, LEPTON distance)
{
for (int index = 0; index < Layer[LAYER_GROUND].Count(); index++) {
ObjectClass * object = Layer[LAYER_GROUND][index];
if (object != NULL && object->Is_Techno()) {
TechnoClass * tech = ((TechnoClass *)object);
// if (tech->What_Am_I() == RTTI_BUILDING && units_only) continue;
if (tech->House->IsPlayerControl) {
if (tech->IsDiscoveredByPlayer && Distance(tech->Center_Coord(), center) <= (tech->Techno_Type_Class()->SightRange * CELL_LEPTON_W) + distance) {
object->Look();
}
} else {
if (tech->What_Am_I() == RTTI_BUILDING && Rule.IsAllyReveal && tech->House->Is_Ally(PlayerPtr) &&
Distance(tech->Center_Coord(), center) <= (tech->Techno_Type_Class()->SightRange * CELL_LEPTON_W) + distance) {
tech->Look();
}
}
}
}
}
/***********************************************************************************************
* DisplayClass::Flag_Cell -- Flag the specified cell to be redrawn. *
* *
* This will flag the cell to be redrawn. *
* *
* INPUT: cell -- The cell to be flagged. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 10/20/1996 JLB : Created. *
*=============================================================================================*/
void DisplayClass::Flag_Cell(CELL cell)
{
Flag_To_Redraw(false);
IsToRedraw = true;
CellRedraw[cell] = true;
}
================================================
FILE: CODE/DISPLAY.H
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/DISPLAY.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 : DISPLAY.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : May 1, 1994 *
* *
* Last Update : May 1, 1994 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef DISPLAY_H
#define DISPLAY_H
#include "map.h"
#include "layer.h"
#define ICON_PIXEL_W 24
#define ICON_PIXEL_H 24
#define ICON_LEPTON_W 256
#define ICON_LEPTON_H 256
#define CELL_PIXEL_W ICON_PIXEL_W
#define CELL_PIXEL_H ICON_PIXEL_H
#define CELL_LEPTON_W ICON_LEPTON_W
#define CELL_LEPTON_H ICON_LEPTON_H
// -----------------------------------------------------------
#define PIXEL_LEPTON_W (ICON_LEPTON_W/ICON_PIXEL_W)
#define PIXEL_LEPTON_H (ICON_LEPTON_H/ICON_PIXEL_H)
#define SIDE_BAR_TAC_WIDTH 10
#define SIDE_BAR_TAC_HEIGHT 8
extern COORDINATE Coord_Add(COORDINATE coord1, COORDINATE coord2);
class DisplayClass: public MapClass
{
public:
/*
** The tactical map display position is indicated by the cell of the
** upper left hand corner. These should not be altered directly. Use
** the Set_Tactical_Position function instead.
*/
COORDINATE TacticalCoord;
/*
** The dimensions (in cells) of the visible window onto the game map. This tactical
** map is how the player interacts and views the game world.
*/
LEPTON TacLeptonWidth;
LEPTON TacLeptonHeight;
/*
** These layer control elements are used to group the displayable objects
** so that proper overlap can be obtained.
*/
static LayerClass Layer[LAYER_COUNT];
/*
** This records the position and shape of a placement cursor to display
** over the map. This cursor is used when placing buildings and also used
** extensively by the scenario editor.
*/
CELL ZoneCell;
short ZoneOffset;
short const *CursorSize;
bool ProximityCheck; // Is proximity check ok?
/*
** This holds the building type that is about to be placed upon the map.
** It is only valid during the building placement state. The PendingLegal
** flag is updated as the cursor moves and it reflects the legality of
** placing the building at the desired location.
*/
ObjectClass * PendingObjectPtr;
ObjectTypeClass const * PendingObject;
HousesType PendingHouse;
static unsigned char FadingBrighten[256];
static unsigned char FadingShade[256];
static unsigned char FadingWayDark[256];
static unsigned char FadingLight[256];
static unsigned char FadingGreen[256];
static unsigned char FadingYellow[256];
static unsigned char FadingRed[256];
static unsigned char TranslucentTable[(MAGIC_COL_COUNT+1)*256];
static unsigned char WhiteTranslucentTable[(1+1)*256];
static unsigned char MouseTranslucentTable[(4+1)*256];
static void const *TransIconset;
static unsigned char UnitShadow[(USHADOW_COL_COUNT+1)*256];
static unsigned char UnitShadowAir[(USHADOW_COL_COUNT+1)*256];
static unsigned char SpecialGhost[2*256];
//-------------------------------------------------------------------------
DisplayClass(void);
DisplayClass(NoInitClass const & x) : MapClass(x) {};
virtual void Read_INI(CCINIClass & ini);
void Write_INI(CCINIClass & ini);
/*
** Initialization
*/
virtual void One_Time(void); // One-time inits
virtual void Init_Clear(void); // Clears all to known state
virtual void Init_IO(void); // Inits button list
virtual void Init_Theater(TheaterType theater); // Theater-specific inits
/*
** General display/map/interface support functionality.
*/
virtual void AI(KeyNumType &input, int x, int y);
virtual void Draw_It(bool complete=false);
/*
** Added functionality.
*/
void All_To_Look(bool units_only=false);
void Constrained_Look(COORDINATE coord, LEPTON distance);
void Shroud_Cell(CELL cell/*KO, bool shadeit = false*/);
void Encroach_Shadow(void);
void Center_Map(COORDINATE center=0L);
virtual bool Map_Cell(CELL cell, HouseClass *house);
virtual CELL Click_Cell_Calc(int x, int y) const;
virtual void Help_Text(int , int =-1, int =-1, int =YELLOW, bool =false) {};
virtual MouseType Get_Mouse_Shape(void) const = 0;
virtual bool Scroll_Map(DirType facing, int & distance, bool really);
virtual void Refresh_Cells(CELL cell, short const *list);
virtual void Set_View_Dimensions(int x, int y, int width=-1, int height=-1);
/*
** Pending object placement control.
*/
virtual void Put_Place_Back(TechnoClass * ) {}; // Affects 'pending' system.
void Cursor_Mark(CELL pos, bool on);
void Set_Cursor_Shape(short const * list);
CELL Set_Cursor_Pos(CELL pos = -1);
void Get_Occupy_Dimensions(int & w, int & h, short const *list) const;
/*
** Tactical map only functionality.
*/
virtual void Set_Tactical_Position(COORDINATE coord);
void Refresh_Band(void);
void Select_These(COORDINATE coord1, COORDINATE coord2);
COORDINATE Pixel_To_Coord(int x, int y) const;
bool Coord_To_Pixel(COORDINATE coord, int & x, int & y) const;
bool Push_Onto_TacMap(COORDINATE &source, COORDINATE &dest);
void Remove(ObjectClass const * object, LayerType layer);
void Submit(ObjectClass const * object, LayerType layer);
CELL Calculated_Cell(SourceType dir, WAYPOINT waypoint=-1, CELL cell=-1, SpeedType loco=SPEED_FOOT, bool zonecheck=true, MZoneType mzone=MZONE_NORMAL) const;
bool In_View(register CELL cell) const;
bool Passes_Proximity_Check(ObjectTypeClass const * object, HousesType house, short const * list, CELL trycell) const;
ObjectClass * Cell_Object(CELL cell, int x=0, int y=0) const;
ObjectClass * Next_Object(ObjectClass * object) const;
ObjectClass * Prev_Object(ObjectClass * object) const;
int Cell_Shadow(CELL cell) const;
short const * Text_Overlap_List(char const * text, int x, int y) const;
bool Is_Spot_Free(COORDINATE coord) const;
COORDINATE Closest_Free_Spot(COORDINATE coord, bool any=false) const;
void Sell_Mode_Control(int control);
void Repair_Mode_Control(int control);
virtual void Flag_Cell(CELL cell);
bool Is_Cell_Flagged(CELL cell) const {return CellRedraw.Is_True(cell);};
/*
** Computes starting position based on player's units' Coords.
*/
void Compute_Start_Pos(void);
/*
** File I/O.
*/
virtual void Code_Pointers(void);
virtual void Decode_Pointers(void);
protected:
virtual void Mouse_Right_Press(void);
virtual void Mouse_Left_Press(int x, int y);
virtual void Mouse_Left_Up(CELL cell, bool shadow, ObjectClass * object, ActionType action, bool wsmall = false);
virtual void Mouse_Left_Held(int x, int y);
virtual void Mouse_Left_Release(CELL cell, int x, int y, ObjectClass * object, ActionType action, bool wsmall = false);
public:
/*
** This is the pixel offset for the upper left corner of the tactical map.
*/
int TacPixelX;
int TacPixelY;
/*
** This is the coordinate that the tactical map should be in at next available opportunity.
*/
COORDINATE DesiredTacticalCoord;
/*
** If something in the tactical map is to be redrawn, this flag is set to true.
*/
unsigned IsToRedraw:1;
/*
** If the player is currently wielding a wrench (to select buildings for repair),
** then this flag is true. In such a state, normal movement and combat orders
** are preempted.
*/
unsigned IsRepairMode:1;
/*
** If the player is currently in "sell back" mode, then this flag will be
** true. While in this mode, anything clicked on will be sold back to the
** "factory".
*/
unsigned IsSellMode:1;
/*
** If the player is currently in ion cannon targeting mode, then this
** flag will be true. While in this mode, anything clicked on will be
** be destroyed by the ION cannon.
*/
SpecialWeaponType IsTargettingMode;
protected:
/*
** If it is currently in rubber band mode (multi unit selection), then this
** flag will be true. While in such a mode, normal input is preempted while
** the extended selection is in progress.
*/
unsigned IsRubberBand:1;
/*
** The moment the mouse is held down, this flag gets set. If the mouse is dragged
** a sufficient distance while held down, then true rubber band mode selection
** can begin. Using a minimum distance prevents accidental rubber band selection
** mode from being initiated.
*/
unsigned IsTentative:1;
/*
** This gadget class is used for capturing input to the tactical map. All mouse input
** will be routed through this gadget.
*/
class TacticalClass : public GadgetClass {
public:
TacticalClass(void) : GadgetClass(0,0,0,0,LEFTPRESS|LEFTRELEASE|LEFTHELD|LEFTUP|RIGHTPRESS,true) {};
protected:
virtual int Action(unsigned flags, KeyNumType & key);
};
friend class TacticalClass;
/*
** This is the "button" that tracks all input to the tactical map.
** It must be available to derived classes, for Save/Load purposes.
*/
static TacticalClass TacButton;
private:
/*
** This is a utility flag that is set during the icon draw process only if there
** was at least one shadow icon detected that should be redrawn. When the shadow
** drawing logic is to take place, but this flag is false, then the shadow drawing
** will be skipped since it would perform no function.
*/
unsigned IsShadowPresent:1;
/*
** Rubber band mode consists of stretching a box from the anchor point (specified
** here) to the current cursor position.
*/
int BandX,BandY;
int NewX,NewY;
static void const *ShadowShapes;
static unsigned char ShadowTrans[(SHADOW_COL_COUNT+1)*256];
void Redraw_Icons(void);
void Redraw_OIcons(void);
void Redraw_Shadow(void);
/*
** This bit array is used to flag cells to be redrawn. If the icon needs to
** be redrawn for a cell, then the corresponding flag will be true.
*/
static BooleanVectorClass CellRedraw;
bool Good_Reinforcement_Cell(CELL outcell, CELL incell, SpeedType loco, int zone, MZoneType mzone) const;
};
#endif
================================================
FILE: CODE/DOOR.CPP
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/DOOR.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 : DOOR.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 06/11/95 *
* *
* Last Update : June 14, 1995 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* DoorClass::AI -- Handles the door processing logic. *
* DoorClass::Close_Door -- Try to close the unit's door. *
* DoorClass::DoorClass -- Constructor for the DoorClass object. *
* DoorClass::Door_Stage -- Fetches the current door animation frame. *
* DoorClass::Open_Door -- Opens the door for this unit. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
/***********************************************************************************************
* DoorClass::DoorClass -- Constructor for the DoorClass object. *
* *
* This constructor sets the door to an initial closed state. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/14/1995 JLB : Created. *
*=============================================================================================*/
DoorClass::DoorClass(void)
{
State = IS_CLOSED;
IsToRedraw = false;
Stages = 0;
}
/***********************************************************************************************
* DoorClass::AI -- Handles the door processing logic. *
* *
* This routine should be called every game frame. It handles the door closing and opening *
* logic. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/13/1995 JLB : Created. *
*=============================================================================================*/
void DoorClass::AI(void)
{
if (Control.Graphic_Logic()) {
if (Control.Fetch_Stage() >= Stages) {
Control.Set_Rate(0);
switch (State) {
case IS_OPENING:
State = IS_OPEN;
break;
case IS_CLOSING:
State = IS_CLOSED;
break;
}
}
IsToRedraw = true;
}
}
/***********************************************************************************************
* DoorClass::Open_Door -- Opens the door for this unit. *
* *
* This routine will perform the door open operation for this unit. It will control vehicle *
* rotation if necessary. *
* *
* INPUT: rate -- The animation rate (delay) to use for the door animation logic. *
* *
* stages -- The number of animations stages that this door must pass through. *
* *
* OUTPUT: Was action initiated to open the door? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/08/1995 JLB : Created. *
*=============================================================================================*/
bool DoorClass::Open_Door(int rate, int stages)
{
switch (State) {
case IS_CLOSED:
case IS_CLOSING:
State = IS_OPENING;
Stages = stages-1;
Control.Set_Stage(0);
Control.Set_Rate(rate);
return(true);
}
return(false);
}
/***********************************************************************************************
* DoorClass::Close_Door -- Try to close the unit's door. *
* *
* This routine will attempt to close the unit's door. If the door is already closed or *
* in the process of closing, then no action is performed. *
* *
* INPUT: rate -- The animation rate (delay) to use for the door animation logic. *
* *
* stages -- The number of animations stages that this door must pass through. *
* *
* OUTPUT: Action was initiated to close the door? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/08/1995 JLB : Created. *
*=============================================================================================*/
bool DoorClass::Close_Door(int rate, int stages)
{
switch (State) {
case IS_OPEN:
case IS_OPENING:
State = IS_CLOSING;
Stages = stages-1;
Control.Set_Stage(0);
Control.Set_Rate(rate);
return(true);
}
return(false);
}
/***********************************************************************************************
* DoorClass::Door_Stage -- Fetches the current door animation frame. *
* *
* Use this routine to fetch the current door animation frame number. Frame zero is the *
* closed frame and frame 'N' is the open frame. If the door is in the process of opening *
* or closing, the appropriate frame number is used. 'N' is defined as the number of *
* stages in the animation minus 1 (e.g., a four frame animation will return a door stage *
* number between 0 and 3, inclusive). *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the door animation frame number. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/14/1995 JLB : Created. *
*=============================================================================================*/
int DoorClass::Door_Stage(void) const
{
switch (State) {
case IS_CLOSING:
return((Stages-1) - Control.Fetch_Stage());
case IS_CLOSED:
return(0);
case IS_OPENING:
return(Control.Fetch_Stage());
case IS_OPEN:
return(Stages-1);
}
return(0);
}
================================================
FILE: CODE/DOOR.H
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/DOOR.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 : DOOR.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 06/11/95 *
* *
* Last Update : June 11, 1995 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef DOOR_H
#define DOOR_H
class DoorClass
{
private:
/*
** This is the animation control handler.
*/
StageClass Control;
/*
** This is the recorded number of stages of the current
** door animation process.
*/
unsigned char Stages;
/*
** This is the door state.
*/
enum {
IS_CLOSED, // Door is closed.
IS_OPENING, // Door is in the process of opening.
IS_OPEN, // Door is fully open.
IS_CLOSING // Door is in the process of closing.
} State;
/*
** If the animation for this door indicates that the object it is
** attached to should be redrawn, then this flag will be true.
*/
unsigned IsToRedraw:1;
public:
DoorClass(void);
DoorClass(NoInitClass const & x) : Control(x) {};
bool Time_To_Redraw(void) {return(IsToRedraw);};
void Clear_Redraw_Flag(void) {IsToRedraw = false;};
void AI(void);
int Door_Stage(void) const;
bool Is_Door_Opening(void) const {return(State == IS_OPENING);};
bool Is_Door_Closing(void) const {return(State == IS_CLOSING);};
bool Open_Door(int rate, int stages);
bool Close_Door(int rate, int stages);
bool Is_Door_Open(void) const {return(State == IS_OPEN);};
bool Is_Door_Closed(void) const {return(State == IS_CLOSED);};
bool Is_Ready_To_Open(void) const;
};
#endif
================================================
FILE: CODE/DPMI.CPP
================================================
/*
** 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 .
*/
/* $Header: F:\projects\c&c0\vcs\code\dpmi.cpv 4.41 04 Jul 1996 16:12:42 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 : DPMI.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : July 2, 1994 *
* *
* Last Update : July 2, 1994 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifdef __FLAT__
#pragma inline
#endif
//#include "function.h"
#include "dpmi.h"
#ifndef __FLAT__
void DOSSegmentClass::Swap(DOSSegmentClass &src, int soffset, DOSSegmentClass &dest, int doffset, int size)
{
if (!size) return;
unsigned short ssel = src.Selector;
unsigned short dsel = dest.Selector;
asm {
push es
push ds
mov si,soffset
mov di,doffset
mov cx,size
mov ax,ssel
mov dx,dsel
mov ds,ax
mov es,dx
}
again:
asm {
mov al,ds:[si]
mov ah,es:[di]
mov ds:[si],ah
mov es:[di],al
inc di
inc si
dec cx
jnz again
pop ds
pop es
}
}
#endif
void DOSSegmentClass::Swap(DOSSegmentClass &src, int soffset, DOSSegmentClass &dest, int doffset, int size)
{
extern void dss_swap(char *src, char *dest, int size);
#pragma aux dss_swap = \
"again: mov al,[esi]" \
"mov ah,[edi]" \
"mov [esi],ah" \
"stosb" \
"inc esi" \
"loop again" \
parm [esi] [edi] [ecx] \
modify [ax];
if (!size) return;
dss_swap((char *)(src.Selector + soffset), (char *)(dest.Selector + doffset), size);
}
#ifdef OBSOLETE
void DOSSegmentClass::Copy(DOSSegmentClass &src, int soffset, DOSSegmentClass &dest, int doffset, int size)
{
extern void dss_copy(char *src, char *dest, int size);
#pragma aux dss_copy = \
"mov ebx,ecx" \
"shr ecx,2" \
"jecxz copskip1" \
"rep movsd" \
"copskip1: mov ecx,ebx" \
"and ecx,3" \
"jecxz copskip2" \
"rep movsb" \
"copskip2:" \
parm [esi edi ecx] \
modify [ebx];
if (!size) return;
dss_copy((char *)(src.Selector + soffset), (char *)(dest.Selector + doffset), size);
}
#endif
#ifdef OBSOLETE
void DOSSegmentClass::Copy_To(void *source, int dest, int size)
{
extern void dss_copy_to(void *src, (void *)dest, int size);
#pragma aux dss_copy_to = \
"mov ebx,ecx" \
"shr ecx,2" \
"jecxz cop2skip1" \
"rep movsd" \
"cop2skip1: mov ecx,ebx" \
"and ecx,3" \
"jecxz cop2skip2" \
"rep movsb" \
"cop2skip2:" \
parm [esi edi ecx] \
modify [ebx];
if (!size) return;
dss_copy_to(src, (void *)(Selector + dest), size);
}
#endif
#ifdef OBSOLETE
void DOSSegmentClass::Copy_From(void *dest, int source, int size)
{
extern void dss_copy_from(void *dest, (void *)source, int size);
#pragma aux dss_copy_from = \
"mov ebx,ecx" \
"shr ecx,2" \
"jecxz copfskip1" \
"rep movsd" \
"copfskip1: mov ecx,ebx" \
"and ecx,3" \
"jecxz copfskip2" \
"rep movsb" \
"copfskip2:" \
parm [edi esi ecx] \
modify [ebx];
if (!size) return;
dss_copy_from(dest, (void *)(Selector + source), size);
}
#endif
================================================
FILE: CODE/DPMI.H
================================================
/*
** 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 .
*/
/* $Header: F:\projects\c&c0\vcs\code\dpmi.h_v 4.43 05 Jul 1996 17:58:40 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 : DPMI.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : July 2, 1994 *
* *
* Last Update : July 2, 1994 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef DPMI_Hx
#define DPMI_Hx
#include
#include
#include
#include
extern void output(short port, short data);
class DOSSegmentClass {
/*
** This is the selector/segment value. In real mode it is the segment, in protected
** mode it is the selector (also 16 bits). This value is moved into DS or ES when
** accessing memory.
** Note: in Watcom flat addressing, Selector == Segment<<4 (ex: 0A0000h)
*/
unsigned int Selector;
/*
** These are C equivalents for pushing and popping the DS segment register. By using
** these, it is possible to create very small code that uses a segment and
** offset without damaging the DS register. These are especially useful in protected
** mode, but they are legal in real mode as well.
*/
void Push_DS(void) {/*__emit__(0x1E);*/};
void Pop_DS(void) {/*__emit__(0x1F);*/};
public:
DOSSegmentClass(void);
~DOSSegmentClass(void);
DOSSegmentClass(unsigned short segment, long size=(1024L*64L));
unsigned int Get_Selector(void);
/*
** This routine is used to assign where the descriptor actually points to in
** low DOS memory. In real mode, this is a simple segment assignment and the size
** is always 64K regardless of what is specified. In protected mode, the segment
** is used to update the selector and the size can be any length.
** In Watcom flat mode, it sets Selector == segment<<4
*/
void Assign(unsigned short segment, long size=(1024L*64L));
/*
** These routines will move the data to/from regular memory and the segment/descriptor
** memory.
*/
void Copy_To(void *source, int dest, int size);
void Copy_From(void *dest, int source, int size);
void Copy_Word_To(short data, int dest);
void Copy_Byte_To(char data, int dest);
void Copy_DWord_To(long data, int dest);
short Copy_Word_From(int source);
char Copy_Byte_From(int source);
long Copy_DWord_From(int source);
/*
** These routines move data around between sections of segmented (descriptor) memory.
** Typically, this is used when accessing DOS memory in protected mode or when dealing
** with hard memory areas such as the screen.
*/
static void Copy(DOSSegmentClass &src, int soffset, DOSSegmentClass &dest, int doffset, int size);
static void Swap(DOSSegmentClass &src, int soffset, DOSSegmentClass &dest, int doffset, int size);
};
inline DOSSegmentClass::DOSSegmentClass(void)
{
Selector = 0xB0000;
}
inline DOSSegmentClass::~DOSSegmentClass(void)
{
}
inline void DOSSegmentClass::Copy_Word_To(short data, int dest)
{
*(short *)(Selector+dest) = data;
}
inline void DOSSegmentClass::Copy_Byte_To(char data, int dest)
{
*(char *)(Selector+dest) = data;
}
inline void DOSSegmentClass::Copy_DWord_To(long data, int dest)
{
*(long *)(Selector+dest) = data;
}
inline void DOSSegmentClass::Assign(unsigned short segment, long)
{
Selector = (long)(segment)<<4L;
}
inline DOSSegmentClass::DOSSegmentClass(unsigned short segment, long)
{
Assign(segment);
}
inline void DOSSegmentClass::Copy_To(void *source, int dest, int size)
{
memmove((void*)(Selector+dest), source, (unsigned)size);
}
inline void DOSSegmentClass::Copy_From(void *dest, int source, int size)
{
memmove(dest, (void*)(Selector+source), (unsigned)size);
}
inline void DOSSegmentClass::Copy(DOSSegmentClass &src, int soffset, DOSSegmentClass &dest, int doffset, int size) {
memmove((void*)(dest.Selector+doffset), (void*)(src.Selector+soffset), (unsigned)size);
}
inline short DOSSegmentClass::Copy_Word_From(int source)
{
return *(short*)(Selector+source);
}
inline char DOSSegmentClass::Copy_Byte_From(int source)
{
return *(char*)(Selector+source);
}
inline long DOSSegmentClass::Copy_DWord_From(int source)
{
return *(long*)(Selector+source);
}
inline unsigned int DOSSegmentClass::Get_Selector(void)
{
return Selector;
}
#endif
================================================
FILE: CODE/DRIVE.CPP
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/DRIVE.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 : DRIVE.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : April 22, 1994 *
* *
* Last Update : October 31, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* DriveClass::AI -- Processes unit movement and rotation. *
* DriveClass::Approach_Target -- Handles approaching the target in order to attack it. *
* DriveClass::Assign_Destination -- Set the unit's NavCom. *
* DriveClass::Class_Of -- Fetches a reference to the class type for this object. *
* DriveClass::Debug_Dump -- Displays status information to monochrome screen. *
* DriveClass::Do_Turn -- Tries to turn the vehicle to the specified direction. *
* DriveClass::DriveClass -- Constructor for drive class object. *
* DriveClass::Fixup_Path -- Adds smooth start path to normal movement path. *
* DriveClass::Force_Track -- Forces the unit to use the indicated track. *
* DriveClass::Lay_Track -- Handles track laying logic for the unit. *
* DriveClass::Limbo -- Prepares vehicle and then limbos it. *
* DriveClass::Mark_Track -- Marks the midpoint of the track as occupied. *
* DriveClass::Ok_To_Move -- Checks to see if this object can begin moving. *
* DriveClass::Per_Cell_Process -- Handles when unit finishes movement into a cell. *
* DriveClass::Response_Attack -- Voice feedback when ordering the unit to attack a target. *
* DriveClass::Response_Move -- Voice feedback when ordering the unit to move. *
* DriveClass::Response_Select -- Voice feedback when selecting the unit. *
* DriveClass::Scatter -- Causes the unit to travel to a nearby safe cell. *
* DriveClass::Smooth_Turn -- Handles the low level coord calc for smooth turn logic. *
* DriveClass::Start_Of_Move -- Tries to get a unit to advance toward cell. *
* DriveClass::Stop_Driver -- Handles removing occupation bits when driving stops. *
* DriveClass::Teleport_To -- Teleport object to specified location. *
* DriveClass::While_Moving -- Processes unit movement. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
#ifdef NEVER
void test(void)
{
enum nums {one, two, three};
nums x;
nums *ptr;
ptr = &x;
}
#endif
/***********************************************************************************************
* DriveClass::Response_Select -- Voice feedback when selecting the unit. *
* *
* This is the voice to play when the unit is selected. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/30/1994 JLB : Created. *
*=============================================================================================*/
void DriveClass::Response_Select(void)
{
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));
}
}
/***********************************************************************************************
* DriveClass::Response_Move -- Voice feedback when ordering the unit to move. *
* *
* This plays the audio feedback when ordering this unit to move to a new destination. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/30/1994 JLB : Created. *
*=============================================================================================*/
void DriveClass::Response_Move(void)
{
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));
}
}
/***********************************************************************************************
* DriveClass::Response_Attack -- Voice feedback when ordering the unit to attack a target. *
* *
* This plays the audio feedback when ordering this unit to attack. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/30/1994 JLB : Created. *
*=============================================================================================*/
void DriveClass::Response_Attack(void)
{
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));
}
}
/***********************************************************************************************
* DriveClass::Scatter -- Causes the unit to travel to a nearby safe cell. *
* *
* This routine is called when the unit discovers that it should get out of the "hot seat" *
* and move to an adjacent cell. Since the safety of the adjacent cell is not determined *
* before the move begins, it will appear that the unit is just scattering (which it *
* should). *
* *
* INPUT: threat -- The coordinate of the source of the threat. The unit will try to move *
* roughly away from the threat. *
* *
* forced -- The threat is real and a serious effort to scatter should be made. *
* *
* nokidding-- The scatter should affect the player's infantry even if it otherwise *
* wouldn't have. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/25/1994 JLB : Created. *
* 09/27/1995 JLB : Revised to never scatter if already moving. *
* 07/09/1996 JLB : Moved to DriveClass so that ships will scatter too. *
* 08/02/1996 JLB : Added the "nokidding" parameter. *
*=============================================================================================*/
void DriveClass::Scatter(COORDINATE threat, bool forced, bool nokidding)
{
assert(IsActive);
/*
** Certain missions prevent scattering regardless of whether it would be
** a good idea or not.
*/
if (MissionControl[Mission].IsParalyzed) return;
if ((What_Am_I() != RTTI_UNIT || !((UnitClass *)this)->IsDumping) && (!Target_Legal(NavCom) || (nokidding && !IsRotating))) {
if (!Target_Legal(TarCom) || forced || Random_Pick(1, 4) == 1) {
FacingType toface;
FacingType newface;
CELL newcell;
if (threat != 0) {
toface = Dir_Facing(Direction8(threat, Coord));
toface = toface + FacingType(Random_Pick(0, 2)-1);
} else {
toface = Dir_Facing(PrimaryFacing.Current());
toface = toface + FacingType(Random_Pick(0, 2)-1);
}
for (FacingType face = FACING_N; face < FACING_COUNT; face++) {
newface = toface + face;
newcell = Adjacent_Cell(Coord_Cell(Coord), newface);
if (Map.In_Radar(newcell) && Can_Enter_Cell(newcell) == MOVE_OK) {
Assign_Destination(::As_Target(newcell));
}
}
}
}
}
/***********************************************************************************************
* DriveClass::Limbo -- Prepares vehicle and then limbos it. *
* *
* This routine removes the occupation bits for the vehicle and also handles cleaning up *
* any vehicle reservation bits. After this, it then proceeds with limboing the unit. *
* *
* INPUT: none *
* *
* OUTPUT: bool; Was the vehicle limboed? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/22/1994 JLB : Created. *
*=============================================================================================*/
bool DriveClass::Limbo(void)
{
if (!IsInLimbo) {
Stop_Driver();
TrackNumber = -1;
}
return(FootClass::Limbo());
}
/***********************************************************************************************
* DriveClass::Stop_Driver -- Handles removing occupation bits when driving stops. *
* *
* This routine will remove the "reservation" flag (if present) when the vehicle is *
* required to stop movement. *
* *
* INPUT: none *
* *
* OUTPUT: bool; Was the vehicle stopped? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/22/1994 JLB : Created. *
*=============================================================================================*/
bool DriveClass::Stop_Driver(void)
{
assert(IsActive);
/*
** We only need to do something if the vehicle is actually going
** somewhere.
*/
if (Head_To_Coord()) {
/*
** Safe off whether the vehicle is down or not so we know whether
** we have to put it back down.
*/
int temp = IsDown;
/*
** If the vehicle is down, pick it up so it doesn't interfere with
** our flags.
*/
if (temp) {
Mark(MARK_UP);
}
/*
** Call the drive class function which will let us release the
** reserved track.
*/
Mark_Track(Head_To_Coord(), MARK_UP);
/*
** If it was down it should be down when we are done.
*/
if (temp) {
Mark(MARK_DOWN);
}
}
return(FootClass::Stop_Driver());
}
/***********************************************************************************************
* DriveClass::Do_Turn -- Tries to turn the vehicle to the specified direction. *
* *
* This routine will set the vehicle to rotate to the direction specified. For tracked *
* vehicles, it is just a simple rotation. For wheeled vehicles, it performs a series *
* of short drives (three point turn) to face the desired direction. *
* *
* INPUT: dir -- The direction that this vehicle should face. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/29/1995 JLB : Created. *
*=============================================================================================*/
void DriveClass::Do_Turn(DirType dir)
{
assert(IsActive);
if (dir != PrimaryFacing) {
#ifdef TOFIX
/*
** Special rotation track is needed for units that
** cannot rotate in place.
*/
if (Special.IsThreePoint && TrackNumber == -1 && Techno_Type_Class()->Speed == SPEED_WHEEL) {
int facediff; // Signed difference between current and desired facing.
FacingType face; // Current facing (ordinal value).
facediff = PrimaryFacing.Difference(dir) >> 5;
facediff = Bound(facediff, -2, 2);
if (facediff) {
face = Dir_Facing(PrimaryFacing);
IsOnShortTrack = true;
Force_Track(face*FACING_COUNT + (face + facediff), Coord);
Path[0] = FACING_NONE;
Set_Speed(0xFF); // Full speed.
}
} else {
PrimaryFacing.Set_Desired(dir);
}
#else
PrimaryFacing.Set_Desired(dir);
// IsRotating = true;
#endif
}
}
/***********************************************************************************************
* DriveClass::Teleport_To -- Teleport object to specified location. *
* *
* This will teleport the object to the specified location or as close as possible to it *
* if the destination is blocked. *
* *
* INPUT: cell -- The desired destination cell to teleport to. *
* *
* OUTPUT: bool; Was the teleport successful? *
* *
* WARNINGS: All current activity of this object will be terminated by the teleport. It will *
* arrive at the destination in static guard mode. *
* *
* HISTORY: *
* 10/21/1996 JLB : Created. *
* 10/31/1996 JLB : Handles flag teleport case. *
*=============================================================================================*/
bool DriveClass::Teleport_To(CELL cell)
{
/*
** All cargo gets destroyed.
*/
if (Rule.IsChronoKill) {
Kill_Cargo(NULL);
}
Stop_Driver();
Force_Track(-1, 0);
PrimaryFacing.Set_Current(PrimaryFacing.Desired());
Transmit_Message(RADIO_OVER_OUT);
Assign_Destination(TARGET_NONE);
Assign_Target(TARGET_NONE);
Assign_Mission(MISSION_NONE);
Commence();
Mark(MARK_UP);
/*
** A teleported unit will drop the flag right where it's at.
*/
if (What_Am_I() == RTTI_UNIT && ((UnitClass *)this)->Flagged != HOUSE_NONE) {
HouseClass::As_Pointer(((UnitClass *)this)->Flagged)->Flag_Attach(Coord_Cell(Coord));
}
if (Can_Enter_Cell(cell) != MOVE_OK) {
cell = Map.Nearby_Location(cell, Techno_Type_Class()->Speed);
}
Coord = Cell_Coord(cell);
Mark(MARK_DOWN);
return(true);
}
/***********************************************************************************************
* DriveClass::Force_Track -- Forces the unit to use the indicated track. *
* *
* This override (nuclear bomb) style routine is to be used when a unit needs to start *
* on a movement track but is outside the normal movement system. This occurs when a *
* harvester starts driving off of a refinery. *
* *
* INPUT: track -- The track number to start on. *
* *
* coord -- The coordinate that the unit will end up at when the movement track *
* is completed. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 03/17/1995 JLB : Created. *
*=============================================================================================*/
void DriveClass::Force_Track(int track, COORDINATE coord)
{
assert(IsActive);
TrackNumber = track;
TrackIndex = 0;
if (coord != 0) {
Start_Driver(coord);
}
}
/***********************************************************************************************
* DriveClass::DriveClass -- Constructor for drive class object. *
* *
* This will initialize the drive class to its default state. It is called as a result *
* of creating a unit. *
* *
* INPUT: classid -- The unit's ID class. It is passed on to the foot class constructor. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/13/1994 JLB : Created. *
*=============================================================================================*/
DriveClass::DriveClass(RTTIType rtti, int id, HousesType house) :
FootClass(rtti, id, house),
IsMoebius(false),
IsHarvesting(false),
IsTurretLockedDown(false),
IsOnShortTrack(false),
SpeedAccum(0),
MoebiusCountDown(0),
MoebiusCell(0),
TrackNumber(-1),
TrackIndex(0)
{
}
#ifdef CHEAT_KEYS
/***********************************************************************************************
* DriveClass::Debug_Dump -- Displays status information to monochrome screen. *
* *
* This debug utility function will display the status of the drive class to the mono *
* screen. It is through this information that bugs can be tracked down. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/31/1994 JLB : Created. *
*=============================================================================================*/
void DriveClass::Debug_Dump(MonoClass * mono) const
{
assert(IsActive);
mono->Fill_Attrib(66, 14, 12, 1, IsMoebius ? MonoClass::INVERSE : MonoClass::NORMAL);
FootClass::Debug_Dump(mono);
}
#endif
/***********************************************************************************************
* DriveClass::Smooth_Turn -- Handles the low level coord calc for smooth turn logic. *
* *
* This routine calculates the new coordinate value needed for the *
* smooth turn logic. The adjustment and flag values must be *
* determined prior to entering this routine. *
* *
* INPUT: adj -- The adjustment coordinate as lifted from the *
* correct smooth turn table. *
* *
* dir -- Pointer to dir for possible modification *
* according to the flag bits. *
* *
* OUTPUT: Returns with the coordinate the unit should positioned to. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 03/14/1994 JLB : Created. *
* 07/13/1994 JLB : Converted to member function. *
*=============================================================================================*/
COORDINATE DriveClass::Smooth_Turn(COORDINATE adj, DirType & dir)
{
assert(IsActive);
DirType workdir = dir;
int x,y;
int temp;
TrackControlType flags = TrackControl[TrackNumber].Flag;
x = Coord_X(adj);
y = Coord_Y(adj);
if (flags & F_T) {
temp = x;
x = y;
y = temp;
workdir = (DirType)(DIR_W - workdir);
}
if (flags & F_X) {
x = -x;
workdir = (DirType)-workdir;
}
if (flags & F_Y) {
y = -y;
workdir = (DirType)(DIR_S - workdir);
}
dir = workdir;
return(XY_Coord( (LEPTON)(Coord_X(Head_To_Coord()) + x), (LEPTON)(Coord_Y(Head_To_Coord()) + y)));
}
/***********************************************************************************************
* DriveClass::Assign_Destination -- Set the unit's NavCom. *
* *
* This routine is used to set the unit's navigation computer to the *
* specified target. Once the navigation computer is set, the unit *
* will start planning and moving toward the destination. *
* *
* INPUT: target -- The destination target for the unit to head to. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/07/1992 JLB : Created. *
* 04/15/1994 JLB : Converted to member function. *
*=============================================================================================*/
void DriveClass::Assign_Destination(TARGET target)
{
assert(IsActive);
/*
** Abort early if there is anything wrong with the parameters
** or the unit already is assigned the specified destination.
*/
if (target == NavCom) return;
/*
** For harvesting type vehicles, it might go into a dock and unload procedure
** when the harvester is full and an empty refinery is selected as a target.
*/
BuildingClass * b = As_Building(target);
/*
** If the player clicked on refinery but it is not busy, then assign
** it to unload at the refinery.
*/
if (b != NULL && *b == STRUCT_REFINERY && What_Am_I() == RTTI_UNIT && ((UnitTypeClass *)Techno_Type_Class())->IsToHarvest) {
if (Contact_With_Whom() != b && !b->In_Radio_Contact()) {
/*
** Establish radio contact protocol. If the facility responds correctly,
** then remain in radio contact and proceed toward the desired destination.
*/
if (Transmit_Message(RADIO_HELLO, b) == RADIO_ROGER) {
if (Mission != MISSION_ENTER && Mission != MISSION_HARVEST) {
Assign_Mission(MISSION_ENTER);
target = TARGET_NONE;
} else {
// target = TARGET_NONE;
}
} else {
// target = TARGET_NONE;
}
} else {
// target = TARGET_NONE;
}
}
/*
** Set the unit's navigation computer.
*/
FootClass::Assign_Destination(target);
Path[0] = FACING_NONE; // Force recalculation of path.
if (!IsDriving && Mission != MISSION_UNLOAD) {
Start_Of_Move();
}
}
/***********************************************************************************************
* DriveClass::While_Moving -- Processes unit movement. *
* *
* This routine is used to process movement for the units as they move. *
* It is called many times for each cell's worth of movement. This *
* routine only applies after the next cell HeadTo has been determined. *
* *
* INPUT: none *
* *
* OUTPUT: true/false; Should this routine be called again? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 02/02/1992 JLB : Created. *
* 04/15/1994 JLB : Converted to member function. *
*=============================================================================================*/
bool DriveClass::While_Moving(void)
{
assert(IsActive);
/*
** Perform quick legality checks.
*/
if (!IsDriving || TrackNumber == -1 || (IsRotating && !Techno_Type_Class()->IsTurretEquipped)) {
SpeedAccum = 0; // Kludge? No speed should accumulate if movement is on hold.
return(false);
}
/*
** If enough movement has accumulated so that the unit can
** visibly move on the map, then process accordingly.
** Slow the unit down if he's carrying a flag.
*/
MPHType maxspeed = MPHType(min(Techno_Type_Class()->MaxSpeed * SpeedBias * House->GroundspeedBias, (int)MPH_LIGHT_SPEED));
if (IsFormationMove) maxspeed = FormationMaxSpeed;
int actual; // Working movement addition value.
if (((UnitClass *)this)->Flagged != HOUSE_NONE) {
actual = SpeedAccum + ((int)maxspeed/2) * fixed(Speed, 256);
} else {
actual = SpeedAccum + maxspeed * fixed(Speed, 256);
}
if (actual > PIXEL_LEPTON_W) {
TurnTrackType const * track; // Track control pointer.
TrackType const * ptr; // Pointer to coord offset values.
int tracknum; // The track number being processed.
FacingType nextface; // Next facing queued in path.
bool adj; // Is a turn coming up?
track = &TrackControl[TrackNumber];
if (IsOnShortTrack) {
tracknum = track->StartTrack;
} else {
tracknum = track->Track;
}
ptr = RawTracks[tracknum-1].Track;
nextface = Path[0];
/*
** Determine if there is a turn coming up. If there is
** a turn, then track jumping might occur.
*/
adj = false;
if (nextface != FACING_NONE && Dir_Facing(track->Facing) != nextface) {
adj = true;
}
/*
** Skip ahead the number of track steps required (limited only
** by track length). Set the unit to the new position and
** flag the unit accordingly.
*/
Mark(MARK_UP);
while (actual > PIXEL_LEPTON_W) {
COORDINATE offset;
DirType dir;
actual -= PIXEL_LEPTON_W;
offset = ptr[TrackIndex].Offset;
if (offset || !TrackIndex) {
dir = ptr[TrackIndex].Facing;
Coord = Smooth_Turn(offset, dir);
PrimaryFacing.Set(dir);
/*
** See if "per cell" processing is necessary.
*/
if (TrackIndex && RawTracks[tracknum-1].Cell == TrackIndex) {
Mark(MARK_DOWN);
Per_Cell_Process(PCP_DURING);
if (!IsActive) {
return(false);
}
Mark(MARK_UP);
}
/*
** The unit could "jump tracks". Check to see if the unit should
** do so.
*/
if (/**this != UNIT_GUNBOAT &&*/ nextface != FACING_NONE && adj && RawTracks[tracknum-1].Jump == TrackIndex && TrackIndex) {
TurnTrackType const * newtrack; // Proposed jump-to track.
int tnum;
tnum = (int)(Dir_Facing(track->Facing) * FACING_COUNT) + (int)nextface;
newtrack = &TrackControl[tnum];
if (newtrack->Track && RawTracks[newtrack->Track-1].Entry) {
COORDINATE c = Head_To_Coord();
int oldspeed = Speed;
c = Adjacent_Cell(c, nextface);
switch (Can_Enter_Cell(Coord_Cell(c), nextface)) {
case MOVE_OK:
IsOnShortTrack = false; // Shouldn't be necessary, but...
TrackNumber = tnum;
track = newtrack;
tracknum = track->Track;
TrackIndex = RawTracks[tracknum-1].Entry-1; // Anticipate increment.
ptr = RawTracks[tracknum-1].Track;
adj = false;
Stop_Driver();
IsDriving = true;
Per_Cell_Process(PCP_END);
IsDriving = false;
if (!IsActive) return(false);
if (Start_Driver(c)) {
Set_Speed(oldspeed);
memcpy((char*)&Path[0], (char*)&Path[1], CONQUER_PATH_MAX-1);
Path[CONQUER_PATH_MAX-1] = FACING_NONE;
} else {
Path[0] = FACING_NONE;
TrackNumber = -1;
actual = 0;
}
break;
case MOVE_CLOAK:
Map[c].Shimmer();
break;
case MOVE_TEMP:
#ifdef TOFIX
if (*this == UNIT_HARVESTER || !House->IsHuman) {
#else
if (!House->IsHuman) {
#endif
Map[c].Incoming(0, true, true);
}
break;
}
}
}
TrackIndex++;
} else {
actual = 0;
Coord = Head_To_Coord();
Stop_Driver();
TrackNumber = -1;
TrackIndex = NULL;
/*
** Perform "per cell" activities.
*/
Mark(MARK_DOWN);
Per_Cell_Process(PCP_END);
if (!IsActive) return(false);
Mark(MARK_UP);
break;
}
}
if (IsActive) {
Mark(MARK_DOWN);
}
}
/*
** Replace any remainder back into the unit's movement
** accumulator to be processed next pass.
*/
SpeedAccum = actual;
return(true);
}
/***********************************************************************************************
* DriveClass::Per_Cell_Process -- Handles when unit finishes movement into a cell. *
* *
* This routine is called when a unit has mostly or completely *
* entered a cell. The unit might be in the middle of a movement track *
* when this routine is called. It's primary purpose is to perform *
* sighting and other "per cell" activities. *
* *
* INPUT: why -- Specifies the circumstances under which this routine was called. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/03/1993 JLB : Created. *
* 03/30/1994 JLB : Revamped for track system. *
* 04/15/1994 JLB : Converted to member function. *
* 06/18/1994 JLB : Converted to virtual function. *
* 06/18/1994 JLB : Distinguishes between center and near-center conditions. *
*=============================================================================================*/
void DriveClass::Per_Cell_Process(PCPType why)
{
assert(IsActive);
if (why == PCP_END) {
CELL cell = Coord_Cell(Coord);
/*
** Check to see if it has reached its destination. If so, then clear the NavCom
** regardless of the remaining path list.
*/
if (As_Cell(NavCom) == cell) {
IsTurretLockedDown = false;
NavCom = TARGET_NONE;
Path[0] = FACING_NONE;
}
Lay_Track();
}
FootClass::Per_Cell_Process(why);
}
/***********************************************************************************************
* DriveClass::Start_Of_Move -- Tries to get a unit to advance toward cell. *
* *
* This will try to start a unit advancing toward the cell it is *
* facing. It will check for and handle legality and reserving of the *
* necessary cell. *
* *
* INPUT: none *
* *
* OUTPUT: true/false; Should this routine be called again because *
* initial start operation is temporarily delayed? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 02/02/1992 JLB : Created. *
* 10/18/1993 JLB : This should be called repeatedly until HeadTo is not NULL. *
* 03/16/1994 JLB : Revamped for track logic. *
* 04/15/1994 JLB : Converted to member function. *
* 06/19/1995 JLB : Fixed so that it won't fire on ground unnecessarily. *
* 07/13/1995 JLB : Handles bumping into cloaked objects. *
* 09/22/1995 JLB : Breaks out of hopeless hunt mode. *
* 07/10/1996 JLB : Sets scan limit if necessary. *
*=============================================================================================*/
bool DriveClass::Start_Of_Move(void)
{
assert(IsActive);
FacingType facing; // Direction movement will commence.
DirType dir; // Desired actual facing toward destination.
int facediff; // Difference between current and desired facing.
int speed; // Speed of unit.
CELL destcell; // Cell of destination.
LandType ground; // Ground unit is entering.
COORDINATE dest; // Destination coordinate.
facing = Path[0];
if (!Target_Legal(NavCom) && facing == FACING_NONE) {
IsTurretLockedDown = false;
Stop_Driver();
if (Mission == MISSION_MOVE) {
Enter_Idle_Mode();
}
return(false); // Why is it calling this routine!?!
}
/*
** Reduce the path length if the target is a unit and the
** range to the unit is less than the precalculated path steps.
*/
if (facing != FACING_NONE) {
int dist;
if (Is_Target_Vessel(NavCom) || Is_Target_Unit(NavCom) || Is_Target_Infantry(NavCom)) {
dist = Lepton_To_Cell((LEPTON)Distance(NavCom));
if (dist < ARRAY_SIZE(Path)) {
Path[dist] = FACING_NONE;
facing = Path[0]; // Maybe needed.
}
}
}
/*
** If the path is invalid at this point, then generate one. If
** generating a new path fails, then abort NavCom.
*/
if (facing == FACING_NONE) {
/*
** If after a path search, there is still no valid path, then set the
** NavCom to null and let the script take care of assigning a new
** navigation target.
*/
if (PathDelay != 0) {
return(false);
}
if (!Basic_Path()) {
/*
** If the unit is close enough to the target then just stop
** driving now. This prevents the fidgeting that would occur
** if they mindlessly kept trying to get to the exact location
** desired. This is quite necessary since it is typical to move
** several units with the same mouse click.
*/
if (!Is_On_Priority_Mission() && Distance(NavCom) < Rule.CloseEnoughDistance && (Mission == MISSION_MOVE || Mission == MISSION_GUARD_AREA)) {
Assign_Destination(TARGET_NONE);
if (!IsActive) return(false);
} else {
/*
** If a basic path could not be found, but the immediate move destination is
** blocked by a friendly temporary blockage, then cause that blockage
** to scatter.
*/
CELL cell = Adjacent_Cell(Coord_Cell(Center_Coord()), PrimaryFacing.Current());
if (Map.In_Radar(cell)) {
MoveType ok = Can_Enter_Cell(cell);
if (ok == MOVE_TEMP) {
CellClass * cellptr = &Map[cell];
TechnoClass * blockage = cellptr->Cell_Techno();
if (blockage && House->Is_Ally(blockage)) {
/*
** If the target can be told to get out of the way, only bother
** to do so if we aren't very close to the target and this
** object can just say "good enough" and stop here.
*/
if (Distance(NavCom) < Rule.CloseEnoughDistance && !In_Radio_Contact()) {
Assign_Destination(TARGET_NONE);
return(false);
} else {
cellptr->Incoming(0, true, false);
// cellptr->Incoming(0, true, true);
}
}
}
}
if (TryTryAgain > 0) {
TryTryAgain--;
} else {
Assign_Destination(TARGET_NONE);
if (!IsActive) return(false);
if (IsNewNavCom) Sound_Effect(VOC_SCOLD);
IsNewNavCom = false;
}
}
/*
** Since the path was blocked, check to make sure that it was completely
** blocked. If so and it has a valid TarCom and it is out of range of the
** TarCom, then give this unit a range limit so that it might not pick
** a "can't reach" target again.
*/
if (!Target_Legal(NavCom) && Target_Legal(TarCom) && !In_Range(TarCom)) {
IsScanLimited = true;
if (Team.Is_Valid()) Team->Scan_Limit();
Assign_Target(TARGET_NONE);
}
/*
** Stop the movement, for now, and let the subsequent logic in later game
** frames resume movement as appropriate.
*/
Stop_Driver();
TrackNumber = -1;
IsTurretLockedDown = false;
return(false);
}
/*
** If a basic path could be found, but the immediate move destination is
** blocked by a friendly temporary blockage, then cause that blockage
** to scatter.
*/
CELL cell = Adjacent_Cell(Coord_Cell(Center_Coord()), Path[0]);
if (Map.In_Radar(cell)) {
MoveType ok = Can_Enter_Cell(cell);
if (ok == MOVE_TEMP) {
CellClass * cellptr = &Map[cell];
TechnoClass * blockage = cellptr->Cell_Techno();
if (blockage && House->Is_Ally(blockage)) {
/*
** If the target can be told to get out of the way, only bother
** to do so if we aren't very close to the target and this
** object can just say "good enough" and stop here.
*/
if (Distance(NavCom) < Rule.CloseEnoughDistance && !In_Radio_Contact()) {
Assign_Destination(TARGET_NONE);
return(false);
} else {
cellptr->Incoming(0, true, false);
// cellptr->Incoming(0, true, true);
}
}
}
}
TryTryAgain = PATH_RETRY;
facing = Path[0];
}
/*
** Determine the coordinate of the next cell to move into.
*/
dest = Adjacent_Cell(Coord, facing);
dir = Facing_Dir(facing);
/*
** Set the facing correctly if it isn't already correct. This
** means starting a rotation track if necessary.
*/
facediff = PrimaryFacing.Difference(dir);
if (facediff) {
/*
** Request a change of facing.
*/
Do_Turn(dir);
return(true);
} else {
/* NOTE: Beyond this point, actual track assignment can begin.
**
** If the cell to move into is impassable (probably for some unexpected
** reason), then abort the path list and set the speed to zero. The
** next time this routine is called, a new path will be generated.
*/
destcell = Coord_Cell(dest);
Mark(MARK_UP);
MoveType cando = Can_Enter_Cell(destcell, facing);
Mark(MARK_DOWN);
if (cando != MOVE_OK) {
if (Mission == MISSION_MOVE /*KO&& House->IsHuman */&& Distance(NavCom) < Rule.CloseEnoughDistance) {
Assign_Destination(TARGET_NONE);
if (!IsActive) return(false);//BG
}
/*
** If a temporary friendly object is blocking the path, then cause it to
** get out of the way.
*/
if (cando == MOVE_TEMP) {
Map[destcell].Incoming(0, true, true);
}
/*
** If a cloaked object is blocking, then shimmer the cell.
*/
if (cando == MOVE_CLOAK) {
Map[destcell].Shimmer();
}
Stop_Driver();
if (cando != MOVE_MOVING_BLOCK) {
Path[0] = FACING_NONE; // Path is blocked!
}
/*
** If blocked by a moving block then just exit start of move and
** try again next tick.
*/
if (cando == MOVE_DESTROYABLE) {
if (Map[destcell].Cell_Object()) {
if (!House->Is_Ally(Map[destcell].Cell_Object())) {
Override_Mission(MISSION_ATTACK, Map[destcell].Cell_Object()->As_Target(), TARGET_NONE);
}
} else {
if (Map[destcell].Overlay != OVERLAY_NONE && OverlayTypeClass::As_Reference(Map[destcell].Overlay).IsWall) {
Override_Mission(MISSION_ATTACK, ::As_Target(destcell), TARGET_NONE);
}
}
} else {
if (IsNewNavCom) Sound_Effect(VOC_SCOLD);
}
IsNewNavCom = false;
TrackNumber = -1;
return(true);
}
/*
** Determine the speed that the unit can travel to the desired square.
*/
ground = Map[destcell].Land_Type();
speed = Ground[ground].Cost[Techno_Type_Class()->Speed] * 256;
/* change speed if it's related to a team move */
if (IsFormationMove) speed = Ground[ground].Cost[FormationSpeed] * 256;
if (!speed) speed = 128;
#ifdef NEVER
/*
** Set the jiggle flag if the terrain would cause the unit
** to jiggle when travelled over.
*/
BaseF &= ~BASEF_JIGGLE;
if (Ground[ground].Jiggle) {
BaseF |= BASEF_JIGGLE;
}
#endif
/*
** A damaged unit has a reduced speed.
*/
if (Health_Ratio() <= Rule.ConditionYellow /*(Techno_Type_Class()->MaxStrength>>1) > Strength*/) {
speed -= (speed/4); // Three quarters speed.
}
if ((speed != Speed)/* || !SpeedAdd*/) {
Set_Speed(speed); // Full speed.
}
/*
** Reserve the destination cell so that it won't become
** occupied AS this unit is moving into it.
*/
if (cando != MOVE_OK) {
Path[0] = FACING_NONE; // Path is blocked!
TrackNumber = -1;
dest = NULL;
} else {
Overrun_Square(Coord_Cell(dest), true);
/*
** Determine which track to use (based on recorded path).
*/
FacingType nextface = Path[1];
if (nextface == FACING_NONE) nextface = facing;
IsOnShortTrack = false;
TrackNumber = facing * FACING_COUNT + (int)nextface;
if (TrackControl[TrackNumber].Track == 0) {
Path[0] = FACING_NONE;
TrackNumber = -1;
return(true);
} else {
if (TrackControl[TrackNumber].Flag & F_D) {
/*
** If the middle cell of a two cell track contains a crate,
** the check for goodies before movement starts.
*/
if (!Map[destcell].Goodie_Check(this)) {
cando = MOVE_NO;
if (!IsActive) return(false);
} else {
if (!IsActive) return(false);
dest = Adjacent_Cell(dest, nextface);
destcell = Coord_Cell(dest);
cando = Can_Enter_Cell(destcell);
}
if (!IsActive) return(false);
if (cando != MOVE_OK) {
/*
** If a temporary friendly object is blocking the path, then cause it to
** get out of the way.
*/
if (cando == MOVE_TEMP) {
Map[destcell].Incoming(0, true, true);
}
/*
** If a cloaked object is blocking, then shimmer the cell.
*/
if (cando == MOVE_CLOAK) {
Map[destcell].Shimmer();
}
Path[0] = FACING_NONE; // Path is blocked!
TrackNumber = -1;
dest = NULL;
if (cando == MOVE_DESTROYABLE) {
if (Map[destcell].Cell_Object()) {
if (!House->Is_Ally(Map[destcell].Cell_Object())) {
Override_Mission(MISSION_ATTACK, Map[destcell].Cell_Object()->As_Target(), TARGET_NONE);
}
} else {
if (Map[destcell].Overlay != OVERLAY_NONE && OverlayTypeClass::As_Reference(Map[destcell].Overlay).IsWall) {
Override_Mission(MISSION_ATTACK, ::As_Target(destcell), TARGET_NONE);
}
}
IsNewNavCom = false;
TrackIndex = 0;
return(true);
}
} else {
memcpy((char*)&Path[0], (char*)&Path[2], CONQUER_PATH_MAX-2);
Path[CONQUER_PATH_MAX-2] = FACING_NONE;
IsPlanningToLook = true;
}
} else {
memcpy((char*)&Path[0], (char*)&Path[1], CONQUER_PATH_MAX-1);
}
Path[CONQUER_PATH_MAX-1] = FACING_NONE;
}
}
IsNewNavCom = false;
TrackIndex = 0;
if (!Start_Driver(dest)) {
TrackNumber = -1;
Path[0] = FACING_NONE;
Set_Speed(0);
}
}
return(false);
}
/***********************************************************************************************
* DriveClass::AI -- Processes unit movement and rotation. *
* *
* This routine is used to process unit movement and rotation. It *
* functions autonomously from the script system. Thus, once a unit *
* is give rotation command or movement path, it will follow this *
* until specifically instructed to stop. The advantage of this *
* method is that it allows smooth movement of units, faster game *
* execution, and reduced script complexity (since actual movement *
* dynamics need not be controlled directly by the scripts). *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: This routine relies on the process control bits for the *
* specified unit (for speed reasons). Thus, only setting *
* movement, rotation, or path list will the unit perform *
* any physics. *
* *
* HISTORY: *
* 09/26/1993 JLB : Created. *
* 04/15/1994 JLB : Converted to member function. *
*=============================================================================================*/
void DriveClass::AI(void)
{
assert(IsActive);
FootClass::AI();
if (!IsActive || Height > 0) return;
/*
** Is this a unit that's been teleported using the chronosphere, and if so,
** has his timer expired such that he needs to teleport back?
*/
if (IsMoebius) {
#ifdef FIXIT_CSII // checked - ajw 9/28/98
if (What_Am_I() != RTTI_UNIT || ((UnitClass *)this)->Class->Type != UNIT_CHRONOTANK) {
#endif
if (MoebiusCountDown == 0) {
IsMoebius = false;
Teleport_To(MoebiusCell);
MoebiusCell = 0;
}
#ifdef FIXIT_CSII // checked - ajw 9/28/98
}
#endif
}
/*
** If the unit is following a track, then continue
** to do so -- mindlessly.
*/
if (TrackNumber != -1) {
/*
** Perform the movement accumulation.
*/
While_Moving();
if (!IsActive) return;
if (TrackNumber == -1 && (Target_Legal(NavCom) || Path[0] != FACING_NONE) && (What_Am_I() != RTTI_UNIT || !((UnitClass*)this)->IsDumping)) {
Start_Of_Move();
if (!IsActive) return;
While_Moving();
if (!IsActive) return;
}
} else {
/*
** For tracked units that are rotating in place, perform the rotation now.
*/
#ifdef TOFIX
if ((Class->Speed == SPEED_FLOAT || Class->Speed == SPEED_HOVER || Class->Speed == SPEED_TRACK || (Class->Speed == SPEED_WHEEL && !Special.IsThreePoint)) && PrimaryFacing.Is_Rotating()) {
if (PrimaryFacing.Rotation_Adjust(Class->ROT)) {
Mark(MARK_CHANGE);
}
#else
if (PrimaryFacing.Is_Rotating()) {
Mark(MARK_CHANGE_REDRAW);
if (PrimaryFacing.Rotation_Adjust(Techno_Type_Class()->ROT * House->GroundspeedBias)) {
Mark(MARK_CHANGE_REDRAW);
}
#endif
if (!IsRotating) {
Per_Cell_Process(PCP_ROTATION);
if (!IsActive) return;
}
} else {
/*
** The unit has no track to follow, but if there
** is a navigation target or a remaining path,
** then start on a new track.
*/
if ((Mission != MISSION_GUARD || Target_Legal(NavCom)) && Mission != MISSION_UNLOAD) {
if (Target_Legal(NavCom) || Path[0] != FACING_NONE) {
/*
** Double check to make sure that the movement destination is
** in a zone that this unit can travel to. If not, then abort
** the navigation target.
*/
if (IsLocked && Mission != MISSION_ENTER && Target_Legal(NavCom) && !Is_In_Same_Zone(As_Cell(NavCom))) {
Stop_Driver();
Assign_Destination(TARGET_NONE);
} else {
Start_Of_Move();
if (!IsActive) return;
While_Moving();
if (!IsActive) return;
}
} else {
Stop_Driver();
}
}
}
}
}
/***********************************************************************************************
* DriveClass::Fixup_Path -- Adds smooth start path to normal movement path. *
* *
* This routine modifies the path of the specified unit so that it *
* will not start out with a rotation. This is necessary for those *
* vehicles that have difficulty with rotating in place. Typically, *
* this includes wheeled vehicles. *
* *
* INPUT: unit -- Pointer to the unit to adjust. *
* *
* path -- Pointer to path structure. *
* *
* OUTPUT: none *
* *
* WARNINGS: Only units that require a fixup get modified. The *
* modification only occurs, if there is a legal path to *
* do so. *
* *
* HISTORY: *
* 04/03/1994 JLB : Created. *
* 04/06/1994 JLB : Uses path structure. *
* 04/10/1994 JLB : Diagonal smooth turn added. *
* 04/15/1994 JLB : Converted to member function. *
*=============================================================================================*/
void DriveClass::Fixup_Path(PathType * path)
{
assert(IsActive);
FacingType stage[6]={FACING_N,FACING_N,FACING_N,FACING_N,FACING_N,FACING_N}; // Prefix path elements.
int facediff; // The facing difference value (0..4 | 0..-4).
static FacingType _path[4][6] = {
{(FacingType)2,(FacingType)0,(FacingType)2,(FacingType)0,(FacingType)0,(FacingType)0},
{(FacingType)3,(FacingType)0,(FacingType)2,(FacingType)2,(FacingType)0,(FacingType)0},
{(FacingType)4,(FacingType)0,(FacingType)2,(FacingType)2,(FacingType)0,(FacingType)0},
{(FacingType)4,(FacingType)0,(FacingType)2,(FacingType)2,(FacingType)1,(FacingType)0}
};
static FacingType _dpath[4][6] = {
{(FacingType)0,(FacingType)0,(FacingType)0,(FacingType)0,(FacingType)0,(FacingType)0},
{(FacingType)3,(FacingType)0,(FacingType)2,(FacingType)2,(FacingType)0,(FacingType)0},
{(FacingType)4,(FacingType)0,(FacingType)2,(FacingType)2,(FacingType)1,(FacingType)0},
{(FacingType)5,(FacingType)0,(FacingType)2,(FacingType)2,(FacingType)1,(FacingType)0}
};
int index;
int counter; // Path addition
FacingType * ptr; // Path list pointer.
FacingType * ptr2; // Copy of new path list pointer.
FacingType nextpath; // Next path value.
CELL cell; // Working cell value.
bool ok;
/*
** Verify that the unit is valid and there is a path problem to resolve.
*/
if (!path || path->Command[0] == FACING_NONE) {
return;
}
/*
** Only wheeled vehicles need a path fixup -- to avoid 3 point turns.
*/
#ifdef TOFIX
if (!Special.IsThreePoint || Class->Speed != SPEED_WHEEL) {
#else
if (What_Am_I() == RTTI_UNIT || What_Am_I() == RTTI_VESSEL) {
// if (What_Am_I() == RTTI_UNIT) {
#endif
return;
}
/*
** If the original path starts in the same direction as the unit, then
** there is no problem to resolve -- abort.
*/
facediff = PrimaryFacing.Difference((DirType)(path->Command[0]<<5)) >> 5;
if (!facediff) return;
if (Dir_Facing(PrimaryFacing) & FACING_NE) {
ptr = &_dpath[(FacingType)ABS((int)facediff)-FACING_NE][1]; // Pointer to path adjust list.
counter = (int)_dpath[(FacingType)ABS((int)facediff)-FACING_NE][0]; // Number of path adjusts.
} else {
ptr = &_path[(FacingType)ABS((int)facediff)-FACING_NE][1]; // Pointer to path adjust list.
counter = (int)_path[(FacingType)ABS((int)facediff)-FACING_NE][0]; // Number of path adjusts.
}
ptr2 = ptr;
ok = true; // Presume adjustment is all ok.
cell = Coord_Cell(Coord); // Starting cell.
nextpath = Dir_Facing(PrimaryFacing); // Starting path.
for (index = 0; index < counter; index++) {
/*
** Determine next path element and add it to the
** working path list.
*/
if (facediff > 0) {
nextpath = nextpath + *ptr++;
} else {
nextpath = nextpath - *ptr++;
}
stage[index] = nextpath;
cell = Adjacent_Cell(cell, nextpath);
//cell = Coord_Cell(Adjacent_Cell(Cell_Coord(cell), nextpath));
/*
** If it can't enter this cell, then abort the path
** building operation without adjusting the unit's
** path.
*/
if (Can_Enter_Cell(cell, nextpath) != MOVE_OK) {
ok = false;
break;
}
}
/*
** If veering to the left was not successful, then try veering
** to the right. This only makes sense if the vehicle is trying
** to turn 180 degrees.
*/
if (!ok && ABS(facediff) == 4) {
ptr = ptr2; // Pointer to path adjust list.
facediff = -facediff;
ok = true; // Presume adjustment is all ok.
cell = Coord_Cell(Coord); // Starting cell.
nextpath = Dir_Facing(PrimaryFacing); // Starting path.
for (index = 0; index < counter; index++) {
/*
** Determine next path element and add it to the
** working path list.
*/
if (facediff > 0) {
nextpath = nextpath + *ptr++;
} else {
nextpath = nextpath - *ptr++;
}
stage[index] = nextpath;
cell = Coord_Cell(Adjacent_Cell(Cell_Coord(cell), nextpath));
/*
** If it can't enter this cell, then abort the path
** building operation without adjusting the unit's
** path.
*/
if (Can_Enter_Cell(cell, nextpath) != MOVE_OK) {
ok = false;
break;
}
}
}
/*
** If a legal path addition was created, then install it in place
** of the first path value. The initial path entry is to be replaced
** with a sequence of path entries that create smooth turning.
*/
if (ok) {
if (path->Length <= 1) {
memmove((char *)&stage[0], (char*)path->Command, max(counter, 1));
path->Length = counter;
} else {
/*
** Optimize the transition path step from the smooth turn
** first part as it joins with the rest of the normal
** path. The normal prefix path steps are NOT to be optimized.
*/
if (counter) {
counter--;
path->Command[0] = stage[counter];
Optimize_Moves(path, MOVE_OK);
}
/*
** If there is more than one prefix path element, then
** insert the rest now.
*/
if (counter) {
memmove((char*)&path->Command[0], (char*)&path->Command[counter], 40-counter);
memmove((char*)&stage[0], (char*)&path->Command[0], counter);
path->Length += counter;
}
}
path->Command[path->Length] = FACING_NONE;
}
}
/***********************************************************************************************
* DriveClass::Lay_Track -- Handles track laying logic for the unit. *
* *
* This routine handles the track laying for the unit. This entails examining the unit's *
* current location as well as the direction and whether this unit is allowed to lay *
* tracks in the first place. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/28/1994 JLB : Created. *
*=============================================================================================*/
void DriveClass::Lay_Track(void)
{
assert(IsActive);
#ifdef NEVER
static IconCommandType * _trackdirs[8] = {
TrackN_S,
TrackNE_SW,
TrackE_W,
TrackNW_SE,
TrackN_S,
TrackNE_SW,
TrackE_W,
TrackNW_SE
};
if (!(ClassF & CLASSF_TRACKS)) return;
Icon_Install(Coord_Cell(Coord), _trackdirs[Facing_To_8(BodyFacing)]);
#endif
}
/***********************************************************************************************
* DriveClass::Mark_Track -- Marks the midpoint of the track as occupied. *
* *
* This routine will ensure that the midpoint (if any) of the track that the unit is *
* following, will be marked according to the mark type specified. *
* *
* INPUT: headto -- The head to coordinate. *
* *
* type -- The type of marking to perform. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/30/1995 JLB : Created. *
*=============================================================================================*/
void DriveClass::Mark_Track(COORDINATE headto, MarkType type)
{
assert(IsActive);
int value;
if (type == MARK_UP) {
value = false;
} else {
value = true;
}
if (headto) {
if (!IsOnShortTrack && TrackNumber != -1) {
/*
** If we have not passed the per cell process point we need
** to deal with it.
*/
int tracknum = TrackControl[TrackNumber].Track;
if (tracknum) {
TrackType const * ptr = RawTracks[tracknum - 1].Track;
int cellidx = RawTracks[tracknum - 1].Cell;
if (cellidx > -1) {
DirType dir = ptr[cellidx].Facing;
if (TrackIndex < cellidx && cellidx != -1) {
COORDINATE offset = Smooth_Turn(ptr[cellidx].Offset, dir);
Map[offset].Flag.Occupy.Vehicle = value;
}
}
}
}
Map[headto].Flag.Occupy.Vehicle = value;
}
}
/***********************************************************************************************
* DriveClass::Ok_To_Move -- Checks to see if this object can begin moving. *
* *
* This routine is used to verify that this object is allowed to move. Some objects can *
* be temporarily occupied and thus cannot move until the situation permits. *
* *
* INPUT: direction -- The direction that movement would be desired. *
* *
* OUTPUT: Can the unit move in the direction specified? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/29/1995 JLB : Created. *
*=============================================================================================*/
bool DriveClass::Ok_To_Move(DirType ) const
{
assert(IsActive);
return true;
}
/***************************************************************************
** Smooth turn track tables. These are coordinate offsets from the center
** of the destination cell. These are the raw tracks that are modified
** by negating the X and Y portions as necessary. Also for reverse travelling
** direction, the track list can be processed backward.
**
** Track 1 = N
** Track 2 = NE
** Track 3 = N->NE 45 deg (double path consumption)
** Track 4 = N->E 90 deg (double path consumption)
** Track 5 = NE->SE 90 deg (double path consumption)
** Track 6 = NE->N 45 deg (double path consumption)
** Track 7 = N->NE (facing change only)
** Track 8 = NE->E (facing change only)
** Track 9 = N->E (facing change only)
** Track 10= NE->SE (facing change only)
** Track 11= back up into refinery
** Track 12= drive out of refinery
*/
#pragma warn -ias
DriveClass::TrackType const DriveClass::Track1[24] = {
{0x00F50000L,(DirType)0},
{0x00EA0000L,(DirType)0},
{0x00DF0000L,(DirType)0},
{0x00D40000L,(DirType)0},
{0x00C90000L,(DirType)0},
{0x00BE0000L,(DirType)0},
{0x00B30000L,(DirType)0},
{0x00A80000L,(DirType)0},
{0x009D0000L,(DirType)0},
{0x00920000L,(DirType)0},
{0x00870000L,(DirType)0},
{0x007C0000L,(DirType)0}, // Track jump check here.
{0x00710000L,(DirType)0},
{0x00660000L,(DirType)0},
{0x005B0000L,(DirType)0},
{0x00500000L,(DirType)0},
{0x00450000L,(DirType)0},
{0x003A0000L,(DirType)0},
{0x002F0000L,(DirType)0},
{0x00240000L,(DirType)0},
{0x00190000L,(DirType)0},
{0x000E0000L,(DirType)0},
{0x00030000L,(DirType)0},
{0x00000000L,(DirType)0}
};
DriveClass::TrackType const DriveClass::Track2[] = {
{0x00F8FF08L,(DirType)32},
{0x00F0FF10L,(DirType)32},
{0x00E8FF18L,(DirType)32},
{0x00E0FF20L,(DirType)32},
{0x00D8FF28L,(DirType)32},
{0x00D0FF30L,(DirType)32},
{0x00C8FF38L,(DirType)32},
{0x00C0FF40L,(DirType)32},
{0x00B8FF48L,(DirType)32},
{0x00B0FF50L,(DirType)32},
{0x00A8FF58L,(DirType)32},
{0x00A0FF60L,(DirType)32},
{0x0098FF68L,(DirType)32},
{0x0090FF70L,(DirType)32},
{0x0088FF78L,(DirType)32},
{0x0080FF80L,(DirType)32}, // Track jump check here.
{0x0078FF88L,(DirType)32},
{0x0070FF90L,(DirType)32},
{0x0068FF98L,(DirType)32},
{0x0060FFA0L,(DirType)32},
{0x0058FFA8L,(DirType)32},
{0x0050FFB0L,(DirType)32},
{0x0048FFB8L,(DirType)32},
{0x0040FFC0L,(DirType)32},
{0x0038FFC8L,(DirType)32},
{0x0030FFD0L,(DirType)32},
{0x0028FFD8L,(DirType)32},
{0x0020FFE0L,(DirType)32},
{0x0018FFE8L,(DirType)32},
{0x0010FFF0L,(DirType)32},
{0x0008FFF8L,(DirType)32},
{0x00000000L,(DirType)32}
};
DriveClass::TrackType const DriveClass::Track3[] = {
{0x01F5FF00L,(DirType)0},
{0x01EAFF00L,(DirType)0},
{0x01DFFF00L,(DirType)0},
{0x01D4FF00L,(DirType)0},
{0x01C9FF00L,(DirType)0},
{0x01BEFF00L,(DirType)0},
{0x01B3FF00L,(DirType)0},
{0x01A8FF00L,(DirType)0},
{0x019DFF00L,(DirType)0},
{0x0192FF00L,(DirType)0},
{0x0187FF00L,(DirType)0},
{0x0180FF00L,(DirType)0},
{0x0175FF00L,(DirType)0}, // Jump entry point here.
{0x016BFF00L,(DirType)0},
{0x0160FF02L,(DirType)1},
{0x0155FF04L,(DirType)3},
{0x014CFF06L,(DirType)4},
{0x0141FF08L,(DirType)5},
{0x0137FF0BL,(DirType)7},
{0x012EFF0FL,(DirType)8},
{0x0124FF13L,(DirType)9},
{0x011AFF17L,(DirType)11},
{0x0110FF1BL,(DirType)12},
{0x0107FF1FL,(DirType)13}, // Center cell processing here.
{0x00FCFF24L,(DirType)15},
{0x00F3FF28L,(DirType)16},
{0x00ECFF2CL,(DirType)17},
{0x00E0FF32L,(DirType)19},
{0x00D7FF36L,(DirType)20},
{0x00CFFF3DL,(DirType)21},
{0x00C6FF42L,(DirType)23},
{0x00BAFF49L,(DirType)24},
{0x00B0FF4DL,(DirType)25},
{0x00A8FF58L,(DirType)27},
{0x00A0FF60L,(DirType)28},
{0x0098FF68L,(DirType)29},
{0x0090FF70L,(DirType)31},
{0x0088FF78L,(DirType)32},
{0x0080FF80L,(DirType)32}, // Track jump check here.
{0x0078FF88L,(DirType)32},
{0x0070FF90L,(DirType)32},
{0x0068FF98L,(DirType)32},
{0x0060FFA0L,(DirType)32},
{0x0058FFA8L,(DirType)32},
{0x0050FFB0L,(DirType)32},
{0x0048FFB8L,(DirType)32},
{0x0040FFC0L,(DirType)32},
{0x0038FFC8L,(DirType)32},
{0x0030FFD0L,(DirType)32},
{0x0028FFD8L,(DirType)32},
{0x0020FFE0L,(DirType)32},
{0x0018FFE8L,(DirType)32},
{0x0010FFF0L,(DirType)32},
{0x0008FFF8L,(DirType)32},
{0x00000000L,(DirType)32}
};
DriveClass::TrackType const DriveClass::Track4[] = {
{0x00F5FF00L,(DirType)0},
{0x00EBFF00L,(DirType)0},
{0x00E0FF00L,(DirType)0},
{0x00D5FF00L,(DirType)0},
{0x00CBFF01L,(DirType)0},
{0x00C0FF03L,(DirType)0},
{0x00B5FF05L,(DirType)1},
{0x00ABFF07L,(DirType)1},
{0x00A0FF0AL,(DirType)2},
{0x0095FF0DL,(DirType)3},
{0x008BFF10L,(DirType)4},
{0x0080FF14L,(DirType)5}, // Track entry here.
{0x0075FF18L,(DirType)8},
{0x006DFF1CL,(DirType)12},
{0x0063FF22L,(DirType)16},
{0x005AFF25L,(DirType)20},
{0x0052FF2BL,(DirType)23},
{0x0048FF32L,(DirType)27},
{0x0040FF37L,(DirType)32},
{0x0038FF3DL,(DirType)36},
{0x0030FF46L,(DirType)39},
{0x002BFF4FL,(DirType)43},
{0x0024FF58L,(DirType)47},
{0x0020FF60L,(DirType)51},
{0x001BFF6DL,(DirType)54},
{0x0017FF79L,(DirType)57},
{0x0014FF82L,(DirType)60}, // Track jump here.
{0x0011FF8FL,(DirType)62},
{0x000DFF98L,(DirType)63},
{0x0009FFA2L,(DirType)64},
{0x0006FFACL,(DirType)64},
{0x0004FFB5L,(DirType)66},
{0x0003FFC0L,(DirType)64},
{0x0002FFCBL,(DirType)64},
{0x0001FFD5L,(DirType)64},
{0x0000FFE0L,(DirType)64},
{0x0000FFEBL,(DirType)64},
{0x0000FFF5L,(DirType)64},
{0x00000000L,(DirType)64}
};
DriveClass::TrackType const DriveClass::Track5[] = {
{0xFFF8FE08L,(DirType)32},
{0xFFF0FE10L,(DirType)32},
{0xFFE8FE18L,(DirType)32},
{0xFFE0FE20L,(DirType)32},
{0xFFD8FE28L,(DirType)32},
{0xFFD0FE30L,(DirType)32},
{0xFFC8FE38L,(DirType)32},
{0xFFC0FE40L,(DirType)32},
{0xFFB8FE48L,(DirType)32},
{0xFFB0FE50L,(DirType)32},
{0xFFA8FE58L,(DirType)32},
{0xFFA0FE60L,(DirType)32},
{0xFF98FE68L,(DirType)32},
{0xFF90FE70L,(DirType)32},
{0xFF88FE78L,(DirType)32},
{0xFF80FE80L,(DirType)32}, // Track entry here.
{0xFF78FE88L,(DirType)32},
{0xFF71FE90L,(DirType)32},
{0xFF6AFE97L,(DirType)32},
{0xFF62FE9FL,(DirType)32},
{0xFF5AFEA8L,(DirType)32},
{0xFF53FEB0L,(DirType)35},
{0xFF4BFEB7L,(DirType)38},
{0xFF44FEBEL,(DirType)41},
{0xFF3EFEC4L,(DirType)44},
{0xFF39FECEL,(DirType)47},
{0xFF34FED8L,(DirType)50},
{0xFF30FEE0L,(DirType)53},
{0xFF2DFEEBL,(DirType)56},
{0xFF2CFEF5L,(DirType)59},
{0xFF2BFF00L,(DirType)62},
{0xFF2CFF0BL,(DirType)66},
{0xFF2DFF15L,(DirType)69},
{0xFF30FF1FL,(DirType)72},
{0xFF34FF28L,(DirType)75},
{0xFF39FF30L,(DirType)78},
{0xFF3EFF3AL,(DirType)81},
{0xFF44FF44L,(DirType)84},
{0xFF4BFF4BL,(DirType)87},
{0xFF53FF50L,(DirType)90},
{0xFF5AFF58L,(DirType)93},
{0xFF62FF60L,(DirType)96},
{0xFF6AFF68L,(DirType)96},
{0xFF71FF70L,(DirType)96},
{0xFF78FF78L,(DirType)96},
{0xFF80FF80L,(DirType)96}, // Track jump check here.
{0xFF88FF88L,(DirType)96},
{0xFF90FF90L,(DirType)96},
{0xFF98FF98L,(DirType)96},
{0xFFA0FFA0L,(DirType)96},
{0xFFA8FFA8L,(DirType)96},
{0xFFB0FFB0L,(DirType)96},
{0xFFB8FFB8L,(DirType)96},
{0xFFC0FFC0L,(DirType)96},
{0xFFC8FFC8L,(DirType)96},
{0xFFD0FFD0L,(DirType)96},
{0xFFD8FFD8L,(DirType)96},
{0xFFE0FFE0L,(DirType)96},
{0xFFE8FFE8L,(DirType)96},
{0xFFF0FFF0L,(DirType)96},
{0xFFF8FFF8L,(DirType)96},
{0x00000000L,(DirType)96}
};
DriveClass::TrackType const DriveClass::Track6[] = {
{0x0100FE00L,(DirType)32},
{0x00F8FE08L,(DirType)32},
{0x00F0FE10L,(DirType)32},
{0x00E8FE18L,(DirType)32},
{0x00E0FE20L,(DirType)32},
{0x00D8FE28L,(DirType)32},
{0x00D0FE30L,(DirType)32},
{0x00C8FE38L,(DirType)32},
{0x00C0FE40L,(DirType)32},
{0x00B8FE48L,(DirType)32},
{0x00B0FE50L,(DirType)32},
{0x00A8FE58L,(DirType)32},
{0x00A0FE60L,(DirType)32},
{0x0098FE68L,(DirType)32},
{0x0090FE70L,(DirType)32},
{0x0088FE78L,(DirType)32},
{0x0080FE80L,(DirType)32}, // Jump entry point here.
{0x0078FE88L,(DirType)32},
{0x0070FE90L,(DirType)32},
{0x0068FE98L,(DirType)32},
{0x0060FEA0L,(DirType)32},
{0x0058FEA8L,(DirType)32},
{0x0055FEAEL,(DirType)32},
{0x004EFEB8L,(DirType)35},
{0x0048FEC0L,(DirType)37},
{0x0042FEC9L,(DirType)40},
{0x003BFED2L,(DirType)43},
{0x0037FEDAL,(DirType)45},
{0x0032FEE3L,(DirType)48},
{0x002BFEEBL,(DirType)51},
{0x0026FEF5L,(DirType)53},
{0x0022FEFEL,(DirType)56},
{0x001CFF08L,(DirType)59},
{0x0019FF12L,(DirType)61},
{0x0015FF1BL,(DirType)64},
{0x0011FF26L,(DirType)64},
{0x000EFF30L,(DirType)64},
{0x000BFF39L,(DirType)64},
{0x0009FF43L,(DirType)64},
{0x0007FF4EL,(DirType)64},
{0x0005FF57L,(DirType)64},
{0x0003FF62L,(DirType)64},
{0x0001FF6DL,(DirType)64},
{0x0000FF77L,(DirType)64},
{0x0000FF80L,(DirType)64}, // Track jump check here.
{0x0000FF8BL,(DirType)64},
{0x0000FF95L,(DirType)64},
{0x0000FFA0L,(DirType)64},
{0x0000FFABL,(DirType)64},
{0x0000FFB5L,(DirType)64},
{0x0000FFC0L,(DirType)64},
{0x0000FFCBL,(DirType)64},
{0x0000FFD5L,(DirType)64},
{0x0000FFE0L,(DirType)64},
{0x0000FFEBL,(DirType)64},
{0x0000FFF5L,(DirType)64},
{0x00000000L,(DirType)64}
};
DriveClass::TrackType const DriveClass::Track7[] = {
{0x0006FFFFL,(DirType)0},
{0x000CFFFEL,(DirType)4},
{0x0011FFFCL,(DirType)8},
{0x0018FFFAL,(DirType)12},
{0x001FFFF6L,(DirType)16},
{0x0024FFF3L,(DirType)19},
{0x002BFFF0L,(DirType)22},
{0x0030FFFDL,(DirType)23},
{0x0035FFEBL,(DirType)24},
{0x0038FFE8L,(DirType)25},
{0x003CFFE6L,(DirType)26},
{0x0040FFE3L,(DirType)27},
{0x0043FFE0L,(DirType)28},
{0x0046FFDDL,(DirType)29},
{0x0043FFDFL,(DirType)30},
{0x0040FFE1L,(DirType)30},
{0x003CFFE3L,(DirType)30},
{0x0038FFE5L,(DirType)30},
{0x0035FFE7L,(DirType)31},
{0x0030FFE9L,(DirType)31},
{0x002BFFEBL,(DirType)31},
{0x0024FFEDL,(DirType)31},
{0x001FFFF1L,(DirType)31},
{0x0018FFF4L,(DirType)32},
{0x0011FFF7L,(DirType)32},
{0x000CFFFAL,(DirType)32},
{0x0006FFFDL,(DirType)32},
{0x00000000L,(DirType)32}
};
DriveClass::TrackType const DriveClass::Track8[] = {
{0x0003FFFCL,(DirType)32},
{0x0006FFF7L,(DirType)36},
{0x000AFFF1L,(DirType)40},
{0x000CFFEBL,(DirType)44},
{0x000DFFE4L,(DirType)46},
{0x000EFFDCL,(DirType)48},
{0x000FFFD5L,(DirType)50},
{0x0010FFD0L,(DirType)52},
{0x0011FFC9L,(DirType)54},
{0x0012FFC2L,(DirType)56},
{0x0011FFC0L,(DirType)58},
{0x0010FFC2L,(DirType)60},
{0x000EFFC9L,(DirType)62},
{0x000CFFCFL,(DirType)64},
{0x000AFFD5L,(DirType)64},
{0x0008FFDAL,(DirType)64},
{0x0006FFE2L,(DirType)64},
{0x0004FFE9L,(DirType)64},
{0x0002FFEFL,(DirType)64},
{0x0001FFF5L,(DirType)64},
{0x0000FFF9L,(DirType)64},
{0x00000000L,(DirType)64}
};
DriveClass::TrackType const DriveClass::Track9[] = {
{0xFFF50002L,(DirType)0},
{0xFFEB0004L,(DirType)2},
{0xFFE00006L,(DirType)4},
{0xFFD50009L,(DirType)6},
{0xFFCE000CL,(DirType)9},
{0xFFC8000FL,(DirType)11},
{0xFFC00012L,(DirType)13},
{0xFFB80015L,(DirType)16},
{0xFFC00012L,(DirType)18},
{0xFFC8000EL,(DirType)20},
{0xFFCE000AL,(DirType)22},
{0xFFD50004L,(DirType)24},
{0xFFDE0000L,(DirType)26},
{0xFFE9FFF8L,(DirType)28},
{0xFFEEFFF2L,(DirType)30},
{0xFFF5FFEBL,(DirType)32},
{0xFFFDFFE1L,(DirType)34},
{0x0002FFD8L,(DirType)36},
{0x0007FFD2L,(DirType)39},
{0x000BFFCBL,(DirType)41},
{0x0010FFC5L,(DirType)43},
{0x0013FFBEL,(DirType)45},
{0x0015FFB7L,(DirType)48},
{0x0013FFBEL,(DirType)50},
{0x0011FFC5L,(DirType)52},
{0x000BFFCCL,(DirType)54},
{0x0008FFD4L,(DirType)56},
{0x0005FFDFL,(DirType)58},
{0x0003FFEBL,(DirType)62},
{0x0001FFF5L,(DirType)64},
{0x00000000L,(DirType)64}
};
DriveClass::TrackType const DriveClass::Track10[] = {
{0xFFF6000BL,(DirType)32},
{0xFFF00015L,(DirType)37},
{0xFFEB0020L,(DirType)42},
{0xFFE9002BL,(DirType)47},
{0xFFE50032L,(DirType)52},
{0xFFE30038L,(DirType)57},
{0xFFE00040L,(DirType)60},
{0xFFE20038L,(DirType)62},
{0xFFE40032L,(DirType)64},
{0xFFE5002AL,(DirType)68},
{0xFFE6001EL,(DirType)70},
{0xFFE70015L,(DirType)72},
{0xFFE8000BL,(DirType)74},
{0xFFE90000L,(DirType)76},
{0xFFE8FFF5L,(DirType)78},
{0xFFE7FFEBL,(DirType)80},
{0xFFE6FFE0L,(DirType)82},
{0xFFE5FFD5L,(DirType)84},
{0xFFE4FFCEL,(DirType)86},
{0xFFE2FFC5L,(DirType)88},
{0xFFE0FFC0L,(DirType)90},
{0xFFE3FFC5L,(DirType)92},
{0xFFE5FFCEL,(DirType)94},
{0xFFE9FFD5L,(DirType)95},
{0xFFEBFFE0L,(DirType)96},
{0xFFF0FFEBL,(DirType)96},
{0xFFF6FFF5L,(DirType)96},
{0x00000000L,(DirType)96}
};
DriveClass::TrackType const DriveClass::Track11[] = {
{0x01000000L,DIR_SW},
{0x00F30008L,DIR_SW},
{0x00E50010L,DIR_SW_X1},
{0x00D60018L,DIR_SW_X1},
{0x00C80020L,DIR_SW_X1},
{0x00B90028L,DIR_SW_X1},
{0x00AB0030L,DIR_SW_X2},
{0x009C0038L,DIR_SW_X2},
{0x008D0040L,DIR_SW_X2},
{0x007F0048L,DIR_SW_X2},
{0x00710050L,DIR_SW_X2},
{0x00640058L,DIR_SW_X2},
{0x00550060L,DIR_SW_X2},
{0x00000000L,DIR_SW_X2}
};
DriveClass::TrackType const DriveClass::Track12[] = {
{0xFF550060L,DIR_SW_X2},
{0xFF640058L,DIR_SW_X2},
{0xFF710050L,DIR_SW_X2},
{0xFF7F0048L,DIR_SW_X2},
{0xFF8D0040L,DIR_SW_X2},
{0xFF9C0038L,DIR_SW_X2},
{0xFFAB0030L,DIR_SW_X2},
{0xFFB90028L,DIR_SW_X1},
{0xFFC80020L,DIR_SW_X1},
{0xFFD60018L,DIR_SW_X1},
{0xFFE50010L,DIR_SW_X1},
{0xFFF30008L,DIR_SW},
{0x00000000L,DIR_SW}
};
#if(1)
/*
** Drive out of weapon's factory.
*/
DriveClass::TrackType const DriveClass::Track13[] = {
{XYP_COORD(0,-35),DIR_S},
{XYP_COORD(0,-34),DIR_S},
{XYP_COORD(0,-33),DIR_S},
{XYP_COORD(0,-32),DIR_S},
{XYP_COORD(0,-31),DIR_S},
{XYP_COORD(0,-30),DIR_S},
{XYP_COORD(0,-29),DIR_S},
{XYP_COORD(0,-28),DIR_S},
{XYP_COORD(0,-27),DIR_S},
{XYP_COORD(0,-26),DIR_S},
{XYP_COORD(0,-25),DIR_S},
{XYP_COORD(0,-24),DIR_S},
{XYP_COORD(0,-23),DIR_S},
{XYP_COORD(0,-22),DIR_S},
{XYP_COORD(0,-21),DIR_S},
{XYP_COORD(0,-20),DIR_S},
{XYP_COORD(0,-19),DIR_S},
{XYP_COORD(0,-18),DIR_S},
{XYP_COORD(0,-17),DIR_S},
{XYP_COORD(0,-16),DIR_S},
{XYP_COORD(0,-15),DIR_S},
{XYP_COORD(0,-14),DIR_S},
{XYP_COORD(0,-13),DIR_S},
{XYP_COORD(0,-12),DIR_S},
{XYP_COORD(0,-11),DIR_S},
{XYP_COORD(0,-10),DIR_S},
{XYP_COORD(0,-9),DIR_S},
{XYP_COORD(0,-8),DIR_S},
{XYP_COORD(0,-7),DIR_S},
{XYP_COORD(0,-6),DIR_S},
{XYP_COORD(0,-5),DIR_S},
{XYP_COORD(0,-4),DIR_S},
{XYP_COORD(0,-3),DIR_S},
{XYP_COORD(0,-2),DIR_S},
{XYP_COORD(0,-1),DIR_S},
{0x00000000L,DIR_S}
};
#else
/*
** Drive out of weapon's factory.
*/
DriveClass::TrackType const DriveClass::Track13[] = {
{XYP_COORD(10,-21),(DirType)(DIR_SW-10)},
{XYP_COORD(10,-21),(DirType)(DIR_SW-10)},
{XYP_COORD(10,-20),(DirType)(DIR_SW-10)},
{XYP_COORD(10,-20),(DirType)(DIR_SW-10)},
{XYP_COORD(9,-18),(DirType)(DIR_SW-10)},
{XYP_COORD(9,-18),(DirType)(DIR_SW-10)},
{XYP_COORD(9,-17),(DirType)(DIR_SW-10)},
{XYP_COORD(8,-16),(DirType)(DIR_SW-10)},
{XYP_COORD(8,-15),(DirType)(DIR_SW-10)},
{XYP_COORD(7,-14),(DirType)(DIR_SW-10)},
{XYP_COORD(7,-13),(DirType)(DIR_SW-10)},
{XYP_COORD(6,-12),(DirType)(DIR_SW-10)},
{XYP_COORD(6,-11),(DirType)(DIR_SW-10)},
{XYP_COORD(5,-10),(DirType)(DIR_SW-10)},
{XYP_COORD(5,-9),(DirType)(DIR_SW-10)},
{XYP_COORD(4,-8),(DirType)(DIR_SW-10)},
{XYP_COORD(4,-7),(DirType)(DIR_SW-10)},
{XYP_COORD(3,-6),(DirType)(DIR_SW-10)},
{XYP_COORD(3,-5),(DirType)(DIR_SW-9)},
{XYP_COORD(2,-4),(DirType)(DIR_SW-7)},
{XYP_COORD(2,-3),(DirType)(DIR_SW-5)},
{XYP_COORD(1,-2),(DirType)(DIR_SW-3)},
{XYP_COORD(1,-1),(DirType)(DIR_SW-1)},
{0x00000000L,DIR_SW}
};
#endif
/*
** There are a limited basic number of tracks that a vehicle can follow. These
** are they. Each track can be interpreted differently but this is controlled
** by the TrackControl structure elaborated elsewhere.
*/
DriveClass::RawTrackType const DriveClass::RawTracks[13] = {
{Track1, -1, 0, -1},
{Track2, -1, 0, -1},
{Track3, 37, 12, 22},
{Track4, 26, 11, 19},
{Track5, 45, 15, 31},
{Track6, 44, 16, 27},
{Track7, -1, 0, -1},
{Track8, -1, 0, -1},
{Track9, -1, 0, -1},
{Track10, -1, 0, -1},
{Track11, -1, 0, -1},
{Track12, -1, 0, -1},
{Track13, -1, 0, -1}
};
/***************************************************************************
** Smooth turning control table. Given two directions in a path list, this
** table determines which track to use and what modifying operations need
** be performed on the track data.
*/
DriveClass::TurnTrackType const DriveClass::TrackControl[67] = {
{1, 0, DIR_N, F_}, // 0-0
{3, 7, DIR_NE, F_D}, // 0-1 (raw chart)
{4, 9, DIR_E, F_D}, // 0-2 (raw chart)
{0, 0, DIR_SE, F_}, // 0-3 !
{0, 0, DIR_S, F_}, // 0-4 !
{0, 0, DIR_SW, F_}, // 0-5 !
{4, 9, DIR_W, (DriveClass::TrackControlType)(F_X|F_D)}, // 0-6
{3, 7, DIR_NW, (DriveClass::TrackControlType)(F_X|F_D)}, // 0-7
{6, 8, DIR_N, (DriveClass::TrackControlType)(F_T|F_X|F_Y|F_D)}, // 1-0
{2, 0, DIR_NE, F_}, // 1-1 (raw chart)
{6, 8, DIR_E, F_D}, // 1-2 (raw chart)
{5, 10, DIR_SE, F_D}, // 1-3 (raw chart)
{0, 0, DIR_S, F_}, // 1-4 !
{0, 0, DIR_SW, F_}, // 1-5 !
{0, 0, DIR_W, F_}, // 1-6 !
{5, 10, DIR_NW, (DriveClass::TrackControlType)(F_T|F_X|F_Y|F_D)}, // 1-7
{4, 9, DIR_N, (DriveClass::TrackControlType)(F_T|F_X|F_Y|F_D)}, // 2-0
{3, 7, DIR_NE, (DriveClass::TrackControlType)(F_T|F_X|F_Y|F_D)}, // 2-1
{1, 0, DIR_E, (DriveClass::TrackControlType)(F_T|F_X)}, // 2-2
{3, 7, DIR_SE, (DriveClass::TrackControlType)(F_T|F_X|F_D)}, // 2-3
{4, 9, DIR_S, (DriveClass::TrackControlType)(F_T|F_X|F_D)}, // 2-4
{0, 0, DIR_SW, F_}, // 2-5 !
{0, 0, DIR_W, F_}, // 2-6 !
{0, 0, DIR_NW, F_}, // 2-7 !
{0, 0, DIR_N, F_}, // 3-0 !
{5, 10, DIR_NE, (DriveClass::TrackControlType)(F_Y|F_D)}, // 3-1
{6, 8, DIR_E, (DriveClass::TrackControlType)(F_Y|F_D)}, // 3-2
{2, 0, DIR_SE, F_Y}, // 3-3
{6, 8, DIR_S, (DriveClass::TrackControlType)(F_T|F_X|F_D)}, // 3-4
{5, 10, DIR_SW, (DriveClass::TrackControlType)(F_T|F_X|F_D)}, // 3-5
{0, 0, DIR_W, F_}, // 3-6 !
{0, 0, DIR_NW, F_}, // 3-7 !
{0, 0, DIR_N, F_}, // 4-0 !
{0, 0, DIR_NE, F_}, // 4-1 !
{4, 9, DIR_E, (DriveClass::TrackControlType)(F_Y|F_D)}, // 4-2
{3, 7, DIR_SE, (DriveClass::TrackControlType)(F_Y|F_D)}, // 4-3
{1, 0, DIR_S, F_Y}, // 4-4
{3, 7, DIR_SW, (DriveClass::TrackControlType)(F_X|F_Y|F_D)}, // 4-5
{4, 9, DIR_W, (DriveClass::TrackControlType)(F_X|F_Y|F_D)}, // 4-6
{0, 0, DIR_NW, F_}, // 4-7 !
{0, 0, DIR_N, F_}, // 5-0 !
{0, 0, DIR_NE, F_}, // 5-1 !
{0, 0, DIR_E, F_}, // 5-2 !
{5, 10, DIR_SE, (DriveClass::TrackControlType)(F_T|F_D)}, // 5-3
{6, 8, DIR_S, (DriveClass::TrackControlType)(F_T|F_D)}, // 5-4
{2, 0, DIR_SW, F_T}, // 5-5
{6, 8, DIR_W, (DriveClass::TrackControlType)(F_X|F_Y|F_D)}, // 5-6
{5, 10, DIR_NW, (DriveClass::TrackControlType)(F_X|F_Y|F_D)}, // 5-7
{4, 9, DIR_N, (DriveClass::TrackControlType)(F_T|F_Y|F_D)}, // 6-0
{0, 0, DIR_NE, F_}, // 6-1 !
{0, 0, DIR_E, F_}, // 6-2 !
{0, 0, DIR_SE, F_}, // 6-3 !
{4, 9, DIR_S, (DriveClass::TrackControlType)(F_T|F_D)}, // 6-4
{3, 7, DIR_SW, (DriveClass::TrackControlType)(F_T|F_D)}, // 6-5
{1, 0, DIR_W, F_T}, // 6-6
{3, 7, DIR_NW, (DriveClass::TrackControlType)(F_T|F_Y|F_D)}, // 6-7
{6, 8, DIR_N, (DriveClass::TrackControlType)(F_T|F_Y|F_D)}, // 7-0
{5, 10, DIR_NE, (DriveClass::TrackControlType)(F_T|F_Y|F_D)}, // 7-1
{0, 0, DIR_E, F_}, // 7-2 !
{0, 0, DIR_SE, F_}, // 7-3 !
{0, 0, DIR_S, F_}, // 7-4 !
{5, 10, DIR_SW, (DriveClass::TrackControlType)(F_X|F_D)}, // 7-5
{6, 8, DIR_W, (DriveClass::TrackControlType)(F_X|F_D)}, // 7-6
{2, 0, DIR_NW, F_X}, // 7-7
{11, 11, DIR_SW, F_}, // Backup harvester into refinery.
{12, 12, DIR_SW_X2, F_}, // Drive back into refinery.
{13, 13, DIR_SW, F_} // Drive out of weapons factory.
};
================================================
FILE: CODE/DRIVE.H
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/DRIVE.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 : DRIVE.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : April 14, 1994 *
* *
* Last Update : April 14, 1994 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef DRIVE_H
#define DRIVE_H
#include "foot.h"
/****************************************************************************
** Movable objects are handled by this class definition. Moveable objects
** cover everything except buildings.
*/
class DriveClass : public FootClass
{
public:
/*
** If this unit performing harvesting action, then this flag is true. The flag
** is located here because the other bit flags here give it a free place to
** reside.
*/
unsigned IsHarvesting:1;
/*
** This flag controls whether the unit has been moebius'd into a
** different location, and whether the MoebiusCountDown timer should be
** used to take him back where he belongs.
*/
unsigned IsMoebius:1;
/*
** This controls how long a unit can exist in its alternate location
** before being pulled back by the chronosphere into its normal location.
*/
CDTimerClass MoebiusCountDown;
/*
** This is the coord the unit will be taken back to once its moebius
** effect wears off.
*/
CELL MoebiusCell;
/*
** Some units must have their turret locked down to face their body direction.
** When this flag is set, this condition is in effect. This flag is a more
** accurate check than examining the TrackNumber since the turret may be
** rotating into position so that a pending track may start. During this process
** the track number does not indicate anything.
*/
unsigned IsTurretLockedDown:1;
/*
** This vehicle could be processing a "short track". A short track is one that
** doesn't actually go anywhere. Kind of like turning in place.
*/
unsigned IsOnShortTrack:1;
/*---------------------------------------------------------------------
** Constructors, Destructors, and overloaded operators.
*/
DriveClass(RTTIType rtti, int id, HousesType house);
DriveClass(NoInitClass const & x) : FootClass(x), MoebiusCountDown(x) {};
virtual ~DriveClass(void) {};
/*---------------------------------------------------------------------
** Member function prototypes.
*/
bool Teleport_To(CELL cell);
virtual void Response_Select(void);
virtual void Response_Move(void);
virtual void Response_Attack(void);
virtual void Scatter(COORDINATE threat, bool forced=false, bool nokidding=false);
virtual bool Limbo(void);
void Do_Turn(DirType dir);
virtual void Overrun_Square(CELL , bool =true) {};
virtual void Assign_Destination(TARGET target);
virtual void Per_Cell_Process(PCPType why);
virtual bool Ok_To_Move(DirType ) const;
virtual void AI(void);
#ifdef CHEAT_KEYS
virtual void Debug_Dump(MonoClass *mono) const;
#endif
void Force_Track(int track, COORDINATE coord);
virtual bool Stop_Driver(void);
void Mark_Track(COORDINATE headto, MarkType type);
/**********************************************************************
** These enumerations are used as working constants that exist only
** in the DriveClass namespace.
*/
enum DriveClassEnum {
BACKUP_INTO_REFINERY=64, // Track to backup into refinery.
OUT_OF_REFINERY, // Track to leave refinery.
OUT_OF_WEAPON_FACTORY // Track to leave weapons factory.
};
/****************************************************************************
** Smooth turning tracks are controlled by this structure and these
** processing bits.
*/
typedef enum TrackControlType {
F_=0x00, // No translation necessary?
F_T=0x01, // Transpose X and Y components?
F_X=0x02, // Reverse X component sign?
F_Y=0x04, // Reverse Y component sign?
F_D=0x08 // Two cell consumption?
} TrackControlType;
private:
typedef struct {
char Track; // Which track to use.
char StartTrack; // Track when starting from stand-still.
DirType Facing; // Facing when track has been completed.
DriveClass::TrackControlType Flag; // List processing flag bits.
} TurnTrackType;
typedef struct {
COORDINATE Offset; // Offset to origin coordinate.
DirType Facing; // Facing (primary track).
} TrackType;
typedef struct {
TrackType const * Track; // Pointer to track list.
int Jump; // Index where track jumping is allowed.
int Entry; // Entry point if jumping to this track.
int Cell; // Per cell process should occur at this index.
} RawTrackType;
/*
** These speed values are used to accumulate movement and then
** convert them into pixel "steps" that are then translated through
** the currently running track so that the unit will move.
*/
int SpeedAccum;
/*
** This the track control logic (used for ground vehicles only). The 'Track'
** variable holds the track being followed (0 == not following track). The
** 'TrackIndex' variable holds the current index into the specified track
** (starts at 0).
*/
int TrackNumber;
int TrackIndex;
/*---------------------------------------------------------------------
** Member function prototypes.
*/
virtual void Fixup_Path(PathType *path);
bool While_Moving(void);
bool Start_Of_Move(void);
void Lay_Track(void);
COORDINATE Smooth_Turn(COORDINATE adj, DirType & dir);
static TurnTrackType const TrackControl[67];
static RawTrackType const RawTracks[13];
static TrackType const Track13[];
static TrackType const Track12[];
static TrackType const Track11[];
static TrackType const Track10[];
static TrackType const Track9[];
static TrackType const Track8[];
static TrackType const Track7[];
static TrackType const Track6[];
static TrackType const Track5[];
static TrackType const Track4[];
static TrackType const Track3[];
static TrackType const Track2[];
static TrackType const Track1[24];
};
inline DriveClass::TrackControlType operator |(DriveClass::TrackControlType, DriveClass::TrackControlType);
inline DriveClass::TrackControlType operator &(DriveClass::TrackControlType, DriveClass::TrackControlType);
inline DriveClass::TrackControlType operator ~(DriveClass::TrackControlType);
#endif
================================================
FILE: CODE/DROP.CPP
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/DROP.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 : DROP.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 01/24/96 *
* *
* Last Update : January 24, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
#include "drop.h"
DropListClass::DropListClass(int id, char * text, int max_len, TextPrintType flags, int x, int y, int w, int h, void const * up, void const * down) :
EditClass(id, text, max_len, flags, x, y, w, 9*RESFACTOR, ALPHANUMERIC),
IsDropped(false),
ListHeight(h),
DropButton(0, down, x+w, y),
List(0, x, y+Get_Build_Frame_Height(down), w+Get_Build_Frame_Width(down), h, flags, up, down)
{
Fancy_Text_Print("", 0, 0, 0, 0, flags);
EditClass::Height = FontHeight+1;
List.Make_Peer(*this);
DropButton.Make_Peer(*this);
}
void DropListClass::Zap(void)
{
Collapse();
List.Zap();
DropButton.Zap();
EditClass::Zap();
}
DropListClass & DropListClass::Add(LinkClass & object)
{
DropButton.Add(object);
return((DropListClass &)EditClass::Add(object));
}
DropListClass & DropListClass::Add_Tail(LinkClass & object)
{
DropButton.Add_Tail(object);
return((DropListClass &)EditClass::Add_Tail(object));
}
DropListClass & DropListClass::Add_Head(LinkClass & object)
{
DropButton.Add_Head(object);
return((DropListClass &)EditClass::Add_Head(object));
}
DropListClass * DropListClass::Remove(void)
{
if (IsDropped) {
Collapse();
}
DropButton.Remove();
return((DropListClass *)EditClass::Remove());
}
int DropListClass::Add_Item(char const * text)
{
strncpy(String, text, MaxLength);
Flag_To_Redraw();
return(List.Add_Item(text));
}
char const * DropListClass::Current_Item(void)
{
return(List.Current_Item());
}
int DropListClass::Current_Index(void)
{
return(List.Current_Index());
}
void DropListClass::Set_Selected_Index(int index)
{
if ((unsigned)index < List.Count()) {
List.Set_Selected_Index(index);
strcpy(String, List.Get_Item(Current_Index()));
} else {
String[0] = '\0';
}
}
void DropListClass::Clear_Focus(void)
{
Collapse();
}
void DropListClass::Peer_To_Peer(unsigned flags, KeyNumType & key, ControlClass & whom)
{
if (&whom == &DropButton) {
if (flags & LEFTRELEASE) {
if (IsDropped) {
Collapse();
key = (KeyNumType)(ID | KN_BUTTON);
} else {
Expand();
}
}
}
if (&whom == &List) {
strncpy(String, List.Current_Item(), MaxLength);
Flag_To_Redraw();
key = (KeyNumType)(ID | KN_BUTTON);
}
}
void DropListClass::Expand(void)
{
if (!IsDropped) {
List.X = X;
List.Y = Y+9*RESFACTOR;
List.Width = Width;
List.Height = ListHeight;
List.Add(Head_Of_List());
List.Flag_To_Redraw();
IsDropped = true;
}
}
void DropListClass::Collapse(void)
{
if (IsDropped) {
List.Remove();
IsDropped = false;
}
}
DropListClass & DropListClass::operator = (DropListClass const & list)
{
if (this == &list) return(*this);
EditClass::operator =(list);
List = list.List;
IsDropped = list.IsDropped;
ListHeight = list.ListHeight;
DropButton = list.DropButton;
List.Make_Peer(*this);
DropButton.Make_Peer(*this);
return(*this);
}
DropListClass::DropListClass(DropListClass const & list) :
EditClass(list),
IsDropped(list.IsDropped),
ListHeight(list.ListHeight),
DropButton(list.DropButton),
List(list.List)
{
List.Make_Peer(*this);
DropButton.Make_Peer(*this);
}
void DropListClass::Set_Position(int x, int y)
{
EditClass::Set_Position(x, y);
List.Set_Position(x, y + Get_Build_Frame_Height(DropButton.Get_Shape_Data()));
DropButton.Set_Position(x + Width, y);
}
void DropListClass::Set_Selected_Index(char const * text)
{
if (text) {
for (int index = 0; index < Count(); index++) {
if (stricmp(text, List.Get_Item(index)) == 0) {
Set_Selected_Index(index);
break;
}
}
}
}
#ifdef WOLAPI_INTEGRATION
void DropListClass::Flag_To_Redraw(void)
{
if( IsDropped )
List.Flag_To_Redraw();
EditClass::Flag_To_Redraw();
}
#endif
================================================
FILE: CODE/DROP.H
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/DROP.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 : DROP.H *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 07/05/96 *
* *
* Last Update : July 5, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef DROP_H
#define DROP_H
#include "list.h"
#include "edit.h"
class DropListClass : public EditClass {
public:
DropListClass(int id, char * text, int max_len, TextPrintType flags, int x, int y, int w, int h, void const * up, void const * down);
virtual ~DropListClass(void) {};
virtual DropListClass & Add(LinkClass & object);
virtual DropListClass & Add_Tail(LinkClass & object);
virtual DropListClass & Add_Head(LinkClass & object);
virtual DropListClass * Remove(void);
virtual void Zap(void);
virtual int Add_Item(char const * text);
virtual char const * Current_Item(void);
virtual int Current_Index(void);
virtual void Set_Selected_Index(int index);
virtual void Set_Selected_Index(char const * text);
virtual void Peer_To_Peer(unsigned flags, KeyNumType &, ControlClass & whom);
virtual void Clear_Focus(void);
virtual int Count(void) const {return(List.Count());};
virtual char const * Get_Item(int index) const {return(List.Get_Item(index));};
#ifdef WOLAPI_INTEGRATION
virtual void Flag_To_Redraw(void);
#endif
void Expand(void);
void Collapse(void);
virtual void Set_Position(int x, int y);
DropListClass & operator = (DropListClass const & list);
DropListClass(DropListClass const & list);
/*
** Indicates whether the list box has dropped down or not.
*/
unsigned IsDropped:1;
/*
** Height of list box when it is expanded.
*/
int ListHeight;
/*
** Drop down button.
*/
ShapeButtonClass DropButton;
/*
** List object when it is expanded.
*/
ListClass List;
};
template
class TDropListClass : public EditClass {
public:
TDropListClass(int id, char * text, int max_len, TextPrintType flags, int x, int y, int w, int h, void const * up, void const * down);
TDropListClass(TDropListClass const & list);
virtual ~TDropListClass(void) {};
T operator [] (int index) const {return(List[index]);};
T & operator [] (int index) {return(List[index]);};
virtual TDropListClass & Add(LinkClass & object);
virtual TDropListClass & Add_Tail(LinkClass & object);
virtual TDropListClass & Add_Head(LinkClass & object);
virtual TDropListClass * Remove(void);
void Zap(void);
virtual int Add_Item(T text);
virtual T Current_Item(void);
virtual int Current_Index(void);
virtual void Set_Selected_Index(int index);
virtual void Set_Selected_Index(T item);
virtual void Peer_To_Peer(unsigned flags, KeyNumType &, ControlClass & whom);
virtual void Clear_Focus(void);
virtual int Count(void) const {return(List.Count());};
virtual T Get_Item(int index) const {return(List.Get_Item(index));};
void Expand(void);
void Collapse(void);
virtual void Set_Position(int x, int y);
TDropListClass & operator = (TDropListClass const & list);
/*
** Indicates whether the list box has dropped down or not.
*/
unsigned IsDropped:1;
/*
** Height of list box when it is expanded.
*/
int ListHeight;
/*
** Drop down button.
*/
ShapeButtonClass DropButton;
/*
** List object when it is expanded.
*/
TListClass List;
};
template
TDropListClass::TDropListClass(int id, char * text, int max_len, TextPrintType flags, int x, int y, int w, int h, void const * up, void const * down) :
EditClass(id, text, max_len, flags, x, y, w, 9, ALPHANUMERIC),
IsDropped(false),
ListHeight(h),
DropButton(0, down, x+w, y),
List(0, x, y+Get_Build_Frame_Height(down), w+Get_Build_Frame_Width(down), h, flags, up, down)
{
List.Make_Peer(*this);
DropButton.Make_Peer(*this);
}
template
void TDropListClass::Zap(void)
{
Collapse();
List.Zap();
DropButton.Zap();
EditClass::Zap();
}
template
TDropListClass & TDropListClass::Add(LinkClass & object)
{
DropButton.Add(object);
return((TDropListClass &)EditClass::Add(object));
}
template
TDropListClass & TDropListClass::Add_Tail(LinkClass & object)
{
DropButton.Add_Tail(object);
return((TDropListClass &)EditClass::Add_Tail(object));
}
template
TDropListClass & TDropListClass::Add_Head(LinkClass & object)
{
DropButton.Add_Head(object);
return((TDropListClass &)EditClass::Add_Head(object));
}
template
TDropListClass * TDropListClass::Remove(void)
{
if (IsDropped) {
Collapse();
}
DropButton.Remove();
return((TDropListClass *)EditClass::Remove());
}
template
int TDropListClass::Add_Item(T item)
{
strncpy(String, item->Description(), MaxLength);
Flag_To_Redraw();
return(List.Add_Item(item));
}
template
T TDropListClass::Current_Item(void)
{
return(List.Current_Item());
}
template
int TDropListClass::Current_Index(void)
{
return(List.Current_Index());
}
template
void TDropListClass::Set_Selected_Index(int index)
{
if ((unsigned)index < List.Count()) {
List.Set_Selected_Index(index);
strncpy(String, List.Get_Item(Current_Index())->Description(), MaxLength);
} else {
String[0] = '\0';
}
}
template
void TDropListClass::Clear_Focus(void)
{
Collapse();
}
template
void TDropListClass::Peer_To_Peer(unsigned flags, KeyNumType & key, ControlClass & whom)
{
if (&whom == &DropButton) {
if (flags & LEFTRELEASE) {
if (IsDropped) {
Collapse();
key = (KeyNumType)(ID | KN_BUTTON);
} else {
Expand();
}
}
}
if (&whom == &List) {
strncpy(String, List.Current_Item()->Description(), MaxLength);
Flag_To_Redraw();
key = (KeyNumType)(ID | KN_BUTTON);
}
}
template
void TDropListClass::Expand(void)
{
if (!IsDropped) {
List.X = X;
List.Y = Y+9;
List.Width = Width;
List.Height = ListHeight;
List.Add(Head_Of_List());
List.Flag_To_Redraw();
IsDropped = true;
}
}
template
void TDropListClass::Collapse(void)
{
if (IsDropped) {
List.Remove();
IsDropped = false;
}
}
template
TDropListClass & TDropListClass::operator = (TDropListClass const & list)
{
if (this == &list) return(*this);
EditClass::operator =(list);
List = list.List;
IsDropped = list.IsDropped;
ListHeight = list.ListHeight;
DropButton = list.DropButton;
List.Make_Peer(*this);
DropButton.Make_Peer(*this);
return(*this);
}
template
TDropListClass::TDropListClass(TDropListClass const & list) :
EditClass(list),
IsDropped(list.IsDropped),
ListHeight(list.ListHeight),
DropButton(list.DropButton),
List(list.List)
{
List.Make_Peer(*this);
DropButton.Make_Peer(*this);
}
template
void TDropListClass::Set_Position(int x, int y)
{
EditClass::Set_Position(x, y);
List.Set_Position(x, y + Get_Build_Frame_Height(DropButton.Get_Shape_Data()));
DropButton.Set_Position(x + Width, y);
}
template
void TDropListClass::Set_Selected_Index(T text)
{
for (int index = 0; index < Count(); index++) {
if (text == List.Get_Item(index)) {
Set_Selected_Index(index);
break;
}
}
}
#endif
================================================
FILE: CODE/DTABLE.CPP
================================================
/*
** 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 .
*/
long DiffTable[] = {
0, // Index = 0, Token = 0
1, // Index = 0, Token = 1
3, // Index = 0, Token = 2
4, // Index = 0, Token = 3
7, // Index = 0, Token = 4
8, // Index = 0, Token = 5
10, // Index = 0, Token = 6
11, // Index = 0, Token = 7
0, // Index = 0, Token = 8
-1, // Index = 0, Token = 9
-3, // Index = 0, Token = 10
-4, // Index = 0, Token = 11
-7, // Index = 0, Token = 12
-8, // Index = 0, Token = 13
-10, // Index = 0, Token = 14
-11, // Index = 0, Token = 15
1, // Index = 1, Token = 0
3, // Index = 1, Token = 1
5, // Index = 1, Token = 2
7, // Index = 1, Token = 3
9, // Index = 1, Token = 4
11, // Index = 1, Token = 5
13, // Index = 1, Token = 6
15, // Index = 1, Token = 7
-1, // Index = 1, Token = 8
-3, // Index = 1, Token = 9
-5, // Index = 1, Token = 10
-7, // Index = 1, Token = 11
-9, // Index = 1, Token = 12
-11, // Index = 1, Token = 13
-13, // Index = 1, Token = 14
-15, // Index = 1, Token = 15
1, // Index = 2, Token = 0
3, // Index = 2, Token = 1
5, // Index = 2, Token = 2
7, // Index = 2, Token = 3
10, // Index = 2, Token = 4
12, // Index = 2, Token = 5
14, // Index = 2, Token = 6
16, // Index = 2, Token = 7
-1, // Index = 2, Token = 8
-3, // Index = 2, Token = 9
-5, // Index = 2, Token = 10
-7, // Index = 2, Token = 11
-10, // Index = 2, Token = 12
-12, // Index = 2, Token = 13
-14, // Index = 2, Token = 14
-16, // Index = 2, Token = 15
1, // Index = 3, Token = 0
3, // Index = 3, Token = 1
6, // Index = 3, Token = 2
8, // Index = 3, Token = 3
11, // Index = 3, Token = 4
13, // Index = 3, Token = 5
16, // Index = 3, Token = 6
18, // Index = 3, Token = 7
-1, // Index = 3, Token = 8
-3, // Index = 3, Token = 9
-6, // Index = 3, Token = 10
-8, // Index = 3, Token = 11
-11, // Index = 3, Token = 12
-13, // Index = 3, Token = 13
-16, // Index = 3, Token = 14
-18, // Index = 3, Token = 15
1, // Index = 4, Token = 0
3, // Index = 4, Token = 1
6, // Index = 4, Token = 2
8, // Index = 4, Token = 3
12, // Index = 4, Token = 4
14, // Index = 4, Token = 5
17, // Index = 4, Token = 6
19, // Index = 4, Token = 7
-1, // Index = 4, Token = 8
-3, // Index = 4, Token = 9
-6, // Index = 4, Token = 10
-8, // Index = 4, Token = 11
-12, // Index = 4, Token = 12
-14, // Index = 4, Token = 13
-17, // Index = 4, Token = 14
-19, // Index = 4, Token = 15
1, // Index = 5, Token = 0
4, // Index = 5, Token = 1
7, // Index = 5, Token = 2
10, // Index = 5, Token = 3
13, // Index = 5, Token = 4
16, // Index = 5, Token = 5
19, // Index = 5, Token = 6
22, // Index = 5, Token = 7
-1, // Index = 5, Token = 8
-4, // Index = 5, Token = 9
-7, // Index = 5, Token = 10
-10, // Index = 5, Token = 11
-13, // Index = 5, Token = 12
-16, // Index = 5, Token = 13
-19, // Index = 5, Token = 14
-22, // Index = 5, Token = 15
1, // Index = 6, Token = 0
4, // Index = 6, Token = 1
7, // Index = 6, Token = 2
10, // Index = 6, Token = 3
14, // Index = 6, Token = 4
17, // Index = 6, Token = 5
20, // Index = 6, Token = 6
23, // Index = 6, Token = 7
-1, // Index = 6, Token = 8
-4, // Index = 6, Token = 9
-7, // Index = 6, Token = 10
-10, // Index = 6, Token = 11
-14, // Index = 6, Token = 12
-17, // Index = 6, Token = 13
-20, // Index = 6, Token = 14
-23, // Index = 6, Token = 15
1, // Index = 7, Token = 0
4, // Index = 7, Token = 1
8, // Index = 7, Token = 2
11, // Index = 7, Token = 3
15, // Index = 7, Token = 4
18, // Index = 7, Token = 5
22, // Index = 7, Token = 6
25, // Index = 7, Token = 7
-1, // Index = 7, Token = 8
-4, // Index = 7, Token = 9
-8, // Index = 7, Token = 10
-11, // Index = 7, Token = 11
-15, // Index = 7, Token = 12
-18, // Index = 7, Token = 13
-22, // Index = 7, Token = 14
-25, // Index = 7, Token = 15
2, // Index = 8, Token = 0
6, // Index = 8, Token = 1
10, // Index = 8, Token = 2
14, // Index = 8, Token = 3
18, // Index = 8, Token = 4
22, // Index = 8, Token = 5
26, // Index = 8, Token = 6
30, // Index = 8, Token = 7
-2, // Index = 8, Token = 8
-6, // Index = 8, Token = 9
-10, // Index = 8, Token = 10
-14, // Index = 8, Token = 11
-18, // Index = 8, Token = 12
-22, // Index = 8, Token = 13
-26, // Index = 8, Token = 14
-30, // Index = 8, Token = 15
2, // Index = 9, Token = 0
6, // Index = 9, Token = 1
10, // Index = 9, Token = 2
14, // Index = 9, Token = 3
19, // Index = 9, Token = 4
23, // Index = 9, Token = 5
27, // Index = 9, Token = 6
31, // Index = 9, Token = 7
-2, // Index = 9, Token = 8
-6, // Index = 9, Token = 9
-10, // Index = 9, Token = 10
-14, // Index = 9, Token = 11
-19, // Index = 9, Token = 12
-23, // Index = 9, Token = 13
-27, // Index = 9, Token = 14
-31, // Index = 9, Token = 15
2, // Index = 10, Token = 0
6, // Index = 10, Token = 1
11, // Index = 10, Token = 2
15, // Index = 10, Token = 3
21, // Index = 10, Token = 4
25, // Index = 10, Token = 5
30, // Index = 10, Token = 6
34, // Index = 10, Token = 7
-2, // Index = 10, Token = 8
-6, // Index = 10, Token = 9
-11, // Index = 10, Token = 10
-15, // Index = 10, Token = 11
-21, // Index = 10, Token = 12
-25, // Index = 10, Token = 13
-30, // Index = 10, Token = 14
-34, // Index = 10, Token = 15
2, // Index = 11, Token = 0
7, // Index = 11, Token = 1
12, // Index = 11, Token = 2
17, // Index = 11, Token = 3
23, // Index = 11, Token = 4
28, // Index = 11, Token = 5
33, // Index = 11, Token = 6
38, // Index = 11, Token = 7
-2, // Index = 11, Token = 8
-7, // Index = 11, Token = 9
-12, // Index = 11, Token = 10
-17, // Index = 11, Token = 11
-23, // Index = 11, Token = 12
-28, // Index = 11, Token = 13
-33, // Index = 11, Token = 14
-38, // Index = 11, Token = 15
2, // Index = 12, Token = 0
7, // Index = 12, Token = 1
13, // Index = 12, Token = 2
18, // Index = 12, Token = 3
25, // Index = 12, Token = 4
30, // Index = 12, Token = 5
36, // Index = 12, Token = 6
41, // Index = 12, Token = 7
-2, // Index = 12, Token = 8
-7, // Index = 12, Token = 9
-13, // Index = 12, Token = 10
-18, // Index = 12, Token = 11
-25, // Index = 12, Token = 12
-30, // Index = 12, Token = 13
-36, // Index = 12, Token = 14
-41, // Index = 12, Token = 15
3, // Index = 13, Token = 0
9, // Index = 13, Token = 1
15, // Index = 13, Token = 2
21, // Index = 13, Token = 3
28, // Index = 13, Token = 4
34, // Index = 13, Token = 5
40, // Index = 13, Token = 6
46, // Index = 13, Token = 7
-3, // Index = 13, Token = 8
-9, // Index = 13, Token = 9
-15, // Index = 13, Token = 10
-21, // Index = 13, Token = 11
-28, // Index = 13, Token = 12
-34, // Index = 13, Token = 13
-40, // Index = 13, Token = 14
-46, // Index = 13, Token = 15
3, // Index = 14, Token = 0
10, // Index = 14, Token = 1
17, // Index = 14, Token = 2
24, // Index = 14, Token = 3
31, // Index = 14, Token = 4
38, // Index = 14, Token = 5
45, // Index = 14, Token = 6
52, // Index = 14, Token = 7
-3, // Index = 14, Token = 8
-10, // Index = 14, Token = 9
-17, // Index = 14, Token = 10
-24, // Index = 14, Token = 11
-31, // Index = 14, Token = 12
-38, // Index = 14, Token = 13
-45, // Index = 14, Token = 14
-52, // Index = 14, Token = 15
3, // Index = 15, Token = 0
10, // Index = 15, Token = 1
18, // Index = 15, Token = 2
25, // Index = 15, Token = 3
34, // Index = 15, Token = 4
41, // Index = 15, Token = 5
49, // Index = 15, Token = 6
56, // Index = 15, Token = 7
-3, // Index = 15, Token = 8
-10, // Index = 15, Token = 9
-18, // Index = 15, Token = 10
-25, // Index = 15, Token = 11
-34, // Index = 15, Token = 12
-41, // Index = 15, Token = 13
-49, // Index = 15, Token = 14
-56, // Index = 15, Token = 15
4, // Index = 16, Token = 0
12, // Index = 16, Token = 1
21, // Index = 16, Token = 2
29, // Index = 16, Token = 3
38, // Index = 16, Token = 4
46, // Index = 16, Token = 5
55, // Index = 16, Token = 6
63, // Index = 16, Token = 7
-4, // Index = 16, Token = 8
-12, // Index = 16, Token = 9
-21, // Index = 16, Token = 10
-29, // Index = 16, Token = 11
-38, // Index = 16, Token = 12
-46, // Index = 16, Token = 13
-55, // Index = 16, Token = 14
-63, // Index = 16, Token = 15
4, // Index = 17, Token = 0
13, // Index = 17, Token = 1
22, // Index = 17, Token = 2
31, // Index = 17, Token = 3
41, // Index = 17, Token = 4
50, // Index = 17, Token = 5
59, // Index = 17, Token = 6
68, // Index = 17, Token = 7
-4, // Index = 17, Token = 8
-13, // Index = 17, Token = 9
-22, // Index = 17, Token = 10
-31, // Index = 17, Token = 11
-41, // Index = 17, Token = 12
-50, // Index = 17, Token = 13
-59, // Index = 17, Token = 14
-68, // Index = 17, Token = 15
5, // Index = 18, Token = 0
15, // Index = 18, Token = 1
25, // Index = 18, Token = 2
35, // Index = 18, Token = 3
46, // Index = 18, Token = 4
56, // Index = 18, Token = 5
66, // Index = 18, Token = 6
76, // Index = 18, Token = 7
-5, // Index = 18, Token = 8
-15, // Index = 18, Token = 9
-25, // Index = 18, Token = 10
-35, // Index = 18, Token = 11
-46, // Index = 18, Token = 12
-56, // Index = 18, Token = 13
-66, // Index = 18, Token = 14
-76, // Index = 18, Token = 15
5, // Index = 19, Token = 0
16, // Index = 19, Token = 1
27, // Index = 19, Token = 2
38, // Index = 19, Token = 3
50, // Index = 19, Token = 4
61, // Index = 19, Token = 5
72, // Index = 19, Token = 6
83, // Index = 19, Token = 7
-5, // Index = 19, Token = 8
-16, // Index = 19, Token = 9
-27, // Index = 19, Token = 10
-38, // Index = 19, Token = 11
-50, // Index = 19, Token = 12
-61, // Index = 19, Token = 13
-72, // Index = 19, Token = 14
-83, // Index = 19, Token = 15
6, // Index = 20, Token = 0
18, // Index = 20, Token = 1
31, // Index = 20, Token = 2
43, // Index = 20, Token = 3
56, // Index = 20, Token = 4
68, // Index = 20, Token = 5
81, // Index = 20, Token = 6
93, // Index = 20, Token = 7
-6, // Index = 20, Token = 8
-18, // Index = 20, Token = 9
-31, // Index = 20, Token = 10
-43, // Index = 20, Token = 11
-56, // Index = 20, Token = 12
-68, // Index = 20, Token = 13
-81, // Index = 20, Token = 14
-93, // Index = 20, Token = 15
6, // Index = 21, Token = 0
19, // Index = 21, Token = 1
33, // Index = 21, Token = 2
46, // Index = 21, Token = 3
61, // Index = 21, Token = 4
74, // Index = 21, Token = 5
88, // Index = 21, Token = 6
101, // Index = 21, Token = 7
-6, // Index = 21, Token = 8
-19, // Index = 21, Token = 9
-33, // Index = 21, Token = 10
-46, // Index = 21, Token = 11
-61, // Index = 21, Token = 12
-74, // Index = 21, Token = 13
-88, // Index = 21, Token = 14
-101, // Index = 21, Token = 15
7, // Index = 22, Token = 0
22, // Index = 22, Token = 1
37, // Index = 22, Token = 2
52, // Index = 22, Token = 3
67, // Index = 22, Token = 4
82, // Index = 22, Token = 5
97, // Index = 22, Token = 6
112, // Index = 22, Token = 7
-7, // Index = 22, Token = 8
-22, // Index = 22, Token = 9
-37, // Index = 22, Token = 10
-52, // Index = 22, Token = 11
-67, // Index = 22, Token = 12
-82, // Index = 22, Token = 13
-97, // Index = 22, Token = 14
-112, // Index = 22, Token = 15
8, // Index = 23, Token = 0
24, // Index = 23, Token = 1
41, // Index = 23, Token = 2
57, // Index = 23, Token = 3
74, // Index = 23, Token = 4
90, // Index = 23, Token = 5
107, // Index = 23, Token = 6
123, // Index = 23, Token = 7
-8, // Index = 23, Token = 8
-24, // Index = 23, Token = 9
-41, // Index = 23, Token = 10
-57, // Index = 23, Token = 11
-74, // Index = 23, Token = 12
-90, // Index = 23, Token = 13
-107, // Index = 23, Token = 14
-123, // Index = 23, Token = 15
9, // Index = 24, Token = 0
27, // Index = 24, Token = 1
45, // Index = 24, Token = 2
63, // Index = 24, Token = 3
82, // Index = 24, Token = 4
100, // Index = 24, Token = 5
118, // Index = 24, Token = 6
136, // Index = 24, Token = 7
-9, // Index = 24, Token = 8
-27, // Index = 24, Token = 9
-45, // Index = 24, Token = 10
-63, // Index = 24, Token = 11
-82, // Index = 24, Token = 12
-100, // Index = 24, Token = 13
-118, // Index = 24, Token = 14
-136, // Index = 24, Token = 15
10, // Index = 25, Token = 0
30, // Index = 25, Token = 1
50, // Index = 25, Token = 2
70, // Index = 25, Token = 3
90, // Index = 25, Token = 4
110, // Index = 25, Token = 5
130, // Index = 25, Token = 6
150, // Index = 25, Token = 7
-10, // Index = 25, Token = 8
-30, // Index = 25, Token = 9
-50, // Index = 25, Token = 10
-70, // Index = 25, Token = 11
-90, // Index = 25, Token = 12
-110, // Index = 25, Token = 13
-130, // Index = 25, Token = 14
-150, // Index = 25, Token = 15
11, // Index = 26, Token = 0
33, // Index = 26, Token = 1
55, // Index = 26, Token = 2
77, // Index = 26, Token = 3
99, // Index = 26, Token = 4
121, // Index = 26, Token = 5
143, // Index = 26, Token = 6
165, // Index = 26, Token = 7
-11, // Index = 26, Token = 8
-33, // Index = 26, Token = 9
-55, // Index = 26, Token = 10
-77, // Index = 26, Token = 11
-99, // Index = 26, Token = 12
-121, // Index = 26, Token = 13
-143, // Index = 26, Token = 14
-165, // Index = 26, Token = 15
12, // Index = 27, Token = 0
36, // Index = 27, Token = 1
60, // Index = 27, Token = 2
84, // Index = 27, Token = 3
109, // Index = 27, Token = 4
133, // Index = 27, Token = 5
157, // Index = 27, Token = 6
181, // Index = 27, Token = 7
-12, // Index = 27, Token = 8
-36, // Index = 27, Token = 9
-60, // Index = 27, Token = 10
-84, // Index = 27, Token = 11
-109, // Index = 27, Token = 12
-133, // Index = 27, Token = 13
-157, // Index = 27, Token = 14
-181, // Index = 27, Token = 15
13, // Index = 28, Token = 0
39, // Index = 28, Token = 1
66, // Index = 28, Token = 2
92, // Index = 28, Token = 3
120, // Index = 28, Token = 4
146, // Index = 28, Token = 5
173, // Index = 28, Token = 6
199, // Index = 28, Token = 7
-13, // Index = 28, Token = 8
-39, // Index = 28, Token = 9
-66, // Index = 28, Token = 10
-92, // Index = 28, Token = 11
-120, // Index = 28, Token = 12
-146, // Index = 28, Token = 13
-173, // Index = 28, Token = 14
-199, // Index = 28, Token = 15
14, // Index = 29, Token = 0
43, // Index = 29, Token = 1
73, // Index = 29, Token = 2
102, // Index = 29, Token = 3
132, // Index = 29, Token = 4
161, // Index = 29, Token = 5
191, // Index = 29, Token = 6
220, // Index = 29, Token = 7
-14, // Index = 29, Token = 8
-43, // Index = 29, Token = 9
-73, // Index = 29, Token = 10
-102, // Index = 29, Token = 11
-132, // Index = 29, Token = 12
-161, // Index = 29, Token = 13
-191, // Index = 29, Token = 14
-220, // Index = 29, Token = 15
16, // Index = 30, Token = 0
48, // Index = 30, Token = 1
81, // Index = 30, Token = 2
113, // Index = 30, Token = 3
146, // Index = 30, Token = 4
178, // Index = 30, Token = 5
211, // Index = 30, Token = 6
243, // Index = 30, Token = 7
-16, // Index = 30, Token = 8
-48, // Index = 30, Token = 9
-81, // Index = 30, Token = 10
-113, // Index = 30, Token = 11
-146, // Index = 30, Token = 12
-178, // Index = 30, Token = 13
-211, // Index = 30, Token = 14
-243, // Index = 30, Token = 15
17, // Index = 31, Token = 0
52, // Index = 31, Token = 1
88, // Index = 31, Token = 2
123, // Index = 31, Token = 3
160, // Index = 31, Token = 4
195, // Index = 31, Token = 5
231, // Index = 31, Token = 6
266, // Index = 31, Token = 7
-17, // Index = 31, Token = 8
-52, // Index = 31, Token = 9
-88, // Index = 31, Token = 10
-123, // Index = 31, Token = 11
-160, // Index = 31, Token = 12
-195, // Index = 31, Token = 13
-231, // Index = 31, Token = 14
-266, // Index = 31, Token = 15
19, // Index = 32, Token = 0
58, // Index = 32, Token = 1
97, // Index = 32, Token = 2
136, // Index = 32, Token = 3
176, // Index = 32, Token = 4
215, // Index = 32, Token = 5
254, // Index = 32, Token = 6
293, // Index = 32, Token = 7
-19, // Index = 32, Token = 8
-58, // Index = 32, Token = 9
-97, // Index = 32, Token = 10
-136, // Index = 32, Token = 11
-176, // Index = 32, Token = 12
-215, // Index = 32, Token = 13
-254, // Index = 32, Token = 14
-293, // Index = 32, Token = 15
21, // Index = 33, Token = 0
64, // Index = 33, Token = 1
107, // Index = 33, Token = 2
150, // Index = 33, Token = 3
194, // Index = 33, Token = 4
237, // Index = 33, Token = 5
280, // Index = 33, Token = 6
323, // Index = 33, Token = 7
-21, // Index = 33, Token = 8
-64, // Index = 33, Token = 9
-107, // Index = 33, Token = 10
-150, // Index = 33, Token = 11
-194, // Index = 33, Token = 12
-237, // Index = 33, Token = 13
-280, // Index = 33, Token = 14
-323, // Index = 33, Token = 15
23, // Index = 34, Token = 0
70, // Index = 34, Token = 1
118, // Index = 34, Token = 2
165, // Index = 34, Token = 3
213, // Index = 34, Token = 4
260, // Index = 34, Token = 5
308, // Index = 34, Token = 6
355, // Index = 34, Token = 7
-23, // Index = 34, Token = 8
-70, // Index = 34, Token = 9
-118, // Index = 34, Token = 10
-165, // Index = 34, Token = 11
-213, // Index = 34, Token = 12
-260, // Index = 34, Token = 13
-308, // Index = 34, Token = 14
-355, // Index = 34, Token = 15
26, // Index = 35, Token = 0
78, // Index = 35, Token = 1
130, // Index = 35, Token = 2
182, // Index = 35, Token = 3
235, // Index = 35, Token = 4
287, // Index = 35, Token = 5
339, // Index = 35, Token = 6
391, // Index = 35, Token = 7
-26, // Index = 35, Token = 8
-78, // Index = 35, Token = 9
-130, // Index = 35, Token = 10
-182, // Index = 35, Token = 11
-235, // Index = 35, Token = 12
-287, // Index = 35, Token = 13
-339, // Index = 35, Token = 14
-391, // Index = 35, Token = 15
28, // Index = 36, Token = 0
85, // Index = 36, Token = 1
143, // Index = 36, Token = 2
200, // Index = 36, Token = 3
258, // Index = 36, Token = 4
315, // Index = 36, Token = 5
373, // Index = 36, Token = 6
430, // Index = 36, Token = 7
-28, // Index = 36, Token = 8
-85, // Index = 36, Token = 9
-143, // Index = 36, Token = 10
-200, // Index = 36, Token = 11
-258, // Index = 36, Token = 12
-315, // Index = 36, Token = 13
-373, // Index = 36, Token = 14
-430, // Index = 36, Token = 15
31, // Index = 37, Token = 0
94, // Index = 37, Token = 1
157, // Index = 37, Token = 2
220, // Index = 37, Token = 3
284, // Index = 37, Token = 4
347, // Index = 37, Token = 5
410, // Index = 37, Token = 6
473, // Index = 37, Token = 7
-31, // Index = 37, Token = 8
-94, // Index = 37, Token = 9
-157, // Index = 37, Token = 10
-220, // Index = 37, Token = 11
-284, // Index = 37, Token = 12
-347, // Index = 37, Token = 13
-410, // Index = 37, Token = 14
-473, // Index = 37, Token = 15
34, // Index = 38, Token = 0
103, // Index = 38, Token = 1
173, // Index = 38, Token = 2
242, // Index = 38, Token = 3
313, // Index = 38, Token = 4
382, // Index = 38, Token = 5
452, // Index = 38, Token = 6
521, // Index = 38, Token = 7
-34, // Index = 38, Token = 8
-103, // Index = 38, Token = 9
-173, // Index = 38, Token = 10
-242, // Index = 38, Token = 11
-313, // Index = 38, Token = 12
-382, // Index = 38, Token = 13
-452, // Index = 38, Token = 14
-521, // Index = 38, Token = 15
38, // Index = 39, Token = 0
114, // Index = 39, Token = 1
191, // Index = 39, Token = 2
267, // Index = 39, Token = 3
345, // Index = 39, Token = 4
421, // Index = 39, Token = 5
498, // Index = 39, Token = 6
574, // Index = 39, Token = 7
-38, // Index = 39, Token = 8
-114, // Index = 39, Token = 9
-191, // Index = 39, Token = 10
-267, // Index = 39, Token = 11
-345, // Index = 39, Token = 12
-421, // Index = 39, Token = 13
-498, // Index = 39, Token = 14
-574, // Index = 39, Token = 15
42, // Index = 40, Token = 0
126, // Index = 40, Token = 1
210, // Index = 40, Token = 2
294, // Index = 40, Token = 3
379, // Index = 40, Token = 4
463, // Index = 40, Token = 5
547, // Index = 40, Token = 6
631, // Index = 40, Token = 7
-42, // Index = 40, Token = 8
-126, // Index = 40, Token = 9
-210, // Index = 40, Token = 10
-294, // Index = 40, Token = 11
-379, // Index = 40, Token = 12
-463, // Index = 40, Token = 13
-547, // Index = 40, Token = 14
-631, // Index = 40, Token = 15
46, // Index = 41, Token = 0
138, // Index = 41, Token = 1
231, // Index = 41, Token = 2
323, // Index = 41, Token = 3
417, // Index = 41, Token = 4
509, // Index = 41, Token = 5
602, // Index = 41, Token = 6
694, // Index = 41, Token = 7
-46, // Index = 41, Token = 8
-138, // Index = 41, Token = 9
-231, // Index = 41, Token = 10
-323, // Index = 41, Token = 11
-417, // Index = 41, Token = 12
-509, // Index = 41, Token = 13
-602, // Index = 41, Token = 14
-694, // Index = 41, Token = 15
51, // Index = 42, Token = 0
153, // Index = 42, Token = 1
255, // Index = 42, Token = 2
357, // Index = 42, Token = 3
459, // Index = 42, Token = 4
561, // Index = 42, Token = 5
663, // Index = 42, Token = 6
765, // Index = 42, Token = 7
-51, // Index = 42, Token = 8
-153, // Index = 42, Token = 9
-255, // Index = 42, Token = 10
-357, // Index = 42, Token = 11
-459, // Index = 42, Token = 12
-561, // Index = 42, Token = 13
-663, // Index = 42, Token = 14
-765, // Index = 42, Token = 15
56, // Index = 43, Token = 0
168, // Index = 43, Token = 1
280, // Index = 43, Token = 2
392, // Index = 43, Token = 3
505, // Index = 43, Token = 4
617, // Index = 43, Token = 5
729, // Index = 43, Token = 6
841, // Index = 43, Token = 7
-56, // Index = 43, Token = 8
-168, // Index = 43, Token = 9
-280, // Index = 43, Token = 10
-392, // Index = 43, Token = 11
-505, // Index = 43, Token = 12
-617, // Index = 43, Token = 13
-729, // Index = 43, Token = 14
-841, // Index = 43, Token = 15
61, // Index = 44, Token = 0
184, // Index = 44, Token = 1
308, // Index = 44, Token = 2
431, // Index = 44, Token = 3
555, // Index = 44, Token = 4
678, // Index = 44, Token = 5
802, // Index = 44, Token = 6
925, // Index = 44, Token = 7
-61, // Index = 44, Token = 8
-184, // Index = 44, Token = 9
-308, // Index = 44, Token = 10
-431, // Index = 44, Token = 11
-555, // Index = 44, Token = 12
-678, // Index = 44, Token = 13
-802, // Index = 44, Token = 14
-925, // Index = 44, Token = 15
68, // Index = 45, Token = 0
204, // Index = 45, Token = 1
340, // Index = 45, Token = 2
476, // Index = 45, Token = 3
612, // Index = 45, Token = 4
748, // Index = 45, Token = 5
884, // Index = 45, Token = 6
1020, // Index = 45, Token = 7
-68, // Index = 45, Token = 8
-204, // Index = 45, Token = 9
-340, // Index = 45, Token = 10
-476, // Index = 45, Token = 11
-612, // Index = 45, Token = 12
-748, // Index = 45, Token = 13
-884, // Index = 45, Token = 14
-1020, // Index = 45, Token = 15
74, // Index = 46, Token = 0
223, // Index = 46, Token = 1
373, // Index = 46, Token = 2
522, // Index = 46, Token = 3
672, // Index = 46, Token = 4
821, // Index = 46, Token = 5
971, // Index = 46, Token = 6
1120, // Index = 46, Token = 7
-74, // Index = 46, Token = 8
-223, // Index = 46, Token = 9
-373, // Index = 46, Token = 10
-522, // Index = 46, Token = 11
-672, // Index = 46, Token = 12
-821, // Index = 46, Token = 13
-971, // Index = 46, Token = 14
-1120, // Index = 46, Token = 15
82, // Index = 47, Token = 0
246, // Index = 47, Token = 1
411, // Index = 47, Token = 2
575, // Index = 47, Token = 3
740, // Index = 47, Token = 4
904, // Index = 47, Token = 5
1069, // Index = 47, Token = 6
1233, // Index = 47, Token = 7
-82, // Index = 47, Token = 8
-246, // Index = 47, Token = 9
-411, // Index = 47, Token = 10
-575, // Index = 47, Token = 11
-740, // Index = 47, Token = 12
-904, // Index = 47, Token = 13
-1069, // Index = 47, Token = 14
-1233, // Index = 47, Token = 15
90, // Index = 48, Token = 0
271, // Index = 48, Token = 1
452, // Index = 48, Token = 2
633, // Index = 48, Token = 3
814, // Index = 48, Token = 4
995, // Index = 48, Token = 5
1176, // Index = 48, Token = 6
1357, // Index = 48, Token = 7
-90, // Index = 48, Token = 8
-271, // Index = 48, Token = 9
-452, // Index = 48, Token = 10
-633, // Index = 48, Token = 11
-814, // Index = 48, Token = 12
-995, // Index = 48, Token = 13
-1176, // Index = 48, Token = 14
-1357, // Index = 48, Token = 15
99, // Index = 49, Token = 0
298, // Index = 49, Token = 1
497, // Index = 49, Token = 2
696, // Index = 49, Token = 3
895, // Index = 49, Token = 4
1094, // Index = 49, Token = 5
1293, // Index = 49, Token = 6
1492, // Index = 49, Token = 7
-99, // Index = 49, Token = 8
-298, // Index = 49, Token = 9
-497, // Index = 49, Token = 10
-696, // Index = 49, Token = 11
-895, // Index = 49, Token = 12
-1094, // Index = 49, Token = 13
-1293, // Index = 49, Token = 14
-1492, // Index = 49, Token = 15
109, // Index = 50, Token = 0
328, // Index = 50, Token = 1
547, // Index = 50, Token = 2
766, // Index = 50, Token = 3
985, // Index = 50, Token = 4
1204, // Index = 50, Token = 5
1423, // Index = 50, Token = 6
1642, // Index = 50, Token = 7
-109, // Index = 50, Token = 8
-328, // Index = 50, Token = 9
-547, // Index = 50, Token = 10
-766, // Index = 50, Token = 11
-985, // Index = 50, Token = 12
-1204, // Index = 50, Token = 13
-1423, // Index = 50, Token = 14
-1642, // Index = 50, Token = 15
120, // Index = 51, Token = 0
360, // Index = 51, Token = 1
601, // Index = 51, Token = 2
841, // Index = 51, Token = 3
1083, // Index = 51, Token = 4
1323, // Index = 51, Token = 5
1564, // Index = 51, Token = 6
1804, // Index = 51, Token = 7
-120, // Index = 51, Token = 8
-360, // Index = 51, Token = 9
-601, // Index = 51, Token = 10
-841, // Index = 51, Token = 11
-1083, // Index = 51, Token = 12
-1323, // Index = 51, Token = 13
-1564, // Index = 51, Token = 14
-1804, // Index = 51, Token = 15
132, // Index = 52, Token = 0
397, // Index = 52, Token = 1
662, // Index = 52, Token = 2
927, // Index = 52, Token = 3
1192, // Index = 52, Token = 4
1457, // Index = 52, Token = 5
1722, // Index = 52, Token = 6
1987, // Index = 52, Token = 7
-132, // Index = 52, Token = 8
-397, // Index = 52, Token = 9
-662, // Index = 52, Token = 10
-927, // Index = 52, Token = 11
-1192, // Index = 52, Token = 12
-1457, // Index = 52, Token = 13
-1722, // Index = 52, Token = 14
-1987, // Index = 52, Token = 15
145, // Index = 53, Token = 0
436, // Index = 53, Token = 1
728, // Index = 53, Token = 2
1019, // Index = 53, Token = 3
1311, // Index = 53, Token = 4
1602, // Index = 53, Token = 5
1894, // Index = 53, Token = 6
2185, // Index = 53, Token = 7
-145, // Index = 53, Token = 8
-436, // Index = 53, Token = 9
-728, // Index = 53, Token = 10
-1019, // Index = 53, Token = 11
-1311, // Index = 53, Token = 12
-1602, // Index = 53, Token = 13
-1894, // Index = 53, Token = 14
-2185, // Index = 53, Token = 15
160, // Index = 54, Token = 0
480, // Index = 54, Token = 1
801, // Index = 54, Token = 2
1121, // Index = 54, Token = 3
1442, // Index = 54, Token = 4
1762, // Index = 54, Token = 5
2083, // Index = 54, Token = 6
2403, // Index = 54, Token = 7
-160, // Index = 54, Token = 8
-480, // Index = 54, Token = 9
-801, // Index = 54, Token = 10
-1121, // Index = 54, Token = 11
-1442, // Index = 54, Token = 12
-1762, // Index = 54, Token = 13
-2083, // Index = 54, Token = 14
-2403, // Index = 54, Token = 15
176, // Index = 55, Token = 0
528, // Index = 55, Token = 1
881, // Index = 55, Token = 2
1233, // Index = 55, Token = 3
1587, // Index = 55, Token = 4
1939, // Index = 55, Token = 5
2292, // Index = 55, Token = 6
2644, // Index = 55, Token = 7
-176, // Index = 55, Token = 8
-528, // Index = 55, Token = 9
-881, // Index = 55, Token = 10
-1233, // Index = 55, Token = 11
-1587, // Index = 55, Token = 12
-1939, // Index = 55, Token = 13
-2292, // Index = 55, Token = 14
-2644, // Index = 55, Token = 15
194, // Index = 56, Token = 0
582, // Index = 56, Token = 1
970, // Index = 56, Token = 2
1358, // Index = 56, Token = 3
1746, // Index = 56, Token = 4
2134, // Index = 56, Token = 5
2522, // Index = 56, Token = 6
2910, // Index = 56, Token = 7
-194, // Index = 56, Token = 8
-582, // Index = 56, Token = 9
-970, // Index = 56, Token = 10
-1358, // Index = 56, Token = 11
-1746, // Index = 56, Token = 12
-2134, // Index = 56, Token = 13
-2522, // Index = 56, Token = 14
-2910, // Index = 56, Token = 15
213, // Index = 57, Token = 0
639, // Index = 57, Token = 1
1066, // Index = 57, Token = 2
1492, // Index = 57, Token = 3
1920, // Index = 57, Token = 4
2346, // Index = 57, Token = 5
2773, // Index = 57, Token = 6
3199, // Index = 57, Token = 7
-213, // Index = 57, Token = 8
-639, // Index = 57, Token = 9
-1066, // Index = 57, Token = 10
-1492, // Index = 57, Token = 11
-1920, // Index = 57, Token = 12
-2346, // Index = 57, Token = 13
-2773, // Index = 57, Token = 14
-3199, // Index = 57, Token = 15
234, // Index = 58, Token = 0
703, // Index = 58, Token = 1
1173, // Index = 58, Token = 2
1642, // Index = 58, Token = 3
2112, // Index = 58, Token = 4
2581, // Index = 58, Token = 5
3051, // Index = 58, Token = 6
3520, // Index = 58, Token = 7
-234, // Index = 58, Token = 8
-703, // Index = 58, Token = 9
-1173, // Index = 58, Token = 10
-1642, // Index = 58, Token = 11
-2112, // Index = 58, Token = 12
-2581, // Index = 58, Token = 13
-3051, // Index = 58, Token = 14
-3520, // Index = 58, Token = 15
258, // Index = 59, Token = 0
774, // Index = 59, Token = 1
1291, // Index = 59, Token = 2
1807, // Index = 59, Token = 3
2324, // Index = 59, Token = 4
2840, // Index = 59, Token = 5
3357, // Index = 59, Token = 6
3873, // Index = 59, Token = 7
-258, // Index = 59, Token = 8
-774, // Index = 59, Token = 9
-1291, // Index = 59, Token = 10
-1807, // Index = 59, Token = 11
-2324, // Index = 59, Token = 12
-2840, // Index = 59, Token = 13
-3357, // Index = 59, Token = 14
-3873, // Index = 59, Token = 15
284, // Index = 60, Token = 0
852, // Index = 60, Token = 1
1420, // Index = 60, Token = 2
1988, // Index = 60, Token = 3
2556, // Index = 60, Token = 4
3124, // Index = 60, Token = 5
3692, // Index = 60, Token = 6
4260, // Index = 60, Token = 7
-284, // Index = 60, Token = 8
-852, // Index = 60, Token = 9
-1420, // Index = 60, Token = 10
-1988, // Index = 60, Token = 11
-2556, // Index = 60, Token = 12
-3124, // Index = 60, Token = 13
-3692, // Index = 60, Token = 14
-4260, // Index = 60, Token = 15
312, // Index = 61, Token = 0
936, // Index = 61, Token = 1
1561, // Index = 61, Token = 2
2185, // Index = 61, Token = 3
2811, // Index = 61, Token = 4
3435, // Index = 61, Token = 5
4060, // Index = 61, Token = 6
4684, // Index = 61, Token = 7
-312, // Index = 61, Token = 8
-936, // Index = 61, Token = 9
-1561, // Index = 61, Token = 10
-2185, // Index = 61, Token = 11
-2811, // Index = 61, Token = 12
-3435, // Index = 61, Token = 13
-4060, // Index = 61, Token = 14
-4684, // Index = 61, Token = 15
343, // Index = 62, Token = 0
1030, // Index = 62, Token = 1
1717, // Index = 62, Token = 2
2404, // Index = 62, Token = 3
3092, // Index = 62, Token = 4
3779, // Index = 62, Token = 5
4466, // Index = 62, Token = 6
5153, // Index = 62, Token = 7
-343, // Index = 62, Token = 8
-1030, // Index = 62, Token = 9
-1717, // Index = 62, Token = 10
-2404, // Index = 62, Token = 11
-3092, // Index = 62, Token = 12
-3779, // Index = 62, Token = 13
-4466, // Index = 62, Token = 14
-5153, // Index = 62, Token = 15
378, // Index = 63, Token = 0
1134, // Index = 63, Token = 1
1890, // Index = 63, Token = 2
2646, // Index = 63, Token = 3
3402, // Index = 63, Token = 4
4158, // Index = 63, Token = 5
4914, // Index = 63, Token = 6
5670, // Index = 63, Token = 7
-378, // Index = 63, Token = 8
-1134, // Index = 63, Token = 9
-1890, // Index = 63, Token = 10
-2646, // Index = 63, Token = 11
-3402, // Index = 63, Token = 12
-4158, // Index = 63, Token = 13
-4914, // Index = 63, Token = 14
-5670, // Index = 63, Token = 15
415, // Index = 64, Token = 0
1246, // Index = 64, Token = 1
2078, // Index = 64, Token = 2
2909, // Index = 64, Token = 3
3742, // Index = 64, Token = 4
4573, // Index = 64, Token = 5
5405, // Index = 64, Token = 6
6236, // Index = 64, Token = 7
-415, // Index = 64, Token = 8
-1246, // Index = 64, Token = 9
-2078, // Index = 64, Token = 10
-2909, // Index = 64, Token = 11
-3742, // Index = 64, Token = 12
-4573, // Index = 64, Token = 13
-5405, // Index = 64, Token = 14
-6236, // Index = 64, Token = 15
457, // Index = 65, Token = 0
1372, // Index = 65, Token = 1
2287, // Index = 65, Token = 2
3202, // Index = 65, Token = 3
4117, // Index = 65, Token = 4
5032, // Index = 65, Token = 5
5947, // Index = 65, Token = 6
6862, // Index = 65, Token = 7
-457, // Index = 65, Token = 8
-1372, // Index = 65, Token = 9
-2287, // Index = 65, Token = 10
-3202, // Index = 65, Token = 11
-4117, // Index = 65, Token = 12
-5032, // Index = 65, Token = 13
-5947, // Index = 65, Token = 14
-6862, // Index = 65, Token = 15
503, // Index = 66, Token = 0
1509, // Index = 66, Token = 1
2516, // Index = 66, Token = 2
3522, // Index = 66, Token = 3
4529, // Index = 66, Token = 4
5535, // Index = 66, Token = 5
6542, // Index = 66, Token = 6
7548, // Index = 66, Token = 7
-503, // Index = 66, Token = 8
-1509, // Index = 66, Token = 9
-2516, // Index = 66, Token = 10
-3522, // Index = 66, Token = 11
-4529, // Index = 66, Token = 12
-5535, // Index = 66, Token = 13
-6542, // Index = 66, Token = 14
-7548, // Index = 66, Token = 15
553, // Index = 67, Token = 0
1660, // Index = 67, Token = 1
2767, // Index = 67, Token = 2
3874, // Index = 67, Token = 3
4981, // Index = 67, Token = 4
6088, // Index = 67, Token = 5
7195, // Index = 67, Token = 6
8302, // Index = 67, Token = 7
-553, // Index = 67, Token = 8
-1660, // Index = 67, Token = 9
-2767, // Index = 67, Token = 10
-3874, // Index = 67, Token = 11
-4981, // Index = 67, Token = 12
-6088, // Index = 67, Token = 13
-7195, // Index = 67, Token = 14
-8302, // Index = 67, Token = 15
608, // Index = 68, Token = 0
1825, // Index = 68, Token = 1
3043, // Index = 68, Token = 2
4260, // Index = 68, Token = 3
5479, // Index = 68, Token = 4
6696, // Index = 68, Token = 5
7914, // Index = 68, Token = 6
9131, // Index = 68, Token = 7
-608, // Index = 68, Token = 8
-1825, // Index = 68, Token = 9
-3043, // Index = 68, Token = 10
-4260, // Index = 68, Token = 11
-5479, // Index = 68, Token = 12
-6696, // Index = 68, Token = 13
-7914, // Index = 68, Token = 14
-9131, // Index = 68, Token = 15
669, // Index = 69, Token = 0
2008, // Index = 69, Token = 1
3348, // Index = 69, Token = 2
4687, // Index = 69, Token = 3
6027, // Index = 69, Token = 4
7366, // Index = 69, Token = 5
8706, // Index = 69, Token = 6
10045, // Index = 69, Token = 7
-669, // Index = 69, Token = 8
-2008, // Index = 69, Token = 9
-3348, // Index = 69, Token = 10
-4687, // Index = 69, Token = 11
-6027, // Index = 69, Token = 12
-7366, // Index = 69, Token = 13
-8706, // Index = 69, Token = 14
-10045, // Index = 69, Token = 15
736, // Index = 70, Token = 0
2209, // Index = 70, Token = 1
3683, // Index = 70, Token = 2
5156, // Index = 70, Token = 3
6630, // Index = 70, Token = 4
8103, // Index = 70, Token = 5
9577, // Index = 70, Token = 6
11050, // Index = 70, Token = 7
-736, // Index = 70, Token = 8
-2209, // Index = 70, Token = 9
-3683, // Index = 70, Token = 10
-5156, // Index = 70, Token = 11
-6630, // Index = 70, Token = 12
-8103, // Index = 70, Token = 13
-9577, // Index = 70, Token = 14
-11050, // Index = 70, Token = 15
810, // Index = 71, Token = 0
2431, // Index = 71, Token = 1
4052, // Index = 71, Token = 2
5673, // Index = 71, Token = 3
7294, // Index = 71, Token = 4
8915, // Index = 71, Token = 5
10536, // Index = 71, Token = 6
12157, // Index = 71, Token = 7
-810, // Index = 71, Token = 8
-2431, // Index = 71, Token = 9
-4052, // Index = 71, Token = 10
-5673, // Index = 71, Token = 11
-7294, // Index = 71, Token = 12
-8915, // Index = 71, Token = 13
-10536, // Index = 71, Token = 14
-12157, // Index = 71, Token = 15
891, // Index = 72, Token = 0
2674, // Index = 72, Token = 1
4457, // Index = 72, Token = 2
6240, // Index = 72, Token = 3
8023, // Index = 72, Token = 4
9806, // Index = 72, Token = 5
11589, // Index = 72, Token = 6
13372, // Index = 72, Token = 7
-891, // Index = 72, Token = 8
-2674, // Index = 72, Token = 9
-4457, // Index = 72, Token = 10
-6240, // Index = 72, Token = 11
-8023, // Index = 72, Token = 12
-9806, // Index = 72, Token = 13
-11589, // Index = 72, Token = 14
-13372, // Index = 72, Token = 15
980, // Index = 73, Token = 0
2941, // Index = 73, Token = 1
4902, // Index = 73, Token = 2
6863, // Index = 73, Token = 3
8825, // Index = 73, Token = 4
10786, // Index = 73, Token = 5
12747, // Index = 73, Token = 6
14708, // Index = 73, Token = 7
-980, // Index = 73, Token = 8
-2941, // Index = 73, Token = 9
-4902, // Index = 73, Token = 10
-6863, // Index = 73, Token = 11
-8825, // Index = 73, Token = 12
-10786, // Index = 73, Token = 13
-12747, // Index = 73, Token = 14
-14708, // Index = 73, Token = 15
1078, // Index = 74, Token = 0
3235, // Index = 74, Token = 1
5393, // Index = 74, Token = 2
7550, // Index = 74, Token = 3
9708, // Index = 74, Token = 4
11865, // Index = 74, Token = 5
14023, // Index = 74, Token = 6
16180, // Index = 74, Token = 7
-1078, // Index = 74, Token = 8
-3235, // Index = 74, Token = 9
-5393, // Index = 74, Token = 10
-7550, // Index = 74, Token = 11
-9708, // Index = 74, Token = 12
-11865, // Index = 74, Token = 13
-14023, // Index = 74, Token = 14
-16180, // Index = 74, Token = 15
1186, // Index = 75, Token = 0
3559, // Index = 75, Token = 1
5932, // Index = 75, Token = 2
8305, // Index = 75, Token = 3
10679, // Index = 75, Token = 4
13052, // Index = 75, Token = 5
15425, // Index = 75, Token = 6
17798, // Index = 75, Token = 7
-1186, // Index = 75, Token = 8
-3559, // Index = 75, Token = 9
-5932, // Index = 75, Token = 10
-8305, // Index = 75, Token = 11
-10679, // Index = 75, Token = 12
-13052, // Index = 75, Token = 13
-15425, // Index = 75, Token = 14
-17798, // Index = 75, Token = 15
1305, // Index = 76, Token = 0
3915, // Index = 76, Token = 1
6526, // Index = 76, Token = 2
9136, // Index = 76, Token = 3
11747, // Index = 76, Token = 4
14357, // Index = 76, Token = 5
16968, // Index = 76, Token = 6
19578, // Index = 76, Token = 7
-1305, // Index = 76, Token = 8
-3915, // Index = 76, Token = 9
-6526, // Index = 76, Token = 10
-9136, // Index = 76, Token = 11
-11747, // Index = 76, Token = 12
-14357, // Index = 76, Token = 13
-16968, // Index = 76, Token = 14
-19578, // Index = 76, Token = 15
1435, // Index = 77, Token = 0
4306, // Index = 77, Token = 1
7178, // Index = 77, Token = 2
10049, // Index = 77, Token = 3
12922, // Index = 77, Token = 4
15793, // Index = 77, Token = 5
18665, // Index = 77, Token = 6
21536, // Index = 77, Token = 7
-1435, // Index = 77, Token = 8
-4306, // Index = 77, Token = 9
-7178, // Index = 77, Token = 10
-10049, // Index = 77, Token = 11
-12922, // Index = 77, Token = 12
-15793, // Index = 77, Token = 13
-18665, // Index = 77, Token = 14
-21536, // Index = 77, Token = 15
1579, // Index = 78, Token = 0
4737, // Index = 78, Token = 1
7896, // Index = 78, Token = 2
11054, // Index = 78, Token = 3
14214, // Index = 78, Token = 4
17372, // Index = 78, Token = 5
20531, // Index = 78, Token = 6
23689, // Index = 78, Token = 7
-1579, // Index = 78, Token = 8
-4737, // Index = 78, Token = 9
-7896, // Index = 78, Token = 10
-11054, // Index = 78, Token = 11
-14214, // Index = 78, Token = 12
-17372, // Index = 78, Token = 13
-20531, // Index = 78, Token = 14
-23689, // Index = 78, Token = 15
1737, // Index = 79, Token = 0
5211, // Index = 79, Token = 1
8686, // Index = 79, Token = 2
12160, // Index = 79, Token = 3
15636, // Index = 79, Token = 4
19110, // Index = 79, Token = 5
22585, // Index = 79, Token = 6
26059, // Index = 79, Token = 7
-1737, // Index = 79, Token = 8
-5211, // Index = 79, Token = 9
-8686, // Index = 79, Token = 10
-12160, // Index = 79, Token = 11
-15636, // Index = 79, Token = 12
-19110, // Index = 79, Token = 13
-22585, // Index = 79, Token = 14
-26059, // Index = 79, Token = 15
1911, // Index = 80, Token = 0
5733, // Index = 80, Token = 1
9555, // Index = 80, Token = 2
13377, // Index = 80, Token = 3
17200, // Index = 80, Token = 4
21022, // Index = 80, Token = 5
24844, // Index = 80, Token = 6
28666, // Index = 80, Token = 7
-1911, // Index = 80, Token = 8
-5733, // Index = 80, Token = 9
-9555, // Index = 80, Token = 10
-13377, // Index = 80, Token = 11
-17200, // Index = 80, Token = 12
-21022, // Index = 80, Token = 13
-24844, // Index = 80, Token = 14
-28666, // Index = 80, Token = 15
2102, // Index = 81, Token = 0
6306, // Index = 81, Token = 1
10511, // Index = 81, Token = 2
14715, // Index = 81, Token = 3
18920, // Index = 81, Token = 4
23124, // Index = 81, Token = 5
27329, // Index = 81, Token = 6
31533, // Index = 81, Token = 7
-2102, // Index = 81, Token = 8
-6306, // Index = 81, Token = 9
-10511, // Index = 81, Token = 10
-14715, // Index = 81, Token = 11
-18920, // Index = 81, Token = 12
-23124, // Index = 81, Token = 13
-27329, // Index = 81, Token = 14
-31533, // Index = 81, Token = 15
2312, // Index = 82, Token = 0
6937, // Index = 82, Token = 1
11562, // Index = 82, Token = 2
16187, // Index = 82, Token = 3
20812, // Index = 82, Token = 4
25437, // Index = 82, Token = 5
30062, // Index = 82, Token = 6
34687, // Index = 82, Token = 7
-2312, // Index = 82, Token = 8
-6937, // Index = 82, Token = 9
-11562, // Index = 82, Token = 10
-16187, // Index = 82, Token = 11
-20812, // Index = 82, Token = 12
-25437, // Index = 82, Token = 13
-30062, // Index = 82, Token = 14
-34687, // Index = 82, Token = 15
2543, // Index = 83, Token = 0
7630, // Index = 83, Token = 1
12718, // Index = 83, Token = 2
17805, // Index = 83, Token = 3
22893, // Index = 83, Token = 4
27980, // Index = 83, Token = 5
33068, // Index = 83, Token = 6
38155, // Index = 83, Token = 7
-2543, // Index = 83, Token = 8
-7630, // Index = 83, Token = 9
-12718, // Index = 83, Token = 10
-17805, // Index = 83, Token = 11
-22893, // Index = 83, Token = 12
-27980, // Index = 83, Token = 13
-33068, // Index = 83, Token = 14
-38155, // Index = 83, Token = 15
2798, // Index = 84, Token = 0
8394, // Index = 84, Token = 1
13990, // Index = 84, Token = 2
19586, // Index = 84, Token = 3
25183, // Index = 84, Token = 4
30779, // Index = 84, Token = 5
36375, // Index = 84, Token = 6
41971, // Index = 84, Token = 7
-2798, // Index = 84, Token = 8
-8394, // Index = 84, Token = 9
-13990, // Index = 84, Token = 10
-19586, // Index = 84, Token = 11
-25183, // Index = 84, Token = 12
-30779, // Index = 84, Token = 13
-36375, // Index = 84, Token = 14
-41971, // Index = 84, Token = 15
3077, // Index = 85, Token = 0
9232, // Index = 85, Token = 1
15388, // Index = 85, Token = 2
21543, // Index = 85, Token = 3
27700, // Index = 85, Token = 4
33855, // Index = 85, Token = 5
40011, // Index = 85, Token = 6
46166, // Index = 85, Token = 7
-3077, // Index = 85, Token = 8
-9232, // Index = 85, Token = 9
-15388, // Index = 85, Token = 10
-21543, // Index = 85, Token = 11
-27700, // Index = 85, Token = 12
-33855, // Index = 85, Token = 13
-40011, // Index = 85, Token = 14
-46166, // Index = 85, Token = 15
3385, // Index = 86, Token = 0
10156, // Index = 86, Token = 1
16928, // Index = 86, Token = 2
23699, // Index = 86, Token = 3
30471, // Index = 86, Token = 4
37242, // Index = 86, Token = 5
44014, // Index = 86, Token = 6
50785, // Index = 86, Token = 7
-3385, // Index = 86, Token = 8
-10156, // Index = 86, Token = 9
-16928, // Index = 86, Token = 10
-23699, // Index = 86, Token = 11
-30471, // Index = 86, Token = 12
-37242, // Index = 86, Token = 13
-44014, // Index = 86, Token = 14
-50785, // Index = 86, Token = 15
3724, // Index = 87, Token = 0
11172, // Index = 87, Token = 1
18621, // Index = 87, Token = 2
26069, // Index = 87, Token = 3
33518, // Index = 87, Token = 4
40966, // Index = 87, Token = 5
48415, // Index = 87, Token = 6
55863, // Index = 87, Token = 7
-3724, // Index = 87, Token = 8
-11172, // Index = 87, Token = 9
-18621, // Index = 87, Token = 10
-26069, // Index = 87, Token = 11
-33518, // Index = 87, Token = 12
-40966, // Index = 87, Token = 13
-48415, // Index = 87, Token = 14
-55863, // Index = 87, Token = 15
4095, // Index = 88, Token = 0
12286, // Index = 88, Token = 1
20478, // Index = 88, Token = 2
28669, // Index = 88, Token = 3
36862, // Index = 88, Token = 4
45053, // Index = 88, Token = 5
53245, // Index = 88, Token = 6
61436, // Index = 88, Token = 7
-4095, // Index = 88, Token = 8
-12286, // Index = 88, Token = 9
-20478, // Index = 88, Token = 10
-28669, // Index = 88, Token = 11
-36862, // Index = 88, Token = 12
-45053, // Index = 88, Token = 13
-53245, // Index = 88, Token = 14
-61436 // Index = 88, Token = 15
};
================================================
FILE: CODE/DYNAVEC.CPP
================================================
/*
** 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 .
*/
/* $Header: /CounterStrike/DYNAVEC.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***************************************************************************
* *
* Project Name : Red Alert *
* *
* File Name : DYNAVEC.CPP *
* *
* Programmer : Bill R Randolph *
* *
* Start Date : 09/18/96 *
* *
* Last Update : September 18, 1996 [BRR] *
* *
*-------------------------------------------------------------------------*
* Functions: *
* DynamicVectorClass::Add -- Add an element to the vector. *
* DynamicVectorClass::Add_Head -- Adds element to head of the list. *
* DynamicVectorClass::Add_Head -- Adds element to head of the list. *
* DynamicVectorClass::Delete -- Deletes specified index from vector. *
* DynamicVectorClass::Delete -- Remove specified object from vector. *
* DynamicVectorClass::DynamicVectorClass -- Constructor *
* DynamicVectorClass::ID -- Find matching value in dynamic vector. *
* DynamicVectorClass::Resize -- Changes size of a dynamic vector. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
#include "vector.h"
#ifdef WINSOCK_IPX
#include "WSProto.h"
#include "WSPUDP.h"
#endif //WINSOCK_IPX
#include
#include
/***********************************************************************************************
* DynamicVectorClass::DynamicVectorClass -- Constructor for dynamic vector. *
* *
* This is the normal constructor for the dynamic vector class. It is similar to the normal *
* vector class constructor. The vector is initialized to contain the number of elements *
* specified in the "size" parameter. The memory is allocated from free store unless the *
* optional array parameter is provided. In this case it will place the vector at the *
* memory location specified. *
* *
* INPUT: size -- The maximum number of objects allowed in this vector. *
* *
* array -- Optional pointer to the memory area to place the vector at. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 03/10/1995 JLB : Created. *
*=============================================================================================*/
template
DynamicVectorClass::DynamicVectorClass(unsigned size, T const * array)
: VectorClass(size, array)
{
GrowthStep = 10;
ActiveCount = 0;
}
/***********************************************************************************************
* DynamicVectorClass::Resize -- Changes the size of a dynamic vector. *
* *
* Use this routine to change the size of the vector. The size changed is the maximum *
* number of allocated objects within this vector. If a memory buffer is provided, then *
* the vector will be located there. Otherwise, the memory will be allocated out of free *
* store. *
* *
* INPUT: newsize -- The desired maximum size of this vector. *
* *
* array -- Optional pointer to a previously allocated memory array. *
* *
* OUTPUT: bool; Was vector successfully resized according to specifications? *
* *
* WARNINGS: Failure to resize the vector could be the result of lack of free store. *
* *
* HISTORY: *
* 03/10/1995 JLB : Created. *
*=============================================================================================*/
template
int DynamicVectorClass::Resize(unsigned newsize, T const * array)
{
if (VectorClass::Resize(newsize, array)) {
if (Length() < ActiveCount) ActiveCount = Length();
return(true);
}
return(false);
}
/***********************************************************************************************
* DynamicVectorClass::ID -- Find matching value in the dynamic vector. *
* *
* Use this routine to find a matching object (by value) in the vector. Unlike the base *
* class ID function of similar name, this one restricts the scan to the current number *
* of valid objects. *
* *
* INPUT: object -- A reference to the object that a match is to be found in the *
* vector. *
* *
* OUTPUT: Returns with the index number of the object that is equivalent to the one *
* specified. If no equivalent object could be found then -1 is returned. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 03/13/1995 JLB : Created. *
*=============================================================================================*/
template
int DynamicVectorClass::ID(T const & object)
{
for (int index = 0; index < Count(); index++) {
if ((*this)[index] == object) return(index);
}
return(-1);
}
/***********************************************************************************************
* DynamicVectorClass::Add -- Add an element to the vector. *
* *
* Use this routine to add an element to the vector. The vector will automatically be *
* resized to accomodate the new element IF the vector was allocated previously and the *
* growth rate is not zero. *
* *
* INPUT: object -- Reference to the object that will be added to the vector. *
* *
* OUTPUT: bool; Was the object added successfully? If so, the object is added to the end *
* of the vector. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 03/10/1995 JLB : Created. *
*=============================================================================================*/
template
int DynamicVectorClass