summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--GNU.TXT87
-rw-r--r--README.TXT114
-rw-r--r--SRC/A.ASM2420
-rw-r--r--SRC/BSTUB.C532
-rw-r--r--SRC/BUILD.C6589
-rw-r--r--SRC/BUILD.H278
-rw-r--r--SRC/BUILD.TXT5081
-rw-r--r--SRC/BUILD2.TXT1655
-rw-r--r--SRC/BUILDINF.TXT882
-rw-r--r--SRC/CACHE1D.C647
-rw-r--r--SRC/ENGINE.C8829
-rw-r--r--SRC/GAME.C6109
-rw-r--r--SRC/K.ASM544
-rw-r--r--SRC/KDMENG.C1334
-rw-r--r--SRC/MAKEFILE23
-rw-r--r--SRC/MMULTI.C459
-rw-r--r--SRC/MULTI.C1124
-rw-r--r--SRC/NAMES.H49
-rw-r--r--SRC/PRAGMAS.H1934
-rw-r--r--SRC/SREADME.TXT185
-rw-r--r--SRC/VES2.H775
-rw-r--r--UTIL/BACKMAP5.C384
-rw-r--r--UTIL/BACKMAP6.C373
-rw-r--r--UTIL/CONVMAP6.C406
-rw-r--r--UTIL/CONVMAP7.C375
-rw-r--r--UTIL/EDITART.C4579
-rw-r--r--UTIL/KEXTRACT.C175
-rw-r--r--UTIL/KGROUP.C137
-rw-r--r--UTIL/SETUP.C722
-rw-r--r--UTIL/TRANSPAL.C281
-rw-r--r--UTIL/UREADME.TXT45
-rw-r--r--UTIL/WAD2ART.C309
-rw-r--r--UTIL/WAD2MAP.C1604
-rw-r--r--audiolib/AUDIO.MAK187
-rw-r--r--audiolib/AUDIO2.MAK192
-rw-r--r--audiolib/DOPUBLIC.BAT17
-rw-r--r--audiolib/GUS/GUSROTT.INI205
-rw-r--r--audiolib/GUS/UCALC.EXEbin0 -> 14312 bytes
-rw-r--r--audiolib/GUS/ULTRAMID.INI200
-rw-r--r--audiolib/LIB/GF1_OSF.LB2bin0 -> 108544 bytes
-rw-r--r--audiolib/LIB/GF1_OSF.LBKbin0 -> 101888 bytes
-rw-r--r--audiolib/LIB/GF1_OSF.LIBbin0 -> 101888 bytes
-rw-r--r--audiolib/LIB/PAWE32.LIBbin0 -> 50176 bytes
-rw-r--r--audiolib/MAKEDB.BAT2
-rw-r--r--audiolib/OBJ/ADLIBFX.OBJbin0 -> 5579 bytes
-rw-r--r--audiolib/OBJ/AL_MIDI.OBJbin0 -> 15941 bytes
-rw-r--r--audiolib/OBJ/AUDIO_WF.LIBbin0 -> 384000 bytes
-rw-r--r--audiolib/OBJ/AWE32.OBJbin0 -> 6096 bytes
-rw-r--r--audiolib/OBJ/BLASTER.OBJbin0 -> 20817 bytes
-rw-r--r--audiolib/OBJ/DEBUGIO.OBJbin0 -> 2150 bytes
-rw-r--r--audiolib/OBJ/DMA.OBJbin0 -> 2594 bytes
-rw-r--r--audiolib/OBJ/DPMI.OBJbin0 -> 1537 bytes
-rw-r--r--audiolib/OBJ/FX_MAN.OBJbin0 -> 8997 bytes
-rw-r--r--audiolib/OBJ/GMTIMBRE.OBJbin0 -> 3860 bytes
-rw-r--r--audiolib/OBJ/GUS.OBJbin0 -> 5491 bytes
-rw-r--r--audiolib/OBJ/GUSMIDI.OBJbin0 -> 9263 bytes
-rw-r--r--audiolib/OBJ/GUSWAVE.OBJbin0 -> 16682 bytes
-rw-r--r--audiolib/OBJ/IRQ.OBJbin0 -> 3235 bytes
-rw-r--r--audiolib/OBJ/LL_MAN.OBJbin0 -> 1047 bytes
-rw-r--r--audiolib/OBJ/MIDI.OBJbin0 -> 22215 bytes
-rw-r--r--audiolib/OBJ/MPU401.OBJbin0 -> 2705 bytes
-rw-r--r--audiolib/OBJ/MULTIVOC.OBJbin0 -> 31126 bytes
-rw-r--r--audiolib/OBJ/MUSIC.OBJbin0 -> 8867 bytes
-rw-r--r--audiolib/OBJ/MVREVERB.OBJbin0 -> 1248 bytes
-rw-r--r--audiolib/OBJ/MV_MIX.OBJbin0 -> 3971 bytes
-rw-r--r--audiolib/OBJ/MV_MIX16.OBJbin0 -> 4026 bytes
-rw-r--r--audiolib/OBJ/PAS16.OBJbin0 -> 17571 bytes
-rw-r--r--audiolib/OBJ/PCFX.OBJbin0 -> 5216 bytes
-rw-r--r--audiolib/OBJ/PITCH.OBJbin0 -> 2644 bytes
-rw-r--r--audiolib/OBJ/SNDSCAPE.OBJbin0 -> 16158 bytes
-rw-r--r--audiolib/OBJ/SNDSRC.OBJbin0 -> 6488 bytes
-rw-r--r--audiolib/OBJ/TASK_MAN.OBJbin0 -> 4663 bytes
-rw-r--r--audiolib/OBJ/USER.OBJbin0 -> 956 bytes
-rw-r--r--audiolib/OBJDB/AL_MIDI.OBJbin0 -> 22499 bytes
-rw-r--r--audiolib/OBJDB/AUDIO_WF.LIBbin0 -> 468480 bytes
-rw-r--r--audiolib/OBJDB/AWE32.OBJbin0 -> 9011 bytes
-rw-r--r--audiolib/OBJDB/BLASTER.OBJbin0 -> 30834 bytes
-rw-r--r--audiolib/OBJDB/DEBUGIO.OBJbin0 -> 4039 bytes
-rw-r--r--audiolib/OBJDB/DMA.OBJbin0 -> 4751 bytes
-rw-r--r--audiolib/OBJDB/DPMI.OBJbin0 -> 3799 bytes
-rw-r--r--audiolib/OBJDB/FX_MAN.OBJbin0 -> 16269 bytes
-rw-r--r--audiolib/OBJDB/GMTIMBRE.OBJbin0 -> 4333 bytes
-rw-r--r--audiolib/OBJDB/GUS.OBJbin0 -> 5491 bytes
-rw-r--r--audiolib/OBJDB/GUSMIDI.OBJbin0 -> 9263 bytes
-rw-r--r--audiolib/OBJDB/GUSWAVE.OBJbin0 -> 25335 bytes
-rw-r--r--audiolib/OBJDB/IRQ.OBJbin0 -> 5370 bytes
-rw-r--r--audiolib/OBJDB/LL_MAN.OBJbin0 -> 2135 bytes
-rw-r--r--audiolib/OBJDB/MIDI.OBJbin0 -> 30469 bytes
-rw-r--r--audiolib/OBJDB/MPU401.OBJbin0 -> 5372 bytes
-rw-r--r--audiolib/OBJDB/MULTIVOC.OBJbin0 -> 48473 bytes
-rw-r--r--audiolib/OBJDB/MUSIC.OBJbin0 -> 7702 bytes
-rw-r--r--audiolib/OBJDB/MVREVERB.OBJbin0 -> 1248 bytes
-rw-r--r--audiolib/OBJDB/MV_MIX.OBJbin0 -> 3971 bytes
-rw-r--r--audiolib/OBJDB/MV_MIX16.OBJbin0 -> 4026 bytes
-rw-r--r--audiolib/OBJDB/PAS16.OBJbin0 -> 17571 bytes
-rw-r--r--audiolib/OBJDB/PITCH.OBJbin0 -> 3690 bytes
-rw-r--r--audiolib/OBJDB/SNDSCAPE.OBJbin0 -> 22886 bytes
-rw-r--r--audiolib/OBJDB/SNDSRC.OBJbin0 -> 9761 bytes
-rw-r--r--audiolib/OBJDB/TASK_MAN.OBJbin0 -> 4663 bytes
-rw-r--r--audiolib/OBJDB/USER.OBJbin0 -> 1692 bytes
-rw-r--r--audiolib/PUBLIC/AUDIO_WF.LIBbin0 -> 381952 bytes
-rw-r--r--audiolib/PUBLIC/EMIDIAPI.TXT224
-rw-r--r--audiolib/PUBLIC/INCLUDE/AUDIO_WF.LIBbin0 -> 381952 bytes
-rw-r--r--audiolib/PUBLIC/INCLUDE/FX_MAN.H135
-rw-r--r--audiolib/PUBLIC/INCLUDE/MUSIC.H92
-rw-r--r--audiolib/PUBLIC/INCLUDE/SNDCARDS.H55
-rw-r--r--audiolib/PUBLIC/INCLUDE/TASK_MAN.H68
-rw-r--r--audiolib/PUBLIC/INCLUDE/USRHOOKS.C84
-rw-r--r--audiolib/PUBLIC/INCLUDE/USRHOOKS.H55
-rw-r--r--audiolib/PUBLIC/MIDI.TXT60
-rw-r--r--audiolib/PUBLIC/NOTES.TXT1713
-rw-r--r--audiolib/PUBLIC/PM/GMTIMBRE.TMBbin0 -> 3328 bytes
-rw-r--r--audiolib/PUBLIC/PM/MAKEFILE45
-rw-r--r--audiolib/PUBLIC/PM/MAKETMB.EXEbin0 -> 15014 bytes
-rw-r--r--audiolib/PUBLIC/PM/OBJ/PM.OBJbin0 -> 6712 bytes
-rw-r--r--audiolib/PUBLIC/PM/OBJ/USRHOOKS.OBJbin0 -> 630 bytes
-rw-r--r--audiolib/PUBLIC/PM/PM.EXEbin0 -> 343326 bytes
-rw-r--r--audiolib/PUBLIC/PM/PM.TXT37
-rw-r--r--audiolib/PUBLIC/PM/README.TXT31
-rw-r--r--audiolib/PUBLIC/PM/SOURCE/PM.C537
-rw-r--r--audiolib/PUBLIC/PM/SOURCE/USRHOOKS.C84
-rw-r--r--audiolib/PUBLIC/PM/SOURCE/USRHOOKS.H55
-rw-r--r--audiolib/PUBLIC/PM/TIMBRES.ZIPbin0 -> 6479 bytes
-rw-r--r--audiolib/PUBLIC/PS/BINDPS.BAT3
-rw-r--r--audiolib/PUBLIC/PS/MAKEFILE45
-rw-r--r--audiolib/PUBLIC/PS/PS.C410
-rw-r--r--audiolib/PUBLIC/PS/PS.EXEbin0 -> 342555 bytes
-rw-r--r--audiolib/PUBLIC/PS/PS.OBJbin0 -> 5054 bytes
-rw-r--r--audiolib/PUBLIC/PS/USRHOOKS.C84
-rw-r--r--audiolib/PUBLIC/PS/USRHOOKS.H55
-rw-r--r--audiolib/PUBLIC/PS/USRHOOKS.OBJbin0 -> 609 bytes
-rw-r--r--audiolib/PUBLIC/TIMER/MAKEFILE45
-rw-r--r--audiolib/PUBLIC/TIMER/OBJ/TIMER.OBJbin0 -> 2073 bytes
-rw-r--r--audiolib/PUBLIC/TIMER/OBJ/USRHOOKS.OBJbin0 -> 707 bytes
-rw-r--r--audiolib/PUBLIC/TIMER/SOURCE/TIMER.C149
-rw-r--r--audiolib/PUBLIC/TIMER/SOURCE/USRHOOKS.C84
-rw-r--r--audiolib/PUBLIC/TIMER/SOURCE/USRHOOKS.H55
-rw-r--r--audiolib/PUBLIC/TIMER/TIMER.EXEbin0 -> 183377 bytes
-rw-r--r--audiolib/SOURCE/ADLIBFX.C552
-rw-r--r--audiolib/SOURCE/ADLIBFX.H80
-rw-r--r--audiolib/SOURCE/AL_MIDI.C1510
-rw-r--r--audiolib/SOURCE/AL_MIDI.H58
-rw-r--r--audiolib/SOURCE/ASSERT.H45
-rw-r--r--audiolib/SOURCE/AWE32.C540
-rw-r--r--audiolib/SOURCE/AWE32.H58
-rw-r--r--audiolib/SOURCE/BLASTER.C2330
-rw-r--r--audiolib/SOURCE/BLASTER.H148
-rw-r--r--audiolib/SOURCE/BLASTOLD.C2415
-rw-r--r--audiolib/SOURCE/CTAWEAPI.H352
-rw-r--r--audiolib/SOURCE/CTAWEAPI.INC88
-rw-r--r--audiolib/SOURCE/DEBUGIO.C251
-rw-r--r--audiolib/SOURCE/DEBUGIO.H30
-rw-r--r--audiolib/SOURCE/DMA.C379
-rw-r--r--audiolib/SOURCE/DMA.H83
-rw-r--r--audiolib/SOURCE/DPMI.C250
-rw-r--r--audiolib/SOURCE/DPMI.H100
-rw-r--r--audiolib/SOURCE/FX_MAN.C1336
-rw-r--r--audiolib/SOURCE/FX_MAN.H135
-rw-r--r--audiolib/SOURCE/GMTEMP.C289
-rw-r--r--audiolib/SOURCE/GMTIMBRE.C290
-rw-r--r--audiolib/SOURCE/GMTMBOLD.C248
-rw-r--r--audiolib/SOURCE/GUS.C283
-rw-r--r--audiolib/SOURCE/GUSMIDI.C561
-rw-r--r--audiolib/SOURCE/GUSMIDI.H59
-rw-r--r--audiolib/SOURCE/GUSMIDI2.C745
-rw-r--r--audiolib/SOURCE/GUSMIDI2.H56
-rw-r--r--audiolib/SOURCE/GUSWAVE.C1773
-rw-r--r--audiolib/SOURCE/GUSWAVE.H75
-rw-r--r--audiolib/SOURCE/INTERRUP.H48
-rw-r--r--audiolib/SOURCE/IRQ.C325
-rw-r--r--audiolib/SOURCE/IRQ.H54
-rw-r--r--audiolib/SOURCE/LEEOLD.C330
-rw-r--r--audiolib/SOURCE/LEETIMB1.C330
-rw-r--r--audiolib/SOURCE/LEETIMBR.C290
-rw-r--r--audiolib/SOURCE/LINKLIST.H118
-rw-r--r--audiolib/SOURCE/LL_MAN.C173
-rw-r--r--audiolib/SOURCE/LL_MAN.H76
-rw-r--r--audiolib/SOURCE/MEMCHECK.H20
-rw-r--r--audiolib/SOURCE/MIDI.C2265
-rw-r--r--audiolib/SOURCE/MIDI.H98
-rw-r--r--audiolib/SOURCE/MPU401.C451
-rw-r--r--audiolib/SOURCE/MPU401.H61
-rw-r--r--audiolib/SOURCE/MULTIVOC.C3452
-rw-r--r--audiolib/SOURCE/MULTIVOC.H120
-rw-r--r--audiolib/SOURCE/MUSIC.C1035
-rw-r--r--audiolib/SOURCE/MUSIC.H92
-rw-r--r--audiolib/SOURCE/MV1.C2132
-rw-r--r--audiolib/SOURCE/MVREVERB.ASM181
-rw-r--r--audiolib/SOURCE/MV_MIX.ASM505
-rw-r--r--audiolib/SOURCE/MV_MIX1.ASM91
-rw-r--r--audiolib/SOURCE/MV_MIX16.ASM524
-rw-r--r--audiolib/SOURCE/MV_MIX2.ASM122
-rw-r--r--audiolib/SOURCE/MV_MIX3.ASM617
-rw-r--r--audiolib/SOURCE/MV_MIX4.ASM680
-rw-r--r--audiolib/SOURCE/MV_MIX5.ASM680
-rw-r--r--audiolib/SOURCE/MV_MIX6.ASM683
-rw-r--r--audiolib/SOURCE/MYPRINT.C310
-rw-r--r--audiolib/SOURCE/MYPRINT.H43
-rw-r--r--audiolib/SOURCE/NEWGF1.H431
-rw-r--r--audiolib/SOURCE/OLDTIMBR.C248
-rw-r--r--audiolib/SOURCE/PAS16.C1924
-rw-r--r--audiolib/SOURCE/PAS16.H81
-rw-r--r--audiolib/SOURCE/PCFX.C547
-rw-r--r--audiolib/SOURCE/PCFX.H69
-rw-r--r--audiolib/SOURCE/PITCH.C258
-rw-r--r--audiolib/SOURCE/PITCH.H45
-rw-r--r--audiolib/SOURCE/SNDCARDS.H55
-rw-r--r--audiolib/SOURCE/SNDSCAPE.C1661
-rw-r--r--audiolib/SOURCE/SNDSCAPE.H73
-rw-r--r--audiolib/SOURCE/SNDSRC.C658
-rw-r--r--audiolib/SOURCE/SNDSRC.H70
-rw-r--r--audiolib/SOURCE/STANDARD.H72
-rw-r--r--audiolib/SOURCE/TASK_MAN.C976
-rw-r--r--audiolib/SOURCE/TASK_MAN.H68
-rw-r--r--audiolib/SOURCE/USER.C120
-rw-r--r--audiolib/SOURCE/USER.H38
-rw-r--r--audiolib/SOURCE/USRHOOKS.C84
-rw-r--r--audiolib/SOURCE/USRHOOKS.H55
-rw-r--r--audiolib/SOURCE/_AL_MIDI.H174
-rw-r--r--audiolib/SOURCE/_BLASTER.H133
-rw-r--r--audiolib/SOURCE/_GUSWAVE.H164
-rw-r--r--audiolib/SOURCE/_MIDI.H290
-rw-r--r--audiolib/SOURCE/_MULTIVC.H276
-rw-r--r--audiolib/SOURCE/_PAS16.H250
-rw-r--r--audiolib/SOURCE/_SNDSCAP.H136
-rw-r--r--audiolib/WMAKE.BAT2
-rw-r--r--audiolib/gpl.txt342
-rw-r--r--audiolib/readme.txt84
-rw-r--r--extras/ACTORS.C7138
-rw-r--r--extras/ANGLES.H36
-rw-r--r--extras/ANIMLIB.C342
-rw-r--r--extras/ANIMLIB.H157
-rw-r--r--extras/AVG.H60
-rw-r--r--extras/BB.C361
-rw-r--r--extras/CAVE.C2120
-rw-r--r--extras/CD.C895
-rw-r--r--extras/CDROM.H99
-rw-r--r--extras/CLRMAP.H207
-rw-r--r--extras/COMMON.H125
-rw-r--r--extras/CONFIG.C736
-rw-r--r--extras/CONFIG.H56
-rw-r--r--extras/CONTROL.H216
-rw-r--r--extras/CRC.H41
-rw-r--r--extras/DEBUG.C145
-rw-r--r--extras/DEBUG.H125
-rw-r--r--extras/DEBUG4G.C202
-rw-r--r--extras/DEBUG4G.H55
-rw-r--r--extras/DEVELOP.H67
-rw-r--r--extras/DUKE3D.H548
-rw-r--r--extras/DYN.H67
-rw-r--r--extras/ERROR.H29
-rw-r--r--extras/EXTERNAL.H66
-rw-r--r--extras/FILE_LIB.H262
-rw-r--r--extras/FIXED.H291
-rw-r--r--extras/FRAGMENT.C251
-rw-r--r--extras/FUNCT.H584
-rw-r--r--extras/FUNCTION.C196
-rw-r--r--extras/FUNCTION.H105
-rw-r--r--extras/FX_MAN.H132
-rw-r--r--extras/GAME.C9741
-rw-r--r--extras/GAMEDEF.C3211
-rw-r--r--extras/GAMEDEFS.H195
-rw-r--r--extras/GAMEN.C251
-rw-r--r--extras/GAMERBG.H468
-rw-r--r--extras/GIFLIB.H53
-rw-r--r--extras/GIFSAVE.H64
-rw-r--r--extras/GLOBAL.C173
-rw-r--r--extras/GNU.TXT87
-rw-r--r--extras/GRUNT.C530
-rw-r--r--extras/INTERCEP.H426
-rw-r--r--extras/INTERRUP.H49
-rw-r--r--extras/JOYSTICK.H65
-rw-r--r--extras/KEYBOARD.H226
-rw-r--r--extras/LBMLIB.H68
-rw-r--r--extras/LINKLIST.H127
-rw-r--r--extras/LOCATION.H53
-rw-r--r--extras/LUMPTYPE.H222
-rw-r--r--extras/MATH.C180
-rw-r--r--extras/MATHUTIL.H36
-rw-r--r--extras/MENUES.C3512
-rw-r--r--extras/MIPMAP.H49
-rw-r--r--extras/MOUSE.H53
-rw-r--r--extras/MUSIC.H90
-rw-r--r--extras/NAMES.H754
-rw-r--r--extras/PENTTIME.H50
-rw-r--r--extras/PLAYER.C4338
-rw-r--r--extras/PLAYERN.C456
-rw-r--r--extras/PRAGMAS.H1962
-rw-r--r--extras/PRECISE.H41
-rw-r--r--extras/PREMAP.C1555
-rw-r--r--extras/RANDOM.H56
-rw-r--r--extras/RGAME.H472
-rw-r--r--extras/RGB.H70
-rw-r--r--extras/ROX.H64
-rw-r--r--extras/RTS.C241
-rw-r--r--extras/RTS.H86
-rw-r--r--extras/SCRIPLIB.H357
-rw-r--r--extras/SE40.C161
-rw-r--r--extras/SECTOR.C3225
-rw-r--r--extras/SNDCARDS.H53
-rw-r--r--extras/SOUNDEFS.H1233
-rw-r--r--extras/SOUNDS.C672
-rw-r--r--extras/SOUNDS.H55
-rw-r--r--extras/STREAM.H73
-rw-r--r--extras/TASK_MAN.H66
-rw-r--r--extras/TESTDRV.C57
-rw-r--r--extras/TIMELIB.H41
-rw-r--r--extras/TIMER.H51
-rw-r--r--extras/TOKENLIB.H260
-rw-r--r--extras/TYPES.H104
-rw-r--r--extras/USRHOOKS.C82
-rw-r--r--extras/USRHOOKS.H51
-rw-r--r--extras/UTIL_LIB.H69
-rw-r--r--extras/VECTOR.H77
-rw-r--r--extras/VESA.H38
-rw-r--r--extras/VID.H113
-rw-r--r--extras/WAD.H86
-rw-r--r--extras/WAD2.H87
-rw-r--r--extras/WAD2TYPE.H77
-rw-r--r--extras/WADTYPE.H70
-rw-r--r--extras/WATER.C86
-rw-r--r--extras/_ANIMLIB.H44
-rw-r--r--extras/_CLRMAP.H100
-rw-r--r--extras/_CONTROL.H293
-rw-r--r--extras/_DEBUG.H47
-rw-r--r--extras/_FILELIB.H47
-rw-r--r--extras/_FUNCTIO.H249
-rw-r--r--extras/_KEYBOAR.H73
-rw-r--r--extras/_LBMLIB.H97
-rw-r--r--extras/_RANDOM.H306
-rw-r--r--extras/_ROX.H126
-rw-r--r--extras/_RTS.H56
-rw-r--r--extras/_SCRPLIB.H207
-rw-r--r--extras/_TOKENLI.H60
-rw-r--r--extras/_UTIL_LB.H47
-rw-r--r--extras/_WAD.H48
-rw-r--r--extras/_ZONE.H77
-rw-r--r--extras/_ZONEOLD.H77
-rw-r--r--kenbuild_data/NAMES.H49
-rw-r--r--kenbuild_data/STUFF.DATbin0 -> 840714 bytes
-rw-r--r--kenbuild_data/ascboard.mapbin0 -> 76522 bytes
-rw-r--r--kenbuild_data/boards.mapbin0 -> 12402 bytes
-rw-r--r--kenbuild_data/evilal.mapbin0 -> 17946 bytes
-rw-r--r--kenbuild_data/kensig.mapbin0 -> 9250 bytes
-rw-r--r--kenbuild_data/nsnoal.mapbin0 -> 324642 bytes
-rw-r--r--kenbuild_data/nukeland.mapbin0 -> 50394 bytes
-rw-r--r--source/A.OBJbin0 -> 10879 bytes
-rw-r--r--source/ACTORS.C7136
-rw-r--r--source/ANIMLIB.C340
-rw-r--r--source/ANIMLIB.H155
-rw-r--r--source/AUDIO_WF.LIBbin0 -> 384000 bytes
-rw-r--r--source/BUILD.H287
-rw-r--r--source/BUTWCD4.LIBbin0 -> 33280 bytes
-rw-r--r--source/CACHE1D.OBJbin0 -> 10646 bytes
-rw-r--r--source/CONFIG.C734
-rw-r--r--source/CONFIG.H54
-rw-r--r--source/CONTROL.H214
-rw-r--r--source/DEVELOP.H65
-rw-r--r--source/DUKE3D.H546
-rw-r--r--source/ENGINE.OBJbin0 -> 197095 bytes
-rw-r--r--source/FILE_LIB.H260
-rw-r--r--source/FUNCT.H582
-rw-r--r--source/FUNCTION.H103
-rw-r--r--source/FX_MAN.H130
-rw-r--r--source/GAME.C9786
-rw-r--r--source/GAMEDEF.C3215
-rw-r--r--source/GAMEDEFS.H193
-rw-r--r--source/GLOBAL.C174
-rw-r--r--source/GNU.TXT87
-rw-r--r--source/KEYBOARD.H224
-rw-r--r--source/MAKEFILE38
-rw-r--r--source/MAKEFILE.LNK8
-rw-r--r--source/MENUES.C3535
-rw-r--r--source/MMULTI.OBJbin0 -> 5343 bytes
-rw-r--r--source/MOUSE.H51
-rw-r--r--source/MUSIC.H88
-rw-r--r--source/NAMES.H752
-rw-r--r--source/PLAYER.C4336
-rw-r--r--source/PRAGMAS.H1960
-rw-r--r--source/PREMAP.C1563
-rw-r--r--source/RTS.C239
-rw-r--r--source/RTS.H84
-rw-r--r--source/SCRIPLIB.H355
-rw-r--r--source/SECTOR.C3223
-rw-r--r--source/SNDCARDS.H51
-rw-r--r--source/SOUNDEFS.H1231
-rw-r--r--source/SOUNDS.C672
-rw-r--r--source/SOUNDS.H53
-rw-r--r--source/TASK_MAN.H64
-rw-r--r--source/TYPES.H102
-rw-r--r--source/UTIL_LIB.H67
-rw-r--r--source/_ANIMLIB.H42
-rw-r--r--source/_FUNCTIO.H247
-rw-r--r--source/_RTS.H54
-rw-r--r--source/duke3d.tgt1072
-rw-r--r--source/duke3d.wpj43
-rw-r--r--source/mact/GNU.TXT87
-rw-r--r--source/mact/MACT386.LIBbin0 -> 138752 bytes
-rw-r--r--testdata/DEFS.CON1239
-rw-r--r--testdata/GAME.CON8554
-rw-r--r--testdata/GNU.TXT87
-rw-r--r--testdata/LOOKUP.DATbin0 -> 10266 bytes
-rw-r--r--testdata/USER.CON965
403 files changed, 204639 insertions, 0 deletions
diff --git a/GNU.TXT b/GNU.TXT
new file mode 100644
index 0000000..2f3289a
--- /dev/null
+++ b/GNU.TXT
@@ -0,0 +1,87 @@
+GNU GENERAL PUBLIC LICENSE
+Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+Preamble
+The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
+
+We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
+
+Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
+
+Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
+
+The precise terms and conditions for copying, distribution and modification follow.
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
+
+1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
+
+
+a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
+
+b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
+
+c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
+These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
+Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
+
+3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
+
+a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
+
+b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
+
+c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
+The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
+If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
+
+4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
+
+5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
+
+6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
+
+7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
+
+This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
+
+8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
+
+9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
+
+10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
+
+NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+
+END OF TERMS AND CONDITIONS
diff --git a/README.TXT b/README.TXT
new file mode 100644
index 0000000..abf0da8
--- /dev/null
+++ b/README.TXT
@@ -0,0 +1,114 @@
+===================================================================
+Duke Nukem 3D (v1.5 CD Version) Source Code Release - April 1, 2003
+===================================================================
+
+LEGAL STUFF
+-----------
+
+"Duke Nukem" is a registered trademark of Apogee Software, Ltd. (a.k.a. 3D Realms).
+"Duke Nukem 3D" copyright 1996 - 2003 3D Realms. All trademarks and copyrights reserved.
+
+This is the complete source code for Duke Nukem 3D version 1.5, buildable as detailed in the next section.
+
+The code is licensed under the terms of the GPL (gnu public license). You should read the entire license (filename "GNU.TXT" in this archive), so you understand your rights and what you can and cannot do with the source code from this release.
+
+All of the Duke Nukem 3D data files remain copyrighted and licensed by 3D Realms under the original terms. You cannot redistribute our data or data files from the original game. You can use our data for personal entertainment or educational purposes. If you need the data, you can order a Duke Nukem 3D CD from our store on our website.
+
+Please do not contact us for possible commercial exploitation of Duke Nukem 3D -- we will not be interested.
+
+Please note that this is being released without any kind of support from Apogee Software, Ltd / 3D Realms Entertainment. We cannot help in getting this running and we do not guarantee that you will be able to get it to work, nor do we guarantee that it won't blow up your computer if you do try and use it. Use at your own risk.
+
+SPECIAL THANKS
+--------------
+
+First, we'd like to thank all the fans of 3D Realms and Duke Nukem. We wouldn't be where we are without you and without your support.
+
+Second, we'd like to thank Charlie Wiederhold for putting this release together. We had decided some time ago to release the source code, but people are busy and it always seemed to be low priority. A couple of weeks ago, Charlie got a source archive from Scott, and came back a few days later with it all compiling.
+
+Thanks also to Ken Silverman and Jim Dose for allowing us to include some of their source in this build, so we have it all in one archive.
+
+Finally, we'd like to thank the whole Duke Nukem Forever team. These guys are all working incredibly hard on the next installment of Duke Nukem.
+
+Enjoy the source code. We can't wait to see what people do with it. And we really look forward to being able to play the game under XP, with sound, internet play, hardware acceleration and whatever else you're clever enough to put in :)
+
+George Broussard & Scott Miller
+3D Realms
+
+======================================================
+HOW TO COMPILE THE SOURCE CODE (by Charlie Wiederhold)
+======================================================
+
+This source code release was compiled on March 20th, 2003 using the materials in this archive.
+
+Duke was originally written with the Watcom 10.0 C/C++ compiler. This code has been updated to allow it to compile under the free version of the Watcom compiler available from their webpage (http://www.openwatcom.org).
+
+It was compiled under both Open Watcom 1.0 and Watcom 11.0c for Windows. Both are free to download, and I didn't notice much of a difference between the two when using them. This means, thankfully, that anybody can work with this code right away without trying to find an out of production compiler or wait for someone to port it to other modern compilers.
+
+Step 1) Install Watcom C/C++ onto your system.
+
+Step 2) When you install, make sure that you select DOS 32 Bit as one of your target environments to build for.
+
+Step 3) Choose a place you want to work from and unzip the contents of this .ZIP file into that directory.
+
+From here you have two choices on how to work. You can use the command line compiler that comes with Watcom, or you can use the IDE (basically the development studio that manages your files, options for compiling, editing files, debugger, etc). Whichever one you choose depends on what you are comfortable with.
+
+IF YOU USE THE COMMAND LINE COMPILER
+------------------------------------
+
+- In a Command Prompt, go into the Source directory where you should find a MAKEFILE. and a MAKEFILE.LNK file.
+- At the Command Prompt type "wmake" or "wmake makefile" without the quotes.
+- This should compile and create a DUKE3D.EXE file which you can then copy into the directory with your Duke 3D data and run.
+
+IF YOU USE THE IDE
+------------------
+
+- Start up the Watcom IDE and go to File -> Open Project.
+- Find the directory where you've unzipped the Source files into, and you should see a DUKE3D.WPJ, select this and hit "OK".
+- Click the "Make Current Target" button, or press "F4" or go to the menu Targets -> Make. You'll see lots of Warnings as it compiles, that's normal.
+- This will create a DUKE3D.EXE file in the same directory where the DUKE3D.WPJ was located, which can then be copied in the directory with your Duke 3D data and run.
+
+ONCE YOU HAVE DUKE3D.EXE COMPILED
+---------------------------------
+
+- If you own Duke 3D version 1.5, you are set... simply copy your new .EXE into the directory and run it.
+- If you own Duke 3D version 1.4 or 1.3d, follow the same steps below except don't download the shareware data.
+- If you own neither versions: Download the shareware version of Duke 3D from http://www.3drealms.com (go to Downloads).
+- In the directory you have Duke 3D installed now, copy the four files in the TESTDATA directory into your Duke 3D directory. Now you should be able to play the game well enough to test, though unfortunately there will still be some minor issues. Your best results will come from owning a copy of Duke 3D version 1.5, which can still be purchased from the 3D Realms website.
+
+This should be enough to get you started. Unfortunately nobody at 3D Realms will be able to devote the time to answer any support questions if you do encounter problems. However, go to http://www.3drealms.com/forums.html and you will find people discussing the source code in the Duke 3D Source category and able to answer questions. I will try to answer extremely common questions there shortly after the release, but I promise, within a very short time the community will outgrow my knowledge/understanding of this source and be better suited to answer any questions itself.
+
+MISC NOTES ABOUT THIS RELEASE
+-----------------------------
+
+- All changes I made from the original are indicated by a "// CTW" style comment. In all but one case I commented out the original code so that it would still be there. I made as few changes as possible since the fun for people is working on the Duke 3D original code, not my personal rewrite/interpretation.
+
+- Unfortunately the source to the SETUP.EXE and SETMAIN.EXE programs used for creating setup configuration files for Duke 3D is nowhere to be found, so if you need a setup utility to create custom .CFG files you'll need to write your own. If we find the source code we'll update this release to include that as well. The code to read .CFG files is within the Duke 3D CONFIG.C source itself, so it gives you something to start with.
+
+- This source includes the Build Engine data (.OBJ files) needed for compiling. The Build Engine is a seperate entity from Duke 3D, though Duke 3D is built upon the Build Engine.
+
+- The BUILDENGINE.ZIP file contains all of the data you need from Ken Silverman's released version to compile the Build Engine itself. Instructions for doing this are contained within that file. I have tested this with the free versions of Watcom and it works. More information about this code at Ken's webpage here: http://www.advsys.net/ken/buildsrc/default.htm
+
+- The AUDIOLIB.ZIP file contains all of the data you need from Jim Dose's sound engine that was used in both Rise of the Triad and Duke 3D to compile the actual Audio Library itself. Instructions for doing this are contained in that file. I have not tested this personally to see if it compiles under the free version of Watcom.
+
+- Sound will be sketchy if you are on any modern system. It does work, but only as well as the original Duke 3D's does.
+
+- Networking works. Scott Miller and I fired up a quick game and it worked fine. The only catch is you need to disable sound for this to work in modern systems. No testing over a modem was done.
+
+- The original .DMO demo files do not work. However recording new ones and playing those back does work, sometimes. I've disabled playback of demos in the source for stability when people first try to run their compiled version. It shouldn't be too hard to find how to re-enable it for those who want to go in and fix it.
+
+- If you would like to play Duke 3D in high res Vesa modes instead of 320x200, download Ken's utility here: http://www.advsys.net/ken/build.htm
+
+- The files in the EXTRAS folder are there purely for curiosity and educational purposes. Things like Allen Blum's experiments with room over room can be found in there, as well as older versions of the source files that ultimately made it into the game. None of these are necessary and are purely, well, extra.
+
+- Duke 3D used DOS/4GW for it's DOS Extender. Watcom 1.0/11.0c comes with a couple free DOS Extenders, however you will need to bind it to the extender in order to distribute the EXE you create to other computers where it wasn't compiled. How you do this depends on which extender you choose to use. I trust that once you get to the point of distributing an EXE you can figure out how to bind it to the extender. Since DOS/4GW was a commercial licensed product, we can't distribute the resources we used to do this.
+
+- All references to TEN (Total Entertainment Network) have been commented out of the version that will be compiled, but left in for the curious to look at.
+
+- This page was an invaluable learning tool for me when working on preparing the source code for release: http://www.clipx.net/ ... The actual information I used can be found here: http://www.clipx.net/ng/zcpp/index.php
+
+- I started working on this having no knowledge of Watcom, DOS based C programming, etc. and got it up and going within a night (and a half...ish) after work hours. So if you have a basic understanding of programming, you shouldn't have much trouble getting this up and running.
+
+- The first things I think everyone would like to see done is an update to the sound engine and an update to the networking to allow play over the internet. But there is no end to the changes people can make, so everyone at 3D Realms looks forward to what people will do now that the source code is finally out there. It's been a long time coming (too long probably), but here you go, have fun!
+
+Charlie Wiederhold
+3D Realms
diff --git a/SRC/A.ASM b/SRC/A.ASM
new file mode 100644
index 0000000..973906b
--- /dev/null
+++ b/SRC/A.ASM
@@ -0,0 +1,2420 @@
+; "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
+; Ken Silverman's official web site: "http://www.advsys.net/ken"
+; See the included license file "BUILDLIC.TXT" for license info.
+
+.586P
+.8087
+;include mmx.inc ;Include this if using < WATCOM 11.0 WASM
+
+;Warning: IN THIS FILE, ALL SEGMENTS ARE REMOVED. THIS MEANS THAT DS:[]
+;MUST BE ADDED FOR ALL SELF-MODIFIES FOR MASM TO WORK.
+;
+;WASM PROBLEMS:
+; 1. Requires all scaled registers (*1,*2,*4,*8) to be last thing on line
+; 2. Using 'DATA' is nice for self-mod. code, but WDIS only works with 'CODE'
+;
+;MASM PROBLEMS:
+; 1. Requires DS: to be written out for self-modifying code to work
+; 2. Doesn't encode short jumps automatically like WASM
+; 3. Stupidly adds wait prefix to ffree's
+
+EXTRN _asm1 : dword
+EXTRN _asm2 : dword
+EXTRN _asm3 : dword
+EXTRN _asm4 : dword
+EXTRN _reciptable : near
+EXTRN _fpuasm : dword
+EXTRN _globalx3 : dword
+EXTRN _globaly3 : dword
+EXTRN _ylookup : near
+
+EXTRN _vplce : near
+EXTRN _vince : near
+EXTRN _palookupoffse : near
+EXTRN _bufplce : near
+
+EXTRN _ebpbak : dword
+EXTRN _espbak : dword
+
+EXTRN _pow2char : near
+EXTRN _pow2long : near
+
+CODE SEGMENT PUBLIC USE32 'DATA'
+ASSUME cs:CODE,ds:CODE
+
+ALIGN 16
+PUBLIC sethlinesizes_
+sethlinesizes_:
+ mov byte ptr [machxbits1+2], al
+ mov byte ptr [machxbits2+2], al
+ mov byte ptr [machxbits3+2], al
+ neg al
+ mov byte ptr [hxsiz1+2], al
+ mov byte ptr [hxsiz2+2], al
+ mov byte ptr [hxsiz3+2], al
+ mov byte ptr [hxsiz4+2], al
+ mov byte ptr [machnegxbits1+2], al
+
+ mov byte ptr [hysiz1+3], bl
+ mov byte ptr [hysiz2+3], bl
+ mov byte ptr [hysiz3+3], bl
+ mov byte ptr [hysiz4+3], bl
+ mov byte ptr [hmach3a+2], bl
+ mov byte ptr [hmach3b+2], bl
+ mov byte ptr [hmach3c+2], bl
+ mov byte ptr [hmach3d+2], bl
+
+ mov dword ptr [hoffs1+2], ecx
+ mov dword ptr [hoffs2+2], ecx
+ mov dword ptr [hoffs3+2], ecx
+ mov dword ptr [hoffs4+2], ecx
+ mov dword ptr [hoffs5+2], ecx
+ mov dword ptr [hoffs6+2], ecx
+ mov dword ptr [hoffs7+2], ecx
+ mov dword ptr [hoffs8+2], ecx
+
+ mov edx, -1
+ mov cl, al
+ sub cl, bl
+ shr edx, cl
+ mov dword ptr [hmach2a+1], edx
+ mov dword ptr [hmach2b+1], edx
+ mov dword ptr [hmach2c+1], edx
+ mov dword ptr [hmach2d+1], edx
+
+ ret
+
+ALIGN 16
+PUBLIC prosethlinesizes_
+prosethlinesizes_:
+ mov dword ptr [prohbuf-4], ecx
+ neg eax
+ mov ecx, eax
+ sub eax, ebx
+ mov byte ptr [prohshru-1], al ;bl = 32-al-bl
+ mov eax, -1
+ shr eax, cl
+ mov ecx, ebx
+ shl eax, cl
+ mov dword ptr [prohand-4], eax ;((-1>>(-oal))<<obl)
+ neg ebx
+ mov byte ptr [prohshrv-1], bl ;bl = 32-bl
+ ret
+
+ALIGN 16
+PUBLIC setvlinebpl_
+setvlinebpl_:
+ mov dword ptr [fixchain1a+2], eax
+ mov dword ptr [fixchain1b+2], eax
+ mov dword ptr [fixchain1m+2], eax
+ mov dword ptr [fixchain1t+2], eax
+ mov dword ptr [fixchain1s+2], eax
+ mov dword ptr [mfixchain1s+2], eax
+ mov dword ptr [tfixchain1s+2], eax
+ mov dword ptr [fixchain2a+2], eax
+ mov dword ptr [profixchain2a+2], eax
+ mov dword ptr [fixchain2ma+2], eax
+ mov dword ptr [fixchain2mb+2], eax
+ mov dword ptr [fixchaint2a+1], eax
+ mov dword ptr [fixchaint2b+2], eax
+ mov dword ptr [fixchaint2c+2], eax
+ mov dword ptr [fixchaint2d+2], eax
+ mov dword ptr [fixchaint2e+2], eax
+ ret
+
+ALIGN 16
+PUBLIC setpalookupaddress_
+setpalookupaddress_:
+ mov dword ptr [pal1+2], eax
+ mov dword ptr [pal2+2], eax
+ mov dword ptr [pal3+2], eax
+ mov dword ptr [pal4+2], eax
+ mov dword ptr [pal5+2], eax
+ mov dword ptr [pal6+2], eax
+ mov dword ptr [pal7+2], eax
+ mov dword ptr [pal8+2], eax
+ ret
+
+ALIGN 16
+PUBLIC prosetpalookupaddress_
+prosetpalookupaddress_:
+ mov dword ptr [prohpala-4], eax
+ ret
+
+ALIGN 16
+PUBLIC setuphlineasm4_
+setuphlineasm4_:
+machxbits3: rol eax, 6 ;xbits
+ mov dword ptr [hmach4a+2], eax
+ mov dword ptr [hmach4b+2], eax
+ mov bl, al
+ mov dword ptr [hmach4c+2], eax
+ mov dword ptr [hmach4d+2], eax
+ mov dword ptr [hmach1a+2], ebx
+ mov dword ptr [hmach1b+2], ebx
+ mov dword ptr [hmach1c+2], ebx
+ mov dword ptr [hmach1d+2], ebx
+ ret
+
+ ;Non-256-stuffed ceiling&floor method with NO SHLD!:
+ ;yinc&0xffffff00 lea eax, [edx+88888800h] 1 1/2
+ ;ybits...xbits and edx, 88000088h 1 1/2
+ ;ybits rol edx, 6 2 1/2
+ ;xinc<<xbits add esi, 88888888h 1 1/2
+ ;xinc>>(32-xbits) adc al, 88h 1 1/2
+ ;bufplc mov cl, byte ptr [edx+88888888h] 1 1/2
+ ;paloffs&255 mov bl, byte ptr [ecx+88888888h] 1 1/2
+ALIGN 16
+PUBLIC hlineasm4_
+hlineasm4_:
+ push ebp
+
+ lea ebp, [eax+1]
+
+ cmp ebp, 8
+ jle shorthline
+
+ test edi, 1
+ jnz short skipthe1byte
+
+ mov eax, esi
+hxsiz1: shr eax, 26
+hysiz1: shld eax, edx, 6
+hoffs1: mov cl, byte ptr [eax+88888888h]
+pal1: mov bl, byte ptr [ecx+88888888h]
+ sub esi, _asm1
+ sub edx, _asm2
+ mov byte ptr [edi], bl
+ dec edi
+ dec ebp
+
+skipthe1byte:
+ test edi, 2
+ jnz short skipthe2byte
+
+ mov eax, esi
+hxsiz2: shr eax, 26
+hysiz2: shld eax, edx, 6
+hoffs2: mov cl, byte ptr [eax+88888888h]
+pal2: mov bh, byte ptr [ecx+88888888h]
+ sub esi, _asm1
+ sub edx, _asm2
+
+ mov eax, esi
+hxsiz3: shr eax, 26
+hysiz3: shld eax, edx, 6
+hoffs3: mov cl, byte ptr [eax+88888888h]
+pal3: mov bl, byte ptr [ecx+88888888h]
+ sub esi, _asm1
+ sub edx, _asm2
+ mov word ptr [edi-1], bx
+ sub edi, 2
+ sub ebp, 2
+
+skipthe2byte:
+
+ mov eax, esi
+machxbits1: shl esi, 6 ;xbits
+machnegxbits1: shr eax, 32-6 ;32-xbits
+ mov dl, al
+
+ inc edi
+
+ add ebx, ebx
+ mov eax, edx
+ jc beginhline64
+
+ mov eax, _asm1
+machxbits2: rol eax, 6 ;xbits
+ mov dword ptr [hmach4a+2], eax
+ mov dword ptr [hmach4b+2], eax
+ mov dword ptr [hmach4c+2], eax
+ mov dword ptr [hmach4d+2], eax
+ mov ebx, eax
+ mov eax, _asm2
+ mov al, bl
+ mov dword ptr [hmach1a+2], eax
+ mov dword ptr [hmach1b+2], eax
+ mov dword ptr [hmach1c+2], eax
+ mov dword ptr [hmach1d+2], eax
+
+ mov eax, edx
+ jmp beginhline64
+ALIGN 16
+prebeginhline64:
+ mov dword ptr [edi], ebx
+beginhline64:
+
+hmach3a: rol eax, 6
+hmach2a: and eax, 00008888h
+hmach4a: sub esi, 88888888h
+hmach1a: sbb edx, 88888888h
+ sub edi, 4
+hoffs4: mov cl, byte ptr [eax+88888888h]
+ mov eax, edx
+
+hmach3b: rol eax, 6
+hmach2b: and eax, 00008888h
+hmach4b: sub esi, 88888888h
+hmach1b: sbb edx, 88888888h
+pal4: mov bh, byte ptr [ecx+88888888h]
+hoffs5: mov cl, byte ptr [eax+88888888h]
+ mov eax, edx
+
+hmach3c: rol eax, 6
+pal5: mov bl, byte ptr [ecx+88888888h]
+hmach2c: and eax, 00008888h
+ shl ebx, 16
+hmach4c: sub esi, 88888888h
+hmach1c: sbb edx, 88888888h
+hoffs6: mov cl, byte ptr [eax+88888888h]
+
+ mov eax, edx
+ ;(
+
+hmach3d: rol eax, 6
+hmach2d: and eax, 00008888h
+hmach4d: sub esi, 88888888h
+hmach1d: sbb edx, 88888888h
+pal6: mov bh, byte ptr [ecx+88888888h]
+hoffs7: mov cl, byte ptr [eax+88888888h]
+ mov eax, edx
+ sub ebp, 4
+ nop
+pal7: mov bl, byte ptr [ecx+88888888h]
+ jnc prebeginhline64
+skipthe4byte:
+
+ test ebp, 2
+ jz skipdrawthe2
+ rol ebx, 16
+ mov word ptr [edi+2], bx
+ sub edi, 2
+skipdrawthe2:
+ test ebp, 1
+ jz skipdrawthe1
+ shr ebx, 24
+ mov byte ptr [edi+3], bl
+skipdrawthe1:
+
+ pop ebp
+ ret
+
+shorthline:
+ test ebp, ebp
+ jz endshorthline
+begshorthline:
+ mov eax, esi
+hxsiz4: shr eax, 26
+hysiz4: shld eax, edx, 6
+hoffs8: mov cl, byte ptr [eax+88888888h]
+pal8: mov bl, byte ptr [ecx+88888888h]
+ sub esi, _asm1
+ sub edx, _asm2
+ mov byte ptr [edi], bl
+ dec edi
+ dec ebp
+ jnz begshorthline
+endshorthline:
+ pop ebp
+ ret
+
+
+ ;eax: 00000000 00000000 00000000 temp----
+ ;ebx: 00000000 00000000 00000000 temp----
+ ;ecx: UUUUUUuu uuuuuuuu uuuuuuuu uuuuuuuu
+ ;edx: VVVVVVvv vvvvvvvv vvvvvvvv vvvvvvvv
+ ;esi: cnt----- -------- -------- --------
+ ;edi: vid----- -------- -------- --------
+ ;ebp: paloffs- -------- -------- --------
+ ;esp: ???????? ???????? ???????? ????????
+ALIGN 16
+PUBLIC prohlineasm4_
+prohlineasm4_:
+ push ebp
+
+ lea ebp, [ecx+88888888h]
+prohpala:
+ mov ecx, esi
+ lea esi, [eax+1]
+ sub edi, esi
+
+prohbeg:
+ mov eax, ecx
+ shr eax, 20
+prohshru:
+ mov ebx, edx
+ shr ebx, 26
+prohshrv:
+ and eax, 88888888h
+prohand:
+ movzx eax, byte ptr [eax+ebx+88888888h]
+prohbuf:
+ mov al, [eax+ebp]
+ sub ecx, _asm1
+ sub edx, _asm2
+ mov [edi+esi], al
+ dec esi
+ jnz prohbeg
+
+ pop ebp
+ ret
+
+
+
+ALIGN 16
+PUBLIC setupvlineasm_
+setupvlineasm_:
+ ;First 2 lines for VLINEASM1, rest for VLINEASM4
+ mov byte ptr [premach3a+2], al
+ mov byte ptr [mach3a+2], al
+
+ push ecx
+ mov byte ptr [machvsh1+2], al ;32-shy
+ mov byte ptr [machvsh3+2], al ;32-shy
+ mov byte ptr [machvsh5+2], al ;32-shy
+ mov byte ptr [machvsh6+2], al ;32-shy
+ mov ah, al
+ sub ah, 16
+ mov byte ptr [machvsh8+2], ah ;16-shy
+ neg al
+ mov byte ptr [machvsh7+2], al ;shy
+ mov byte ptr [machvsh9+2], al ;shy
+ mov byte ptr [machvsh10+2], al ;shy
+ mov byte ptr [machvsh11+2], al ;shy
+ mov byte ptr [machvsh12+2], al ;shy
+ mov cl, al
+ mov eax, 1
+ shl eax, cl
+ dec eax
+ mov dword ptr [machvsh2+2], eax ;(1<<shy)-1
+ mov dword ptr [machvsh4+2], eax ;(1<<shy)-1
+ pop ecx
+ ret
+
+ALIGN 16
+PUBLIC prosetupvlineasm_
+prosetupvlineasm_:
+ ;First 2 lines for VLINEASM1, rest for VLINEASM4
+ mov byte ptr [premach3a+2], al
+ mov byte ptr [mach3a+2], al
+
+ push ecx
+ mov byte ptr [promachvsh1+2], al ;32-shy
+ mov byte ptr [promachvsh3+2], al ;32-shy
+ mov byte ptr [promachvsh5+2], al ;32-shy
+ mov byte ptr [promachvsh6+2], al ;32-shy
+ mov ah, al
+ sub ah, 16
+ mov byte ptr [promachvsh8+2], ah ;16-shy
+ neg al
+ mov byte ptr [promachvsh7+2], al ;shy
+ mov byte ptr [promachvsh9+2], al ;shy
+ mov byte ptr [promachvsh10+2], al ;shy
+ mov byte ptr [promachvsh11+2], al ;shy
+ mov byte ptr [promachvsh12+2], al ;shy
+ mov cl, al
+ mov eax, 1
+ shl eax, cl
+ dec eax
+ mov dword ptr [promachvsh2+2], eax ;(1<<shy)-1
+ mov dword ptr [promachvsh4+2], eax ;(1<<shy)-1
+ pop ecx
+ ret
+
+ALIGN 16
+PUBLIC setupmvlineasm_
+setupmvlineasm_:
+ mov byte ptr [maskmach3a+2], al
+ mov byte ptr [machmv13+2], al
+ mov byte ptr [machmv14+2], al
+ mov byte ptr [machmv15+2], al
+ mov byte ptr [machmv16+2], al
+ ret
+
+ALIGN 16
+PUBLIC setuptvlineasm_
+setuptvlineasm_:
+ mov byte ptr [transmach3a+2], al
+ ret
+
+ALIGN 16
+PUBLIC prevlineasm1_
+prevlineasm1_:
+ test ecx, ecx
+ jnz vlineasm1_
+
+ add eax, edx
+premach3a: shr edx, 32
+ mov dl, byte ptr [esi+edx]
+ mov cl, byte ptr [ebx+edx]
+ mov byte ptr [edi], cl
+ ret
+
+ALIGN 16
+PUBLIC vlineasm1_
+vlineasm1_:
+ push ebp
+ mov ebp, ebx
+ inc ecx
+fixchain1a: sub edi, 320
+beginvline:
+ mov ebx, edx
+mach3a: shr ebx, 32
+fixchain1b: add edi, 320
+ mov bl, byte ptr [esi+ebx]
+ add edx, eax
+ dec ecx
+ mov bl, byte ptr [ebp+ebx]
+ mov byte ptr [edi], bl
+ jnz short beginvline
+ pop ebp
+ mov eax, edx
+ ret
+
+ALIGN 16
+PUBLIC mvlineasm1_ ;Masked vline
+mvlineasm1_:
+ push ebp
+ mov ebp, ebx
+beginmvline:
+ mov ebx, edx
+maskmach3a: shr ebx, 32
+ mov bl, byte ptr [esi+ebx]
+ cmp bl, 255
+ je short skipmask1
+maskmach3c: mov bl, [ebp+ebx]
+ mov byte ptr [edi], bl
+skipmask1:
+ add edx, eax
+fixchain1m: add edi, 320
+ sub ecx, 1
+ jnc short beginmvline
+
+ pop ebp
+ mov eax, edx
+ ret
+
+ALIGN 16
+PUBLIC fixtransluscence_
+fixtransluscence_:
+ mov dword ptr [transmach4+2], eax
+ mov dword ptr [tmach1+2], eax
+ mov dword ptr [tmach2+2], eax
+ mov dword ptr [tmach3+2], eax
+ mov dword ptr [tmach4+2], eax
+ mov dword ptr [tran2traa+2], eax
+ mov dword ptr [tran2trab+2], eax
+ mov dword ptr [tran2trac+2], eax
+ mov dword ptr [tran2trad+2], eax
+ ret
+
+ALIGN 16
+PUBLIC settransnormal_
+settransnormal_:
+ mov byte ptr [transrev0+1], 83h
+ mov byte ptr [transrev1+1], 27h
+ mov byte ptr [transrev2+1], 3fh
+ mov byte ptr [transrev3+1], 98h
+ mov byte ptr [transrev4+1], 90h
+ mov byte ptr [transrev5+1], 37h
+ mov byte ptr [transrev6+1], 90h
+ mov word ptr [transrev7+0], 0f38ah
+ mov byte ptr [transrev8+1], 90h
+ mov word ptr [transrev9+0], 0f78ah
+ mov byte ptr [transrev10+1], 0a7h
+ mov byte ptr [transrev11+1], 81h
+ mov byte ptr [transrev12+2], 9fh
+ mov word ptr [transrev13+0], 0dc88h
+ mov byte ptr [transrev14+1], 81h
+ mov byte ptr [transrev15+1], 9ah
+ mov byte ptr [transrev16+1], 0a7h
+ mov byte ptr [transrev17+1], 82h
+ ret
+
+ALIGN 16
+PUBLIC settransreverse_
+settransreverse_:
+ mov byte ptr [transrev0+1], 0a3h
+ mov byte ptr [transrev1+1], 7h
+ mov byte ptr [transrev2+1], 1fh
+ mov byte ptr [transrev3+1], 0b8h
+ mov byte ptr [transrev4+1], 0b0h
+ mov byte ptr [transrev5+1], 17h
+ mov byte ptr [transrev6+1], 0b0h
+ mov word ptr [transrev7+0], 0d38ah
+ mov byte ptr [transrev8+1], 0b0h
+ mov word ptr [transrev9+0], 0d78ah
+ mov byte ptr [transrev10+1], 87h
+ mov byte ptr [transrev11+1], 0a1h
+ mov byte ptr [transrev12+2], 87h
+ mov word ptr [transrev13+0], 0e388h
+ mov byte ptr [transrev14+1], 0a1h
+ mov byte ptr [transrev15+1], 0bah
+ mov byte ptr [transrev16+1], 87h
+ mov byte ptr [transrev17+1], 0a2h
+ ret
+
+ALIGN 16
+PUBLIC tvlineasm1_ ;Masked & transluscent vline
+tvlineasm1_:
+ push ebp
+ mov ebp, eax
+ xor eax, eax
+ inc ecx
+ mov dword ptr [transmach3c+2], ebx
+ jmp short begintvline
+ALIGN 16
+begintvline:
+ mov ebx, edx
+transmach3a: shr ebx, 32
+ mov bl, byte ptr [esi+ebx]
+ cmp bl, 255
+ je short skiptrans1
+transrev0:
+transmach3c: mov al, [ebx+88888888h]
+transrev1:
+ mov ah, byte ptr [edi]
+transmach4: mov al, byte ptr [eax+88888888h] ;_transluc[eax]
+ mov byte ptr [edi], al
+skiptrans1:
+ add edx, ebp
+fixchain1t: add edi, 320
+ dec ecx
+ jnz short begintvline
+
+ pop ebp
+ mov eax, edx
+ ret
+
+ ;eax: -------temp1-------
+ ;ebx: -------temp2-------
+ ;ecx: dat dat dat dat
+ ;edx: ylo2 ylo4
+ ;esi: yhi1 yhi2
+ ;edi: ---videoplc/cnt----
+ ;ebp: yhi3 yhi4
+ ;esp:
+ALIGN 16
+PUBLIC vlineasm4_
+vlineasm4_:
+ push ebp
+
+ mov eax, dword ptr _ylookup[ecx*4]
+ add eax, edi
+ mov dword ptr [machvline4end+2], eax
+ sub edi, eax
+
+ mov eax, dword ptr _bufplce[0]
+ mov ebx, dword ptr _bufplce[4]
+ mov ecx, dword ptr _bufplce[8]
+ mov edx, dword ptr _bufplce[12]
+ mov dword ptr [machvbuf1+2], ecx
+ mov dword ptr [machvbuf2+2], edx
+ mov dword ptr [machvbuf3+2], eax
+ mov dword ptr [machvbuf4+2], ebx
+
+ mov eax, dword ptr _palookupoffse[0]
+ mov ebx, dword ptr _palookupoffse[4]
+ mov ecx, dword ptr _palookupoffse[8]
+ mov edx, dword ptr _palookupoffse[12]
+ mov dword ptr [machvpal1+2], ecx
+ mov dword ptr [machvpal2+2], edx
+ mov dword ptr [machvpal3+2], eax
+ mov dword ptr [machvpal4+2], ebx
+
+ ; 旼컴컴컴컴컴컴컴쩡컴컴컴컴컴컴컴
+ ;edx: 퀆3lo 퀆1lo
+ ; 쳐컴컴컴컴컴컴컴좔컴컴컴쩡컴컴컴
+ ;esi: 퀆2hi v2lo v3hi
+ ; 쳐컴컴컴컴컴컴컴컴컴컴컴탠컴컴컴
+ ;ebp: 퀆0hi v0lo v1hi
+ ; 읕컴컴컴컴컴컴컴컴컴컴컴좔컴컴컴
+
+ mov ebp, dword ptr _vince[0]
+ mov ebx, dword ptr _vince[4]
+ mov esi, dword ptr _vince[8]
+ mov eax, dword ptr _vince[12]
+ and esi, 0fffffe00h
+ and ebp, 0fffffe00h
+machvsh9: rol eax, 88h ;sh
+machvsh10: rol ebx, 88h ;sh
+ mov edx, eax
+ mov ecx, ebx
+ shr ecx, 16
+ and edx, 0ffff0000h
+ add edx, ecx
+ and eax, 000001ffh
+ and ebx, 000001ffh
+ add esi, eax
+ add ebp, ebx
+ ;
+ mov eax, edx
+ and eax, 0ffff0000h
+ mov dword ptr [machvinc1+2], eax
+ mov dword ptr [machvinc2+2], esi
+ mov byte ptr [machvinc3+2], dl
+ mov byte ptr [machvinc4+2], dh
+ mov dword ptr [machvinc5+2], ebp
+
+ mov ebp, dword ptr _vplce[0]
+ mov ebx, dword ptr _vplce[4]
+ mov esi, dword ptr _vplce[8]
+ mov eax, dword ptr _vplce[12]
+ and esi, 0fffffe00h
+ and ebp, 0fffffe00h
+machvsh11: rol eax, 88h ;sh
+machvsh12: rol ebx, 88h ;sh
+ mov edx, eax
+ mov ecx, ebx
+ shr ecx, 16
+ and edx, 0ffff0000h
+ add edx, ecx
+ and eax, 000001ffh
+ and ebx, 000001ffh
+ add esi, eax
+ add ebp, ebx
+
+ mov ecx, esi
+ jmp short beginvlineasm4
+ALIGN 16
+ nop
+ nop
+ nop
+beginvlineasm4:
+machvsh1: shr ecx, 88h ;32-sh
+ mov ebx, esi
+machvsh2: and ebx, 00000088h ;(1<<sh)-1
+machvinc1: add edx, 88880000h
+machvinc2: adc esi, 88888088h
+machvbuf1: mov cl, byte ptr [ecx+88888888h]
+machvbuf2: mov bl, byte ptr [ebx+88888888h]
+ mov eax, ebp
+machvsh3: shr eax, 88h ;32-sh
+machvpal1: mov cl, byte ptr [ecx+88888888h]
+machvpal2: mov ch, byte ptr [ebx+88888888h]
+ mov ebx, ebp
+ shl ecx, 16
+machvsh4: and ebx, 00000088h ;(1<<sh)-1
+machvinc3: add dl, 88h
+machvbuf3: mov al, byte ptr [eax+88888888h]
+machvinc4: adc dh, 88h
+machvbuf4: mov bl, byte ptr [ebx+88888888h]
+machvinc5: adc ebp, 88888088h
+machvpal3: mov cl, byte ptr [eax+88888888h]
+machvpal4: mov ch, byte ptr [ebx+88888888h]
+machvline4end: mov dword ptr [edi+88888888h], ecx
+fixchain2a: add edi, 88888888h
+ mov ecx, esi
+ jnc short beginvlineasm4
+
+ ; 旼컴컴컴컴컴컴컴쩡컴컴컴컴컴컴컴
+ ;edx: 퀆3lo 퀆1lo
+ ; 쳐컴컴컴컴컴컴컴좔컴컴컴쩡컴컴컴
+ ;esi: 퀆2hi v2lo v3hi
+ ; 쳐컴컴컴컴컴컴컴컴컴컴컴탠컴컴컴
+ ;ebp: 퀆0hi v0lo v1hi
+ ; 읕컴컴컴컴컴컴컴컴컴컴컴좔컴컴컴
+
+ mov dword ptr _vplce[8], esi
+ mov dword ptr _vplce[0], ebp
+ ;vplc2 = (esi<<(32-sh))+(edx>>sh)
+ ;vplc3 = (ebp<<(32-sh))+((edx&65535)<<(16-sh))
+machvsh5: shl esi, 88h ;32-sh
+ mov eax, edx
+machvsh6: shl ebp, 88h ;32-sh
+ and edx, 0000ffffh
+machvsh7: shr eax, 88h ;sh
+ add esi, eax
+machvsh8: shl edx, 88h ;16-sh
+ add ebp, edx
+ mov dword ptr _vplce[12], esi
+ mov dword ptr _vplce[4], ebp
+
+ pop ebp
+ ret
+
+ ;eax: -------temp1-------
+ ;ebx: -------temp2-------
+ ;ecx: ylo4 ---------
+ ;edx: ylo2 ---------
+ ;esi: yhi1 yhi2
+ ;edi: ---videoplc/cnt----
+ ;ebp: yhi3 yhi4
+ ;esp:
+ALIGN 16
+PUBLIC provlineasm4_
+provlineasm4_:
+ push ebp
+
+ mov eax, dword ptr _ylookup[ecx*4]
+ add eax, edi
+ mov dword ptr [promachvline4end1+2], eax
+ inc eax
+ mov dword ptr [promachvline4end2+2], eax
+ inc eax
+ mov dword ptr [promachvline4end3+2], eax
+ inc eax
+ mov dword ptr [promachvline4end4+2], eax
+ sub eax, 3
+ sub edi, eax
+
+ mov eax, dword ptr _bufplce[0]
+ mov ebx, dword ptr _bufplce[4]
+ mov ecx, dword ptr _bufplce[8]
+ mov edx, dword ptr _bufplce[12]
+ mov dword ptr [promachvbuf1+3], ecx
+ mov dword ptr [promachvbuf2+3], edx
+ mov dword ptr [promachvbuf3+3], eax
+ mov dword ptr [promachvbuf4+3], ebx
+
+ mov eax, dword ptr _palookupoffse[0]
+ mov ebx, dword ptr _palookupoffse[4]
+ mov ecx, dword ptr _palookupoffse[8]
+ mov edx, dword ptr _palookupoffse[12]
+ mov dword ptr [promachvpal1+2], ecx
+ mov dword ptr [promachvpal2+2], edx
+ mov dword ptr [promachvpal3+2], eax
+ mov dword ptr [promachvpal4+2], ebx
+
+ ; 旼컴컴컴컴컴컴컴쩡컴컴컴컴컴컴컴
+ ;edx: 퀆3lo 퀆1lo
+ ; 쳐컴컴컴컴컴컴컴좔컴컴컴쩡컴컴컴
+ ;esi: 퀆2hi v2lo v3hi
+ ; 쳐컴컴컴컴컴컴컴컴컴컴컴탠컴컴컴
+ ;ebp: 퀆0hi v0lo v1hi
+ ; 읕컴컴컴컴컴컴컴컴컴컴컴좔컴컴컴
+
+ mov ebp, dword ptr _vince[0]
+ mov ebx, dword ptr _vince[4]
+ mov esi, dword ptr _vince[8]
+ mov eax, dword ptr _vince[12]
+ and esi, 0fffffe00h
+ and ebp, 0fffffe00h
+promachvsh9: rol eax, 88h ;sh
+promachvsh10: rol ebx, 88h ;sh
+ mov edx, eax
+ mov ecx, ebx
+ shr ecx, 16
+ and edx, 0ffff0000h
+ add edx, ecx
+ and eax, 000001ffh
+ and ebx, 000001ffh
+ add esi, eax
+ add ebp, ebx
+ ;
+ mov eax, edx
+ and eax, 0ffff0000h
+ mov dword ptr [promachvinc1+2], eax
+ mov dword ptr [promachvinc2+2], esi
+ shl edx, 16
+ mov dword ptr [promachvinc3+2], edx
+ mov dword ptr [promachvinc5+2], ebp
+
+ mov ebp, dword ptr _vplce[0]
+ mov ebx, dword ptr _vplce[4]
+ mov esi, dword ptr _vplce[8]
+ mov eax, dword ptr _vplce[12]
+ and esi, 0fffffe00h
+ and ebp, 0fffffe00h
+promachvsh11: rol eax, 88h ;sh
+promachvsh12: rol ebx, 88h ;sh
+ mov edx, eax
+ mov ecx, ebx
+ shr ecx, 16
+ and edx, 0ffff0000h
+ add edx, ecx
+ and eax, 000001ffh
+ and ebx, 000001ffh
+ add esi, eax
+ add ebp, ebx
+
+ mov eax, esi
+ mov ecx, edx
+ shl ecx, 16
+ jmp short probeginvlineasm4
+ALIGN 16
+ nop
+ nop
+ nop
+probeginvlineasm4:
+promachvsh1: shr eax, 88h ;32-sh
+ mov ebx, esi
+promachvsh2: and ebx, 00000088h ;(1<<sh)-1
+promachvinc1: add edx, 88880000h
+promachvinc2: adc esi, 88888088h
+promachvbuf1: movzx eax, byte ptr [eax+88888888h]
+promachvbuf2: movzx ebx, byte ptr [ebx+88888888h]
+promachvpal1: mov al, byte ptr [eax+88888888h]
+promachvline4end3: mov byte ptr [edi+88888888h], al
+ mov eax, ebp
+promachvsh3: shr eax, 88h ;32-sh
+promachvpal2: mov bl, byte ptr [ebx+88888888h]
+promachvline4end4: mov byte ptr [edi+88888888h], bl
+ mov ebx, ebp
+promachvsh4: and ebx, 00000088h ;(1<<sh)-1
+promachvbuf3: movzx eax, byte ptr [eax+88888888h]
+promachvinc3: add ecx, 88888888h
+promachvbuf4: movzx ebx, byte ptr [ebx+88888888h]
+promachvinc5: adc ebp, 88888088h
+promachvpal3: mov al, byte ptr [eax+88888888h]
+promachvline4end1: mov byte ptr [edi+88888888h], al
+promachvpal4: mov bl, byte ptr [ebx+88888888h]
+promachvline4end2: mov byte ptr [edi+88888888h], bl
+profixchain2a: add edi, 88888888h
+ mov eax, esi
+ jnc short probeginvlineasm4
+
+ ; 旼컴컴컴컴컴컴컴쩡컴컴컴컴컴컴컴
+ ;edx: 퀆3lo 퀆1lo
+ ; 쳐컴컴컴컴컴컴컴좔컴컴컴쩡컴컴컴
+ ;esi: 퀆2hi v2lo v3hi
+ ; 쳐컴컴컴컴컴컴컴컴컴컴컴탠컴컴컴
+ ;ebp: 퀆0hi v0lo v1hi
+ ; 읕컴컴컴컴컴컴컴컴컴컴컴좔컴컴컴
+
+ mov dword ptr _vplce[8], esi
+ mov dword ptr _vplce[0], ebp
+ ;vplc2 = (esi<<(32-sh))+(edx>>sh)
+ ;vplc3 = (ebp<<(32-sh))+((edx&65535)<<(16-sh))
+promachvsh5: shl esi, 88h ;32-sh
+ mov eax, edx
+promachvsh6: shl ebp, 88h ;32-sh
+ and edx, 0000ffffh
+promachvsh7: shr eax, 88h ;sh
+ add esi, eax
+promachvsh8: shl edx, 88h ;16-sh
+ add ebp, edx
+ mov dword ptr _vplce[12], esi
+ mov dword ptr _vplce[4], ebp
+
+ pop ebp
+ ret
+
+
+ALIGN 16
+PUBLIC mvlineasm4_
+mvlineasm4_:
+ push ebp
+
+ mov eax, dword ptr _bufplce[0]
+ mov ebx, dword ptr _bufplce[4]
+ mov dword ptr [machmv1+2], eax
+ mov dword ptr [machmv4+2], ebx
+ mov eax, dword ptr _bufplce[8]
+ mov ebx, dword ptr _bufplce[12]
+ mov dword ptr [machmv7+2], eax
+ mov dword ptr [machmv10+2], ebx
+
+ mov eax, dword ptr _palookupoffse[0]
+ mov ebx, dword ptr _palookupoffse[4]
+ mov dword ptr [machmv2+2], eax
+ mov dword ptr [machmv5+2], ebx
+ mov eax, dword ptr _palookupoffse[8]
+ mov ebx, dword ptr _palookupoffse[12]
+ mov dword ptr [machmv8+2], eax
+ mov dword ptr [machmv11+2], ebx
+
+ mov eax, dword ptr _vince[0] ;vince
+ mov ebx, dword ptr _vince[4]
+ xor al, al
+ xor bl, bl
+ mov dword ptr [machmv3+2], eax
+ mov dword ptr [machmv6+2], ebx
+ mov eax, dword ptr _vince[8]
+ mov ebx, dword ptr _vince[12]
+ mov dword ptr [machmv9+2], eax
+ mov dword ptr [machmv12+2], ebx
+
+ mov ebx, ecx
+ mov ecx, dword ptr _vplce[0]
+ mov edx, dword ptr _vplce[4]
+ mov esi, dword ptr _vplce[8]
+ mov ebp, dword ptr _vplce[12]
+ mov cl, bl
+ inc cl
+ inc bh
+ mov byte ptr _asm3[0], bh
+fixchain2ma: sub edi, 320
+
+ jmp short beginmvlineasm4
+ALIGN 16
+beginmvlineasm4:
+ dec cl
+ jz endmvlineasm4
+beginmvlineasm42:
+ mov eax, ebp
+ mov ebx, esi
+machmv16: shr eax, 32
+machmv15: shr ebx, 32
+machmv12: add ebp, 88888888h ;vince[3]
+machmv9: add esi, 88888888h ;vince[2]
+machmv10: mov al, byte ptr [eax+88888888h] ;bufplce[3]
+machmv7: mov bl, byte ptr [ebx+88888888h] ;bufplce[2]
+ cmp al, 255
+ adc dl, dl
+ cmp bl, 255
+ adc dl, dl
+machmv8: mov bl, byte ptr [ebx+88888888h] ;palookupoffs[2]
+machmv11: mov bh, byte ptr [eax+88888888h] ;palookupoffs[3]
+
+ mov eax, edx
+machmv14: shr eax, 32
+ shl ebx, 16
+machmv4: mov al, byte ptr [eax+88888888h] ;bufplce[1]
+ cmp al, 255
+ adc dl, dl
+machmv6: add edx, 88888888h ;vince[1]
+machmv5: mov bh, byte ptr [eax+88888888h] ;palookupoffs[1]
+
+ mov eax, ecx
+machmv13: shr eax, 32
+machmv3: add ecx, 88888888h ;vince[0]
+machmv1: mov al, byte ptr [eax+88888888h] ;bufplce[0]
+ cmp al, 255
+ adc dl, dl
+machmv2: mov bl, byte ptr [eax+88888888h] ;palookupoffs[0]
+
+ shl dl, 4
+ xor eax, eax
+fixchain2mb: add edi, 320
+ mov al, dl
+ add eax, offset mvcase0
+ jmp eax ;16 byte cases
+
+ALIGN 16
+endmvlineasm4:
+ dec byte ptr _asm3[0]
+ jnz beginmvlineasm42
+
+ mov dword ptr _vplce[0], ecx
+ mov dword ptr _vplce[4], edx
+ mov dword ptr _vplce[8], esi
+ mov dword ptr _vplce[12], ebp
+ pop ebp
+ ret
+
+ ;5,7,8,8,11,13,12,14,11,13,14,14,12,14,15,7
+ALIGN 16
+mvcase0:
+ jmp beginmvlineasm4
+ALIGN 16
+mvcase1:
+ mov byte ptr [edi], bl
+ jmp beginmvlineasm4
+ALIGN 16
+mvcase2:
+ mov byte ptr [edi+1], bh
+ jmp beginmvlineasm4
+ALIGN 16
+mvcase3:
+ mov word ptr [edi], bx
+ jmp beginmvlineasm4
+ALIGN 16
+mvcase4:
+ shr ebx, 16
+ mov byte ptr [edi+2], bl
+ jmp beginmvlineasm4
+ALIGN 16
+mvcase5:
+ mov byte ptr [edi], bl
+ shr ebx, 16
+ mov byte ptr [edi+2], bl
+ jmp beginmvlineasm4
+ALIGN 16
+ mvcase6:
+ shr ebx, 8
+ mov word ptr [edi+1], bx
+ jmp beginmvlineasm4
+ALIGN 16
+mvcase7:
+ mov word ptr [edi], bx
+ shr ebx, 16
+ mov byte ptr [edi+2], bl
+ jmp beginmvlineasm4
+ALIGN 16
+mvcase8:
+ shr ebx, 16
+ mov byte ptr [edi+3], bh
+ jmp beginmvlineasm4
+ALIGN 16
+mvcase9:
+ mov byte ptr [edi], bl
+ shr ebx, 16
+ mov byte ptr [edi+3], bh
+ jmp beginmvlineasm4
+ALIGN 16
+mvcase10:
+ mov byte ptr [edi+1], bh
+ shr ebx, 16
+ mov byte ptr [edi+3], bh
+ jmp beginmvlineasm4
+ALIGN 16
+mvcase11:
+ mov word ptr [edi], bx
+ shr ebx, 16
+ mov byte ptr [edi+3], bh
+ jmp beginmvlineasm4
+ALIGN 16
+mvcase12:
+ shr ebx, 16
+ mov word ptr [edi+2], bx
+ jmp beginmvlineasm4
+ALIGN 16
+mvcase13:
+ mov byte ptr [edi], bl
+ shr ebx, 16
+ mov word ptr [edi+2], bx
+ jmp beginmvlineasm4
+ALIGN 16
+mvcase14:
+ mov byte ptr [edi+1], bh
+ shr ebx, 16
+ mov word ptr [edi+2], bx
+ jmp beginmvlineasm4
+ALIGN 16
+mvcase15:
+ mov dword ptr [edi], ebx
+ jmp beginmvlineasm4
+
+ALIGN 16
+PUBLIC setupspritevline_
+setupspritevline_:
+ mov dword ptr [spal+2], eax
+
+ mov eax, esi ;xinc's
+ shl eax, 16
+ mov dword ptr [smach1+2], eax
+ mov dword ptr [smach4+2], eax
+ mov eax, esi
+ sar eax, 16
+ add eax, ebx ;watch out with ebx - it's passed
+ mov dword ptr [smach2+2], eax
+ add eax, edx
+ mov dword ptr [smach5+2], eax
+
+ mov dword ptr [smach3+2], ecx ;yinc's
+ ret
+
+ALIGN 16
+PUBLIC spritevline_
+ ;eax = 0, ebx = x, ecx = cnt, edx = y, esi = yplc, edi = p
+prestartsvline:
+smach1: add ebx, 88888888h ;xincshl16
+ mov al, byte ptr [esi]
+smach2: adc esi, 88888888h ;xincshr16+yalwaysinc
+
+startsvline:
+spal: mov al, [eax+88888888h] ;palookup
+ mov byte ptr [edi], al
+fixchain1s: add edi, 320
+
+spritevline_:
+smach3: add edx, 88888888h ;dayinc
+ dec ecx
+ ja short prestartsvline ;jump if (no carry (add)) and (not zero (dec))!
+ jz short endsvline
+smach4: add ebx, 88888888h ;xincshl16
+ mov al, byte ptr [esi]
+smach5: adc esi, 88888888h ;xincshr16+yalwaysinc+daydime
+ jmp short startsvline
+endsvline:
+ ret
+
+ALIGN 16
+PUBLIC msetupspritevline_
+msetupspritevline_:
+ mov dword ptr [mspal+2], eax
+
+ mov eax, esi ;xinc's
+ shl eax, 16
+ mov dword ptr [msmach1+2], eax
+ mov dword ptr [msmach4+2], eax
+ mov eax, esi
+ sar eax, 16
+ add eax, ebx ;watch out with ebx - it's passed
+ mov dword ptr [msmach2+2], eax
+ add eax, edx
+ mov dword ptr [msmach5+2], eax
+
+ mov dword ptr [msmach3+2], ecx ;yinc's
+ ret
+
+ALIGN 16
+PUBLIC mspritevline_
+ ;eax = 0, ebx = x, ecx = cnt, edx = y, esi = yplc, edi = p
+mprestartsvline:
+msmach1: add ebx, 88888888h ;xincshl16
+ mov al, byte ptr [esi]
+msmach2: adc esi, 88888888h ;xincshr16+yalwaysinc
+
+mstartsvline:
+ cmp al, 255
+ je short mskipsvline
+mspal: mov al, [eax+88888888h] ;palookup
+ mov byte ptr [edi], al
+mskipsvline:
+mfixchain1s: add edi, 320
+
+mspritevline_:
+msmach3: add edx, 88888888h ;dayinc
+ dec ecx
+ ja short mprestartsvline ;jump if (no carry (add)) and (not zero (dec))!
+ jz short mendsvline
+msmach4: add ebx, 88888888h ;xincshl16
+ mov al, byte ptr [esi]
+msmach5: adc esi, 88888888h ;xincshr16+yalwaysinc+daydime
+ jmp short mstartsvline
+mendsvline:
+ ret
+
+ALIGN 16
+PUBLIC tsetupspritevline_
+tsetupspritevline_:
+ mov dword ptr [tspal+2], eax
+
+ mov eax, esi ;xinc's
+ shl eax, 16
+ mov dword ptr [tsmach1+2], eax
+ mov dword ptr [tsmach4+2], eax
+ mov eax, esi
+ sar eax, 16
+ add eax, ebx ;watch out with ebx - it's passed
+ mov dword ptr [tsmach2+2], eax
+ add eax, edx
+ mov dword ptr [tsmach5+2], eax
+
+ mov dword ptr [tsmach3+2], ecx ;yinc's
+ ret
+
+ALIGN 16
+PUBLIC tspritevline_
+tspritevline_:
+ ;eax = 0, ebx = x, ecx = cnt, edx = y, esi = yplc, edi = p
+ push ebp
+ mov ebp, ebx
+ xor ebx, ebx
+ jmp tenterspritevline
+ALIGN 16
+tprestartsvline:
+tsmach1: add ebp, 88888888h ;xincshl16
+ mov al, byte ptr [esi]
+tsmach2: adc esi, 88888888h ;xincshr16+yalwaysinc
+
+tstartsvline:
+ cmp al, 255
+ je short tskipsvline
+transrev2:
+ mov bh, byte ptr [edi]
+transrev3:
+tspal: mov bl, [eax+88888888h] ;palookup
+tmach4: mov al, byte ptr [ebx+88888888h] ;_transluc
+ mov byte ptr [edi], al
+tskipsvline:
+tfixchain1s: add edi, 320
+
+tenterspritevline:
+tsmach3: add edx, 88888888h ;dayinc
+ dec ecx
+ ja short tprestartsvline ;jump if (no carry (add)) and (not zero (dec))!
+ jz short tendsvline
+tsmach4: add ebp, 88888888h ;xincshl16
+ mov al, byte ptr [esi]
+tsmach5: adc esi, 88888888h ;xincshr16+yalwaysinc+daydime
+ jmp short tstartsvline
+tendsvline:
+ pop ebp
+ ret
+
+ALIGN 16
+PUBLIC msethlineshift_
+msethlineshift_:
+ neg al
+ mov byte ptr [msh1d+2], al
+ mov byte ptr [msh2d+3], bl
+ mov byte ptr [msh3d+2], al
+ mov byte ptr [msh4d+3], bl
+ mov byte ptr [msh5d+2], al
+ mov byte ptr [msh6d+3], bl
+ ret
+
+ALIGN 16
+PUBLIC mhline_
+mhline_:
+ ;_asm1 = bxinc
+ ;_asm2 = byinc
+ ;_asm3 = shadeoffs
+ ;eax = picoffs
+ ;ebx = bx
+ ;ecx = cnt
+ ;edx = ?
+ ;esi = by
+ ;edi = p
+
+ mov dword ptr [mmach1d+2], eax
+ mov dword ptr [mmach5d+2], eax
+ mov dword ptr [mmach9d+2], eax
+ mov eax, _asm3
+ mov dword ptr [mmach2d+2], eax
+ mov dword ptr [mmach2da+2], eax
+ mov dword ptr [mmach2db+2], eax
+ mov dword ptr [mmach6d+2], eax
+ mov dword ptr [mmach10d+2], eax
+ mov eax, _asm1
+ mov dword ptr [mmach3d+2], eax
+ mov dword ptr [mmach7d+2], eax
+ mov eax, _asm2
+ mov dword ptr [mmach4d+2], eax
+ mov dword ptr [mmach8d+2], eax
+ jmp short mhlineskipmodify_
+
+ALIGN 16
+PUBLIC mhlineskipmodify_
+mhlineskipmodify_:
+
+ push ebp
+
+ xor eax, eax
+ mov ebp, ebx
+
+ test ecx, 00010000h
+ jnz short mbeghline
+
+msh1d: shr ebx, 26
+msh2d: shld ebx, esi, 6
+ add ebp, _asm1
+mmach9d: mov al, byte ptr [ebx+88888888h] ;picoffs
+ add esi, _asm2
+ cmp al, 255
+ je mskip5
+
+ mmach10d: mov cl, byte ptr [eax+88888888h] ;shadeoffs
+ mov byte ptr [edi], cl
+mskip5:
+ inc edi
+ sub ecx, 65536
+ jc mendhline
+ jmp short mbeghline
+
+ALIGN 16
+mpreprebeghline: ;1st only
+ mov al, cl
+mmach2d: mov al, byte ptr [eax+88888888h] ;shadeoffs
+ mov byte ptr [edi], al
+
+mprebeghline:
+ add edi, 2
+ sub ecx, 131072
+ jc short mendhline
+mbeghline:
+mmach3d: lea ebx, [ebp+88888888h] ;bxinc
+msh3d: shr ebp, 26
+msh4d: shld ebp, esi, 6
+mmach4d: add esi, 88888888h ;byinc
+mmach1d: mov cl, byte ptr [ebp+88888888h] ;picoffs
+mmach7d: lea ebp, [ebx+88888888h] ;bxinc
+
+msh5d: shr ebx, 26
+msh6d: shld ebx, esi, 6
+mmach8d: add esi, 88888888h ;byinc
+mmach5d: mov ch, byte ptr [ebx+88888888h] ;picoffs
+
+ cmp cl, 255
+ je short mskip1
+ cmp ch, 255
+ je short mpreprebeghline
+
+ mov al, cl ;BOTH
+mmach2da: mov bl, byte ptr [eax+88888888h] ;shadeoffs
+ mov al, ch
+mmach2db: mov bh, byte ptr [eax+88888888h] ;shadeoffs
+ mov word ptr [edi], bx
+ add edi, 2
+ sub ecx, 131072
+ jnc short mbeghline
+ jmp mendhline
+mskip1: ;2nd only
+ cmp ch, 255
+ je short mprebeghline
+
+ mov al, ch
+mmach6d: mov al, byte ptr [eax+88888888h] ;shadeoffs
+ mov byte ptr [edi+1], al
+ add edi, 2
+ sub ecx, 131072
+ jnc short mbeghline
+mendhline:
+
+ pop ebp
+ ret
+
+ALIGN 16
+PUBLIC tsethlineshift_
+tsethlineshift_:
+ neg al
+ mov byte ptr [tsh1d+2], al
+ mov byte ptr [tsh2d+3], bl
+ mov byte ptr [tsh3d+2], al
+ mov byte ptr [tsh4d+3], bl
+ mov byte ptr [tsh5d+2], al
+ mov byte ptr [tsh6d+3], bl
+ ret
+
+ALIGN 16
+PUBLIC thline_
+thline_:
+ ;_asm1 = bxinc
+ ;_asm2 = byinc
+ ;_asm3 = shadeoffs
+ ;eax = picoffs
+ ;ebx = bx
+ ;ecx = cnt
+ ;edx = ?
+ ;esi = by
+ ;edi = p
+
+ mov dword ptr [tmach1d+2], eax
+ mov dword ptr [tmach5d+2], eax
+ mov dword ptr [tmach9d+2], eax
+ mov eax, _asm3
+ mov dword ptr [tmach2d+2], eax
+ mov dword ptr [tmach6d+2], eax
+ mov dword ptr [tmach10d+2], eax
+ mov eax, _asm1
+ mov dword ptr [tmach3d+2], eax
+ mov dword ptr [tmach7d+2], eax
+ mov eax, _asm2
+ mov dword ptr [tmach4d+2], eax
+ mov dword ptr [tmach8d+2], eax
+ jmp thlineskipmodify_
+
+ALIGN 16
+PUBLIC thlineskipmodify_
+thlineskipmodify_:
+
+ push ebp
+
+ xor eax, eax
+ xor edx, edx
+ mov ebp, ebx
+
+ test ecx, 00010000h
+ jnz short tbeghline
+
+tsh1d: shr ebx, 26
+tsh2d: shld ebx, esi, 6
+ add ebp, _asm1
+tmach9d: mov al, byte ptr [ebx+88888888h] ;picoffs
+ add esi, _asm2
+ cmp al, 255
+ je tskip5
+
+transrev4:
+tmach10d: mov dl, byte ptr [eax+88888888h] ;shadeoffs
+transrev5:
+ mov dh, byte ptr [edi]
+tmach1: mov al, byte ptr [edx+88888888h] ;_transluc
+ mov byte ptr [edi], al
+tskip5:
+ inc edi
+ sub ecx, 65536
+ jc tendhline
+ jmp short tbeghline
+
+ALIGN 16
+tprebeghline:
+ add edi, 2
+ sub ecx, 131072
+ jc short tendhline
+tbeghline:
+tmach3d: lea ebx, [ebp+88888888h] ;bxinc
+tsh3d: shr ebp, 26
+tsh4d: shld ebp, esi, 6
+tmach4d: add esi, 88888888h ;byinc
+tmach1d: mov cl, byte ptr [ebp+88888888h] ;picoffs
+tmach7d: lea ebp, [ebx+88888888h] ;bxinc
+
+tsh5d: shr ebx, 26
+tsh6d: shld ebx, esi, 6
+tmach8d: add esi, 88888888h ;byinc
+tmach5d: mov ch, byte ptr [ebx+88888888h] ;picoffs
+
+ cmp cx, 0ffffh
+ je short tprebeghline
+
+ mov bx, word ptr [edi]
+
+ cmp cl, 255
+ je short tskip1
+ mov al, cl
+transrev6:
+tmach2d: mov dl, byte ptr [eax+88888888h] ;shadeoffs
+transrev7:
+ mov dh, bl
+tmach2: mov al, byte ptr [edx+88888888h] ;_transluc
+ mov byte ptr [edi], al
+
+ cmp ch, 255
+ je short tskip2
+tskip1:
+ mov al, ch
+transrev8:
+tmach6d: mov dl, byte ptr [eax+88888888h] ;shadeoffs
+transrev9:
+ mov dh, bh
+tmach3: mov al, byte ptr [edx+88888888h] ;_transluc
+ mov byte ptr [edi+1], al
+tskip2:
+
+ add edi, 2
+ sub ecx, 131072
+ jnc tbeghline
+tendhline:
+
+ pop ebp
+ ret
+
+
+ ;eax=shiftval, ebx=palookup1, ecx=palookup2
+ALIGN 16
+PUBLIC setuptvlineasm2_
+setuptvlineasm2_:
+ mov byte ptr [tran2shra+2], al
+ mov byte ptr [tran2shrb+2], al
+ mov dword ptr [tran2pala+2], ebx
+ mov dword ptr [tran2palb+2], ecx
+ mov dword ptr [tran2palc+2], ebx
+ mov dword ptr [tran2pald+2], ecx
+ ret
+
+ ;Pass: eax=vplc2, ebx=vinc1, ecx=bufplc1, edx=bufplc2, esi=vplc1, edi=p
+ ; _asm1=vinc2, _asm2=pend
+ ;Return: _asm1=vplc1, _asm2=vplc2
+ALIGN 16
+PUBLIC tvlineasm2_
+tvlineasm2_:
+ push ebp
+
+ mov ebp, eax
+
+ mov dword ptr [tran2inca+2], ebx
+ mov eax, _asm1
+ mov dword ptr [tran2incb+2], eax
+
+ mov dword ptr [tran2bufa+2], ecx ;bufplc1
+ mov dword ptr [tran2bufb+2], edx ;bufplc2
+
+ mov eax, _asm2
+ sub edi, eax
+ mov dword ptr [tran2edia+3], eax
+ mov dword ptr [tran2edic+2], eax
+ inc eax
+ mov dword ptr [tran2edie+2], eax
+fixchaint2a: sub eax, 320
+ mov dword ptr [tran2edif+2], eax
+ dec eax
+ mov dword ptr [tran2edib+3], eax
+ mov dword ptr [tran2edid+2], eax
+
+ xor ecx, ecx
+ xor edx, edx
+ jmp short begintvline2
+
+ ;eax 0000000000 temp temp
+ ;ebx 0000000000 odat2 odat1
+ ;ecx 0000000000000000 ndat1
+ ;edx 0000000000000000 ndat2
+ ;esi vplc1
+ ;edi videoplc--------------
+ ;ebp vplc2
+
+ALIGN 16
+ ;LEFT ONLY
+skipdraw2:
+transrev10:
+tran2edic: mov ah, byte ptr [edi+88888888h] ;getpixel
+transrev11:
+tran2palc: mov al, byte ptr [ecx+88888888h] ;palookup1
+fixchaint2d: add edi, 320
+tran2trac: mov bl, byte ptr [eax+88888888h] ;_transluc
+tran2edid: mov byte ptr [edi+88888888h-320], bl ;drawpixel
+ jnc short begintvline2
+ jmp endtvline2
+
+skipdraw1:
+ cmp dl, 255
+ jne short skipdraw3
+fixchaint2b: add edi, 320
+ jc short endtvline2
+
+begintvline2:
+ mov eax, esi
+tran2shra: shr eax, 88h ;globalshift
+ mov ebx, ebp
+tran2shrb: shr ebx, 88h ;globalshift
+tran2inca: add esi, 88888888h ;vinc1
+tran2incb: add ebp, 88888888h ;vinc2
+tran2bufa: mov cl, byte ptr [eax+88888888h] ;bufplc1
+ cmp cl, 255
+tran2bufb: mov dl, byte ptr [ebx+88888888h] ;bufplc2
+ je short skipdraw1
+ cmp dl, 255
+ je short skipdraw2
+
+ ;mov ax The transluscent reverse of both!
+ ;mov bl, ah
+ ;mov ah
+ ;mov bh
+
+ ;BOTH
+transrev12:
+tran2edia: mov bx, word ptr [edi+88888888h] ;getpixels
+transrev13:
+ mov ah, bl
+transrev14:
+tran2pala: mov al, byte ptr [ecx+88888888h] ;palookup1
+transrev15:
+tran2palb: mov bl, byte ptr [edx+88888888h] ;palookup2
+fixchaint2c: add edi, 320
+tran2traa: mov al, byte ptr [eax+88888888h] ;_transluc
+tran2trab: mov ah, byte ptr [ebx+88888888h] ;_transluc
+tran2edib: mov word ptr [edi+88888888h-320], ax ;drawpixels
+ jnc short begintvline2
+ jmp short endtvline2
+
+ ;RIGHT ONLY
+skipdraw3:
+transrev16:
+tran2edie: mov ah, byte ptr [edi+88888889h] ;getpixel
+transrev17:
+tran2pald: mov al, byte ptr [edx+88888888h] ;palookup2
+fixchaint2e: add edi, 320
+tran2trad: mov bl, byte ptr [eax+88888888h] ;_transluc
+tran2edif: mov byte ptr [edi+88888889h-320], bl ;drawpixel
+ jnc short begintvline2
+
+endtvline2:
+ mov _asm1, esi
+ mov _asm2, ebp
+
+ pop ebp
+ ret
+
+
+BITSOFPRECISION equ 3
+BITSOFPRECISIONPOW equ 8
+
+;Double-texture mapping with palette lookup
+;eax: ylo1------------|----dat|----dat
+;ebx: ylo2--------------------|----cnt
+;ecx: 000000000000000000000000|---temp
+;edx: xhi1-xlo1---------------|---yhi1
+;esi: xhi2-xlo2---------------|---yhi2
+;edi: ------------------------videopos
+;ebp: ----------------------------temp
+
+ALIGN 16
+PUBLIC setupslopevlin2_
+setupslopevlin2_:
+ mov dword ptr [slop3+2], edx ;ptr
+ mov dword ptr [slop7+2], edx ;ptr
+ mov dword ptr [slop4+2], esi ;tptr
+ mov dword ptr [slop8+2], esi ;tptr
+ mov byte ptr [slop2+2], ah ;ybits
+ mov byte ptr [slop6+2], ah ;ybits
+ mov dword ptr [slop9+2], edi ;pinc
+
+ mov edx, 1
+ mov cl, al
+ add cl, ah
+ shl edx, cl
+ dec edx
+ mov cl, ah
+ ror edx, cl
+
+ mov dword ptr [slop1+2], edx ;ybits...xbits
+ mov dword ptr [slop5+2], edx ;ybits...xbits
+
+ ret
+
+ALIGN 16
+PUBLIC slopevlin2_
+slopevlin2_:
+ push ebp
+ xor ecx, ecx
+
+slopevlin2begin:
+ mov ebp, edx
+slop1: and ebp, 88000088h ;ybits...xbits
+slop2: rol ebp, 6 ;ybits
+ add eax, _asm1 ;xinc1<<xbits
+ adc edx, _asm2 ;(yinc1&0xffffff00)+(xinc1>>(32-xbits))
+slop3: mov cl, byte ptr [ebp+88888888h] ;bufplc
+
+ mov ebp, esi
+slop4: mov al, byte ptr [ecx+88888888h] ;paloffs
+slop5: and ebp, 88000088h ;ybits...xbits
+slop6: rol ebp, 6 ;ybits
+ add ebx, _asm3 ;xinc2<<xbits
+slop7: mov cl, byte ptr [ebp+88888888h] ;bufplc
+ adc esi, _asm4 ;(yinc2&0xffffff00)+(xinc2>>(32-xbits))
+slop8: mov ah, byte ptr [ecx+88888888h] ;paloffs
+
+ dec bl
+ mov word ptr [edi], ax
+slop9: lea edi, [edi+88888888h] ;pinc
+ jnz short slopevlin2begin
+
+ pop ebp
+ mov eax, edi
+ ret
+
+
+ALIGN 16
+PUBLIC setupslopevlin_
+setupslopevlin_:
+ mov dword ptr [slopmach3+3], ebx ;ptr
+ mov dword ptr [slopmach5+2], ecx ;pinc
+ neg ecx
+ mov dword ptr [slopmach6+2], ecx ;-pinc
+
+ mov edx, 1
+ mov cl, al
+ shl edx, cl
+ dec edx
+ mov cl, ah
+ shl edx, cl
+ mov dword ptr [slopmach7+2], edx
+
+ neg ah
+ mov byte ptr [slopmach2+2], ah
+
+ sub ah, al
+ mov byte ptr [slopmach1+2], ah
+
+ fild dword ptr _asm1
+ fstp dword ptr _asm2
+ ret
+
+ALIGN 16
+PUBLIC slopevlin_
+slopevlin_:
+ mov _ebpbak, ebp
+ mov _espbak, esp
+
+ sub ecx, esp
+ mov dword ptr [slopmach4+3], ecx
+
+ fild dword ptr _asm3
+slopmach6: lea ebp, [eax+88888888h]
+ fadd dword ptr _asm2
+
+ mov _asm1, ebx
+ shl ebx, 3
+
+ mov eax, _globalx3
+ mov ecx, _globaly3
+ imul eax, ebx
+ imul ecx, ebx
+ add esi, eax
+ add edi, ecx
+
+ mov ebx, edx
+ jmp short bigslopeloop
+ALIGN 16
+bigslopeloop:
+ fst dword ptr _fpuasm
+
+ mov eax, _fpuasm
+ add eax, eax
+ sbb edx, edx
+ mov ecx, eax
+ shr ecx, 24
+ and eax, 00ffe000h
+ shr eax, 11
+ sub cl, 2
+ mov eax, dword ptr _reciptable[eax]
+ shr eax, cl
+ xor eax, edx
+ mov edx, _asm1
+ mov ecx, _globalx3
+ mov _asm1, eax
+ sub eax, edx
+ mov edx, _globaly3
+ imul ecx, eax
+ imul eax, edx
+
+ fadd dword ptr _asm2
+
+ cmp ebx, BITSOFPRECISIONPOW
+ mov _asm4, ebx
+ mov cl, bl
+ jl short slopeskipmin
+ mov cl, BITSOFPRECISIONPOW
+slopeskipmin:
+
+;eax: yinc.............
+;ebx: 0 0 0 ?
+;ecx: xinc......... cnt
+;edx: ?
+;esi: xplc.............
+;edi: yplc.............
+;ebp: videopos
+
+ mov ebx, esi
+ mov edx, edi
+
+beginnerslopeloop:
+slopmach1: shr ebx, 20
+ add esi, ecx
+slopmach2: shr edx, 26
+slopmach7: and ebx, 88888888h
+ add edi, eax
+slopmach5: add ebp, 88888888h ;pinc
+slopmach3: mov dl, byte ptr [ebx+edx+88888888h] ;ptr
+slopmach4: mov ebx, dword ptr [esp+88888888h]
+ sub esp, 4
+ dec cl
+ mov al, byte ptr [ebx+edx] ;tptr
+ mov ebx, esi
+ mov [ebp], al
+ mov edx, edi
+ jnz short beginnerslopeloop
+
+ mov ebx, _asm4
+ sub ebx, BITSOFPRECISIONPOW
+ jg bigslopeloop
+
+ ffree st(0)
+
+ mov esp, _espbak
+ mov ebp, _ebpbak
+ ret
+
+
+ALIGN 16
+PUBLIC setuprhlineasm4_
+setuprhlineasm4_:
+ mov dword ptr [rmach1a+2], eax
+ mov dword ptr [rmach1b+2], eax
+ mov dword ptr [rmach1c+2], eax
+ mov dword ptr [rmach1d+2], eax
+ mov dword ptr [rmach1e+2], eax
+
+ mov dword ptr [rmach2a+2], ebx
+ mov dword ptr [rmach2b+2], ebx
+ mov dword ptr [rmach2c+2], ebx
+ mov dword ptr [rmach2d+2], ebx
+ mov dword ptr [rmach2e+2], ebx
+
+ mov dword ptr [rmach3a+2], ecx
+ mov dword ptr [rmach3b+2], ecx
+ mov dword ptr [rmach3c+2], ecx
+ mov dword ptr [rmach3d+2], ecx
+ mov dword ptr [rmach3e+2], ecx
+
+ mov dword ptr [rmach4a+2], edx
+ mov dword ptr [rmach4b+2], edx
+ mov dword ptr [rmach4c+2], edx
+ mov dword ptr [rmach4d+2], edx
+ mov dword ptr [rmach4e+2], edx
+
+ mov dword ptr [rmach5a+2], esi
+ mov dword ptr [rmach5b+2], esi
+ mov dword ptr [rmach5c+2], esi
+ mov dword ptr [rmach5d+2], esi
+ mov dword ptr [rmach5e+2], esi
+ ret
+
+ ;Non power of 2, non masking, with palookup method #1 (6 clock cycles)
+ ;eax: dat dat dat dat
+ ;ebx: bufplc
+ ;ecx: 0 dat
+ ;edx: xlo
+ ;esi: ylo
+ ;edi: videopos/cnt
+ ;ebp: tempvar
+ ;esp:
+ALIGN 16
+PUBLIC rhlineasm4_
+rhlineasm4_:
+ push ebp
+
+ cmp eax, 0
+ jle endrhline
+
+ lea ebp, [edi-4]
+ sub ebp, eax
+ mov dword ptr [rmach6a+2], ebp
+ add ebp, 3
+ mov dword ptr [rmach6b+2], ebp
+ mov edi, eax
+ test edi, 3
+ jz short begrhline
+ jmp short startrhline1
+
+ALIGN 16
+startrhline1:
+ mov cl, byte ptr [ebx] ;bufplc
+rmach1e: sub edx, 88888888h ;xlo
+ sbb ebp, ebp
+rmach2e: sub esi, 88888888h ;ylo
+rmach3e: sbb ebx, 88888888h ;xhi*tilesizy + yhi+ycarry
+rmach4e: mov al, byte ptr [ecx+88888888h] ;palookup
+rmach5e: and ebp, 88888888h ;tilesizy
+rmach6b: mov byte ptr [edi+88888888h], al ;vidcntoffs
+ sub ebx, ebp
+ dec edi
+ test edi, 3
+ jnz short startrhline1
+ test edi, edi
+ jz endrhline
+
+begrhline:
+ mov cl, byte ptr [ebx] ;bufplc
+rmach1a: sub edx, 88888888h ;xlo
+ sbb ebp, ebp
+rmach2a: sub esi, 88888888h ;ylo
+rmach3a: sbb ebx, 88888888h ;xhi*tilesizy + yhi+ycarry
+rmach5a: and ebp, 88888888h ;tilesizy
+ sub ebx, ebp
+
+rmach1b: sub edx, 88888888h ;xlo
+ sbb ebp, ebp
+rmach4a: mov ah, byte ptr [ecx+88888888h] ;palookup
+ mov cl, byte ptr [ebx] ;bufplc
+rmach2b: sub esi, 88888888h ;ylo
+rmach3b: sbb ebx, 88888888h ;xhi*tilesizy + yhi+ycarry
+rmach5b: and ebp, 88888888h ;tilesizy
+rmach4b: mov al, byte ptr [ecx+88888888h] ;palookup
+ sub ebx, ebp
+
+ shl eax, 16
+
+ mov cl, byte ptr [ebx] ;bufplc
+rmach1c: sub edx, 88888888h ;xlo
+ sbb ebp, ebp
+rmach2c: sub esi, 88888888h ;ylo
+rmach3c: sbb ebx, 88888888h ;xhi*tilesizy + yhi+ycarry
+rmach5c: and ebp, 88888888h ;tilesizy
+ sub ebx, ebp
+
+rmach1d: sub edx, 88888888h ;xlo
+ sbb ebp, ebp
+rmach4c: mov ah, byte ptr [ecx+88888888h] ;palookup
+ mov cl, byte ptr [ebx] ;bufplc
+rmach2d: sub esi, 88888888h ;ylo
+rmach3d: sbb ebx, 88888888h ;xhi*tilesizy + yhi+ycarry
+rmach5d: and ebp, 88888888h ;tilesizy
+rmach4d: mov al, byte ptr [ecx+88888888h] ;palookup
+ sub ebx, ebp
+
+rmach6a: mov dword ptr [edi+88888888h], eax ;vidcntoffs
+ sub edi, 4
+ jnz begrhline
+endrhline:
+ pop ebp
+ ret
+
+ALIGN 16
+PUBLIC setuprmhlineasm4_
+setuprmhlineasm4_:
+ mov dword ptr [rmmach1+2], eax
+ mov dword ptr [rmmach2+2], ebx
+ mov dword ptr [rmmach3+2], ecx
+ mov dword ptr [rmmach4+2], edx
+ mov dword ptr [rmmach5+2], esi
+ ret
+
+ALIGN 16
+PUBLIC rmhlineasm4_
+rmhlineasm4_:
+ push ebp
+
+ cmp eax, 0
+ jle short endrmhline
+
+ lea ebp, [edi-1]
+ sub ebp, eax
+ mov dword ptr [rmmach6+2], ebp
+ mov edi, eax
+ jmp short begrmhline
+
+ALIGN 16
+begrmhline:
+ mov cl, byte ptr [ebx] ;bufplc
+rmmach1: sub edx, 88888888h ;xlo
+ sbb ebp, ebp
+rmmach2: sub esi, 88888888h ;ylo
+rmmach3: sbb ebx, 88888888h ;xhi*tilesizy + yhi+ycarry
+rmmach5: and ebp, 88888888h ;tilesizy
+ cmp cl, 255
+ je short rmskip
+rmmach4: mov al, byte ptr [ecx+88888888h] ;palookup
+rmmach6: mov byte ptr [edi+88888888h], al ;vidcntoffs
+rmskip:
+ sub ebx, ebp
+ dec edi
+ jnz short begrmhline
+endrmhline:
+ pop ebp
+ ret
+
+ALIGN 16
+PUBLIC setupqrhlineasm4_
+setupqrhlineasm4_:
+ mov dword ptr [qrmach2e+2], ebx
+ mov dword ptr [qrmach3e+2], ecx
+ xor edi, edi
+ sub edi, ecx
+ mov dword ptr [qrmach7a+2], edi
+ mov dword ptr [qrmach7b+2], edi
+
+ add ebx, ebx
+ adc ecx, ecx
+ mov dword ptr [qrmach2a+2], ebx
+ mov dword ptr [qrmach2b+2], ebx
+ mov dword ptr [qrmach3a+2], ecx
+ mov dword ptr [qrmach3b+2], ecx
+
+ mov dword ptr [qrmach4a+2], edx
+ mov dword ptr [qrmach4b+2], edx
+ mov dword ptr [qrmach4c+2], edx
+ mov dword ptr [qrmach4d+2], edx
+ mov dword ptr [qrmach4e+2], edx
+ ret
+
+ ;Non power of 2, non masking, with palookup method (FASTER BUT NO SBB'S)
+ ;eax: dat dat dat dat
+ ;ebx: bufplc
+ ;ecx: 0 dat
+ ;edx: 0 dat
+ ;esi: ylo
+ ;edi: videopos/cnt
+ ;ebp: ?
+ ;esp:
+ALIGN 16
+PUBLIC qrhlineasm4_ ;4 pixels in 9 cycles! 2.25 cycles/pixel
+qrhlineasm4_:
+ push ebp
+
+ cmp eax, 0
+ jle endqrhline
+
+ mov ebp, eax
+ test ebp, 3
+ jz short skipqrhline1
+ jmp short startqrhline1
+
+ALIGN 16
+startqrhline1:
+ mov cl, byte ptr [ebx] ;bufplc
+ dec edi
+qrmach2e: sub esi, 88888888h ;ylo
+ dec ebp
+qrmach3e: sbb ebx, 88888888h ;xhi*tilesizy + yhi+ycarry
+qrmach4e: mov al, byte ptr [ecx+88888888h] ;palookup
+ mov byte ptr [edi], al ;vidcntoffs
+ test ebp, 3
+ jnz short startqrhline1
+ test ebp, ebp
+ jz short endqrhline
+
+skipqrhline1:
+ mov cl, byte ptr [ebx] ;bufplc
+ jmp short begqrhline
+ALIGN 16
+begqrhline:
+qrmach7a: mov dl, byte ptr [ebx+88888888h] ;bufplc
+qrmach2a: sub esi, 88888888h ;ylo
+qrmach3a: sbb ebx, 88888888h ;xhi*tilesizy + yhi+ycarry
+qrmach4a: mov ah, byte ptr [ecx+88888888h] ;palookup
+qrmach4b: mov al, byte ptr [edx+88888888h] ;palookup
+ sub edi, 4
+ shl eax, 16
+ mov cl, byte ptr [ebx] ;bufplc
+qrmach7b: mov dl, byte ptr [ebx+88888888h] ;bufplc
+qrmach2b: sub esi, 88888888h ;ylo
+qrmach3b: sbb ebx, 88888888h ;xhi*tilesizy + yhi+ycarry
+qrmach4c: mov ah, byte ptr [ecx+88888888h] ;palookup
+qrmach4d: mov al, byte ptr [edx+88888888h] ;palookup
+ mov cl, byte ptr [ebx] ;bufplc
+ mov dword ptr [edi], eax
+ sub ebp, 4
+ jnz short begqrhline
+
+endqrhline:
+ pop ebp
+ ret
+
+
+PUBLIC setupdrawslab_
+setupdrawslab_:
+ mov dword ptr [voxbpl1+2], eax
+ mov dword ptr [voxbpl2+2], eax
+ mov dword ptr [voxbpl3+2], eax
+ mov dword ptr [voxbpl4+2], eax
+ mov dword ptr [voxbpl5+2], eax
+ mov dword ptr [voxbpl6+2], eax
+ mov dword ptr [voxbpl7+2], eax
+ mov dword ptr [voxbpl8+2], eax
+
+ mov dword ptr [voxpal1+2], ebx
+ mov dword ptr [voxpal2+2], ebx
+ mov dword ptr [voxpal3+2], ebx
+ mov dword ptr [voxpal4+2], ebx
+ mov dword ptr [voxpal5+2], ebx
+ mov dword ptr [voxpal6+2], ebx
+ mov dword ptr [voxpal7+2], ebx
+ mov dword ptr [voxpal8+2], ebx
+ ret
+
+ALIGN 16
+PUBLIC drawslab_
+drawslab_:
+ push ebp
+ cmp eax, 2
+ je voxbegdraw2
+ ja voxskip2
+ xor eax, eax
+voxbegdraw1:
+ mov ebp, ebx
+ shr ebp, 16
+ add ebx, edx
+ dec ecx
+ mov al, byte ptr [esi+ebp]
+voxpal1: mov al, byte ptr [eax+88888888h]
+ mov byte ptr [edi], al
+voxbpl1: lea edi, [edi+88888888h]
+ jnz voxbegdraw1
+ pop ebp
+ ret
+
+voxbegdraw2:
+ mov ebp, ebx
+ shr ebp, 16
+ add ebx, edx
+ xor eax, eax
+ dec ecx
+ mov al, byte ptr [esi+ebp]
+voxpal2: mov al, byte ptr [eax+88888888h]
+ mov ah, al
+ mov word ptr [edi], ax
+voxbpl2: lea edi, [edi+88888888h]
+ jnz voxbegdraw2
+ pop ebp
+ ret
+
+voxskip2:
+ cmp eax, 4
+ jne voxskip4
+ xor eax, eax
+voxbegdraw4:
+ mov ebp, ebx
+ add ebx, edx
+ shr ebp, 16
+ xor eax, eax
+ mov al, byte ptr [esi+ebp]
+voxpal3: mov al, byte ptr [eax+88888888h]
+ mov ah, al
+ shl eax, 8
+ mov al, ah
+ shl eax, 8
+ mov al, ah
+ mov dword ptr [edi], eax
+voxbpl3: add edi, 88888888h
+ dec ecx
+ jnz voxbegdraw4
+ pop ebp
+ ret
+
+voxskip4:
+ add eax, edi
+
+ test edi, 1
+ jz voxskipslab1
+ cmp edi, eax
+ je voxskipslab1
+
+ push eax
+ push ebx
+ push ecx
+ push edi
+voxbegslab1:
+ mov ebp, ebx
+ add ebx, edx
+ shr ebp, 16
+ xor eax, eax
+ mov al, byte ptr [esi+ebp]
+voxpal4: mov al, byte ptr [eax+88888888h]
+ mov byte ptr [edi], al
+voxbpl4: add edi, 88888888h
+ dec ecx
+ jnz voxbegslab1
+ pop edi
+ pop ecx
+ pop ebx
+ pop eax
+ inc edi
+
+voxskipslab1:
+ push eax
+ test edi, 2
+ jz voxskipslab2
+ dec eax
+ cmp edi, eax
+ jge voxskipslab2
+
+ push ebx
+ push ecx
+ push edi
+voxbegslab2:
+ mov ebp, ebx
+ add ebx, edx
+ shr ebp, 16
+ xor eax, eax
+ mov al, byte ptr [esi+ebp]
+voxpal5: mov al, byte ptr [eax+88888888h]
+ mov ah, al
+ mov word ptr [edi], ax
+voxbpl5: add edi, 88888888h
+ dec ecx
+ jnz voxbegslab2
+ pop edi
+ pop ecx
+ pop ebx
+ add edi, 2
+
+voxskipslab2:
+ mov eax, [esp]
+
+ sub eax, 3
+ cmp edi, eax
+ jge voxskipslab3
+
+voxprebegslab3:
+ push ebx
+ push ecx
+ push edi
+voxbegslab3:
+ mov ebp, ebx
+ add ebx, edx
+ shr ebp, 16
+ xor eax, eax
+ mov al, byte ptr [esi+ebp]
+voxpal6: mov al, byte ptr [eax+88888888h]
+ mov ah, al
+ shl eax, 8
+ mov al, ah
+ shl eax, 8
+ mov al, ah
+ mov dword ptr [edi], eax
+voxbpl6: add edi, 88888888h
+ dec ecx
+ jnz voxbegslab3
+ pop edi
+ pop ecx
+ pop ebx
+ add edi, 4
+
+ mov eax, [esp]
+
+ sub eax, 3
+ cmp edi, eax
+ jl voxprebegslab3
+
+voxskipslab3:
+ mov eax, [esp]
+
+ dec eax
+ cmp edi, eax
+ jge voxskipslab4
+
+ push ebx
+ push ecx
+ push edi
+voxbegslab4:
+ mov ebp, ebx
+ add ebx, edx
+ shr ebp, 16
+ xor eax, eax
+ mov al, byte ptr [esi+ebp]
+voxpal7: mov al, byte ptr [eax+88888888h]
+ mov ah, al
+ mov word ptr [edi], ax
+voxbpl7: add edi, 88888888h
+ dec ecx
+ jnz voxbegslab4
+ pop edi
+ pop ecx
+ pop ebx
+ add edi, 2
+
+voxskipslab4:
+ pop eax
+
+ cmp edi, eax
+ je voxskipslab5
+
+voxbegslab5:
+ mov ebp, ebx
+ add ebx, edx
+ shr ebp, 16
+ xor eax, eax
+ mov al, byte ptr [esi+ebp]
+voxpal8: mov al, byte ptr [eax+88888888h]
+ mov byte ptr [edi], al
+voxbpl8: add edi, 88888888h
+ dec ecx
+ jnz voxbegslab5
+
+voxskipslab5:
+ pop ebp
+ ret
+
+;modify: loinc
+;eax: | dat | dat | dat | dat |
+;ebx: | loplc1 |
+;ecx: | loplc2 | cnthi | cntlo |
+;edx: |--------|--------|--------| hiplc1 |
+;esi: |--------|--------|--------| hiplc2 |
+;edi: |--------|--------|--------| vidplc |
+;ebp: |--------|--------|--------| hiinc |
+
+PUBLIC stretchhline_
+stretchhline_:
+ push ebp
+
+ mov eax, ebx
+ shl ebx, 16
+ sar eax, 16
+ and ecx, 0000ffffh
+ or ecx, ebx
+
+ add esi, eax
+ mov eax, edx
+ mov edx, esi
+
+ mov ebp, eax
+ shl eax, 16
+ sar ebp, 16
+
+ add ecx, eax
+ adc esi, ebp
+
+ add eax, eax
+ adc ebp, ebp
+ mov dword ptr [loinc1+2], eax
+ mov dword ptr [loinc2+2], eax
+ mov dword ptr [loinc3+2], eax
+ mov dword ptr [loinc4+2], eax
+
+ inc ch
+
+ jmp begloop
+
+begloop:
+ mov al, [edx]
+loinc1: sub ebx, 88888888h
+ sbb edx, ebp
+ mov ah, [esi]
+loinc2: sub ecx, 88888888h
+ sbb esi, ebp
+ sub edi, 4
+ shl eax, 16
+loinc3: sub ebx, 88888888h
+ mov al, [edx]
+ sbb edx, ebp
+ mov ah, [esi]
+loinc4: sub ecx, 88888888h
+ sbb esi, ebp
+ mov [edi], eax
+ dec cl
+ jnz begloop
+ dec ch
+ jnz begloop
+
+ pop ebp
+ ret
+
+
+PUBLIC mmxoverlay_
+mmxoverlay_:
+ pushfd ;Check if CPUID is available
+ pop eax
+ mov ebx, eax
+ xor eax, 00200000h
+ push eax
+ popfd
+ pushfd
+ pop eax
+ cmp eax, ebx
+ je pentium
+ xor eax, eax
+ dw 0a20fh
+ test eax, eax
+ jz pentium
+ mov eax, 1
+ dw 0a20fh
+ and eax, 00000f00h
+ test edx, 00800000h ;Check if MMX is available
+ jz nommx
+ cmp eax, 00000600h ;Check if P6 Family or not
+ jae pentiumii
+ jmp pentiummmx
+nommx:
+ cmp eax, 00000600h ;Check if P6 Family or not
+ jae pentiumpro
+pentium:
+ ret
+
+;旼컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴커
+; PENTIUM II Overlays
+;읕컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴켸
+pentiumii:
+ ;Hline overlay (MMX doens't help)
+ mov byte ptr [sethlinesizes_], 0xe9
+ mov dword ptr [sethlinesizes_+1], (offset prosethlinesizes_)-(offset sethlinesizes_)-5
+ mov byte ptr [setpalookupaddress_], 0xe9
+ mov dword ptr [setpalookupaddress_+1], (offset prosetpalookupaddress_)-(offset setpalookupaddress_)-5
+ mov byte ptr [setuphlineasm4_], 0xc3 ;ret (no code required)
+ mov byte ptr [hlineasm4_], 0xe9
+ mov dword ptr [hlineasm4_+1], (offset prohlineasm4_)-(offset hlineasm4_)-5
+
+ ;Vline overlay
+ mov byte ptr [setupvlineasm_], 0xe9
+ mov dword ptr [setupvlineasm_+1], (offset prosetupvlineasm_)-(offset setupvlineasm_)-5
+ mov byte ptr [vlineasm4_], 0xe9
+ mov dword ptr [vlineasm4_+1], (offset provlineasm4_)-(offset vlineasm4_)-5
+
+ ret
+
+;旼컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴커
+; PENTIUM MMX Overlays
+;읕컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴켸
+pentiummmx:
+ ret
+
+;旼컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴커
+; PENTIUM PRO Overlays
+;읕컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴켸
+pentiumpro:
+ ;Hline overlay (MMX doens't help)
+ mov byte ptr [sethlinesizes_], 0xe9
+ mov dword ptr [sethlinesizes_+1], (offset prosethlinesizes_)-(offset sethlinesizes_)-5
+ mov byte ptr [setpalookupaddress_], 0xe9
+ mov dword ptr [setpalookupaddress_+1], (offset prosetpalookupaddress_)-(offset setpalookupaddress_)-5
+ mov byte ptr [setuphlineasm4_], 0xc3 ;ret (no code required)
+ mov byte ptr [hlineasm4_], 0xe9
+ mov dword ptr [hlineasm4_+1], (offset prohlineasm4_)-(offset hlineasm4_)-5
+
+ ;Vline overlay
+ mov byte ptr [setupvlineasm_], 0xe9
+ mov dword ptr [setupvlineasm_+1], (offset prosetupvlineasm_)-(offset setupvlineasm_)-5
+ mov byte ptr [vlineasm4_], 0xe9
+ mov dword ptr [vlineasm4_+1], (offset provlineasm4_)-(offset vlineasm4_)-5
+
+ ret
+
+CODE ENDS
+END
diff --git a/SRC/BSTUB.C b/SRC/BSTUB.C
new file mode 100644
index 0000000..39188a4
--- /dev/null
+++ b/SRC/BSTUB.C
@@ -0,0 +1,532 @@
+// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
+// Ken Silverman's official web site: "http://www.advsys.net/ken"
+// See the included license file "BUILDLIC.TXT" for license info.
+
+#include <fcntl.h>
+#include <io.h>
+#include <sys\types.h>
+#include <sys\stat.h>
+#include "build.h"
+#include "pragmas.h"
+#include "names.h"
+#include <dos.h>
+
+extern char keystatus[256];
+
+static char tempbuf[256];
+extern long qsetmode;
+extern short searchsector, searchwall, searchstat;
+extern long zmode, kensplayerheight;
+extern short defaultspritecstat;
+
+extern short temppicnum, tempcstat, templotag, temphitag, tempextra;
+extern char tempshade, temppal, tempxrepeat, tempyrepeat;
+extern char somethingintab;
+
+#define NUMOPTIONS 8
+#define NUMKEYS 19
+static long vesares[13][2] = {320,200,360,200,320,240,360,240,320,400,
+ 360,400,640,350,640,400,640,480,800,600,
+ 1024,768,1280,1024,1600,1200};
+static char option[NUMOPTIONS] = {0,0,0,0,0,0,1,0};
+static char keys[NUMKEYS] =
+{
+ 0xc8,0xd0,0xcb,0xcd,0x2a,0x9d,0x1d,0x39,
+ 0x1e,0x2c,0xd1,0xc9,0x33,0x34,
+ 0x9c,0x1c,0xd,0xc,0xf,
+};
+
+extern char buildkeys[NUMKEYS];
+
+extern long frameplace, xdimenscale, ydimen;
+extern long posx, posy, posz, horiz;
+extern short ang, cursectnum;
+
+static long hang = 0;
+extern long stretchhline(long,long,long,long,long,long);
+#pragma aux stretchhline parm [eax][ebx][ecx][edx][esi][edi];
+
+//Detecting 2D / 3D mode:
+// qsetmode is 200 in 3D mode
+// qsetmode is 350/480 in 2D mode
+//
+//You can read these variables when F5-F8 is pressed in 3D mode only:
+//
+// If (searchstat == 0) WALL searchsector=sector, searchwall=wall
+// If (searchstat == 1) CEILING searchsector=sector
+// If (searchstat == 2) FLOOR searchsector=sector
+// If (searchstat == 3) SPRITE searchsector=sector, searchwall=sprite
+// If (searchstat == 4) MASKED WALL searchsector=sector, searchwall=wall
+//
+// searchsector is the sector of the selected item for all 5 searchstat's
+//
+// searchwall is undefined if searchstat is 1 or 2
+// searchwall is the wall if searchstat = 0 or 4
+// searchwall is the sprite if searchstat = 3 (Yeah, I know - it says wall,
+// but trust me, it's the sprite number)
+
+long ofinetotalclock, ototalclock, averagefps;
+#define AVERAGEFRAMES 32
+static long frameval[AVERAGEFRAMES], framecnt = 0;
+
+#pragma aux inittimer42 =\
+ "in al, 0x61",\
+ "or al, 1",\
+ "out 0x61, al",\
+ "mov al, 0xb4",\
+ "out 0x43, al",\
+ "xor al, al",\
+ "out 0x42, al",\
+ "out 0x42, al",\
+ modify exact [eax]\
+
+#pragma aux uninittimer42 =\
+ "in al, 0x61",\
+ "and al, 252",\
+ "out 0x61, al",\
+ modify exact [eax]\
+
+#pragma aux gettimer42 =\
+ "mov al, 0x84",\
+ "out 0x43, al",\
+ "in al, 0x42",\
+ "shl eax, 24",\
+ "in al, 0x42",\
+ "rol eax, 8",\
+ modify [eax]\
+
+void ExtInit(void)
+{
+ long i, fil;
+
+ /*printf("------------------------------------------------------------------------------\n");
+ printf(" BUILD.EXE copyright(c) 1996 by Ken Silverman. You are granted the\n");
+ printf(" right to use this software for your personal use only. This is a\n");
+ printf(" special version to be used with \"Happy Fun KenBuild\" and may not work\n");
+ printf(" properly with other Build engine games. Please refer to license.doc\n");
+ printf(" for distribution rights\n");
+ printf("------------------------------------------------------------------------------\n");
+ getch();
+ */
+
+ initgroupfile("stuff.dat");
+ if ((fil = open("setup.dat",O_BINARY|O_RDWR,S_IREAD)) != -1)
+ {
+ read(fil,&option[0],NUMOPTIONS);
+ read(fil,&keys[0],NUMKEYS);
+ memcpy((void *)buildkeys,(void *)keys,NUMKEYS); //Trick to make build use setup.dat keys
+ close(fil);
+ }
+ if (option[4] > 0) option[4] = 0;
+ initmouse();
+ initengine();
+ vidoption = option[0]; xdim = vesares[option[6]&15][0]; ydim = vesares[option[6]&15][1];
+
+ //You can load your own palette lookup tables here if you just
+ //copy the right code!
+ for(i=0;i<256;i++)
+ tempbuf[i] = ((i+32)&255); //remap colors for screwy palette sectors
+ makepalookup(16,tempbuf,0,0,0,1);
+
+ kensplayerheight = 32;
+ zmode = 0;
+ defaultspritecstat = 0;
+ pskyoff[0] = 0; pskyoff[1] = 0; pskybits = 1;
+}
+
+void ExtUnInit(void)
+{
+ uninittimer42();
+ uninitgroupfile();
+}
+
+static long daviewingrange, daaspect, horizval1, horizval2;
+void ExtPreCheckKeys(void)
+{
+ long cosang, sinang, dx, dy, mindx, i;
+
+ if (keystatus[0x3e]) //F4 - screen re-size
+ {
+ keystatus[0x3e] = 0;
+
+ //cycle through all vesa modes, then screen-buffer mode
+ getvalidvesamodes();
+ if (vidoption == 1)
+ {
+ for(i=0;i<validmodecnt;i++)
+ if ((validmodexdim[i] == xdim) && (validmodeydim[i] == ydim))
+ {
+ if (i == validmodecnt-1)
+ setgamemode(2,320L,200L);
+ else
+ setgamemode(1,validmodexdim[i+1],validmodeydim[i+1]);
+ break;
+ }
+ }
+ else if (validmodecnt > 0)
+ setgamemode(1,validmodexdim[0],validmodeydim[0]);
+
+ inittimer42(); //Must init here because VESA 0x4F02 messes timer 2
+ }
+
+ if (keystatus[0x2a]|keystatus[0x36])
+ {
+ if (keystatus[0xcf]) hang = max(hang-1,-182);
+ if (keystatus[0xc7]) hang = min(hang+1,182);
+ }
+ else
+ {
+ if (keystatus[0xcf]) hang = max(hang-8,-182);
+ if (keystatus[0xc7]) hang = min(hang+8,182);
+ }
+ if (keystatus[0x4c]) { hang = 0; horiz = 100; }
+ if (hang != 0)
+ {
+ walock[4094] = 255;
+ if (waloff[4094] == 0) allocache(&waloff[4094],240L*384L,&walock[4094]);
+ setviewtotile(4094,240L,384L);
+
+ cosang = sintable[(hang+512)&2047];
+ sinang = sintable[hang&2047];
+
+ dx = dmulscale1(320,cosang,200,sinang); mindx = dx;
+ dy = dmulscale1(-200,cosang,320,sinang);
+ horizval1 = dy*(320>>1)/dx-1;
+
+ dx = dmulscale1(320,cosang,-200,sinang); mindx = min(dx,mindx);
+ dy = dmulscale1(200,cosang,320,sinang);
+ horizval2 = dy*(320>>1)/dx+1;
+
+ daviewingrange = scale(65536,16384*(xdim>>1),mindx-16);
+ daaspect = scale(daviewingrange,scale(320,tilesizx[4094],tilesizy[4094]),horizval2+6-horizval1);
+ setaspect(daviewingrange,scale(daaspect,ydim*320,xdim*200));
+ horiz = 100-divscale15(horizval1+horizval2,daviewingrange);
+ }
+}
+
+#define MAXVOXMIPS 5
+extern char *voxoff[][MAXVOXMIPS];
+void ExtAnalyzeSprites(void)
+{
+ long i, *longptr;
+ spritetype *tspr;
+
+ for(i=0,tspr=&tsprite[0];i<spritesortcnt;i++,tspr++)
+ {
+ switch(tspr->picnum)
+ {
+ case PLAYER:
+ if (!voxoff[0][0]) qloadkvx(0L,"voxel000.kvx");
+ tspr->cstat |= 48;
+ longptr = (long *)voxoff[0][0];
+ tspr->xrepeat = scale(tspr->xrepeat,56,longptr[2]);
+ tspr->yrepeat = scale(tspr->yrepeat,56,longptr[2]);
+ tspr->picnum = 0;
+ tspr->shade -= 6;
+ break;
+ case BROWNMONSTER:
+ if (!voxoff[1][0]) qloadkvx(1L,"voxel001.kvx");
+ tspr->cstat |= 48;
+ tspr->picnum = 1;
+ break;
+ }
+
+ tspr->shade += 6;
+ if (sector[tspr->sectnum].ceilingstat&1)
+ tspr->shade += sector[tspr->sectnum].ceilingshade;
+ else
+ tspr->shade += sector[tspr->sectnum].floorshade;
+ }
+}
+
+static char timerinited = 0;
+void ExtCheckKeys(void)
+{
+ long i, j, p, y, dx, dy, cosang, sinang, bufplc, tsizy, tsizyup15;
+
+ if (qsetmode == 200) //In 3D mode
+ {
+ if (hang != 0)
+ {
+ bufplc = waloff[4094]+(mulscale16(horiz-100,xdimenscale)+(tilesizx[4094]>>1))*tilesizy[4094];
+ setviewback();
+ cosang = sintable[(hang+512)&2047];
+ sinang = sintable[hang&2047];
+ dx = dmulscale1(xdim,cosang,ydim,sinang);
+ dy = dmulscale1(-ydim,cosang,xdim,sinang);
+
+ tsizy = tilesizy[4094];
+ tsizyup15 = (tsizy<<15);
+ dx = mulscale14(dx,daviewingrange);
+ dy = mulscale14(dy,daaspect);
+ sinang = mulscale14(sinang,daviewingrange);
+ cosang = mulscale14(cosang,daaspect);
+ p = ylookup[windowy1]+frameplace+windowx2+1;
+ for(y=windowy1;y<=windowy2;y++)
+ {
+ i = divscale16(tsizyup15,dx);
+ stretchhline(0,(xdim>>1)*i+tsizyup15,xdim>>2,i,mulscale32(i,dy)*tsizy+bufplc,p);
+ dx -= sinang; dy += cosang; p += ylookup[1];
+ }
+ walock[4094] = 1;
+
+ sprintf(tempbuf,"%ld",(hang*180)>>10);
+ printext256(0L,8L,31,-1,tempbuf,1);
+ }
+
+ if (keystatus[0xa]) setaspect(viewingrange+(viewingrange>>8),yxaspect+(yxaspect>>8));
+ if (keystatus[0xb]) setaspect(viewingrange-(viewingrange>>8),yxaspect-(yxaspect>>8));
+ if (keystatus[0xc]) setaspect(viewingrange,yxaspect-(yxaspect>>8));
+ if (keystatus[0xd]) setaspect(viewingrange,yxaspect+(yxaspect>>8));
+
+ if (!timerinited)
+ {
+ timerinited = 1;
+ inittimer42(); //Must init here because VESA 0x4F02 messes timer 2
+ }
+ i = totalclock-ototalclock; ototalclock += i;
+ j = ofinetotalclock-gettimer42(); ofinetotalclock -= j;
+ i = ((i*(1193181/120)-(j&65535)+32768)&0xffff0000)+(j&65535);
+ if (i) { frameval[framecnt&(AVERAGEFRAMES-1)] = 11931810/i; framecnt++; }
+ //Print MAX FRAME RATE
+ i = frameval[(framecnt-1)&(AVERAGEFRAMES-1)];
+ for(j=AVERAGEFRAMES-1;j>0;j--) i = max(i,frameval[j]);
+ averagefps = ((averagefps*3+i)>>2);
+ sprintf(tempbuf,"%ld.%ld",averagefps/10,averagefps%10);
+ printext256(0L,0L,31,-1,tempbuf,1);
+
+ editinput();
+ }
+ else
+ {
+ timerinited = 0;
+ }
+}
+
+void ExtCleanUp(void)
+{
+}
+
+void ExtLoadMap(const char *mapname)
+{
+}
+
+void ExtSaveMap(const char *mapname)
+{
+}
+
+const char *ExtGetSectorCaption(short sectnum)
+{
+ if ((sector[sectnum].lotag|sector[sectnum].hitag) == 0)
+ {
+ tempbuf[0] = 0;
+ }
+ else
+ {
+ sprintf(tempbuf,"%hu,%hu",(unsigned short)sector[sectnum].hitag,
+ (unsigned short)sector[sectnum].lotag);
+ }
+ return(tempbuf);
+}
+
+const char *ExtGetWallCaption(short wallnum)
+{
+ if ((wall[wallnum].lotag|wall[wallnum].hitag) == 0)
+ {
+ tempbuf[0] = 0;
+ }
+ else
+ {
+ sprintf(tempbuf,"%hu,%hu",(unsigned short)wall[wallnum].hitag,
+ (unsigned short)wall[wallnum].lotag);
+ }
+ return(tempbuf);
+}
+
+const char *ExtGetSpriteCaption(short spritenum)
+{
+ if ((sprite[spritenum].lotag|sprite[spritenum].hitag) == 0)
+ {
+ tempbuf[0] = 0;
+ }
+ else
+ {
+ sprintf(tempbuf,"%hu,%hu",(unsigned short)sprite[spritenum].hitag,
+ (unsigned short)sprite[spritenum].lotag);
+ }
+ return(tempbuf);
+}
+
+//printext16 parameters:
+//printext16(long xpos, long ypos, short col, short backcol,
+// char name[82], char fontsize)
+// xpos 0-639 (top left)
+// ypos 0-479 (top left)
+// col 0-15
+// backcol 0-15, -1 is transparent background
+// name
+// fontsize 0=8*8, 1=3*5
+
+//drawline16 parameters:
+// drawline16(long x1, long y1, long x2, long y2, char col)
+// x1, x2 0-639
+// y1, y2 0-143 (status bar is 144 high, origin is top-left of STATUS BAR)
+// col 0-15
+
+void ExtShowSectorData(short sectnum) //F5
+{
+ if (qsetmode == 200) //In 3D mode
+ {
+ }
+ else
+ {
+ clearmidstatbar16(); //Clear middle of status bar
+
+ sprintf(tempbuf,"Sector %d",sectnum);
+ printext16(8,32,11,-1,tempbuf,0);
+
+ printext16(8,48,11,-1,"8*8 font: ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789",0);
+ printext16(8,56,11,-1,"3*5 font: ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789",1);
+
+ drawline16(320,68,344,80,4); //Draw house
+ drawline16(344,80,344,116,4);
+ drawline16(344,116,296,116,4);
+ drawline16(296,116,296,80,4);
+ drawline16(296,80,320,68,4);
+ }
+}
+
+void ExtShowWallData(short wallnum) //F6
+{
+ if (qsetmode == 200) //In 3D mode
+ {
+ }
+ else
+ {
+ clearmidstatbar16(); //Clear middle of status bar
+
+ sprintf(tempbuf,"Wall %d",wallnum);
+ printext16(8,32,11,-1,tempbuf,0);
+ }
+}
+
+void ExtShowSpriteData(short spritenum) //F6
+{
+ if (qsetmode == 200) //In 3D mode
+ {
+ }
+ else
+ {
+ clearmidstatbar16(); //Clear middle of status bar
+
+ sprintf(tempbuf,"Sprite %d",spritenum);
+ printext16(8,32,11,-1,tempbuf,0);
+ }
+}
+
+void ExtEditSectorData(short sectnum) //F7
+{
+ short nickdata;
+
+ if (qsetmode == 200) //In 3D mode
+ {
+ //Ceiling
+ if (searchstat == 1)
+ sector[searchsector].ceilingpicnum++; //Just a stupid example
+
+ //Floor
+ if (searchstat == 2)
+ sector[searchsector].floorshade++; //Just a stupid example
+ }
+ else //In 2D mode
+ {
+ sprintf(tempbuf,"Sector (%ld) Nick's variable: ",sectnum);
+ nickdata = 0;
+ nickdata = getnumber16(tempbuf,nickdata,65536L);
+
+ printmessage16(""); //Clear message box (top right of status bar)
+ ExtShowSectorData(sectnum);
+ }
+}
+
+void ExtEditWallData(short wallnum) //F8
+{
+ short nickdata;
+
+ if (qsetmode == 200) //In 3D mode
+ {
+ }
+ else
+ {
+ sprintf(tempbuf,"Wall (%ld) Nick's variable: ",wallnum);
+ nickdata = 0;
+ nickdata = getnumber16(tempbuf,nickdata,65536L);
+
+ printmessage16(""); //Clear message box (top right of status bar)
+ ExtShowWallData(wallnum);
+ }
+}
+
+void ExtEditSpriteData(short spritenum) //F8
+{
+ short nickdata;
+
+ if (qsetmode == 200) //In 3D mode
+ {
+ }
+ else
+ {
+ sprintf(tempbuf,"Sprite (%ld) Nick's variable: ",spritenum);
+ nickdata = 0;
+ nickdata = getnumber16(tempbuf,nickdata,65536L);
+ printmessage16("");
+
+ printmessage16(""); //Clear message box (top right of status bar)
+ ExtShowSpriteData(spritenum);
+ }
+}
+
+faketimerhandler()
+{
+}
+
+ //Just thought you might want my getnumber16 code
+/*
+getnumber16(char namestart[80], short num, long maxnumber)
+{
+ char buffer[80];
+ long j, k, n, danum, oldnum;
+
+ danum = (long)num;
+ oldnum = danum;
+ while ((keystatus[0x1c] != 2) && (keystatus[0x1] == 0)) //Enter, ESC
+ {
+ sprintf(&buffer,"%s%ld_ ",namestart,danum);
+ printmessage16(buffer);
+
+ for(j=2;j<=11;j++) //Scan numbers 0-9
+ if (keystatus[j] > 0)
+ {
+ keystatus[j] = 0;
+ k = j-1;
+ if (k == 10) k = 0;
+ n = (danum*10)+k;
+ if (n < maxnumber) danum = n;
+ }
+ if (keystatus[0xe] > 0) // backspace
+ {
+ danum /= 10;
+ keystatus[0xe] = 0;
+ }
+ if (keystatus[0x1c] == 1) //L. enter
+ {
+ oldnum = danum;
+ keystatus[0x1c] = 2;
+ asksave = 1;
+ }
+ }
+ keystatus[0x1c] = 0;
+ keystatus[0x1] = 0;
+ return((short)oldnum);
+}
+*/
diff --git a/SRC/BUILD.C b/SRC/BUILD.C
new file mode 100644
index 0000000..36aaad6
--- /dev/null
+++ b/SRC/BUILD.C
@@ -0,0 +1,6589 @@
+// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
+// Ken Silverman's official web site: "http://www.advsys.net/ken"
+// See the included license file "BUILDLIC.TXT" for license info.
+
+#include <dos.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <io.h>
+#include <sys\types.h>
+#include <sys\stat.h>
+#include "build.h"
+#include "pragmas.h"
+
+#pragma intrinsic(min);
+#pragma intrinsic(max);
+
+#define MAXMENUFILES 256
+#define updatecrc16(crc,dat) (crc = (((crc<<8)&65535)^crctable[((((unsigned short)crc)>>8)&65535)^dat]))
+static long crctable[256];
+static char kensig[24];
+
+extern void ExtLoadMap(const char *mapname);
+extern void ExtSaveMap(const char *mapname);
+extern const char *ExtGetSectorCaption(short sectnum);
+extern const char *ExtGetWallCaption(short wallnum);
+extern const char *ExtGetSpriteCaption(short spritenum);
+extern void ExtShowSectorData(short sectnum);
+extern void ExtShowWallData(short wallnum);
+extern void ExtShowSpriteData(short spritenum);
+extern void ExtEditSectorData(short sectnum);
+extern void ExtEditWallData(short wallnum);
+extern void ExtEditSpriteData(short spritenum);
+
+void (__interrupt __far *oldtimerhandler)();
+void __interrupt __far timerhandler(void);
+
+#define KEYFIFOSIZ 64
+void (__interrupt __far *oldkeyhandler)();
+void __interrupt __far keyhandler(void);
+volatile char keystatus[256], keyfifo[KEYFIFOSIZ], keyfifoplc, keyfifoend;
+volatile char readch, oldreadch, extended, keytemp;
+
+long vel, svel, angvel;
+
+#define NUMKEYS 19
+char buildkeys[NUMKEYS] =
+{
+ 0xc8,0xd0,0xcb,0xcd,0x2a,0x9d,0x1d,0x39,
+ 0x1e,0x2c,0xd1,0xc9,0x33,0x34,
+ 0x9c,0x1c,0xd,0xc,0xf,
+};
+
+long posx, posy, posz, horiz = 100;
+short ang, cursectnum;
+long hvel;
+
+static long synctics = 0, lockclock = 0;
+
+extern long stereomode;
+extern char vgacompatible;
+
+extern char picsiz[MAXTILES];
+extern long startposx, startposy, startposz;
+extern short startang, startsectnum;
+extern long frameplace, pageoffset, ydim16;
+
+extern long cachesize, artsize;
+
+static short oldmousebstatus = 0, brightness = 0;
+long zlock = 0x7fffffff, zmode = 0, whitecol, kensplayerheight = 32;
+short defaultspritecstat = 0;
+
+static short localartfreq[MAXTILES];
+static short localartlookup[MAXTILES], localartlookupnum;
+
+char tempbuf[4096];
+
+char names[MAXTILES][17];
+
+short asksave = 0;
+extern short editstatus, searchit;
+extern long searchx, searchy; //search input
+extern short searchsector, searchwall, searchstat; //search output
+
+extern short pointhighlight, linehighlight, highlightcnt;
+short grid = 3, gridlock = 1, showtags = 1;
+long zoom = 768, gettilezoom = 1;
+
+long numsprites;
+
+short highlight[MAXWALLS];
+short highlightsector[MAXSECTORS], highlightsectorcnt = -1;
+extern char textfont[128][8];
+
+static char pskysearch[MAXSECTORS];
+
+short temppicnum, tempcstat, templotag, temphitag, tempextra;
+char tempshade, temppal, tempvis, tempxrepeat, tempyrepeat;
+char somethingintab = 255;
+static char boardfilename[13], oboardfilename[13];
+
+static long repeatcountx, repeatcounty;
+
+static char menuname[MAXMENUFILES][17], curpath[80], menupath[80];
+static long menunamecnt, menuhighlight;
+
+static long fillist[640];
+
+static char scantoasc[128] =
+{
+ 0,0,'1','2','3','4','5','6','7','8','9','0','-','=',0,0,
+ 'q','w','e','r','t','y','u','i','o','p','[',']',0,0,'a','s',
+ 'd','f','g','h','j','k','l',';',39,'`',0,92,'z','x','c','v',
+ 'b','n','m',',','.','/',0,'*',0,32,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,'7','8','9','-','4','5','6','+','1',
+ '2','3','0','.',0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+};
+static char scantoascwithshift[128] =
+{
+ 0,0,'!','@','#','$','%','^','&','*','(',')','_','+',0,0,
+ 'Q','W','E','R','T','Y','U','I','O','P','{','}',0,0,'A','S',
+ 'D','F','G','H','J','K','L',':',34,'~',0,'|','Z','X','C','V',
+ 'B','N','M','<','>','?',0,'*',0,32,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,'7','8','9','-','4','5','6','+','1',
+ '2','3','0','.',0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+};
+
+#pragma aux fillscreen16 =\
+ "mov dx, 0x3ce",\
+ "shl ax, 8",\
+ "out dx, ax",\
+ "mov ax, 0xff08",\
+ "out dx, ax",\
+ "shr ecx, 5",\
+ "add edi, 0xa0000",\
+ "rep stosd",\
+ parm [edi][eax][ecx]\
+ modify [edx]\
+
+main(short int argc,char **argv)
+{
+ char ch, quitflag;
+ long i, j, k;
+
+ editstatus = 1;
+ if (argc >= 2)
+ {
+ strcpy(&boardfilename,argv[1]);
+ if (strchr(boardfilename,'.') == 0)
+ strcat(boardfilename,".map");
+ }
+ else
+ strcpy(&boardfilename,"newboard.map");
+
+ ExtInit();
+ initkeys();
+ inittimer();
+
+ loadpics("tiles000.art");
+ loadnames();
+
+ strcpy(kensig,"BUILD by Ken Silverman");
+ initcrc();
+
+ if (setgamemode(vidoption,xdim,ydim) < 0)
+ {
+ ExtUnInit();
+ uninitkeys();
+ uninittimer();
+ printf("%ld * %ld not supported in this graphics mode\n",xdim,ydim);
+ exit(0);
+ }
+
+ k = 0;
+ for(i=0;i<256;i++)
+ {
+ j = ((long)palette[i*3])+((long)palette[i*3+1])+((long)palette[i*3+2]);
+ if (j > k) { k = j; whitecol = i; }
+ }
+
+ initmenupaths(argv[0]);
+ menunamecnt = 0;
+ menuhighlight = 0;
+
+ for(i=0;i<MAXSECTORS;i++) sector[i].extra = -1;
+ for(i=0;i<MAXWALLS;i++) wall[i].extra = -1;
+ for(i=0;i<MAXSPRITES;i++) sprite[i].extra = -1;
+
+ if (loadboard(boardfilename,&posx,&posy,&posz,&ang,&cursectnum) == -1)
+ {
+ initspritelists();
+ posx = 32768;
+ posy = 32768;
+ posz = 0;
+ ang = 1536;
+ numsectors = 0;
+ numwalls = 0;
+ cursectnum = -1;
+ overheadeditor();
+ keystatus[buildkeys[14]] = 0;
+ }
+ else
+ {
+ ExtLoadMap(boardfilename);
+ }
+
+ updatenumsprites();
+
+ startposx = posx;
+ startposy = posy;
+ startposz = posz;
+ startang = ang;
+ startsectnum = cursectnum;
+
+ totalclock = 0;
+
+ quitflag = 0;
+ while (quitflag == 0)
+ {
+ ExtPreCheckKeys();
+
+ drawrooms(posx,posy,posz,ang,horiz,cursectnum);
+ ExtAnalyzeSprites();
+ drawmasks();
+
+ ExtCheckKeys();
+
+ nextpage();
+ synctics = totalclock-lockclock;
+ lockclock += synctics;
+
+ if (keystatus[1] > 0)
+ {
+ keystatus[1] = 0;
+ printext256(0,0,whitecol,0,"Really want to quit?",0);
+
+ nextpage();
+ synctics = totalclock-lockclock;
+ lockclock += synctics;
+
+ while ((keystatus[1]|keystatus[0x1c]|keystatus[0x39]|keystatus[0x31]) == 0)
+ {
+ if (keystatus[0x15] != 0) { quitflag = 1; break; }
+ }
+ }
+ }
+ uninittimer();
+ uninitkeys();
+ ExtUnInit();
+ uninitengine();
+ setvmode(0x3);
+
+ if (asksave)
+ {
+ printf("Save changes?\n");
+ do
+ {
+ ch = getch();
+ }
+ while ((ch != 'y') && (ch != 'Y') && (ch != 'n') && (ch != 'N'));
+ if ((ch == 'y') || (ch == 'Y'))
+ {
+ updatesector(startposx,startposy,&startsectnum);
+ saveboard(boardfilename,&startposx,&startposy,&startposz,&startang,&startsectnum);
+ ExtSaveMap(boardfilename);
+ }
+ }
+ printf("Memory status: %ld(%ld) bytes\n",cachesize,artsize);
+ printf("%s\n",kensig);
+ return(0);
+}
+
+showmouse()
+{
+ long i;
+
+ for(i=1;i<=4;i++)
+ {
+ plotpixel(searchx+i,searchy,whitecol);
+ plotpixel(searchx-i,searchy,whitecol);
+ plotpixel(searchx,searchy-i,whitecol);
+ plotpixel(searchx,searchy+i,whitecol);
+ }
+}
+
+editinput()
+{
+ char smooshyalign, repeatpanalign, *ptr, buffer[80];
+ short sectnum, nextsectnum, startwall, endwall, dasector, daang;
+ short mousx, mousy, mousz, bstatus;
+ long i, j, k, cnt, templong, doubvel, changedir, wallfind[2], daz[2];
+ long dashade[2], goalz, xvect, yvect, hiz, loz;
+ short hitsect, hitwall, hitsprite;
+ long hitx, hity, hitz, dax, day, hihit, lohit;
+
+ if (keystatus[0x57] > 0) //F11 - brightness
+ {
+ keystatus[0x57] = 0;
+ brightness++;
+ if (brightness > 16) brightness = 0;
+ setbrightness(brightness,palette);
+ }
+ if (keystatus[88] > 0) //F12
+ {
+ screencapture("captxxxx.pcx",keystatus[0x2a]|keystatus[0x36]);
+ keystatus[88] = 0;
+ }
+
+ mousz = 0;
+ getmousevalues(&mousx,&mousy,&bstatus);
+ searchx += (mousx>>1);
+ searchy += (mousy>>1);
+ if (searchx < 4) searchx = 4;
+ if (searchy < 4) searchy = 4;
+ if (searchx > xdim-5) searchx = xdim-5;
+ if (searchy > ydim-5) searchy = ydim-5;
+ showmouse();
+
+ if (keystatus[0x3b] > 0) posx--;
+ if (keystatus[0x3c] > 0) posx++;
+ if (keystatus[0x3d] > 0) posy--;
+ if (keystatus[0x3e] > 0) posy++;
+ if (keystatus[0x43] > 0) ang--;
+ if (keystatus[0x44] > 0) ang++;
+
+ if (angvel != 0) //ang += angvel * constant
+ { //ENGINE calculates angvel for you
+ doubvel = synctics;
+ if (keystatus[buildkeys[4]] > 0) //Lt. shift makes turn velocity 50% faster
+ doubvel += (synctics>>1);
+ ang += ((angvel*doubvel)>>4);
+ ang = (ang+2048)&2047;
+ }
+ if ((vel|svel) != 0)
+ {
+ doubvel = synctics;
+ if (keystatus[buildkeys[4]] > 0) //Lt. shift doubles forward velocity
+ doubvel += synctics;
+ xvect = 0, yvect = 0;
+ if (vel != 0)
+ {
+ xvect += ((vel*doubvel*(long)sintable[(ang+2560)&2047])>>3);
+ yvect += ((vel*doubvel*(long)sintable[(ang+2048)&2047])>>3);
+ }
+ if (svel != 0)
+ {
+ xvect += ((svel*doubvel*(long)sintable[(ang+2048)&2047])>>3);
+ yvect += ((svel*doubvel*(long)sintable[(ang+1536)&2047])>>3);
+ }
+ clipmove(&posx,&posy,&posz,&cursectnum,xvect,yvect,128L,4L<<8,4L<<8,CLIPMASK0);
+ }
+ getzrange(posx,posy,posz,cursectnum,&hiz,&hihit,&loz,&lohit,128L,CLIPMASK0);
+
+ if (keystatus[0x3a] > 0)
+ {
+ zmode++;
+ if (zmode == 3) zmode = 0;
+ if (zmode == 1) zlock = (loz-posz)&0xfffffc00;
+ keystatus[0x3a] = 0;
+ }
+
+ if (zmode == 0)
+ {
+ goalz = loz-(kensplayerheight<<8); //playerheight pixels above floor
+ if (goalz < hiz+(16<<8)) //ceiling&floor too close
+ goalz = ((loz+hiz)>>1);
+ goalz += mousz;
+ if (keystatus[buildkeys[8]] > 0) //A (stand high)
+ {
+ if (keystatus[0x1d] > 0)
+ horiz = max(-100,horiz-((keystatus[buildkeys[4]]+1)<<2));
+ else
+ {
+ goalz -= (16<<8);
+ if (keystatus[buildkeys[4]] > 0) //Either shift key
+ goalz -= (24<<8);
+ }
+ }
+ if (keystatus[buildkeys[9]] > 0) //Z (stand low)
+ {
+ if (keystatus[0x1d] > 0)
+ horiz = min(300,horiz+((keystatus[buildkeys[4]]+1)<<2));
+ else
+ {
+ goalz += (12<<8);
+ if (keystatus[buildkeys[4]] > 0) //Either shift key
+ goalz += (12<<8);
+ }
+ }
+
+ if (goalz != posz)
+ {
+ if (posz < goalz) hvel += 32;
+ if (posz > goalz) hvel = ((goalz-posz)>>3);
+
+ posz += hvel;
+ if (posz > loz-(4<<8)) posz = loz-(4<<8), hvel = 0;
+ if (posz < hiz+(4<<8)) posz = hiz+(4<<8), hvel = 0;
+ }
+ }
+ else
+ {
+ goalz = posz;
+ if (keystatus[buildkeys[8]] > 0) //A
+ {
+ if (keystatus[0x1d] > 0)
+ horiz = max(-100,horiz-((keystatus[buildkeys[4]]+1)<<2));
+ else
+ {
+ if (zmode != 1)
+ goalz -= (8<<8);
+ else
+ {
+ zlock += (4<<8);
+ keystatus[buildkeys[8]] = 0;
+ }
+ }
+ }
+ if (keystatus[buildkeys[9]] > 0) //Z (stand low)
+ {
+ if (keystatus[0x1d] > 0)
+ horiz = min(300,horiz+((keystatus[buildkeys[4]]+1)<<2));
+ else
+ {
+ if (zmode != 1)
+ goalz += (8<<8);
+ else if (zlock > 0)
+ {
+ zlock -= (4<<8);
+ keystatus[buildkeys[9]] = 0;
+ }
+ }
+ }
+
+ if (goalz < hiz+(4<<8)) goalz = hiz+(4<<8);
+ if (goalz > loz-(4<<8)) goalz = loz-(4<<8);
+ if (zmode == 1) goalz = loz-zlock;
+ if (goalz < hiz+(4<<8)) goalz = ((loz+hiz)>>1); //ceiling&floor too close
+ if (zmode == 1) posz = goalz;
+
+ if (goalz != posz)
+ {
+ if (posz < goalz) hvel += (32<<keystatus[buildkeys[4]]);
+ if (posz > goalz) hvel -= (32<<keystatus[buildkeys[4]]);
+
+ posz += hvel;
+
+ if (posz > loz-(4<<8)) posz = loz-(4<<8), hvel = 0;
+ if (posz < hiz+(4<<8)) posz = hiz+(4<<8), hvel = 0;
+ }
+ else
+ hvel = 0;
+ }
+
+ searchit = 2;
+ if (searchstat >= 0)
+ {
+ if ((bstatus&1) > 0)
+ searchit = 0;
+ if (keystatus[0x4a] > 0) // -
+ {
+ keystatus[0x4a] = 0;
+ if ((keystatus[0x38]|keystatus[0xb8]) > 0) //ALT
+ {
+ if ((keystatus[0x1d]|keystatus[0x9d]) > 0) //CTRL
+ {
+ if (visibility < 16384) visibility += visibility;
+ }
+ else
+ {
+ if ((keystatus[0x2a]|keystatus[0x36]) == 0)
+ k = 16; else k = 1;
+
+ if (highlightsectorcnt >= 0)
+ for(i=0;i<highlightsectorcnt;i++)
+ if (highlightsector[i] == searchsector)
+ {
+ while (k > 0)
+ {
+ for(i=0;i<highlightsectorcnt;i++)
+ {
+ sector[highlightsector[i]].visibility++;
+ if (sector[highlightsector[i]].visibility == 240)
+ sector[highlightsector[i]].visibility = 239;
+ }
+ k--;
+ }
+ break;
+ }
+ while (k > 0)
+ {
+ sector[searchsector].visibility++;
+ if (sector[searchsector].visibility == 240)
+ sector[searchsector].visibility = 239;
+ k--;
+ }
+ asksave = 1;
+ }
+ }
+ else
+ {
+ k = 0;
+ if (highlightsectorcnt >= 0)
+ {
+ for(i=0;i<highlightsectorcnt;i++)
+ if (highlightsector[i] == searchsector)
+ {
+ k = 1;
+ break;
+ }
+ }
+
+ if (k == 0)
+ {
+ if (searchstat == 0) wall[searchwall].shade++;
+ if (searchstat == 1) sector[searchsector].ceilingshade++;
+ if (searchstat == 2) sector[searchsector].floorshade++;
+ if (searchstat == 3) sprite[searchwall].shade++;
+ if (searchstat == 4) wall[searchwall].shade++;
+ }
+ else
+ {
+ for(i=0;i<highlightsectorcnt;i++)
+ {
+ dasector = highlightsector[i];
+
+ sector[dasector].ceilingshade++; //sector shade
+ sector[dasector].floorshade++;
+
+ startwall = sector[dasector].wallptr; //wall shade
+ endwall = startwall + sector[dasector].wallnum - 1;
+ for(j=startwall;j<=endwall;j++)
+ wall[j].shade++;
+
+ j = headspritesect[dasector]; //sprite shade
+ while (j != -1)
+ {
+ sprite[j].shade++;
+ j = nextspritesect[j];
+ }
+ }
+ }
+ asksave = 1;
+ }
+ }
+ if (keystatus[0x4e] > 0) // +
+ {
+ keystatus[0x4e] = 0;
+ if ((keystatus[0x38]|keystatus[0xb8]) > 0) //ALT
+ {
+ if ((keystatus[0x1d]|keystatus[0x9d]) > 0) //CTRL
+ {
+ if (visibility > 32) visibility >>= 1;
+ }
+ else
+ {
+ if ((keystatus[0x2a]|keystatus[0x36]) == 0)
+ k = 16; else k = 1;
+
+ if (highlightsectorcnt >= 0)
+ for(i=0;i<highlightsectorcnt;i++)
+ if (highlightsector[i] == searchsector)
+ {
+ while (k > 0)
+ {
+ for(i=0;i<highlightsectorcnt;i++)
+ {
+ sector[highlightsector[i]].visibility--;
+ if (sector[highlightsector[i]].visibility == 239)
+ sector[highlightsector[i]].visibility = 240;
+ }
+ k--;
+ }
+ break;
+ }
+ while (k > 0)
+ {
+ sector[searchsector].visibility--;
+ if (sector[searchsector].visibility == 239)
+ sector[searchsector].visibility = 240;
+ k--;
+ }
+ asksave = 1;
+ }
+ }
+ else
+ {
+ k = 0;
+ if (highlightsectorcnt >= 0)
+ {
+ for(i=0;i<highlightsectorcnt;i++)
+ if (highlightsector[i] == searchsector)
+ {
+ k = 1;
+ break;
+ }
+ }
+
+ if (k == 0)
+ {
+ if (searchstat == 0) wall[searchwall].shade--;
+ if (searchstat == 1) sector[searchsector].ceilingshade--;
+ if (searchstat == 2) sector[searchsector].floorshade--;
+ if (searchstat == 3) sprite[searchwall].shade--;
+ if (searchstat == 4) wall[searchwall].shade--;
+ }
+ else
+ {
+ for(i=0;i<highlightsectorcnt;i++)
+ {
+ dasector = highlightsector[i];
+
+ sector[dasector].ceilingshade--; //sector shade
+ sector[dasector].floorshade--;
+
+ startwall = sector[dasector].wallptr; //wall shade
+ endwall = startwall + sector[dasector].wallnum - 1;
+ for(j=startwall;j<=endwall;j++)
+ wall[j].shade--;
+
+ j = headspritesect[dasector]; //sprite shade
+ while (j != -1)
+ {
+ sprite[j].shade--;
+ j = nextspritesect[j];
+ }
+ }
+ }
+ asksave = 1;
+ }
+ }
+ if (keystatus[0xc9] > 0) // PGUP
+ {
+ k = 0;
+ if (highlightsectorcnt >= 0)
+ {
+ for(i=0;i<highlightsectorcnt;i++)
+ if (highlightsector[i] == searchsector)
+ {
+ k = 1;
+ break;
+ }
+ }
+
+ if ((searchstat == 0) || (searchstat == 1))
+ {
+ if (k == 0)
+ {
+ i = headspritesect[searchsector];
+ while (i != -1)
+ {
+ templong = getceilzofslope(searchsector,sprite[i].x,sprite[i].y);
+ templong += ((tilesizy[sprite[i].picnum]*sprite[i].yrepeat)<<2);
+ if (sprite[i].cstat&128) templong += ((tilesizy[sprite[i].picnum]*sprite[i].yrepeat)<<1);
+ if (sprite[i].z == templong)
+ sprite[i].z -= 1024;
+ i = nextspritesect[i];
+ }
+ sector[searchsector].ceilingz -= 1024;
+ }
+ else
+ {
+ for(j=0;j<highlightsectorcnt;j++)
+ {
+ i = headspritesect[highlightsector[j]];
+ while (i != -1)
+ {
+ templong = getceilzofslope(highlightsector[j],sprite[i].x,sprite[i].y);
+ templong += ((tilesizy[sprite[i].picnum]*sprite[i].yrepeat)<<2);
+ if (sprite[i].cstat&128) templong += ((tilesizy[sprite[i].picnum]*sprite[i].yrepeat)<<1);
+ if (sprite[i].z == templong)
+ sprite[i].z -= 1024;
+ i = nextspritesect[i];
+ }
+ sector[highlightsector[j]].ceilingz -= 1024;
+ }
+ }
+ }
+ if (searchstat == 2)
+ {
+ if (k == 0)
+ {
+ i = headspritesect[searchsector];
+ while (i != -1)
+ {
+ templong = getflorzofslope(searchsector,sprite[i].x,sprite[i].y);
+ if (sprite[i].cstat&128) templong += ((tilesizy[sprite[i].picnum]*sprite[i].yrepeat)<<1);
+ if (sprite[i].z == templong)
+ sprite[i].z -= 1024;
+ i = nextspritesect[i];
+ }
+ sector[searchsector].floorz -= 1024;
+ }
+ else
+ {
+ for(j=0;j<highlightsectorcnt;j++)
+ {
+ i = headspritesect[highlightsector[j]];
+ while (i != -1)
+ {
+ templong = getflorzofslope(highlightsector[j],sprite[i].x,sprite[i].y);
+ if (sprite[i].cstat&128) templong += ((tilesizy[sprite[i].picnum]*sprite[i].yrepeat)<<1);
+ if (sprite[i].z == templong)
+ sprite[i].z -= 1024;
+ i = nextspritesect[i];
+ }
+ sector[highlightsector[j]].floorz -= 1024;
+ }
+ }
+ }
+ if (sector[searchsector].floorz < sector[searchsector].ceilingz)
+ sector[searchsector].floorz = sector[searchsector].ceilingz;
+ if (searchstat == 3)
+ {
+ if ((keystatus[0x1d]|keystatus[0x9d]) > 0) //CTRL - put sprite on ceiling
+ {
+ sprite[searchwall].z = getceilzofslope(searchsector,sprite[searchwall].x,sprite[searchwall].y);
+ if (sprite[searchwall].cstat&128) sprite[searchwall].z -= ((tilesizy[sprite[searchwall].picnum]*sprite[searchwall].yrepeat)<<1);
+ if ((sprite[searchwall].cstat&48) != 32)
+ sprite[searchwall].z += ((tilesizy[sprite[searchwall].picnum]*sprite[searchwall].yrepeat)<<2);
+ }
+ else
+ {
+ k = 0;
+ if (highlightcnt >= 0)
+ for(i=0;i<highlightcnt;i++)
+ if (highlight[i] == searchwall+16384)
+ {
+ k = 1;
+ break;
+ }
+
+ if (k == 0)
+ sprite[searchwall].z -= (4<<8);
+ else
+ {
+ for(i=0;i<highlightcnt;i++)
+ if ((highlight[i]&0xc000) == 16384)
+ sprite[highlight[i]&16383].z -= (4<<8);
+ }
+ }
+ }
+ asksave = 1;
+ keystatus[0xc9] = 0;
+ }
+ if (keystatus[0xd1] > 0) // PGDN
+ {
+ k = 0;
+ if (highlightsectorcnt >= 0)
+ {
+ for(i=0;i<highlightsectorcnt;i++)
+ if (highlightsector[i] == searchsector)
+ {
+ k = 1;
+ break;
+ }
+ }
+
+ if ((searchstat == 0) || (searchstat == 1))
+ {
+ if (k == 0)
+ {
+ i = headspritesect[searchsector];
+ while (i != -1)
+ {
+ templong = getceilzofslope(searchsector,sprite[i].x,sprite[i].y);
+ if (sprite[i].cstat&128) templong += ((tilesizy[sprite[i].picnum]*sprite[i].yrepeat)<<1);
+ templong += ((tilesizy[sprite[i].picnum]*sprite[i].yrepeat)<<2);
+ if (sprite[i].z == templong)
+ sprite[i].z += 1024;
+ i = nextspritesect[i];
+ }
+ sector[searchsector].ceilingz += 1024;
+ }
+ else
+ {
+ for(j=0;j<highlightsectorcnt;j++)
+ {
+ i = headspritesect[highlightsector[j]];
+ while (i != -1)
+ {
+ templong = getceilzofslope(highlightsector[j],sprite[i].x,sprite[i].y);
+ if (sprite[i].cstat&128) templong += ((tilesizy[sprite[i].picnum]*sprite[i].yrepeat)<<1);
+ templong += ((tilesizy[sprite[i].picnum]*sprite[i].yrepeat)<<2);
+ if (sprite[i].z == templong)
+ sprite[i].z += 1024;
+ i = nextspritesect[i];
+ }
+ sector[highlightsector[j]].ceilingz += 1024;
+ }
+ }
+ }
+ if (searchstat == 2)
+ {
+ if (k == 0)
+ {
+ i = headspritesect[searchsector];
+ while (i != -1)
+ {
+ templong = getflorzofslope(searchsector,sprite[i].x,sprite[i].y);
+ if (sprite[i].cstat&128) templong += ((tilesizy[sprite[i].picnum]*sprite[i].yrepeat)<<1);
+ if (sprite[i].z == templong)
+ sprite[i].z += 1024;
+ i = nextspritesect[i];
+ }
+ sector[searchsector].floorz += 1024;
+ }
+ else
+ {
+ for(j=0;j<highlightsectorcnt;j++)
+ {
+ i = headspritesect[highlightsector[j]];
+ while (i != -1)
+ {
+ templong = getflorzofslope(highlightsector[j],sprite[i].x,sprite[i].y);
+ if (sprite[i].cstat&128) templong += ((tilesizy[sprite[i].picnum]*sprite[i].yrepeat)<<1);
+ if (sprite[i].z == templong)
+ sprite[i].z += 1024;
+ i = nextspritesect[i];
+ }
+ sector[highlightsector[j]].floorz += 1024;
+ }
+ }
+ }
+ if (sector[searchsector].ceilingz > sector[searchsector].floorz)
+ sector[searchsector].ceilingz = sector[searchsector].floorz;
+ if (searchstat == 3)
+ {
+ if ((keystatus[0x1d]|keystatus[0x9d]) > 0) //CTRL - put sprite on ground
+ {
+ sprite[searchwall].z = getflorzofslope(searchsector,sprite[searchwall].x,sprite[searchwall].y);
+ if (sprite[searchwall].cstat&128) sprite[searchwall].z -= ((tilesizy[sprite[searchwall].picnum]*sprite[searchwall].yrepeat)<<1);
+ }
+ else
+ {
+ k = 0;
+ if (highlightcnt >= 0)
+ for(i=0;i<highlightcnt;i++)
+ if (highlight[i] == searchwall+16384)
+ {
+ k = 1;
+ break;
+ }
+
+ if (k == 0)
+ sprite[searchwall].z += (4<<8);
+ else
+ {
+ for(i=0;i<highlightcnt;i++)
+ if ((highlight[i]&0xc000) == 16384)
+ sprite[highlight[i]&16383].z += (4<<8);
+ }
+ }
+ }
+ asksave = 1;
+ keystatus[0xd1] = 0;
+ }
+ if (keystatus[0x0f] > 0) //TAB
+ {
+ if (searchstat == 0)
+ {
+ temppicnum = wall[searchwall].picnum;
+ tempshade = wall[searchwall].shade;
+ temppal = wall[searchwall].pal;
+ tempxrepeat = wall[searchwall].xrepeat;
+ tempyrepeat = wall[searchwall].yrepeat;
+ tempcstat = wall[searchwall].cstat;
+ templotag = wall[searchwall].lotag;
+ temphitag = wall[searchwall].hitag;
+ tempextra = wall[searchwall].extra;
+ }
+ if (searchstat == 1)
+ {
+ temppicnum = sector[searchsector].ceilingpicnum;
+ tempshade = sector[searchsector].ceilingshade;
+ temppal = sector[searchsector].ceilingpal;
+ tempvis = sector[searchsector].visibility;
+ tempxrepeat = sector[searchsector].ceilingxpanning;
+ tempyrepeat = sector[searchsector].ceilingypanning;
+ tempcstat = sector[searchsector].ceilingstat;
+ templotag = sector[searchsector].lotag;
+ temphitag = sector[searchsector].hitag;
+ tempextra = sector[searchsector].extra;
+ }
+ if (searchstat == 2)
+ {
+ temppicnum = sector[searchsector].floorpicnum;
+ tempshade = sector[searchsector].floorshade;
+ temppal = sector[searchsector].floorpal;
+ tempvis = sector[searchsector].visibility;
+ tempxrepeat = sector[searchsector].floorxpanning;
+ tempyrepeat = sector[searchsector].floorypanning;
+ tempcstat = sector[searchsector].floorstat;
+ templotag = sector[searchsector].lotag;
+ temphitag = sector[searchsector].hitag;
+ tempextra = sector[searchsector].extra;
+ }
+ if (searchstat == 3)
+ {
+ temppicnum = sprite[searchwall].picnum;
+ tempshade = sprite[searchwall].shade;
+ temppal = sprite[searchwall].pal;
+ tempxrepeat = sprite[searchwall].xrepeat;
+ tempyrepeat = sprite[searchwall].yrepeat;
+ tempcstat = sprite[searchwall].cstat;
+ templotag = sprite[searchwall].lotag;
+ temphitag = sprite[searchwall].hitag;
+ tempextra = sprite[searchwall].extra;
+ }
+ if (searchstat == 4)
+ {
+ temppicnum = wall[searchwall].overpicnum;
+ tempshade = wall[searchwall].shade;
+ temppal = wall[searchwall].pal;
+ tempxrepeat = wall[searchwall].xrepeat;
+ tempyrepeat = wall[searchwall].yrepeat;
+ tempcstat = wall[searchwall].cstat;
+ templotag = wall[searchwall].lotag;
+ temphitag = wall[searchwall].hitag;
+ tempextra = wall[searchwall].extra;
+ }
+ somethingintab = searchstat;
+ keystatus[0x0f] = 0;
+ }
+ if (keystatus[0x1c] > 0) //Left ENTER
+ {
+ if ((keystatus[0x2a]|keystatus[0x36]) > 0) //Either shift key
+ {
+ if (((searchstat == 0) || (searchstat == 4)) && ((keystatus[0x1d]|keystatus[0x9d]) > 0)) //Ctrl-shift Enter (auto-shade)
+ {
+ dashade[0] = 127;
+ dashade[1] = -128;
+ i = searchwall;
+ do
+ {
+ if ((long)wall[i].shade < dashade[0]) dashade[0] = wall[i].shade;
+ if ((long)wall[i].shade > dashade[1]) dashade[1] = wall[i].shade;
+
+ i = wall[i].point2;
+ }
+ while (i != searchwall);
+
+ daang = getangle(wall[wall[searchwall].point2].x-wall[searchwall].x,wall[wall[searchwall].point2].y-wall[searchwall].y);
+ i = searchwall;
+ do
+ {
+ j = getangle(wall[wall[i].point2].x-wall[i].x,wall[wall[i].point2].y-wall[i].y);
+ k = ((j+2048-daang)&2047);
+ if (k > 1024)
+ k = 2048-k;
+ wall[i].shade = dashade[0]+mulscale10(k,dashade[1]-dashade[0]);
+
+ i = wall[i].point2;
+ }
+ while (i != searchwall);
+ }
+ else if (somethingintab < 255)
+ {
+ if (searchstat == 0) wall[searchwall].shade = tempshade, wall[searchwall].pal = temppal;
+ if (searchstat == 1)
+ {
+ sector[searchsector].ceilingshade = tempshade, sector[searchsector].ceilingpal = temppal;
+ if ((somethingintab == 1) || (somethingintab == 2))
+ sector[searchsector].visibility = tempvis;
+ }
+ if (searchstat == 2)
+ {
+ sector[searchsector].floorshade = tempshade, sector[searchsector].floorpal = temppal;
+ if ((somethingintab == 1) || (somethingintab == 2))
+ sector[searchsector].visibility = tempvis;
+ }
+ if (searchstat == 3) sprite[searchwall].shade = tempshade, sprite[searchwall].pal = temppal;
+ if (searchstat == 4) wall[searchwall].shade = tempshade, wall[searchwall].pal = temppal;
+ }
+ }
+ else if (((searchstat == 0) || (searchstat == 4)) && ((keystatus[0x1d]|keystatus[0x9d]) > 0) && (somethingintab < 255)) //Either ctrl key
+ {
+ i = searchwall;
+ do
+ {
+ wall[i].picnum = temppicnum;
+ wall[i].shade = tempshade;
+ wall[i].pal = temppal;
+ if ((somethingintab == 0) || (somethingintab == 4))
+ {
+ wall[i].xrepeat = tempxrepeat;
+ wall[i].yrepeat = tempyrepeat;
+ wall[i].cstat = tempcstat;
+ }
+ fixrepeats((short)i);
+ i = wall[i].point2;
+ }
+ while (i != searchwall);
+ }
+ else if (((searchstat == 1) || (searchstat == 2)) && ((keystatus[0x1d]|keystatus[0x9d]) > 0) && (somethingintab < 255)) //Either ctrl key
+ {
+ clearbuf((long)(&pskysearch[0]),(long)((numsectors+3)>>2),0L);
+ if (searchstat == 1)
+ {
+ i = searchsector;
+ if ((sector[i].ceilingstat&1) > 0)
+ pskysearch[i] = 1;
+
+ while (pskysearch[i] == 1)
+ {
+ sector[i].ceilingpicnum = temppicnum;
+ sector[i].ceilingshade = tempshade;
+ sector[i].ceilingpal = temppal;
+ if ((somethingintab == 1) || (somethingintab == 2))
+ {
+ sector[i].ceilingxpanning = tempxrepeat;
+ sector[i].ceilingypanning = tempyrepeat;
+ sector[i].ceilingstat = tempcstat;
+ }
+ pskysearch[i] = 2;
+
+ startwall = sector[i].wallptr;
+ endwall = startwall + sector[i].wallnum - 1;
+ for(j=startwall;j<=endwall;j++)
+ {
+ k = wall[j].nextsector;
+ if (k >= 0)
+ if ((sector[k].ceilingstat&1) > 0)
+ if (pskysearch[k] == 0)
+ pskysearch[k] = 1;
+ }
+
+ for(j=0;j<numsectors;j++)
+ if (pskysearch[j] == 1)
+ i = j;
+ }
+ }
+ if (searchstat == 2)
+ {
+ i = searchsector;
+ if ((sector[i].floorstat&1) > 0)
+ pskysearch[i] = 1;
+
+ while (pskysearch[i] == 1)
+ {
+ sector[i].floorpicnum = temppicnum;
+ sector[i].floorshade = tempshade;
+ sector[i].floorpal = temppal;
+ if ((somethingintab == 1) || (somethingintab == 2))
+ {
+ sector[i].floorxpanning = tempxrepeat;
+ sector[i].floorypanning = tempyrepeat;
+ sector[i].floorstat = tempcstat;
+ }
+ pskysearch[i] = 2;
+
+ startwall = sector[i].wallptr;
+ endwall = startwall + sector[i].wallnum - 1;
+ for(j=startwall;j<=endwall;j++)
+ {
+ k = wall[j].nextsector;
+ if (k >= 0)
+ if ((sector[k].floorstat&1) > 0)
+ if (pskysearch[k] == 0)
+ pskysearch[k] = 1;
+ }
+
+ for(j=0;j<numsectors;j++)
+ if (pskysearch[j] == 1)
+ i = j;
+ }
+ }
+ }
+ else if (somethingintab < 255)
+ {
+ if (searchstat == 0)
+ {
+ wall[searchwall].picnum = temppicnum;
+ wall[searchwall].shade = tempshade;
+ wall[searchwall].pal = temppal;
+ if (somethingintab == 0)
+ {
+ wall[searchwall].xrepeat = tempxrepeat;
+ wall[searchwall].yrepeat = tempyrepeat;
+ wall[searchwall].cstat = tempcstat;
+ wall[searchwall].lotag = templotag;
+ wall[searchwall].hitag = temphitag;
+ wall[searchwall].extra = tempextra;
+ }
+ fixrepeats(searchwall);
+ }
+ if (searchstat == 1)
+ {
+ sector[searchsector].ceilingpicnum = temppicnum;
+ sector[searchsector].ceilingshade = tempshade;
+ sector[searchsector].ceilingpal = temppal;
+ if ((somethingintab == 1) || (somethingintab == 2))
+ {
+ sector[searchsector].ceilingxpanning = tempxrepeat;
+ sector[searchsector].ceilingypanning = tempyrepeat;
+ sector[searchsector].ceilingstat = tempcstat;
+ sector[searchsector].visibility = tempvis;
+ sector[searchsector].lotag = templotag;
+ sector[searchsector].hitag = temphitag;
+ sector[searchsector].extra = tempextra;
+ }
+ }
+ if (searchstat == 2)
+ {
+ sector[searchsector].floorpicnum = temppicnum;
+ sector[searchsector].floorshade = tempshade;
+ sector[searchsector].floorpal = temppal;
+ if ((somethingintab == 1) || (somethingintab == 2))
+ {
+ sector[searchsector].floorxpanning= tempxrepeat;
+ sector[searchsector].floorypanning= tempyrepeat;
+ sector[searchsector].floorstat = tempcstat;
+ sector[searchsector].visibility = tempvis;
+ sector[searchsector].lotag = templotag;
+ sector[searchsector].hitag = temphitag;
+ sector[searchsector].extra = tempextra;
+ }
+ }
+ if (searchstat == 3)
+ {
+ sprite[searchwall].picnum = temppicnum;
+ if ((tilesizx[temppicnum] <= 0) || (tilesizy[temppicnum] <= 0))
+ {
+ j = 0;
+ for(k=0;k<MAXTILES;k++)
+ if ((tilesizx[k] > 0) && (tilesizy[k] > 0))
+ {
+ j = k;
+ break;
+ }
+ sprite[searchwall].picnum = j;
+ }
+ sprite[searchwall].shade = tempshade;
+ sprite[searchwall].pal = temppal;
+ if (somethingintab == 3)
+ {
+ sprite[searchwall].xrepeat = tempxrepeat;
+ sprite[searchwall].yrepeat = tempyrepeat;
+ if (sprite[searchwall].xrepeat < 1) sprite[searchwall].xrepeat = 1;
+ if (sprite[searchwall].yrepeat < 1) sprite[searchwall].yrepeat = 1;
+ sprite[searchwall].cstat = tempcstat;
+ sprite[searchwall].lotag = templotag;
+ sprite[searchwall].hitag = temphitag;
+ sprite[searchwall].extra = tempextra;
+ }
+ }
+ if (searchstat == 4)
+ {
+ wall[searchwall].overpicnum = temppicnum;
+ if (wall[searchwall].nextwall >= 0)
+ wall[wall[searchwall].nextwall].overpicnum = temppicnum;
+ wall[searchwall].shade = tempshade;
+ wall[searchwall].pal = temppal;
+ if (somethingintab == 4)
+ {
+ wall[searchwall].xrepeat = tempxrepeat;
+ wall[searchwall].yrepeat = tempyrepeat;
+ wall[searchwall].cstat = tempcstat;
+ wall[searchwall].lotag = templotag;
+ wall[searchwall].hitag = temphitag;
+ wall[searchwall].extra = tempextra;
+ }
+ fixrepeats(searchwall);
+ }
+ }
+ asksave = 1;
+ keystatus[0x1c] = 0;
+ }
+ if (keystatus[0x2e] > 0) //C
+ {
+ keystatus[0x2e] = 0;
+ if (keystatus[0x38] > 0) //Alt-C
+ {
+ if (somethingintab < 255)
+ {
+ switch(searchstat)
+ {
+ case 0:
+ j = wall[searchwall].picnum;
+ for(i=0;i<numwalls;i++)
+ if (wall[i].picnum == j) wall[i].picnum = temppicnum;
+ break;
+ case 1:
+ j = sector[searchsector].ceilingpicnum;
+ for(i=0;i<numsectors;i++)
+ if (sector[i].ceilingpicnum == j) sector[i].ceilingpicnum = temppicnum;
+ break;
+ case 2:
+ j = sector[searchsector].floorpicnum;
+ for(i=0;i<numsectors;i++)
+ if (sector[i].floorpicnum == j) sector[i].floorpicnum = temppicnum;
+ break;
+ case 3:
+ j = sprite[searchwall].picnum;
+ for(i=0;i<MAXSPRITES;i++)
+ if (sprite[i].statnum < MAXSTATUS)
+ if (sprite[i].picnum == j) sprite[i].picnum = temppicnum;
+ break;
+ case 4:
+ j = wall[searchwall].overpicnum;
+ for(i=0;i<numwalls;i++)
+ if (wall[i].overpicnum == j) wall[i].overpicnum = temppicnum;
+ break;
+ }
+ }
+ }
+ else //C
+ {
+ if (searchstat == 3)
+ {
+ sprite[searchwall].cstat ^= 128;
+ asksave = 1;
+ }
+ }
+ }
+ if (keystatus[0x2f] > 0) //V
+ {
+ if (searchstat == 0) templong = wall[searchwall].picnum;
+ if (searchstat == 1) templong = sector[searchsector].ceilingpicnum;
+ if (searchstat == 2) templong = sector[searchsector].floorpicnum;
+ if (searchstat == 3) templong = sprite[searchwall].picnum;
+ if (searchstat == 4) templong = wall[searchwall].overpicnum;
+ templong = gettile(templong);
+ if (searchstat == 0) wall[searchwall].picnum = templong;
+ if (searchstat == 1) sector[searchsector].ceilingpicnum = templong;
+ if (searchstat == 2) sector[searchsector].floorpicnum = templong;
+ if (searchstat == 3) sprite[searchwall].picnum = templong;
+ if (searchstat == 4)
+ {
+ wall[searchwall].overpicnum = templong;
+ if (wall[searchwall].nextwall >= 0)
+ wall[wall[searchwall].nextwall].overpicnum = templong;
+ }
+ asksave = 1;
+ keystatus[0x2f] = 0;
+ }
+
+ if (keystatus[0x1a]) // [
+ {
+ keystatus[0x1a] = 0;
+ if (keystatus[0x38]|keystatus[0xb8])
+ {
+ i = wall[searchwall].nextsector;
+ if (i >= 0)
+ switch(searchstat)
+ {
+ case 0: case 1: case 4:
+ alignceilslope(searchsector,wall[searchwall].x,wall[searchwall].y,getceilzofslope(i,wall[searchwall].x,wall[searchwall].y));
+ break;
+ case 2:
+ alignflorslope(searchsector,wall[searchwall].x,wall[searchwall].y,getflorzofslope(i,wall[searchwall].x,wall[searchwall].y));
+ break;
+ }
+ }
+ else
+ {
+ i = 512;
+ if (keystatus[0x36]) i = 8;
+ if (keystatus[0x2a]) i = 1;
+
+ if (searchstat == 1)
+ {
+ if (!(sector[searchsector].ceilingstat&2))
+ sector[searchsector].ceilingheinum = 0;
+ sector[searchsector].ceilingheinum = max(sector[searchsector].ceilingheinum-i,-32768);
+ }
+ if (searchstat == 2)
+ {
+ if (!(sector[searchsector].floorstat&2))
+ sector[searchsector].floorheinum = 0;
+ sector[searchsector].floorheinum = max(sector[searchsector].floorheinum-i,-32768);
+ }
+ }
+
+ if (sector[searchsector].ceilingheinum == 0)
+ sector[searchsector].ceilingstat &= ~2;
+ else
+ sector[searchsector].ceilingstat |= 2;
+
+ if (sector[searchsector].floorheinum == 0)
+ sector[searchsector].floorstat &= ~2;
+ else
+ sector[searchsector].floorstat |= 2;
+ asksave = 1;
+ }
+ if (keystatus[0x1b]) // ]
+ {
+ keystatus[0x1b] = 0;
+ if (keystatus[0x38]|keystatus[0xb8])
+ {
+ i = wall[searchwall].nextsector;
+ if (i >= 0)
+ switch(searchstat)
+ {
+ case 1:
+ alignceilslope(searchsector,wall[searchwall].x,wall[searchwall].y,getceilzofslope(i,wall[searchwall].x,wall[searchwall].y));
+ break;
+ case 0: case 2: case 4:
+ alignflorslope(searchsector,wall[searchwall].x,wall[searchwall].y,getflorzofslope(i,wall[searchwall].x,wall[searchwall].y));
+ break;
+ }
+ }
+ else
+ {
+ i = 512;
+ if (keystatus[0x36]) i = 8;
+ if (keystatus[0x2a]) i = 1;
+
+ if (searchstat == 1)
+ {
+ if (!(sector[searchsector].ceilingstat&2))
+ sector[searchsector].ceilingheinum = 0;
+ sector[searchsector].ceilingheinum = min(sector[searchsector].ceilingheinum+i,32767);
+ }
+ if (searchstat == 2)
+ {
+ if (!(sector[searchsector].floorstat&2))
+ sector[searchsector].floorheinum = 0;
+ sector[searchsector].floorheinum = min(sector[searchsector].floorheinum+i,32767);
+ }
+ }
+
+ if (sector[searchsector].ceilingheinum == 0)
+ sector[searchsector].ceilingstat &= ~2;
+ else
+ sector[searchsector].ceilingstat |= 2;
+
+ if (sector[searchsector].floorheinum == 0)
+ sector[searchsector].floorstat &= ~2;
+ else
+ sector[searchsector].floorstat |= 2;
+
+ asksave = 1;
+ }
+
+ smooshyalign = keystatus[0x4c];
+ repeatpanalign = (keystatus[0x2a]|keystatus[0x36]);
+ if ((keystatus[0x4b]|keystatus[0x4d]) > 0) // 4 & 6 (keypad)
+ {
+ repeatcountx++;
+
+ if ((repeatcountx == 1) || (repeatcountx > 16))
+ {
+ changedir = 0;
+ if (keystatus[0x4b] > 0) changedir = -1;
+ if (keystatus[0x4d] > 0) changedir = 1;
+
+ if ((searchstat == 0) || (searchstat == 4))
+ {
+ if (repeatpanalign == 0)
+ wall[searchwall].xrepeat = changechar(wall[searchwall].xrepeat,changedir,smooshyalign,1);
+ else
+ wall[searchwall].xpanning = changechar(wall[searchwall].xpanning,changedir,smooshyalign,0);
+ }
+ if ((searchstat == 1) || (searchstat == 2))
+ {
+ if (searchstat == 1)
+ sector[searchsector].ceilingxpanning = changechar(sector[searchsector].ceilingxpanning,changedir,smooshyalign,0);
+ else
+ sector[searchsector].floorxpanning = changechar(sector[searchsector].floorxpanning,changedir,smooshyalign,0);
+ }
+ if (searchstat == 3)
+ {
+ sprite[searchwall].xrepeat = changechar(sprite[searchwall].xrepeat,changedir,smooshyalign,1);
+ if (sprite[searchwall].xrepeat < 4)
+ sprite[searchwall].xrepeat = 4;
+ }
+ asksave = 1;
+ }
+ }
+ else
+ repeatcountx = 0;
+
+ if ((keystatus[0x48]|keystatus[0x50]) > 0) // 2 & 8 (keypad)
+ {
+ repeatcounty++;
+
+ if ((repeatcounty == 1) || (repeatcounty > 16))
+ {
+ changedir = 0;
+ if (keystatus[0x48] > 0) changedir = -1;
+ if (keystatus[0x50] > 0) changedir = 1;
+
+ if ((searchstat == 0) || (searchstat == 4))
+ {
+ if (repeatpanalign == 0)
+ wall[searchwall].yrepeat = changechar(wall[searchwall].yrepeat,changedir,smooshyalign,1);
+ else
+ wall[searchwall].ypanning = changechar(wall[searchwall].ypanning,changedir,smooshyalign,0);
+ }
+ if ((searchstat == 1) || (searchstat == 2))
+ {
+ if (searchstat == 1)
+ sector[searchsector].ceilingypanning = changechar(sector[searchsector].ceilingypanning,changedir,smooshyalign,0);
+ else
+ sector[searchsector].floorypanning = changechar(sector[searchsector].floorypanning,changedir,smooshyalign,0);
+ }
+ if (searchstat == 3)
+ {
+ sprite[searchwall].yrepeat = changechar(sprite[searchwall].yrepeat,changedir,smooshyalign,1);
+ if (sprite[searchwall].yrepeat < 4)
+ sprite[searchwall].yrepeat = 4;
+ }
+ asksave = 1;
+ }
+ }
+ else
+ repeatcounty = 0;
+
+ if (keystatus[0x33] > 0) // , Search & fix panning to the left (3D)
+ {
+ if (searchstat == 3)
+ {
+ i = searchwall;
+ if ((keystatus[0x2a]|keystatus[0x36]) > 0)
+ sprite[i].ang = ((sprite[i].ang+2048-1)&2047);
+ else
+ {
+ sprite[i].ang = ((sprite[i].ang+2048-128)&2047);
+ keystatus[0x33] = 0;
+ }
+ }
+ }
+ if (keystatus[0x34] > 0) // . Search & fix panning to the right (3D)
+ {
+ if ((searchstat == 0) || (searchstat == 4))
+ {
+ AutoAlignWalls((long)searchwall,0L);
+
+ /*wallfind[0] = searchwall;
+ cnt = 4096;
+ do
+ {
+ wallfind[1] = wall[wallfind[0]].point2;
+ j = -1;
+ if (wall[wallfind[1]].picnum == wall[searchwall].picnum)
+ j = wallfind[1];
+ k = wallfind[1];
+
+ while ((wall[wallfind[1]].nextwall >= 0) && (wall[wall[wallfind[1]].nextwall].point2 != k))
+ {
+ i = wall[wall[wallfind[1]].nextwall].point2; //break if going around in circles on red lines with same picture on both sides
+ if (wallfind[1] == wall[wall[i].nextwall].point2)
+ break;
+
+ wallfind[1] = wall[wall[wallfind[1]].nextwall].point2;
+ if (wall[wallfind[1]].picnum == wall[searchwall].picnum)
+ j = wallfind[1];
+ }
+ wallfind[1] = j;
+
+ if ((j >= 0) && (wallfind[1] != searchwall))
+ {
+ j = (wall[wallfind[0]].xpanning+(wall[wallfind[0]].xrepeat<<3)) % tilesizx[wall[wallfind[0]].picnum];
+ wall[wallfind[1]].cstat &= ~8; //Set to non-flip
+ wall[wallfind[1]].cstat |= 4; //Set y-orientation
+ wall[wallfind[1]].xpanning = j;
+
+ for(k=0;k<2;k++)
+ {
+ sectnum = sectorofwall((short)wallfind[k]);
+ nextsectnum = wall[wallfind[k]].nextsector;
+
+ if (nextsectnum == -1)
+ {
+ if ((wall[wallfind[k]].cstat&4) == 0)
+ daz[k] = sector[sectnum].ceilingz;
+ else
+ daz[k] = sector[sectnum].floorz;
+ }
+ else //topstep
+ {
+ if (sector[nextsectnum].ceilingz > sector[sectnum].ceilingz)
+ daz[k] = sector[nextsectnum].ceilingz;
+ else if (sector[nextsectnum].floorz < sector[sectnum].floorz)
+ daz[k] = sector[nextsectnum].floorz;
+ }
+ }
+
+ j = (picsiz[wall[searchwall].picnum]>>4);
+ if ((1<<j) != tilesizy[wall[searchwall].picnum]) j++;
+
+ j = ((wall[wallfind[0]].ypanning+(((daz[1]-daz[0])*wall[wallfind[0]].yrepeat)>>(j+3)))&255);
+ wall[wallfind[1]].ypanning = j;
+ wall[wallfind[1]].yrepeat = wall[wallfind[0]].yrepeat;
+ if (nextsectnum >= 0)
+ if (sector[nextsectnum].ceilingz >= sector[sectnum].ceilingz)
+ if (sector[nextsectnum].floorz <= sector[sectnum].floorz)
+ {
+ if (wall[wall[wallfind[1]].nextwall].picnum == wall[searchwall].picnum)
+ {
+ wall[wall[wallfind[1]].nextwall].yrepeat = wall[wallfind[0]].yrepeat;
+ if ((wall[wall[wallfind[1]].nextwall].cstat&4) == 0)
+ daz[1] = sector[nextsectnum].floorz;
+ else
+ daz[1] = sector[sectnum].ceilingz;
+ wall[wall[wallfind[1]].nextwall].ypanning = j;
+ }
+ }
+ }
+ wallfind[0] = wallfind[1];
+ cnt--;
+ }
+ while ((wall[wallfind[0]].picnum == wall[searchwall].picnum) && (wallfind[0] != searchwall) && (cnt > 0));
+ */
+
+ keystatus[0x34] = 0;
+ }
+ if (searchstat == 3)
+ {
+ i = searchwall;
+ if ((keystatus[0x2a]|keystatus[0x36]) > 0)
+ sprite[i].ang = ((sprite[i].ang+2048+1)&2047);
+ else
+ {
+ sprite[i].ang = ((sprite[i].ang+2048+128)&2047);
+ keystatus[0x34] = 0;
+ }
+ }
+ }
+ if (keystatus[0x35] > 0) // /? Reset panning&repeat to 0
+ {
+ if ((searchstat == 0) || (searchstat == 4))
+ {
+ wall[searchwall].xpanning = 0;
+ wall[searchwall].ypanning = 0;
+ wall[searchwall].xrepeat = 8;
+ wall[searchwall].yrepeat = 8;
+ wall[searchwall].cstat = 0;
+ fixrepeats((short)searchwall);
+ }
+ if (searchstat == 1)
+ {
+ sector[searchsector].ceilingxpanning = 0;
+ sector[searchsector].ceilingypanning = 0;
+ sector[searchsector].ceilingstat &= ~2;
+ sector[searchsector].ceilingheinum = 0;
+ }
+ if (searchstat == 2)
+ {
+ sector[searchsector].floorxpanning = 0;
+ sector[searchsector].floorypanning = 0;
+ sector[searchsector].floorstat &= ~2;
+ sector[searchsector].floorheinum = 0;
+ }
+ if (searchstat == 3)
+ {
+ if ((keystatus[0x2a]|keystatus[0x36]) > 0)
+ {
+ sprite[searchwall].xrepeat = sprite[searchwall].yrepeat;
+ }
+ else
+ {
+ sprite[searchwall].xrepeat = 64;
+ sprite[searchwall].yrepeat = 64;
+ }
+ }
+ keystatus[0x35] = 0;
+ asksave = 1;
+ }
+
+ if (keystatus[0x19] > 0) // P (parallaxing sky)
+ {
+ if ((keystatus[0x1d]|keystatus[0x9d]) > 0)
+ {
+ parallaxtype++;
+ if (parallaxtype == 3)
+ parallaxtype = 0;
+ }
+ else if ((keystatus[0x38]|keystatus[0xb8]) > 0)
+ {
+ switch (searchstat)
+ {
+ case 0: case 4:
+ strcpy(buffer,"Wall pal: ");
+ wall[searchwall].pal = getnumber256(buffer,wall[searchwall].pal,256L);
+ break;
+ case 1:
+ strcpy(buffer,"Ceiling pal: ");
+ sector[searchsector].ceilingpal = getnumber256(buffer,sector[searchsector].ceilingpal,256L);
+ break;
+ case 2:
+ strcpy(buffer,"Floor pal: ");
+ sector[searchsector].floorpal = getnumber256(buffer,sector[searchsector].floorpal,256L);
+ break;
+ case 3:
+ strcpy(buffer,"Sprite pal: ");
+ sprite[searchwall].pal = getnumber256(buffer,sprite[searchwall].pal,256L);
+ break;
+ }
+ }
+ else
+ {
+ if ((searchstat == 0) || (searchstat == 1) || (searchstat == 4))
+ {
+ sector[searchsector].ceilingstat ^= 1;
+ asksave = 1;
+ }
+ else if (searchstat == 2)
+ {
+ sector[searchsector].floorstat ^= 1;
+ asksave = 1;
+ }
+ }
+ keystatus[0x19] = 0;
+ }
+
+ if (keystatus[0x20] != 0) //Alt-D (adjust sprite[].clipdist)
+ {
+ keystatus[0x20] = 0;
+ if ((keystatus[0x38]|keystatus[0xb8]) > 0)
+ {
+ if (searchstat == 3)
+ {
+ strcpy(buffer,"Sprite clipdist: ");
+ sprite[searchwall].clipdist = getnumber256(buffer,sprite[searchwall].clipdist,256L);
+ }
+ }
+ }
+
+ if (keystatus[0x30] > 0) // B (clip Blocking xor) (3D)
+ {
+ if (searchstat == 3)
+ {
+ sprite[searchwall].cstat ^= 1;
+ sprite[searchwall].cstat &= ~256;
+ sprite[searchwall].cstat |= ((sprite[searchwall].cstat&1)<<8);
+ asksave = 1;
+ }
+ else
+ {
+ wall[searchwall].cstat ^= 1;
+ wall[searchwall].cstat &= ~64;
+ if ((wall[searchwall].nextwall >= 0) && ((keystatus[0x2a]|keystatus[0x36]) == 0))
+ {
+ wall[wall[searchwall].nextwall].cstat &= ~(1+64);
+ wall[wall[searchwall].nextwall].cstat |= (wall[searchwall].cstat&1);
+ }
+ asksave = 1;
+ }
+ keystatus[0x30] = 0;
+ }
+ if (keystatus[0x14] > 0) // T (transluscence for sprites/masked walls)
+ {
+ /*if (searchstat == 1) //Set masked/transluscent ceilings/floors
+ {
+ i = (sector[searchsector].ceilingstat&(128+256));
+ sector[searchsector].ceilingstat &= ~(128+256);
+ switch(i)
+ {
+ case 0: sector[searchsector].ceilingstat |= 128; break;
+ case 128: sector[searchsector].ceilingstat |= 256; break;
+ case 256: sector[searchsector].ceilingstat |= 384; break;
+ case 384: sector[searchsector].ceilingstat |= 0; break;
+ }
+ asksave = 1;
+ }
+ if (searchstat == 2)
+ {
+ i = (sector[searchsector].floorstat&(128+256));
+ sector[searchsector].floorstat &= ~(128+256);
+ switch(i)
+ {
+ case 0: sector[searchsector].floorstat |= 128; break;
+ case 128: sector[searchsector].floorstat |= 256; break;
+ case 256: sector[searchsector].floorstat |= 384; break;
+ case 384: sector[searchsector].floorstat |= 0; break;
+ }
+ asksave = 1;
+ }*/
+ if (searchstat == 3)
+ {
+ if ((sprite[searchwall].cstat&2) == 0)
+ sprite[searchwall].cstat |= 2;
+ else if ((sprite[searchwall].cstat&512) == 0)
+ sprite[searchwall].cstat |= 512;
+ else
+ sprite[searchwall].cstat &= ~(2+512);
+ asksave = 1;
+ }
+ if (searchstat == 4)
+ {
+ if ((wall[searchwall].cstat&128) == 0)
+ wall[searchwall].cstat |= 128;
+ else if ((wall[searchwall].cstat&512) == 0)
+ wall[searchwall].cstat |= 512;
+ else
+ wall[searchwall].cstat &= ~(128+512);
+
+ if (wall[searchwall].nextwall >= 0)
+ {
+ wall[wall[searchwall].nextwall].cstat &= ~(128+512);
+ wall[wall[searchwall].nextwall].cstat |= (wall[searchwall].cstat&(128+512));
+ }
+ asksave = 1;
+ }
+ keystatus[0x14] = 0;
+ }
+
+ if (keystatus[0x2] > 0) // 1 (make 1-way wall)
+ {
+ if (searchstat != 3)
+ {
+ wall[searchwall].cstat ^= 32;
+ asksave = 1;
+ }
+ else
+ {
+ sprite[searchwall].cstat ^= 64;
+ i = sprite[searchwall].cstat;
+ if ((i&48) == 32)
+ {
+ sprite[searchwall].cstat &= ~8;
+ if ((i&64) > 0)
+ if (posz > sprite[searchwall].z)
+ sprite[searchwall].cstat |= 8;
+ }
+ asksave = 1;
+ }
+ keystatus[0x2] = 0;
+ }
+ if (keystatus[0x3] > 0) // 2 (bottom wall swapping)
+ {
+ if (searchstat != 3)
+ {
+ wall[searchwall].cstat ^= 2;
+ asksave = 1;
+ }
+ keystatus[0x3] = 0;
+ }
+ if (keystatus[0x18] > 0) // O (top/bottom orientation - for doors)
+ {
+ if ((searchstat == 0) || (searchstat == 4))
+ {
+ wall[searchwall].cstat ^= 4;
+ asksave = 1;
+ }
+ if (searchstat == 3) // O (ornament onto wall) (2D)
+ {
+ asksave = 1;
+ i = searchwall;
+
+ hitscan(sprite[i].x,sprite[i].y,sprite[i].z,sprite[i].sectnum,
+ sintable[(sprite[i].ang+2560+1024)&2047],
+ sintable[(sprite[i].ang+2048+1024)&2047],
+ 0,
+ &hitsect,&hitwall,&hitsprite,&hitx,&hity,&hitz,CLIPMASK1);
+
+ sprite[i].x = hitx;
+ sprite[i].y = hity;
+ sprite[i].z = hitz;
+ changespritesect(i,hitsect);
+ if (hitwall >= 0)
+ sprite[i].ang = ((getangle(wall[wall[hitwall].point2].x-wall[hitwall].x,wall[wall[hitwall].point2].y-wall[hitwall].y)+512)&2047);
+
+ //Make sure sprite's in right sector
+ if (inside(sprite[i].x,sprite[i].y,sprite[i].sectnum) == 0)
+ {
+ j = wall[hitwall].point2;
+ sprite[i].x -= ksgn(wall[j].y-wall[hitwall].y);
+ sprite[i].y += ksgn(wall[j].x-wall[hitwall].x);
+ }
+ }
+ keystatus[0x18] = 0;
+ }
+ if (keystatus[0x32] > 0) // M (masking walls)
+ {
+ if (searchstat != 3)
+ {
+ i = wall[searchwall].nextwall;
+ templong = (keystatus[0x2a]|keystatus[0x36]);
+ if (i >= 0)
+ {
+ wall[searchwall].cstat ^= 16;
+ if ((wall[searchwall].cstat&16) > 0)
+ {
+ wall[searchwall].cstat &= ~8;
+ if (templong == 0)
+ {
+ wall[i].cstat |= 8; //auto other-side flip
+ wall[i].cstat |= 16;
+ wall[i].overpicnum = wall[searchwall].overpicnum;
+ }
+ }
+ else
+ {
+ wall[searchwall].cstat &= ~8;
+ if (templong == 0)
+ {
+ wall[i].cstat &= ~8; //auto other-side unflip
+ wall[i].cstat &= ~16;
+ }
+ }
+ wall[searchwall].cstat &= ~32;
+ if (templong == 0) wall[i].cstat &= ~32;
+ asksave = 1;
+ }
+ }
+ keystatus[0x32] = 0;
+ }
+ if (keystatus[0x23] > 0) // H (hitscan sensitivity)
+ {
+ if (searchstat == 3)
+ {
+ sprite[searchwall].cstat ^= 256;
+ asksave = 1;
+ }
+ else
+ {
+ wall[searchwall].cstat ^= 64;
+ if ((wall[searchwall].nextwall >= 0) && ((keystatus[0x2a]|keystatus[0x36]) == 0))
+ {
+ wall[wall[searchwall].nextwall].cstat &= ~64;
+ wall[wall[searchwall].nextwall].cstat |= (wall[searchwall].cstat&64);
+ }
+ asksave = 1;
+ }
+ keystatus[0x23] = 0;
+ }
+ if (keystatus[0x12] > 0) // E (expand)
+ {
+ if (searchstat == 1)
+ {
+ sector[searchsector].ceilingstat ^= 8;
+ asksave = 1;
+ }
+ if (searchstat == 2)
+ {
+ sector[searchsector].floorstat ^= 8;
+ asksave = 1;
+ }
+ keystatus[0x12] = 0;
+ }
+ if (keystatus[0x13] > 0) // R (relative alignment, rotation)
+ {
+ if (searchstat == 1)
+ {
+ sector[searchsector].ceilingstat ^= 64;
+ asksave = 1;
+ }
+ if (searchstat == 2)
+ {
+ sector[searchsector].floorstat ^= 64;
+ asksave = 1;
+ }
+ if (searchstat == 3)
+ {
+ i = sprite[searchwall].cstat;
+ if ((i&48) < 32) i += 16; else i &= ~48;
+ sprite[searchwall].cstat = i;
+ asksave = 1;
+ }
+ keystatus[0x13] = 0;
+ }
+ if (keystatus[0x21] > 0) //F (Flip)
+ {
+ keystatus[0x21] = 0;
+ if ((keystatus[0x38]|keystatus[0xb8]) > 0) //ALT-F (relative alignmment flip)
+ {
+ if (searchstat != 3)
+ {
+ setfirstwall(searchsector,searchwall);
+ asksave = 1;
+ }
+ }
+ else
+ {
+ if ((searchstat == 0) || (searchstat == 4))
+ {
+ i = wall[searchwall].cstat;
+ i = ((i>>3)&1)+((i>>7)&2); //3-x,8-y
+ switch(i)
+ {
+ case 0: i = 1; break;
+ case 1: i = 3; break;
+ case 2: i = 0; break;
+ case 3: i = 2; break;
+ }
+ i = ((i&1)<<3)+((i&2)<<7);
+ wall[searchwall].cstat &= ~0x0108;
+ wall[searchwall].cstat |= i;
+ asksave = 1;
+ }
+ if (searchstat == 1) //8-way ceiling flipping (bits 2,4,5)
+ {
+ i = sector[searchsector].ceilingstat;
+ i = (i&0x4)+((i>>4)&3);
+ switch(i)
+ {
+ case 0: i = 6; break;
+ case 6: i = 3; break;
+ case 3: i = 5; break;
+ case 5: i = 1; break;
+ case 1: i = 7; break;
+ case 7: i = 2; break;
+ case 2: i = 4; break;
+ case 4: i = 0; break;
+ }
+ i = (i&0x4)+((i&3)<<4);
+ sector[searchsector].ceilingstat &= ~0x34;
+ sector[searchsector].ceilingstat |= i;
+ asksave = 1;
+ }
+ if (searchstat == 2) //8-way floor flipping (bits 2,4,5)
+ {
+ i = sector[searchsector].floorstat;
+ i = (i&0x4)+((i>>4)&3);
+ switch(i)
+ {
+ case 0: i = 6; break;
+ case 6: i = 3; break;
+ case 3: i = 5; break;
+ case 5: i = 1; break;
+ case 1: i = 7; break;
+ case 7: i = 2; break;
+ case 2: i = 4; break;
+ case 4: i = 0; break;
+ }
+ i = (i&0x4)+((i&3)<<4);
+ sector[searchsector].floorstat &= ~0x34;
+ sector[searchsector].floorstat |= i;
+ asksave = 1;
+ }
+ if (searchstat == 3)
+ {
+ i = sprite[searchwall].cstat;
+ if (((i&48) == 32) && ((i&64) == 0))
+ {
+ sprite[searchwall].cstat &= ~0xc;
+ sprite[searchwall].cstat |= (i&4^4);
+ }
+ else
+ {
+ i = ((i>>2)&3);
+ switch(i)
+ {
+ case 0: i = 1; break;
+ case 1: i = 3; break;
+ case 2: i = 0; break;
+ case 3: i = 2; break;
+ }
+ i <<= 2;
+ sprite[searchwall].cstat &= ~0xc;
+ sprite[searchwall].cstat |= i;
+ }
+ asksave = 1;
+ }
+ }
+ }
+ if (keystatus[0x1f] > 0) //S (insert sprite) (3D)
+ {
+ dax = 16384;
+ day = divscale14(searchx-(xdim>>1),xdim>>1);
+ rotatepoint(0,0,dax,day,ang,&dax,&day);
+
+ hitscan(posx,posy,posz,cursectnum, //Start position
+ dax,day,(scale(searchy,200,ydim)-horiz)*2000, //vector of 3D ang
+ &hitsect,&hitwall,&hitsprite,&hitx,&hity,&hitz,CLIPMASK1);
+
+ if (hitsect >= 0)
+ {
+ dax = hitx;
+ day = hity;
+ if ((gridlock > 0) && (grid > 0))
+ {
+ if ((searchstat == 0) || (searchstat == 4))
+ {
+ hitz = (hitz&0xfffffc00);
+ }
+ else
+ {
+ dax = ((dax+(1024>>grid))&(0xffffffff<<(11-grid)));
+ day = ((day+(1024>>grid))&(0xffffffff<<(11-grid)));
+ }
+ }
+
+ i = insertsprite(hitsect,0);
+ sprite[i].x = dax, sprite[i].y = day;
+ sprite[i].cstat = defaultspritecstat;
+ sprite[i].shade = 0;
+ sprite[i].pal = 0;
+ sprite[i].xrepeat = 64, sprite[i].yrepeat = 64;
+ sprite[i].xoffset = 0, sprite[i].yoffset = 0;
+ sprite[i].ang = 1536;
+ sprite[i].xvel = 0; sprite[i].yvel = 0; sprite[i].zvel = 0;
+ sprite[i].owner = -1;
+ sprite[i].clipdist = 32;
+ sprite[i].lotag = 0;
+ sprite[i].hitag = 0;
+ sprite[i].extra = -1;
+
+ for(k=0;k<MAXTILES;k++)
+ localartfreq[k] = 0;
+ for(k=0;k<MAXSPRITES;k++)
+ if (sprite[k].statnum < MAXSTATUS)
+ localartfreq[sprite[k].picnum]++;
+ j = 0;
+ for(k=0;k<MAXTILES;k++)
+ if (localartfreq[k] > localartfreq[j])
+ j = k;
+ if (localartfreq[j] > 0)
+ sprite[i].picnum = j;
+ else
+ sprite[i].picnum = 0;
+
+ if (somethingintab == 3)
+ {
+ sprite[i].picnum = temppicnum;
+ if ((tilesizx[temppicnum] <= 0) || (tilesizy[temppicnum] <= 0))
+ {
+ j = 0;
+ for(k=0;k<MAXTILES;k++)
+ if ((tilesizx[k] > 0) && (tilesizy[k] > 0))
+ {
+ j = k;
+ break;
+ }
+ sprite[i].picnum = j;
+ }
+ sprite[i].shade = tempshade;
+ sprite[i].pal = temppal;
+ sprite[i].xrepeat = tempxrepeat;
+ sprite[i].yrepeat = tempyrepeat;
+ if (sprite[i].xrepeat < 1) sprite[i].xrepeat = 1;
+ if (sprite[i].yrepeat < 1) sprite[i].yrepeat = 1;
+ sprite[i].cstat = tempcstat;
+ }
+
+ j = ((tilesizy[sprite[i].picnum]*sprite[i].yrepeat)<<1);
+ if ((sprite[i].cstat&128) == 0)
+ sprite[i].z = min(max(hitz,getceilzofslope(hitsect,hitx,hity)+(j<<1)),getflorzofslope(hitsect,hitx,hity));
+ else
+ sprite[i].z = min(max(hitz,getceilzofslope(hitsect,hitx,hity)+j),getflorzofslope(hitsect,hitx,hity)-j);
+
+ if ((searchstat == 0) || (searchstat == 4))
+ {
+ sprite[i].cstat |= (16+64);
+ if (hitwall >= 0)
+ sprite[i].ang = ((getangle(wall[wall[hitwall].point2].x-wall[hitwall].x,wall[wall[hitwall].point2].y-wall[hitwall].y)+512)&2047);
+
+ //Make sure sprite's in right sector
+ if (inside(sprite[i].x,sprite[i].y,sprite[i].sectnum) == 0)
+ {
+ j = wall[hitwall].point2;
+ sprite[i].x -= ksgn(wall[j].y-wall[hitwall].y);
+ sprite[i].y += ksgn(wall[j].x-wall[hitwall].x);
+ }
+ }
+ else
+ {
+ if (tilesizy[sprite[i].picnum] >= 32) sprite[i].cstat |= 1;
+ }
+
+ updatenumsprites();
+ asksave = 1;
+ }
+
+ keystatus[0x1f] = 0;
+ }
+ if (keystatus[0xd3] > 0)
+ {
+ if (searchstat == 3)
+ {
+ deletesprite(searchwall);
+ updatenumsprites();
+ asksave = 1;
+ }
+ keystatus[0xd3] = 0;
+ }
+
+ if ((keystatus[0x3f]|keystatus[0x40]) > 0) //F5,F6
+ {
+ switch(searchstat)
+ {
+ case 1: case 2: ExtShowSectorData(searchsector); break;
+ case 0: case 4: ExtShowWallData(searchwall); break;
+ case 3: ExtShowSpriteData(searchwall); break;
+ }
+ keystatus[0x3f] = 0, keystatus[0x40] = 0;
+ }
+ if ((keystatus[0x41]|keystatus[0x42]) > 0) //F7,F8
+ {
+ switch(searchstat)
+ {
+ case 1: case 2: ExtEditSectorData(searchsector); break;
+ case 0: case 4: ExtEditWallData(searchwall); break;
+ case 3: ExtEditSpriteData(searchwall); break;
+ }
+ keystatus[0x41] = 0, keystatus[0x42] = 0;
+ }
+
+ }
+ if (keystatus[buildkeys[14]] > 0) // Enter
+ {
+ overheadeditor();
+ keystatus[buildkeys[14]] = 0;
+ }
+}
+
+changechar(char dachar, long dadir, char smooshyalign, char boundcheck)
+{
+ if (dadir < 0)
+ {
+ if ((dachar > 0) || (boundcheck == 0))
+ {
+ dachar--;
+ if (smooshyalign > 0)
+ dachar = (dachar&0xf8);
+ }
+ }
+ else if (dadir > 0)
+ {
+ if ((dachar < 255) || (boundcheck == 0))
+ {
+ dachar++;
+ if (smooshyalign > 0)
+ {
+ if (dachar >= 256-8) dachar = 255;
+ else dachar = ((dachar+7)&0xf8);
+ }
+ }
+ }
+ return(dachar);
+}
+
+gettile(long tilenum)
+{
+ char snotbuf[80];
+ long i, j, k, otilenum, topleft, gap, temp, templong;
+ long xtiles, ytiles, tottiles;
+
+ xtiles = (xdim>>6); ytiles = (ydim>>6); tottiles = xtiles*ytiles;
+ otilenum = tilenum;
+
+ keystatus[0x2f] = 0;
+ for(i=0;i<MAXTILES;i++)
+ {
+ localartfreq[i] = 0;
+ localartlookup[i] = i;
+ }
+ if ((searchstat == 1) || (searchstat == 2))
+ for(i=0;i<numsectors;i++)
+ {
+ localartfreq[sector[i].ceilingpicnum]++;
+ localartfreq[sector[i].floorpicnum]++;
+ }
+ if (searchstat == 0)
+ for(i=0;i<numwalls;i++)
+ localartfreq[wall[i].picnum]++;
+ if (searchstat == 4)
+ for(i=0;i<numwalls;i++)
+ localartfreq[wall[i].overpicnum]++;
+ if (searchstat == 3)
+ for(i=0;i<MAXSPRITES;i++)
+ if (sprite[i].statnum < MAXSTATUS)
+ localartfreq[sprite[i].picnum]++;
+ gap = (MAXTILES>>1);
+ do
+ {
+ for(i=0;i<MAXTILES-gap;i++)
+ {
+ temp = i;
+ while ((localartfreq[temp] < localartfreq[temp+gap]) && (temp >= 0))
+ {
+ templong = localartfreq[temp];
+ localartfreq[temp] = localartfreq[temp+gap];
+ localartfreq[temp+gap] = templong;
+ templong = localartlookup[temp];
+ localartlookup[temp] = localartlookup[temp+gap];
+ localartlookup[temp+gap] = templong;
+
+ if (tilenum == temp)
+ tilenum = temp+gap;
+ else if (tilenum == temp+gap)
+ tilenum = temp;
+
+ temp -= gap;
+ }
+ }
+ gap >>= 1;
+ }
+ while (gap > 0);
+ localartlookupnum = 0;
+ while (localartfreq[localartlookupnum] > 0)
+ localartlookupnum++;
+
+ if (localartfreq[0] == 0)
+ {
+ tilenum = otilenum;
+ localartlookupnum = MAXTILES;
+ for(i=0;i<MAXTILES;i++)
+ localartlookup[i] = i;
+ }
+
+ topleft = ((tilenum/(xtiles<<gettilezoom))*(xtiles<<gettilezoom))-(xtiles<<gettilezoom);
+ if (topleft < 0) topleft = 0;
+ if (topleft > MAXTILES-(tottiles<<(gettilezoom<<1))) topleft = MAXTILES-(tottiles<<(gettilezoom<<1));
+ while ((keystatus[0x1c]|keystatus[1]) == 0)
+ {
+ drawtilescreen(topleft,tilenum);
+ if ((vidoption != 2) && ((vidoption != 1) || (vgacompatible == 1))) limitrate();
+
+ nextpage();
+ synctics = totalclock-lockclock;
+ lockclock += synctics;
+
+ if ((keystatus[0x37] > 0) && (gettilezoom < 2))
+ {
+ gettilezoom++;
+ topleft = ((tilenum/(xtiles<<gettilezoom))*(xtiles<<gettilezoom))-(xtiles<<gettilezoom);
+ if (topleft < 0) topleft = 0;
+ if (topleft > MAXTILES-(tottiles<<(gettilezoom<<1))) topleft = MAXTILES-(tottiles<<(gettilezoom<<1));
+ keystatus[0x37] = 0;
+ }
+ if ((keystatus[0xb5] > 0) && (gettilezoom > 0))
+ {
+ gettilezoom--;
+ topleft = ((tilenum/(xtiles<<gettilezoom))*(xtiles<<gettilezoom))-(xtiles<<gettilezoom);
+ if (topleft < 0) topleft = 0;
+ if (topleft > MAXTILES-(tottiles<<(gettilezoom<<1))) topleft = MAXTILES-(tottiles<<(gettilezoom<<1));
+ keystatus[0xb5] = 0;
+ }
+ if ((keystatus[0xcb] > 0) && (tilenum > 0))
+ tilenum--, keystatus[0xcb] = 0;
+ if ((keystatus[0xcd] > 0) && (tilenum < MAXTILES-1))
+ tilenum++, keystatus[0xcd] = 0;
+ if ((keystatus[0xc8] > 0) && (tilenum >= (xtiles<<gettilezoom)))
+ tilenum-=(xtiles<<gettilezoom), keystatus[0xc8] = 0;
+ if ((keystatus[0xd0] > 0) && (tilenum < MAXTILES-(xtiles<<gettilezoom)))
+ tilenum+=(xtiles<<gettilezoom), keystatus[0xd0] = 0;
+ if ((keystatus[0xc9] > 0) && (tilenum >= (xtiles<<gettilezoom)))
+ {
+ tilenum-=(tottiles<<(gettilezoom<<1));
+ if (tilenum < 0) tilenum = 0;
+ keystatus[0xc9] = 0;
+ }
+ if ((keystatus[0xd1] > 0) && (tilenum < MAXTILES-(xtiles<<gettilezoom)))
+ {
+ tilenum+=(tottiles<<(gettilezoom<<1));
+ if (tilenum >= MAXTILES) tilenum = MAXTILES-1;
+ keystatus[0xd1] = 0;
+ }
+ if (keystatus[0x2f] > 0) //V
+ {
+ keystatus[0x2f] = 0;
+ if (tilenum < localartlookupnum)
+ tilenum = localartlookup[tilenum];
+ else
+ tilenum = 0;
+ localartlookupnum = MAXTILES;
+ for(i=0;i<MAXTILES;i++)
+ localartlookup[i] = i;
+ }
+ if (keystatus[0x22] > 0) //G (goto)
+ {
+ if (tilenum < localartlookupnum) //Automatically press 'V'
+ tilenum = localartlookup[tilenum];
+ else
+ tilenum = 0;
+ localartlookupnum = MAXTILES;
+ for(i=0;i<MAXTILES;i++)
+ localartlookup[i] = i;
+
+ keystatus[0x22] = 0;
+
+ j = tilenum;
+ while (keystatus[1] == 0)
+ {
+ drawtilescreen(topleft,tilenum);
+ if ((vidoption != 2) && ((vidoption != 1) || (vgacompatible == 1))) limitrate();
+ sprintf(&snotbuf,"Goto tile: %d_ ",j);
+ printext256(0,0,whitecol,0,snotbuf,0);
+ nextpage();
+
+ for(k=0;k<10;k++)
+ if (keystatus[((k+9)%10)+2] > 0)
+ {
+ keystatus[((k+9)%10)+2] = 0;
+ i = (j*10)+k;
+ if (i < MAXTILES) j = i;
+ }
+ if (keystatus[0xe] > 0)
+ {
+ keystatus[0xe] = 0;
+ j /= 10;
+ }
+ if (keystatus[0x1c] > 0)
+ {
+ keystatus[0x1c] = 0;
+ tilenum = j;
+ break;
+ }
+ }
+ }
+ while (tilenum < topleft) topleft -= (xtiles<<gettilezoom);
+ while (tilenum >= topleft+(tottiles<<(gettilezoom<<1))) topleft += (xtiles<<gettilezoom);
+ if (topleft < 0) topleft = 0;
+ if (topleft > MAXTILES-(tottiles<<(gettilezoom<<1))) topleft = MAXTILES-(tottiles<<(gettilezoom<<1));
+ }
+
+ if (keystatus[0x1c] == 0)
+ {
+ tilenum = otilenum;
+ }
+ else
+ {
+ if (tilenum < localartlookupnum)
+ {
+ tilenum = localartlookup[tilenum];
+ if ((tilesizx[tilenum] == 0) || (tilesizy[tilenum] == 0))
+ tilenum = otilenum;
+ }
+ else
+ tilenum = otilenum;
+ }
+ keystatus[0x1] = 0;
+ keystatus[0x1c] = 0;
+ return(tilenum);
+}
+
+drawtilescreen(long pictopleft, long picbox)
+{
+ long i, j, vidpos, vidpos2, dat, wallnum, xdime, ydime, cnt, pinc;
+ long dax, day, scaledown, xtiles, ytiles, tottiles;
+ char *picptr, snotbuf[80];
+
+ xtiles = (xdim>>6); ytiles = (ydim>>6); tottiles = xtiles*ytiles;
+
+ pinc = ylookup[1];
+ clearview(0L);
+ for(cnt=0;cnt<(tottiles<<(gettilezoom<<1));cnt++) //draw the 5*3 grid of tiles
+ {
+ wallnum = cnt+pictopleft;
+ if (wallnum < localartlookupnum)
+ {
+ wallnum = localartlookup[wallnum];
+ if ((tilesizx[wallnum] != 0) && (tilesizy[wallnum] != 0))
+ {
+ if (waloff[wallnum] == 0) loadtile(wallnum);
+ picptr = (char *)(waloff[wallnum]);
+ xdime = tilesizx[wallnum];
+ ydime = tilesizy[wallnum];
+
+ dax = ((cnt%(xtiles<<gettilezoom))<<(6-gettilezoom));
+ day = ((cnt/(xtiles<<gettilezoom))<<(6-gettilezoom));
+ vidpos = ylookup[day]+dax+frameplace;
+ if ((xdime <= (64>>gettilezoom)) && (ydime <= (64>>gettilezoom)))
+ {
+ for(i=0;i<xdime;i++)
+ {
+ vidpos2 = vidpos+i;
+ for(j=0;j<ydime;j++)
+ {
+ *(char *)vidpos2 = *picptr++;
+ vidpos2 += pinc;
+ }
+ }
+ }
+ else //if 1 dimension > 64
+ {
+ if (xdime > ydime)
+ scaledown = ((xdime+(63>>gettilezoom))>>(6-gettilezoom));
+ else
+ scaledown = ((ydime+(63>>gettilezoom))>>(6-gettilezoom));
+
+ for(i=0;i<xdime;i+=scaledown)
+ {
+ if (waloff[wallnum] == 0) loadtile(wallnum);
+ picptr = (char *)(waloff[wallnum]) + ydime*i;
+ vidpos2 = vidpos;
+ for(j=0;j<ydime;j+=scaledown)
+ {
+ *(char *)vidpos2 = *picptr;
+ picptr += scaledown;
+ vidpos2 += pinc;
+ }
+ vidpos++;
+ }
+ }
+ if (localartlookupnum < MAXTILES)
+ {
+ dax = ((cnt%(xtiles<<gettilezoom))<<(6-gettilezoom));
+ day = ((cnt/(xtiles<<gettilezoom))<<(6-gettilezoom));
+ sprintf(snotbuf,"%ld",localartfreq[cnt+pictopleft]);
+ printext256(dax,day,whitecol,-1,snotbuf,1);
+ }
+ }
+ }
+ }
+
+ cnt = picbox-pictopleft; //draw open white box
+ dax = ((cnt%(xtiles<<gettilezoom))<<(6-gettilezoom));
+ day = ((cnt/(xtiles<<gettilezoom))<<(6-gettilezoom));
+
+ for(i=0;i<(64>>gettilezoom);i++)
+ {
+ plotpixel(dax+i,day,whitecol);
+ plotpixel(dax+i,day+(63>>gettilezoom),whitecol);
+ plotpixel(dax,day+i,whitecol);
+ plotpixel(dax+(63>>gettilezoom),day+i,whitecol);
+ }
+
+ i = localartlookup[picbox];
+ sprintf(snotbuf,"%ld",i);
+ printext256(0L,ydim-8,whitecol,-1,snotbuf,0);
+ printext256(xdim-(strlen(names[i])<<3),ydim-8,whitecol,-1,names[i],0);
+
+ return(0);
+}
+
+overheadeditor()
+{
+ char buffer[80], *dabuffer;
+ long i, j, k, m, mousxplc, mousyplc, firstx, firsty, oposz, col;
+ long templong, templong1, templong2, opageoffset, doubvel;
+ long startwall, endwall, dax, day, daz, x1, y1, x2, y2, x3, y3, x4, y4;
+ long highlightx1, highlighty1, highlightx2, highlighty2, xvect, yvect;
+ short pag, suckwall, sucksect, newnumwalls, newnumsectors, split, bad;
+ short splitsect, danumwalls, secondstartwall, joinsector[2], joinsectnum;
+ short splitstartwall, splitendwall, loopnum;
+ short mousx, mousy, bstatus;
+ long centerx, centery, circlerad;
+ short circlewall, circlepoints, circleang1, circleang2, circleangdir;
+ long sectorhighlightx, sectorhighlighty;
+ short cursectorhighlight, sectorhighlightstat;
+ short hitsect, hitwall, hitsprite;
+ long hitx, hity, hitz;
+ walltype *wal;
+
+ searchx = scale(searchx,640,xdim);
+ searchy = scale(searchy,480,ydim);
+ oposz = posz;
+
+ qsetmode640480();
+
+ pageoffset = 0; ydim16 = 144;
+ drawline16(0,0,639,0,7);
+ drawline16(0,143,639,143,7);
+ drawline16(0,0,0,143,7);
+ drawline16(639,0,639,143,7);
+ drawline16(0,24,639,24,7);
+ drawline16(192,0,192,24,7);
+ printext16(9L,9L,4,-1,kensig,0);
+ printext16(8L,8L,12,-1,kensig,0);
+ printmessage16("Version: 9/23/95");
+ drawline16(0,143-24,639,143-24,7);
+ drawline16(256,143-24,256,143,7);
+ pageoffset = 92160; ydim16 = 336;
+
+ outpw(0x3d4,0x000c);
+ outpw(0x3d4,0x000d);
+ pag = 0;
+ highlightcnt = -1;
+ cursectorhighlight = -1;
+
+ //White out all bordering lines of grab that are
+ //not highlighted on both sides
+ for(i=highlightsectorcnt-1;i>=0;i--)
+ {
+ startwall = sector[highlightsector[i]].wallptr;
+ endwall = startwall + sector[highlightsector[i]].wallnum;
+ for(j=startwall;j<endwall;j++)
+ {
+ if (wall[j].nextwall >= 0)
+ {
+ for(k=highlightsectorcnt-1;k>=0;k--)
+ if (highlightsector[k] == wall[j].nextsector)
+ break;
+ if (k < 0)
+ {
+ wall[wall[j].nextwall].nextwall = -1;
+ wall[wall[j].nextwall].nextsector = -1;
+ wall[j].nextwall = -1;
+ wall[j].nextsector = -1;
+ }
+ }
+ }
+ }
+
+ for(i=0;i<(MAXWALLS>>3);i++) //Clear all highlights
+ show2dwall[i] = 0;
+ for(i=0;i<(MAXSPRITES>>3);i++)
+ show2dsprite[i] = 0;
+
+ sectorhighlightstat = -1;
+ newnumwalls = -1;
+ joinsector[0] = -1;
+ circlewall = -1;
+ circlepoints = 7;
+ oldmousebstatus = 0;
+ keystatus[buildkeys[14]] = 0;
+ while ((keystatus[buildkeys[14]]>>1) == 0)
+ {
+ oldmousebstatus = bstatus;
+ getmousevalues(&mousx,&mousy,&bstatus);
+ searchx += (mousx>>1);
+ searchy += (mousy>>1);
+ if (searchx < 8) searchx = 8;
+ if (searchx > 631) searchx = 631;
+ if (searchy < 8) searchy = 8;
+ if (searchy > 341) searchy = 341;
+
+ if (keystatus[0x3b] > 0) posx--, keystatus[0x3b] = 0;
+ if (keystatus[0x3c] > 0) posx++, keystatus[0x3c] = 0;
+ if (keystatus[0x3d] > 0) posy--, keystatus[0x3d] = 0;
+ if (keystatus[0x3e] > 0) posy++, keystatus[0x3e] = 0;
+ if (keystatus[0x43] > 0) ang--, keystatus[0x43] = 0;
+ if (keystatus[0x44] > 0) ang++, keystatus[0x44] = 0;
+ if (angvel != 0) //ang += angvel * constant
+ { //ENGINE calculates angvel for you
+ doubvel = synctics;
+ if (keystatus[buildkeys[4]] > 0) //Lt. shift makes turn velocity 50% faster
+ doubvel += (synctics>>1);
+ ang += ((angvel*doubvel)>>4);
+ ang = (ang+2048)&2047;
+ }
+ if ((vel|svel) != 0)
+ {
+ doubvel = synctics;
+ if (keystatus[buildkeys[4]] > 0) //Lt. shift doubles forward velocity
+ doubvel += synctics;
+ xvect = 0, yvect = 0;
+ if (vel != 0)
+ {
+ xvect += ((vel*doubvel*(long)sintable[(ang+2560)&2047])>>3);
+ yvect += ((vel*doubvel*(long)sintable[(ang+2048)&2047])>>3);
+ }
+ if (svel != 0)
+ {
+ xvect += ((svel*doubvel*(long)sintable[(ang+2048)&2047])>>3);
+ yvect += ((svel*doubvel*(long)sintable[(ang+1536)&2047])>>3);
+ }
+ clipmove(&posx,&posy,&posz,&cursectnum,xvect,yvect,128L,4L<<8,4L<<8,CLIPMASK0);
+ }
+
+ getpoint(searchx,searchy,&mousxplc,&mousyplc);
+ linehighlight = getlinehighlight(mousxplc, mousyplc);
+
+ if (newnumwalls >= numwalls)
+ {
+ dax = mousxplc;
+ day = mousyplc;
+ adjustmark(&dax,&day,newnumwalls);
+ wall[newnumwalls].x = dax;
+ wall[newnumwalls].y = day;
+ }
+
+ ydim16 = 336;
+
+ templong = numwalls;
+ numwalls = newnumwalls;
+ if (numwalls < 0) numwalls = templong;
+
+ clear2dscreen();
+ draw2dgrid(posx,posy,ang,zoom,grid);
+
+ x2 = mulscale14(startposx-posx,zoom); //Draw brown arrow (start)
+ y2 = mulscale14(startposy-posy,zoom);
+ if (((320+x2) >= 2) && ((320+x2) <= 637))
+ if (((200+y2) >= 2) && ((200+y2) <= ydim16-3))
+ {
+ x1 = mulscale11(sintable[(startang+2560)&2047],zoom) / 768;
+ y1 = mulscale11(sintable[(startang+2048)&2047],zoom) / 768;
+ drawline16((320+x2)+x1,(200+y2)+y1,(320+x2)-x1,(200+y2)-y1,6);
+ drawline16((320+x2)+x1,(200+y2)+y1,(320+x2)+y1,(200+y2)-x1,6);
+ drawline16((320+x2)+x1,(200+y2)+y1,(320+x2)-y1,(200+y2)+x1,6);
+ }
+
+ draw2dscreen(posx,posy,ang,zoom,grid);
+
+ if ((showtags == 1) && (zoom >= 768))
+ {
+ for(i=0;i<numsectors;i++)
+ {
+ dabuffer = (char *)ExtGetSectorCaption(i);
+ if (dabuffer[0] != 0)
+ {
+ dax = 0; //Get average point of sector
+ day = 0;
+ startwall = sector[i].wallptr;
+ endwall = startwall + sector[i].wallnum - 1;
+ for(j=startwall;j<=endwall;j++)
+ {
+ dax += wall[j].x;
+ day += wall[j].y;
+ }
+ if (endwall > startwall)
+ {
+ dax /= (endwall-startwall+1);
+ day /= (endwall-startwall+1);
+ }
+
+ dax = mulscale14(dax-posx,zoom);
+ day = mulscale14(day-posy,zoom);
+
+ x1 = 320+dax-(strlen(dabuffer)<<1);
+ y1 = 200+day-4;
+ x2 = x1 + (strlen(dabuffer)<<2)+2;
+ y2 = y1 + 7;
+ if ((x1 >= 0) && (x2 < 640) && (y1 >= 0) && (y2 < ydim16))
+ printext16(x1,y1+(pageoffset/640),0,7,dabuffer,1);
+ }
+ }
+
+ x3 = divscale14(-320,zoom)+posx;
+ y3 = divscale14(-196,zoom)+posy;
+ x4 = divscale14(320,zoom)+posx;
+ y4 = divscale14(ydim16-196,zoom)+posy;
+
+ for(i=numwalls-1,wal=&wall[i];i>=0;i--,wal--)
+ {
+ //Get average point of wall
+ dax = ((wal->x+wall[wal->point2].x)>>1);
+ day = ((wal->y+wall[wal->point2].y)>>1);
+ if ((dax > x3) && (dax < x4) && (day > y3) && (day < y4))
+ {
+ dabuffer = (char *)ExtGetWallCaption(i);
+ if (dabuffer[0] != 0)
+ {
+ dax = mulscale14(dax-posx,zoom);
+ day = mulscale14(day-posy,zoom);
+ x1 = 320+dax-(strlen(dabuffer)<<1);
+ y1 = 200+day-4;
+ x2 = x1 + (strlen(dabuffer)<<2)+2;
+ y2 = y1 + 7;
+ if ((x1 >= 0) && (x2 < 640) && (y1 >= 0) && (y2 < ydim16))
+ printext16(x1,y1+(pageoffset/640),0,4,dabuffer,1);
+ }
+ }
+ }
+
+ i = 0; j = numsprites;
+ while ((j > 0) && (i < MAXSPRITES))
+ {
+ if (sprite[i].statnum < MAXSTATUS)
+ {
+ dabuffer = (char *)ExtGetSpriteCaption(i);
+ if (dabuffer[0] != 0)
+ {
+ //Get average point of sprite
+ dax = sprite[i].x;
+ day = sprite[i].y;
+
+ dax = mulscale14(dax-posx,zoom);
+ day = mulscale14(day-posy,zoom);
+
+ x1 = 320+dax-(strlen(dabuffer)<<1);
+ y1 = 200+day-4;
+ x2 = x1 + (strlen(dabuffer)<<2)+2;
+ y2 = y1 + 7;
+ if ((x1 >= 0) && (x2 < 640) && (y1 >= 0) && (y2 < ydim16))
+ {
+ if ((sprite[i].cstat&1) == 0) col = 3; else col = 5;
+ printext16(x1,y1+(pageoffset/640),0,col,dabuffer,1);
+ }
+ }
+ j--;
+ }
+ i++;
+ }
+ }
+
+ printcoords16(posx,posy,ang);
+
+ numwalls = templong;
+
+ if (highlightsectorcnt > 0)
+ for(i=0;i<highlightsectorcnt;i++)
+ fillsector(highlightsector[i],2);
+
+ col = 15-((gridlock<<1)+gridlock);
+ drawline16(searchx,searchy-8,searchx,searchy-1,col);
+ drawline16(searchx+1,searchy-8,searchx+1,searchy-1,col);
+ drawline16(searchx,searchy+2,searchx,searchy+9,col);
+ drawline16(searchx+1,searchy+2,searchx+1,searchy+9,col);
+ drawline16(searchx-8,searchy,searchx-1,searchy,col);
+ drawline16(searchx-8,searchy+1,searchx-1,searchy+1,col);
+ drawline16(searchx+2,searchy,searchx+9,searchy,col);
+ drawline16(searchx+2,searchy+1,searchx+9,searchy+1,col);
+
+ //Draw the white pixel closest to mouse cursor on linehighlight
+ getclosestpointonwall(mousxplc,mousyplc,(long)linehighlight,&dax,&day);
+ x2 = mulscale14(dax-posx,zoom);
+ y2 = mulscale14(day-posy,zoom);
+ if (wall[linehighlight].nextsector >= 0)
+ drawline16(320+x2,200+y2,320+x2,200+y2,15);
+ else
+ drawline16(320+x2,200+y2,320+x2,200+y2,5);
+
+ if (keystatus[88] > 0) //F12
+ {
+ keystatus[88] = 0;
+ i = pageoffset; pageoffset = 92160;
+ j = ydim16; ydim16 = 480;
+ outpw(0x3d4,0x000c);
+ outpw(0x3d4,0x000d);
+ clear2dscreen();
+ draw2dgrid(posx,posy,ang,zoom,grid);
+ draw2dscreen(posx,posy,ang,zoom,grid);
+
+ screencapture("captxxxx.pcx",keystatus[0x2a]|keystatus[0x36]);
+
+ pageoffset = i;
+ ydim16 = j;
+ }
+ if (keystatus[0x30] > 0) // B (clip Blocking xor) (2D)
+ {
+ pointhighlight = getpointhighlight(mousxplc, mousyplc);
+ linehighlight = getlinehighlight(mousxplc, mousyplc);
+
+ if ((pointhighlight&0xc000) == 16384)
+ {
+ sprite[pointhighlight&16383].cstat ^= 1;
+ sprite[pointhighlight&16383].cstat &= ~256;
+ sprite[pointhighlight&16383].cstat |= ((sprite[pointhighlight&16383].cstat&1)<<8);
+ asksave = 1;
+ }
+ else if (linehighlight >= 0)
+ {
+ wall[linehighlight].cstat ^= 1;
+ wall[linehighlight].cstat &= ~64;
+ if ((wall[linehighlight].nextwall >= 0) && ((keystatus[0x2a]|keystatus[0x36]) == 0))
+ {
+ wall[wall[linehighlight].nextwall].cstat &= ~(1+64);
+ wall[wall[linehighlight].nextwall].cstat |= (wall[linehighlight].cstat&1);
+ }
+ asksave = 1;
+ }
+ keystatus[0x30] = 0;
+ }
+ if (keystatus[0x21] > 0) //F (F alone does nothing in 2D right now)
+ {
+ keystatus[0x21] = 0;
+ if ((keystatus[0x38]|keystatus[0xb8]) > 0) //ALT-F (relative alignmment flip)
+ {
+ linehighlight = getlinehighlight(mousxplc, mousyplc);
+ if (linehighlight >= 0)
+ {
+ setfirstwall(sectorofwall(linehighlight),linehighlight);
+ asksave = 1;
+ printmessage16("This wall now sector's first wall (sector[].wallptr)");
+ }
+ }
+ }
+
+ if (keystatus[0x18] > 0) // O (ornament onto wall) (2D)
+ {
+ keystatus[0x18] = 0;
+ if ((pointhighlight&0xc000) == 16384)
+ {
+ asksave = 1;
+ i = (pointhighlight&16383);
+
+ hitscan(sprite[i].x,sprite[i].y,sprite[i].z,sprite[i].sectnum,
+ sintable[(sprite[i].ang+2560+1024)&2047],
+ sintable[(sprite[i].ang+2048+1024)&2047],
+ 0,
+ &hitsect,&hitwall,&hitsprite,&hitx,&hity,&hitz,CLIPMASK1);
+
+ sprite[i].x = hitx;
+ sprite[i].y = hity;
+ sprite[i].z = hitz;
+ changespritesect(i,hitsect);
+ if (hitwall >= 0)
+ sprite[i].ang = ((getangle(wall[wall[hitwall].point2].x-wall[hitwall].x,wall[wall[hitwall].point2].y-wall[hitwall].y)+512)&2047);
+
+ //Make sure sprite's in right sector
+ if (inside(sprite[i].x,sprite[i].y,sprite[i].sectnum) == 0)
+ {
+ j = wall[hitwall].point2;
+ sprite[i].x -= ksgn(wall[j].y-wall[hitwall].y);
+ sprite[i].y += ksgn(wall[j].x-wall[hitwall].x);
+ }
+ }
+ }
+
+ if (keystatus[0x33] > 0) // , (2D)
+ {
+ if (highlightsectorcnt > 0)
+ {
+ k = 0;
+ dax = 0;
+ day = 0;
+ for(i=0;i<highlightsectorcnt;i++)
+ {
+ startwall = sector[highlightsector[i]].wallptr;
+ endwall = startwall+sector[highlightsector[i]].wallnum-1;
+ for(j=startwall;j<=endwall;j++)
+ {
+ dax += wall[j].x;
+ day += wall[j].y;
+ k++;
+ }
+ }
+ if (k > 0)
+ {
+ dax /= k;
+ day /= k;
+ }
+
+ k = (keystatus[0x2a]|keystatus[0x36]);
+
+ if (k == 0)
+ {
+ if ((gridlock > 0) && (grid > 0))
+ {
+ dax = ((dax+(1024>>grid))&(0xffffffff<<(11-grid)));
+ day = ((day+(1024>>grid))&(0xffffffff<<(11-grid)));
+ }
+ }
+
+ for(i=0;i<highlightsectorcnt;i++)
+ {
+ startwall = sector[highlightsector[i]].wallptr;
+ endwall = startwall+sector[highlightsector[i]].wallnum-1;
+ for(j=startwall;j<=endwall;j++)
+ {
+ if (k == 0)
+ {
+ x3 = wall[j].x;
+ y3 = wall[j].y;
+ wall[j].x = dax+day-y3;
+ wall[j].y = day+x3-dax;
+ }
+ else
+ {
+ rotatepoint(dax,day,wall[j].x,wall[j].y,1,&wall[j].x,&wall[j].y);
+ }
+ }
+
+ j = headspritesect[highlightsector[i]];
+ while (j != -1)
+ {
+ if (k == 0)
+ {
+ x3 = sprite[j].x;
+ y3 = sprite[j].y;
+ sprite[j].x = dax+day-y3;
+ sprite[j].y = day+x3-dax;
+ sprite[j].ang = ((sprite[j].ang+512)&2047);
+ }
+ else
+ {
+ rotatepoint(dax,day,sprite[j].x,sprite[j].y,1,&sprite[j].x,&sprite[j].y);
+ sprite[j].ang = ((sprite[j].ang+1)&2047);
+ }
+
+ j = nextspritesect[j];
+ }
+ }
+ if (k == 0) keystatus[0x33] = 0;
+ asksave = 1;
+ }
+ else
+ {
+ if (pointhighlight >= 16384)
+ {
+ i = pointhighlight-16384;
+ if ((keystatus[0x2a]|keystatus[0x36]) > 0)
+ sprite[i].ang = ((sprite[i].ang+2048-1)&2047);
+ else
+ {
+ sprite[i].ang = ((sprite[i].ang+2048-128)&2047);
+ keystatus[0x33] = 0;
+ }
+
+ clearmidstatbar16();
+ showspritedata((short)pointhighlight-16384);
+ }
+ }
+ }
+ if (keystatus[0x34] > 0) // . (2D)
+ {
+ if (highlightsectorcnt > 0)
+ {
+ k = 0;
+ dax = 0;
+ day = 0;
+ for(i=0;i<highlightsectorcnt;i++)
+ {
+ startwall = sector[highlightsector[i]].wallptr;
+ endwall = startwall+sector[highlightsector[i]].wallnum-1;
+ for(j=startwall;j<=endwall;j++)
+ {
+ dax += wall[j].x;
+ day += wall[j].y;
+ k++;
+ }
+ }
+ if (k > 0)
+ {
+ dax /= k;
+ day /= k;
+ }
+
+ k = (keystatus[0x2a]|keystatus[0x36]);
+
+ if (k == 0)
+ {
+ if ((gridlock > 0) && (grid > 0))
+ {
+ dax = ((dax+(1024>>grid))&(0xffffffff<<(11-grid)));
+ day = ((day+(1024>>grid))&(0xffffffff<<(11-grid)));
+ }
+ }
+
+ for(i=0;i<highlightsectorcnt;i++)
+ {
+ startwall = sector[highlightsector[i]].wallptr;
+ endwall = startwall+sector[highlightsector[i]].wallnum-1;
+ for(j=startwall;j<=endwall;j++)
+ {
+ if (k == 0)
+ {
+ x3 = wall[j].x;
+ y3 = wall[j].y;
+ wall[j].x = dax+y3-day;
+ wall[j].y = day+dax-x3;
+ }
+ else
+ {
+ rotatepoint(dax,day,wall[j].x,wall[j].y,2047,&wall[j].x,&wall[j].y);
+ }
+ }
+
+ j = headspritesect[highlightsector[i]];
+ while (j != -1)
+ {
+ if (k == 0)
+ {
+ x3 = sprite[j].x;
+ y3 = sprite[j].y;
+ sprite[j].x = dax+y3-day;
+ sprite[j].y = day+dax-x3;
+ sprite[j].ang = ((sprite[j].ang+1536)&2047);
+ }
+ else
+ {
+ rotatepoint(dax,day,sprite[j].x,sprite[j].y,2047,&sprite[j].x,&sprite[j].y);
+ sprite[j].ang = ((sprite[j].ang+2047)&2047);
+ }
+
+ j = nextspritesect[j];
+ }
+ }
+ if (k == 0) keystatus[0x34] = 0;
+ asksave = 1;
+ }
+ else
+ {
+ if (pointhighlight >= 16384)
+ {
+ i = pointhighlight-16384;
+ if ((keystatus[0x2a]|keystatus[0x36]) > 0)
+ sprite[i].ang = ((sprite[i].ang+2048+1)&2047);
+ else
+ {
+ sprite[i].ang = ((sprite[i].ang+2048+128)&2047);
+ keystatus[0x34] = 0;
+ }
+
+ clearmidstatbar16();
+ showspritedata((short)pointhighlight-16384);
+ }
+ }
+ }
+ if (keystatus[0x46] > 0) //Scroll lock (set starting position)
+ {
+ startposx = posx;
+ startposy = posy;
+ startposz = posz;
+ startang = ang;
+ startsectnum = cursectnum;
+ keystatus[0x46] = 0;
+ asksave = 1;
+ }
+
+ if (keystatus[0x3f] > 0) //F5
+ {
+ keystatus[0x3f] = 0;
+
+ for (i=0;i<numsectors;i++)
+ if (inside(mousxplc,mousyplc,i) == 1)
+ {
+ opageoffset = pageoffset; pageoffset = 0; ydim16 = 144;
+ ExtShowSectorData((short)i);
+ pageoffset = opageoffset; ydim16 = 336;
+ break;
+ }
+ }
+ if (keystatus[0x40] > 0) //F6
+ {
+ keystatus[0x40] = 0;
+
+ if (pointhighlight >= 16384)
+ {
+ i = pointhighlight-16384;
+
+ opageoffset = pageoffset; pageoffset = 0; ydim16 = 144;
+ ExtShowSpriteData((short)i);
+ pageoffset = opageoffset; ydim16 = 336;
+ }
+ else if (linehighlight >= 0)
+ {
+ i = linehighlight;
+
+ opageoffset = pageoffset; pageoffset = 0; ydim16 = 144;
+ ExtShowWallData((short)i);
+ pageoffset = opageoffset; ydim16 = 336;
+ }
+ }
+ if (keystatus[0x41] > 0) //F7
+ {
+ keystatus[0x41] = 0;
+
+ for (i=0;i<numsectors;i++)
+ if (inside(mousxplc,mousyplc,i) == 1)
+ {
+ opageoffset = pageoffset; pageoffset = 0; ydim16 = 144;
+ ExtEditSectorData((short)i);
+ pageoffset = opageoffset; ydim16 = 336;
+ break;
+ }
+ }
+ if (keystatus[0x42] > 0) //F8
+ {
+ keystatus[0x42] = 0;
+
+ if (pointhighlight >= 16384)
+ {
+ i = pointhighlight-16384;
+
+ opageoffset = pageoffset; pageoffset = 0; ydim16 = 144;
+ ExtEditSpriteData((short)i);
+ pageoffset = opageoffset; ydim16 = 336;
+ }
+ else if (linehighlight >= 0)
+ {
+ i = linehighlight;
+
+ opageoffset = pageoffset; pageoffset = 0; ydim16 = 144;
+ ExtEditWallData((short)i);
+ pageoffset = opageoffset; ydim16 = 336;
+ }
+ }
+
+ if (keystatus[0x14] > 0) // T (tag)
+ {
+ keystatus[0x14] = 0;
+ if ((keystatus[0x1d]|keystatus[0x9d]) > 0) //Ctrl-T
+ {
+ showtags ^= 1;
+ if (showtags == 0)
+ printmessage16("Show tags OFF");
+ else
+ printmessage16("Show tags ON");
+ }
+ else if ((keystatus[0x38]|keystatus[0xb8]) > 0) //ALT
+ {
+ if (pointhighlight >= 16384)
+ {
+ i = pointhighlight-16384;
+ sprintf(buffer,"Sprite (%ld) Lo-tag: ",i);
+ sprite[i].lotag = getnumber16(buffer,sprite[i].lotag,65536L);
+ clearmidstatbar16();
+ showspritedata((short)i);
+ }
+ else if (linehighlight >= 0)
+ {
+ i = linehighlight;
+ sprintf(buffer,"Wall (%ld) Lo-tag: ",i);
+ wall[i].lotag = getnumber16(buffer,wall[i].lotag,65536L);
+ clearmidstatbar16();
+ showwalldata((short)i);
+ }
+ printmessage16("");
+ }
+ else
+ {
+ for (i=0;i<numsectors;i++)
+ if (inside(mousxplc,mousyplc,i) == 1)
+ {
+ sprintf(buffer,"Sector (%ld) Lo-tag: ",i);
+ sector[i].lotag = getnumber16(buffer,sector[i].lotag,65536L);
+ clearmidstatbar16();
+ showsectordata((short)i);
+ break;
+ }
+ printmessage16("");
+ }
+ }
+ if (keystatus[0x23] > 0) //H (Hi 16 bits of tag)
+ {
+ keystatus[0x23] = 0;
+ if ((keystatus[0x1d]|keystatus[0x9d]) > 0) //Ctrl-H
+ {
+ pointhighlight = getpointhighlight(mousxplc, mousyplc);
+ linehighlight = getlinehighlight(mousxplc, mousyplc);
+
+ if ((pointhighlight&0xc000) == 16384)
+ {
+ sprite[pointhighlight&16383].cstat ^= 256;
+ asksave = 1;
+ }
+ else if (linehighlight >= 0)
+ {
+ wall[linehighlight].cstat ^= 64;
+ if ((wall[linehighlight].nextwall >= 0) && ((keystatus[0x2a]|keystatus[0x36]) == 0))
+ {
+ wall[wall[linehighlight].nextwall].cstat &= ~64;
+ wall[wall[linehighlight].nextwall].cstat |= (wall[linehighlight].cstat&64);
+ }
+ asksave = 1;
+ }
+ }
+ else if ((keystatus[0x38]|keystatus[0xb8]) > 0) //ALT
+ {
+ if (pointhighlight >= 16384)
+ {
+ i = pointhighlight-16384;
+ sprintf(buffer,"Sprite (%ld) Hi-tag: ",i);
+ sprite[i].hitag = getnumber16(buffer,sprite[i].hitag,65536L);
+ clearmidstatbar16();
+ showspritedata((short)i);
+ }
+ else if (linehighlight >= 0)
+ {
+ i = linehighlight;
+ sprintf(buffer,"Wall (%ld) Hi-tag: ",i);
+ wall[i].hitag = getnumber16(buffer,wall[i].hitag,65536L);
+ clearmidstatbar16();
+ showwalldata((short)i);
+ }
+ }
+ else
+ {
+ for (i=0;i<numsectors;i++)
+ if (inside(mousxplc,mousyplc,i) == 1)
+ {
+ sprintf(buffer,"Sector (%ld) Hi-tag: ",i);
+ sector[i].hitag = getnumber16(buffer,sector[i].hitag,65536L);
+ clearmidstatbar16();
+ showsectordata((short)i);
+ break;
+ }
+ }
+ printmessage16("");
+ }
+ if (keystatus[0x19] > 0) // P (palookup #)
+ {
+ keystatus[0x19] = 0;
+
+ for (i=0;i<numsectors;i++)
+ if (inside(mousxplc,mousyplc,i) == 1)
+ {
+ sprintf(buffer,"Sector (%ld) Ceilingpal: ",i);
+ sector[i].ceilingpal = getnumber16(buffer,sector[i].ceilingpal,256L);
+ clearmidstatbar16();
+ showsectordata((short)i);
+
+ sprintf(buffer,"Sector (%ld) Floorpal: ",i);
+ sector[i].floorpal = getnumber16(buffer,sector[i].floorpal,256L);
+ clearmidstatbar16();
+ showsectordata((short)i);
+
+ printmessage16("");
+ break;
+ }
+ }
+ if (keystatus[0x12] > 0) // E (status list)
+ {
+ if (pointhighlight >= 16384)
+ {
+ i = pointhighlight-16384;
+ sprintf(buffer,"Sprite (%ld) Status list: ",i);
+ changespritestat(i,getnumber16(buffer,sprite[i].statnum,65536L));
+ clearmidstatbar16();
+ showspritedata((short)i);
+ }
+
+ printmessage16("");
+
+ keystatus[0x12] = 0;
+ }
+
+ if (keystatus[0x0f] > 0) //TAB
+ {
+ clearmidstatbar16();
+
+ if ((keystatus[0x38]|keystatus[0xb8]) > 0) //ALT
+ {
+ if (pointhighlight >= 16384)
+ showspritedata((short)pointhighlight-16384);
+ else if (linehighlight >= 0)
+ showwalldata((short)linehighlight);
+ }
+ else
+ {
+ for (i=0;i<numsectors;i++)
+ if (inside(mousxplc,mousyplc,i) == 1)
+ {
+ showsectordata((short)i);
+ break;
+ }
+ }
+ keystatus[0x0f] = 0;
+ }
+
+
+ if (highlightsectorcnt < 0)
+ {
+ if (keystatus[0x36] > 0) //Right shift (point highlighting)
+ {
+ if (highlightcnt == 0)
+ {
+ highlightx2 = searchx, highlighty2 = searchy;
+ ydim16 = 336;
+ drawline16(highlightx2,highlighty1,highlightx1,highlighty1,5);
+ drawline16(highlightx2,highlighty2,highlightx1,highlighty2,5);
+ drawline16(highlightx1,highlighty2,highlightx1,highlighty1,5);
+ drawline16(highlightx2,highlighty2,highlightx2,highlighty1,5);
+ }
+ if (highlightcnt != 0)
+ {
+ highlightx1 = searchx;
+ highlighty1 = searchy;
+ highlightx2 = searchx;
+ highlighty2 = searchx;
+ highlightcnt = 0;
+
+ for(i=0;i<(MAXWALLS>>3);i++) //Clear all highlights
+ show2dwall[i] = 0;
+ for(i=0;i<(MAXSPRITES>>3);i++)
+ show2dsprite[i] = 0;
+ }
+ }
+ else
+ {
+ if (highlightcnt == 0)
+ {
+ getpoint(highlightx1,highlighty1,&highlightx1,&highlighty1);
+ getpoint(highlightx2,highlighty2,&highlightx2,&highlighty2);
+ if (highlightx1 > highlightx2)
+ {
+ templong = highlightx1; highlightx1 = highlightx2; highlightx2 = templong;
+ }
+ if (highlighty1 > highlighty2)
+ {
+ templong = highlighty1; highlighty1 = highlighty2; highlighty2 = templong;
+ }
+
+ if ((keystatus[0x1d]|keystatus[0x9d]) > 0)
+ {
+ if ((linehighlight >= 0) && (linehighlight < MAXWALLS))
+ {
+ i = linehighlight;
+ do
+ {
+ highlight[highlightcnt++] = i;
+ show2dwall[i>>3] |= (1<<(i&7));
+
+ for(j=0;j<numwalls;j++)
+ if (wall[j].x == wall[i].x)
+ if (wall[j].y == wall[i].y)
+ if (i != j)
+ {
+ highlight[highlightcnt++] = j;
+ show2dwall[j>>3] |= (1<<(j&7));
+ }
+
+ i = wall[i].point2;
+ }
+ while (i != linehighlight);
+ }
+ }
+ else
+ {
+ for(i=0;i<numwalls;i++)
+ if ((wall[i].x >= highlightx1) && (wall[i].x <= highlightx2))
+ if ((wall[i].y >= highlighty1) && (wall[i].y <= highlighty2))
+ {
+ highlight[highlightcnt++] = i;
+ show2dwall[i>>3] |= (1<<(i&7));
+ }
+ for(i=0;i<MAXSPRITES;i++)
+ if (sprite[i].statnum < MAXSTATUS)
+ if ((sprite[i].x >= highlightx1) && (sprite[i].x <= highlightx2))
+ if ((sprite[i].y >= highlighty1) && (sprite[i].y <= highlighty2))
+ {
+ highlight[highlightcnt++] = i+16384;
+ show2dsprite[i>>3] |= (1<<(i&7));
+ }
+ }
+
+ if (highlightcnt <= 0)
+ highlightcnt = -1;
+ }
+ }
+ }
+ if (highlightcnt < 0)
+ {
+ if (keystatus[0xb8] > 0) //Right alt (sector highlighting)
+ {
+ if (highlightsectorcnt == 0)
+ {
+ highlightx2 = searchx, highlighty2 = searchy;
+ ydim16 = 336;
+ drawline16(highlightx2,highlighty1,highlightx1,highlighty1,10);
+ drawline16(highlightx2,highlighty2,highlightx1,highlighty2,10);
+ drawline16(highlightx1,highlighty2,highlightx1,highlighty1,10);
+ drawline16(highlightx2,highlighty2,highlightx2,highlighty1,10);
+ }
+ if (highlightsectorcnt != 0)
+ {
+ for(i=0;i<highlightsectorcnt;i++)
+ {
+ startwall = sector[highlightsector[i]].wallptr;
+ endwall = startwall+sector[highlightsector[i]].wallnum-1;
+ for(j=startwall;j<=endwall;j++)
+ {
+ if (wall[j].nextwall >= 0)
+ checksectorpointer(wall[j].nextwall,wall[j].nextsector);
+ checksectorpointer((short)j,highlightsector[i]);
+ }
+ }
+ highlightx1 = searchx;
+ highlighty1 = searchy;
+ highlightx2 = searchx;
+ highlighty2 = searchx;
+ highlightsectorcnt = 0;
+ }
+ }
+ else
+ {
+ if (highlightsectorcnt == 0)
+ {
+ getpoint(highlightx1,highlighty1,&highlightx1,&highlighty1);
+ getpoint(highlightx2,highlighty2,&highlightx2,&highlighty2);
+ if (highlightx1 > highlightx2)
+ {
+ templong = highlightx1; highlightx1 = highlightx2; highlightx2 = templong;
+ }
+ if (highlighty1 > highlighty2)
+ {
+ templong = highlighty1; highlighty1 = highlighty2; highlighty2 = templong;
+ }
+
+ for(i=0;i<numsectors;i++)
+ {
+ startwall = sector[i].wallptr;
+ endwall = startwall + sector[i].wallnum;
+ bad = 0;
+ for(j=startwall;j<endwall;j++)
+ {
+ if (wall[j].x < highlightx1) bad = 1;
+ if (wall[j].x > highlightx2) bad = 1;
+ if (wall[j].y < highlighty1) bad = 1;
+ if (wall[j].y > highlighty2) bad = 1;
+ if (bad == 1) break;
+ }
+ if (bad == 0)
+ highlightsector[highlightsectorcnt++] = i;
+ }
+ if (highlightsectorcnt <= 0)
+ highlightsectorcnt = -1;
+
+ //White out all bordering lines of grab that are
+ //not highlighted on both sides
+ for(i=highlightsectorcnt-1;i>=0;i--)
+ {
+ startwall = sector[highlightsector[i]].wallptr;
+ endwall = startwall + sector[highlightsector[i]].wallnum;
+ for(j=startwall;j<endwall;j++)
+ {
+ if (wall[j].nextwall >= 0)
+ {
+ for(k=highlightsectorcnt-1;k>=0;k--)
+ if (highlightsector[k] == wall[j].nextsector)
+ break;
+ if (k < 0)
+ {
+ wall[wall[j].nextwall].nextwall = -1;
+ wall[wall[j].nextwall].nextsector = -1;
+ wall[j].nextwall = -1;
+ wall[j].nextsector = -1;
+ }
+ }
+ }
+ }
+
+ }
+ }
+ }
+
+ if (((bstatus&1) < (oldmousebstatus&1)) && (highlightsectorcnt < 0)) //after dragging
+ {
+ j = 1;
+ if (highlightcnt > 0)
+ for (i=0;i<highlightcnt;i++)
+ if (pointhighlight == highlight[i])
+ {
+ j = 0;
+ break;
+ }
+
+ if (j == 0)
+ {
+ for(i=0;i<highlightcnt;i++)
+ {
+ if ((highlight[i]&0xc000) == 16384)
+ {
+ j = (highlight[i]&16383);
+
+ setsprite(j,sprite[j].x,sprite[j].y,sprite[j].z);
+
+ templong = ((tilesizy[sprite[j].picnum]*sprite[j].yrepeat)<<2);
+ sprite[j].z = max(sprite[j].z,getceilzofslope(sprite[j].sectnum,sprite[j].x,sprite[j].y)+templong);
+ sprite[j].z = min(sprite[j].z,getflorzofslope(sprite[j].sectnum,sprite[j].x,sprite[j].y));
+ }
+ }
+ }
+ else if ((pointhighlight&0xc000) == 16384)
+ {
+ j = (pointhighlight&16383);
+
+ setsprite(j,sprite[j].x,sprite[j].y,sprite[j].z);
+
+ templong = ((tilesizy[sprite[j].picnum]*sprite[j].yrepeat)<<2);
+
+ sprite[j].z = max(sprite[j].z,getceilzofslope(sprite[j].sectnum,sprite[j].x,sprite[j].y)+templong);
+ sprite[j].z = min(sprite[j].z,getflorzofslope(sprite[j].sectnum,sprite[j].x,sprite[j].y));
+ }
+
+ if ((pointhighlight&0xc000) == 0)
+ {
+ dax = wall[pointhighlight].x;
+ day = wall[pointhighlight].y;
+ }
+ else
+ {
+ dax = sprite[pointhighlight&16383].x;
+ day = sprite[pointhighlight&16383].y;
+ }
+
+ for(i=numwalls-1;i>=0;i--) //delete points
+ {
+ if (wall[i].x == wall[wall[i].point2].x)
+ if (wall[i].y == wall[wall[i].point2].y)
+ {
+ deletepoint((short)i);
+ printmessage16("Point deleted.");
+ asksave = 1;
+ }
+ }
+ for(i=0;i<numwalls;i++) //make new red lines?
+ {
+ if ((wall[i].x == dax) && (wall[i].y == day))
+ {
+ checksectorpointer((short)i,sectorofwall((short)i));
+ fixrepeats((short)i);
+ asksave = 1;
+ }
+ else if ((wall[wall[i].point2].x == dax) && (wall[wall[i].point2].y == day))
+ {
+ checksectorpointer((short)i,sectorofwall((short)i));
+ fixrepeats((short)i);
+ asksave = 1;
+ }
+ }
+
+ }
+
+ if ((bstatus&1) > 0) //drag points
+ {
+ if (highlightsectorcnt > 0)
+ {
+ if ((bstatus&1) > (oldmousebstatus&1))
+ {
+ newnumwalls = -1;
+ sectorhighlightstat = -1;
+ updatesector(mousxplc,mousyplc,&cursectorhighlight);
+
+ if ((cursectorhighlight >= 0) && (cursectorhighlight < numsectors))
+ {
+ for (i=0;i<highlightsectorcnt;i++)
+ if (cursectorhighlight == highlightsector[i])
+ {
+ //You clicked inside one of the flashing sectors!
+ sectorhighlightstat = 1;
+
+ dax = mousxplc;
+ day = mousyplc;
+ if ((gridlock > 0) && (grid > 0))
+ {
+ dax = ((dax+(1024>>grid))&(0xffffffff<<(11-grid)));
+ day = ((day+(1024>>grid))&(0xffffffff<<(11-grid)));
+ }
+ sectorhighlightx = dax;
+ sectorhighlighty = day;
+ break;
+ }
+ }
+ }
+ else if (sectorhighlightstat == 1)
+ {
+ dax = mousxplc;
+ day = mousyplc;
+ if ((gridlock > 0) && (grid > 0))
+ {
+ dax = ((dax+(1024>>grid))&(0xffffffff<<(11-grid)));
+ day = ((day+(1024>>grid))&(0xffffffff<<(11-grid)));
+ }
+
+ dax -= sectorhighlightx;
+ day -= sectorhighlighty;
+ sectorhighlightx += dax;
+ sectorhighlighty += day;
+
+ for(i=0;i<highlightsectorcnt;i++)
+ {
+ startwall = sector[highlightsector[i]].wallptr;
+ endwall = startwall+sector[highlightsector[i]].wallnum-1;
+ for(j=startwall;j<=endwall;j++)
+ { wall[j].x += dax; wall[j].y += day; }
+
+ for(j=headspritesect[highlightsector[i]];j>=0;j=nextspritesect[j])
+ { sprite[j].x += dax; sprite[j].y += day; }
+ }
+
+ //for(i=0;i<highlightsectorcnt;i++)
+ //{
+ // startwall = sector[highlightsector[i]].wallptr;
+ // endwall = startwall+sector[highlightsector[i]].wallnum-1;
+ // for(j=startwall;j<=endwall;j++)
+ // {
+ // if (wall[j].nextwall >= 0)
+ // checksectorpointer(wall[j].nextwall,wall[j].nextsector);
+ // checksectorpointer((short)j,highlightsector[i]);
+ // }
+ //}
+ asksave = 1;
+ }
+
+ }
+ else
+ {
+ if ((bstatus&1) > (oldmousebstatus&1))
+ pointhighlight = getpointhighlight(mousxplc, mousyplc);
+
+ if (pointhighlight >= 0)
+ {
+ dax = mousxplc;
+ day = mousyplc;
+ if ((gridlock > 0) && (grid > 0))
+ {
+ dax = ((dax+(1024>>grid))&(0xffffffff<<(11-grid)));
+ day = ((day+(1024>>grid))&(0xffffffff<<(11-grid)));
+ }
+
+ j = 1;
+ if (highlightcnt > 0)
+ for (i=0;i<highlightcnt;i++)
+ if (pointhighlight == highlight[i])
+ { j = 0; break; }
+
+ if (j == 0)
+ {
+ if ((pointhighlight&0xc000) == 0)
+ {
+ dax -= wall[pointhighlight].x;
+ day -= wall[pointhighlight].y;
+ }
+ else
+ {
+ dax -= sprite[pointhighlight&16383].x;
+ day -= sprite[pointhighlight&16383].y;
+ }
+ for(i=0;i<highlightcnt;i++)
+ {
+ if ((highlight[i]&0xc000) == 0)
+ {
+ wall[highlight[i]].x += dax;
+ wall[highlight[i]].y += day;
+ }
+ else
+ {
+ sprite[highlight[i]&16383].x += dax;
+ sprite[highlight[i]&16383].y += day;
+ }
+ }
+ }
+ else
+ {
+ if ((pointhighlight&0xc000) == 0)
+ dragpoint(pointhighlight,dax,day);
+ else if ((pointhighlight&0xc000) == 16384)
+ {
+ daz = ((tilesizy[sprite[pointhighlight&16383].picnum]*sprite[pointhighlight&16383].yrepeat)<<2);
+
+ for(i=0;i<numsectors;i++)
+ if (inside(dax,day,i) == 1)
+ if (sprite[pointhighlight&16383].z >= getceilzofslope(i,dax,day))
+ if (sprite[pointhighlight&16383].z-daz <= getflorzofslope(i,dax,day))
+ {
+ sprite[pointhighlight&16383].x = dax;
+ sprite[pointhighlight&16383].y = day;
+ if (sprite[pointhighlight&16383].sectnum != i)
+ changespritesect(pointhighlight&16383,(short)i);
+ break;
+ }
+ }
+ }
+ asksave = 1;
+ }
+ }
+ }
+ else
+ {
+ pointhighlight = getpointhighlight(mousxplc, mousyplc);
+ sectorhighlightstat = -1;
+ }
+
+ if ((bstatus&6) > 0)
+ {
+ searchx = 320;
+ searchy = 200;
+ posx = mousxplc;
+ posy = mousyplc;
+ }
+
+ if ((keystatus[buildkeys[8]] > 0) && (zoom < 16384)) zoom += (zoom>>4);
+ if ((keystatus[buildkeys[9]] > 0) && (zoom > 24)) zoom -= (zoom>>4);
+
+ if (keystatus[0x22] > 0) // G (grid on/off)
+ {
+ grid++;
+ if (grid == 7) grid = 0;
+ keystatus[0x22] = 0;
+ }
+ if (keystatus[0x26] > 0) // L (grid lock)
+ {
+ gridlock = 1-gridlock, keystatus[0x26] = 0;
+ if (gridlock == 0)
+ printmessage16("Grid locking OFF");
+ else
+ printmessage16("Grid locking ON");
+ }
+
+ if (keystatus[0x24] > 0) // J (join sectors)
+ {
+ if (joinsector[0] >= 0)
+ {
+ joinsector[1] = -1;
+ for(i=0;i<numsectors;i++)
+ if (inside(mousxplc,mousyplc,i) == 1)
+ {
+ joinsector[1] = i;
+ break;
+ }
+ if ((joinsector[1] >= 0) && (joinsector[0] != joinsector[1]))
+ {
+ newnumwalls = numwalls;
+
+ for(k=0;k<2;k++)
+ {
+ startwall = sector[joinsector[k]].wallptr;
+ endwall = startwall + sector[joinsector[k]].wallnum - 1;
+ for(j=startwall;j<=endwall;j++)
+ {
+ if (wall[j].cstat == 255)
+ continue;
+ joinsectnum = k;
+ if (wall[j].nextsector == joinsector[1-joinsectnum])
+ {
+ wall[j].cstat = 255;
+ continue;
+ }
+
+ i = j;
+ m = newnumwalls;
+ do
+ {
+ memcpy(&wall[newnumwalls],&wall[i],sizeof(walltype));
+ wall[newnumwalls].point2 = newnumwalls+1;
+ newnumwalls++;
+ wall[i].cstat = 255;
+
+ i = wall[i].point2;
+ if (wall[i].nextsector == joinsector[1-joinsectnum])
+ {
+ i = wall[wall[i].nextwall].point2;
+ joinsectnum = 1 - joinsectnum;
+ }
+ }
+ while ((wall[i].cstat != 255) && (wall[i].nextsector != joinsector[1-joinsectnum]));
+ wall[newnumwalls-1].point2 = m;
+ }
+ }
+
+ if (newnumwalls > numwalls)
+ {
+ memcpy(&sector[numsectors],&sector[joinsector[0]],sizeof(sectortype));
+ sector[numsectors].wallptr = numwalls;
+ sector[numsectors].wallnum = newnumwalls-numwalls;
+
+ //fix sprites
+ for(i=0;i<2;i++)
+ {
+ j = headspritesect[joinsector[i]];
+ while (j != -1)
+ {
+ k = nextspritesect[j];
+ changespritesect(j,numsectors);
+ j = k;
+ }
+ }
+
+ numsectors++;
+
+ for(i=numwalls;i<newnumwalls;i++)
+ {
+ if (wall[i].nextwall >= 0)
+ {
+ wall[wall[i].nextwall].nextwall = i;
+ wall[wall[i].nextwall].nextsector = numsectors-1;
+ }
+ }
+
+ numwalls = newnumwalls;
+ newnumwalls = -1;
+
+ for(k=0;k<2;k++)
+ {
+ startwall = sector[joinsector[k]].wallptr;
+ endwall = startwall + sector[joinsector[k]].wallnum - 1;
+ for(j=startwall;j<=endwall;j++)
+ {
+ wall[j].nextwall = -1;
+ wall[j].nextsector = -1;
+ }
+ }
+
+ deletesector((short)joinsector[0]);
+ if (joinsector[0] < joinsector[1])
+ joinsector[1]--;
+ deletesector((short)joinsector[1]);
+ printmessage16("Sectors joined.");
+ }
+ }
+ joinsector[0] = -1;
+ }
+ else
+ {
+ joinsector[0] = -1;
+ for(i=0;i<numsectors;i++)
+ if (inside(mousxplc,mousyplc,i) == 1)
+ {
+ joinsector[0] = i;
+ printmessage16("Join sector - press J again on sector to join with.");
+ break;
+ }
+ }
+ keystatus[0x24] = 0;
+ }
+
+ if (((keystatus[0x38]|keystatus[0xb8])&keystatus[0x1f]) > 0) //ALT-S
+ {
+ if ((linehighlight >= 0) && (wall[linehighlight].nextwall == -1))
+ {
+ if ((newnumwalls = whitelinescan(linehighlight)) < numwalls)
+ {
+ printmessage16("Can't make a sector out there.");
+ }
+ else
+ {
+ for(i=numwalls;i<newnumwalls;i++)
+ {
+ wall[wall[i].nextwall].nextwall = i;
+ wall[wall[i].nextwall].nextsector = numsectors;
+ }
+ numwalls = newnumwalls;
+ newnumwalls = -1;
+ numsectors++;
+ printmessage16("Inner loop made into new sector.");
+ }
+ }
+ keystatus[0x1f] = 0;
+ }
+ else if (keystatus[0x1f] > 0) //S
+ {
+ sucksect = -1;
+ for(i=0;i<numsectors;i++)
+ if (inside(mousxplc,mousyplc,i) == 1)
+ {
+ sucksect = i;
+ break;
+ }
+
+ if (sucksect >= 0)
+ {
+ dax = mousxplc;
+ day = mousyplc;
+ if ((gridlock > 0) && (grid > 0))
+ {
+ dax = ((dax+(1024>>grid))&(0xffffffff<<(11-grid)));
+ day = ((day+(1024>>grid))&(0xffffffff<<(11-grid)));
+ }
+
+ i = insertsprite(sucksect,0);
+ sprite[i].x = dax, sprite[i].y = day;
+ sprite[i].cstat = defaultspritecstat;
+ sprite[i].shade = 0;
+ sprite[i].pal = 0;
+ sprite[i].xrepeat = 64, sprite[i].yrepeat = 64;
+ sprite[i].xoffset = 0, sprite[i].yoffset = 0;
+ sprite[i].ang = 1536;
+ sprite[i].xvel = 0; sprite[i].yvel = 0; sprite[i].zvel = 0;
+ sprite[i].owner = -1;
+ sprite[i].clipdist = 32;
+ sprite[i].lotag = 0;
+ sprite[i].hitag = 0;
+ sprite[i].extra = -1;
+
+ sprite[i].z = getflorzofslope(sucksect,dax,day);
+ if ((sprite[i].cstat&128) != 0)
+ sprite[i].z -= ((tilesizy[sprite[i].picnum]*sprite[i].yrepeat)<<1);
+
+ for(k=0;k<MAXTILES;k++)
+ localartfreq[k] = 0;
+ for(k=0;k<MAXSPRITES;k++)
+ if (sprite[k].statnum < MAXSTATUS)
+ localartfreq[sprite[k].picnum]++;
+ j = 0;
+ for(k=0;k<MAXTILES;k++)
+ if (localartfreq[k] > localartfreq[j])
+ j = k;
+ if (localartfreq[j] > 0)
+ sprite[i].picnum = j;
+ else
+ sprite[i].picnum = 0;
+
+ if (somethingintab == 3)
+ {
+ sprite[i].picnum = temppicnum;
+ if ((tilesizx[temppicnum] <= 0) || (tilesizy[temppicnum] <= 0))
+ {
+ j = 0;
+ for(k=0;k<MAXTILES;k++)
+ if ((tilesizx[k] > 0) && (tilesizy[k] > 0))
+ {
+ j = k;
+ break;
+ }
+ sprite[i].picnum = j;
+ }
+ sprite[i].shade = tempshade;
+ sprite[i].pal = temppal;
+ sprite[i].xrepeat = tempxrepeat;
+ sprite[i].yrepeat = tempyrepeat;
+ if (sprite[i].xrepeat < 1) sprite[i].xrepeat = 1;
+ if (sprite[i].yrepeat < 1) sprite[i].yrepeat = 1;
+ sprite[i].cstat = tempcstat;
+ }
+
+ if (tilesizy[sprite[i].picnum] >= 32)
+ sprite[i].cstat |= 1;
+
+ printmessage16("Sprite inserted.");
+ updatenumsprites();
+ asksave = 1;
+ }
+
+ keystatus[0x1f] = 0;
+ }
+
+ if (keystatus[0x2e] > 0) // C (make circle of points)
+ {
+ if (circlewall >= 0)
+ {
+ circlewall = -1;
+ }
+ else
+ {
+ if (linehighlight >= 0)
+ circlewall = linehighlight;
+ }
+ keystatus[0x2e] = 0;
+ }
+ if (keystatus[0x4a] > 0) // -
+ {
+ if (circlepoints > 1)
+ circlepoints--;
+ keystatus[0x4a] = 0;
+ }
+ if (keystatus[0x4e] > 0) // +
+ {
+ if (circlepoints < 63)
+ circlepoints++;
+ keystatus[0x4e] = 0;
+ }
+
+ bad = (keystatus[0x39] > 0); //Gotta do this to save lots of 3 spaces!
+
+ if (circlewall >= 0)
+ {
+ x1 = wall[circlewall].x;
+ y1 = wall[circlewall].y;
+ x2 = wall[wall[circlewall].point2].x;
+ y2 = wall[wall[circlewall].point2].y;
+ x3 = mousxplc;
+ y3 = mousyplc;
+ adjustmark(&x3,&y3,newnumwalls);
+ templong1 = dmulscale4(x3-x2,x1-x3,y1-y3,y3-y2);
+ templong2 = dmulscale4(y1-y2,x1-x3,y1-y3,x2-x1);
+ if (templong2 != 0)
+ {
+ centerx = (((x1+x2) + scale(y1-y2,templong1,templong2))>>1);
+ centery = (((y1+y2) + scale(x2-x1,templong1,templong2))>>1);
+
+ dax = mulscale14(centerx-posx,zoom);
+ day = mulscale14(centery-posy,zoom);
+ drawline16(320+dax-2,200+day-2,320+dax+2,200+day+2,14);
+ drawline16(320+dax-2,200+day+2,320+dax+2,200+day-2,14);
+
+ circleang1 = getangle(x1-centerx,y1-centery);
+ circleang2 = getangle(x2-centerx,y2-centery);
+
+ circleangdir = 1;
+ k = ((circleang2-circleang1)&2047);
+ if (mulscale4(x3-x1,y2-y1) < mulscale4(x2-x1,y3-y1))
+ {
+ circleangdir = -1;
+ k = -((circleang1-circleang2)&2047);
+ }
+
+ circlerad = (ksqrt(dmulscale4(centerx-x1,centerx-x1,centery-y1,centery-y1))<<2);
+
+ for(i=circlepoints;i>0;i--)
+ {
+ j = ((circleang1 + scale(i,k,circlepoints+1))&2047);
+ dax = centerx+mulscale14(sintable[(j+512)&2047],circlerad);
+ day = centery+mulscale14(sintable[j],circlerad);
+
+ if (dax <= -131072) dax = -131072;
+ if (dax >= 131072) dax = 131072;
+ if (day <= -131072) day = -131072;
+ if (day >= 131072) day = 131072;
+
+ if (bad > 0)
+ {
+ m = 0;
+ if (wall[circlewall].nextwall >= 0)
+ if (wall[circlewall].nextwall < circlewall) m = 1;
+ insertpoint(circlewall,dax,day);
+ circlewall += m;
+ }
+ dax = mulscale14(dax-posx,zoom);
+ day = mulscale14(day-posy,zoom);
+ drawline16(320+dax-2,200+day-2,320+dax+2,200+day-2,14);
+ drawline16(320+dax+2,200+day-2,320+dax+2,200+day+2,14);
+ drawline16(320+dax+2,200+day+2,320+dax-2,200+day+2,14);
+ drawline16(320+dax-2,200+day+2,320+dax-2,200+day-2,14);
+ }
+ if (bad > 0)
+ {
+ bad = 0;
+ keystatus[0x39] = 0;
+ asksave = 1;
+ printmessage16("Circle points inserted.");
+ circlewall = -1;
+ }
+ }
+ }
+
+ if (bad > 0) //Space bar test
+ {
+ keystatus[0x39] = 0;
+ adjustmark(&mousxplc,&mousyplc,newnumwalls);
+ if (checkautoinsert(mousxplc,mousyplc,newnumwalls) == 1)
+ {
+ printmessage16("You must insert a point there first.");
+ bad = 0;
+ }
+ }
+
+ if (bad > 0) //Space
+ {
+ if ((newnumwalls < numwalls) && (numwalls < MAXWALLS-1))
+ {
+ firstx = mousxplc, firsty = mousyplc; //Make first point
+ newnumwalls = numwalls;
+ suckwall = -1;
+ split = 0;
+
+ clearbufbyte(FP_OFF(&wall[newnumwalls]),sizeof(walltype),0L);
+ wall[newnumwalls].extra = -1;
+
+ wall[newnumwalls].x = mousxplc;
+ wall[newnumwalls].y = mousyplc;
+ wall[newnumwalls].nextsector = -1;
+ wall[newnumwalls].nextwall = -1;
+ for(i=0;i<numwalls;i++)
+ if ((wall[i].x == mousxplc) && (wall[i].y == mousyplc))
+ suckwall = i;
+ wall[newnumwalls].point2 = newnumwalls+1;
+ printmessage16("Sector drawing started.");
+ newnumwalls++;
+ }
+ else
+ { //if not back to first point
+ if ((firstx != mousxplc) || (firsty != mousyplc)) //nextpoint
+ {
+ j = 0;
+ for(i=numwalls;i<newnumwalls;i++)
+ if ((mousxplc == wall[i].x) && (mousyplc == wall[i].y))
+ j = 1;
+ if (j == 0)
+ {
+ //check if starting to split a sector
+ if (newnumwalls == numwalls+1)
+ {
+ dax = ((wall[numwalls].x+mousxplc)>>1);
+ day = ((wall[numwalls].y+mousyplc)>>1);
+ for(i=0;i<numsectors;i++)
+ if (inside(dax,day,i) == 1)
+ { //check if first point at point of sector
+ m = -1;
+ startwall = sector[i].wallptr;
+ endwall = startwall + sector[i].wallnum - 1;
+ for(k=startwall;k<=endwall;k++)
+ if (wall[k].x == wall[numwalls].x)
+ if (wall[k].y == wall[numwalls].y)
+ {
+ m = k;
+ break;
+ }
+ if (m >= 0)
+ if ((wall[wall[k].point2].x != mousxplc) || (wall[wall[k].point2].y != mousyplc))
+ if ((wall[lastwall((short)k)].x != mousxplc) || (wall[lastwall((short)k)].y != mousyplc))
+ {
+ split = 1;
+ splitsect = i;
+ splitstartwall = m;
+ break;
+ }
+ }
+ }
+
+ //make new point
+
+ //make sure not drawing over old red line
+ bad = 0;
+ for(i=0;i<numwalls;i++)
+ {
+ if (wall[i].nextwall >= 0)
+ {
+ if ((wall[i].x == mousxplc) && (wall[i].y == mousyplc))
+ if ((wall[wall[i].point2].x == wall[newnumwalls-1].x) && (wall[wall[i].point2].y == wall[newnumwalls-1].y))
+ bad = 1;
+ if ((wall[i].x == wall[newnumwalls-1].x) && (wall[i].y == wall[newnumwalls-1].y))
+ if ((wall[wall[i].point2].x == mousxplc) && (wall[wall[i].point2].y == mousyplc))
+ bad = 1;
+ }
+ }
+
+ if (bad == 0)
+ {
+ clearbufbyte(FP_OFF(&wall[newnumwalls]),sizeof(walltype),0L);
+ wall[newnumwalls].extra = -1;
+
+ wall[newnumwalls].x = mousxplc;
+ wall[newnumwalls].y = mousyplc;
+ wall[newnumwalls].nextsector = -1;
+ wall[newnumwalls].nextwall = -1;
+ for(i=0;i<numwalls;i++)
+ if ((wall[i].x == mousxplc) && (wall[i].y == mousyplc))
+ suckwall = i;
+ wall[newnumwalls].point2 = newnumwalls+1;
+ newnumwalls++;
+ }
+ else
+ {
+ printmessage16("You can't draw new lines over red lines.");
+ }
+ }
+ }
+
+ //if not split and back to first point
+ if ((split == 0) && (firstx == mousxplc) && (firsty == mousyplc) && (newnumwalls >= numwalls+3))
+ {
+ wall[newnumwalls-1].point2 = numwalls;
+
+ if (suckwall == -1) //if no connections to other sectors
+ {
+ k = -1;
+ for(i=0;i<numsectors;i++)
+ if (inside(firstx,firsty,i) == 1)
+ k = i;
+ if (k == -1) //if not inside another sector either
+ { //add island sector
+ if (clockdir(numwalls) == 1)
+ flipwalls(numwalls,newnumwalls);
+
+ clearbufbyte(FP_OFF(&sector[numsectors]),sizeof(sectortype),0L);
+ sector[numsectors].extra = -1;
+
+ sector[numsectors].wallptr = numwalls;
+ sector[numsectors].wallnum = newnumwalls-numwalls;
+ sector[numsectors].ceilingz = (-32<<8);
+ sector[numsectors].floorz = (32<<8);
+ for(i=numwalls;i<newnumwalls;i++)
+ {
+ wall[i].cstat = 0;
+ wall[i].shade = 0;
+ wall[i].yrepeat = 8;
+ fixrepeats((short)i);
+ wall[i].picnum = 0;
+ wall[i].overpicnum = 0;
+ wall[i].nextsector = -1;
+ wall[i].nextwall = -1;
+ }
+ headspritesect[numsectors] = -1;
+ numsectors++;
+ }
+ else //else add loop to sector
+ {
+ if (clockdir(numwalls) == 0)
+ flipwalls(numwalls,newnumwalls);
+
+ j = newnumwalls-numwalls;
+
+ sector[k].wallnum += j;
+ for(i=k+1;i<numsectors;i++)
+ sector[i].wallptr += j;
+ suckwall = sector[k].wallptr;
+
+ for(i=0;i<numwalls;i++)
+ {
+ if (wall[i].nextwall >= suckwall)
+ wall[i].nextwall += j;
+ if (wall[i].point2 >= suckwall)
+ wall[i].point2 += j;
+ }
+
+ for(i=newnumwalls-1;i>=suckwall;i--)
+ memcpy(&wall[i+j],&wall[i],sizeof(walltype));
+ for(i=0;i<j;i++)
+ memcpy(&wall[i+suckwall],&wall[i+newnumwalls],sizeof(walltype));
+
+ for(i=suckwall;i<suckwall+j;i++)
+ {
+ wall[i].point2 += (suckwall-numwalls);
+
+ wall[i].cstat = wall[suckwall+j].cstat;
+ wall[i].shade = wall[suckwall+j].shade;
+ wall[i].yrepeat = wall[suckwall+j].yrepeat;
+ fixrepeats((short)i);
+ wall[i].picnum = wall[suckwall+j].picnum;
+ wall[i].overpicnum = wall[suckwall+j].overpicnum;
+
+ wall[i].nextsector = -1;
+ wall[i].nextwall = -1;
+ }
+ }
+ }
+ else
+ {
+ //add new sector with connections
+ if (clockdir(numwalls) == 1)
+ flipwalls(numwalls,newnumwalls);
+
+ clearbufbyte(FP_OFF(&sector[numsectors]),sizeof(sectortype),0L);
+ sector[numsectors].extra = -1;
+
+ sector[numsectors].wallptr = numwalls;
+ sector[numsectors].wallnum = newnumwalls-numwalls;
+ sucksect = sectorofwall(suckwall);
+ sector[numsectors].ceilingstat = sector[sucksect].ceilingstat;
+ sector[numsectors].floorstat = sector[sucksect].floorstat;
+ sector[numsectors].ceilingxpanning = sector[sucksect].ceilingxpanning;
+ sector[numsectors].floorxpanning = sector[sucksect].floorxpanning;
+ sector[numsectors].ceilingshade = sector[sucksect].ceilingshade;
+ sector[numsectors].floorshade = sector[sucksect].floorshade;
+ sector[numsectors].ceilingz = sector[sucksect].ceilingz;
+ sector[numsectors].floorz = sector[sucksect].floorz;
+ sector[numsectors].ceilingpicnum = sector[sucksect].ceilingpicnum;
+ sector[numsectors].floorpicnum = sector[sucksect].floorpicnum;
+ sector[numsectors].ceilingheinum = sector[sucksect].ceilingheinum;
+ sector[numsectors].floorheinum = sector[sucksect].floorheinum;
+ for(i=numwalls;i<newnumwalls;i++)
+ {
+ wall[i].cstat = wall[suckwall].cstat;
+ wall[i].shade = wall[suckwall].shade;
+ wall[i].yrepeat = wall[suckwall].yrepeat;
+ fixrepeats((short)i);
+ wall[i].picnum = wall[suckwall].picnum;
+ wall[i].overpicnum = wall[suckwall].overpicnum;
+ checksectorpointer((short)i,(short)numsectors);
+ }
+ headspritesect[numsectors] = -1;
+ numsectors++;
+ }
+ numwalls = newnumwalls;
+ newnumwalls = -1;
+ asksave = 1;
+ }
+ if (split == 1)
+ {
+ //split sector
+ startwall = sector[splitsect].wallptr;
+ endwall = startwall + sector[splitsect].wallnum - 1;
+ for(k=startwall;k<=endwall;k++)
+ if (wall[k].x == wall[newnumwalls-1].x)
+ if (wall[k].y == wall[newnumwalls-1].y)
+ {
+ bad = 0;
+ if (loopnumofsector(splitsect,splitstartwall) != loopnumofsector(splitsect,(short)k))
+ bad = 1;
+
+ if (bad == 0)
+ {
+ //SPLIT IT!
+ //Split splitsect given: startwall,
+ // new points: numwalls to newnumwalls-2
+
+ splitendwall = k;
+ newnumwalls--; //first fix up the new walls
+ for(i=numwalls;i<newnumwalls;i++)
+ {
+ wall[i].cstat = wall[startwall].cstat;
+ wall[i].shade = wall[startwall].shade;
+ wall[i].yrepeat = wall[startwall].yrepeat;
+ fixrepeats((short)i);
+ wall[i].picnum = wall[startwall].picnum;
+ wall[i].overpicnum = wall[startwall].overpicnum;
+
+ wall[i].nextwall = -1;
+ wall[i].nextsector = -1;
+ wall[i].point2 = i+1;
+ }
+
+ danumwalls = newnumwalls; //where to add more walls
+ m = splitendwall; //copy rest of loop next
+ while (m != splitstartwall)
+ {
+ memcpy(&wall[danumwalls],&wall[m],sizeof(walltype));
+ wall[danumwalls].point2 = danumwalls+1;
+ danumwalls++;
+ m = wall[m].point2;
+ }
+ wall[danumwalls-1].point2 = numwalls;
+
+ //Add other loops for 1st sector
+ loopnum = loopnumofsector(splitsect,splitstartwall);
+ i = loopnum;
+ for(j=startwall;j<=endwall;j++)
+ {
+ k = loopnumofsector(splitsect,(short)j);
+ if ((k != i) && (k != loopnum))
+ {
+ i = k;
+ if (loopinside(wall[j].x,wall[j].y,numwalls) == 1)
+ {
+ m = j; //copy loop
+ k = danumwalls;
+ do
+ {
+ memcpy(&wall[danumwalls],&wall[m],sizeof(walltype));
+ wall[danumwalls].point2 = danumwalls+1;
+ danumwalls++;
+ m = wall[m].point2;
+ }
+ while (m != j);
+ wall[danumwalls-1].point2 = k;
+ }
+ }
+ }
+
+ secondstartwall = danumwalls;
+ //copy split points for other sector backwards
+ for(j=newnumwalls;j>numwalls;j--)
+ {
+ memcpy(&wall[danumwalls],&wall[j],sizeof(walltype));
+ wall[danumwalls].nextwall = -1;
+ wall[danumwalls].nextsector = -1;
+ wall[danumwalls].point2 = danumwalls+1;
+ danumwalls++;
+ }
+ m = splitstartwall; //copy rest of loop next
+ while (m != splitendwall)
+ {
+ memcpy(&wall[danumwalls],&wall[m],sizeof(walltype));
+ wall[danumwalls].point2 = danumwalls+1;
+ danumwalls++;
+ m = wall[m].point2;
+ }
+ wall[danumwalls-1].point2 = secondstartwall;
+
+ //Add other loops for 2nd sector
+ loopnum = loopnumofsector(splitsect,splitstartwall);
+ i = loopnum;
+ for(j=startwall;j<=endwall;j++)
+ {
+ k = loopnumofsector(splitsect,(short)j);
+ if ((k != i) && (k != loopnum))
+ {
+ i = k;
+ if (loopinside(wall[j].x,wall[j].y,secondstartwall) == 1)
+ {
+ m = j; //copy loop
+ k = danumwalls;
+ do
+ {
+ memcpy(&wall[danumwalls],&wall[m],sizeof(walltype));
+ wall[danumwalls].point2 = danumwalls+1;
+ danumwalls++;
+ m = wall[m].point2;
+ }
+ while (m != j);
+ wall[danumwalls-1].point2 = k;
+ }
+ }
+ }
+
+ //fix all next pointers on old sector line
+ for(j=numwalls;j<danumwalls;j++)
+ {
+ if (wall[j].nextwall >= 0)
+ {
+ wall[wall[j].nextwall].nextwall = j;
+ if (j < secondstartwall)
+ wall[wall[j].nextwall].nextsector = numsectors;
+ else
+ wall[wall[j].nextwall].nextsector = numsectors+1;
+ }
+ }
+ //set all next pointers on split
+ for(j=numwalls;j<newnumwalls;j++)
+ {
+ m = secondstartwall+(newnumwalls-1-j);
+ wall[j].nextwall = m;
+ wall[j].nextsector = numsectors+1;
+ wall[m].nextwall = j;
+ wall[m].nextsector = numsectors;
+ }
+ //copy sector attributes & fix wall pointers
+ memcpy(&sector[numsectors],&sector[splitsect],sizeof(sectortype));
+ memcpy(&sector[numsectors+1],&sector[splitsect],sizeof(sectortype));
+ sector[numsectors].wallptr = numwalls;
+ sector[numsectors].wallnum = secondstartwall-numwalls;
+ sector[numsectors+1].wallptr = secondstartwall;
+ sector[numsectors+1].wallnum = danumwalls-secondstartwall;
+
+ //fix sprites
+ j = headspritesect[splitsect];
+ while (j != -1)
+ {
+ k = nextspritesect[j];
+ if (loopinside(sprite[j].x,sprite[j].y,numwalls) == 1)
+ changespritesect(j,numsectors);
+ //else if (loopinside(sprite[j].x,sprite[j].y,secondstartwall) == 1)
+ else //Make sure no sprites get left out & deleted!
+ changespritesect(j,numsectors+1);
+ j = k;
+ }
+
+ numsectors+=2;
+
+ //Back of number of walls of new sector for later
+ k = danumwalls-numwalls;
+
+ //clear out old sector's next pointers for clean deletesector
+ numwalls = danumwalls;
+ for(j=startwall;j<=endwall;j++)
+ {
+ wall[j].nextwall = -1;
+ wall[j].nextsector = -1;
+ }
+ deletesector(splitsect);
+
+ //Check pointers
+ for(j=numwalls-k;j<numwalls;j++)
+ {
+ if (wall[j].nextwall >= 0)
+ checksectorpointer(wall[j].nextwall,wall[j].nextsector);
+ checksectorpointer((short)j,sectorofwall((short)j));
+ }
+
+ //k now safe to use as temp
+
+ for(m=numsectors-2;m<numsectors;m++)
+ {
+ j = headspritesect[m];
+ while (j != -1)
+ {
+ k = nextspritesect[j];
+ setsprite(j,sprite[j].x,sprite[j].y,sprite[j].z);
+ j = k;
+ }
+ }
+
+ newnumwalls = -1;
+ printmessage16("Sector split.");
+ break;
+ }
+ else
+ {
+ //Sector split - actually loop joining
+
+ splitendwall = k;
+ newnumwalls--; //first fix up the new walls
+ for(i=numwalls;i<newnumwalls;i++)
+ {
+ wall[i].cstat = wall[startwall].cstat;
+ wall[i].shade = wall[startwall].shade;
+ wall[i].yrepeat = wall[startwall].yrepeat;
+ fixrepeats((short)i);
+ wall[i].picnum = wall[startwall].picnum;
+ wall[i].overpicnum = wall[startwall].overpicnum;
+
+ wall[i].nextwall = -1;
+ wall[i].nextsector = -1;
+ wall[i].point2 = i+1;
+ }
+
+ danumwalls = newnumwalls; //where to add more walls
+ m = splitendwall; //copy rest of loop next
+ do
+ {
+ memcpy(&wall[danumwalls],&wall[m],sizeof(walltype));
+ wall[danumwalls].point2 = danumwalls+1;
+ danumwalls++;
+ m = wall[m].point2;
+ } while (m != splitendwall);
+
+ //copy split points for other sector backwards
+ for(j=newnumwalls;j>numwalls;j--)
+ {
+ memcpy(&wall[danumwalls],&wall[j],sizeof(walltype));
+ wall[danumwalls].nextwall = -1;
+ wall[danumwalls].nextsector = -1;
+ wall[danumwalls].point2 = danumwalls+1;
+ danumwalls++;
+ }
+
+ m = splitstartwall; //copy rest of loop next
+ do
+ {
+ memcpy(&wall[danumwalls],&wall[m],sizeof(walltype));
+ wall[danumwalls].point2 = danumwalls+1;
+ danumwalls++;
+ m = wall[m].point2;
+ } while (m != splitstartwall);
+ wall[danumwalls-1].point2 = numwalls;
+
+ //Add other loops to sector
+ loopnum = loopnumofsector(splitsect,splitstartwall);
+ i = loopnum;
+ for(j=startwall;j<=endwall;j++)
+ {
+ k = loopnumofsector(splitsect,(short)j);
+ if ((k != i) && (k != loopnumofsector(splitsect,splitstartwall)) && (k != loopnumofsector(splitsect,splitendwall)))
+ {
+ i = k;
+ m = j; k = danumwalls; //copy loop
+ do
+ {
+ memcpy(&wall[danumwalls],&wall[m],sizeof(walltype));
+ wall[danumwalls].point2 = danumwalls+1;
+ danumwalls++;
+ m = wall[m].point2;
+ } while (m != j);
+ wall[danumwalls-1].point2 = k;
+ }
+ }
+
+ //fix all next pointers on old sector line
+ for(j=numwalls;j<danumwalls;j++)
+ {
+ if (wall[j].nextwall >= 0)
+ {
+ wall[wall[j].nextwall].nextwall = j;
+ wall[wall[j].nextwall].nextsector = numsectors;
+ }
+ }
+
+ //copy sector attributes & fix wall pointers
+ memcpy(&sector[numsectors],&sector[splitsect],sizeof(sectortype));
+ sector[numsectors].wallptr = numwalls;
+ sector[numsectors].wallnum = danumwalls-numwalls;
+
+ //fix sprites
+ j = headspritesect[splitsect];
+ while (j != -1)
+ {
+ k = nextspritesect[j];
+ changespritesect(j,numsectors);
+ j = k;
+ }
+
+ numsectors++;
+
+ //Back of number of walls of new sector for later
+ k = danumwalls-numwalls;
+
+ //clear out old sector's next pointers for clean deletesector
+ numwalls = danumwalls;
+ for(j=startwall;j<=endwall;j++)
+ {
+ wall[j].nextwall = -1;
+ wall[j].nextsector = -1;
+ }
+ deletesector(splitsect);
+
+ //Check pointers
+ for(j=numwalls-k;j<numwalls;j++)
+ {
+ if (wall[j].nextwall >= 0)
+ checksectorpointer(wall[j].nextwall,wall[j].nextsector);
+ checksectorpointer((short)j,numsectors-1);
+ }
+
+ newnumwalls = -1;
+ printmessage16("Loops joined.");
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (keystatus[0x1c] > 0) //Left Enter
+ {
+ keystatus[0x1c] = 0;
+ if (keystatus[0x2a]&keystatus[0x1d])
+ {
+ printmessage16("CHECKING ALL POINTERS!");
+ for(i=0;i<numsectors;i++)
+ {
+ startwall = sector[i].wallptr;
+ for(j=startwall;j<numwalls;j++)
+ if (wall[j].point2 < startwall) startwall = wall[j].point2;
+ sector[i].wallptr = startwall;
+ }
+ for(i=numsectors-2;i>=0;i--)
+ sector[i].wallnum = sector[i+1].wallptr-sector[i].wallptr;
+ sector[numsectors-1].wallnum = numwalls-sector[numsectors-1].wallptr;
+
+ for(i=0;i<numwalls;i++)
+ {
+ wall[i].nextsector = -1;
+ wall[i].nextwall = -1;
+ }
+ for(i=0;i<numsectors;i++)
+ {
+ startwall = sector[i].wallptr;
+ endwall = startwall + sector[i].wallnum;
+ for(j=startwall;j<endwall;j++)
+ checksectorpointer((short)j,(short)i);
+ }
+ printmessage16("ALL POINTERS CHECKED!");
+ asksave = 1;
+ }
+ else
+ {
+ if (linehighlight >= 0)
+ {
+ checksectorpointer(linehighlight,sectorofwall(linehighlight));
+ printmessage16("Highlighted line pointers checked.");
+ asksave = 1;
+ }
+ }
+ }
+
+ if ((keystatus[0x0e] > 0) && (newnumwalls >= numwalls)) //Backspace
+ {
+ if (newnumwalls > numwalls)
+ {
+ newnumwalls--;
+ asksave = 1;
+ keystatus[0x0e] = 0;
+ }
+ if (newnumwalls == numwalls)
+ {
+ newnumwalls = -1;
+ asksave = 1;
+ keystatus[0x0e] = 0;
+ }
+ }
+
+ if ((keystatus[0xd3] > 0) && (keystatus[0x9d] > 0) && (numwalls >= 0))
+ { //sector delete
+ keystatus[0xd3] = 0;
+
+ sucksect = -1;
+ for(i=0;i<numsectors;i++)
+ if (inside(mousxplc,mousyplc,i) == 1)
+ {
+ k = 0;
+ if (highlightsectorcnt >= 0)
+ for(j=0;j<highlightsectorcnt;j++)
+ if (highlightsector[j] == i)
+ {
+ for(j=highlightsectorcnt-1;j>=0;j--)
+ {
+ deletesector(highlightsector[j]);
+ for(k=j-1;k>=0;k--)
+ if (highlightsector[k] >= highlightsector[j])
+ highlightsector[k]--;
+ }
+ printmessage16("Highlighted sectors deleted.");
+ newnumwalls = -1;
+ k = 1;
+ highlightsectorcnt = -1;
+ break;
+ }
+ if (k == 0)
+ {
+ deletesector((short)i);
+ highlightsectorcnt = -1;
+ printmessage16("Sector deleted.");
+ }
+ newnumwalls = -1;
+ asksave = 1;
+ break;
+ }
+ }
+
+ if ((keystatus[0xd3] > 0) && (pointhighlight >= 0))
+ {
+ if ((pointhighlight&0xc000) == 16384) //Sprite Delete
+ {
+ deletesprite(pointhighlight&16383);
+ printmessage16("Sprite deleted.");
+ updatenumsprites();
+ asksave = 1;
+ }
+ keystatus[0xd3] = 0;
+ }
+
+ if (keystatus[0xd2] > 0) //InsertPoint
+ {
+ if (highlightsectorcnt >= 0)
+ {
+ newnumsectors = numsectors;
+ newnumwalls = numwalls;
+ for(i=0;i<highlightsectorcnt;i++)
+ {
+ copysector(highlightsector[i],newnumsectors,newnumwalls,1);
+ newnumsectors++;
+ newnumwalls += sector[highlightsector[i]].wallnum;
+ }
+
+ for(i=0;i<highlightsectorcnt;i++)
+ {
+ startwall = sector[highlightsector[i]].wallptr;
+ endwall = startwall+sector[highlightsector[i]].wallnum-1;
+ for(j=startwall;j<=endwall;j++)
+ {
+ if (wall[j].nextwall >= 0)
+ checksectorpointer(wall[j].nextwall,wall[j].nextsector);
+ checksectorpointer((short)j,highlightsector[i]);
+ }
+ highlightsector[i] = numsectors+i;
+ }
+ numsectors = newnumsectors;
+ numwalls = newnumwalls;
+
+ newnumwalls = -1;
+ newnumsectors = -1;
+
+ updatenumsprites();
+ printmessage16("Sectors duplicated and stamped.");
+ asksave = 1;
+ }
+ else if (highlightcnt >= 0)
+ {
+ for(i=0;i<highlightcnt;i++)
+ if ((highlight[i]&0xc000) == 16384)
+ {
+ //duplicate sprite
+ k = (highlight[i]&16383);
+ j = insertsprite(sprite[k].sectnum,sprite[k].statnum);
+ memcpy(&sprite[j],&sprite[k],sizeof(spritetype));
+ sprite[j].sectnum = sprite[k].sectnum; //Don't let memcpy overwrite sector!
+ setsprite(j,sprite[j].x,sprite[j].y,sprite[j].z);
+ }
+ updatenumsprites();
+ printmessage16("Sprites duplicated and stamped.");
+ asksave = 1;
+ }
+ else if (linehighlight >= 0)
+ {
+ getclosestpointonwall(mousxplc,mousyplc,(long)linehighlight,&dax,&day);
+ adjustmark(&dax,&day,newnumwalls);
+ insertpoint(linehighlight,dax,day);
+ printmessage16("Point inserted.");
+
+ j = 0;
+ //Check to see if point was inserted over another point
+ for(i=numwalls-1;i>=0;i--) //delete points
+ if (wall[i].x == wall[wall[i].point2].x)
+ if (wall[i].y == wall[wall[i].point2].y)
+ {
+ deletepoint((short)i);
+ j++;
+ }
+ for(i=0;i<numwalls;i++) //make new red lines?
+ {
+ if ((wall[i].x == dax) && (wall[i].y == day))
+ {
+ checksectorpointer((short)i,sectorofwall((short)i));
+ fixrepeats((short)i);
+ }
+ else if ((wall[wall[i].point2].x == dax) && (wall[wall[i].point2].y == day))
+ {
+ checksectorpointer((short)i,sectorofwall((short)i));
+ fixrepeats((short)i);
+ }
+ }
+ //if (j != 0)
+ //{
+ // dax = ((wall[linehighlight].x + wall[wall[linehighlight].point2].x)>>1);
+ // day = ((wall[linehighlight].y + wall[wall[linehighlight].point2].y)>>1);
+ // if ((dax != wall[linehighlight].x) || (day != wall[linehighlight].y))
+ // if ((dax != wall[wall[linehighlight].point2].x) || (day != wall[wall[linehighlight].point2].y))
+ // {
+ // insertpoint(linehighlight,dax,day);
+ // printmessage16("Point inserted at midpoint.");
+ // }
+ //}
+
+ asksave = 1;
+ }
+ keystatus[0xd2] = 0;
+ }
+
+ ExtCheckKeys();
+
+ j = 0;
+ for(i=22-1;i>=0;i--) updatecrc16(j,kensig[i]);
+ if ((j&0xffff) != 0xebf)
+ {
+ setvmode(0x3);
+ printf("Don't screw with my name.\n");
+ exit(0);
+ }
+ printext16(9L,9L,4,-1,kensig,0);
+ printext16(8L,8L,12,-1,kensig,0);
+
+ nextpage();
+ synctics = totalclock-lockclock;
+ lockclock += synctics;
+
+ if (keystatus[buildkeys[14]] > 0)
+ {
+ updatesector(posx,posy,&cursectnum);
+ if (cursectnum >= 0)
+ keystatus[buildkeys[14]] = 2;
+ else
+ printmessage16("Arrow must be inside a sector before entering 3D mode.");
+ }
+ if (keystatus[1] > 0)
+ {
+ keystatus[1] = 0;
+ printmessage16("(N)ew, (L)oad, (S)ave, save (A)s, (Q)uit");
+ bad = 1;
+ while (bad == 1)
+ {
+ if (keystatus[1] > 0)
+ {
+ keystatus[1] = 0;
+ bad = 0;
+ printmessage16("");
+ }
+ if (keystatus[0x31] > 0) //N
+ {
+ bad = 0;
+ keystatus[0x31] = 0;
+ printmessage16("Are you sure you want to start a new board?");
+ while ((keystatus[1]|keystatus[0x1c]|keystatus[0x39]|keystatus[0x31]) == 0)
+ {
+ if (keystatus[0x15] != 0)
+ {
+ keystatus[0x15] = 0;
+
+ highlightsectorcnt = -1;
+ highlightcnt = -1;
+
+ for(i=0;i<(MAXWALLS>>3);i++) //Clear all highlights
+ show2dwall[i] = 0;
+ for(i=0;i<(MAXSPRITES>>3);i++)
+ show2dsprite[i] = 0;
+
+ for(i=0;i<MAXSECTORS;i++) sector[i].extra = -1;
+ for(i=0;i<MAXWALLS;i++) wall[i].extra = -1;
+ for(i=0;i<MAXSPRITES;i++) sprite[i].extra = -1;
+
+ sectorhighlightstat = -1;
+ newnumwalls = -1;
+ joinsector[0] = -1;
+ circlewall = -1;
+ circlepoints = 7;
+
+ posx = 32768; //new board!
+ posy = 32768;
+ posz = 0;
+ ang = 1536;
+ numsectors = 0;
+ numwalls = 0;
+ cursectnum = -1;
+ initspritelists();
+ strcpy(&boardfilename,"newboard.map");
+ break;
+ }
+ }
+ printmessage16("");
+ }
+ if (keystatus[0x26] > 0) //L
+ {
+ bad = 0;
+ keystatus[0x26] = 0;
+ i = menuselect();
+ if (i < 0)
+ {
+ if (i == -2)
+ printmessage16("No .MAP files found.");
+ }
+ else
+ {
+ strcpy(&boardfilename,menuname[menuhighlight]);
+
+ if (highlightsectorcnt >= 0)
+ {
+ j = 0; k = 0;
+ for(i=0;i<highlightsectorcnt;i++)
+ {
+ j += sector[highlightsector[i]].wallnum;
+
+ m = headspritesect[highlightsector[i]];
+ while (m != -1)
+ {
+ k++;
+ m = nextspritesect[m];
+ }
+ }
+
+ updatenumsprites();
+ if ((numsectors+highlightsectorcnt > MAXSECTORS) || (numwalls+j > MAXWALLS) || (numsprites+k > MAXSPRITES))
+ {
+ highlightsectorcnt = -1;
+ }
+ else
+ {
+ //Put sectors&walls to end of lists
+ j = MAXWALLS;
+ for(i=0;i<highlightsectorcnt;i++)
+ {
+ j -= sector[highlightsector[i]].wallnum;
+ copysector(highlightsector[i],(short)(MAXSECTORS-highlightsectorcnt+i),(short)j,0);
+ }
+
+ //Put sprites to end of list
+ //DONT USE m BETWEEN HERE AND SPRITE RE-ATTACHING!
+ m = MAXSPRITES;
+ for(i=MAXSPRITES-1;i>=0;i--)
+ if (sprite[i].statnum < MAXSTATUS)
+ {
+ k = sprite[i].sectnum;
+ for(j=0;j<highlightsectorcnt;j++)
+ if (highlightsector[j] == k)
+ {
+ m--;
+ if (i != m)
+ memcpy(&sprite[m],&sprite[i],sizeof(spritetype));
+
+ //HACK - THESE 2 buffers back up .sectnum and .statnum
+ //for initspritelists() inside the loadboard call
+ tsprite[m].picnum = MAXSECTORS-highlightsectorcnt+j;
+ tsprite[m].owner = sprite[i].statnum;
+
+ break;
+ }
+ }
+ }
+ }
+
+ highlightcnt = -1;
+ sectorhighlightstat = -1;
+ newnumwalls = -1;
+ joinsector[0] = -1;
+ circlewall = -1;
+ circlepoints = 7;
+
+ for(i=0;i<MAXSECTORS;i++) sector[i].extra = -1;
+ for(i=0;i<MAXWALLS;i++) wall[i].extra = -1;
+ for(i=0;i<MAXSPRITES;i++) sprite[i].extra = -1;
+
+ if (loadboard(boardfilename,&posx,&posy,&posz,&ang,&cursectnum) == -1)
+ {
+ printmessage16("Invalid map format.");
+ }
+ else
+ {
+ ExtLoadMap(boardfilename);
+
+ if (highlightsectorcnt >= 0)
+ {
+ if ((numsectors+highlightsectorcnt > MAXSECTORS) || (sector[MAXSECTORS-highlightsectorcnt].wallptr < numwalls))
+ {
+ highlightsectorcnt = -1;
+ }
+ else
+ {
+ //Re-attach sectors&walls
+ for(i=0;i<highlightsectorcnt;i++)
+ {
+ copysector((short)(MAXSECTORS-highlightsectorcnt+i),numsectors,numwalls,0);
+ highlightsector[i] = numsectors;
+ numwalls += sector[numsectors].wallnum;
+ numsectors++;
+ }
+ //Re-attach sprites
+ while (m < MAXSPRITES)
+ {
+ //HACK - THESE 2 buffers back up .sectnum and .statnum
+ //for initspritelists() inside the loadboard call
+ //tsprite[m].picnum = sprite[i].sectnum;
+ //tsprite[m].owner = sprite[i].statnum;
+
+ j = insertsprite(tsprite[m].picnum+(numsectors-MAXSECTORS),tsprite[m].owner);
+ memcpy(&sprite[j],&sprite[m],sizeof(spritetype));
+ sprite[j].sectnum = tsprite[m].picnum+(numsectors-MAXSECTORS);
+ sprite[j].statnum = tsprite[m].owner;
+ m++;
+ }
+
+ for(i=0;i<highlightsectorcnt;i++)
+ {
+ startwall = sector[highlightsector[i]].wallptr;
+ endwall = startwall+sector[highlightsector[i]].wallnum-1;
+ for(j=startwall;j<=endwall;j++)
+ {
+ if (wall[j].nextwall >= 0)
+ checksectorpointer(wall[j].nextwall,wall[j].nextsector);
+ checksectorpointer((short)j,highlightsector[i]);
+ }
+ }
+
+ }
+ }
+
+ printmessage16("Map loaded successfully.");
+ }
+ updatenumsprites();
+ startposx = posx; //this is same
+ startposy = posy;
+ startposz = posz;
+ startang = ang;
+ startsectnum = cursectnum;
+ }
+ chdir(curpath);
+ keystatus[0x1c] = 0;
+ }
+ if (keystatus[0x1e] > 0) //A
+ {
+ bad = 0;
+ keystatus[0x1e] = 0;
+
+ strcpy(oboardfilename,boardfilename);
+
+ i = 0;
+ while ((boardfilename[i] != 0) && (i < 13))
+ i++;
+ if (boardfilename[i-4] == '.')
+ i -= 4;
+ boardfilename[i] = 0;
+
+ while (bad == 0)
+ {
+ sprintf(buffer,"Save as: %s",boardfilename);
+ printmessage16(buffer);
+
+ if (keystatus[1] > 0) bad = 1;
+ if (keystatus[0x1c] > 0) bad = 2;
+
+ if (i > 0)
+ {
+ if (keystatus[0xe] > 0)
+ {
+ keystatus[0xe] = 0;
+ i--;
+ boardfilename[i] = 0;
+ }
+ }
+ if (i < 8)
+ {
+ if ((keystatus[0x2a]|keystatus[0x36]) > 0)
+ {
+ for(j=0;j<128;j++)
+ if (scantoascwithshift[j] > 0)
+ if (keystatus[j] > 0)
+ {
+ keystatus[j] = 0;
+ boardfilename[i++] = scantoascwithshift[j];
+ boardfilename[i] = 0;
+ }
+ }
+ else
+ {
+ for(j=0;j<128;j++)
+ if (scantoasc[j] > 0)
+ if (keystatus[j] > 0)
+ {
+ keystatus[j] = 0;
+ boardfilename[i++] = scantoasc[j];
+ boardfilename[i] = 0;
+ }
+ }
+ }
+ }
+ if (bad == 1)
+ {
+ strcpy(boardfilename,oboardfilename);
+ keystatus[1] = 0;
+ printmessage16("Operation cancelled");
+ }
+ if (bad == 2)
+ {
+ keystatus[0x1c] = 0;
+
+ boardfilename[i] = '.';
+ boardfilename[i+1] = 'm';
+ boardfilename[i+2] = 'a';
+ boardfilename[i+3] = 'p';
+ boardfilename[i+4] = 0;
+
+ sprintf(buffer,"Saving to %s...",boardfilename);
+ printmessage16(buffer);
+
+ fixspritesectors(); //Do this before saving!
+ updatesector(startposx,startposy,&startsectnum);
+ saveboard(boardfilename,&startposx,&startposy,&startposz,&startang,&startsectnum);
+ ExtSaveMap(boardfilename);
+ printmessage16("Board saved.");
+ }
+ bad = 0;
+ }
+ if (keystatus[0x1f] > 0) //S
+ {
+ bad = 0;
+ keystatus[0x1f] = 0;
+ printmessage16("Saving board...");
+ fixspritesectors(); //Do this before saving!
+ updatesector(startposx,startposy,&startsectnum);
+ saveboard(boardfilename,&startposx,&startposy,&startposz,&startang,&startsectnum);
+ ExtSaveMap(boardfilename);
+ printmessage16("Board saved.");
+ }
+ if (keystatus[0x10] > 0) //Q
+ {
+ bad = 0;
+ keystatus[0x10] = 0;
+ printmessage16("Are you sure you want to quit?");
+ while ((keystatus[1]|keystatus[0x1c]|keystatus[0x39]|keystatus[0x31]) == 0)
+ {
+ if (keystatus[0x15] != 0)
+ {
+ keystatus[0x15] = 0; //QUIT!
+
+ printmessage16("Save changes?");
+ while ((keystatus[1]|keystatus[0x1c]|keystatus[0x39]|keystatus[0x31]) == 0)
+ {
+ if (keystatus[0x15] > 0)
+ {
+ keystatus[0x15] = 0;
+
+ fixspritesectors(); //Do this before saving!
+ updatesector(startposx,startposy,&startsectnum);
+ saveboard(boardfilename,&startposx,&startposy,&startposz,&startang,&startsectnum);
+ ExtSaveMap(boardfilename);
+ break;
+ }
+ }
+ uninittimer();
+ uninitkeys();
+ ExtUnInit();
+ uninitengine();
+ setvmode(0x3);
+ printf("Memory status: %ld(%ld) bytes\n",cachesize,artsize);
+ printf("%s\n",kensig);
+ exit(0);
+ }
+ }
+ printmessage16("");
+ }
+ }
+ }
+ }
+
+ for(i=0;i<highlightsectorcnt;i++)
+ {
+ startwall = sector[highlightsector[i]].wallptr;
+ endwall = startwall+sector[highlightsector[i]].wallnum-1;
+ for(j=startwall;j<=endwall;j++)
+ {
+ if (wall[j].nextwall >= 0)
+ checksectorpointer(wall[j].nextwall,wall[j].nextsector);
+ checksectorpointer((short)j,highlightsector[i]);
+ }
+ }
+
+ fixspritesectors();
+
+ if (setgamemode(vidoption,xdim,ydim) < 0)
+ {
+ ExtUnInit();
+ uninitkeys();
+ uninittimer();
+ printf("%ld * %ld not supported in this graphics mode\n",xdim,ydim);
+ exit(0);
+ }
+
+ posz = oposz;
+ searchx = scale(searchx,xdim,640);
+ searchy = scale(searchy,ydim,480);
+}
+
+getpoint(long searchxe, long searchye, long *x, long *y)
+{
+ if (posx <= -131072) posx = -131072;
+ if (posx >= 131072) posx = 131072;
+ if (posy <= -131072) posy = -131072;
+ if (posy >= 131072) posy = 131072;
+
+ *x = posx + divscale14(searchxe-320,zoom);
+ *y = posy + divscale14(searchye-200,zoom);
+
+ if (*x <= -131072) *x = -131072;
+ if (*x >= 131072) *x = 131072;
+ if (*y <= -131072) *y = -131072;
+ if (*y >= 131072) *y = 131072;
+}
+
+getlinehighlight(long xplc, long yplc)
+{
+ long i, dst, dist, closest, x1, y1, x2, y2, nx, ny;
+
+ if (numwalls == 0)
+ return(-1);
+ dist = 0x7fffffff;
+ closest = numwalls-1;
+ for(i=0;i<numwalls;i++)
+ {
+ getclosestpointonwall(xplc,yplc,i,&nx,&ny);
+ dst = klabs(xplc-nx)+klabs(yplc-ny);
+ if (dst <= dist)
+ dist = dst, closest = i;
+ }
+
+ if (wall[closest].nextwall >= 0)
+ { //if red line, allow highlighting of both sides
+ x1 = wall[closest].x;
+ y1 = wall[closest].y;
+ x2 = wall[wall[closest].point2].x;
+ y2 = wall[wall[closest].point2].y;
+ if (dmulscale32(xplc-x1,y2-y1,-(x2-x1),yplc-y1) >= 0)
+ closest = wall[closest].nextwall;
+ }
+
+ return(closest);
+}
+
+getpointhighlight(long xplc, long yplc)
+{
+ long i, dst, dist, closest;
+
+ if (numwalls == 0)
+ return(-1);
+
+ dist = 0;
+ if (grid > 0)
+ dist = 1024;
+
+ closest = -1;
+ for(i=0;i<numwalls;i++)
+ {
+ dst = klabs(xplc-wall[i].x) + klabs(yplc-wall[i].y);
+ if (dst <= dist)
+ dist = dst, closest = i;
+ }
+ for(i=0;i<MAXSPRITES;i++)
+ if (sprite[i].statnum < MAXSTATUS)
+ {
+ dst = klabs(xplc-sprite[i].x) + klabs(yplc-sprite[i].y);
+ if (dst <= dist)
+ dist = dst, closest = i+16384;
+ }
+ return(closest);
+}
+
+adjustmark(long *xplc, long *yplc, short danumwalls)
+{
+ long i, dst, dist, dax, day, pointlockdist;
+
+ if (danumwalls < 0)
+ danumwalls = numwalls;
+
+ pointlockdist = 0;
+ if ((grid > 0) && (gridlock > 0))
+ pointlockdist = (128>>grid);
+
+ dist = pointlockdist;
+ dax = *xplc;
+ day = *yplc;
+ for(i=0;i<danumwalls;i++)
+ {
+ dst = klabs((*xplc)-wall[i].x) + klabs((*yplc)-wall[i].y);
+ if (dst < dist)
+ {
+ dist = dst;
+ dax = wall[i].x;
+ day = wall[i].y;
+ }
+ }
+ if (dist == pointlockdist)
+ if ((gridlock > 0) && (grid > 0))
+ {
+ dax = ((dax+(1024>>grid))&(0xffffffff<<(11-grid)));
+ day = ((day+(1024>>grid))&(0xffffffff<<(11-grid)));
+ }
+
+ *xplc = dax;
+ *yplc = day;
+ return(0);
+}
+
+checkautoinsert(long dax, long day, short danumwalls)
+{
+ long i, x1, y1, x2, y2;
+
+ if (danumwalls < 0)
+ danumwalls = numwalls;
+ for(i=0;i<danumwalls;i++) // Check if a point should be inserted
+ {
+ x1 = wall[i].x;
+ y1 = wall[i].y;
+ x2 = wall[wall[i].point2].x;
+ y2 = wall[wall[i].point2].y;
+
+ if ((x1 != dax) || (y1 != day))
+ if ((x2 != dax) || (y2 != day))
+ if (((x1 <= dax) && (dax <= x2)) || ((x2 <= dax) && (dax <= x1)))
+ if (((y1 <= day) && (day <= y2)) || ((y2 <= day) && (day <= y1)))
+ if ((dax-x1)*(y2-y1) == (day-y1)*(x2-x1))
+ return(1); //insertpoint((short)i,dax,day);
+ }
+ return(0);
+}
+
+clockdir(short wallstart) //Returns: 0 is CW, 1 is CCW
+{
+ short i, themin;
+ long minx, templong, x0, x1, x2, y0, y1, y2;
+
+ minx = 0x7fffffff;
+ themin = -1;
+ i = wallstart-1;
+ do
+ {
+ i++;
+ if (wall[wall[i].point2].x < minx)
+ {
+ minx = wall[wall[i].point2].x;
+ themin = i;
+ }
+ }
+ while ((wall[i].point2 != wallstart) && (i < MAXWALLS));
+
+ x0 = wall[themin].x;
+ y0 = wall[themin].y;
+ x1 = wall[wall[themin].point2].x;
+ y1 = wall[wall[themin].point2].y;
+ x2 = wall[wall[wall[themin].point2].point2].x;
+ y2 = wall[wall[wall[themin].point2].point2].y;
+
+ if ((y1 >= y2) && (y1 <= y0)) return(0);
+ if ((y1 >= y0) && (y1 <= y2)) return(1);
+
+ templong = (x0-x1)*(y2-y1) - (x2-x1)*(y0-y1);
+ if (templong < 0)
+ return(0);
+ else
+ return(1);
+}
+
+flipwalls(short numwalls, short newnumwalls)
+{
+ long i, j, nume, templong;
+
+ nume = newnumwalls-numwalls;
+
+ for(i=numwalls;i<numwalls+(nume>>1);i++)
+ {
+ j = numwalls+newnumwalls-i-1;
+ templong = wall[i].x; wall[i].x = wall[j].x; wall[j].x = templong;
+ templong = wall[i].y; wall[i].y = wall[j].y; wall[j].y = templong;
+ }
+}
+
+insertpoint(short linehighlight, long dax, long day)
+{
+ short sucksect;
+ long i, j, k;
+
+ j = linehighlight;
+ sucksect = sectorofwall((short)j);
+
+ sector[sucksect].wallnum++;
+ for(i=sucksect+1;i<numsectors;i++)
+ sector[i].wallptr++;
+
+ movewalls((long)j+1,+1L);
+ memcpy(&wall[j+1],&wall[j],sizeof(walltype));
+
+ wall[j].point2 = j+1;
+ wall[j+1].x = dax;
+ wall[j+1].y = day;
+ fixrepeats((short)j);
+ fixrepeats((short)j+1);
+
+ if (wall[j].nextwall >= 0)
+ {
+ k = wall[j].nextwall;
+
+ sucksect = sectorofwall((short)k);
+
+ sector[sucksect].wallnum++;
+ for(i=sucksect+1;i<numsectors;i++)
+ sector[i].wallptr++;
+
+ movewalls((long)k+1,+1L);
+ memcpy(&wall[k+1],&wall[k],sizeof(walltype));
+
+ wall[k].point2 = k+1;
+ wall[k+1].x = dax;
+ wall[k+1].y = day;
+ fixrepeats((short)k);
+ fixrepeats((short)k+1);
+
+ j = wall[k].nextwall;
+ wall[j].nextwall = k+1;
+ wall[j+1].nextwall = k;
+ wall[k].nextwall = j+1;
+ wall[k+1].nextwall = j;
+ }
+}
+
+deletepoint(point)
+{
+ long i, j, k, sucksect;
+
+ sucksect = sectorofwall(point);
+
+ sector[sucksect].wallnum--;
+ for(i=sucksect+1;i<numsectors;i++)
+ sector[i].wallptr--;
+
+ j = lastwall(point);
+ k = wall[point].point2;
+ wall[j].point2 = k;
+
+ if (wall[j].nextwall >= 0)
+ {
+ wall[wall[j].nextwall].nextwall = -1;
+ wall[wall[j].nextwall].nextsector = -1;
+ }
+ if (wall[point].nextwall >= 0)
+ {
+ wall[wall[point].nextwall].nextwall = -1;
+ wall[wall[point].nextwall].nextsector = -1;
+ }
+ movewalls((long)point,-1L);
+
+ checksectorpointer((short)j,(short)sucksect);
+}
+
+deletesector(short sucksect)
+{
+ long i, j, k, nextk, startwall, endwall;
+
+ while (headspritesect[sucksect] >= 0)
+ deletesprite(headspritesect[sucksect]);
+ updatenumsprites();
+
+ startwall = sector[sucksect].wallptr;
+ endwall = startwall + sector[sucksect].wallnum - 1;
+ j = sector[sucksect].wallnum;
+
+ for(i=sucksect;i<numsectors-1;i++)
+ {
+ k = headspritesect[i+1];
+ while (k != -1)
+ {
+ nextk = nextspritesect[k];
+ changespritesect((short)k,(short)i);
+ k = nextk;
+ }
+
+ memcpy(&sector[i],&sector[i+1],sizeof(sectortype));
+ sector[i].wallptr -= j;
+ }
+ numsectors--;
+
+ j = endwall-startwall+1;
+ for (i=startwall;i<=endwall;i++)
+ if (wall[i].nextwall != -1)
+ {
+ wall[wall[i].nextwall].nextwall = -1;
+ wall[wall[i].nextwall].nextsector = -1;
+ }
+ movewalls(startwall,-j);
+ for(i=0;i<numwalls;i++)
+ if (wall[i].nextwall >= startwall)
+ wall[i].nextsector--;
+ return(0);
+}
+
+fixspritesectors()
+{
+ long i, j, dax, day, daz;
+
+ for(i=numsectors-1;i>=0;i--)
+ if ((sector[i].wallnum <= 0) || (sector[i].wallptr >= numwalls))
+ deletesector((short)i);
+
+ for(i=0;i<MAXSPRITES;i++)
+ if (sprite[i].statnum < MAXSTATUS)
+ {
+ dax = sprite[i].x;
+ day = sprite[i].y;
+ if (inside(dax,day,sprite[i].sectnum) != 1)
+ {
+ daz = ((tilesizy[sprite[i].picnum]*sprite[i].yrepeat)<<2);
+
+ for(j=0;j<numsectors;j++)
+ if (inside(dax,day,(short)j) == 1)
+ if (sprite[i].z >= getceilzofslope(j,dax,day))
+ if (sprite[i].z-daz <= getflorzofslope(j,dax,day))
+ {
+ changespritesect((short)i,(short)j);
+ break;
+ }
+ }
+ }
+}
+
+movewalls(long start, long offs)
+{
+ long i;
+
+ if (offs < 0) //Delete
+ {
+ for(i=start;i<numwalls+offs;i++)
+ memcpy(&wall[i],&wall[i-offs],sizeof(walltype));
+ }
+ else if (offs > 0) //Insert
+ {
+ for(i=numwalls+offs-1;i>=start+offs;i--)
+ memcpy(&wall[i],&wall[i-offs],sizeof(walltype));
+ }
+ numwalls += offs;
+ for(i=0;i<numwalls;i++)
+ {
+ if (wall[i].nextwall >= start) wall[i].nextwall += offs;
+ if (wall[i].point2 >= start) wall[i].point2 += offs;
+ }
+ return(0);
+}
+
+checksectorpointer(short i, short sectnum)
+{
+ long j, k, startwall, endwall, x1, y1, x2, y2;
+
+ x1 = wall[i].x;
+ y1 = wall[i].y;
+ x2 = wall[wall[i].point2].x;
+ y2 = wall[wall[i].point2].y;
+
+ if (wall[i].nextwall >= 0) //Check for early exit
+ {
+ k = wall[i].nextwall;
+ if ((wall[k].x == x2) && (wall[k].y == y2))
+ if ((wall[wall[k].point2].x == x1) && (wall[wall[k].point2].y == y1))
+ return(0);
+ }
+
+ wall[i].nextsector = -1;
+ wall[i].nextwall = -1;
+ for(j=0;j<numsectors;j++)
+ {
+ startwall = sector[j].wallptr;
+ endwall = startwall + sector[j].wallnum - 1;
+ for(k=startwall;k<=endwall;k++)
+ {
+ if ((wall[k].x == x2) && (wall[k].y == y2))
+ if ((wall[wall[k].point2].x == x1) && (wall[wall[k].point2].y == y1))
+ if (j != sectnum)
+ {
+ wall[i].nextsector = j;
+ wall[i].nextwall = k;
+ wall[k].nextsector = sectnum;
+ wall[k].nextwall = i;
+ }
+ }
+ }
+ return(0);
+}
+
+fixrepeats(short i)
+{
+ long dax, day, dist;
+
+ dax = wall[wall[i].point2].x-wall[i].x;
+ day = wall[wall[i].point2].y-wall[i].y;
+ dist = ksqrt(dax*dax+day*day);
+ dax = wall[i].xrepeat; day = wall[i].yrepeat;
+ wall[i].xrepeat = (char)min(max(mulscale10(dist,day),1),255);
+}
+
+clearmidstatbar16()
+{
+ long opageoffset;
+
+ opageoffset = pageoffset; //clear bottom part of status bar
+ pageoffset = 0;
+ ydim16 = 144;
+ fillscreen16((640L*25L)>>3,8L,640L*(143L-(25<<1)));
+ drawline16(0,0,0,143,7);
+ drawline16(639,0,639,143,7);
+ pageoffset = opageoffset;
+ ydim16 = 336;
+}
+
+loopinside(long x, long y, short startwall)
+{
+ long x1, y1, x2, y2, templong;
+ short i, cnt;
+
+ cnt = clockdir(startwall);
+ i = startwall;
+ do
+ {
+ x1 = wall[i].x; x2 = wall[wall[i].point2].x;
+ if ((x1 >= x) || (x2 >= x))
+ {
+ y1 = wall[i].y; y2 = wall[wall[i].point2].y;
+ if (y1 > y2)
+ {
+ templong = x1, x1 = x2, x2 = templong;
+ templong = y1, y1 = y2, y2 = templong;
+ }
+ if ((y1 <= y) && (y2 > y))
+ if (x1*(y-y2)+x2*(y1-y) <= x*(y1-y2))
+ cnt ^= 1;
+ }
+ i = wall[i].point2;
+ }
+ while (i != startwall);
+ return(cnt);
+}
+
+numloopsofsector(short sectnum)
+{
+ long i, numloops, startwall, endwall;
+
+ numloops = 0;
+ startwall = sector[sectnum].wallptr;
+ endwall = startwall + sector[sectnum].wallnum;
+ for(i=startwall;i<endwall;i++)
+ if (wall[i].point2 < i) numloops++;
+ return(numloops);
+}
+
+getnumber16(char namestart[80], short num, long maxnumber)
+{
+ char buffer[80];
+ long j, k, n, danum, oldnum;
+
+ danum = (long)num;
+ oldnum = danum;
+ while ((keystatus[0x1c] != 2) && (keystatus[0x1] == 0))
+ {
+ sprintf(&buffer,"%s%ld_ ",namestart,danum);
+ printmessage16(buffer);
+
+ for(j=2;j<=11;j++)
+ if (keystatus[j] > 0)
+ {
+ keystatus[j] = 0;
+ k = j-1;
+ if (k == 10) k = 0;
+ n = (danum*10)+k;
+ if (n < maxnumber) danum = n;
+ }
+ if (keystatus[0xe] > 0) // backspace
+ {
+ danum /= 10;
+ keystatus[0xe] = 0;
+ }
+ if (keystatus[0x1c] == 1)
+ {
+ oldnum = danum;
+ keystatus[0x1c] = 2;
+ asksave = 1;
+ }
+ }
+ keystatus[0x1c] = 0;
+ keystatus[0x1] = 0;
+ return((short)oldnum);
+}
+
+getnumber256(char namestart[80], short num, long maxnumber)
+{
+ char buffer[80];
+ long j, k, n, danum, oldnum;
+
+ danum = (long)num;
+ oldnum = danum;
+ while ((keystatus[0x1c] != 2) && (keystatus[0x1] == 0))
+ {
+ drawrooms(posx,posy,posz,ang,horiz,cursectnum);
+ ExtAnalyzeSprites();
+ drawmasks();
+
+ sprintf(&buffer,"%s%ld_ ",namestart,danum);
+ printmessage256(buffer);
+ nextpage();
+
+ for(j=2;j<=11;j++)
+ if (keystatus[j] > 0)
+ {
+ keystatus[j] = 0;
+ k = j-1;
+ if (k == 10) k = 0;
+ n = (danum*10)+k;
+ if (n < maxnumber) danum = n;
+ }
+ if (keystatus[0xe] > 0) // backspace
+ {
+ danum /= 10;
+ keystatus[0xe] = 0;
+ }
+ if (keystatus[0x1c] == 1)
+ {
+ oldnum = danum;
+ keystatus[0x1c] = 2;
+ asksave = 1;
+ }
+ }
+ keystatus[0x1c] = 0;
+ keystatus[0x1] = 0;
+
+ lockclock = totalclock; //Reset timing
+
+ return((short)oldnum);
+}
+
+initmenupaths(char *filename)
+{
+ long i;
+
+ strcpy(&curpath,filename);
+ i = 0;
+ while ((i < 80) && (curpath[i] != 0)) i++;
+ while ((i > 0) && (curpath[i] != 92)) i--;
+ curpath[i] = 0;
+ strcpy(&menupath,curpath);
+}
+
+getfilenames(char kind[6])
+{
+ short type;
+ struct find_t fileinfo;
+
+ if (strcmp(kind,"SUBD") == 0)
+ {
+ strcpy(kind,"*.*");
+ if (_dos_findfirst(kind,_A_SUBDIR,&fileinfo) != 0)
+ return(-1);
+ type = 1;
+ }
+ else
+ {
+ if (_dos_findfirst(kind,_A_NORMAL,&fileinfo) != 0)
+ return(-1);
+ type = 0;
+ }
+ do
+ {
+ if ((type == 0) || ((fileinfo.attrib&16) > 0))
+ if ((fileinfo.name[0] != '.') || (fileinfo.name[1] != 0))
+ {
+ strcpy(menuname[menunamecnt],fileinfo.name);
+ menuname[menunamecnt][16] = type;
+ menunamecnt++;
+ }
+ }
+ while (_dos_findnext(&fileinfo) == 0);
+
+ return(0);
+}
+
+sortfilenames()
+{
+ char sortbuffer[17];
+ long i, j, k;
+
+ for(i=1;i<menunamecnt;i++)
+ for(j=0;j<i;j++)
+ {
+ k = 0;
+ while ((menuname[i][k] == menuname[j][k]) && (menuname[i][k] != 0) && (menuname[j][k] != 0))
+ k++;
+ if (menuname[i][k] < menuname[j][k])
+ {
+ memcpy(&sortbuffer[0],&menuname[i][0],sizeof(menuname[0]));
+ memcpy(&menuname[i][0],&menuname[j][0],sizeof(menuname[0]));
+ memcpy(&menuname[j][0],&sortbuffer[0],sizeof(menuname[0]));
+ }
+ }
+}
+
+menuselect()
+{
+ long newhighlight, i, j, topplc;
+ char ch, buffer[42];
+
+ chdir(menupath);
+ menunamecnt = 0;
+ getfilenames("SUBD");
+ getfilenames("*.MAP");
+ sortfilenames();
+ if (menunamecnt == 0)
+ return(-2);
+
+ printmessage16("Select .MAP file with arrows&enter.");
+ fillscreen16((399360-pageoffset)>>3,0L,640L*336L);
+ if (menuhighlight < 0) menuhighlight = 0;
+ if (menuhighlight >= menunamecnt) menuhighlight = menunamecnt-1;
+
+ newhighlight = menuhighlight;
+ do
+ {
+ if (menunamecnt <= 36)
+ {
+ topplc = 0;
+ }
+ else
+ {
+ topplc = newhighlight-11;
+ if (topplc < 0) topplc = 0;
+ if (topplc > menunamecnt-37) topplc = menunamecnt-37;
+ }
+
+ for(i=0;i<menunamecnt;i++)
+ {
+ for(j=0;j<38;j++)
+ buffer[j] = 32;
+ buffer[38] = 0;
+ if (i == newhighlight)
+ {
+ buffer[0] = '-';
+ buffer[1] = '-';
+ buffer[2] = '>';
+ }
+ j = 0;
+ while (menuname[i][j] != 0)
+ {
+ buffer[j+4] = menuname[i][j];
+ j++;
+ }
+ if ((i-topplc >= 0) && (i-topplc <= 36))
+ {
+ if (menuname[i][16] == 1)
+ {
+ printext16(0L,((i-topplc)<<3)+16L+((399360-pageoffset)/640),4,0,buffer,0);
+ }
+ else
+ {
+ printext16(0L,((i-topplc)<<3)+16L+((399360-pageoffset)/640),7,0,buffer,0);
+ }
+ }
+ }
+
+ keystatus[0xcb] = 0;
+ keystatus[0xcd] = 0;
+ keystatus[0xc8] = 0;
+ keystatus[0xd0] = 0;
+ keystatus[0x1c] = 0;
+ keystatus[1] = 0;
+ ch = 0; //Interesting fakery of ch = getch()
+ while (ch == 0)
+ {
+ if (keystatus[0xcb] > 0) ch = 75;
+ if (keystatus[0xcd] > 0) ch = 77;
+ if (keystatus[0xc8] > 0) ch = 72;
+ if (keystatus[0xd0] > 0) ch = 80;
+ if (keystatus[0x1c] > 0) ch = 13;
+ if (keystatus[1] > 0) ch = 27;
+ }
+
+ if ((ch == 75) || (ch == 72))
+ {
+ newhighlight--;
+ if (newhighlight < 0)
+ newhighlight = menunamecnt-1;
+ }
+ if ((ch == 77) || (ch == 80))
+ {
+ newhighlight++;
+ if (newhighlight >= menunamecnt)
+ newhighlight = 0;
+ }
+ if ((ch == 13) && (menuname[newhighlight][16] == 1))
+ {
+ if ((menuname[newhighlight][0] == '.') && (menuname[newhighlight][1] == '.'))
+ {
+ i = 0;
+ while ((i < 80) && (menupath[i] != 0)) i++;
+ while ((i > 0) && (menupath[i] != 92)) i--;
+ menupath[i] = 0;
+ }
+ else
+ {
+ strcat(&menupath,"\\");
+ strcat(&menupath,menuname[newhighlight]);
+ }
+ chdir(menuname[newhighlight]);
+ menunamecnt = 0;
+ getfilenames("SUBD");
+ getfilenames("*.MAP");
+ sortfilenames();
+ newhighlight = 0;
+ ch = 0;
+ fillscreen16((399360-pageoffset)>>3,0L,640L*336L);
+ }
+ }
+ while ((ch != 13) && (ch != 27));
+ if (ch == 13)
+ {
+ menuhighlight = newhighlight;
+ return(newhighlight);
+ }
+ return(-1);
+}
+
+fillsector(short sectnum, char fillcolor)
+{
+ long x1, x2, y1, y2, sy, y, templong;
+ long lborder, rborder, uborder, dborder, miny, maxy, dax;
+ short z, zz, startwall, endwall, fillcnt;
+
+ lborder = 0; rborder = 640;
+ uborder = 0; dborder = ydim16;
+
+ if (sectnum == -1)
+ return(0);
+ miny = dborder-1;
+ maxy = uborder;
+ startwall = sector[sectnum].wallptr;
+ endwall = startwall + sector[sectnum].wallnum - 1;
+ for(z=startwall;z<=endwall;z++)
+ {
+ y1 = (((wall[z].y-posy)*zoom)>>14)+200;
+ y2 = (((wall[wall[z].point2].y-posy)*zoom)>>14)+200;
+ if (y1 < miny) miny = y1;
+ if (y2 < miny) miny = y2;
+ if (y1 > maxy) maxy = y1;
+ if (y2 > maxy) maxy = y2;
+ }
+ if (miny < uborder) miny = uborder;
+ if (maxy >= dborder) maxy = dborder-1;
+
+ for(sy=miny+(numframes%3);sy<=maxy;sy+=3)
+ {
+ y = posy+(((sy-200)<<14)/zoom);
+
+ fillist[0] = lborder; fillcnt = 1;
+ for(z=startwall;z<=endwall;z++)
+ {
+ x1 = wall[z].x; x2 = wall[wall[z].point2].x;
+ y1 = wall[z].y; y2 = wall[wall[z].point2].y;
+ if (y1 > y2)
+ {
+ templong = x1; x1 = x2; x2 = templong;
+ templong = y1; y1 = y2; y2 = templong;
+ }
+ if ((y1 <= y) && (y2 > y))
+ //if (x1*(y-y2) + x2*(y1-y) <= 0)
+ {
+ dax = x1+scale(y-y1,x2-x1,y2-y1);
+ dax = (((dax-posx)*zoom)>>14)+320;
+ if (dax >= lborder)
+ fillist[fillcnt++] = dax;
+ }
+ }
+ if (fillcnt > 0)
+ {
+ for(z=1;z<fillcnt;z++)
+ for (zz=0;zz<z;zz++)
+ if (fillist[z] < fillist[zz])
+ {
+ templong = fillist[z]; fillist[z] = fillist[zz]; fillist[zz] = templong;
+ }
+
+ for (z=(fillcnt&1);z<fillcnt-1;z+=2)
+ {
+ if (fillist[z] > rborder) break;
+ if (fillist[z+1] > rborder)
+ fillist[z+1] = rborder;
+ drawline16(fillist[z],sy,fillist[z+1],sy,fillcolor);
+ }
+ }
+ }
+ return(0);
+}
+
+whitelinescan(short dalinehighlight)
+{
+ long i, j, k;
+ short sucksect, newnumwalls;
+
+ sucksect = sectorofwall(dalinehighlight);
+
+ memcpy(&sector[numsectors],&sector[sucksect],sizeof(sectortype));
+ sector[numsectors].wallptr = numwalls;
+ sector[numsectors].wallnum = 0;
+ i = dalinehighlight;
+ newnumwalls = numwalls;
+ do
+ {
+ j = lastwall((short)i);
+ if (wall[j].nextwall >= 0)
+ {
+ j = wall[j].point2;
+ for(k=0;k<numwalls;k++)
+ {
+ if (wall[wall[k].point2].x == wall[j].x)
+ if (wall[wall[k].point2].y == wall[j].y)
+ if (wall[k].nextwall == -1)
+ {
+ j = k;
+ break;
+ }
+ }
+ }
+
+ memcpy(&wall[newnumwalls],&wall[i],sizeof(walltype));
+
+ wall[newnumwalls].nextwall = j;
+ wall[newnumwalls].nextsector = sectorofwall((short)j);
+
+ newnumwalls++;
+ sector[numsectors].wallnum++;
+
+ i = j;
+ }
+ while (i != dalinehighlight);
+
+ for(i=numwalls;i<newnumwalls-1;i++)
+ wall[i].point2 = i+1;
+ wall[newnumwalls-1].point2 = numwalls;
+
+ if (clockdir(numwalls) == 1)
+ return(-1);
+ else
+ return(newnumwalls);
+}
+
+#define loadbyte(fil,tempbuf,bufplc,dat) \
+{ \
+ if (bufplc == 0) \
+ { \
+ for(bufplc=0;bufplc<4096;bufplc++) \
+ tempbuf[bufplc] = 0; \
+ bufplc = 0; \
+ read(fil,tempbuf,4096); \
+ } \
+ dat = tempbuf[bufplc]; \
+ bufplc = ((bufplc+1)&4095); \
+} \
+
+loadnames()
+{
+ char buffer[80], firstch, ch;
+ long fil, i, num, buffercnt, bufplc;
+
+ if ((fil = open("names.h",O_BINARY|O_RDWR,S_IREAD)) == -1) return(-1);
+ bufplc = 0;
+ do { loadbyte(fil,tempbuf,bufplc,firstch); } while (firstch != '#');
+
+ while ((firstch == '#') || (firstch == '/'))
+ {
+ do { loadbyte(fil,tempbuf,bufplc,ch); } while (ch > 32);
+
+ buffercnt = 0;
+ do
+ {
+ loadbyte(fil,tempbuf,bufplc,ch);
+ if (ch > 32) buffer[buffercnt++] = ch;
+ }
+ while (ch > 32);
+
+ num = 0;
+ do
+ {
+ loadbyte(fil,tempbuf,bufplc,ch);
+ if ((ch >= 48) && (ch <= 57)) num = num*10+(ch-48);
+ }
+ while (ch != 13);
+ for(i=0;i<buffercnt;i++) names[num][i] = buffer[i];
+ names[num][buffercnt] = 0;
+
+ loadbyte(fil,tempbuf,bufplc,firstch);
+ if (firstch == 10) loadbyte(fil,tempbuf,bufplc,firstch);
+ }
+ close(fil);
+ return(0);
+}
+
+printcoords16(long posxe, long posye, short ange)
+{
+ char snotbuf[80];
+ long i;
+
+ sprintf(snotbuf,"x=%ld y=%ld ang=%ld",posxe,posye,ange);
+ i = 0;
+ while ((snotbuf[i] != 0) && (i < 30))
+ i++;
+ while (i < 30)
+ {
+ snotbuf[i] = 32;
+ i++;
+ }
+ snotbuf[30] = 0;
+
+ printext16(8, 128, 11, 6, snotbuf,0);
+
+ sprintf(snotbuf,"%ld/%ld sect. %ld/%ld walls %ld/%ld spri.",numsectors,MAXSECTORS,numwalls,MAXWALLS,numsprites,MAXSPRITES);
+ i = 0;
+ while ((snotbuf[i] != 0) && (i < 46))
+ i++;
+ while (i < 46)
+ {
+ snotbuf[i] = 32;
+ i++;
+ }
+ snotbuf[46] = 0;
+
+ printext16(264, 128, 14, 6, snotbuf,0);
+}
+
+updatenumsprites()
+{
+ long i;
+
+ numsprites = 0;
+ for(i=0;i<MAXSPRITES;i++)
+ if (sprite[i].statnum < MAXSTATUS)
+ numsprites++;
+}
+
+copysector(short soursector, short destsector, short deststartwall, char copystat)
+{
+ short j, k, m, newnumwalls, startwall, endwall;
+
+ newnumwalls = deststartwall; //erase existing sector fragments
+
+ //duplicate walls
+ startwall = sector[soursector].wallptr;
+ endwall = startwall + sector[soursector].wallnum;
+ for(j=startwall;j<endwall;j++)
+ {
+ memcpy(&wall[newnumwalls],&wall[j],sizeof(walltype));
+ wall[newnumwalls].point2 += deststartwall-startwall;
+ if (wall[newnumwalls].nextwall >= 0)
+ {
+ wall[newnumwalls].nextwall += deststartwall-startwall;
+ wall[newnumwalls].nextsector += destsector-soursector;
+ }
+ newnumwalls++;
+ }
+
+ //for(j=deststartwall;j<newnumwalls;j++)
+ //{
+ // if (wall[j].nextwall >= 0)
+ // checksectorpointer(wall[j].nextwall,wall[j].nextsector);
+ // checksectorpointer((short)j,destsector);
+ //}
+
+ if (newnumwalls > deststartwall)
+ {
+ //duplicate sectors
+ memcpy(&sector[destsector],&sector[soursector],sizeof(sectortype));
+ sector[destsector].wallptr = deststartwall;
+ sector[destsector].wallnum = newnumwalls-deststartwall;
+
+ if (copystat == 1)
+ {
+ //duplicate sprites
+ j = headspritesect[soursector];
+ while (j >= 0)
+ {
+ k = nextspritesect[j];
+
+ m = insertsprite(destsector,sprite[j].statnum);
+ memcpy(&sprite[m],&sprite[j],sizeof(spritetype));
+ sprite[m].sectnum = destsector; //Don't let memcpy overwrite sector!
+
+ j = k;
+ }
+ }
+
+ }
+}
+
+showsectordata(short sectnum)
+{
+ char snotbuf[80];
+
+ sprintf(snotbuf,"Sector %d",sectnum);
+ printext16(8,32,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Firstwall: %d",sector[sectnum].wallptr);
+ printext16(8,48,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Numberofwalls: %d",sector[sectnum].wallnum);
+ printext16(8,56,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Firstsprite: %d",headspritesect[sectnum]);
+ printext16(8,64,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Tags: %ld, %ld",sector[sectnum].hitag,sector[sectnum].lotag);
+ printext16(8,72,11,-1,snotbuf,0);
+ sprintf(snotbuf," (0x%x), (0x%x)",sector[sectnum].hitag,sector[sectnum].lotag);
+ printext16(8,80,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Extra: %ld",sector[sectnum].extra);
+ printext16(8,88,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Visibility: %ld",sector[sectnum].visibility);
+ printext16(8,96,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Pixel height: %ld",(sector[sectnum].floorz-sector[sectnum].ceilingz)>>8);
+ printext16(8,104,11,-1,snotbuf,0);
+
+ printext16(200,32,11,-1,"CEILINGS:",0);
+ sprintf(snotbuf,"Flags (hex): %x",sector[sectnum].ceilingstat);
+ printext16(200,48,11,-1,snotbuf,0);
+ sprintf(snotbuf,"(X,Y)pan: %d, %d",sector[sectnum].ceilingxpanning,sector[sectnum].ceilingypanning);
+ printext16(200,56,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Shade byte: %d",sector[sectnum].ceilingshade);
+ printext16(200,64,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Z-coordinate: %ld",sector[sectnum].ceilingz);
+ printext16(200,72,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Tile number: %d",sector[sectnum].ceilingpicnum);
+ printext16(200,80,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Ceiling heinum: %d",sector[sectnum].ceilingheinum);
+ printext16(200,88,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Palookup number: %d",sector[sectnum].ceilingpal);
+ printext16(200,96,11,-1,snotbuf,0);
+
+ printext16(400,32,11,-1,"FLOORS:",0);
+ sprintf(snotbuf,"Flags (hex): %x",sector[sectnum].floorstat);
+ printext16(400,48,11,-1,snotbuf,0);
+ sprintf(snotbuf,"(X,Y)pan: %d, %d",sector[sectnum].floorxpanning,sector[sectnum].floorypanning);
+ printext16(400,56,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Shade byte: %d",sector[sectnum].floorshade);
+ printext16(400,64,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Z-coordinate: %ld",sector[sectnum].floorz);
+ printext16(400,72,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Tile number: %d",sector[sectnum].floorpicnum);
+ printext16(400,80,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Floor heinum: %d",sector[sectnum].floorheinum);
+ printext16(400,88,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Palookup number: %d",sector[sectnum].floorpal);
+ printext16(400,96,11,-1,snotbuf,0);
+}
+
+showwalldata(short wallnum)
+{
+ long dax, day, dist;
+ char snotbuf[80];
+
+ sprintf(snotbuf,"Wall %d",wallnum);
+ printext16(8,32,11,-1,snotbuf,0);
+ sprintf(snotbuf,"X-coordinate: %ld",wall[wallnum].x);
+ printext16(8,48,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Y-coordinate: %ld",wall[wallnum].y);
+ printext16(8,56,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Point2: %d",wall[wallnum].point2);
+ printext16(8,64,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Sector: %d",sectorofwall(wallnum));
+ printext16(8,72,11,-1,snotbuf,0);
+
+ sprintf(snotbuf,"Tags: %ld, %ld",wall[wallnum].hitag,wall[wallnum].lotag);
+ printext16(8,88,11,-1,snotbuf,0);
+ sprintf(snotbuf," (0x%x), (0x%x)",wall[wallnum].hitag,wall[wallnum].lotag);
+ printext16(8,96,11,-1,snotbuf,0);
+
+ printext16(200,32,11,-1,names[wall[wallnum].picnum],0);
+ sprintf(snotbuf,"Flags (hex): %x",wall[wallnum].cstat);
+ printext16(200,48,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Shade: %d",wall[wallnum].shade);
+ printext16(200,56,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Pal: %d",wall[wallnum].pal);
+ printext16(200,64,11,-1,snotbuf,0);
+ sprintf(snotbuf,"(X,Y)repeat: %d, %d",wall[wallnum].xrepeat,wall[wallnum].yrepeat);
+ printext16(200,72,11,-1,snotbuf,0);
+ sprintf(snotbuf,"(X,Y)pan: %d, %d",wall[wallnum].xpanning,wall[wallnum].ypanning);
+ printext16(200,80,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Tile number: %d",wall[wallnum].picnum);
+ printext16(200,88,11,-1,snotbuf,0);
+ sprintf(snotbuf,"OverTile number: %d",wall[wallnum].overpicnum);
+ printext16(200,96,11,-1,snotbuf,0);
+
+ sprintf(snotbuf,"nextsector: %d",wall[wallnum].nextsector);
+ printext16(400,48,11,-1,snotbuf,0);
+ sprintf(snotbuf,"nextwall: %d",wall[wallnum].nextwall);
+ printext16(400,56,11,-1,snotbuf,0);
+
+ sprintf(snotbuf,"Extra: %d",wall[wallnum].extra);
+ printext16(400,72,11,-1,snotbuf,0);
+
+ dax = wall[wallnum].x-wall[wall[wallnum].point2].x;
+ day = wall[wallnum].y-wall[wall[wallnum].point2].y;
+ dist = ksqrt(dax*dax+day*day);
+ sprintf(snotbuf,"Wall length: %d",dist>>4);
+ printext16(400,96,11,-1,snotbuf,0);
+
+ dax = (long)sectorofwall(wallnum);
+ sprintf(snotbuf,"Pixel height: %ld",(sector[dax].floorz-sector[dax].ceilingz)>>8);
+ printext16(400,104,11,-1,snotbuf,0);
+}
+
+showspritedata(short spritenum)
+{
+ char snotbuf[80];
+
+ sprintf(snotbuf,"Sprite %d",spritenum);
+ printext16(8,32,11,-1,snotbuf,0);
+ sprintf(snotbuf,"X-coordinate: %ld",sprite[spritenum].x);
+ printext16(8,48,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Y-coordinate: %ld",sprite[spritenum].y);
+ printext16(8,56,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Z-coordinate: %ld",sprite[spritenum].z);
+ printext16(8,64,11,-1,snotbuf,0);
+
+ sprintf(snotbuf,"Sectnum: %d",sprite[spritenum].sectnum);
+ printext16(8,72,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Statnum: %d",sprite[spritenum].statnum);
+ printext16(8,80,11,-1,snotbuf,0);
+
+ sprintf(snotbuf,"Tags: %ld, %ld",sprite[spritenum].hitag,sprite[spritenum].lotag);
+ printext16(8,96,11,-1,snotbuf,0);
+ sprintf(snotbuf," (0x%x), (0x%x)",sprite[spritenum].hitag,sprite[spritenum].lotag);
+ printext16(8,104,11,-1,snotbuf,0);
+
+ printext16(200,32,11,-1,names[sprite[spritenum].picnum],0);
+ sprintf(snotbuf,"Flags (hex): %x",sprite[spritenum].cstat);
+ printext16(200,48,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Shade: %d",sprite[spritenum].shade);
+ printext16(200,56,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Pal: %d",sprite[spritenum].pal);
+ printext16(200,64,11,-1,snotbuf,0);
+ sprintf(snotbuf,"(X,Y)repeat: %d, %d",sprite[spritenum].xrepeat,sprite[spritenum].yrepeat);
+ printext16(200,72,11,-1,snotbuf,0);
+ sprintf(snotbuf,"(X,Y)offset: %d, %d",sprite[spritenum].xoffset,sprite[spritenum].yoffset);
+ printext16(200,80,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Tile number: %d",sprite[spritenum].picnum);
+ printext16(200,88,11,-1,snotbuf,0);
+
+ sprintf(snotbuf,"Angle (2048 degrees): %d",sprite[spritenum].ang);
+ printext16(400,48,11,-1,snotbuf,0);
+ sprintf(snotbuf,"X-Velocity: %d",sprite[spritenum].xvel);
+ printext16(400,56,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Y-Velocity: %d",sprite[spritenum].yvel);
+ printext16(400,64,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Z-Velocity: %d",sprite[spritenum].zvel);
+ printext16(400,72,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Owner: %d",sprite[spritenum].owner);
+ printext16(400,80,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Clipdist: %d",sprite[spritenum].clipdist);
+ printext16(400,88,11,-1,snotbuf,0);
+ sprintf(snotbuf,"Extra: %d",sprite[spritenum].extra);
+ printext16(400,96,11,-1,snotbuf,0);
+}
+
+inittimer()
+{
+ outp(0x43,0x34); outp(0x40,(1193181/120)&255); outp(0x40,(1193181/120)>>8);
+ oldtimerhandler = _dos_getvect(0x8);
+ _disable(); _dos_setvect(0x8, timerhandler); _enable();
+}
+
+uninittimer()
+{
+ outp(0x43,0x34); outp(0x40,0); outp(0x40,0); //18.2 times/sec
+ _disable(); _dos_setvect(0x8, oldtimerhandler); _enable();
+}
+
+void __interrupt __far timerhandler()
+{
+ totalclock++;
+ keytimerstuff();
+ outp(0x20,0x20);
+}
+
+initkeys()
+{
+ long i;
+
+ keyfifoplc = 0; keyfifoend = 0;
+ for(i=0;i<256;i++) keystatus[i] = 0;
+ oldkeyhandler = _dos_getvect(0x9);
+ _disable(); _dos_setvect(0x9, keyhandler); _enable();
+}
+
+uninitkeys()
+{
+ short *ptr;
+
+ _dos_setvect(0x9, oldkeyhandler);
+ //Turn off shifts to prevent stucks with quitting
+ ptr = (short *)0x417; *ptr &= ~0x030f;
+}
+
+void __interrupt __far keyhandler()
+{
+ oldreadch = readch; readch = kinp(0x60);
+ keytemp = kinp(0x61); koutp(0x61,keytemp|128); koutp(0x61,keytemp&127);
+ koutp(0x20,0x20);
+ if ((readch|1) == 0xe1) { extended = 128; return; }
+ if (oldreadch != readch)
+ {
+ if ((readch&128) == 0)
+ {
+ keytemp = readch+extended;
+ if (keystatus[keytemp] == 0)
+ {
+ keystatus[keytemp] = 1;
+ keyfifo[keyfifoend] = keytemp;
+ keyfifo[(keyfifoend+1)&(KEYFIFOSIZ-1)] = 1;
+ keyfifoend = ((keyfifoend+2)&(KEYFIFOSIZ-1));
+ }
+ }
+ else
+ {
+ keytemp = (readch&127)+extended;
+ keystatus[keytemp] = 0;
+ keyfifo[keyfifoend] = keytemp;
+ keyfifo[(keyfifoend+1)&(KEYFIFOSIZ-1)] = 0;
+ keyfifoend = ((keyfifoend+2)&(KEYFIFOSIZ-1));
+ }
+ }
+ extended = 0;
+}
+
+keytimerstuff()
+{
+ if (keystatus[buildkeys[5]] == 0)
+ {
+ if (keystatus[buildkeys[2]] > 0) angvel = max(angvel-16,-128);
+ if (keystatus[buildkeys[3]] > 0) angvel = min(angvel+16,127);
+ }
+ else
+ {
+ if (keystatus[buildkeys[2]] > 0) svel = min(svel+8,127);
+ if (keystatus[buildkeys[3]] > 0) svel = max(svel-8,-128);
+ }
+ if (keystatus[buildkeys[0]] > 0) vel = min(vel+8,127);
+ if (keystatus[buildkeys[1]] > 0) vel = max(vel-8,-128);
+ if (keystatus[buildkeys[12]] > 0) svel = min(svel+8,127);
+ if (keystatus[buildkeys[13]] > 0) svel = max(svel-8,-128);
+
+ if (angvel < 0) angvel = min(angvel+12,0);
+ if (angvel > 0) angvel = max(angvel-12,0);
+ if (svel < 0) svel = min(svel+2,0);
+ if (svel > 0) svel = max(svel-2,0);
+ if (vel < 0) vel = min(vel+2,0);
+ if (vel > 0) vel = max(vel-2,0);
+}
+
+printmessage16(char name[82])
+{
+ char snotbuf[60];
+ long i;
+
+ i = 0;
+ while ((name[i] != 0) && (i < 54))
+ {
+ snotbuf[i] = name[i];
+ i++;
+ }
+ while (i < 54)
+ {
+ snotbuf[i] = 32;
+ i++;
+ }
+ snotbuf[54] = 0;
+
+ printext16(200L, 8L, 0, 6, snotbuf, 0);
+}
+
+printmessage256(char name[82])
+{
+ char snotbuf[40];
+ long i;
+
+ i = 0;
+ while ((name[i] != 0) && (i < 38))
+ {
+ snotbuf[i] = name[i];
+ i++;
+ }
+ while (i < 38)
+ {
+ snotbuf[i] = 32;
+ i++;
+ }
+ snotbuf[38] = 0;
+
+ printext256(0L,0L,whitecol,0,snotbuf,0);
+}
+
+ //Find closest point (*dax, *day) on wall (dawall) to (x, y)
+getclosestpointonwall(long x, long y, long dawall, long *nx, long *ny)
+{
+ walltype *wal;
+ long i, j, dx, dy;
+
+ wal = &wall[dawall];
+ dx = wall[wal->point2].x-wal->x;
+ dy = wall[wal->point2].y-wal->y;
+ i = dx*(x-wal->x) + dy*(y-wal->y);
+ if (i <= 0) { *nx = wal->x; *ny = wal->y; return; }
+ j = dx*dx+dy*dy;
+ if (i >= j) { *nx = wal->x+dx; *ny = wal->y+dy; return; }
+ i = divscale30(i,j);
+ *nx = wal->x + mulscale30(dx,i);
+ *ny = wal->y + mulscale30(dy,i);
+}
+
+initcrc()
+{
+ long i, j, k, a;
+
+ for(j=0;j<256;j++) //Calculate CRC table
+ {
+ k = (j<<8); a = 0;
+ for(i=7;i>=0;i--)
+ {
+ if (((k^a)&0x8000) > 0)
+ a = ((a<<1)&65535) ^ 0x1021; //0x1021 = genpoly
+ else
+ a = ((a<<1)&65535);
+ k = ((k<<1)&65535);
+ }
+ crctable[j] = (a&65535);
+ }
+}
+
+static char visited[8192];
+
+GetWallZPeg(long nWall)
+{
+ long z, nSector, nNextSector;
+
+ nSector = sectorofwall((short)nWall);
+ nNextSector = wall[nWall].nextsector;
+ if (nNextSector == -1)
+ {
+ //1-sided wall
+ if (wall[nWall].cstat&4) z = sector[nSector].floorz;
+ else z = sector[nSector].ceilingz;
+ }
+ else
+ {
+ //2-sided wall
+ if (wall[nWall].cstat&4)
+ z = sector[nSector].ceilingz;
+ else
+ {
+ if (sector[nNextSector].ceilingz > sector[nSector].ceilingz)
+ z = sector[nNextSector].ceilingz; //top step
+ if (sector[nNextSector].floorz < sector[nSector].floorz)
+ z = sector[nNextSector].floorz; //bottom step
+ }
+ }
+ return(z);
+}
+
+AlignWalls(long nWall0, long z0, long nWall1, long z1, long nTile)
+{
+ long n;
+
+ //do the x alignment
+ wall[nWall1].cstat &= ~0x0108; //Set to non-flip
+ wall[nWall1].xpanning = (char)((wall[nWall0].xpanning+(wall[nWall0].xrepeat<<3))%tilesizx[nTile]);
+
+ z1 = GetWallZPeg(nWall1);
+
+ for(n=(picsiz[nTile]>>4);((1<<n)<tilesizy[nTile]);n++);
+
+ wall[nWall1].yrepeat = wall[nWall0].yrepeat;
+ wall[nWall1].ypanning = (char)(wall[nWall0].ypanning+(((z1-z0)*wall[nWall0].yrepeat)>>(n+3)));
+}
+
+AutoAlignWalls(long nWall0, long ply)
+{
+ long z0, z1, nTile, nWall1, branch, visible, nNextSector, nSector;
+
+ nTile = wall[nWall0].picnum;
+ branch = 0;
+ if (ply == 0)
+ {
+ //clear visited bits
+ memset(visited,0,sizeof(visited));
+ visited[nWall0] = 1;
+ }
+
+ z0 = GetWallZPeg(nWall0);
+
+ nWall1 = wall[nWall0].point2;
+
+ //loop through walls at this vertex in CCW order
+ while (1)
+ {
+ //break if this wall would connect us in a loop
+ if (visited[nWall1]) break;
+
+ visited[nWall1] = 1;
+
+ //break if reached back of left wall
+ if (wall[nWall1].nextwall == nWall0) break;
+
+ if (wall[nWall1].picnum == nTile)
+ {
+ z1 = GetWallZPeg(nWall1);
+ visible = 0;
+
+ nNextSector = wall[nWall1].nextsector;
+ if (nNextSector < 0)
+ visible = 1;
+ else
+ {
+ //ignore two sided walls that have no visible face
+ nSector = wall[wall[nWall1].nextwall].nextsector;
+ if (getceilzofslope((short)nSector,wall[nWall1].x,wall[nWall1].y) <
+ getceilzofslope((short)nNextSector,wall[nWall1].x,wall[nWall1].y))
+ visible = 1;
+
+ if (getflorzofslope((short)nSector,wall[nWall1].x,wall[nWall1].y) >
+ getflorzofslope((short)nNextSector,wall[nWall1].x,wall[nWall1].y))
+ visible = 1;
+ }
+
+ if (visible)
+ {
+ branch++;
+ AlignWalls(nWall0,z0,nWall1,z1,nTile);
+
+ //if wall was 1-sided, no need to recurse
+ if (wall[nWall1].nextwall < 0)
+ {
+ nWall0 = nWall1;
+ z0 = GetWallZPeg(nWall0);
+ nWall1 = wall[nWall0].point2;
+ branch = 0;
+ continue;
+ }
+ else
+ AutoAlignWalls(nWall1,ply+1);
+ }
+ }
+
+ if (wall[nWall1].nextwall < 0) break;
+ nWall1 = wall[wall[nWall1].nextwall].point2;
+ }
+}
diff --git a/SRC/BUILD.H b/SRC/BUILD.H
new file mode 100644
index 0000000..d5e965d
--- /dev/null
+++ b/SRC/BUILD.H
@@ -0,0 +1,278 @@
+// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
+// Ken Silverman's official web site: "http://www.advsys.net/ken"
+// See the included license file "BUILDLIC.TXT" for license info.
+
+#define MAXSECTORS 1024
+#define MAXWALLS 8192
+#define MAXSPRITES 4096
+
+#define MAXTILES 9216
+#define MAXSTATUS 1024
+#define MAXPLAYERS 16
+#define MAXXDIM 1600
+#define MAXYDIM 1200
+#define MAXPALOOKUPS 256
+#define MAXPSKYTILES 256
+#define MAXSPRITESONSCREEN 1024
+
+#define CLIPMASK0 (((1L)<<16)+1L)
+#define CLIPMASK1 (((256L)<<16)+64L)
+
+ //Make all variables in BUILD.H defined in the ENGINE,
+ //and externed in GAME
+#ifdef ENGINE
+ #define EXTERN
+#else
+ #define EXTERN extern
+#endif
+
+#pragma pack(push,1);
+
+//ceilingstat/floorstat:
+// bit 0: 1 = parallaxing, 0 = not "P"
+// bit 1: 1 = groudraw, 0 = not
+// bit 2: 1 = swap x&y, 0 = not "F"
+// bit 3: 1 = double smooshiness "E"
+// bit 4: 1 = x-flip "F"
+// bit 5: 1 = y-flip "F"
+// bit 6: 1 = Align texture to first wall of sector "R"
+// bits 7-8: "T"
+// 00 = normal floors
+// 01 = masked floors
+// 10 = transluscent masked floors
+// 11 = reverse transluscent masked floors
+// bits 9-15: reserved
+
+ //40 bytes
+typedef struct
+{
+ short wallptr, wallnum;
+ long ceilingz, floorz;
+ short ceilingstat, floorstat;
+ short ceilingpicnum, ceilingheinum;
+ signed char ceilingshade;
+ char ceilingpal, ceilingxpanning, ceilingypanning;
+ short floorpicnum, floorheinum;
+ signed char floorshade;
+ char floorpal, floorxpanning, floorypanning;
+ char visibility, filler;
+ short lotag, hitag, extra;
+} sectortype;
+
+//cstat:
+// bit 0: 1 = Blocking wall (use with clipmove, getzrange) "B"
+// bit 1: 1 = bottoms of invisible walls swapped, 0 = not "2"
+// bit 2: 1 = align picture on bottom (for doors), 0 = top "O"
+// bit 3: 1 = x-flipped, 0 = normal "F"
+// bit 4: 1 = masking wall, 0 = not "M"
+// bit 5: 1 = 1-way wall, 0 = not "1"
+// bit 6: 1 = Blocking wall (use with hitscan / cliptype 1) "H"
+// bit 7: 1 = Transluscence, 0 = not "T"
+// bit 8: 1 = y-flipped, 0 = normal "F"
+// bit 9: 1 = Transluscence reversing, 0 = normal "T"
+// bits 10-15: reserved
+
+ //32 bytes
+typedef struct
+{
+ long x, y;
+ short point2, nextwall, nextsector, cstat;
+ short picnum, overpicnum;
+ signed char shade;
+ char pal, xrepeat, yrepeat, xpanning, ypanning;
+ short lotag, hitag, extra;
+} walltype;
+
+//cstat:
+// bit 0: 1 = Blocking sprite (use with clipmove, getzrange) "B"
+// bit 1: 1 = transluscence, 0 = normal "T"
+// bit 2: 1 = x-flipped, 0 = normal "F"
+// bit 3: 1 = y-flipped, 0 = normal "F"
+// bits 5-4: 00 = FACE sprite (default) "R"
+// 01 = WALL sprite (like masked walls)
+// 10 = FLOOR sprite (parallel to ceilings&floors)
+// bit 6: 1 = 1-sided sprite, 0 = normal "1"
+// bit 7: 1 = Real centered centering, 0 = foot center "C"
+// bit 8: 1 = Blocking sprite (use with hitscan / cliptype 1) "H"
+// bit 9: 1 = Transluscence reversing, 0 = normal "T"
+// bits 10-14: reserved
+// bit 15: 1 = Invisible sprite, 0 = not invisible
+
+ //44 bytes
+typedef struct
+{
+ long x, y, z;
+ short cstat, picnum;
+ signed char shade;
+ char pal, clipdist, filler;
+ unsigned char xrepeat, yrepeat;
+ signed char xoffset, yoffset;
+ short sectnum, statnum;
+ short ang, owner, xvel, yvel, zvel;
+ short lotag, hitag, extra;
+} spritetype;
+
+#pragma pack(pop);
+
+EXTERN sectortype sector[MAXSECTORS];
+EXTERN walltype wall[MAXWALLS];
+EXTERN spritetype sprite[MAXSPRITES];
+
+EXTERN long spritesortcnt;
+EXTERN spritetype tsprite[MAXSPRITESONSCREEN];
+
+EXTERN char vidoption;
+EXTERN long xdim, ydim, ylookup[MAXYDIM+1], numpages;
+EXTERN long yxaspect, viewingrange;
+
+EXTERN long validmodecnt;
+EXTERN short validmode[256];
+EXTERN long validmodexdim[256], validmodeydim[256];
+
+EXTERN short numsectors, numwalls;
+EXTERN volatile long totalclock;
+EXTERN long numframes, randomseed;
+EXTERN short sintable[2048];
+EXTERN char palette[768];
+EXTERN short numpalookups;
+EXTERN char *palookup[MAXPALOOKUPS];
+EXTERN char parallaxtype, showinvisibility;
+EXTERN long parallaxyoffs, parallaxyscale;
+EXTERN long visibility, parallaxvisibility;
+
+EXTERN long windowx1, windowy1, windowx2, windowy2;
+EXTERN short startumost[MAXXDIM], startdmost[MAXXDIM];
+
+EXTERN short pskyoff[MAXPSKYTILES], pskybits;
+
+EXTERN short headspritesect[MAXSECTORS+1], headspritestat[MAXSTATUS+1];
+EXTERN short prevspritesect[MAXSPRITES], prevspritestat[MAXSPRITES];
+EXTERN short nextspritesect[MAXSPRITES], nextspritestat[MAXSPRITES];
+
+EXTERN short tilesizx[MAXTILES], tilesizy[MAXTILES];
+EXTERN char walock[MAXTILES];
+EXTERN long numtiles, picanm[MAXTILES], waloff[MAXTILES];
+
+ //These variables are for auto-mapping with the draw2dscreen function.
+ //When you load a new board, these bits are all set to 0 - since
+ //you haven't mapped out anything yet. Note that these arrays are
+ //bit-mapped.
+ //If you want draw2dscreen() to show sprite #54 then you say:
+ // spritenum = 54;
+ // show2dsprite[spritenum>>3] |= (1<<(spritenum&7));
+ //And if you want draw2dscreen() to not show sprite #54 then you say:
+ // spritenum = 54;
+ // show2dsprite[spritenum>>3] &= ~(1<<(spritenum&7));
+ //Automapping defaults to 0 (do nothing). If you set automapping to 1,
+ // then in 3D mode, the walls and sprites that you see will show up the
+ // next time you flip to 2D mode.
+
+EXTERN char show2dsector[(MAXSECTORS+7)>>3];
+EXTERN char show2dwall[(MAXWALLS+7)>>3];
+EXTERN char show2dsprite[(MAXSPRITES+7)>>3];
+EXTERN char automapping;
+
+EXTERN char gotpic[(MAXTILES+7)>>3];
+EXTERN char gotsector[(MAXSECTORS+7)>>3];
+
+/*************************************************************************
+POSITION VARIABLES:
+
+ POSX is your x - position ranging from 0 to 65535
+ POSY is your y - position ranging from 0 to 65535
+ (the length of a side of the grid in EDITBORD would be 1024)
+ POSZ is your z - position (height) ranging from 0 to 65535, 0 highest.
+ ANG is your angle ranging from 0 to 2047. Instead of 360 degrees, or
+ 2 * PI radians, I use 2048 different angles, so 90 degrees would
+ be 512 in my system.
+
+SPRITE VARIABLES:
+
+ EXTERN short headspritesect[MAXSECTORS+1], headspritestat[MAXSTATUS+1];
+ EXTERN short prevspritesect[MAXSPRITES], prevspritestat[MAXSPRITES];
+ EXTERN short nextspritesect[MAXSPRITES], nextspritestat[MAXSPRITES];
+
+ Example: if the linked lists look like the following:
+ 旼컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴커
+ Sector lists: Status lists:
+ 쳐컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴캑
+ Sector0: 4, 5, 8 Status0: 2, 0, 8
+ Sector1: 16, 2, 0, 7 Status1: 4, 5, 16, 7, 3, 9
+ Sector2: 3, 9
+ 읕컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴켸
+ Notice that each number listed above is shown exactly once on both the
+ left and right side. This is because any sprite that exists must
+ be in some sector, and must have some kind of status that you define.
+
+
+Coding example #1:
+ To go through all the sprites in sector 1, the code can look like this:
+
+ sectnum = 1;
+ i = headspritesect[sectnum];
+ while (i != -1)
+ {
+ nexti = nextspritesect[i];
+
+ //your code goes here
+ //ex: printf("Sprite %d is in sector %d\n",i,sectnum);
+
+ i = nexti;
+ }
+
+Coding example #2:
+ To go through all sprites with status = 1, the code can look like this:
+
+ statnum = 1; //status 1
+ i = headspritestat[statnum];
+ while (i != -1)
+ {
+ nexti = nextspritestat[i];
+
+ //your code goes here
+ //ex: printf("Sprite %d has a status of 1 (active)\n",i,statnum);
+
+ i = nexti;
+ }
+
+ insertsprite(short sectnum, short statnum);
+ deletesprite(short spritenum);
+ changespritesect(short spritenum, short newsectnum);
+ changespritestat(short spritenum, short newstatnum);
+
+TILE VARIABLES:
+ NUMTILES - the number of tiles found TILES.DAT.
+ TILESIZX[MAXTILES] - simply the x-dimension of the tile number.
+ TILESIZY[MAXTILES] - simply the y-dimension of the tile number.
+ WALOFF[MAXTILES] - the actual 32-bit offset pointing to the top-left
+ corner of the tile.
+ PICANM[MAXTILES] - flags for animating the tile.
+
+TIMING VARIABLES:
+ TOTALCLOCK - When the engine is initialized, TOTALCLOCK is set to zero.
+ From then on, it is incremented 120 times a second by 1. That
+ means that the number of seconds elapsed is totalclock / 120.
+ NUMFRAMES - The number of times the draw3dscreen function was called
+ since the engine was initialized. This helps to determine frame
+ rate. (Frame rate = numframes * 120 / totalclock.)
+
+OTHER VARIABLES:
+
+ STARTUMOST[320] is an array of the highest y-coordinates on each column
+ that my engine is allowed to write to. You need to set it only
+ once.
+ STARTDMOST[320] is an array of the lowest y-coordinates on each column
+ that my engine is allowed to write to. You need to set it only
+ once.
+ SINTABLE[2048] is a sin table with 2048 angles rather than the
+ normal 360 angles for higher precision. Also since SINTABLE is in
+ all integers, the range is multiplied by 16383, so instead of the
+ normal -1<sin(x)<1, the range of sintable is -16383<sintable[]<16383
+ If you use this sintable, you can possibly speed up your code as
+ well as save space in memory. If you plan to use sintable, 2
+ identities you may want to keep in mind are:
+ sintable[ang&2047] = sin(ang * (3.141592/1024)) * 16383
+ sintable[(ang+512)&2047] = cos(ang * (3.141592/1024)) * 16383
+ NUMSECTORS - the total number of existing sectors. Modified every time
+ you call the loadboard function.
+***************************************************************************/
diff --git a/SRC/BUILD.TXT b/SRC/BUILD.TXT
new file mode 100644
index 0000000..657786b
--- /dev/null
+++ b/SRC/BUILD.TXT
@@ -0,0 +1,5081 @@
+// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
+// Ken Silverman's official web site: "http://www.advsys.net/ken"
+// See the included license file "BUILDLIC.TXT" for license info.
+
+BUILD engine Notes (8/14/95):
+
+BUILD programmed by Ken Silverman
+
+旼컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+ GAME KEYS:
+읕컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+ ESC = Quit
+ Mouse = Movement
+ Arrows = Movement
+ Lt. Enter = Single-player: Play back game.
+ Multi-player: View from other player's eyes.
+ Rt. Enter = Switch between 3D / 2D modes
+ Lt. +/- = Zoom in 2D mode
+ A/Z = Move up and down
+ Left-Ctrl = Shoot
+ 1/2 = Select weapon
+Left-Shift = Run
+ T = Reset Timing (sets totalclock = 0)
+ V = Change visibility. In BUILD.H there is a visiblity variable.
+ It is initialized to 13. It can range from around 8 (darker)
+ to about 15 (lighter).
+ P = Change parallaxing sky mode. (0, 1, and 2 (Default = 2)
+ F12 = Screen capture (saves image as a *.BMP file, starting as file
+ name CAPTUR00.BMP and incrementing by 1 each time F12 is
+ pressed.
+
+旼컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+ BUILD EDITOR INTRODUCTION:
+읕컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+
+There are 2 modes in the BUILD editor:
+ 3D EDIT MODE (Same as PLAY MODE but with a mouse cursor)
+ 2D EDIT MODE (The overhead map of the board with an arrow showing your
+ position and angle and a mouse cursor)
+
+It is essential that you use both editor modes:
+
+ Use the 3D EDIT MODE to change the attributes of a sector, wall, or sprite
+ such as:
+
+ Tile number - Tells which picture in the artwork file goes on the
+ object. Press V to change.
+ Shade - The shade of the object. Press -/+ to change.
+ Repeating - The "smooshiness" of a wall. Also for sprites. Press
+ keypad 2,4,6,8 to change.
+ Panning - The starting offset into the tile graphics. Press
+ Shift + keypad 2,4,6,8 to change.
+ Height - For ceilings, floors, and sprites. Press PGUP or PGDN
+ to change.
+ and there are a few other special attributes.
+
+ Use the 2D EDIT MODE to add, delete, or change the shape of sectors.
+
+ To switch between the two EDIT MODES, press the keypad enter key.
+
+旼컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+ 3D EDIT MODE KEYS:
+읕컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+ ESC = Quit
+keypad ENTER = Flip to the 2D overhead editor
+
+ Mouse = Move mouse cursor
+ Arrows = Move you in the appropriate directions
+ Caps Lock = There are 3 different Z coordinate modes in BUILD.
+ Mode 0: Game mode (default)
+ Mode 1: Height lock mode
+ Mode 2: Float mode
+ Press Caps Lock to switch between the 3 modes.
+ A and Z move up and down for all 3 modes.
+
+
+Note: For the following keys, it is important to move the mouse cursor to
+the right position before using them. Also, if you hold down the first mouse
+button, then the item under the mouse cursor will be locked as the
+highlighted object while the button is held down. This is useful for the
+PGUP/DN keys, when different objects come into view even without moving your
+coordinates or the mouse cursor.
+ There are 4 basic types of objects that can be worked with in this part
+of the editor: WALLS, CEILINGS, FLOORS, and SPRITES.
+
+ PGUP/DN = Raise or Lower a ceiling or floor. (If a wall is selected,
+ the ceiling of that sector will move) Also, if you did a
+ sector highlight in 2D EDIT MODE, you can raise / lower
+ multiple sectors at a time.
+Ctrl-PGUP/DN = For sprites only, puts sprites exactly on the floor or exactly
+ on the ceiling.
+
+ V = Tile selection - use arrow keys to move around. Press ENTER
+ to change the object to the highlighted piece of artwork, or
+ press ESC to cancel without changes made.
+ ALT-V = Height selection - works just like V, but this selects the
+ groudraw height map.
+
+2,4,6,8 (keypad) = Repeat values (smooshiness of the sizes of pixels) -
+ think of these keys as arrow keys controlling the bottom
+ right corner of the bitmap. Normally, this is used for walls
+ and sprites. If you select a floor or ceiling, all the walls
+ in that sector will be affected. Perhaps this can be used
+ to make sprites grow and shrink as they get healthy or hurt.
+Shift +
+2,4,6,8 (keypad) = Panning values (offset into the tile) - These keys are
+ useful when the you want a long wall to look continuous when
+ they normally would not look continuous.
+ / = Use this key to reset the panning values (if you're lost!)
+ 5 (keypad) = If you hold down this key down in addition to the 2,4,6,8
+ keys (keypad),the values will align at multiples of 8.
+ .> = This key attempts to match up all the tiles along a wall. It
+ scans along the walls towards the right as long as the picture
+ number of the next wall is the same as the original picture
+ number. Note that some walls may not work right, especially
+ floor / ceiling steps.
+
+ F = Flip an object. For sprites and walls, this flips the object
+ x-wise. For ceilings and floors, the objects are flipped in
+ 8 possible ways. Just keep pressing 'F' to go through
+ the 8 ways.
+ ALT-F = When you use relative alignment mode on ceiling and floor
+ textures, you can press Alt-F on the ceiling or floor to
+ choose a new wall to align to. It actually rotates the walls
+ of a sector by 1.
+ O = Wall orientation (whether it starts from the top or bottom)
+ Normally, walls are oriented from the top. For example, if
+ you hold down 2/8 on the keypad in 3D EDIT MODE, the wall
+ always starts from the top. Orientation works differently
+ for white lines and red lines, so if a wall doesn't look
+ right, just press 'O' anyway to see if it get fixed.
+
+COPY & PASTE
+ TAB = COPY. Copy the attibutes of the highlighted objects into a
+ temporary place. The attributes it remembers are:
+ tile, shade, x-repeat, y-repeat, and cstat values.
+ Left ENTER = PASTE. Paste the stored attributes over the highlighted
+ object. Whenever you press ENTER, the y-repeat values stay
+ the same, and the x-repeat values are adjusted so the pixels
+ of the bitmaps have a square-aspect ratio.
+Ctrl+L.ENTER = Left ENTER with the ctrl key will paste the attribtues to
+ every wall in a loop (if a wall is highlighted).
+Shft+L.ENTER = Left ENTER with the shift key also pressed copies the shade
+ only.
+Ctrl+Shft+L.ENTER = Auto-shade a sector. First make any wall of the loop
+ as light as the lightest shade you want. Then make any other
+ wall of the loop as dark as the darkest shade you want.
+ Finally press Ctrl-Shift Enter on the wall that should be
+ lightest. Now the loop should be smoothly shaded. If it
+ is not smoothly shaded, you may need to insert more points
+ on the walls.
+
+SECTOR FLAGS:
+
+ P = Make the ceiling of the given sector have a Parallaxing sky
+ or just a normal ceiling.
+ G = Make the floor of the given sector have a Groudraw
+ (floor with height mapping). I do not recommend using this
+ attribute very extensively yet. (See the H key for selecting
+ the height map)
+ E = An option for ceilings and floors. If for some reason, you
+ want a tile to be smooshed into the normal 64*64 area, press
+ E to unExpand the tile. Press E again, and the tile will be
+ expanded, so the pixel size is the same as the normal 64*64
+ ceiling/floor.
+ R = Relative alignment - switch between relative alignment mode
+ and normal mode. Allows floor / ceiling textures to align
+ to the first 2 points of a sector. Textures will rotate/pan
+ with moving sectors properly. Notice that bit 6 of both
+ sector[].ceilingstat and sector[].floorstat are relative
+ alignment bits.
+
+WALL FLAGS:
+
+ B = Make an invisible wall, such as a window, block you from
+ going through. Since the wall is invisible, you can also
+ highlight the ceiling right above the window or floor
+ right below the window. You can block either the front or
+ the back of the window. If you block the back only, you
+ will be able to go onto the window sill.
+ T = Press to make a maskable wall 50/50 transluscent. Press T
+ again to put the masked wall back to normal mode.
+ M = Make a maskable wall. Press in the same place you press 'B'.
+ The masking wall takes all its attributes from the front of
+ the wall, so it must have the same repeat, panning, and cstat
+ values as the walls above or below it (if you have a step).
+ The masking picture number is stored in overpicnum. Also,
+ the masking walls is also automatically added the the other
+ side of the wall, with the picture flipped. (see the 'F'
+ key descripte above)
+ Shift + M = Make a maskable wall just like 'M' described above, but only
+ on the front side.
+
+ 1 = Make a 1-way wall.
+ 2 = Some walls have two different sections. One step on the
+ ceiling and one step on the floor. Normally they always
+ have the same attributes. It is possible though, to give
+ both the top and bottom different attributes by pressing 2 on
+ that wall. 2 simply makes the bottom wall's attributes
+ separately editable. Press 2 on either the top or bottom
+ wall.
+ O = Wall orientation (whether it starts from the top or bottom)
+ Normally, walls are oriented from the top. For example, if
+ you hold down 2/8 on the keypad in 3D EDIT MODE, the wall
+ always starts from the top. Orientation works differently
+ for white lines and red lines, so if a wall doesn't look
+ right, just press 'O' anyway to see if it get fixed.
+ H = Toggle hitscan pass through bit. Default is pass through.
+
+SPRITE FLAGS:
+
+ B = When the mouse cursor is on a sprite, this makes a sprite
+ block you from walking through. Also makes the sprite
+ sensitive to hitscan. Sprites with the 'B' attribute will
+ appear pink in 2D EDIT MODE
+ T = Press to make a sprite 50/50 transluscent. Press T again
+ to put sprite back to normal mode.
+
+旼컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+ 2D EDIT MODE KEYS:
+읕컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+ ESC = Show a menu that says, "(N)ew, (L)oad, (S)ave, (Q)uit"
+ Press ESC again to cancel the menu.
+ keypad ENTER = Flip back to the 3D edit mode
+
+ Mouse = Move mouse cursor
+ Left mouse button = If you hold down the left mouse button, you can drag
+ existing points. To drag multiple points you can use
+ the right shift key to first select a rectangular
+ region of points to highlight, then just drag any of
+ the highlighted points and the rest move with it.
+Right mouse button = Moves the player's positions to the mouse cursor.
+ This is useful when you accidently get stuck somewhere
+ in the board, or when you need to edit some part of
+ a sector that is hard to access.
+ Right Shift = Select a bunch of points for use with dragging around.
+ Selects all points inside a box. (Use the left mouse
+ button to drag)
+ Ctrl+Right Shift = Select a bunch of points for use with dragging around.
+ Selects all points on a loop. (Use the left mouse
+ button to drag)
+ Right Alt = Select a bunch of sectors for either duplication or
+ dragging around. (see left mouse button for
+ dragging and the insert key for duplication).
+
+ Arrows = Move player position in the appropriate directions.
+ The player will be clipped. To jump to a different part
+ of the board, use the right mouse button.
+ Space = Press the space bar when drawing new sectors. There
+ are several ways of drawing new sectors. The following
+ three ways of drawing sectors can all be done by only
+ using the space bar. The computer is smart enough to
+ decide which method you are using.
+
+ 1. Drawing a FULL LOOP - that is, whenever the new
+ sector meets the old sector, draw over that line
+ again. In full loop mode the new sector must not
+ already be in another sector. The loop is done
+ when you press the space bar at the first point
+ again.
+ 2. SPLITTING a sector - press space bar to draw points
+ at which you want to split a sector. The computer
+ knows you are done splitting when you end at
+ another point that's on the edge of the sector you
+ are splitting.
+ 3. Drawing a sector COMPLETELY INSIDE another sector.
+ (for example, columns) To do this, just press space
+ bar at every point in the loop. The loop is done
+ when you press the space bar at the first point
+ again.
+ Backspace = When plotting points with the space bar, you can use
+ backspace to get rid of the last point plotted. You
+ can press the backspace to get rid of all the points
+ if you didn't want to start a sector at all.
+
+ Insert = Inserts a new point at the midpoint of the highlighted
+ line. Then you can drag the point to wherever you like.
+ (If you insert on a red line, the point will be inserted
+ on both sides of the sector line.)
+ If a bunch of sectors are selected (see right ALT) then
+ instead of inserted points, the selected sector bunch
+ will be duplicated (stamped). Don't forget to drag
+ the selected sectors after stamping.
+
+ Delete = Use this to delete sprites (blue circles). To delete
+ points of a sector border, don't press delete. Instead,
+ drag the point into one of its 2 neighbor points on the
+ sector. This is easist done if grid locking is on
+ (mouse cursor is pink). If 2 neighbor points are equal,
+ one will automatically be deleted.
+ Right Ctrl-Delete = This deletes the whole sector that the mouse cursor is
+ in. Note the right ctrl for protection.
+ (Note: to delete a point of a sector, just drag that point into the next
+ point and it will automatically be deleted. You should do this with
+ grid-locking on)
+ J = Use to join two neighboring sectors. Press J when mouse
+ cursor is over the first sector. Then press J again
+ when the mouse cursor is over the neighboring sector.
+ The attributes of the combined sector will be taken from
+ the first sector selected.
+ ALT-S = When you have a white loop inside a sector, you can
+ press ALT-S on it (highlight any of its lines) to turn
+ the whole loop red.
+ S = Places a sprite at the location under the mouse cursor.
+ A sprite looks like a blue circle in the overhead map.
+
+ B = Blocks / unblocks you from going through a wall or
+ sprites. A blocked wall or sprite will appear pink
+ in 2D EDIT MODE. See the description for 'B' in
+ the 3D EDIT MODE section for more details.
+
+ C = Turn a line into a circle defined by short line
+ segments. First press 'C' on a highlighted wall. Then
+ move the mouse to the right place and press '+' or '-'
+ if you want to change the number of points on the
+ circle. Press 'C' again to cancel the circle drawing or
+ press the Space bar to actually change the map.
+ +/- = Increase / Decrease the number of points on the circle.
+
+ T = Type in a LO-tag for a sector. Move the mouse cursor to
+ the inside of a sector that you want to tag first.
+ ALT-T = Just like 'T' but for walls and sprites.
+ H = Type in a HI-tag for a sector. Move the mouse cursor to
+ the inside of a sector that you want to tag first.
+ ALT-H = Just like 'H' but for walls and sprites.
+ E = Change a sprite's status list number.
+ < and > = Changes angle of sprite. Move the mouse cursor to a
+ sprite first. You can hold down shift with the < and >
+ to get more precise angles. If you did a sector
+ highlight, then the selected sector will be rotated
+ instead.
+ CTRL-T = Turn tag boxes on/off.
+
+ TAB = Move the mouse cursor to the inside of a sector that you
+ you want to see the attributes of. It will show them
+ at the bottom of the status bar. To clear it, press
+ TAB again at somewhere in the board that is not part
+ of any sector. This is a useful key for debugging.
+ ALT-TAB = Works just like TAB, but here, you can see the
+ attributes of highlighted walls or sprites. For red
+ lines, the side the mouse cursor is on the line affects
+ which line is highlighted, since red lines are actually
+ defined as 2 walls (1 wall for each sector).
+
+ Scroll Lock = Set starting position (brown arrow) to your current
+ position (white arrow).
+
+ A,Z = Zoom in and out. This is useful for choosing whether
+ you want to edit finely or not.
+ G = Change grid resolution. The grid resolution cycles
+ through this sequence:
+ (off, 1x, 2x, 4x (default), 8x, 16x)
+ L = Turns grid locking on or off. If the mouse cursor is
+ pink then grid locking is on. If it is white then
+ grid locking is off. There is no grid locking
+ if the grid is turned off. Also, grid locking will
+ lock to nearby points.
+
+旼컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+ EDITART KEYS:
+읕컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+
+ ---- Keys you will need to know if you want to select from a section of
+ a 320*200*256 picture file (.BMP and .PCX only) and put it into the BUILD
+ engine.
+
+ U - Use this to import a section of a 320*200*256 .BMP, .PCX, or .GIF.
+ Enter - Convert the image that is inside the rectangular selection
+ rectangle to the BUILD palette.
+ Space - Convert the image that is inside the rectangular selection
+ rectangle without remapping the palette.
+ P - If in the picture selecting screen (after pressing U and loading
+ the picture), you press P, then the palette of BUILD can be
+ 읕 replaced by the palette of the displayed picture.
+ PGUP/PGDN - Select tile to edit (4096 tile maximum right now).
+ G - GOTO a tile by typing in the tile number.
+ S - Re-size tile. The X and Y sizes can be any unsigned short integer.
+ X ranges from 0 to 1024, and Y ranges from 0 to 240.
+ Delete - short cut key to set both the X and Y sizes to 0.
+ +,- Change the animation setting. (Default: NoAnm = 0.)
+ To change the animation type, press - when the value is 0.
+ Ex: If you want an object to have 4 tiles of animation, you can
+ animate it in 4 different sequences: (0 is the current tile)
+ NoAnm=4 sequence: 0,0,0,0,0,0,0,0,0,0,0,... (no animation)
+ Oscis=4 sequence: 0,1,2,3,2,1,0,1,2,3,2,... (oscillate)
+ AnmFD=4 sequence: 0,1,2,3,0,1,2,3,0,1,2,... (forwards)
+ AnmBK=4 sequence: 0,-1,-2,-3,0,-1,-2,-3,... (backwards)
+ A - Set the animation speed of the tile. Press + and - to change the
+ animation speed. There are 16 different animation speeds. The
+ animation speed set here set the speed for BUILD and your GAME also.
+ (Speed is proportional to (totalclock>>animspeed))
+ ~' - This key (located just above the TAB key) allows you to center a
+ sprite. Simply use the arrow keys to get to the desired position.
+ N - Name a tile. Naming a tile simply changes the #define statement in
+ NAMES.H. You should include NAMES.H when compiling so you can easily
+ refer to sprites by name rather than by number.
+ O - Optimize the size of an individual piece of artwork. Use this for
+ tiles with invisible pixels on the sides.
+ V - View and select a tile to edit.
+ Space - To swap 2 tiles simply press space bar on the first tile,
+ then space bar on the second.
+ 1,2,3 - To swap a group of tiles, press 1 on the first tile,
+ press 2 to remember the region between where you pressed
+ 1 and 2. Press 3 at the place to where you want to swap
+ 읕 all the tiles.
+ALT+U- Re-grab artwork from original pictures according to the CAPFIL.TXT
+ file. If you press ALT-U in the main screen, everything will be
+ re-grabbed. If you press ALT-U in 'V' mode, then you should first
+ select the range by pressing '1' and '2' on the range boundaries.
+ALT+R- Generate a Tile frequency report by scanning all maps in directory.
+ Use in 'V' mode only.
+F12 - Screen capture (saves image as a *.BMP file, starting as file
+ name CAPTUR00.BMP and incrementing by 1 each time F12 is
+ pressed.
+
+ ESC - Quit.
+
+
+
+ ---- Extra features: (if you actually want to do the artwork in EDITART
+ or if you want to touch-up some imported art.)
+
+ C - Change all pixels on the tile having the same color under the
+ graphics cursor to to selected color.
+ Arrows / Mouse - Move graphics cursor.
+ Shift + Arrows - Select color. (on bottom right corner of screen)
+ Space - Plot a pixel with the selected color.
+ T - Turn drawing trail on / off.
+ Tab - Select the color under the graphics cursor.
+ BACKSPACE - Set the color to color 255 (transparent color).
+ F - Floodfill a region with the current color and with the current
+ color as a boundary.
+ M,P - Use M to back up a tile into a temporary buffer in memory and P
+ to restore it. It may be wise to press M before a floodfill (F)
+ (because sometimes you miss encapsulating the region by 1 pixel,
+ and the whole picture gets killed, etc...)
+ J - Randomly plots dots of current color over any pixels having the
+ same color as the color under the tile cursor.
+ [ - Random antialias of colors in color band under graphics cursor.
+ ] - Non-random antialias of colors in color band under graphics cursor.
+ ; - 3-Dimentionalize an image. Makes colors in different rows of the
+ color bar either appear to stick out or stick in to the wall.
+ ' - 3-Dimentionalize the other way.
+ R - Rotate the tile in a specified direction.
+
+ 1 - Mark the first corner of a rectangle for a copy/paste operation.
+ 2 - Mark the other corner of a rectangle for a copy/paste operation.
+ 3 - Paste the selected rectangle (Note: You must press 1 and 2 in that
+ order first before pressing 3. Pretty simple 1-2-3 for copy&paste)
+
+ 4 - Flip the copied rectangular region x-wise.
+ 5 - Flip the copied rectangular region y-wise.
+ 6 - Swap the x and y coordinates of the copied rectangular region.
+
+ ,.<> - Change the shade of the selected region.
+ \ - Move the cursor to the center or the tile.
+ | - Get the coordinates of the cursor.
+
+藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁敲
+勁胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱
+勁胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱
+勁胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱
+勁胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱
+勁胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱
+勁胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱
+勁胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱
+勁胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱
+훤姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦
+
+旼컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+ IMPORTANT ENGINE FUNCTIONS:
+읕컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+
+initengine(char vidoption, long xdim, long ydim)
+ Sets up interrupt vectors for keyboard, and initializes many variables
+ for the BUILD engine. You should call this once before any other
+ functions of the BUILD engine are used.
+
+ vidoption can be anywhere from 0-6
+ xdim,ydim can be any mode x resolution if vidoption = 0
+ xdim,ydim can be any vesa resolution if vidoption = 1
+ xdim,ydim must be 320*200 for any other mode.
+ (see graphics mode selection in my setup program)
+uninitengine();
+ Restores interrupt vectors for keyboard and timer, and frees
+ buffers. You should call this once at the end of the program
+ before quitting to dos.
+loadboard(char *filename, long *posx, long *posy, long *posz, short *ang, short *cursectnum)
+ Loads the given board file into memory for the BUILD engine.
+ Returns -1 if file not found. If no extension is given, .MAP will
+ be appended to the filename.
+saveboard(char *filename, long *posx, long *posy, long *posz, short *ang, short *cursectnum)
+ Saves the given board from memory inro the specified filename.
+ Returns -1 if unable to save. If no extension is given, .MAP will
+ be appended to the filename.
+loadpics(char *filename);
+ Loads the given artwork file into memory for the BUILD engine.
+ Returns -1 if file not found. If no extension is given, .ART will
+ be appended to the filename.
+setgamemode();
+ This function sets the video mode to 320*200*256color graphics.
+ Since BUILD supports several different modes including mode x,
+ mode 13h, and other special modes, I don't expect you to write
+ any graphics output functions. (Soon I have all the necessary
+ functions) If for some reason, you use your own graphics mode,
+ you must call this function again before using the BUILD drawing
+ functions.
+
+drawrooms(long posx, long posy, long posz, short ang, long horiz, short cursectnum)
+ This function draws the 3D screen to the current drawing page,
+ which is not yet shown. This way, you can overwrite some things
+ over the 3D screen such as a gun. Be sure to call the drawmasks()
+ function soon after you call the drawrooms() function. To view
+ the screen, use the nextpage() function. The nextpage() function
+ should always be called sometime after each draw3dscreen()
+ function.
+drawmasks();
+ This function draws all the sprites and masked walls to the current
+ drawing page which is not yet shown. The reason I have the drawing
+ split up into these 2 routines is so you can animate just the
+ sprites that are about to be drawn instead of having to animate
+ all the sprites on the whole board. Drawrooms() prepares these
+ variables: spritex[], spritey[], spritepicnum[], thesprite[],
+ and spritesortcnt. Spritesortcnt is the number of sprites about
+ to be drawn to the page. To change the sprite's picnum, simply
+ modify the spritepicnum array If you want to change other parts
+ of the sprite structure, then you can use the thesprite array to
+ get an index to the actual sprite number.
+
+engineinput();
+ This function allows the engine to adjust your position depending
+ on the status of the arrow keys, and other control keys. It
+ handles timing and clipping.
+nextpage();
+ After a screen is prepared, use this function to view the screen.
+
+draw2dscreen(long posxe, long posye, short ange, long zoome,
+ short gride)
+ Draws the 2d screen - this function is a direct replacement
+ for the drawrooms() and drawmasks() functions. Be sure
+ to call either qsetmode640350() or qsetmode640480()
+ first. When switching back to 3d mode, be sure to call
+ qsetmode320200().
+ IMPORTANT NOTES:
+ 1. The overwritesprite function should only be called in
+ 3D mode. If you do this in 2D mode, junk will be
+ written to the 2D screen and a crash is possible.
+ 2. When you switch back to 3D mode, you should call the
+ permanentwritesprite functions to draw the status bar,
+ or whatever else you have to draw.
+ 3. You must call the nextpage() function in both 2D and
+ 3D modes.
+qsetmode320200();
+ Set to the game mode and load palette (320*200*256)
+qsetmode640350();
+ Set to the 2D map mode #1 (640*350*16)
+qsetmode640480();
+ Set to the 2D map mode #2 (640*480*16)
+
+doanimations(long numtics);
+ This function animates anything you use setanimation for (like doors).
+ You should call it for every frame. Pass the number of tics (lockspeed)
+ as a parameter to it to tell how much everything should animate.
+
+kenchaintimer(void (__interrupt __far *datimerchainaddress)(),
+ short dachainpersecond)
+ This function makes the engine's timerhandler chain to another timer
+ handler at any specified interrupt rate. This function forces IRQ0 to
+ point to my engine's timerhandler. Clockspeed and totalclock will
+ be fixed at counting 120 per second regardless of the chaining interrupt
+ rate. If you call this function with a NULL pointer, then the engine's
+ timerhandler will not chain anymore.
+
+ Here's how you should structure your code if you use this function:
+
+ main()
+ {
+ initengine();
+
+ musicon(); //Turn music on after engine
+ kenchaintimer(yourtimerhandleraddress,yourtimerrate);
+ //When IRQ0 goes off, it will now go to
+ //Ken's timer handler. Then, Ken's timer
+ (main loop) //handler will make yourtimerhandler
+ //interrupt yourtimerrate times per second
+
+ kenchaintimer(0,0); //Stop chaining BEFORE music handler dies!
+ musicoff();
+
+ uninitengine();
+ }
+
+旼컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+ OTHER ENGINE FUNCTIONS:
+읕컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+
+overwritesprite (long thex, long they, short tilenum,
+ signed char shade, char orientation, char dapalnum)
+
+ Use this function to draw any sprites that must be drawn to the screen
+ for every single frame, such as a gun or a menu system.
+
+ If Bit 0 of orientation = 0: (thex, they) is top-left corner
+ If Bit 0 of orientation = 1: (thex, they) is middle
+ If Bit 1 of orientation = 0: no relation to viewing window
+ If Bit 1 of orientation = 1: scale and clip to viewing window
+ If Bit 2 of orientation = 0: normal
+ If Bit 2 of orientation = 1: 50/50 transluscent!
+ If Bit 3 of orientation = 0: normal
+ If Bit 3 of orientation = 1: x-flipped
+ If Bit 4 of orientation = 0: normal
+ If Bit 4 of orientation = 1: y-flipped
+
+ * If it works at full screen, simply set bit 1 of orientation
+ to 1, and it should automatically scale properly!
+
+ Use this function to write sprites over the 3d view. For example,
+ you can make a menu system with this function. Be sure
+ that you call this function for every single frame after the 3d
+ view is drawn or else it will be flashed on for only 1 frame.
+ If you want x and y to be the top left corner, set the orientation
+ to 0. If you want x and y to be the middle of the sprite, set the
+ orientation to 1. The reason I included the orienation = 1 option
+ is so that if you want a sprite centered and the size of the tile
+ changes, you don't need to recompile and guess where the new top
+ left corner is. Oh yeah, and I forget to mention that if shade is
+ greater than 32, than overwritesprite does transluscence. (Try it
+ out!) This function will clip the sprite to the startumost and
+ startdmost arrays. Dapalnum refers to a palette lookup list
+ (normally 0).
+
+rotatesprite (long sx, long sy, long z, short a, short picnum,
+ signed char dashade, char dapalnum, char dastat,
+ long cx1, long cy1, long cx2, long cy2)
+ (sx, sy) is the center of the sprite to draw defined as
+ screen coordinates shifted up by 16.
+ (z) is the zoom. Normal zoom is 65536.
+ Ex: 131072 is zoomed in 2X and 32768 is zoomed out 2X.
+ (a) is the angle (0 is straight up)
+ (picnum) is the tile number
+ (dashade) is 0 normally but can be any standard shade up to 31 or 63.
+ (dapalnum) can be from 0-255.
+ if ((dastat&1) == 0) - no transluscence
+ if ((dastat&1) != 0) - transluscence
+ if ((dastat&2) == 0) - don't scale to setview's viewing window
+ if ((dastat&2) != 0) - scale to setview's viewing window (windowx1,etc.)
+ if ((dastat&4) == 0) - nuttin' special
+ if ((dastat&4) != 0) - y-flip image
+ if ((dastat&8) == 0) - clip to startumost/startdmost
+ if ((dastat&8) != 0) - don't clip to startumost/startdmost
+ if ((dastat&16) == 0) - use Editart center as point passed
+ if ((dastat&16) != 0) - force point passed to be top-left corner
+ if ((dastat&32) == 0) - nuttin' special
+ if ((dastat&32) != 0) - use reverse transluscence
+ if ((dastat&64) == 0) - masked drawing (check 255's) (slower)
+ if ((dastat&64) != 0) - draw everything (don't check 255's) (faster)
+
+ Note: As a special case, if both ((dastat&2) != 0) and ((dastat&8) != 0)
+ then rotatesprite will scale to the full screen (0,0,xdim-1,ydim-1)
+ rather than setview's viewing window. (windowx1,windowy1,etc.) This
+ case is useful for status bars, etc.
+
+ Ex: rotatesprite(160L<<16,100L<<16,65536,totalclock<<4,
+ DEMOSIGN,2,50L,50L,270L,150L);
+ This example will draw the DEMOSIGN tile in the center of the
+ screen and rotate about once per second. The sprite will only
+ get drawn inside the rectangle from (50,50) to (270,150)
+
+permanentwritesprite (long thex, long they, short tilenum, signed char shade,
+ long cx1, long cy1, long cx2, long cy2, char dapalnum)
+ - Added permanentwritesprite function for status bars or other
+ sections of the screen that will not be overwritten by the
+ engine. The format of this function is like overwritesprite
+ except that the x and y are always top left corner, no
+ orientation variable, and no translucence.
+ The 4 last parameters (cx1, cy1) - (cx2, cy2) define a
+ rectangular clipping window of where permanentwritesprite
+ can draw to. Dapalnum refers to a palette lookup list
+ (normally 0).
+
+printext(long x, long y, char buffer[42], short tilenum, char invisiblecol);
+ Use this function to print text anywhere on the screen from a font
+ that you can create in EDITART. Please see my example font in
+ TILES.ART to see how I lay out the user-defined font. X ranges
+ from 0-319. Y ranges from 0-199. The buffer is the string to
+ print. Tilenum specifies which font to use. Invisiblecol tells
+ printext what color to draw the transparent pixels. If
+ invisiblecol is 255 then the transpararent pixels are still
+ transparent.
+printnum(long x, long y, long num, short tilenum, char invisiblecol);
+ Printnum is a function call that will print a long integer (num)
+ starting at top left corner x, y. Please look at the documentation
+ for printext, since internally, printnum simply prepares a buffer
+ and calls the printext function.
+
+setvmode(long videomode);
+ If you look at the top of GAME.C, you will see something like this:
+ #pragma aux setvmode =\... This is how you do in-line assembler in
+ WATCOM C. All this function is doing is setting the video mode.
+showengineinfo();
+ Use this function after setting to text mode to view some statics
+ about the engine, such as frame rate.
+resettiming();
+ Resets timing, such as setting totalclock = 0. Also resets other
+ timers. This is for use with the showengineinfo function above.
+
+ksqrt(long num); returns (long)square root
+ A square root function optimized for integers. Use this function
+ only if you want to.
+krand()
+ This simply returns a random number. You can easily set the random
+ seed by externing the randomseed variable as a long. This is useful
+ for keeping the random seed the same on multiple computers when playing
+ multi-player mode.
+
+getangle(long xvect,long yvect); returns (short)angle;
+ Use this function call to determine the angle between two points.
+ For example, if you want a monster to shoot a bullet towards you,
+ you would get the bullet's angle this way:
+ sprite[bullet].ang = getangle(posx-sprite[monst].x,posy-sprite[monst].y);
+
+lastwall(short point);
+ Use this function as a reverse function of wall[].point2. In order
+ to save memory, my walls are only on a single linked list.
+
+rotatepoint(long xpivot, long ypivot, long x, long y,
+ short daang, long *x2, long *y2);
+ This function is a very convenient and fast math helper function.
+ Rotate points easily with this function without having to juggle your
+ cosines and sines. Simply pass it:
+
+ Input: 1. Pivot point (xpivot,ypivot)
+ 2. Original point (x,y)
+ 3. Angle to rotate (0 = nothing, 512 = 90 CW, etc.)
+ Output: 4. Rotated point (*x2,*y2)
+
+clipmove(long *x, long *y, long *z, short *sectnum, long xvect, long yvect,
+ long walldist, long ceildist, long flordist, char cliptype)
+ Moves any object (x, y, z) in any direction at any velocity and will
+ make sure the object will stay a certain distance from walls (walldist)
+ Pass the pointers of the starting position (x, y, z). Then
+ pass the starting position's sector number as a pointer also.
+ Also these values will be modified accordingly. Pass the
+ direction and velocity by using a vector (xvect, yvect).
+ If you don't fully understand these equations, please call me.
+ xvect = velocity * cos(angle)
+ yvect = velocity * sin(angle)
+ Walldist tells how close the object can get to a wall. I use
+ 128L as my default. If you increase walldist all of a sudden
+ for a certain object, the object might leak through a wall, so
+ don't do that!
+ If cliptype is 0, then the clipping is normal (Use 0 to clip you
+ and monsters). If the cliptype is 1, then the object is clipped to
+ the same things that hitscan is clipped to (use 1 for all bullets).
+
+ Clipmove can either return 0 (touched nothing)
+ 32768+wallnum (wall first touched)
+ 49152+spritenum (sprite first touched)
+
+getzrange(long x, long y, long z, short sectnum,
+ long *ceilz, long *ceilhit,
+ long *florz, long *florhit,
+ long walldist, char cliptype)
+
+ Use this in conjunction with clipmove. This function will keep the
+ player from falling off cliffs when you're too close to the edge. This
+ function finds the highest and lowest z coordinates that your clipping
+ BOX can get to. It must search for all sectors (and sprites) that go
+ into your clipping box. This method is better than using
+ sector[cursectnum].ceilingz and sector[cursectnum].floorz because this
+ searches the whole clipping box for objects, not just 1 point.
+ Pass x, y, z, sector normally. Walldist can be 128. Cliptype can be
+ 0, 1, or 2. (just like movesprite and clipmove) This function returns
+ the z extents in ceilz and florz. It will return the object hit in ceilhit
+ and florhit.
+ Ceilhit and florhit will also be either:
+ 16384+sector (sector first touched) or
+ 49152+spritenum (sprite first touched)
+
+updatesector(long x, long y, &sectnum);
+ This function updates the sector number according to the x and y values
+ passed to it. Be careful when you use this function with sprites because
+ remember that the sprite's sector number should not be modified directly.
+ If you want to update a sprite's sector, I recomment using the setsprite
+ function described below.
+
+inside(long x, long y, short sectnum);
+ Tests to see whether the overhead point (x, y) is inside sector (sectnum)
+ Returns either 0 or 1, where 1 means it is inside, and 0 means it is not.
+
+copytilepiece(long tilenume1, long sourcex1, long sourcey1,
+ long xsiz, long ysiz,
+ long tilenume2, long destx1, long desty1)
+
+ This function simply copies any section of a source tile
+ to any part of a destination tile. It will automatically
+ skip transparent pixels. It will wrap-around in the
+ source but not the destination. If for some reason
+ the destination tile gets removed from the cache, the
+ destination tile will be reset to original form. This
+ is why I had to add this second function:
+
+allocatepermanenttile(short tilenume, long xsiz, long ysiz)
+ This function allocates a place on the cache as permanent.
+ Right now, I reset the cache every time you call this
+ function so I would recommend calling this function
+ right after loadpics.
+
+makepalookup(long palnum, char *remapbuf,
+ signed char r, signed char g, signed char b,
+ char dastat)
+ This function allows different shirt colors for sprites. First prepare
+ remapbuf, which is a 256 byte buffer of chars which the colors to remap.
+ Palnum can be anywhere from 1-15. Since 0 is where the normal palette is
+ stored, it is a bad idea to call this function with palnum=0.
+ In BUILD.H notice I added a new variable, spritepal[MAXSPRITES].
+ Usually the value of this is 0 for the default palette. But if you
+ change it to the palnum in the code between drawrooms() and drawmasks
+ then the sprite will be drawn with that remapped palette. The last 3
+ parameters are the color that the palette fades to as you get further
+ away. This color is normally black (0,0,0). White would be (63,63,63).
+ if ((dastat&1) == 0) then makepalookup will allocate & deallocate
+ the memory block for use but will not waste the time creating a palookup
+ table (assuming you will create one yourself)
+
+copytilepiece(long walnume1, long x1, long y1, long xsiz, long ysiz,
+ long walnume2, long x2, long y2, char shadeoffs);
+ Copies section of tile 1 (walnume1) with top-left corner (x1,y1) and
+ rectangular size (xsiz, ysiz) to top-left corner (x2, y2) of tile 2
+ (walnume). You can animate tiles with this function. For example, with
+ this function, you can make a slot machine like in Ken's Labyrinth or an
+ electronic sign with text sliding from right to left.
+
+loadtile(short tilenume);
+ This function will load the tile, tilenum, into the artwork cache. A
+ tile is not in the cache if (waloff[tilenum] == -1). If
+ (waloff[tilenum] >= 0) then it is in the cache, and you don't need to call
+ this function.
+
+precache();
+ This function will go through the tilenums of all sectors, walls, and
+ sprites and call loadtile() on them. This function will not cache in some
+ tiles of animations since their tilenums may not all be in the structures.
+
+hitscan(long xstart, long ystart, long zstart, short startsectnum,
+ long vectorx, long vectory, long vectorz,
+ short *hitsect, short *hitwall, short *hitsprite,
+ long *hitx, long *hity, long *hitz);
+
+ Pass the starting 3D position:
+ (xstart, ystart, zstart, startsectnum)
+ Then pass the 3D angle to shoot (defined as a 3D vector):
+ (vectorx, vectory, vectorz)
+ Then set up the return values for the object hit:
+ (hitsect, hitwall, hitsprite)
+ and the exact 3D point where the ray hits:
+ (hitx, hity, hitz)
+
+ How to determine what was hit:
+ * Hitsect is always equal to the sector that was hit (always >= 0).
+
+ * If the ray hits a sprite then:
+ hitsect = thesectornumber
+ hitsprite = thespritenumber
+ hitwall = -1
+
+ * If the ray hits a wall then:
+ hitsect = thesectornumber
+ hitsprite = -1
+ hitwall = thewallnumber
+
+ * If the ray hits the ceiling of a sector then:
+ hitsect = thesectornumber
+ hitsprite = -1
+ hitwall = -1
+ vectorz < 0
+ (If vectorz < 0 then you're shooting upward which means
+ that you couldn't have hit a floor)
+
+ * If the ray hits the floor of a sector then:
+ hitsect = thesectornumber
+ hitsprite = -1
+ hitwall = -1
+ vectorz > 0
+ (If vectorz > 0 then you're shooting downard which means
+ that you couldn't have hit a ceiling)
+
+neartag(long x, long y, long z, short sectnum, short ang, //Starting position & angle
+ short *neartagsector, //Returns near sector if sector[].tag != 0
+ short *neartagwall, //Returns near wall if wall[].tag != 0
+ short *neartagsprite, //Returns near sprite if sprite[].tag != 0
+ long *neartaghitdist, //Returns actual distance to object (scale: 1024=largest grid size)
+ long neartagrange, //Choose maximum distance to scan (scale: 1024=largest grid size)
+ char tagsearch) //1-lotag only, 2-hitag only, 3-lotag&hitag
+ Neartag works sort of like hitscan, but is optimized to
+ scan only close objects and scan only objects with
+ tags != 0. Neartag is perfect for the first line of your space bar code.
+ It will tell you what door you want to open or what switch you want to
+ flip.
+
+cansee(long x1, long y1, long z1, short sectnum1,
+ long x2, long y2, long z2, short sectnum2); returns 0 or 1
+ This function determines whether or not two 3D points can "see" each
+ other or not. All you do is pass it the coordinates of a 3D line defined
+ by two 3D points (with their respective sectors) The function will return
+ a 1 if the points can see each other or a 0 if there is something blocking
+ the two points from seeing each other. This is how I determine whether a
+ monster can see you or not. Try playing DOOM1.DAT to fully enjoy this
+ great function!
+
+setanimation(long *animptr, long thegoal, long thevel);
+ This is a function for your convenience that will animate a long
+ variable, such as sector[].floorz for platforms, or sector[].ceilingz
+ for doors. All you do is pass it the long pointer into memory, specifying
+ which long variable is to be animated; you also pass the goal (long value
+ to animate towards), and the velocity at which the variable is animated.
+ Velocity = 128 is a normal speed door. You may also modify the animation
+ arrays directly if you wish:
+
+ The animation arrays are as follows:
+ long *animateptr[MAXANIMATES], animategoal[MAXANIMATES];
+ long animatevel[MAXANIMATES], animatecnt;
+
+getanimationgoal(long animptr);
+ Check to see if a certain variable in memory is already being animated
+ by the engine. If so, an index into the animation arrays is returned,
+ else -1 is returned. This is function is useful when you are press
+ space bar near a door, and it is already animating, you simply want
+ to reverse its direction.
+
+dragpoint(short wallnum, long newx, long newy);
+ This function will drag a point in the exact same way a point is dragged
+ in 2D EDIT MODE using the left mouse button. Simply pass it which wall
+ to drag and then pass the new x and y coordinates for that point.
+ Please use this function because if you don't and try to drag points
+ yourself, I can guarantee that it won't work as well as mine and you
+ will get confused. Note: Every wall of course has 2 points. When you
+ pass a wall number to this function, you are actually passing 1 point,
+ the left side of the wall (given that you are in the sector of that wall)
+ Got it?
+
+nextsectorneighborz(short sectnum, long thez, short topbottom, short direction);
+ This function searches z-coordinates of neighboring sectors to find the
+ closest (next) ceiling starting at the given z-coordinate (thez).
+ For example, if you want to find the goal z-coordinate when opening a
+ door, you might want the door to stop at the next closest neighboring
+ ceiling z-coordinate. You can get the z-coordinate this way:
+
+ newz = sector[nextsectorneighborz(sectnum,startz,-1,-1)].ceilingz
+
+ topbottom (3rd parameter) -1 = search ceilings
+ 1 = search floors
+ direction (4th parameter) -1 = search upwards
+ 1 = search downwards
+
+screencapture(char *filename)
+ Capture the screen and save it as a .BMP file. I don't know why my
+ .BMP format isn't compatible with other programs.
+
+旼컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+ SPRITE FUNCTIONS:
+읕컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+
+insertsprite(short sectnum, short statnum); //returns (short)spritenum;
+ Whenever you insert a sprite, you must pass it the sector
+ number, and a status number (statnum). The status number can be any
+ number from 0 to MAXSTATUS-1. Insertsprite works like a memory
+ allocation function and returns the sprite number.
+
+deletesprite(short spritenum);
+ Deletes the sprite.
+
+changespritesect(short spritenum, short newsectnum);
+ Changes the sector of sprite (spritenum) to the
+ newsector (newsectnum). This function may become
+ internal to the engine in the movesprite function. But
+ this function is necessary since all the sectors have
+ their own doubly-linked lists of sprites.
+
+changespritestat(short spritenum, short newstatnum);
+ Changes the status of sprite (spritenum) to status
+ (newstatus). Newstatus can be any number from 0 to MAXSTATUS-1.
+ You can use this function to put a monster on a list of active sprites
+ when it first sees you.
+
+setsprite(short spritenum, long newx, long newy, long newz);
+ This function simply sets the sprite's position to a specified
+ coordinate (newx, newy, newz) without any checking to see
+ whether the position is valid or not. You could directly
+ modify the sprite[].x, sprite[].y, and sprite[].z values, but
+ if you use my function, the sprite is guaranteed to be in the
+ right sector.
+
+movesprite(short spritenum, long xchange, long ychange, long zchange,
+ long ceildist, long flordist, char cliptype, long numtics)
+ This function moves the sprite given by spritenum by the 3
+ increments, xchange, ychange, and zchange. If cliptype is 0, then
+ the clipping is normal (Use 0 to clip you and monsters). If the
+ cliptype is 1, then the object is clipped to the same things that
+ hitscan is clipped to (use 1 for all bullets).
+ Movesprite can either return 0 (touched nothing)
+ 16384+sectnum (ceiling/floor first touched)
+ 32768+wallnum (wall first touched)
+ 49152+spritenum (sprite first touched)
+
+getspritescreencoord(short spritesortnum, long *scrx, long *scry)
+ This function returns the actual screen coordinates of a sprite. It
+ is useful for locking on to a target. Use this function between
+ drawrooms and drawmasks. Note that spritesortnum is the index into the
+ spritesortcnt arrays, NOT the normal sprite arrays. Scrx and scry are
+ actual screen coordinates ranging from 0-319 and 0-199 respectively.
+
+旼컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+ MULTIPLAYER FUNCTIONS (multi.obj)
+읕컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+
+ initmultiplayers(char option[4], char option[5], char priority);
+ Call this right after initengine. Pass option[4] and option[5]
+ exactly the way I have it written here. (option[4] is the COM1-COM4,
+ network option and option[5] is the com speed selection option)
+ Priority can be used to decide who becomes master. Lower is more
+ towards the master.
+
+ uninitmultiplayers();
+ Call this right before uninitengine.
+
+ sendlogon();
+ Use this function after everything's initialized, but before you
+ go into the main game loop. Right after you call sendlogon(), you
+ should run a loop that will wait until a specified number of players.
+ Here's some example code:
+
+ sendlogon();
+ while (numplayers < waitplayers)
+ {
+ getpackets();
+ }
+ screenpeek = myconnectindex;
+
+ Getpackets reserves the packet header range from 200-255. If you
+ keep calling getpackets after sendlogon, the numplayers variable will
+ automatically be incremented when other people log on.
+
+ sendlogoff();
+ Call this before leaving, before uninitializing the multiplayer
+ code.
+
+ sendpacket (short otherconnectindex, char *bufptr, short bufleng)
+ For COM(modem) communications, the otherconnectindex doesn't matter.
+ For network communcations, you can specify which computer to send
+ to by setting otherconnectindex to the proper index number. You
+ can also do a broadcast by setting otherconnectindex to -1.
+ Also pass the buffer and length parameters.
+
+ short getpacket (short *otherconnectindex, char *bufptr) returns bufleng
+ When using getpacket, first check the value it returns.
+ If the value is 0, then the buffer length is 0 which means there
+ are no packets available. If the buffer length is greater than
+ 0, then use that value as the length of the buffer. Getpacket also
+ tells you what computer the message was received from -
+ (otherconnectindex).
+
+旼컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+ DIGITIZED SOUND FUNCTIONS:
+읕컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+Note: If you want to write your own digitized sound driver, simply delete
+ these functions from GAME.C.
+
+initsb();
+ Initializes the digitized sound routines. You need to call this
+ only once at the beginning of the program. Currently, the
+ sample rate is 11,025 Hz.
+
+wsay(char *filename, long freq, char volume);
+ Play the sound file at the given frequency and volume. If you
+ set freq = 4096, the sound will play at normal frequency (given
+ the sound was also recorded at 11025 Hz) To play the sound an
+ octave higher, for example, set freq = 8192. Volume ranges from
+ 0 (silent) to 255 (full volume). Ex: wsay("blowup.wav",4096L,255);
+
+uninitsb();
+ Turns the speaker off, so sounds don't continue playing while
+ your back in DOS.
+
+旼컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+ MUSIC FUNCTIONS:
+읕컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+Note: If you want to write your own music driver, simply delete these
+ functions from GAME.C. The BUILD engine uses interrupt vector 0x8 (IRQ0)
+ and that may complicate things. If you like my music, perhaps I can send
+ you my MIDI sequencer program (It requires MPU-401, and TSENG-ET4000 SVGA,
+ but could be standardized if there's enough demand).
+
+loadmusic(char *filename);
+ Loads the given song into memory. Be sure INSTS.DAT is in the
+ current directory. If no extension is given, then .KSM will be
+ appended to the filename. You should use this function only when
+ the music is off.
+musicon();
+ Enable the playing of music. Use this only after loadmusic has
+ been called.
+musicoff();
+ Disable the playing of music. Be sure to call this before quitting
+ to DOS.
+
+藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁藁敲
+勁胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱
+勁胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱
+勁胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱
+勁胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱
+勁胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱
+勁胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱
+勁胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱
+勁胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱胱
+훤姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦姦
+
+旼컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+ BUILD Revision History:
+읕컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+2/6/94 - Added this revision thing.
+ - Setup program.
+ - A faster new mode for standard VGAs called chain mode.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+2/8/94 - Fixed chain mode with groudraws.
+ - Added sector joining in 2D EDIT MODE - press J on first sector.
+ Then press J again on sector to join with. Attributes will be
+ taken from first sector. Possible bugs.
+ - Improved controls for slower computers.
+ - Made timer interrupt rate 120/second instead of 240/second.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+2/9/94 - Started to work on status bar in 2D EDIT MODE.
+ - Added special optimization for the Western Digitial (Paradise)
+ chipset just like with TSENG ET4000.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+2/10/94 - Added a door attribute to sectors. To make a sector a door,
+ press "D" on the ceiling of the sector in 3D EDIT MODE. For
+ the door to work, the ceiling of the door sector must be a
+ tiny bit lower than lowest neighboring ceiling. To open/close
+ the door, you may press the space bar. Note: Space Bar is also
+ used for copy and paste in 3D EDIT MODE. You may have to go
+ into game mode to test out the doors for now.
+ - Added a wall orientation attribute to walls. This attribute is
+ used especially in conjunction with doors. So far, you have
+ been working with walls that are start from the top. For
+ example, if you hold down 2/8 on the keypad in 3D EDIT MODE,
+ the wall always starts from the top. But for doors, you
+ sometimes need walls to start from the bottom. To do this,
+ press "O" (for orientation) on the wall, and it will now
+ start from the bottom.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+2/12/94 - Fixed some bugs for sprites. Sprites don't disappear anymore.
+ Now you will pick up all sprites when running over them.
+ Monsters will not stop shooting anymore.
+ - Made the sound blaster sounds have a 1-sound cache. That is, if
+ the same sound is to be played several times in a row, it will
+ only be loaded once.
+ - Added *.GIF format support to EDITART for 320*200 size images.
+ - Changed the PASTE key in 3D EDIT MODE from Space bar to Left
+ Enter because the Space bar conflicted with opening doors.
+ - Added music as an option in the setup program. To run the music,
+ you need INSTS.DAT and a song file with a .KSM extension.
+ - Split the editor from the game.
+ BUILD is now the map editor - you don't need BUILD.C anymore.
+ GAME is now the actual game that you will be programming.
+ I am giving you GAME.C to work with. Its code is simpler
+ than before because there are no more editing function
+ calls in it.
+ - Sprites move in a straight line now until they hit walls. When
+ they hit walls, they pick a new angle to travel in.
+ - Remember that tiny little guy with the "Al" on his shirt?
+ Next time you're in DOOM1.DAT, try shooting him. Then look
+ at the code in GAME.C.
+ - In EDITART, when you press, "u", you now select filenames with
+ the arrow keys and enter rather than having to type in
+ the exact filename.
+ - Board maps now have extension .MAP and artwork files now have
+ extension .ART to help distinguish between the different types
+ of files.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+2/22/94 - Fixed small bug with EDITART not loading right when names.h
+ existed with no names defined.
+ - You can now edit new boards by typing:
+ BUILD <file that doesn't exist> like "BUILD NEWBOARD"
+ - Added ALT-S in 2D EDIT Mode to change a whole white loop inside a
+ sector to a red loop.
+ - When viewing the tiles (pressing "v") you can now use PGUP/PGDN.
+ - Added a message bar in 2D EDIT Mode.
+ - Added TAB and L.ALT-TAB keys to view all the attributes of a
+ sector, wall, or sprite (see above documentation).
+ - Debugged and bullet-proofed ALT-S.
+ - Fixed a bug that doesn't allow you to drag points with number
+ greater than 1023. (There can actually be 4096 walls and 1024
+ sectors, and 4096 sprites currently, an easy thing to increase)
+ - Changed overwritesprite function paramaters. If you are using it
+ in your c file, you must change it! Now it looks like this:
+
+ overwritesprite (long x, long y, short tilenum, char shade,
+ char orientation);
+
+ If orientation = 0: x and y are the top left corner.
+ If orientation = 1: x and y are the middle (like before).
+ - Added permanentwritesprite function for status bars or other
+ sections of the screen that will not be overwritten by the
+ engine. When using this function, you may want to modify the
+ STARTUMOST / STARTDMOST arrays. The format of this function is
+ like overwritesprite except that the x and y are always top
+ left corner, no orientation variable, and no translucence.
+
+ permanentwritesprite (long x, long y, short tilenum, char shade);
+
+ - Added an attribute to the printext and printnum functions. Please
+ change these function if you use them in your program. The
+ current formats are:
+
+ printext(long x, long y, char buffer[42], short tilenum,
+ char invisiblecol)
+ printnum(long x, long y, long num, short tilenum,
+ char invisiblecol);
+
+ Invisiblecol tells printext what color to draw the transparent
+ pixels. If invisiblecol is 255 then the transpararent pixels are
+ still transparent.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+2/26/94 - Completely reprogrammed EDITART.
+ IMPORTANT: PLEASE RUN CONVART.EXE ON ALL ARTWORK FILES! (If you have not
+ already). It will convert PICS.ART in the old format to
+ TILES.ART in the new format, so you may have to do some
+ renaming when converting artwork and also rename the loadpics
+ line in your C file. BUILD WILL NOT RUN UNLESS YOU DO THIS!
+ With the new artwork file, the tiles can now be any size from
+ 1*1 to 1024*240 and they no longer have to be powers of 2.
+ This feature allows parallaxing skies that are 1024 pixels wide
+ to cover all 360, or 320 pixel wide status bars. It can also
+ be used to display 320*200 title screens.
+ - When pressing 'U' in EDITART, you can now change directories
+ and the current loading directory will be remembered.
+ - When pressing 'U' in EDITART, you can press the mouse button to
+ readjust the size of the tile.
+ - When pressing 'U' in EDITART, press ENTER for an automatic
+ palette conversion or press SPACE BAR for no conversion.
+ - Walls that are Blocked ('B') in BUILD are now shown in pink.
+ If the wall does not show pink in your board, just press
+ 'B' twice to permanently fix it.
+ - Made smooshiness values easier to work with. Hold down 5 on the
+ keypad with 2/4/6/8 to align the walls to multiples of the
+ tile that is used. Also, when you do Tab and L.Enter for
+ Copy&Paste, the y-repeat values stay the same, and the
+ x-repeat values are adjusted so the pixels of the bitmaps
+ have a square-aspect ratio.
+ - Added masked walls. But since they don't quite work perfectly
+ yet, and they are extremely hard to edit now, so for now, just
+ enjoy the technologiy in DOOM1.MAP. Don't worry - you'll get
+ your hands on this soon!
+ - Fixed the "earthquake" effect on really high walls. The walls
+ will not move up and down, but the pixel fuzzyness bug is
+ still in there.
+ - Put door variables and tile information into BUILD.H for you to
+ play around with.
+ - Made walls, ceilings, and floors also work with the animation
+ attribute in EDITART.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+3/2/94 - Made power of 2 size tiles work with ceilings & floors.
+ - When using different size ceilings & floors, made an option in
+ 3D EDIT MODE. If you want a tile to be smooshed into the normal
+ 64*64 area, press 'E' to unExpand the tile.
+ - Groudraws now look more cubical than before. (But be careful of
+ crashing with them for now)
+ - IMPORTANT: Changed the Board format. If you tried running BUILD
+ before reading this, and it didn't work, shame on you! You
+ should always look at the history section of BUILD.TXT first!
+ Since from now on, I am writing Board/Art converters, I am
+ giving you CONVMAP.EXE to convert maps. You can type either:
+ C:\BUILD>convmap house.map
+ to convert an individual map or:
+ C:\BUILD>for %i in (*.map) do convmap %i
+ to convert all the maps in a directory.
+
+ - IMPORTANT: Sprites are now on 2 different sets of doubly-linked
+ lists. The big advantage of this method is that when sprites
+ are deleted, there can be holes in the sprite list with
+ no slow down. Before I used to have linked lists for each
+ sector pointing to all the sprites in it. Well, I have updated
+ that and added more linked lists that tell whether sprites
+ are active or inactive (not a fun thing to progam) But not
+ to worry, you don't have to deal with changing the linked
+ lists, thanks to my very easy function calls. YOU WILL
+ HAVE TO CHANGE YOUR CODE TO SUPPORT THE NEW LINKED LISTS.
+ You should know how to search through each list. See BUILD.H
+ for a detailed description of how the linked lists work, and
+ see the top of this file for description of the new sprite
+ function calls.
+
+ insertsprite(short sectnum, short statnum);
+ deletesprite(short spritenum);
+ changespritesect(short spritenum, short newsectnum);
+ changespritestat(short spritenum, short newstatnum);
+
+ In your code, you will have to change the following:
+ firstsprite[spritenum] --> headspritesect[spritenum]
+ sprite[spritenum].point2 --> nextspritesect[spritenum]
+
+ Also, you should change the part of your main loop that scans
+ through all the active sprites to look more like this:
+
+
+ i = headspritestat[1]; //head of active sprite list
+ while (i != -1)
+ {
+ nexti = nextspritestat[i]; //back up next sprite in case current
+ //one is deleted.
+
+ //your code goes here (use i as the sprite number)
+
+spriteisdeletedskip:
+ i = nexti; //go to next sprite
+ }
+
+
+
+ - Added tagging (naming) to any sector, sprite, or wall. That means
+ you can change a tag in the BUILD editor by pressing T with the
+ mouse cursor on the highlighted sector. And in GAME.C, you
+ can access the tag this way:
+ sector[sectnum].tag;
+ sprite[spritenum].tag;
+ wall[wallnum].tag;
+ Note: All 3 types of tags are long integers, but in BUILD.C
+ you can only make them short integers. I am planning to
+ let you use the upper 16 bits of the tag byte as use for
+ you only. (like permanently unreserved bits)
+ - Added serial link. But it doesn't work very well yet. You
+ may have to try going into GAME several times before it works.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+3/15/94 - Fixed maskable walls - now sort out with sprite better. Easier
+ to edit. Simply press 'M' at a place where a maskable wall
+ should be (like where you normally press 'B' for blocking)
+ - Can flip walls, masked walls, and sprites x-wise by pressing
+ 'F' in 3D EDIT MODE. Also, it is possible to save space in
+ sprite rotations, by flipping it x-wise by programming one of
+ the bits in sprite[].cstat.
+ - A few other minor things, but I forgot what they were.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+3/19/94 - Fixed one of the many crashing bugs.
+ For Duke Nukem III team:
+ CITY.MAP will not crash anymore with new version. The
+ reason it crashed was because in your TILES.ART, you had
+ either ANMFD:0, ANMBK:0, or OSCI:0. That caused a MOD 0
+ in my animation routine. I bullet-proofed that. How about
+ fixing tiles #34, #112, or #114 in your TILES.ART.
+ - Wrote divide by zero handler. Now if there is a divide by zero,
+ BUILD goes back into text mode and fills the screen with
+ /0/0/0/0/..., then gives a DOS prompt. (In other words, you
+ don't have to type "MODE CO80" anymore for /0 crashes)
+ - Optimized routines in assembly for 486's using my great new
+ Intel 32-bit optimizing techniques book that dad got for me.
+ - Fixed ALT-S in BUILD so ANY white loop can be converted into a
+ red loop except for the 1 and only 1 outermost white loop.
+ - FINALLY! Splitsector bug is fixed! You can now split a very
+ complicated sector with tons of sectors inside it or with
+ plenty of sprites. Also sprites will not get deleted
+ spontaneously with split sector any more.
+ - Ctrl-Enter in 3D EDIT MODE is like the normal Enter paste key,
+ but Ctrl-Enter pastes the attributes to an entire loop of
+ walls (if a wall is highlighted).
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+3/22/94 - Added doors that open left and right. See sector[].tag #9 in the top
+ of this file for details - also look at my board, NUKELAND.MAP,
+ in BUILD to see how to make this type of door.
+ - Increased the number of status lists. You may recall my active /
+ inactive sprite lists called headspritestat, prevspritestat,
+ and nextspritestat. Don't worry - you will NOT have to
+ change any of your code. The only thing I changed is now
+ you can have 1024 different lists of sprites rather than just
+ 2 lists if you want to use them. For example, you might want
+ to run through all the brown monsters on the board. Instead
+ of putting all different types of monsters on the active
+ list, it is faster to have a separate list just for brown
+ monsters. Use your imagination!
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+3/31/94 - Fixed some palette problems with EDITART. Now when you press 'P'
+ in 'U' mode, the palette of all the existing tiles are
+ converted to the new palette. Also the text colors should
+ be similar colors on different palettes now.
+ - Changed bit 0 of sprite[].cstat to the hitscan checking / ignoring
+ bit. You should set this bit to 1 for monsters, 0 for
+ bullets, 0 for pick-upable objects like coins, and 1 for
+ objects like columns. Right now, (Since it's not in the
+ BUILD editor), you must set these bits in your code right
+ after you load the board.
+ - I did not document the neartagsector, neartagwall, and
+ neartagsprite very well, so if you don't know how to use
+ them alreay, please read on. These 3 variables are modified
+ by the engine every time you call draw3dscreen(). These
+ variables are usually -1. These variables will be >= 0 if
+ all of these cases are true:
+ 1. You are looking at a wall, sprite, or sector.
+ 2. You are close enough to the wall, sprite, or sector
+ to be able to use the action key with it.
+ 3. The tag of the wall, sprite, or sector is greater or
+ equal to 1.
+ As you can see, neartagsector makes a perfect variable for
+ detecting whether or not you are opening a door. You can
+ also use neartagwall for switches on walls. Also, you can
+ use neartagsprite for sprites that are switches.
+ - PROGRAMMERS: PLEASE MAKE THESE EASY CODE MODIFICATIONS:
+ I reversed the way variables are stored in BUILD.H.
+ Now the variables will be local to the ENGINE and externed
+ to GAME. Before they were local to GAME and externed to the
+ engine. All you have to do is this:
+ 1. You can remove the #define MAIN if you want to.
+ 2. Delete the externs declarations that I used to have
+ in the beginning of GAME.C, because I put them in
+ BUILD.H. I will try not to put externs in the GAME
+ in the future to save you the time of copying and
+ pasting code. Here is a list of externs I moved:
+
+ EXTERN short neartagsector, neartagwall, neartagsprite;
+ EXTERN long *animateptr[MAXANIMATES], animategoal[MAXANIMATES];
+ EXTERN long animatevel[MAXANIMATES], animatecnt;
+ EXTERN short tilesizx[MAXTILES], tilesizy[MAXTILES];
+ EXTERN long numtiles, picanm[MAXTILES], waloff[MAXTILES];
+ - Added a global parallaxing sky type variable. Now I have 3
+ different types of parallaxing skies. Here they are:
+
+ 0 - Totally flat parallaxing sky.
+ 1 - X-only stretching parallaxing sky (This is what DOOM uses).
+ 2 - X- and Y- stretching parallaxing sky. (This is what BUILD
+ uses by default)
+ A good place to set the parallaxing sky is right after you
+ call initengine().
+ - Added local tile selection to the BUILD editor. This means
+ that when you press V on a sprite, you will see only the
+ sprites that are on the level so far. If you want to use
+ a sprite that is not already used on the current board, press
+ V again and you will be able to select from the huge list
+ that you are used to from before. The local tile list will
+ be sorted according to how much each tile is used on the
+ current board. Note that the local tile list will be
+ different depending where the mouse cursor was left when you
+ pressed V (or H).
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+4/4/94 - Changed the way ART files work. YOU MUST READ THIS:
+ There are some two easy things that you must do 2 things before
+ you can use the new engine:
+
+ 1. Type CONVART1.EXE to convert your ARTWORK to the new
+ format. (If I forgot to send this file to you, please call
+ and torture me.) Now, instead of everything being stored
+ in one huge file, TILES.ART, I am splitting the artwork into
+ several files each holding 256 tiles in it. This will allow
+ you to make infinitely large artwork files in EDITART.
+
+ 2. In GAME.C, you must change the line,
+ loadpics("tiles.art");
+ to:
+ loadpics("tiles000.art");
+ All you have to give loadpics is the first filename of your
+ artwork, and the engine will automatically know how to
+ modify the 3 digits at the end and load all the artwork
+ files properly.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+4/5/94 - Fixed the "fuzzy" pixels on high walls. Now you make walls as
+ high as skyscrapers, and when you look at it up close, the
+ pixels will still look like perfect rectangles. Note: This
+ fix may require you to press 'O' in 3D EDIT MODE to put
+ your boards back to normal.
+ - When you pressed ENTER on weird-sized tiles, sometimes in the old
+ version the pixels would not be square aspect ratio. Now
+ when you press ENTER, they will be.
+ - You can now set the starting position in 2D EDIT MODE with the
+ Scroll Lock key. The starting position will look like a
+ brown arrow, and your current position will look like a
+ white arrow. Now you don't have to keep returning to start
+ when you save your board.
+ - Added some new things to the structures - guess what this means?
+ CONVMAP3! THE NEW OBJ'S and BUILD will NOT work until you
+ run CONVMAP3. (Please call if I forgot to give
+ you this file)
+ Notice that I added these things to the structures:
+
+ sectortype:
+ bit 2 of ceilingstat&floorstat:
+ 1 = North/South panning, 0 = East/West panning
+ char ceilingpanning, floorpanning;
+ walltype:
+ bit 6 of cstat
+ 1 = Vertical panning, 0 = Horizontal panning
+ char panning;
+ short overpicnum;
+ spritetype:
+ char *extra;
+
+ Now an explanation of each:
+ To the sector structure, I added the capability to pan
+ the floors and ceilings. Usually ceilingpanning and
+ floorpanning are set to 0. For example, a good way to make
+ an earthquake would be to randomly increment or decrement
+ to panning values. To allow you to pan the ceilings or
+ floors at any of the standard 90 degree angles, I made
+ bit 2 of sectortype's ceilingstat/floorstat byte choose
+ whether the ceilingpanning/floorpanning byte should move
+ the ceiling/floor North/South or East/West.
+ To the wall structure, I added panning also. Bit 6
+ of cstat and the panning values work in the same as the
+ ceilings and floors.
+ To the sprite structure, I added only 1 variable.
+ The "extra" pointer is intended for your use only, so you
+ can have the sprite's structure extended if you so desire.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+4/6/94 - In 2D EDIT MODE, you can now press ESC to get a message in the
+ message bar that says this:
+
+ (N)ew, (L)oad, (S)ave, (Q)uit
+
+ And it all works too. (Press ESC to cancel)
+ Loading lets you select the file just like 'U' in EDITART.
+ - The old version of BUILD had the coordinate system all screwed
+ up in 2D EDIT MODE. I fixed this. Included with
+ CONVMAP3.EXE is a conversion utility that will make your
+ boards have the same orientation as in the older BUILD
+ editors. If you don't care if the whole map gets rotated
+ in the 2D editor, then press N.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+4/7/94 - Changed the way Orientation works ('O' in 3D EDIT MODE)
+
+ Now, when you draw a normal door in BUILD, you do NOT have to
+ press 'O' everywhere to make the walls of the door move right.
+ Now, the default is that everything moves right. Here's a
+ detailed description of how the new orientation works:
+
+ For white lines (no neighboring sector):
+
+ orientation = 0 (default) means picture is aligned with
+ sector[].ceilingz.
+ orientation = 1 means picture aligned with sector[].floorz.
+
+ For red lines (has a neighboring sector):
+
+ orientation = 0 (default) means picture is aligned with
+ either the ceilingz or floorz of the next sector.
+ orientation = 1 means picture aligned with
+ sector[].ceilingz.
+
+ Don't worry if you don't understand the detailed description.
+ Just know that it's better this way. I have included the
+ proper conversions in CONVMAP3.EXE.
+ - Added wall&ceiling x-panning keys to the 3D EDIT MODE. Press
+ the , or . keys to pan a wall or ceiling left or right. You
+ can hold down the 5 key on the keypad to align at every eighth
+ panning value. (Just like with 2,4,6,8).
+ - Made TAB&ENTER in 3D EDIT MODE also copy the CSTAT byte of
+ the wall's attributes. This means that attributes such as
+ the block attribute, 1-way wall attribute, orientation,
+ and x-flipping attribute are also copied & pasted.
+ - Added a new function, cansee.
+
+ cansee(long x1, long y1, long z1, short sectnum1,
+ long x2, long y2, long z2, short sectnum2)
+
+ All you do is pass it the coordinates of a 3D line
+ and the respective sectors of each point of the line.
+ The function will return a 1 if the points can see each
+ other or a 0 if there is something blocking the two points
+ from seeing each other. This is how I determine whether
+ a monster can see you or not. Try playing DOOM1.DAT with
+ digitized sound enabled to fully enjoy this great new
+ function!
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+4/12/94 - Fixed HITSCAN function. Since it works a little differently
+ and the parameters are different, let me describe how the
+ new hitscan works:
+
+ hitscan(long xstart, long ystart, long zstart, short startsectnum,
+ long vectorx, long vectory, long vectorz,
+ short *hitsect, short *hitwall, short *hitsprite,
+ long *hitx, long *hity, long *hitz);
+
+ Pass the starting 3D position:
+ (xstart, ystart, zstart, startsectnum)
+ Then pass the 3D angle to shoot (defined as a 3D vector):
+ (vectorx, vectory, vectorz)
+ Then set up the return values for the object hit:
+ (hitsect, hitwall, hitsprite)
+ and the exact 3D point where the ray hits:
+ (hitx, hity, hitz)
+
+ How to determine what was hit:
+ * Hitsect is always equal to the sector that was hit
+ (always >= 0).
+
+ * If the ray hits a sprite then:
+ hitsect = thesectornumber
+ hitsprite = thespritenumber
+ hitwall = -1
+
+ * If the ray hits a wall then:
+ hitsect = thesectornumber
+ hitsprite = -1
+ hitwall = thewallnumber
+
+ * If the ray hits the ceiling of a sector then:
+ hitsect = thesectornumber
+ hitsprite = -1
+ hitwall = -1
+ vectorz < 0
+ (If vectorz < 0 then you're shooting upward which means
+ that you couldn't have hit a floor)
+
+ * If the ray hits the floor of a sector then:
+ hitsect = thesectornumber
+ hitsprite = -1
+ hitwall = -1
+ vectorz > 0
+ (If vectorz > 0 then you're shooting downard which means
+ that you couldn't have hit a ceiling)
+
+ - Added a position window to the bottom of the menu in 2D EDIT
+ MODE. It shows the posx, posy, and ang variables.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+4/14/94 - Overwritesprite now clips to the startumost / startdmost arrays.
+ Now the only way to write to the status bar is with
+ the permanentwritesprite function.
+
+ - ATTENTION PROGRAMMERS! I Split draw3dscreen() into 2 separate
+ function calls.
+
+ old: draw3dscreen(); //Draws walls, ceilings, floors, p-skies
+ // groudraws, sprites, and masked walls.
+
+ new: drawrooms(); //Draws walls, ceilings, floors, p-skies
+ // and groudraws.
+ drawmasks(); //Draws sprites and masked walls.
+
+ The reason I split draw3dscreen was so you could manipulate only
+ the sprites that the engine is going to draw to the screen
+ before the sprites are actually drawn.
+
+ - I think I may have fixed that darn sector line bug! Before, the
+ bug usually appeared when you were on a (red) sector line where
+ the ceiling and floor of the sector were very far from each
+ other. This overflowed some really high positive values into
+ the negative range and vice versa.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+4/18/94 - Wall clipping now works much better! (You can still VERY RARELY
+ sneak through walls, however)
+ ATTENTION PROGRAMMERS:
+ MOVESPRITE and CLIPMOVE have been changed. They now look
+ like this:
+
+ clipmove (long *x, long *y, long *z, short *sectnum,
+ long xvect, long yvect, long walldist,
+ char cliptype);
+
+ movesprite(short spritenum,
+ long xchange, long ychange, long zchange,
+ long walldist, char cliptype);
+
+ To use the new clipmove:
+ Pass the pointers of the starting position (x, y, z). Then
+ pass the starting position's sector number as a pointer also.
+ Also these values will be modified accordingly. Pass the
+ direction and velocity by using a vector (xvect, yvect).
+ If you don't fully understand these equations, please call me.
+ xvect = velocity * cos(angle)
+ yvect = velocity * sin(angle)
+ Walldist tells how close the object can get to a wall. I use
+ 128L as my default. If you increase walldist all of a sudden
+ for a certain object, the object might leak through a wall, so
+ don't do that!
+
+ To use the new movesprite:
+ Works like before, but you also pass walldist (How close the
+ sprite can get to a wall)
+
+ - New function for sprites:
+ setsprite(short spritenum, long newx, long newy, long newz);
+
+ This function simply sets the sprite's position to a specified
+ coordinate (newx, newy, newz) without any checking to see
+ whether the position is valid or not. You could directly
+ modify the sprite[].x, sprite[].y, and sprite[].z values, but
+ if you use my function, the sprite is guaranteed to be in the
+ right sector.
+
+ - You can now change the angle in 2D EDIT MODE with the
+ < and > keys. Move the mouse cursor to a sprite first.
+ Hold down shift with the < and > to get more precise angles.
+ - You can now press 'B' on sprites in 3D EDIT MODE. This in effect
+ is xoring bit 0 of sprite[].cstat, which will not only be
+ sensitive to hitscan, but will also block you from walking
+ through the sprite. Sprites with the 'B' attribute will
+ appear pink in 2D EDIT MODE.
+ - You can now edit the Hi 16 bits of the tag in 2D EDIT MODE.
+ Just like T and ALT-T, you press H and ALT-H to edit the high
+ 16-bits. When a structure's attributes are displayed, the tag
+ will be displayed as 2 unsigned shorts. The first number
+ represents the hi 16 bits and the second number represents the
+ lo 16 bits.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+4/23/94 - Added 'G' in Editart to GOTO a tile by typing in the tile number.
+ - Changed the way masking walls work a little bit. Now the
+ masking walls use the picture wall[].overpicnum rather than
+ wall[].picnum.
+ - Made hitscan hit maskable walls.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+4/24/94 - Made palette.dat support any number of shades up to 64. There
+ is no change to the palette.dat format. The palette.dat
+ format is:
+
+ First the palette (768 bytes) Values range from 0-63
+ Then the lookup shades (256 * number_of_shades) The
+ shades are stored in groups of 256 bytes.
+
+ - If you use Mark Dochtermann's palette program, then you can
+ convert his data files (such as palette.pal and colormap.lmp)
+ to my palette format, palette.dat, with my great Qbasic
+ program, PALMP.BAS. To run it, first copy the basic program
+ into the same directory as the 2 source palette files are in.
+ Then type: "QBASIC PALMP" and then press SHIFT+F5 (to run it).
+
+ - Added a global variable, HORIZ. Horiz usually equals 100.
+ Modifying horiz will move the whole screen up / down. I
+ added 2 keys, +/- in my own game.c to demonstrate this. You
+ can use this variable for looking up and down if you want.
+ (Even though this is not "truly" looking up and down, if
+ you're lucky, you might be able to fake out some people!)
+
+ - New Key in 3D EDIT MODE, the forward slash. Use / with the
+ tile panning keys (, and .) to flip the horizontal / vertical
+ orientation bits for walls, ceilings or floors.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+4/28/94 - NEW BOARD VERSION! You must run CONVMAP4.EXE on all your boards.
+ Here's what I changed in the structures:
+
+ Sectors:
+ I got rid of:
+ char sector[].ceilingpanning, sector[].floorpanning;
+ sector[].ceilingstat/floorstat bit 2 zeroed out
+ and added:
+ char sector[].ceilingxpanning, sector[].ceilingypanning;
+ char sector[].floorgxpanning, sector[].floorypanning;
+
+ Walls:
+
+ I got rid of:
+ char wall[].panning;
+ wall[].cstat bit 6 zeroed out
+ and added:
+ char wall[].xpanning;
+ char wall[].ypanning;
+
+ Sprites:
+
+ I got rid of:
+ short sprite[].vel;
+ and added:
+ short sprite[].xvel;
+ short sprite[].yvel;
+ The reason I did this was so sprites could be moved in
+ different directions than sprite[].ang. Please make
+ use of both xvel and yvel. Here's the equation I would
+ use to convert from the old to new. For example:
+
+ old:
+ sprite[i].vel = 256;
+ new:
+ sprite[i].xvel = (sintable[(sprite[i].ang+512)&2047]>>6);
+ sprite[i].yvel = (sintable[sprite[i].ang&2047]>>6);
+
+ The reason I am shifting the sines right by 6 is becuase
+ my sintable ranges from -16384 to 16384. Dividing by
+ 64 gives a maximum range of -256 to 256.
+
+ CONVMAP4.EXE also attempts to convert the masked walls so
+ overpicnum is the masked wall's picnum.
+
+ - Changed 3D EDIT MODE panning keys:
+ Since panning is now all 4 directions, I got rid of the
+ , and . keys and put the keys on the keypad using 2,4,6,8.
+ Usually 2,4,6,8 are for x- and y-repeats, but if you hold
+ down either shift key, then they act as x- and y- panning
+ values.
+ The / key now resets the panning values to 0.
+
+ - Please read the updated descriptions of how to make masking walls
+ in the 3D EDIT MODE KEYS in the top of build.txt. See
+ the 'M' and 'Shift + M' keys.
+
+ - Also look at the top of this file for a description of dragpoint(), a
+ great new function that makes it easy to morph sectors.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+4/29/94 - Added some minor keys to 3D EDIT MODE. Alt. +/- change the
+ visibility variable. It ranges from 5 (darkest) to 17
+ (lightest) and it starts at 13.
+
+ - Made 1-way walls have more options. Now, for example, you can
+ make rectangular switches on walls. Please look at my
+ nukeland.map for an example of how to do switches. (The
+ switches are close to start - just go through the door and
+ bear left.)
+
+ - For those who asked, here's how some sample bobbing code:
+ First, calculate the distance actually moved - because if you
+ are not moving then you shouldn't bob:
+
+ CODE:
+ oposx = posx; oposy = posy;
+ clipmove(&posx,&posy,&posz,&cursectnum,xvect,yvect,128L);
+ dist = ksqrt((posx-oposx)*(posx-oposx)+(posy-oposy)*(posy-oposy));
+
+ Then modify the horizon value by multiplying the distance
+ actually moved by a sine wave. (default is horiz = 100).
+
+ CODE:
+ horiz = 100 + ((dist*sintable[(totalclock<<5)&2047])>>19);
+
+ - Remember that moving block in the slime in NUKELAND.MAP? It
+ works a lot better now. I am now modifying the floor panning
+ values to make the floor match up correctly with the block.
+
+ - Fixed the screen capturing (F12) to save captures as PCX files.
+ This is for BUILD, GAME, and EDITART.
+
+ - Fixed bug in EDITART when you press 'U' on a blank tile. It
+ should not crash any more.
+
+ - Made Tab & Enter a little smarter in copying the right attributes
+ to different types of objects.
+
+ - Added ceiling / floor 90 rotation attributes. All 8
+ rotations are possible. 3 bits have been added to both
+ the sector[].ceilingstat and sector[].floorstat flags.
+ If you look in BUILD.H, you will see the new flags
+ descriptions. You can use the 'F' key in 3D EDIT MODE on
+ a ceiling or floor to change the rotation.
+
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+4/30/94 - ATTENTION PROGRAMMERS:
+ I removed the function, getsector, and added a more expandable
+ function, updatesector. Also, updatesector is smart enough
+ to check to see if you are in the same sector OR neighboring
+ sectors first before going through every single sector.
+ Getsector used to go though all the sectors every time you
+ crossed a sector line.
+
+ getsector(); (no arguments, returns nothing - REMOVED)
+ * used to make sure that CURSECTNUM matched up with
+ the right sector according to the POSX and POSY values.
+ updatesector(posx,posy,&cursectnum);
+ * the new way of writing getsector. You can do a
+ search&replace on your code. Be careful when you use this
+ function with sprites because remember that the sprite's
+ sector number should not be modified directly. For example,
+ you might want to code it this way:
+
+ tempsectnum = sprite[i].sectnum;
+ updatesector(sprite[i].x,sprite[i].y,&tempsectnum);
+ if (tempsectnum != sprite[i].sectnum)
+ changespritesect(i,tempsectnum);
+
+ Actually, I think the setsprite function is better for
+ updating a sprite's sector number.
+
+ - Added swinging doors! Look at NUKELAND.MAP in my GAME.EXE for
+ an example. For swinging doors, I used a new math-helper
+ function, rotatepoint.
+
+ rotatepoint(long xpivot, long ypivot,
+ long x, long y,
+ short deltaang,
+ long *x2, long *y2);
+
+ Rotatepoint will rotate point(x,y) around point(xpivot,ypivot)
+ by the deltang value. The resultant point will be s
+
+ - Fixed crashing bug in BUILD when a wall's tile doesn't exist.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/02/94 - I improved the pre-level check on the swinging doors, so now
+ you can have multiple doors in a sector that open any way.
+ This is how I do my double swinging doors (demonstrated in
+ NUKELAND.MAP)
+
+ - I added a revolving door! See NUKELAND.MAP for an example. (The
+ revolving door is beyond the bouncing platforms in the slime
+ pit)
+
+ - Fixed bug with joining sectors in 2D EDIT MODE. The sprites
+ don't get deleted any more.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/04/94 - Optimized the masked walls.
+
+ - Cleaned up the sprite drawing code (and many bugs that that came
+ along with it.)
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/05/94 - Made cylindrical walls with any number of points VERY easy to
+ make in BUILD. Here's how you do it: Highlight a wall and
+ press 'C' on it. Then move the mouse to the proper position
+ to make a nice circle. You can press '+' or '-' to change
+ the number of points on the circle. Press 'C' again to cancel
+ or press space bar to actually change the map.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/07/94 - Made a fully-operational subway! Look at subway.map.
+
+ - Made a new type of door - a sliding door where the door doesn't
+ get "x-smooshed" when it is opened. (See description of
+ sector tag 16 & wall tag 6)
+
+ - Also note that I my first subroutine in game.c! It is:
+ operatesector(short dasector)
+ All the door code is now in this function (with a few
+ exceptions, such as parts of the swinging doors and revolving
+ door)
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/08/94 - Made EDITART and BUILD support different tile sizes in 'V' mode.
+ Here are the three possible sizes:
+ 0. 64*64 - 5*3 grid - views 15 tiles (old default)
+ 1. 32*32 - 10*6 grid - views 60 tiles (new default)
+ 2. 16*16 - 20*12 grid - views 240 tiles
+ Press the '*' and '/' keys in 'V' mode if you want to change
+ the grid resolution.
+
+ - Added/fixed up a new key in 3D EDIT MODE, the dot key (. or >)
+ This key attempts to match up all the tiles along a wall. It
+ scans along the walls towards the right as long as the picture
+ number of the next wall is the same as the original picture
+ number. Note that some walls may not work right, especially
+ floor / ceiling steps.
+
+ - Made 2D EDIT MODE default to this when inserting sprites:
+ 1. Sprite clipping = on for sprites taller than 32 pixels
+ 2. Sprite clipping = off for sprites shorter than 32 pixels.
+
+ - Fixed sprite clipping with Z-coordinates
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/10/94 - Fixed some sprite dragging bugs
+
+ - Made neartag? maximum sensing distance a global variable called
+ neartagdist. See build.h.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/11/94 - Added sector / groups of sectors selection. When selecting
+ sectors, hold down the right ALT key. It works just like
+ right shift. You must completely surround any sector you
+ wish to select. Once selected, you can drag the mess of
+ sectors with the mouse. This is great for separating sectors
+ from each other.
+
+ - Added sector duplication. First select a bunch of sectors. Then
+ press the insert key. (with the select sectors flashing) Then
+ This duplication is like stamping. So, you must drag
+ the sector bunch somewhere else after stamping to see your
+ great accomplishments.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/12/94 - Added group-sector PGUP / PGDN. Here's a neat trick that will
+ let you move a whole section of a board up / down quickly.
+ First you select a bunch of sectors with the right ALT key in
+ 2D mode. Then flip to 3D mode and if you press PGUP / PGDN
+ on any of the highlighted sectors, the rest of the highlighted
+ sectors will move also.
+
+ - Added group-sector rotation. Once you do a sector select (right
+ ALT), you can press the , or . keys to rotate the selected
+ sectors. Hold down the shift key with the keys to get fine
+ angle rotation (WARNING: You will get distortion with fine
+ angle rotation in this version)
+
+ - Added sector count and wall count information at the bottom of
+ the 2D edit mode status bar.
+
+ - Fixed some stupid bug that you probably wouldn't have found if
+ you made boards with BUILD for the rest of your life.
+
+ - You can now press 'B' to block / unblock a wall or sprite in
+ 2D edit mode.
+
+ - Made Ctrl-Shift Enter auto-shade a sector. First make any
+ wall of the loop as light as the lightest shade you want.
+ Then make any other wall of the loop as dark as the darkest
+ shade you want. Finally press Ctrl-Shift Enter on the wall
+ that should be lightest. Now the loop should be smoothly
+ shaded. If it is not smoothly shaded, you may need to insert
+ more points on the walls.
+
+ - Fixed my .PCX format bug. My screen captures now load properly
+ in Deluxe programs.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/13/94 - Made my serial code in Game.c work better. I fixed the bullet
+ shooting and made all types of doors work. Unfortunately, you
+ still may have to run at slower COM speeds.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/14/94 - Fixed deadly bug with sector copy & sprites.
+
+ - Added hitscan sensitivity bit. It is bit 6 (64) of wall[].cstat.
+ In 3D edit mode, you can press 'H' to toggle the bit. (H used
+ to be like 'V' for choosing height tile numbers for groudraws -
+ I change the 'H' key to Alt-V since I don't think anybody was
+ using it anyway) By default, hitscan CAN go through maskable
+ walls. If a hitscan is set to not go through a maskable wall,
+ The wall will appear BRIGHT pink in 2D edit mode.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/15/94 - Made more subroutines in game.c and moved documentation from the
+ end of game.c into this text file. Added some more comments
+ also. Game.c is so much easier to read now! The main loop is
+ less than 50 lines long!
+
+ - Made some optimizations to my serial code now that everything
+ is in functions.
+
+ - ATTENTION PROGRAMMERS:
+ I added one new paramater (cliptype) to both the movesprite
+ and clipmove functions. If the new parameter is a 0, then
+ the clipping is normal (Use 0 to clip you and monsters).
+ If the new parameter is a 1, then the object is clipped to
+ the same things that hitscan is clipped to (use 1 for all
+ bullets).
+ See the above documentation for a detailed description of the
+ parameters. (Remember that I moved the documentation from
+ GAME.C into the middle BUILD.TXT)
+ Finally, you can have sprites and bullets going where you
+ want them to go!
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/18/94 - Added support for the Spaceplayer (6-degree of freedom Space ball)
+ Try out the SETUP program now.
+
+ - Fixed some bugs with the 'E' key in 3D EDIT MODE. As long as both
+ dimensions of the tile are powers of 2, then the picture should
+ be visible. It should not be a solid color with a few weird
+ lines any more.
+
+ - Fixed some bugs with the Z control in 3D EDIT MODE. In normal
+ operation, BUILD attempts to keep your Z constant even if
+ you cross sector lines. Then I added a special new mode that
+ locks your heightofffloor to a certain value. You Z will
+ change instantly if you cross sector lines. To use this mode,
+ press the Caps Lock key. Press Caps Lock key again for normal
+ operation.
+
+ - ATTENTION PROGRAMMERS! I put all of engineinput into GAME.C
+ This means you have absolutely total control of the Z's. (The
+ only thing left is some key code I still have in my timer
+ handler)
+
+ OK, now read carefully! Here's how to convert to the new OBJ's:
+
+ 1. First of all, the Spaceball code is now also in game.c.
+ A. You will need to put this line in game.c:
+ include "spw_int.h"
+ B. And make sure to add spwint.obj your makefile.
+ 2. Heightoffceiling, heightofffloor, and gravity have been
+ removed from BUILD.H. If you still want to use them
+ then you should defined them as globals in your own code.
+ 3. You should go through every single key of my gameinput()
+ function in game.c and copy any code you want.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/23/94 - GREAT NEW STUFF!
+
+ Be sure to check out GAME.EXE and try out these new keys!
+
+ Rt. Enter = Switch between 3D / 2D modes
+ Lt. +/- = Zoom in 2D mode
+
+ Added 2D map display with auto-mapping! The 2D maps use a
+ higher resolution 16-color mode. You have a choice of either
+ using a 640*350*16 screen or a 640*480*16 screen with a 144-high
+ status bar (remember that 640*480*16 cannot fit in 256K with 2
+ screen pages so I have to cheat with a status bar).
+
+ NEW FUNCTIONS:
+
+ draw2dscreen(long posxe, long posye, short ange, long zoome,
+ short gride)
+ Draws the 2d screen - this function is a direct replacement
+ for the drawrooms() and drawmasks() functions. Be sure
+ to call either qsetmode640350() or qsetmode640480()
+ first. When switching back to 3d mode, be sure to call
+ qsetmode320200().
+
+ IMPORTANT NOTES:
+ 1. The overwritesprite function should only be called in
+ 3D mode. If you do this in 2D mode, junk will be
+ written to the 2D screen and a crash is possible.
+ 2. When you switch back to 3D mode, you should call the
+ permanentwritesprite functions to draw the status bar,
+ or whatever else you have to draw.
+ 3. You must call the nextpage() function in both 2D and
+ 3D modes.
+
+ qsetmode320200();
+ Set to the game mode and load palette (320*200*256)
+ qsetmode640350();
+ Set to the 2D map mode #1 (640*350*16)
+ qsetmode640480();
+ Set to the 2D map mode #2 (640*480*16)
+
+ NEW VARIABLES (see description in build.h):
+
+ EXTERN char show2dwall[MAXWALLS>>3];
+ EXTERN char show2dsprite[MAXSPRITES>>3];
+ EXTERN char automapping;
+
+ - Added parallaxing floors! Works like the parallaxing skies, but
+ the other side. In 3D EDIT MODE, press P on ceiling for
+ parallaxing sky, or press P on floor for parallaxing floor.
+
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/24/94 - There is a new function that I forgot to document in the last
+ version. Oops!
+
+ doanimations() is this function.
+ It's not really new, but I split it off of the
+ drawrooms/drawmasks functions. This function animates anything
+ that you use setanimation with. Please stick it in your code
+ somewhere after you draw the screen.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/26/94 - You can now do TRANSLUSCENT sprites! I am using bit 1 of
+ sprite[].cstat to detemine whether or not the sprite is
+ transluscent or not. In 3D EDIT MODE, you can press 'T' to
+ toggle the transluscence bit.
+ IMPORTANT: Transluscence WILL NOT WORK until you run my
+ TRANSPAL.EXE program. On the command line, simply type:
+ C:\BUILD>transpal [filename]
+ If you do not specify a filename, the default will be
+ palette.dat. If your palette.dat file is now around 40K long,
+ then you are ready for transluscence!
+
+ - Added TRANSLUSCENCE to masked walls. See bit 7 of wall[].cstat.
+ Press 'T' on wall to toggle the transluscence bit.
+
+ - In this BUILD update, I have collected many different palettes
+ for comparison purposes. Try running TRANSPAL.EXE on each of
+ them and see for yourself which palettes work the best with
+ transluscence!
+
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/29/94 - ATTENTION PROGRAMMERS: I completely rewrote the neartag code.
+ Here's what you have to do to convert your game.c files:
+
+ 1. You should move the neartag variables that I used to
+ have in BUILD.H into your C code.
+ 2. You must call the neartag function yourself if you want
+ to see if you're near a tagged object. Neartag is NOT
+ automatically updated by the engine any more.
+ 3. I highly recommend that you put your neartag function
+ call at the first line in your space bar code. This way,
+ you can optimize the neartag calculations by only doing
+ them when you press the space bar. (Exception: For
+ ladders, I think you'll have to call neartag every single
+ frame)
+
+ Here's a description of the new neartag function:
+ Neartag works sort of like hitscan, but is optimized to
+ scan only close objects and scan only objects with
+ tags != 0.
+
+ neartag(long x, long y, long z, short sectnum, short ang, //Starting position & angle
+ short *neartagsector, //Returns near sector if sector[].tag != 0
+ short *neartagwall, //Returns near wall if wall[].tag != 0
+ short *neartagsprite, //Returns near sprite if sprite[].tag != 0
+ long *neartaghitdist, //Returns actual distance to object (scale: 1024=largest grid size)
+ long neartagrange) //Choose maximum distance to scan (scale: 1024=largest grid size)
+
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/31/94 - Added a function to get a sprite's screen coordinates. I put
+ some sample code in my GAME in the analyzesprites function.
+ Simply hold down the CAPS LOCK key in my GAME.EXE, and the
+ screen will be centered around the sprite closest to the
+ center of the screen.
+
+ Here's a new function in the engine I used to do this:
+
+ getspritescreencoord(short spritesortnum, long *scrx, long *scry)
+
+ Note that spritesortnum is the index into the spritesortcnt
+ arrays, NOT the normal sprite arrays. Scrx and scry are actual
+ screen coordinates ranging from 0-319 and 0-199 respectively.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+6/6/94 - Made EDITART support sprite centering and animation speed.
+
+ Now when you press 'A' in EDITART, the animation speed is
+ actually saved to disk and runs the same speed in BUILD
+ and your GAME. Press + and - to change the animation speed.
+ There are 16 different animation speeds.
+ (Speed is proportional to (totalclock>>animspeed))
+
+ To center a sprite, press the weird ~` key (located just above
+ the TAB key). You will see some cross hairs. Simply use
+ the arrow keys to the desired position.
+
+ For both the 'A' and ~` keys, you can press Enter to accept
+ the new values or ESC to cancel.
+
+ - Added a variable to BUILD.H, lockclock. Lockclock is to
+ totalclock as lockspeed is to clockspeed.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+6/7/94 - Made 3 different Z coordinate modes in BUILD.
+
+ Mode 0: Game mode (default)
+ Mode 1: Height lock mode
+ Mode 2: Float mode
+
+ Press Caps Lock to switch between the 3 modes.
+ A and Z move up and down for all 3 modes.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+6/10/94 - Added a new function that should solve all your sound problems.
+
+ kenchaintimer(void (__interrupt __far *datimerchainaddress)(),
+ short dachainpersecond)
+
+ Please look at the IMPORTANT ENGINE FUNCTIONS section above for
+ a full description.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+6/20/94 - Got rid of the comsend / comgetchar functions. Replaced them
+ with sendpacket and getpacket.
+
+ - Added network support.
+
+ - Got rid of qsetmode320200(). Just replace it with setgamemode().
+ The 2 are exactly the same.
+
+ - Got rid of clockspeed variables. Just replace it with lockspeed.
+
+ - Adjusted my z directions of shooting depending on the horizon.
+ You may want to readjust your code for this.
+
+ - You now pass the number of tics as a long to doanimations.
+ doanimations(long numtics);
+
+ - FIXED DEADLY BUG! This may have been causing bigtime crash-city
+ bugs! The problem was with show2dsprite and show2dwall. In
+ my engine.c I forgot that they were BIT arrays, not BYTE arrays.
+ When I initialized the arrays to 0, I initialized 8 times the
+ length, possibly overwriting your precious data! I initialize
+ these arrays in the initengine and loadboard functions.
+
+ - ATTENTION PROGRAMMERS: In order to get rid of the posx, posy,
+ posz, ang, posz, and horiz variables from BUILD.H, I added some
+ parameters to a few functions. YOU MUST REWRITE YOUR CODE
+ TO SUPPORT THESE:
+ loadboard(char *filename, long *posx, long *posy, long *posz,
+ short *ang, short *cursectnum)
+ saveboard(char *filename, long *posx, long *posy, long *posz,
+ short *ang, short *cursectnum)
+ drawrooms(long posx, long posy, long posz,
+ short ang, long horiz, short *cursectnum)
+
+ THESE VARIABLES SHOULD BE MOVED INTO GAME.C:
+ long posx, posy, posz, horiz;
+ short ang, cursectnum;
+ long hvel;
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+6/22/94 - ATTENTION PROGRAMMERS: Added 1 parameter to movesprite, the
+ number of tics (such as lockspeed).
+
+ movesprite(short spritenum, long xchange, long ychange,
+ long zchange, long walldist,
+ char cliptype, long numtics)
+
+ - ATTENTION PROGRAMMERS: At one time, I used to have 4 timing
+ variable in the engine. (totalclock, clockspeed,
+ lockclock, lockspeed). I got rid of all of them except
+ totalclock. If you want to use the other 3 variables, you
+ must simulate them yourself. Here's how you do it:
+
+ Step 1. Define clockspeed, lockclock, and lockspeed as global
+ longs in your code.
+
+ Step 2. Be sure to zero out all 3 variables just before
+ starting to play each level. (You could zero out
+ totalclock also.)
+
+ Step 3. Right after every time you call the nextpage()
+ function, insert this code line for line:
+
+ lockspeed = totalclock-lockclock;
+ lockclock += lockspeed;
+ clockspeed = lockspeed;
+
+ You really don't need clockspeed if you have lockspeed.
+ You should replace all clockspeed's with lockspeed's.
+ Before, I had both because both totalclock and clockspeed used
+ to be incremented in the timer handler and could be changed
+ at any time.
+
+ - I added my own optional random function, krand() which returns
+ a pseudo-random number as a long from 0 to 65535. Notice that
+ I put a randomseed variable in BUILD.H called randomseed.
+
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+6/24/94 - I just want to try to explain how all of my multiplayer code
+ works. Theory: Think of the whole program as 2 functions:
+
+ Function 1. Draw the screen (could be 2D / 3D)
+ Function 2. Move things. (sprites, walls, sectors, and you!)
+
+ My communications in GAME.C work on a MASTER/SLAVE
+ system where it would be nice if the faster computer was the
+ MASTER. (Right now, the first computer in is the MASTER).
+ The big trick to keeping everything in sync (and I do mean
+ everything- even moving platforms, revolving doors, & subways)
+ is to call function #2 with the exact same parameters as input
+ on all computers the same number of times and in the same
+ order. Now this might seem like a lot of information but it
+ really isn't! Let me explain the role of the MASTER and SLAVE:
+
+ The MASTER's job:
+ 1. Read in own input changes
+ 2. Read in any slave player input changes
+ (getpackets function - reads in foreign vel, svel,
+ angvel, & the bits)
+
+ 3. Just before calling the movethings function, send the
+ input to the movethings function:
+ A. Master's tic cnt (synctics)
+ B. Every player's velocities (syncvel, svel, angvel)
+ C. Every player's status bits (Space, Ctrl, Shift, etc.)
+ 4. Call the movethings function
+ 5. Draw screen
+
+ The SLAVE's job:
+ 1. Read in own input changes
+ 2. Send own input changes to master.
+ 3. Read in all master movethings input parameters and
+ call movethings function for each packet. This may
+ mean calling the movethings function more than once
+ between calling the drawscreen functions. This is
+ waste, but it's the price you have to pay to keep
+ things in sync.
+ 4. Draw screen
+
+
+ You may ask how do monsters stay in sync even if you are
+ not sending any monster information over the line. The
+ answer to this is simple.
+ 1. You make sure that a random seed starts the same on
+ both computers.
+ 2. Only call the rand() or krand() function in the
+ movethings function.
+
+ Before you try my demo, I wanted to say that, I have
+ ABSOLUTELY NO ERROR CORRECTION in my code at this point. It
+ is most certainly my next project. For serial link, I would
+ recommend a rate of about 14400 baud. In the future, I think
+ I can optimize the code enough to work at rates as low at 2400
+ baud! Let me explain how well certain setups should work
+ without error correction:
+ Ken's guesses on how badly it will crash WITH NO ERROR
+ CORRECTION (Build the way it is now):
+
+ 1. Serial link using 8250 chips - out of sync after 15
+ seconds because a few bytes were missed.
+ 2. Serial link using 16550 chips - out of sync after 10
+ minutes because 16550 chips have a 16 byte FIFO and
+ therefore don't lose bytes as often as the 8250.
+ 3. Modem - out of sync after less than 5 seconds.
+ 4. Network - out of sync after 1 minute. Networks love to
+ lose full packets here and there.
+
+ I will be working on error correction for all of the above
+ situations. Any error correction techniques I use will be
+ internal to the engine and completely transparent to you (so
+ you can start coding now!) If the demo actually works multi-
+ player, then you may want to look at my GAME keys at the top
+ of this file again. There are some significant changes.
+
+ * I replaced the old COM functions section at the top of
+ BUILD.TXT with a COMMUNICATIONS FUNCTIONS section. Please
+ look through it for descriptions of at least these 2
+ functions:
+
+ sendpacket(short otherconnectnum, char *bufptr, short bufleng)
+ getpacket(short *otherconnectnum, char *bufptr)
+
+ * Another rule to keep in mind while testing: (as if there
+ aren't enough already) Always make sure you have the
+ same EXE's and MAP'S or else the games will get out of sync.
+
+ * Connection numbers and Index numbers:
+ For networks, each computer has a given connection number.
+ Connection numbers range from 1 to 100. Player number 1
+ might have connection number 5 and player number 2 might have
+ connection number 17. Since a player's connection number
+ can be anything between 1 and 100, I don't want you to
+ allocate 100 of every variable such as posx[100]. My
+ solution was to make index numbers. So in this case:
+
+ connectnum[0] = 5; connectindex[5] = 0;
+ connectnum[1] = 17; connectindex[17] = 1;
+
+ * Now I'll will describe some new variables at the top of GAME.C
+
+ myconnectnum - connection number of your computer
+ myconnectindex - index number of your computer
+ masterconnectnum - connection number of the MASTER computer
+ screenpeek - index number of which player's eyes you are
+ looking through.
+ numplayers - if numplayers >= 2 then multiplayer mode is
+ enabled, else single player game.
+
+ connecthead, connectpoint2[MAXPLAYERS] - These 2 variables
+ form a linked list of all the index numbers.
+ Here's some example code that traverses the list of
+ players:
+
+ p = connecthead;
+ while (p != -1)
+ {
+ printf("Player index %d has connection number %d\n",p,connectnum[p]);
+ p = connectpoint2[p];
+ }
+
+ * These variables are used to record / playback a demo. (This
+ is like POSCAPT.DAT, but with everything in sync!) In my
+ GAME, i single player mode, I have it so if you press the
+ Left ENTER, then it will playback everything. These are
+ the only variables necessary to store a demo run:
+
+ static long reccnt; //Number of frames
+ static short recsyncvel[16384]; //Vel for each frame
+ static short recsyncsvel[16384]; //Svel for each frame
+ static short recsyncangvel[16384]; //Angvel for each frame
+ static short recsyncbits[16384]; //Bits for each frame
+ static short recsynctics[16384]; //Tics for each frame
+
+ * These variables are used for communications syncing:
+
+ static short syncvel[MAXPLAYERS+1]; //Vel of each player
+ static short syncsvel[MAXPLAYERS+1]; //Svel of each player
+ static short syncangvel[MAXPLAYERS+1]; //Angvel of each player
+ static short syncbits[MAXPLAYERS+1]; //Bits for each player
+ static short synctics; //Number of tics of MASTER ONLY
+
+ * Unless I suddenly make BUILD a 6-degree of freedom engine
+ tomorrow, this should be the most difficult update in a long
+ time! Good Luck in programming! I'm sure I left a lot of
+ things out, so I'll be expecting plenty of phone calls!
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+6/27/94 - I scaled the vel, svel and angvel variabile down 1 bit so they
+ fit into a signed char. (Before they ranged from -256 to 256)
+ Now they range from (-128 to 127).
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+6/28/94 - Optimized the size of my COM(modem)/network packets in game.c.
+ I made the tics into a char. I also use some new buffers called
+ osyncvel, osyncsvel, osyncangvel, and osyncbits. Now I send
+ extra byte with bit fields that tell whether I need to update
+ the syncvel, syncsvel, syncangvel, or syncbits variables. If
+ the bit field of the extra byte is off then I don't send the
+ byte(s) it represents. You can now play my GAME at 4800 baud.
+
+ static signed char syncvel[MAXPLAYERS+1], osyncvel[MAXPLAYERS+1];
+ static signed char syncsvel[MAXPLAYERS+1], osyncsvel[MAXPLAYERS+1];
+ static signed char syncangvel[MAXPLAYERS+1], osyncangvel[MAXPLAYERS+1];
+ static short syncbits[MAXPLAYERS+1], osyncbits[MAXPLAYERS+1];
+ static unsigned char synctics;
+
+ - There was an crashing error with transluscence palette on low
+ memory configurations. When you exit the BUILD editor,
+ you normally get some numbers like this.
+ Memory status: 788979(788979) bytes
+ If the first number (art memory cache size) was less than the
+ second number (art file size), then the whole art file did
+ not fit in memory. The reason for the crashing was because
+ loadpics() sucks all memory up to the size of the art file.
+ The 64K transluscent palette is malloc'd when you call the
+ setgamemode() function for the first time. The was no memory
+ left to allocate the palette. I fixed this by making the
+ transluscent palette take 64K of the art memory cache if
+ it could not malloc the 64K.
+
+ - I programmed some error correction for the COM(modem). Here is
+ my new of Ken's guesses on how badly it will crash (assuming
+ that it will always crash eventually.) You will be seeing new
+ and better correction methods in the future.
+
+ ERROR CORRECTION METHOD #1:
+ 1. Serial link using 8250 chips - out of sync after 5 minutes.
+ 2. Serial link using 16550 chips - out of sync after 10 minutes.
+ 3. Modem - out of sync after 3 minutes - try it!
+ 4. Network - out of sync after 1 minute. Networks love to
+ lose full packets here and there. (not changed)
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+6/29/94 - Added some code to my GAME.C that will let you type in messages
+ and send them to all remote players. Press Tab (or T for
+ those people who play that other, very bad, game too much)
+ to start typing in a message. Press either Enter key to send
+ the message to the other player.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+6/30/94 - ATTENTION PROGRAMMERS: I changed the values that clipmove and
+ movesprite return! Here's how they work now:
+ If you did not hit anything, then they return 0.
+ Movesprite only: If the object hits a ceiling / floor
+ then movesprite returns 16384+(sectornum hit).
+ If the first object you hit before sliding was a wall,
+ then they return the 32768+(wallnum hit).
+ If the first object you hit before sliding was a sprite,
+ then they return the 49152+(spritenum hit).
+
+ Be careful when adding these changes to your code since the
+ return value are sort of reversed:
+
+ return values: Hit nothing: Hit something:
+ 袴袴袴袴袴袴袴誥袴袴袴袴袴袴袴妄袴袴袴袴袴袴袴袴袴袴袴袴
+ Old functions: 1 0
+ 컴컴컴컴컴컴컴켰컴컴컴컴컴컴컴탠컴컴컴컴컴컴컴컴컴컴컴컴-
+ 16384+sectnum (Movesprite only)
+ New functions: 0 or 32768+wallnum
+ or 49152+spritenum
+
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+7/1/94 - Made getangle always return an angle from 0 to 2047. Before I
+ forgot to and it 2047 and sometimes the angle was negative.
+
+ - Made overwritesprite when using the centering option be sensitive
+ to the Editart centering tool. (The ~` key.)
+
+ - Made Ctrl+Rt.Shift highlight points on a loop rather than points
+ inside a rectangle.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+7/2/94 - Added some neat features to my GAME.C to make multi-player mode
+ even more fun. I added a portable bowling ball/bomb-thrower.
+ kills instantly! (similar to rocket launcher) I also added
+ water fountains. If you hold the space bar down on them,
+ you slowly get more life.
+
+ - O.K. I think I actually got the syncronization working perfectly
+ for COM(modem) play. I haven't had all day to test it out yet!
+ (Still no error correction with networks)
+
+ Here are some steps in playing over the modem:
+ 1. Be sure that both people have the exact same version of
+ the EXEs, ART, and MAPs.
+ 2. Then go into SETUP and set the COM port to the com port
+ of your modem. Even though 9600 baud should work, I
+ would recommend going at 4800 baud because:
+ A. It works fine at 4800 baud so there is really
+ no need to go any faster.
+ B. Fewer errors over the modem so less time
+ spent re-sending packets.
+ 3. Then type: MODEM [mapname] (must be same mapname!)
+ This will bring you into my terminal program. You can
+ set the modem initialization string in MODEM.BAT by
+ changing the first command line option of the TERM
+ line. Please disable modem compression and
+ correction for least jerky play. Then connect with
+ the other modem using various methods, such as one
+ person typing ATA and the other typing ATD or one
+ person typing ATS0=1 and the other typing
+ ATDT(phone #).
+ 4. Wait through the beeps and buzzes until it says CONNECT
+ on the bottom window.
+ 5. If you can now chat with each other then things are
+ going well. When the first person presses ESC, both
+ computers will automatically quit to DOS and go right
+ into the GAME.
+ 6. Play!
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+7/5/94 - Serial moder over COM(modem) should work perfectly now.
+
+ - Added scaredfallz to BUILD.H. It is a global variable that
+ tells monsters what height is too high to fall through. You
+ can set cliptype parameter to 2 for movesprite and clipmove.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+7/6/94 - Fixed clipping bug that used to let you go through certain concave
+ corners.
+
+ - Added new function which works well with clipmove. Ever notice
+ was when you're at the edge of a cliff and you go just a tiny
+ bit over, you fall, but shouldn't yet? Unlike what you have
+ been doing, this new function finds the highest and lowest z
+ coordinates that your clipping BOX can get to. It must search
+ for all sectors (and sprites) that go into your clipping box.
+ Currently, you were searching the z's at the center point only
+ by simply using the sector[].ceilingz and sector[].floorz
+ variables.
+
+ getzrange(long x, long y, long z, short sectnum,
+ long *ceilz, long *florz,
+ long walldist, char cliptype)
+
+ Pass x, y, z, sector normally. Walldist can be 128. Cliptype
+ can be 0, 1, or 2. (just like movesprite and clipmove)
+ This function returnes the 2 z maxes in ceilz and florz.
+ See GAME.C for an example.
+
+ - Fixed bug with weird vertical lines in transluscent masked walls
+ in chain mode.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+7/10/94 - Made screen capture (F12) work in 2D modes also. It always
+ saves to a 256 color PCX file.
+
+ - Made screen re-sizeable. Use this easy new function to re-size
+ the screen:
+
+ setview(long scrx1, long scry1, long scrx2, long scry2);
+
+ It is TOO easy to use. You simply pass is the Upper-left hand
+ corner and the bottom-right corner in screen coordinates of the
+ rectangular region you want the engine to draw to. The engine
+ automatically centers the horizon at the middle of the window and
+ scales everything properly.
+
+ Notes:
+ - Since the engine does extra scaling calculations for
+ window sizes that are not 320 pixels wide, I do not
+ recommend making the default mode with a window size
+ just under 320 pixels wide since the engine can
+ actually run a little slower. (such as 312-319
+ pixels wide) Keep them 320 wide.
+ - Feel free to modify the startumost / startdmost arrays
+ AFTER a setview call if you want weird window shapes.
+ Keep in mind that startumost[0] and startdmost[0] are
+ always refer to the left edge of the viewing window.
+ (NOT left edge of screen.)
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+7/19/94 - Finally got around to writing the number-of-tiles-per-file
+ resizer. Simply type rsizeart. All instructions will be
+ displayed when running the program before the actual
+ conversion.
+
+ - Fixed a few bugs in Editart. I hope I fixed those evil bugs that
+ rarely come by. I'm pretty sure I fixed the bug that made the
+ screen go blank in 'V' mode, and the bug where a few pixels
+ in the top left corners of tiles sometimes get overwritten.
+
+ - Added a key in Build 2D edit mode. Press 'E' on a sprite to
+ change its status list number.
+
+ - Fixed those lousy Editart subdirectory colors in 'U' for those
+ teams with great color palettes, but don't have my ugly shade
+ of pink.
+
+ - Fixed bug with non-200 high P-skies. The p-skies are now (by
+ default) centered on the horizon no matter what the height is.
+
+ - Added multiple size PCX and GIF support in Editart. You can now
+ load pictures up to 1024*256. (That's all that can fit in VGA
+ video memory) If you need to load a bigger picture than that,
+ it will be chopped off at the bottom, but will still load the
+ top piece.
+
+ - I know that I have introduced some wonderful new bugs with the
+ sprite drawing. I know why they're happening, but I am
+ looking for a good solution so as to not make you change
+ any code. I will put another upload with these bugs fixed
+ soon.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+7/20/94 - Added TRUE ornamented walls. Right now the actual ornamentation
+ must be programmed by you with 2 simple functions:
+
+ copytilepiece(long tilenume1, long sourcex1, long sourcey1,
+ long xsiz, long ysiz,
+ long tilenume2, long destx1, long desty1)
+
+ * This function simply copies any section of a source tile
+ to any part of a destination tile. It will automatically
+ skip transparent pixels. It will wrap-around in the
+ source but not the destination. If for some reason
+ the destination tile gets removed from the cache, the
+ destination tile will be reset to original form. This
+ is why I had to add this second function:
+
+ allocatepermanenttile(short tilenume, long xsiz, long ysiz)
+
+ * This function allocates a place on the cache as permanent.
+ Right now, I reset the cache every time you call this
+ function so I would recommend calling this function
+ right after loadpics.
+
+ I have an example of both of these functions in GAME.C. Try
+ playing GAME DOOM1.MAP and go into the secret room with
+ the pictures of Ken. Shoot some walls there. The pictures
+ with Ken and the Explosion over it were done with
+ copytilepiece and allocated permanently at tile 4095. A
+ good idea for allocating permanent tiles would be to start
+ at 4095 and decrement. You can also allocate a permanent
+ tile over the original tile itself.
+
+ - Tile panning matching keys work a lot better. They now work
+ well with bottom steps. Also, it works well with matching
+ up windows.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+7/25/94 - A week ago, I uploaded a version of BUILD which unfortunately
+ had more bugs than the previous version. This upload should
+ have those bugs fixed - especially the sprite bugs. (I hope)
+
+ - I think I may actually have the sprite feet behind stairs bug
+ working perfectly.
+
+ - The engine should now be even faster the before last week. (A
+ week ago, I temporarily changed the parallaxing sky algorithm,
+ making the engine slower in those areas)
+
+ - Added a variable, parallaxyoffs in BUILD.H. It defaults to 0.
+ If you set it to 100, then all parallaxing skies will be
+ properly moved 100 pixels higher.
+
+ - Fixed some weird drawing bug related to parallaxing skies and
+ sprites.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+7/26/94 - Made sprite's sectors dependent on the z coordinates in the BUILD
+ editor. (Helpful if you use overlapping in your maps)
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+7/29/94 - Made precache function. Simply call:
+ precache() (no parameters)
+ right after you call loadboard(?,?,...) and it will load
+ all tiles in the current board into the cache. Note that
+ animations of sprites after the first one will not be
+ precached. I have included my precacheing code at the
+ end of game.c for those interested in making the precaching
+ fancy.
+
+ - Fixed bug in editart which made it sometimes save the art files
+ and names.h in the wrong directory (the last directory you
+ were in when you were in 'U' mode). You may want to search
+ your artwork directories to see if you were a victim of this
+ bug.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+7/30/94 - Made Ctrl-Enter paste parallaxing sky tiles to all neighboring
+ parallaxing sky areas also.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+7/31/94 - Fixed (most) crashing bugs - Doesn't even crash on the highest
+ skyscrapers now! Since I can never be SURE that the crashing
+ is gone, I need you to test it for me - compare the number
+ of times it crashes per second since the last version. It
+ should be much better.
+
+ - Fixed sector line bug! Get close to a step, hold down Shift+Z
+ and the edges of the step will NOT jitter like before AND you
+ will not get random walls going through the screen.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+8/1/94 - Got rid of the OLD transluscent stuff from overwritesprite and
+ permanentwritesprite. (Before it used the 8K shading table
+ which didn't work very well)
+
+ - Added new true 50/50 transluscence option to overwritesprite.
+ See bit 2 in the next comment.
+
+ - Fixed overwritesprite so it works with different screen sizes.
+ You don't need to do any scaling calculations! Should be
+ compatible with old function. Added new bit 1 to orientation
+ parameter to determine whether or not the sprite should be
+ scaled and clipped to the viewing window.
+
+ overwritesprite (long thex, long they, short tilenum,
+ signed char shade, char orientation)
+
+ If Bit 0 of orientation = 0: (thex, they) is top-left corner
+ If Bit 0 of orientation = 1: (thex, they) is middle
+ If Bit 1 of orientation = 0: no relation to viewing window
+ If Bit 1 of orientation = 1: scale and clip to viewing window
+ If Bit 2 of orientation = 0: normal
+ If Bit 2 of orientation = 1: 50/50 transluscent!
+
+ * If it works at full screen, simply set bit 1 of orientation
+ to 1, and it should automatically scale properly!
+
+ - Made it so 2/4/6/8 keys in 3D EDIT MODE now only move the objects
+ 1 step rather than continuously, giving more control over the
+ repeat/panning values of things.
+
+ - Made the / key not only reset the repeats of walls, but also for
+ sprites. It will set both repeats of the sprite to the default
+ size of 64. If you hold down shift with / on a sprite, it
+ will give the sprite a square aspect ratio by setting the
+ xrepeat to equal the yrepeat value.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+8/2/94 - Doubled the board size from: (0 to 65536, 0 to 65536) to
+ (-65536 to 65536, -65536 to 65536) Notice that the grid in
+ 2D EDIT MODE is much bigger than before. Since it is very easy
+ to double the maximum board size, just tell me if you need
+ a larger board. The only bad thing about allowing larger
+ boards is that the map designer is more likely to make some
+ sectors too large and cause overflow bugs. 32 bits can only
+ go so far you know!
+
+ - I think I MAY have fixed a bug in BUILD that used to make it crash
+ when quitting. It had something to do with the vertical grid
+ lines in 2D EDIT MODE when zoomed way in around the upper left
+ corner of the map (I think).
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+8/3/94 - Optimized Editart loading and saving.
+
+ - Made 'V' screen in Editart 320*400 instead of 320*200.
+
+ - Before I said I fixed the bug in EDITART where a few pixels in the
+ top left corners of tiles sometimes got overwritten. Well I
+ lied. This time I really fixed it. (I hope)
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+8/7/94 - Made x&y repeats, x&y pannings easier to adjust. It now works
+ like the default keyboard handler. It moves once when you
+ first press the key. A little later, it starts to move fast.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+8/11/94 - Added great new sprite rotation function which works like
+ overwritesprite (like 2DRAW sprites)
+
+ rotatesprite(long sx, long sy, long z, short a, short picnum)
+
+ (sx, sy) is the center of the sprite to draw defined as
+ screen coordinates shifted up by 16.
+ (z) is the zoom. Normal size is 65536.
+ Ex: 131072 is zoomed in 2X and 32768 is zoomed out 2X.
+ (a) is the angle (0 is straight up)
+ (picnum) is the tile number
+
+ Ex: rotatesprite(160L<<16,100L<<16,65536,lockclock<<4,DEMOSIGN);
+ This example will draw the DEMOSIGN tile in the center of the
+ screen and rotate about once per second.
+
+ Rotatesprite clips to the same area as overwritesprite but does
+ not scale or do transluscence yet.
+
+ - Please look at the new permanentwritesprite documentation at the
+ top of this file!
+
+ - Network should now work again - It now works great on my network
+ with 3 players! It may possibly also work with 4 or 5 players
+ too, but I didn't feel like running between 2 rooms to test it!
+ I never thought the day would come when I would get NET, COM,
+ and MODEM all working respectably!
+
+ - Changed setup program so you can select 2, 3, 4, or 5 players in
+ a network game. (The 5 is just to annoy people who like that
+ other lousy game)
+
+ - ATTENTION BUILDERS! Added TILE MOVING to EDITART! For now, it
+ will only work WITHIN THE SAME ART FILE. Do the tile moving
+ all in 'V' mode. Here are the new keys in 'V' mode:
+
+ To swap 2 tiles:
+ Simply press space bar on the first tile, then space
+ bar on the second.
+ To swap a group of tiles:
+ Press 1 on the first tile, press 2 to remember the region
+ between where you pressed 1 and 2. Press 3 at the
+ place to where you want to swap all the tiles.
+
+ Don't forget that this is all SWAPPING, tiles will (should)
+ NOT be overwritten using these keys.
+
+ - ATTENTION PROGRAMMERS! Added ceildist and flordist parameters to
+ both clipmove and movesprite. I always had them all set to
+ (4<<8) by default.
+
+ clipmove(long *x, long *y, long *z, short *sectnum,
+ long xvect, long yvect,
+ long walldist, long ceildist, long flordist,
+ char cliptype)
+
+ movesprite(short spritenum, long xchange, long ychange, long zchange,
+ long walldist, long ceildist, long flordist,
+ char cliptype, long numtics)
+
+ - Moved some com/network code from the getpackets function in game
+ into the engine.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+8/15/94 - Fixed some network initialization code and it now works with 4
+ players. (I tested it.)
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+8/16/94 - Added different shirt color support. Here's how you do it:
+
+ allocatespritepalookup(long palnum, char *remapbuf)
+
+ See more documentation of allocatespritepalookup at the top of
+ this file.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+8/18/94 - I made it so you can redefine the keys in the setup program under
+ the input devices menu.
+
+ - ATTENTION EVERYONE - for this new version, you MUST go into my
+ new SETUP program, and SAVE CHANGES AND QUIT once. The arrow
+ key code will not work if you don't do this! If you are
+ one of those people who actually read BUILD.TXT, give yourself
+ 1 point. I wonder who will get "caught" for not reading this!
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+8/22/94 - Added pixel height and wall length information to 2D EDIT MODE
+ when you press Tab or Alt-Tab on a sector or wall.
+
+ - Now show the actual number of sprites in 2D EDIT MODE.
+
+ - Improved digitized sound routines. Just thought I'd mention it.
+
+ - Added a "save As" feature to 2D EDIT MODE.
+
+ - Now show all lo and hi tags in 2D EDIT MODE on the map itself!
+ Note that position of the sector tag's text is put at the
+ average point of all the points of the sector, so if you have
+ a weird shape tagged sector, the text might show up at an
+ inconvenient place.
+
+ - You can turn the tag boxes on or off by pressing CTRL-T or by
+ zooming out.
+
+ - ATTENTION EVERYONE - for the new BUILD.EXE and OBJ's, you will
+ need to copy my new TABLES.DAT over your old one. Also, you
+ must go into SETUP and SAVE&QUIT. I have split the TABLES.DAT
+ file into 2 separate files. They are:
+
+ TABLES.DAT - 10880 bytes - sin tables, fonts, etc.
+ SETUP.DAT - 23 bytes - (6 options) + (17 custom keys)
+
+ The SETUP.DAT file is the only file SETUP.EXE accesses now.
+ This means that from now on, if I want to add something to
+ TABLES.DAT, you won't have to go into the setup program and reset
+ the options again.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+8/24/94 - Relative alignment now fully works with ROTATION! Relative
+ alignment will allow ceilings and floors to align with the
+ first 2 points of a sector. This will relieve you of
+ programming special ceiling and floor panning code for moving
+ sectors.
+ In 3D EDIT MODE, simply press 'R' on a ceiling / floor to switch
+ between relative alignment mode and normal mode. Notice that
+ bit 6 of both sector[].ceilingstat and sector[].floorstat are
+ relative alignment bits.
+ I have an example of relative alignment in nukeland.map in the
+ high blue room off the main octagonal room. Also note that my
+ subways and dragsectors now use relative alignment for panning.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+8/25/94 - I added a new parameter to printext256 and printext16. I need
+ to document this stuff!
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+8/27/94 - Made it so you can't shrink sprites so much you can't grab them
+ any more in 3D EDIT MODE.
+
+ - Added (G)oto feature into Build 'V' mode. Simply press G, type
+ the tile number and it will go there.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+9/7/94 - Fixed relative alignment bugs I noticed. My subway.map won't
+ crash anymore and the relatively aligned ceilings and floors
+ should not pan crazily anymore when looking from a far
+ distance.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+9/9/94 - ATTENTION PROGRAMMERS: I added a new parameter to
+ overwritesprite. Dapalnum can be from 0-15 depending on
+ what palette lookup table is being used. Dapalnum is normally
+ 0. Overwritesprite now looks like this:
+
+ overwritesprite (long thex, long they, short tilenum,
+ signed char shade, char orientation, char dapalnum)
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+9/13/94 - ATTENTION PROGRAMMERS: I changed the last parameter of drawrooms
+ (sector number) to be passed as a value, NOT a pointer anymore.
+
+ drawrooms(long daposx, long daposy, long daposz,
+ short daang, long dahoriz, short dacursectnum)
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+9/15/94 - ATTENTION PROGRAMMERS: I took out the COM(modem)/network code
+ from my engine.obj and put it into a separate .obj called
+ multi.obj. (I also removed the sound from my engine and stuck
+ it in kdmeng.obj) Please include it in your makefile. Here is
+ a list of ALL of the variables and functions you will need to
+ know to program for multiple players:
+
+ VARIABLES: (You should extern these in your game.c)
+ extern short numplayers, myconnectindex;
+ extern short connecthead, connectpoint2[MAXPLAYERS];
+ extern long *lastpacket2clock;
+
+ FUNCTIONS:
+ initmultiplayers(option[4],option[5]);
+ uninitmultiplayers();
+
+ sendlogon();
+ sendlogoff();
+
+ sendpacket(connecthead,tempbuf,j);
+ sendpacket(-1,tempbuf,j);
+ leng = getpacket(&otherconnectindex,tempbuf);
+
+ Please see detailed descriptions of these functions at the top
+ of this file.
+
+ - Multiplayer code is now MUCH cleaner!
+
+ - Please try my game on your networks again! My game now works
+ perfectly with 3 players on a network that used to crash at
+ the DOS4GW prompt just a week ago! My game needs only IPX,
+ no server to run.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+9/16/94 - ATTENTION PROGRAMMERS: CONVMAP5!!! YOU MUST RUN CONVMAP5 ON
+ ALL OF YOUR MAPS IF YOU WANT THEM TO WORK WITH THE NEW
+ BUILD.EXE OR OBJ'S! Following are the exact changes I made
+ to the new map format:
+
+ * Added numextras
+ * Added sector[].ceilingpal
+ * Added sector[].floorpal
+ * Added sector[].visibility
+ * Split sector[].tag to sector[].lotag and sector[].hitag
+ * Added sector[].extra
+ * Expanded wall[].cstat to a short
+ * Split wall[].tag to wall[].lotag and wall[].hitag
+ * Added wall[].extra
+ * Split sprite[].tag to sprite[].lotag and sprite[].hitag
+ * Got rid of sprite[].extra (the void * mess)
+ * Added sprite[].extra
+
+ The only thing programmers have to worry about when converting
+ are the tags. I split them into lo and hi tags.
+ (See BUILD.H for new structure formats)
+
+ I got rid of the (void *)extra thing from the sprite
+ structure. I know I may have made some promises it
+ wouldn't change and it was for your use only, but what
+ can I say - it's not needed anymore (in other words,
+ if you're already using it, TOUGH LUCK). I have my
+ own, new, method for extending sector, wall, or
+ sprite structures. You will be able to extend any
+ structure as much as you want AND be able to edit it
+ all in the BUILD editor to be saved in the permanent
+ map format. Notice I added a (short)extra to all 3
+ main structures. They default to -1. But if they
+ are >= 0 then they form a linked list out of the
+ extra structure. NOTE: THIS EXTRA STUFF IS NOT
+ PROGRAMMED YET! I'm just mentioning it becuase the
+ new map format has this extendability. I'll try to
+ get it done soon though. (9/21/94) - Actually just
+ ignore the fact that this paragraph ever existed.
+ I'm just keeping it here for history purposes.
+
+ - Renamed my allocatespritepalookup function to makepalookup since
+ it now also applies to walls, ceilings, floors, p-skies and
+ masked walls.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+9/20/94 - Added rotated sprites. These new rotated sprites rotate in the
+ same way as masked walls. Sounds like a waste since the
+ engine already has masked walls? NOT AT ALL! With rotated
+ sprites, you can EASILY do TRUE ornamented walls FULLY inside
+ the BUILD editor with even MORE versatility than that other
+ game out there. For example, you can place the ornamentation
+ anywhere on the wall, with sizing control using 2,4,6,8 on the
+ keypad, and even ornament with transluscence! In 3D EDIT
+ MODE, simply press 'R' on a sprite to make it a rotated
+ sprite (Programmers see bit 4 of sprite[].cstat)
+
+ - Fixed crashing bug with sector (Rt. ALT) copy/paste in 2D EDIT
+ MODE.
+
+ - You can now copy groups of sectors from 1 map to another! Here's
+ how you do it:
+
+ Step 1: Capture a bunch of sectors with the Rt. ALT selection
+ tool.
+ Step 2: With the sectors still highlighted, you can now load
+ another map and the highlighted sectors will
+ automatically be inserted into the new map. (They
+ will still be highlighted)
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+9/21/94 - Fixed bug with cursectnum not always being right after loading
+ the board. I now check it and make sure it's right when
+ saving in BUILD now.
+
+ - Added 'O' key in 2D/3D EDIT MODES. It will push a rotated sprite
+ backwards (using hitscan) into the first wall and
+ automatically adjust the angle to make the sprite appear
+ as if it was part of the wall.
+
+ - You can now press 'S' to insert a sprite in 3D EDIT MODE. Press
+ 'S' on a ceiling or floor.
+
+ - You can now press delete to delete a sprite in 3D EDIT MODE.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+9/22/94 - Programmed Nick & Peter's BUILD stub to their EXACT
+ specifications. See WSTUB.C for code & documentation.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+9/27/94 - Fixed Rt. Alt block copying nextsector1 pointer bug.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+9/29/94 - Added special bitmapped effect which I either call lava or
+ boiling slime. See my initlava and movelava functions
+ inside GAME.C.
+
+ - I added a bit array call gotpic. The engine will set the
+ respective gotpic bit for each picnum drawn to the screen,
+ including ceilings, floors, walls, sprites, masked walls -
+ even overwritesprites, etc. This array is mainly for
+ making the game only calculate special bitmapped effects
+ when that certain picnum is on the screen.
+
+ Note 1: The engine does NOT automatically clear the gotpic
+ bits for you. If you want to test gotpic for a certain
+ picnum, you should clear it if you want to test it again.
+
+ Note 2: It is not necessary to use permanentwritesprite
+ for bitmapped special effects - after all, if you see it,
+ it MUST be in the cache.
+
+ Added to BUILD.H:
+ EXTERN char gotpic[MAXTILES>>3];
+
+ Example code in GAME.C:
+ if ((gotpic[SLIME>>3]&(1<<(SLIME&7))) > 0) //test bit
+ {
+ gotpic[SLIME>>3] &= ~(1<<(SLIME&7)); //clear bit
+
+ if (waloff[SLIME] != -1) //if in cache
+ movelava((char *)waloff[SLIME]); //calculate!
+ }
+
+ - Added what some people call gamma correction. I think
+ brightness is a better description though.
+
+ setbrightness(char brightness);
+
+ Simply call this function where brightness ranges from
+ 0 to 4. Brightness defaults to 0. Levels 1-4 are all brighter
+ than 0. If you switch between 2D & 3D modes, the engine will
+ remember the current brightness level.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+9/30/94 - Added a few keys to fake a multiplayer game all on 1 computer.
+ In my game, press Insert to add a new player at the starting
+ position, and Delete to delete the last player. Press
+ scroll lock to get control of the other players. In the same
+ way Lt. Enter lets you view other players, Scroll lock will
+ let you control other players (single player game only)
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+10/2/94 - Moved all doanimations code from engine into game.c. If you
+ are using the doanimations code, here's exactly what you
+ need to do to make it work with your code again:
+
+ Step 1: Copy these 3 functions which you should find at
+ the end of my Game.c:
+
+ doanimations(long numtics)
+ getanimationgoal(long animptr)
+ setanimation(long *animptr, long thegoal, long thevel)
+
+ Step 2: Move these variables out of BUILD.H and into your
+ game.c:
+
+ #define MAXANIMATES 512
+ static long *animateptr[MAXANIMATES], animategoal[MAXANIMATES];
+ static long animatevel[MAXANIMATES], animatecnt = 0;
+
+ * If you copied my door code, you will probably have to convert
+ some parameters to longs. (oops!)
+
+ - Got rid of printnum from the engine. It is an outdated function.
+ Use either printext256 or printext16 instead.
+
+ - Added y-flipping for both normal and rotated sprites. (see bit
+ 3 of sprite[].cstat in BUILD.H.
+
+ - Added y-flipping for walls. (see bit 8 of wall[].cstat in
+ BUILD.H.
+
+ - Fixed bug with initialization of Master and Slave for
+ COM(Modem) only. If both computers went in at the same
+ time, it used to sometimes think both were Masters.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+10/4/94 - Alt-C in 3D EDIT MODE changes all picnums on the whole map
+ from the picnum in tab to the picnum under the mouse cursor.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+10/6/94 - Fixed y-flipping bug on walls and masked walls.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+10/16/94 - Fixed bug in editart that didn't convert the maps right after
+ swapping tiles.
+
+ - Added excellent function to my multi.obj.
+
+ long getoutputcirclesize();
+ This function returns the number of bytes that have not
+ yet been copied. If there are still more than say, 16 bytes,
+ then you may be sending too many bytes per second. This can
+ happen if the frame rate of a computer is faster than the
+ speed of the serial mode (Ex: Try 2400 baud with a Pentium 90!)
+ this function will tell you how many bytes are left to copy
+ In other words, if getoutputcirclesize() < 16 then it is safe
+ to send a packet. If you already have serial mode working
+ all you have to do to update your code is to copy the lines
+ in my sync() function the deal with the getoutputcirclesize
+ function. Everything else in sync() and getpackets() is
+ pretty much the same.
+
+ - Programmed some example code in my game that will allow players
+ to change masters and slaves during the game without losing
+ sync. Simply press 'M' in my multiplayer game, and that
+ computer will become the master! It is interesting how
+ the frame rate and controllability changes.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+10/31/94 - Added basic scripting to EDITART. Don't expect it to be
+ everything you ever dreamed of (yet).
+
+ Scripts are saved in a file called CAPFIL.TXT. You can edit the
+ text file, but be careful not to screw it up too badly (such
+ as extra commas, spaces in weird places, etc.) since I am
+ parsing it in EDITART.
+
+ Whenever you select a box in 'U' mode, a line will be appended to
+ the CAPFIL.TXT file.
+
+ WRITING THE CAPFIL.TXT FILE:
+ In 'U' mode, you can press 'O' instead of ENTER to select a tile.
+ What 'O' does that is different from ENTER is that it takes
+ the center point of the highlighted rectangle, and searches
+ outward until a total rectangle of transparent pixels (255)
+ is reached. This is useful for grabbing sprites - not only
+ will you not have fine adjust to the exact borders of a
+ sprite now, but when you re-grab from the pcx's you can
+ change the size of the sprite freely.
+
+ READING THE CAPFIL.TXT FILE:
+ There are 2 ways to re-grab from the CAPFIL.TXT file. If you
+ press ALT-U in the main screen, everything will be re-grabbed.
+ If you press ALT-U in 'V' mode, then you should first select
+ the range by pressing '1' and '2' on the range boundaries.
+
+ Format of CAPFIL.TXT lines:
+ Tile #, Full path/file name, x1, y1, xsize, ysize
+
+ Note: If xsize and ysize are 0, then that means you did
+ an 'O' grab and EDITART will search from point (x1, y1)
+ when you do a re-grab.
+
+ Example CAPFIL.TXT file:
+ 31,D:\CAPTUR00.PCX,220,98,64,64
+ 110,D:\CAPTUR00.PCX,49,72,0,0
+
+ The first line says that tile #31 is a 64*64 tile and the
+ second line says that tile #110 is unknown size tile (grabbed
+ with the 'O' key)
+
+ Note: You can only do 1 grab per tile with my scripting system.
+ You may have done your parallaxing skies with several grabs.
+ If so then try to make the tile into 1 large PCX and do 1
+ grab. (The largest grabbing size right now is 1024*256)
+
+ -------------------------------------------------------------------
+
+ - Made Editart's screen capture (F12) save to PCX's the exact size
+ of the tile and not include the status bar at the bottom. It
+ will also save large tiles to large PCX's - Now it's easy and
+ lossless to extract a tile from Editart!
+
+ - ATTENTION PROGRAMMES! Added 2 new parameters to getzrange for
+ returning the objects hit on top and bottom.
+ (sectors / sprites) See my updated documentation at the top
+ of this file.
+
+ - Fixed clipping bugs with sprites near sector lines. (I hope)
+
+ - Got 3D Red-Blue glasses mode working for all VGA cards. First
+ set the graphics mode to red-blue mode in the setup program.
+ The left eye is red and the right eye is blue. There are
+ 4 keys that let you adjust the 3D view:
+ [,] = Adjust width between eyes (3D width)
+ Shift [,] = Adjust width of parallax (2D width)
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+11/1/94 - Guess what? I turned 19 today. Doesn't that just suck. Now,
+ if you play my build game on my birthday, all the extemely
+ evil and scary brown monsters will be replaced with super
+ happy fun dogs that throw smiley red jelly coconuts at you.
+ Also, my incredibly evil and scary music will be replaced
+ with super happy music. Actually this whole paragraph is
+ a joke (except for the birthday part).
+
+ - Made centering work with rotated sprites.
+
+ - Fix centering with x and y flipped sprites.
+
+ - Rotated sprites now get chopped off by the ceiling or floor in
+ the same way normal sprites get chopped. Sprites do not get
+ chopped if there is a parallaxing sky / floor.
+
+ - Made Shift + F12 is BUILD 2D mode inverse black and white.
+
+ - If SETUP.DAT is not found then default options are loaded
+ instead of quitting to DOS.
+
+ - ATTENTION PROGRAMMERS! Added 3 parameters to makepalookup that
+ allow you to do FOG effects. The first 2 parameters are the
+ same as before. The last 3 are the color that the palette
+ fades to as you get further away. Before, this color was
+ always black (0,0,0). White would be (63,63,63).
+
+ makepalookup(long palnum, char *remapbuf,
+ char redvalue, char greenvalue, char bluevalue)
+
+ - ATTENTION PROGRAMMERS! Moved 2 things into BUILD.H. Please
+ make sure to update it:
+
+ #define MAXPALOOKUPS 256
+ and
+ EXTERN char *palookup[MAXPALOOKUPS];
+
+ The palookup array is an array of pointers that point to the
+ first byte of each 8K palette lookup table. All 256 pointers
+ are initialized to NULL by initengine() except for palookup[0]
+ which is the default 8K palette. This will allow you to modify
+ the palette lookup table directly for non-snowy fading effects,
+ etc. Each palette lookup table has 32 shades. Each shade has
+ 256 bytes. Shade 0 is closest (actual palette brightness) and
+ shade 31 is farthest (dark usually). (256*32 = 8192 or 8K)
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+11/3/94 - Now show white lines in 'V' mode of EDITART at ART file tile
+ boundaries.
+
+ - Added Insert and Delete commands to EDITART! These Insert and
+ Delete keys WILL shift all tiles after the one being inserted
+ or deleted just like a regular text editor. To insert or
+ delete tiles, simply go the 'V' screen in EDITART and bang
+ away! Don't worry these keys are fully multi-tile file
+ compatible (unlike swapping right now).
+ You will notice that the white line boundaries that
+ I just added will actually move if you press Insert or Delete.
+ This changes the number of tiles per art file. But that's
+ ok. If the art files ever get too unbalanced, you can run
+ the RSIZEART.EXE utility to fix it.
+ Ken's lesson of the day: For the final release of your
+ games, you only need 1 art file. The reason I spent my time
+ programming multiple art files was because of EDITART.
+ Since EDITART need to READ & WRITE to the art files, it must
+ hold a whole art file in memory at a time. Since Build and
+ Game only READ the art files, a caching system can be made
+ and only 1 art file is necessary even for lo-memory systems.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+11/4/94 - ATTENTION MAP DESIGNERS! Added a long-awaited feature to BUILD
+ which I call "loop joining". Have you ever gotten this
+ frustrating message in 2D EDIT MODE before?
+
+ "You can't split sector by connecting different loops."
+
+ Well, you're not going to see it any more because I fixed
+ it! Yup. You can now split a sector along a line connecting
+ different loops of the sector.
+
+ Try this - Convert the sector on the left to the sector
+ on the right:
+
+ Split #1 Split #2
+ 旼컴컴컴 旼컴쩡컴 旼컴쩡컴
+ 旼컴 旼좔 旼좔
+
+ 읕컴 읕컴 읕쩡
+ 읕컴컴컴 읕컴컴컴 읕컴좔컴
+ (Given) (Half done) (Result)
+ (1 sector) (Still 1 sector) (2 sectors)
+
+ Before the only was to do this was to delete all the
+ sectors and then redraw them again.
+
+ I'm sure loop joining has its share of tricks, as most
+ BUILD functions do, so you may want to spend some time just
+ playing around with this new function.
+
+ - Removed my own profiler stuff - Hline calculations, etc. code.
+ Watcom's sampler and profiler is much better anyway.
+
+ - Fixed neartag divide by zero bug with walls (I hope).
+ Anyone calling neartag for every player per movethings?
+ I would try not to - How much is that unnoticable extra 0.02
+ frames per second worth to you anyway?
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+11/9/94 - Added new array to BUILD.H called gotsector. It works a lot
+ like the gotpic array, but this array determines which sectors
+ were considered during the drawrooms function. Note that
+ gotsector, unlike gotpic IS cleared to 0 during every call
+ to drawrooms.
+
+ - Fixed Editart 'U' mode mouse control bug. I typed too fast this
+ time.
+
+ - Fixed Build split sector bug of accidently deleting sprites. It
+ should not delete any sprites when splitting sectors now.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+11/15/94 - ATTENTION PROGRAMMERS!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ I moved ALL my timer code and arrow key code into GAME.C.
+ Here are the exact instructions that you need to follow to
+ upgrade your code to the new obj's:
+
+ 1. From the end of my GAME.C, take the code from these 4
+ functions:
+
+ ---> inittimer();
+ ---> uninittimer();
+ ---> void __interrupt __far timerhandler();
+ ---> keytimerstuff();
+
+ 2. After each initengine, call inittimer right AFTER:
+
+ initengine();
+ ---> inittimer();
+
+ After each uninitengine, call uninittimer right BEFORE:
+
+ ---> uninittimer();
+ uninitengine();
+
+ 3. You may need to include this (if not already included):
+
+ ---> #include <dos.h>
+
+ 4. Add these 2 lines to declare the timerhandler:
+
+ ---> void (__interrupt __far *oldtimerhandler)();
+ ---> void __interrupt __far timerhandler(void);
+
+ 5. Since BUILD.H NO LONGER has vel, svel, and angvel, you
+ must add the following line to your game:
+ (These variables are modified inside keytimerstuff())
+
+ ---> static long vel, svel, angvel;
+
+ 6. Let me list some variables that I recently removed from my
+ GAME. This may or may not affect you:
+
+ oposx[], oposy[], oang[], etc.. - GONE!
+ lastpacket2clock - GONE!
+ lastsynctics - GONE!
+ drawscreen's smoothratio parameter & related code - GONE!
+ kenchaintimer - GONE! (Don't think anybody was using it
+ because it didn't solve sound compatibility problems)
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+11/16/94 - Made swinging door clipping work MUCH better! It is much more
+ difficult to "sneak" through the door now. With the swinging
+ door clipping working much better, I made it possible to open
+ doors even if you are in the same sector as the door itself.
+ Now you won't have to stand back a certain distance to open
+ the doors. (It is much less annoying this way) Since neartag
+ does not normally scan cursectnum's sector tags, you will
+ need to check cursectnum's tags yourself (if you so desire)
+
+ Example: (extracted from my GAME.C)
+
+ neartag(posx[snum],posy[snum],posz[snum],cursectnum[snum],
+ ang[snum],&neartagsector,&neartagwall,&neartagsprite,
+ &neartaghitdist,1024L);
+ if (neartagsector == -1) //If no neartagsector found...
+ {
+ i = cursectnum[snum]; //Test current sector for tagging
+ if ((sector[i].lotag|sector[i].hitag) != 0)
+ neartagsector = i; //Cursectnum is the neartagsector!
+ }
+
+ - Improved my gamma correction algorithm. Since it now uses a new
+ 1K at the end of my TABLES.DAT, be sure to update all your
+ TABLES.DAT files! My new gamma correction supports 16 levels
+ of brightness (0-15). You need not change any code in your
+ game if you already have gamma correction programmed.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+11/17/94 - Made swinging door clipping code work even better. The bug was:
+ it only tested the clipping if you were in the same sector as
+ the door. So I put this handy little function in GAME.C which
+ simply tests if 2 sectors are neighbors or not:
+ testneighborsectors(short sect1, short sect2)
+ Check it out!
+
+ - Rewrote my clipinsidebox function. You probably don't use this
+ function, but if you copied my swinging door code, then you
+ will need to update this. Clipinsidebox is used for clipping
+ to determine whether a player or sprite is too close to a
+ wall.
+
+ clipinsidebox(long x, long y, short wallnum, long walldist)
+ X and y are the position of the sprite or player. Wallnum
+ is the wall to test, and walldist is the fatness of the sprite
+ or player (same as clipmove). It returns a 1 if the sprite or
+ player's clipping square intersects the wall or 0 if not.
+
+ Example - You can test all 4 walls of a swinging door and make
+ sure the door doesn't run you over:
+
+ short swingwall[4]; //4 wall indeces of a swinging door
+ for (i=0;i<4;i++)
+ if (clipinsidebox(posx,posy,swingwall[i],128L) == 1)
+ {
+ //Swinging door swung into player, so move door back to
+ //its old position / inverse swinging direction.
+
+ break;
+ }
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+11/22/94 - Made build posx, posy, posz, ang, cursectnum, and horiz variables
+ nonstatic.
+
+ - Made hi-res screen capture work.
+
+ - Fixed some of those evil view-clipping bugs with rotated sprites
+ on red sector lines. I think it should work with rotated
+ sprites on horizontal or vertical red lines. I'm not sure
+ about weird angled lines.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+11/23/94 - ATTENTION PROGRAMMERS: Made parallaxing skies tileable in any
+ equal size chunk where the chunk x size is a power of 2
+ from 16-1024. You can now make a 2048 wide parallaxing sky
+ with 2 chunks of 1024 (gobble gobble).
+
+ These lines were added to BUILD.H:
+
+ #define MAXPSKYTILES 256
+ EXTERN short pskyoff[MAXPSKYTILES], pskybits;
+
+ pskyoff[MAXPSKYTILES] is an array of OFFSETS of each tile
+ from the picnum of the parallaxing sky.
+
+ pskybits is NOT the actual number of tiles, but the
+ log (base 2) of the number of tiles. Look at this table:
+
+ For 1 tile, pskybits = 0
+ For 2 tiles, pskybits = 1
+ For 4 tiles, pskybits = 2
+ For 8 tiles, pskybits = 3
+ For 16 tiles, pskybits = 4
+ etc.
+
+
+ I know that most teams have a 1024 wide parallaxing sky that
+ wraps all the way around. Don't worry - this is the
+ default now. When initengine is called, the variables
+ default to this:
+
+ pskyoff[0] = 0;
+ pskybits = 0;
+
+ You may have used a 512 wide parallaxing sky (like in my game)
+ that repeated every 180 degrees. To make this work with
+ the new version, set these variables like this right after
+ initengine is called:
+
+ pskyoff[0] = 0;
+ pskyoff[1] = 0;
+ pskybits = 1;
+
+ Note that both pskyoff variables are 0 here. This will
+ make the parallaxing sky repeat.
+
+ With the new tiling, you can save memory by making small
+ chuck sizes, such as 64 or 128, and repeating certain
+ sections.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+11/25/94 - Fixed some really stupid keyboard problem in Build.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+11/29/94 - Added FLOOR SPRITES!!! Here are some things that floor sprites
+ can do for you:
+
+ * Make bridges and balconies
+ * Use them for ceiling and floor ornamentation
+ * Use them in place of a rotating sector - modifying 1 angle
+ is much faster than rotating tons of points.
+ * Weapon such as a spinning saw blade or, of course, a smiley
+ red jelly coconut. (?)
+ * How about a "walking" hole like in Ken's Labyrinth
+ * You could throw a footstep on the floor every time you make a
+ step. The steps would go away after awhile. Maybe if you
+ step in mud, the next 16 or so footsteps will be plotted.
+ * You could even fake radial shading with a transluscent floor
+ sprite. (Transluscent floor sprites not yet programmed)
+
+ Just imagine all the great stuff you can do with floor
+ sprites combined with wall sprites! I can't wait to see what
+ you all come up with!
+
+ 旼 To clear some confusion, and to shorten conversations, let
+ me give official names to my 3 kinds of sprites:
+
+ Normal stupid sprites - "FACE SPRITES"
+ Rotated / masked wall sprites - "WALL SPRITES"
+ New ceiling & floor sprites - "FLOOR SPRITES"
+
+ Also let me clear up the 2 kinds of clipping:
+
+ Clipping when moving something - "MOVEMENT CLIPPING"
+ 읕 Clipping when drawing something - "VIEW CLIPPING"
+
+ To make a floor sprite in BUILD, simply press 'R' on any
+ sprite until it becomes a floor sprite. The xrepeat and
+ yrepeat values should work perfectly with floor sprites.
+ Floor sprites can be rotated at any of 2048 degrees, using
+ the sprite[].ang. Press < / > for course angle adjustment
+ or < / > with shift for fine angle adjustment. Also, you
+ can press 'F' on a floor sprite to flip it over like a
+ mirror. I am using another bit in sprite[].cstat to determine
+ the type of sprite. See the documentation in BUILD.H.
+
+ Now for the bad news:
+
+ * Floor sprite textures have similar restrictions as normal
+ ceilings and floors - both dimensions must be a power of 2.
+ This will most likely not change.
+
+ And some known problems which I will have to fix:
+ * Transluscence doesn't work yet
+ * Sorting with other sprites
+ * View clipping with walls
+ * Doesn't work too well in hi-res mode
+
+ See NUKELAND.MAP for some examples of floor sprites. I have both
+ a bridge and a balcony on the level. Please find them!
+ Remember that floor sprites don't work in mode x or hi-res
+ mode YET!
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+11/30/94 - Made WALL SPRITE and FLOOR SPRITE correctly do movement clipping.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+12/1/94 - Made new map called BRIDGES.MAP. It is excellent! It has 3
+ bridges all crossing each other. Enjoy!
+
+ - For Editart, I added re-centering after delete and / to reset
+ centering while in centering mode.
+
+ - Debugged more of the floor sprite stuff.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+12/2/94 - Made transluscence with floor sprites work. Check out my fake
+ radial shading under the lights of SUBWAY.MAP.
+
+ - Optimized floor sprites in assembler. Transluscent floor sprites
+ are a bit slower than normal floor sprites.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+12/6/94 - Made a special 1-way mode for WALL and FLOOR sprites
+ (not FACE sprites). In BUILD 3D mode, you can press '1' on
+ a wall or floor sprite to make it only draw if you are on
+ 1 side of it. This method of back-face culling will not only
+ make non-masking objects with thickness draw twice as fast,
+ but will also make fewer drawing bugs due to sprite drawing
+ order. Try out my BRIDGES.MAP. There's a new section at the
+ top and it's not another "ugly Ken's face n' slime" room.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+12/8/94 - Editart and Build now capture with capt#### rather than captur##
+ allowing 10000 captured pictures.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+12/23/94 - Increased Maximum number of walls to 8192.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+12/28/94 - Made BUILD stub keys F5-F8 work in 3D mode also. See top
+ of BSTUB.C for full documentation of some new useful
+ variables that can be used inside the stub:
+
+ extern long qsetmode;
+ extern short searchsector, searchwall, searchstat;
+
+ In 3D mode, F5 and F6 do the exact same thing and F7 and F8
+ do the exact same thing (you don't need the extra key to
+ distinguish between sectors, walls and sprites, since the
+ mouse cursor can only be on 1 of the 3 objects in 3D mode.
+
+ Note: Since F5-F8 are called in 3D mode, you must be sure
+ NOT to use any 2D routines during those calls! This means
+ you will have to put the 3D/2D case check in all six
+ subroutines:
+ ExtShowSectorData, ExtShowWallData, ExtShowSpriteData,
+ ExtEditSectorData, ExtEditWallData, ExtEditSpriteData
+
+ - KEN'S PROPOSAL (NOT YET DONE) I am thinking of making a new
+ (and maybe final) map format. But before I do it, I am going
+ to ask all of you for any suggestions on new fields to add to
+ my 3 big structures (sector, wall, sprite):
+
+ Here are a few things already on my list to add:
+
+ * char sprite[].clipdist - THIS IS FOR SURE
+ This will be a sprite's clipping distance. My default
+ walldist is 128. With this field, you will finally be
+ able to make a unique fatness for each sprite with no
+ clipping bugs. I will probably shift this field up 2-4
+ bits to give it a range of more than just 0-255.
+
+ * char wall[].pal, sprite[].pal - PRETTY SURE
+ It should have been this way the whole time. Currently
+ the wall's palookup number is sector[].floorpal. While
+ it may save some memory, It has too many limitations.
+ I can make my map converter automatically convert all
+ walls of a sector to equal the sector[].floorpal so
+ don't worry about that type of conversion. If I do
+ this, I can get rid of the spritepal[] hack.
+
+ * I have decided that the sector[].extra, wall[].extra, and
+ sprite[].extra will remain in the structures as little
+ gifts for your use only. That's right! ALL YOURS!
+ ENJOY!!!
+
+ * char sprite[].xoffset, sprite[].yoffset - NOT SURE YET
+ Some have asked for monster animations using the same
+ frame at 2 different times of an animation sequence having
+ different centers.
+ These will be signed chars. I'm not sure whether to
+ make these offsets as offsets to the centering information
+ from Editart or just make them the absolute offsets where
+ Editart's data is the default offset. I wonder if there's
+ a better way to do this without having to waste 8K.
+
+ * Do I have your permission to remove nextsector2 and
+ nextwall2? Anybody using them? If so, can you use the
+ extra variable instead? This will save 16K since both
+ are shorts. (MAXWALLS*short + MAXWALLS*short = 16384)
+ They were originally intended for 2 stories
+ but it would be totally ridiculous for me even to think
+ about programming that now. Besides, you can use wall
+ and floor sprites to fake 2 story areas. KEN PROMISE:
+ I will fix those darn view-clipping bugs eventually!
+
+
+ Please send any comments/suggestions to my internet address
+ (kjs@lems.brown.edu) I will consider each suggestion
+ carefully, because everything you suggest now won't have
+ to be an ugly hack like spritepal[] later.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+1/1/95 - 栢栢 栢栢栢 栢 栢 栢 栢 栢 栢 栢栢栢 栢栢栢 栢栢栢 栢
+ 栢 栢 栢 栢白 栢 栢 栢 栢白蔔栢 栢 栢 栢 栢 栢 栢
+ 栢 栢 栢 栢栢栢 栢 蔔 栢賞幡栢 栢栢栢 栢栢栢 栢栢栢 栢
+ 栢 栢 栢 栢 賞栢 栢栢 栢 栢 栢 栢 栢 栢 栢
+ 栢栢 栢栢栢 栢 賞 賞 栢 栢 栢 栢 栢 栢栢栢 栢
+
+ CONVMAP6! Here is what I changed in the structures:
+
+ * Added wall[].pal, sprite[].pal
+ * Added sprite[].clipdist
+ * Expanded sprite[].cstat to a short
+ * Added sprite[].xoffset, sprite[].yoffset
+ * Removed wall[].nextsector2, wall[].nextwall2
+ * Renamed wall[].nextsector1 to just wall[].nextsector
+ * Renamed wall[].nextwall1 to just wall[].nextwall
+ * Scrapped numextras and extratype structure - Don't confuse
+ this with sector[].extra, wall[].extra, sprite[].extra
+ which ARE in map version 6.
+
+ Probably the only change above that will affect programmers is
+ getting rid of the '1' in wall[].nextsector1&wall[].nextwall1.
+ All the following changes were possible because of the new
+ map format.
+
+ - Got rid of the spritepal array in BUILD.H. With my grea
+ new map version 6, you can simply modify sprite[].pal!
+
+ - Made all .pal fields editable in 3D EDIT MODE. Press ALT-P
+ and simply edit the number as you would in 2D mode.
+
+ - Made sprite[].xoffset and sprite[].yoffset work as
+ offsets to the offsets that are already in EDITART.
+ Simple addition. They should work for all 3 types
+ of sprites.
+
+ - Made BUILD Tab&Enter also copy tags&extra if copying similar
+ structures. Also fixed some other attributes when
+ copying between structure types.
+
+ - Made sprites highlighted with Rt. Shift duplicate and stamp
+ when the insert key is pressed in 2D EDIT MODE.
+
+ - Made sprite[].clipdist work as the FACE SPRITE'S clipping
+ fatness. NOTE: Sprite[].clipdist is shifted up 2 to
+ allow a range from 0-1020, so if the sprite[].clipdist
+ is set to 32, then the clipping radius is actually 128.
+
+ - Removed the walldist parameter from movesprite. Movesprite
+ now just uses the sprite[spritenum].clipdist field of
+ whatever sprite is passed (shifted up 2).
+
+ movesprite(short spritenum, long xchange, long ychange,
+ long zchange, long ceildist, long flordist,
+ char cliptype, long numtics)
+
+ If you use clipmove or getzrange, you should check that you
+ are passing the correct walldist parameters. I'm saying
+ you may want to change some of the 128s to
+ (sprite[spritenum].clipdist<<2).
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+1/3/95 - Made startumost[], startdmost[] into shorts.
+
+ - Optimized and fixed gamma correction in Stereo Red-Blue mode.
+
+ - Made weapons or anything using overwritesprite in Stereo Red-Blue
+ mode be at screen depth.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+1/4/95 - Not that anybody would care (except for some crazed mega-hackers)
+ but I am just mentioning the fact that I did this:
+
+ animateoffs(short tilenum, short fakevar);
+ where fakevar is sectnum+0
+ or wallnum+16384
+ or spritenum+32768
+ or 49152 (just ignore-it's for rotatesprite)
+
+ Also: I changed one: "mov al, 0" instruction into an
+ "xor al, al", a net savings of
+ ONE LOUSY BYTE! Let's not get TOO
+ excited! (By the way, just kidding)
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+1/5/95 - Fixed the sprite centering with x-flipped FACE SPRITES.
+
+ - Found a bug with my swinging door clipping code. There are 2
+ types of swinging doors, forwards (opens CCW) and
+ backwards (opens CW). The bug was that you could sneak
+ through a backwards door from the back side. Well, I fixed
+ it, so now I challenge you to sneak through my swinging doors
+ now! If you are using my swinging door code, please make
+ these changes which you should find in my new GAME.C:
+
+ 1. Changed declaration at beginning of GAME.C:
+ static short swingwall[32][5];
+
+ 2. Added new line in prepareboard:
+ swingwall[swingcnt][4] = lastwall(swingwall[swingcnt][3]);
+
+ 3. Modified some stuff in tagcode:
+ //swingangopendir is -1 if forwards, 1 is backwards
+ l = (swingangopendir[i] > 0);
+ for(k=l+3;k>=l;k--)
+ if...
+
+ - Here are some more functions that have been in the engine for
+ a while, but I forgot to document...
+ precache, loadtile, lastwall, rotatepoint
+ They are now documented at the top of this file.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+1/6/95 - Optimized loading/saving of maps by using fewer read/write calls.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+1/14/95 - Fixed evil crashing bug that I accidently introduced in the
+ 1/3/95 version of Build. This crashing bug happened mostly
+ in tall rooms with lots of FACE SPRITES. It used to crash
+ very infrequently when you were standing almost exactly, but
+ NOT on the same x & y coordinates of a FACE SPRITE where the
+ z-distance was high.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+1/15/95 - Fixed up network code so now you can miss 4 packets in row safely
+ over the network rather than just 2.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+1/16/95 - Added strafe left / strafe right keys to my SETUP.DAT file and
+ char keys[19] array. If you actually use my keys array for
+ custom keys, here's what to do: I inserted the new strafing
+ keys at keys[12] & keys[13], so just add 2 to any keys with
+ an index >= 12.
+
+ - Made the sprites in 2D EDIT MODE of Build highlight properly
+ again.
+
+ - Added another parameter to permanentwritesprite, palookup number:
+
+ permanentwritesprite(long thex, long they, short tilenum,
+ signed char shade, long cx1, long cy1,
+ long cx2, long cy2, char dapalnum);
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+1/17/95 - You can now select a bunch of sprites in 2D EDIT MODE with
+ Rt. shift, then go to 3D mode and change the z's of all the
+ highlighted sprites.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+1/20/95 - Made Tab&Enter in 3D EDIT MODE copy .pal also whenever .shade is
+ normally copied. Shift+Enter will now copy just
+ .pal and .shade.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+1/21/95 - Made Splitsector work with overlapping better.
+
+ - In Editart 'U' mode, it now goes automatically to the PCX and
+ coordinates of a tile if it is already in capfil.txt.
+
+ - In Editart, made capt????.PCX not get overwritten if they already
+ exist.
+
+ - Fixed Build tab on masked walls.
+
+ - Made zmode and kensplayerheight variables public in BUILD/BSTUB
+ so you can now compile BUILD to start out with your own
+ preferred settings. Kensplayerheight defaults to 32 and
+ zmode defaults to 0. You can over-ride these settings in
+ the new ExtInit function.
+
+ - Made Editart tiles much easier to center by showing all tiles
+ in the center of the screen instead of at the top-left corner.
+ (Editart will not allow you to center tiles larger than
+ 320*200 right now)
+
+ - Made 'O' (optimize) key in Editart automatically preserve
+ the centering information.
+
+ - ATTENTION BSTUB PROGRAMMERS! Added ExtInit, ExtUnInit, and
+ ExtCheckKeys to BSTUB.C. Please just copy mine into your
+ current BSTUB. ExtInit and ExtUnInit are called only once.
+ ExtInit is called before loadpics() and after initengine().
+ ExtCheckKeys() is called just before nextpage in both 2D
+ and 3D modes. In 3D mode, you must call editinput inside
+ ExtCheckKeys just like my example in BSTUB.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+1/24/95 - Fixed vertical line chained mode bug with permanentwritesprites.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+1/31/95 - Fixed parallaxing sky tiling bug.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+2/1/95 - Fixed network crashing bug when call interrupt 0x1c. You call
+ this interrupt when you chain to the old timer handler. Now
+
+ - Rewrote multiplayer code in game.c a bit. Moved both sync()
+ and getpackets() into the main program. The master code and
+ single player game code are now the same. Slaves need to
+ drawscreen and send packets only when a packet is received
+ from the master. Got rid of fake sync[MAXPLAYERS] slot by
+ using a local sync buffers. Rewrote checkmasterslaveswitch().
+ If you don't get what I did, it doesn't matter because you
+ already have working network code!
+
+ - Added new key in EDITART 'V' mode. Press ALT-R to generate
+ a tile frequency report. It will scan all MAP files in the
+ same directory as the ART files. The frequency count will
+ show up as text in the top-left corner of the boxes in
+ 'V' mode. Press ALT-R again to turn off text.
+
+ - Perfected NCOPY! Copies about 150K / second which is 10 times
+ faster than a 115200bps serial cable. Since NCOPY already
+ links with multi.obj, it should not be too difficult to make
+ joining work in the middle of a network game. Please wait
+ until I make some sample code for you!
+ Receiver types: NCOPY (Ex: "NCOPY")
+ Sender types: NCOPY [filespec] (Ex: "NCOPY *.ART")
+
+ Ken's formula:
+ NCOPY + Loading&Saving GAMES = joining in middle
+ of network game!
+
+ - Made a DOOM to BUILD converter. Right now it only converts
+ ceilings, floors, and walls now, and some of the wall
+ textures are screwed up. Just because I converted some
+ lousy stinkin' maps DOES NOT MEAN I AM GOING TO PROGRAM DOOM!
+ Unfortunately, the converter is programmed in QuickBasic right
+ now, it won't compile, and I didn't feel like putting up the
+ 7 MEG converted ART file up. When I convert it to C, I'll
+ upload it for all!
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+2/7/95 - Fixed overwritesprite bugs with translucence in chained mode
+ and above top of screen.
+
+ - Made bit 3 of overwritesprite x-flip the picture if set.
+
+ - Optimized various parts of engine.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+2/8/95 - Fixed shading of all sprite types so they match perfectly with
+ their surroundings. Floor sprites now shade in the exact same
+ way as ceilings and floors. (Before, the whole floor sprite
+ had the same shade throughout)
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+2/9/95 - Started on loading and saving game code so I could give some
+ sample code for joining network games, but none of it works
+ yet, so just ignore it for now!
+
+ - Added frame rate in BSTUB.C. It averages the last 16 frames.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+2/16/95 - Added another bit to sprite[].cstat for y-centering control. If
+ bit 7 is set then the sprite's center will be the actual
+ center rather then at the default position which is at the
+ bottom of the sprite. If you use this centering bit,
+ you finally get "WYSIWYG" centering contol in EDITART.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+2/24/95 - Made floor sprites now support any x size by a power of 2 y size.
+ (That's better than before!) These are the same restrictions
+ on walls.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+2/25/95 - Got loading / saving code to work with my game. Press Ctrl-L to
+ load game and Ctrl-S to save game. Saved games are called
+ SAVE0000.GAME and are about 300K. Don't worry about the large
+ sizes of the saved game files since they can be easily
+ compressed to less than 50K.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+2/26/95 - I Finally made my multiplayer code run with fast frame rates AND
+ pefect controls on ALL computers of a multiplayer game. I am
+ now sending keystrokes of all computers at a constant rate of
+ 40 times per second. All computers interpolate between frames
+ to get screen frame rates of higher or lower than 40 fps
+ (even in single player mode).
+
+ Here are the exact steps you will need to follow if you want to
+ update your code:
+
+ 1. WHAT'S THE FAKETIMERHANDLER()?
+
+ To send packets exactly 40 times a second, it would
+ sure be nice to send them right from the timer interrupt
+ handler. Too bad network packets just won't get sent
+ from the interrupt handler. (It may work from the
+ interrupt handler in Serial/Modem mode) So the solution
+ is to make a "fake" timer handler that must be called
+ at least 40 times a second even on the slowest computer.
+ Throughout my engine, I call faketimerhandler(). If you
+ have any slow parts in your game code, you may want to
+ called faketimerhandler() also.
+ Besides the very first few lines, the rest of the code
+ was taken directly from my old sync and getpackets
+ functions.
+
+ 2. BYE BYE SYNCTICS!
+
+ Now that all computers are calling movethings a
+ constant number of times a second, you don't need any
+ synctics variables anymore. You can convert all the
+ synctics variables to a define such as:
+ "#define TICSPERFRAME 3"
+ Doing this will guarantee that a game runs the same on
+ all speed computers.
+
+ 3. FRAME INTERPOLATION (optional):
+
+ static long ototalclock = 0, gotlastpacketclock = 0;
+ static long oposx[MAXPLAYERS], cposx[MAXPLAYERS];
+ static long oposy[MAXPLAYERS], cposy[MAXPLAYERS];
+ static long oposz[MAXPLAYERS], cposz[MAXPLAYERS];
+ static long ohoriz[MAXPLAYERS], choriz[MAXPLAYERS];
+ static long ozoom[MAXPLAYERS], czoom[MAXPLAYERS];
+ static short oang[MAXPLAYERS], cang[MAXPLAYERS];
+
+ Add to prepareboard:
+ for(i=connecthead;i>=0;i=connectpoint2[i])
+ {
+ oposx[i] = posx[i];
+ oposy[i] = (etc.)
+ }
+ ototalclock = 0;
+ gotlastpacketclock = 0;
+
+ Even though you may be getting more than 40fps, you will
+ only be seeing 40fps unless you interpolate between frames.
+ The oposx[], etc. variables back up the last posx[], etc.
+ variables so you can interpolate your actually drawing
+ position as some fraction between the two. This fraction
+ is smoothratio.
+ See beginning of drawscreen code. Here's where I actually
+ calculate the interpolated position to draw the screen.
+
+ for(i=connecthead;i>=0;i=connectpoint2[i])
+ {
+ cposx[i] = oposx[i]+mulscale(posx[i]-oposx[i],smoothratio,16);
+ cposy[i] = oposy[i]+mulscale(posy[i]-oposy[i],smoothratio,16);
+ cposz[i] = oposz[i]+mulscale(posz[i]-oposz[i],smoothratio,16);
+ choriz[i] = ohoriz[i]+mulscale(horiz[i]-ohoriz[i],smoothratio,16);
+ czoom[i] = ozoom[i]+mulscale(zoom[i]-ozoom[i],smoothratio,16);
+ cang[i] = oang[i]+mulscale(((ang[i]+1024-oang[i])&2047)-1024,smoothratio,16);
+ }
+
+ Draw the screen using cposx[], etc. instead of posx[], etc.
+
+ #pragma aux mulscale =\
+ "imul ebx",\
+ "shrd eax, edx, cl",\
+ parm [eax][ebx][ecx]\
+ modify [edx]\
+
+ It reads: eax = (eax*ebx)>>cl. Unlike C, this will
+ not overflow even if eax*ebx > 2^31, making full use of
+ the 64-bit result of the imul instruction.
+
+ 4. MOVETHINGS FIFO:
+
+ static long movefifoplc, movefifoend;
+ static signed char baksyncvel[64][MAXPLAYERS];
+ static signed char baksyncsvel[64][MAXPLAYERS];
+ static signed char baksyncangvel[64][MAXPLAYERS];
+ static short baksyncbits[64][MAXPLAYERS];
+
+ Add to prepareboard: movefifoplc = 0; movefifoend = 0;
+
+ It is bad to call movethings inside faketimerhandler
+ because you don't want things to move while you're drawing
+ the screen. To solve this, I made movethings just save
+ away the parameters it was called with using a circular
+ buffer, and when I'm actually ready to DO the movement code,
+ I call domovethings.
+ Rename movethings to domovethings and see my new
+ movethings. This code is all for the fifo.
+
+ Put this line in movethings:
+ gotlastpacketclock = totalclock;
+
+ At the top of domovethings, copy my code for loading off
+ of the fifo. Also set oposx[] = posx[], etc. here.
+
+ 5. You may want to add a global variable that controls whether
+ you are in continuous packet sending mode or not. Only
+ in the main loop should ready2send be != 0.
+ static long ready2send = 0;
+
+ 6. The new main loop can be as short as this, with no case
+ checking for masters and slaves.
+
+ ready2send = 1;
+ while (keystatus[1] == 0) //Main loop starts here
+ {
+ //Actaully move everything here.
+ while (movefifoplc != movefifoend) domovethings();
+
+ //Second parameter is for frame interpolation,
+ //A fraction that ranges from 0-65536.
+ drawscreen(screenpeek,(totalclock-gotlastpacketclock)*(65536/TICSPERFRAME));
+ }
+ ready2send = 0;
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+3/6/95 - New key in BUILD. Now when you use relative alignment mode on
+ ceiling and floor textures, you can press Alt-F on the ceiling
+ or floor to choose a new wall to align to. It actually
+ rotates the walls of a sector by 1.
+
+ - Fixed screen capture PCX saving bug in both EDITART and BUILD.
+
+ - Added a parameter to screencapture, a filename.
+ screencapture(char *filename)
+ Ex: screencapture("captxxxx.pcx");
+ Please specify the full filename. Screencapture will modify
+ the 4 x's of the string to be a number starting at 0000.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+3/8/95 - Made my rotatesprite function use Editart centering information.
+ The center is the pivot point of rotation.
+
+ - Added y-flipping to overwritesprite. See above documentation.
+
+ - Added 2 new parameters to rotatesprite, shade and pal
+
+ rotatesprite (long sx, long sy, long z, short a,
+ short picnum, signed char shade, char pal);
+
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+3/10/95 - Fixed sprite showing through closed sectors bug.
+
+ - Made it possible to draw the overhead map in 3D mode by adding
+ a line drawing function in 3D mode called drawline256. It
+ draws a line clipped to the viewing rectangle last set in
+ setview(). Here are the parameters:
+
+ drawline256(long x1, long y1, long x2, long y2, char col);
+
+ Note: The coordinates are all shifted up 12.
+ Example: drawline256(0L,0L,319L<<12,199L<<12,31);
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+3/11/95 - Made drawline256 draw in a cleaner way, making use of the full
+ 12 bits of precision.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+3/14/95 - Optimized / cleaned up parts of hitscan, neartag, cansee.
+ Gee, I hope they all still work!
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+3/18/95 - I'm back in RI!
+
+ - Fixed recently added movesprite z parameter bug that may have
+ done strange things with monsters, such as stuck in sectors
+ I thought the following expression: !(cstat&128)
+ would be true if bit 7 was a 0, but I WAS WRONG!
+ Get this straight:
+ ! - logical NOT, returns 0 if != 0 else 1 (!2457=0, !0=1)
+ ~ - bitwise NOT, xor's it with 0xffffffff (~0x5f=0xa0)
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+3/21/95 - Gave access to some more variables in BSTUB.
+
+ - Made clipmove return a valid sector even if you're not between
+ its ceiling and floor. If you use overlapping sectors,
+ clipmove will find the sector closest to your z.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+3/28/95 - Optimized transluscence for masked walls and wall sprites.
+
+ - Today is the day I declare my serial/modem error correction code
+ perfect! Sure, I may have bragged over and over again about
+ how perfect my correction method is each time, but this time
+ I mean it. This is ship-it quality error correction. The old
+ method had a few dark, evil, and ugly bugs that sometimes
+ totally screwed up bigtime.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+4/5/95 - Got Master/Slave switching to stay in sync again with new
+ multiplayer code. Right after the master sends a packet
+ where a switch is made, I disable the master from sending
+ any more packets by setting ready2send to 0. Ready2send
+ will be set back to 1 only after the actual switch in
+ checkmasterslaveswitch. Here's what I added to movethings:
+
+ //Do this for Master/Slave switching
+ for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
+ if (syncbits[i]&512) ready2send = 0;
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+4/10/95 - Optimized continuous setview calls between 2 different window
+ sizes.
+
+ - ATTENTION PROGRAMMERS: Moved movesprite code into game.c. It
+ no longer exists in the engine. It is a "cover-up" function
+ and it should be yours.
+
+ - Added a circular keyboard buffer to my keyboard handler. It is
+ fully compatible with the keystatus arrays. Use this buffer
+ for typing in messages or cheat codes. If you do not use this
+ buffer (or you wrote your own interrupt handler), you will miss
+ keys and it is very annoying.
+
+ I added these variables to build.h:
+
+ #define KEYFIFOSIZ 64
+ EXTERN volatile char keyfifo[KEYFIFOSIZ],
+ keyfifoplc, keyfifoend;
+
+ Every time a key is pressed and released, I add 2 bytes to the
+ circular buffer. The first byte is the scan code. The second
+ byte is a 1 for key pressed or 0 for key released. You can
+ ignore the key releases if you wish. You must read 2 bytes at
+ a time from this buffer.
+ (scancode,keystat),(scancode,keystat),...
+
+ Here's how you read the keyboard fifo:
+ while (keyfifoplc != keyfifoend) //More characters to read
+ {
+ ch = keyfifo[keyfifoplc];
+ keystate = keyfifo[(keyfifoplc+1)&(KEYFIFOSIZ-1)];
+ //Increment buffer pointer
+ keyfifoplc = ((keyfifoplc+2)&(KEYFIFOSIZ-1));
+
+ printf("Scancode: %d, status: %d\n",ch,keystate);
+ }
+
+ The interrupt handler does the same as above but writes and
+ increments using keyfifoend as the index.
+ You can easily clear the buffer this way:
+ keyfifoplc = keyfifoend
+
+ - Made clipmove/getzrange not clip on the back side of a 1-sided
+ wall/floor sprite. It makes the clipping a little faster
+ and seems to fix a few minor clipping bugs. Don't get too
+ excited.
+
+ - Fixed getzrange's ceilz/florz mismatch with floor sprites against
+ normal ceilings and floors.
+
+ - Made Build default to y-centered centering mode when sprites
+ are inserted (bit 7 of sprite[].cstat)
+
+ - Fixed clipmove bugs with y-centered centering mode.
+
+ - Made it so you don't get stuck sliding along multiple properly
+ aligned wall/floor sprites.
+
+ - Please update to my new tables.dat.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+4/11/95 - Optimized parts of clipmove / getzrange. Is it faster? Did I
+ make more bugs?
+
+ - Made the movesprite code in GAME.C now use getzrange. This
+ allows sprites to walk on floor sprites and bombs roll across
+ bridges. I will include the original movesprite code that
+ came from the engine in case you want to start with things
+ the way they used to be.
+
+ - Made ornamentation in BUILD 3D mode much easier. Now you can
+ press 'S' to insert a sprite on walls (not just ceilings
+ and floors). When you insert a sprite on a wall, it will
+ automatically be set to a wall sprite at the wall's angle.
+ Also it will be 1-sided with blocking off (The optimal
+ options for a decorative sprite on a wall).
+
+ - Added ALT-D to BUILD 3D mode. It lets you type in clipdist
+ for sprites. It works in the same way as ALT-P for palookup
+ changing.
+
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+4/15/95 - Fixed return value bug in setanimation and cleaned up these 3
+ functions: doanimations, getanimationgoal, setanimation.
+ Since they are now in game.c, you will need to copy them to
+ update.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+4/16/95 - Fixed hitscan not passing through loops bug.
+
+ - Fixed hitscan so it hits wall and floor sprites in the right
+ places.
+
+ - ATTENTION PROGRAMMERS!!! Made bit 8 of sprite[].cstat the
+ hitscan clipping bit. It works like the hitscan bit for walls.
+ Note that both the wall and sprite cstat variables now have
+ 2 separate bits for clipping, where:
+ 1 is for use with the clipmove/getzrange function and
+ 1 is for use with the hitscan function only.
+ Before, hitscan used to use 1 bit for all sprite clipping.
+ In your maps, the sprite hitscan bits are all zeros. That's bad!
+ To make things work like they used to, the sprite hitscan bit
+ must be set equal to the old sprite blocking bit. So I was nice
+ enough to make a program, FIXSPRBT.EXE, which will do just that.
+
+ PLEASE RUN FIXSPRBT.EXE ON ALL YOUR MAPS. You don't HAVE to
+ run it on all your maps since the map format hasn't changed, but
+ it will save you annoying attribute setting time if you do.
+
+ - Did a few things to make these blocking bits easier to edit:
+ Since H and ALT-H were already used, I made CTRL-H toggle the
+ hitscan bit for both walls and sprites in 2D mode. B toggles
+ the blocking bit. B also now sets the hitscan bit to its
+ default value when you press it. For sprites, the hitscan bit
+ default is equal to the clipmove bit. For walls, the hitscan
+ bit default is always 0.
+
+ - Added new map mode! Check it out in my game. I now have 3 map
+ modes. Not that this really matters to you game programmers, but
+ this is how my game works:
+ dimensionmode[snum] == 1 3D MODE + junky line map
+ dimensionmode[snum] == 2 SUPER MAP!
+ dimensionmode[snum] == 3 3D MODE
+
+ I added show2dsector to BUILD.H which controls which works
+ like the other show2d... bit arrays. It tells which sectors
+ to show.
+ EXTERN char show2dsector[MAXSECTORS>>3];
+
+ I rewrote parts of drawoverheadmap to accommodate this new
+ mode - so it would be nice if you updated to my new code.
+
+ Added a new function that clears full screen to a specified
+ color:
+ clearview(0L);
+
+ Oh and did I forget to mention the big function! Parameters
+ are the exact same my drawoverheadmap function:
+ drawmapview(cposx,cposy,czoom,cang);
+
+ Note: The new map mode right now is slowed down bigtime by
+ the face sprites using the rotatesprite function. The
+ rotatesprite right now is using a worse than awful
+ algorithm. When I optimize rotatesprite, the frame rate
+ of the new map mode will fly!
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+4/18/95 - Added default sprite cstat variable when you insert new sprites.
+ Set it to 0 if you hate the new centering mode in ExtInit
+ or 128 if you like the new centering mode.
+ Add this line to your Bstub if you wish:
+ extern short defaultspritecstat;
+
+ - If a wall & sprite are same distance away using hitscan, hitscan
+ now chooses the sprite.
+
+ - Optimized rotatesprite.
+
+ - ATTENTION PROGRAMMERS: Added new paramater at end of
+ rotatesprite: A char where the first bit tells it to use
+ transluscence mode or not.
+
+ rotatesprite(long sx, long sy, long z, short a, short picnum,
+ signed char dashade, char dapalnum, char dastat)
+
+ if ((dastat&1) == 0) - no transluscence
+ if ((dastat&1) != 0) - transluscence
+
+ - Cleaned up drawmapview further by making ALL floor sprite draw
+ with the texture in the right place and made the polygon
+ filling algorithm use higher screen coordinate precision.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+4/19/95 - Added parameter to makepalookup:
+
+ makepalookup(long palnum, char *remapbuf,
+ signed char r, signed char g, signed char b,
+ char dastat)
+
+ if ((dastat&1) == 0) then makepalookup will allocate & deallocate
+ the memory block for use but will not waste the time creating
+ a palookup table (assuming you will create one yourself)
+ if ((dastat&1) != 0) then makepalookup will allocate & deallocate
+ the memory block AND create a palookup table using the rgb
+ values you pass.
+
+ - Made my ceiling&floor update the self-modified palookup pointers
+ when palookup[sector[].?pal] changes, not just when
+ sector[].?pal] changes. Watching for changing pointers rather
+ than changing indeces should solve the problem with screwy
+ palookup selection for ceilings&floors. Ignore what I said
+ before. You should now be able to change palookup pointers
+ freely.
+
+ - Optimized relative alignment. It should be the same speed as
+ all other ceilings & floors now.
+
+ - Warning: Since I added the new bit in sprite[].cstat, there are
+ now 9 bits in use. Make sure to treat it as a short. In my
+ code, I had some bugs where I did this:
+ sprite[].cstat &= (255-4); BAD! Cstat's a short! Please
+ check your code and make sure you clear the bits this way:
+ sprite[].cstat &= ~4;
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+4/21/95 - Fixed bug with flipping textures on ceilings & floors. In
+ BUIL0419.ZIP I had a bug whenever a ceiling or floor texture
+ had bit 4 set. It drew the texture backwards. Well, I
+ fixed it. Hope you didn't "Build" on this bug!
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+4/22/95 - Fixed really really stupid hitscan returning sector < 0 bug. If
+ you were calling hitscan from the top-left triangular region
+ of the board it stupidly returned a -1 for the sector. Well,
+ I fixed it.
+
+ - ATTENTION EVERYBODY!!! Moved setup.dat loading from the engine
+ into GAME.C and BSTUB.C. If you copy this code from game.c
+ into your game / bstub, they will work like it used to:
+
+ ----- NEW GLOBAL VARIABLES: -----
+
+ #define NUMOPTIONS 8
+ #define NUMKEYS 19
+ static long chainxres[4] = {256,320,360,400};
+ static long chainyres[11] = {200,240,256,270,300,350,
+ 360,400,480,512,540};
+ static long vesares[7][2] = {320,200,640,400,640,480,
+ 800,600,1024,768,
+ 1280,1024,1600,1200};
+ static char option[NUMOPTIONS] = {0,0,0,0,0,0,1,0};
+ static char keys[NUMKEYS] =
+ {
+ 0xc8,0xd0,0xcb,0xcd,0x2a,0x9d,0x1d,0x39,
+ 0x1e,0x2c,0xd1,0xc9,0x47,0x49,
+ 0x9c,0x1c,0xd,0xc,0xf,
+ };
+
+ ----- Put this where you call initengine -----
+
+ long fil;
+
+ if ((fil = open("setup.dat",O_BINARY|O_RDWR,S_IREAD)) != -1)
+ {
+ read(fil,&option[0],NUMOPTIONS);
+ read(fil,&keys[0],NUMKEYS);
+ close(fil);
+ }
+ if (option[3] != 0) moustat = initmouse();
+
+ switch(option[0])
+ {
+ case 0: initengine(0,chainxres[option[6]&15],chainyres[option[6]>>4]); break;
+ case 1: initengine(1,vesares[option[6]&15][0],vesares[option[6]&15][1]); break;
+ case 2: initengine(2,320L,200L); break;
+ case 3: initengine(3,320L,200L); break;
+ case 4: initengine(4,320L,200L); break;
+ case 5: initengine(5,320L,200L); break;
+ case 6: initengine(6,320L,200L); break;
+ }
+
+ ----- That's it! -----
+
+ Initengine now has 3 parameters:
+ initengine(char davidoption, long daxdim, long daydim)
+ See revised initengine description at the top of this file.
+
+ Now that engine.c doesn't use setup.dat, you can use your
+ own setup program.
+
+ Don't forget to update BSTUB!
+
+ NOTE!!! While MY setup program allows you select many different
+ video modes, no new modes are supported yet in BUILD!
+ (It's on my list.)
+
+
+ - Fixed keyboard repeating.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+4/26/95 - Hi-res now works in all modes! The code I gave in the 4/22/95
+ description is still perfectly valid, so please copy it if
+ you haven't already looked at it. Here are some important
+ new variables I put in BUILD.H:
+
+ EXTERN char vidoption;
+ EXTERN long xdim, ydim, ylookup[MAXYDIM+1];
+
+ Vidoption is simply the first parameter you pass to
+ initengine. Xdim and Ydim are the screen sizes you pass to
+ initengine, such as 320*200 or 640*480.
+ Ylookup is a lookup table that works like this:
+ If (vidoption == 0) ylookup[i] = ((i*xdim)>>2);
+ if (vidoption != 0) ylookup[i] = i*xdim;
+ There is 1 exception: If you are using a chained mode which
+ can only fit only 1 viewing page, then the engine actually
+ does a screen-buffer mode and blits to the chained screen
+ so for this case, ylookup[i] = i*xdim.
+
+ - Added bit to the dastat parameter of rotatesprite.
+ if ((dastat&2) != 0) - align to screen size so the gun or
+ whatever is always over the same relative spot of the screen.
+ Works like bit 2 of the flags parameter in overwritesprite.
+
+ - Added pixel writing and reading that will work in all BUILD
+ graphics modes. They work just like you think they should.
+
+ plotpixel(long x, long y, char col);
+ char getpixel(long x, long y);
+
+ Please do not overuse these functions! They are NOT intended
+ for fast drawing!
+
+ - Changed tables.dat so parallaxing skies at high resolutions
+ work accurately.
+
+ - I made bit 15 of sprite[].cstat the invisible bit. If it is
+ set, then the sprite won't even be considered for sorting and
+ there is absolutely no speed loss due to its existence. It is
+ faster to use this bit then manually set thesprite[] to -1.
+
+ Since drawrooms collects the list of sprites drawmasks is about
+ to sort, make sure the bit is set before drawrooms. If you use
+ frame interpolation, you usually want to tell drawmasks somehow
+ to not draw yourself. Before you used to use the
+ thesprite[] = -1 trick. Now you do it like this:
+
+ sprite[i].cstat |= 0x8000; //Set invisible bit
+ drawrooms(posx,posy,etc.);
+ sprite[i].cstat &= ~0x8000; //Restore invisible bit
+
+ - Fixed distance overflow bug (the one that showed garbage
+ textures if a wall was really far away).
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+4/27/95 - Made an example board, MONWALK.MAP, where monsters walk along
+ a bridge with no railing, onto a sector, and even up and down
+ a stairway without falling off it. If you shoot a brown so
+ it's almost dead, it will turn transluscent. If it's
+ transluscent, it won't shoot bullets. It is much easier to
+ test the monsters' walking when they don't shoot!
+
+ - Try my new and improved fake network player mode! Each fake
+ network player now gets their own window. Use insert and
+ delete to add or remove players. Use Scroll lock to switch
+ which window you control. If you have a Pentium, I would
+ recommend trying this out in 640*480 mode.
+
+ - Noticed a bug with my movesprite code:
+ For clipmove, I was getting the z-coordinate right, but for
+ getzrange I forgot to subtract half the sprite's height if
+ the sprite was using the real centered centering mode.
+
+ These lines set daz to the actual center of sprite i no matter
+ what centering mode is used:
+
+ daz = sprite[i].z;
+ if ((sprite[i].cstat&128) == 0)
+ daz -= ((tilesizy[sprite[i].picnum]*sprite[i].yrepeat)<<1);
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+4/28/95 - ATTENTION PROGRAMMERS! When a tile is not in the cache:
+ Before it used to be this:
+
+ if (waloff[tilenum] == -1) loadtile(tilenum);
+ or
+ if (waloff[tilenum] < 0) loadtile(tilenum);
+
+ Now it's this:
+
+ if (waloff[tilenum] == 0) loadtile(tilenum);
+
+ PLEASE MODIFY YOUR CODE IF YOU USE WALOFF!
+
+ Windows can allocate memory with addresses so high, they
+ are negative. That makes the (waloff[tilenum] < 0)
+ method totally stupid and attempt to reload from disk
+ the tile constantly! I can think of 3 reasons why I
+ originally designed my system in this fashion:
+ mestupid, mestinx, and merottts.
+
+ - Fixed visibility for different screen sizes.
+
+ - ATTENTION PROGRAMMERS! Now multiply by visibility rather than
+ shift right by visiblity so you get a broader range of
+ visibility. If you want the visiblity to work like before,
+ use this conversion table:
+
+ Old visibility New visibility
+ 8 -> 16384
+ 9 -> 8192
+ 10 -> 4096
+ 11 -> 2048
+ 12 -> 1024
+ 13 -> 512
+ 14 -> 256
+ 15 -> 128
+
+ - Made Alt-F make the selected wall the first wall of a sector.
+ This is useful for quick relative alignment adjustments.
+ Alt-F for 2D and 3D modes may not work for sectors with loops
+ inside of them.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/1/95 - Optimized horizontal line setup code from 9 multiplies to
+ 7 multiplies.
+
+ - Fixed dark vertical lines in parallaxing skies bug I recently
+ introduced.
+
+ - Optimized horizontal line assembly code so it doesn't use the
+ awful SHLD instruction any more. This is a good speed
+ improvement for Pentiums only.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/2/95 - Added some code to my GAME.C which detects when a computer gets
+ out of sync in a multiplayer game. It's not as easy as you
+ may think with all the faketimerhandler and fifo crap. If
+ you want to put this code in your game, search all areas in
+ my code with the keyword "syncval".
+
+ - Fixed palookup crashing bug.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/6/95 - Moved windowx1, windowy1, windowx2, windowy2 variables into
+ BUILD.H. They are the exact parameters you passed to the
+ last setview call. Please DO NOT modify them directly.
+ Use setview to modify them.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/10/95 - Fixed makepalookup bug when shading to non 0.
+
+ - Fixed palookup pointer setting bug.
+
+ - ATTENTION PROGRAMMERS! I made a new cacheing system which allows
+ any type of object to be allocated in my cache, such as
+ artwork tiles and sounds or whatever else you may want to
+ put on the cache. This may or may not affect you. If you
+ haven't been hacking into my code, then you shouldn't have to
+ change your code. The cacheing routines have been moved into
+ a separate module, cache1d.obj. If you link engine.obj, then
+ you must also link cache1d.obj. Please update your makefiles.
+
+ For anybody who may want to re-write my cacheing system, here's
+ how it now works: (I have only 3 functions in cache1d.obj
+ right now, initcache, uninitcache, and allocache)
+
+ Allocate a nice BIG buffer, like from 1MB-4MB and
+ call initcache(long cachestart, long cachesize) where
+
+ cachestart = (long)(pointer to start of BIG buffer)
+ cachesize = length of BIG buffer
+
+ Ex: initcache(FP_OFF(pic),cachesize);
+
+ Loadpics calls this function for you so you don't normally
+ need to call it.
+
+ call allocache(long ptr, long siz) whenever you need to
+ allocate a temporary buffer, where
+
+ ptr = (long)(pointer to (4-byte pointer to thing))\
+ siz = number of bytes
+
+ Ex: if (waloff[tilenume] == 0)
+ allocache((long)&waloff[tilenume],walsiz[tilenume]);
+
+ Allocache is totally tile independent. To allocate a sound
+ on the cache, you can call allocache.
+
+ There are 3 functions in the engine which help manage the
+ cache for you: loadpics - calls initcache
+ loadtile - calls allocache
+ allocatepermanenttile - special function
+ that allocates permanent memory
+ from the cache.
+
+ - Fixed clipmove crashing bug when passing a sectnum < 0. Whenever
+ you moved in BUILD and you weren't in a valid sector, memory
+ was getting trashed.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/12/95 - Added ExtPreCheckKeys(void) to BSTUB.C. It is called before
+ drawrooms / drawmasks in 3D mode, whereas ExtCheckKeys(void)
+ is called after drawrooms / drawmasks (and before nextpage).
+
+ - Added bit to flags of rotatesprite to allow x-flipping. See
+ updated documentation.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/17/95 - Added aspect ratio for those weird modes like 320*400, etc.
+ You could call setaspect to properly adjust a mode that is
+ not exactly correct, or for special effect that stretch
+ the screen.
+
+ In ENGINE.OBJ, I added a function, setaspect(long daaspect),
+ where you pass the Y/X aspect ratio scaled up 16 bits, so
+ 65536 would be normal. You don't need to call this if you
+ don't want to. By default, in setview, I call setaspect
+ with these parameters:
+
+ setaspect(divscale16(ydim*320,xdim*200));
+ (also written as:)
+ setaspect(((ydim*320)<<16)/(xdim*200));
+
+ Note that in 320*200 mode the value passed would be 65536
+ which is a 1:1 aspect ratio.
+
+ In BUILD.H, I added yxaspect and xyaspect.
+
+ When you call setaspect(daaspect),
+
+ yxaspect = daaspect;
+ xyaspect = (1<<32) / yxaspect; //reciprocal
+ and other internal variables, so DON'T MODIFY YXASPECT
+ AND XYASPECT DIRECTLY!
+
+ Since drawmapview is also affect by the aspect ratio, you
+ will need to make sure drawoverheadmap is affected so
+ the map modes match up. Please look at and copy my updated
+ drawoverheadmap function into your GAME.C if you use it.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/18/95 - Revised caching system so it supports locking.
+ Here are the new parameters to allocache:
+
+ allocache(long *bufptr, long bufsiz, char *lockptr)
+ *bufptr = pointer to 4-byte pointer to buffer
+ bufsiz = number of bytes to allocate
+ *lockptr = pointer to 1-byte locking char. 1=locked, 0=not
+
+ And uninitcache works a little differently too:
+ Call uninitcache(0) to remove all UNLOCKED items or
+ Call uninitcache(1) to remove ALL items.
+ After calling uninitcache, you do not need to call
+ initcache to use the cache again.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/21/95 - Made changespritesect and changespritestat return 0 instead of -1
+ when changing to same value.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/25/95 - Added relative visibility for sectors. In 3D EDIT MODE, use
+ ALT+(keyp.)+/- to change an individual sector's visibility.
+ Press Shift in addition for fine visibility changine. By
+ default you change it by 16. Press CTRL+ALT+(keyp.)+/- to
+ change the global visibility. The global visibility is not
+ saved in the map.
+
+ - Can now delete many sectors at a time. Select sectors with the
+ rt. Alt. Then press Ctrl-delete on any highlighted sector to
+ delete all the highlighted sectors.
+
+ - Fixed build sometimes not saving when quitting from 2D mode bug.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/27/95 - Fixed bugs in network work that should make it miss packets
+ much less often than before.
+
+ - Fixed bug in ncopy so it shouldn't halt or crash anymore.
+
+ - Added spritecstat[] the thesprite arrays. Please use my
+ thesprite arrays rather than modifying the sprite directly
+ since hitscan and clipmove use bits 4 and 8 of sprite[].cstat.
+
+ - ATTENTION PROGRAMMERS: Added 1 parameter to neartag that will
+ allow you to search only lotags or only hitags. See updated
+ documentation above.
+
+ neartag (long xs, long ys, long zs, short sectnum, short ange,
+ short *neartagsector, short *neartagwall, short *neartagsprite,
+ long *neartaghitdist, long neartagrange, char tagsearch)
+
+ If tagsearch = 1, neartag searches lotag only
+ If tagsearch = 2, neartag searches hitag only
+ If tagsearch = 3, neartag searches lotag&hitag
+
+ Neartag used to always search both lotag&hitag.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+5/30/95 - Added ExtAnalyzeSprites(void) to BSTUB and a spriteshade array
+ to BUILD.H.
+
+ - Made circle drawing in 2D EDIT MODE work better at large sizes.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+6/5/95 - Added shareware / registered artwork version control to EDITART.
+ In 'V' mode, when you press ALT-R to get a report of tile
+ frequencies of tiles on all the maps in the current directory,
+ you can toggle the shareware/registered bit with the space bar.
+ This bit is saved in the top bit of the picanm bits so it is
+ stored permanently in the art file. Press ALT-D in this mode
+ to automatically delete all registered tiles. Please before
+ you do the deleting phase, copy all artwork to a temporary
+ directory!!! It is safe, however, the toggle the new bit in
+ the full version.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+6/7/95 - Made 3 main structures defined with typedef so struct prefix
+ is no longer needed with sectortype, walltype, and spritetype.
+
+ - Added new function to engine:
+
+ short sectorofwall(short dawall);
+
+ It returns the sector of a given wall. It is well optimized
+ including sector[sector[].nextwall].nextsector if a red wall
+ and a binary search on the sector[].wallptr's if it is a
+ white wall. On average, sectorofwall should have to scan
+ through only 10 different sector indeces to find the right
+ sector (not 1024!).
+
+ - ATTENTION PROGRAMMERS! Made all the separate thesprite arrays
+ into a single array of sprite structures call tsprite. See
+ BUILD.H!!! This means:
+
+ spritepicnum[i] is now tsprite[i].picnum
+ spritex[i] is now tsprite[i].x
+ spritey[i] is now tsprite[i].y
+ spritez[i] is now tsprite[i].z
+ spriteshade[i] is now tsprite[i].shade
+ spritecstat[i] is now tsprite[i].cstat
+ spritepal[i] is now tsprite[i].pal
+ thesprite[i] is now tsprite[i].owner <<<============
+
+ Everything above is straight forward, except for thesprite,
+ which has been renamed to owner.
+
+ All other tsprite parameters, such as .xrepeat, .yoffset,
+ etc. can also be modified without changing the real
+ sprite structure so the game won't out of sync.
+
+ - Made tsprite[].statnum be a priority variable for sorting sprites
+ that are the exact same distance from you. I think higher
+ means more in front.
+
+ - Made clipmove allow you to cross any red sector line when the z's
+ of the next sector are farther apart. This may solve clipping
+ bugs such as when you're in water. You may be able to remove
+ some work-arounds you may have programmed previously.
+
+ - NEW FILE GROUPING SYSTEM!!!
+ My system will first search for the stand-alone file in the
+ directory. If it doesn't find it, then it will search for it
+ in the group file. If it still doesn't find it then -1 city.
+ Use KGROUP.EXE to create a grouped file from a lot of other
+ files. Type KGROUP [grouped filename][filespec][filespec][...]
+ For example this line will create the new grouped file,
+ stuff.dat, including all the following files specified:
+ kgroup stuff.dat *.art *.map tables.dat palette.dat
+ Feel free to make your own batch files. If there is demand,
+ I can make kgroup support appending, replacing, and extraction.
+
+ Here is the file format of a grouped file:
+ 旼컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+ 12 bytes - File grouping ID
+ 4 bytes - Number of files
+ 쳐컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+ 쿑or each file: (16 bytes per file)
+ 12 bytes - Filename with extension (13th byte would be a 0)
+ 4 bytes - Length of file
+ 쳐컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+ Pure, raw file data, ordered just like you think it would be
+ 읕컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+ There just couldn't be a simpler format. This format is so
+ hacker happy that when you view it in a hex editor, all the
+ filenames line up perfectly since they're multiples of 16.
+ Anybody who can't figure this out, of course, not only rots,
+ but is probably one of those really stupid people who would
+ actually "pay" to get the full version of a game.
+
+ The engine currently supports grouping for:
+ *.ART, *.MAP, TABLES.DAT and PALETTE.DAT. If you want
+ to group your own files, you will have to use my loading
+ routines rather than the standard ones for those files. My
+ file routines are basically an extra layer around the standard
+ lo-level functions. Look at these 5 routines I currently
+ support:
+
+ Welcome to the K-routines!
+ open -> kopen4load(char *filename)
+ read -> kread(long handle, void *buffer, long leng)
+ lseek -> klseek(long handle, long offset, long whence)
+ filelength -> kfilelength(long handle)
+ close -> kclose(long handle)
+
+ Note that you only pass the filename to my kopen4load function.
+
+ Here are 2 other routines that you MUST use, whether you like
+ my file grouping system or not:
+
+ initgroupfile(char *groupfilename)
+ Call this with the name of your grouped file before
+ any possible file loading will the k-routines. Note that
+ tables.dat uses the k-routines and it is in initengine().
+ Please don't give your grouped filename an extension that
+ starts with W, ends with D, and has a vowel in between.
+ And don't even bother to write your own file grouping
+ system because even if you do, people still have to write
+ their own new utilities to read the ART and MAP files.
+
+ uninitgroupfile()
+ Call before quitting to DOS.
+ ------------------------------------------------------
+ - ATTENTION PROGRAMMERS! Changed kopen4load from:
+
+ kopen4load(char *filename)
+ to:
+ kopen4load(char *filename, char searchfirst)
+
+ where:
+ if searchfirst = 0 then search stand alone first then group file
+ if searchfirst = 1 then search group file only
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+6/12/95 - Tracked down an OUT OF SYNC bug with my multiplayer code!
+ In my GAME.C, the way I had my sync arrays organized were
+ wrong. The problem was that if faketimerhandler was
+ called during domovethings, the sync arrays may have been
+ changed, getting the game out of sync. The solution is
+ to keep the sync arrays in domovethings totally separate
+ from the sync arrays in faketimerhandler. I split my sync
+ arrays into 2 separate arrays, sync and fsync, where fsync
+ and osync are for use BEFORE the FIFO only (such as
+ faketimerhandler and getpackets), and sync is used AFTER
+ the FIFO only (such as domovethings). PLEASE SPLIT YOUR
+ SYNC ARRAYS AS I DESCRIBED!
+
+ - The OUT OF SYNC message doesn't flicker any more. See the
+ section of code in GAME.C where I set syncstat.
+
+ - Fixed up a waitforeverybody function for network games which
+ waits for everybody to be at a certain part of the game.
+ Waitforeverybody also uses getpackets message number 5.
+
+ - Added new clipping function that will push players away from
+ walls that are too close. It solves A LOT of movement
+ clipping problems. It can be pretty darn slow if it detects
+ that you're too close to a wall, so I'd recommend using it
+ only for players.
+
+ pushmove (long *x, long *y, long *z, short *sectnum,
+ long walldist, long ceildist, long flordist, char cliptype)
+
+ The parameters are exactly the same as clipmove but with no
+ xvect or yvect. Pushmove returns either a 0 or -1. If
+ it returns a -1, then that means that it could not push
+ the player away from the offending wall after 256 tries.
+ When this happens, then you should kill the player
+ instantly, because this only happens when the player is
+ getting smooshed.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+6/13/95 - Made clipinsidebox and clipinsideboxline return 0 if line doesn't
+ intersect box, 1 if line intersects box and center of box
+ is in front of line, or 2 if line intersects box and center
+ of box is behind line.
+
+ - Cansee should now work properly with overlapping.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+6/19/95 - ATTENTION! Remove work-arounds!!! Found nasty getzrange bug.
+ Getzrange used to let you fall through red sector line cracks
+ when you were near more multiple red sector line sharing the
+ same 2 sectors. Sound familiar anybody?
+
+ - Made pushmove return the sector of whatever x and y end up in.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+6/22/95 - I included cache1d.c renamed to cache1d.txt in this upload.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+6/26/95 - Made face and wall sprites of clipmove, getzrange, hitscan, and
+ neartag sensitive to the y-offset that you set in Editart.
+
+ - Made one sprite sorting case work perfectly: where multiple
+ sprites have the same x and y location (and priority). The
+ sorting still doesn't work perfectly, but this one case can
+ solve many of the current sprite sorting bugs, such as
+ inserting a floor sprite of blood below a dead body.
+
+ - Fixed some sprite drawing clipping bugs for wall and floor
+ sprites. Now, wall sprites and floor sprites should not
+ show through walls, ceilings, or floors when they're not
+ supposed to. Also, I fixed a case where wall sprites
+ disappeared when they happened to be between 2 white walls
+ that clipped it.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+6/27/95 - Fixed even more sprite drawing clipping bugs for wall sprites.
+
+ - BONUS!!! Wall sprites now clip to white walls! (not red walls)
+ If you ornament a wall, make sure that neither endpoint of the
+ wall sprite is behind the wall or else it will get clipped.
+ Please run lookatme.map from my game.exe which demonstrates
+ some of the things you can do in build now without bugs.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+6/30/95 - Made drawline256 clip with startumost/startdmost.
+
+ - Moved keyboard handler into GAME.C. Here's what you need to do
+ to use my keyboard handler (see my GAME.C):
+
+ 1. Some global variables:
+
+ #define KEYFIFOSIZ 64
+ void (__interrupt __far *oldkeyhandler)();
+ void __interrupt __far keyhandler(void);
+ volatile char keystatus[256], keyfifo[KEYFIFOSIZ];
+ volatile char keyfifoplc, keyfifoend;
+ volatile char readch, oldreadch, extended, keytemp;
+
+ 2. initkeys()
+
+ 3. uninitkeys()
+
+ 4. keyhandler()
+
+ 5. Make sure to call initkeys and uninitkeys. A good place
+ would be next to where you call inittimer / uninittimer.
+
+ I didn't put my keyboard handler into BSTUB since I am using
+ keystatus throughout build.obj. Besides I didn't want to anybody
+ too bad of a headache for one upload.
+
+ - Did you know that screencapture inverses black and white if you
+ hold either shift key down? This option is useful for
+ printing out board maps. Since I don't own the keyboard
+ any more, I had to make screencapture take inverseit as the
+ second parameter.
+
+ screencapture(char *filename, char inverseit);
+
+ Ex: screencapture("captxxxx.pcx",keystatus[0x2a]|keystatus[0x36]);
+
+ If (inverseit == 0) then nuttin' special
+ If (inverseit == 1) then super-reverso blacko-whiteo mode!
+
+ I also had to move the stereo adjustment keys into game.c
+ Just search for the "stereo" keyword in GAME.C. It'll take
+ through all the necessary places.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+7/5/95 - Moved my keytimerstuff from my timerhandler into getinput.
+ (which is where it should be)
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+7/10/95 - Added a loadtilelockmode variable to BUILD.H. It's a global
+ variable that makes future loadtile calls allocate their
+ buffers on the cache as unlocked (0-default) or locked (1).
+ I decided to make this a global variable rather than a
+ parameter to save some people from rewriting code.
+
+ EXTERN char loadtilelockmode;
+
+ - Made my 2D EDIT MODE space bar code clear out new sectors and
+ wall structures to 0. (except for the extras which are -1)
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+7/20/95 - I forgot to documenent rotatesprite bit 3, which controls
+ whether or not the sprite will be clipped to the startumost
+ /startdmost arrays. If the bit is a 1, then the sprite will
+ not be clipped. This mode is useful for doing status bars
+ at variable resolutions. What you do is instead of calling
+ permanentwritesprite, you call rotatesprite with the scaling
+ bit and startumost/startdmost clipping bit off. For non
+ screen-buffer modes, be sure to call rotatesprite for each
+ page of the mode. Use the numpages variable in BUILD.H to
+ get the number of video pages used.
+
+ - Added clipping box parameters to rotatesprite: Here is the
+ prototype now:
+
+ rotatesprite (long sx, long sy, long z, short a, short picnum,
+ signed char dashade, char dapalnum, char dastat,
+ long cx1, long cy1, long cx2, long cy2)
+
+ For your information, rotatesprite used to choose default
+ clipping box sizes using this code:
+
+ if ((dastat&8) == 0)
+ { //0,0,xdim-1,ydim-1
+ cx1 = windowx1; cy1 = windowy1;
+ cx2 = windowx2; cy2 = windowy2;
+ }
+ else
+ {
+ cx1 = 0; cy1 = 0;
+ cx2 = xdim-1; cy2 = ydim-1;
+ }
+
+ Now both permanentwritesprite and overwrite can both be
+ replaced with rotatesprite which now does everything.
+ To replace permanentwritesprite, you must make sure to
+ draw to all the pages in numpages.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+7/27/95 - Fixed recently introduced build 3D mode bug when you press the
+ L.ENTER key on a blank map. Also made sectorofwall return -1
+ if an invalid wall is passed to it.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+7/28/95 - Added a function to my game that shows only the local area of
+ the map by scanning through the nextsectors of walls and
+ setting the show2dsector, show2dwall, and show2dsprite
+ arrays properly. You should call this function any time
+ (show2dsector[cursectnum>>3] & (1<<(cursectnum&7))) == 0)
+ That means it's not showing the sector you're currently
+ in. You should also manipulate show2dsprite any time you
+ insert or warp a sprite.
+
+ - You know the one thing in my engine that doesn't work in chained
+ mode? Well I fixed it!
+
+ - Fixed a bug which made it print out of sync when it really
+ wasn't (This bug probably only affecting my game.) In
+ getsyncstat, I was calling updatecrc16() with things other
+ than chars, making it index invalid parts of the crctable
+ array.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+7/30/95 - Reduced some overhead memory:
+ * Removed walsiz[] array. (16K saved). If you ACTUALLY used
+ this array, you can multiply tilesizx[]*tilesizy[] instead.
+ * Made sqr table from longs to shorts with same precision.
+ * Removed tantable. (4K saved)
+ * Reduced internal constant, MAXWALLSB, from 4096 to 2048
+ (96K saved).
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+8/1/95 - Added another bit to rotatesprite for top-left corner mode and
+ made documentation of the stat bits more clear.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+8/3/95 - Fixed a bug with rotatesprite so it now scales perfectly to the
+ full screen view when enabling bits 2 and 8 of the stat field.
+ This means that with rotatesprite, you can easily get your
+ status bars, etc., to work at any resolution.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+8/4/95 - New Doom->Build update! You can now convert doors and lots of
+ other weird things. Fixed more conversion bugs. Sprites now
+ convert properly in doom-artwork mode. You can now convert
+ PWADS.
+
+ - Added some wacky aspect ratio keys to 3D EDIT MODE of BUILD.
+ Use Rt.Ctrl Rt.Alt Lt.- or Rt.Ctrl Rt.Alt Lt.= to select.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+8/12/95 - Added parameter to initmultiplayers to allow who becomes
+ master at the start of a multiplayer game.
+
+ - Added parallaxyscale variable to BUILD.H which control the ratio
+ at which the parallaxing skies scroll in relation to the
+ horizon. Default is 65536. With lower values, you don't
+ need as much artwork and can look higher, but I like 65536
+ because it is the correct projection.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+8/13/95 - Had MAJOR bug with my searchmap function. If you use it, please
+ re-copy from my game.c
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+8/14/95 - Fixed some EVIL bugs with Rt.ALT sector copying. It shouldn't
+ screw up your maps anymore! And if you have maps that were
+ screwed up with it, you can try my new map correcting key,
+ L.Ctrl+L.Shift+L.Enter. This key will not affect an already
+ perfect map. However it can SOMETIMES clean up a map that
+ was screwed up. I take no responsibility if it screws up
+ your map even more, so please check them before saving!
diff --git a/SRC/BUILD2.TXT b/SRC/BUILD2.TXT
new file mode 100644
index 0000000..c715797
--- /dev/null
+++ b/SRC/BUILD2.TXT
@@ -0,0 +1,1655 @@
+// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
+// Ken Silverman's official web site: "http://www.advsys.net/ken"
+// See the included license file "BUILDLIC.TXT" for license info.
+
+BUILD engine Notes (7/24/96):
+
+BUILD programmed by Ken Silverman
+
+BUILD.TXT CONTINUED... (BUILD.TXT WAS GETTING TOO BIG!!!)
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+8/12/95 - Added parameter to initmultiplayers to allow who becomes
+ master at the start of a multiplayer game.
+
+ - Added parallaxyscale variable to BUILD.H which control the ratio
+ at which the parallaxing skies scroll in relation to the
+ horizon. Default is 65536. With lower values, you don't
+ need as much artwork and can look higher, but I like 65536
+ because it is the correct projection.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+8/13/95 - Had MAJOR bug with my searchmap function. If you use it, please
+ re-copy from my game.c
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+8/14/95 - Fixed some EVIL bugs with Rt.ALT sector copying. It shouldn't
+ screw up your maps anymore! And if you have maps that were
+ screwed up with it, you can try my new map correcting key,
+ L.Ctrl+L.Shift+L.Enter. This key will not affect an already
+ perfect map. However it can SOMETIMES clean up a map that
+ was screwed up. I take no responsibility if it screws up
+ your map even more, so please check them before saving!
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+8/16/95 - Added error correction to mmulti.obj. Mmulti.obj is like
+ multi.obj but it is made to work with Mark's real mode
+ multiplayer driver that he calls COMMIT.
+
+
+ MMULTI.OBJ vs. MULTI.OBJ:
+ * initmultiplayers is the same, but the parameters are ignored
+ * uninitmultiplayers can be called but does nothing.
+ * sendlogon can be called but does nothing.
+ * sendlogoff sends packet 255 to everybody else. It does not
+ need to be called any more.
+ * sendpacket and getpacket are the same.
+ * connecthead, connectpoint2[], numplayers, myconnectindex
+ are the same. They can be externed just like before.
+ * getoutputcirclesize always returns 0. It is not needed.
+ * setsocket does nothing. The socket is now in commit.dat.
+ * crctable can still be externed.
+ * syncstate can still be externed but is not used.
+ * Do not use the option[4] variable. Initmultiplayers will
+ always return a valid number in numplayers from 1-16.
+
+
+ You can link mmulti.obj in place of multi.obj and use
+ commit.dat as the setup file for multiplayer options.
+
+ There are 2 ways you can run your game through commit:
+ 1. Set the launch name (usually game.exe) in commit.dat
+ and type something like "commit map01 /asdf"
+ 2. Type "commit launch game map01 /asdf". This method
+ is easier if you want to use the debugger with commit
+ since you won't have to change commit.dat constantly.
+ Ex: "commit launch wd /tr=rsi game map01 /asdf"
+
+ I have not tested mmulti.obj with my BUILD game yet because
+ I have been using 2DRAW as my test program. I may put up a
+ new version of mmulti.obj with better error correction for
+ extremely error-prone lines soon.
+
+ - Kgroup can now accept a parameter as a filename with a list of
+ files to be put into the group file.
+ Ex: "kgroup @filelist.txt"
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+8/18/95 - Found a way to greatly reduce slave "hitching" on multiplayer
+ games for faketimerhandler style communications. It's pretty
+ simple.
+
+ Step 1: In the beginning of faketimerhandler, change
+
+ ototalclock = totalclock;
+ TO:
+ ototalclock += TICSPERFRAME;
+
+ This makes the timing of the game more constant and to
+ never miss ticks. I should have done this in the first
+ place all along.
+
+ Step 2: In getpackets, (for slaves only) count the number of
+ times movethings is called. Normally, movethings should
+ be called exactly once for every time getpackets is called
+ inside faketimerhandler. The hitching is because
+ movethings is called in a 0-2-0-2-0-2 cycle instead of the
+ standard 1-1-1-1-1-1 cycle. This happens because the
+ timers of the 2 computers are aligning in such a way that
+ the slave is receiving the master's packets at nearly the
+ same time as it calls getpackets. To correct the problem,
+ if movethings is called an even number of times, I randomly
+ add or subtract (TICSPERFRAME>>1) to ototalclock. Throw
+ this code at the end of getpackets:
+
+ Beginning of getpackets:
+ movecnt = 0;
+
+ Where slave receives buffer in getpackets, next to movethings:
+ movecnt++;
+
+ End of getpackets:
+ if ((myconnectindex != connecthead) && ((movecnt&1) == 0))
+ {
+ if (rand()&1) ototalclock += (TICSPERFRAME>>1);
+ else ototalclock -= (TICSPERFRAME>>1);
+ }
+
+ - Found a way to interpolate anything using the doanimations
+ code for faketimerhandler style multiplayer games. It's not
+ as hard as I thought it would be (and it doesn't waste too
+ much memory!) To smooth out doanimations, since there's no
+ temporary variables that can be thrown away like with tsprite,
+ the current doanimations positions must be backed up at the
+ beginning of drawscreen and restored at the end of drawscreen.
+ If you want smooth up&down doors, do this:
+
+ Global declaration:
+ static long oanimateval[MAXANIMATES];
+
+ Beginning of drawscreen:
+ for(i=animatecnt-1;i>=0;i--)
+ {
+ oanimateval[i] = *animateptr[i]; //Backup doanimations interpolation
+
+ j = *animateptr[i];
+ if (j < animategoal[i])
+ j = min(j+animatevel[i]*(totalclock-gotlastpacketclock),animategoal[i]);
+ else
+ j = max(j-animatevel[i]*(totalclock-gotlastpacketclock),animategoal[i]);
+
+ *animateptr[i] = j;
+ }
+
+ End of drawscreen:
+ //Restore doanimations interpolation
+ for(i=animatecnt-1;i>=0;i--) *animateptr[i] = oanimateval[i];
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+8/19/95 - Added global invisibility variable. Initengine sets it to 0
+ by default. If you set global invisibility to 1, then
+ all sprites with the invisible bit set (sprite[].cstat&0x8000)
+ will be shown. This is useful for editing invisiblie sprites.
+
+ - Made the hitscan blocking bit for sprites be the bit checked
+ when using cliptype 1 instead of the blocking bit. Before
+ I was accidently using the clipmove blocking bit on sprites
+ with cliptype 1. I should have done it this way in the first
+ place. I hope you haven't "built" around this bug too much!
+ Here's how everything works now:
+
+ Clipmove blocking bits:
+ Which bits:
+ wall[].cstat & 1
+ sprite[].cstat & 1
+ Used in these cases:
+ clipmove when cliptype = 0
+ getzrange when cliptype = 0
+
+ Hitscan blocking bits:
+ Which bits:
+ wall[].cstat & 64
+ sprite[].cstat & 256
+ Used in these cases:
+ clipmove when cliptype = 1
+ getzrange when cliptype = 1
+ hitscan always
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+8/20/95 - Reduced some overhead memory by combining 2 large internal
+ arrays which were used in different parts of the engine.
+ This is a total savings of about 90K.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+8/24/95 - Changed the way 'E' mode works on ceiling and floor textures.
+ 64*64 and 128*128 textures are the same as before so I think
+ this won't screw up your existing maps. (But I can never be
+ sure) Now, 'E' mode always smooshes the texture size by 2 for
+ any size texture.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+8/29/95 - 蔔栢栢白 栢 蔔栢栢白 蔔栢栢白 蔔栢栢白 蔔栢栢白 栢 栢 栢
+ 栢 栢 栢 賞 栢 栢 栢 栢 栢 栢 栢
+ 賞栢栢白 栢 栢 栢 栢栢栢幡 栢栢栢 賞栢栢白 栢 栢 栢
+ 栢 栢 栢 蔔 栢 栢 栢 賽 賽 賽
+ 賞栢栢幡 賞栢栢栢 賞栢栢幡 栢 賞栢栢幡 賞栢栢幡 栢 栢 栢
+
+ New 3D EDIT MODE BUILD keys:
+ Press [ or ] on a ceiling or floor to change the slope.
+ Shift + [ or ] on a ceiling or floor to adjust finely.
+ Press / to reset a ceiling or floor to slope 0.
+ Use Alt-F in either 2D or 3D mode to change the slope's hinge.
+
+ Sector fields used for slopes:
+ The useless groudraw fields, ceilingheinum and floorheinum,
+ are now being used as the slope value. They are treated
+ as signed shorts, where 0 is slope 0, of course. To enable
+ slope mode, you must also set bit 1 of the ceilingstat or
+ floorstat bits.
+
+ Known bugs:
+ There are still a few bugs that I haven't gotten around to
+ fixing yet. They're not necessarily hard to fix - it's just
+ that there are a lot of little things that need to be updated
+ (on my part).
+
+ - Hitscan does not hit slopes correctly.
+ - Rare divide overflow bug in my wallmost function only when
+ you're very close to a red sector line of a slope.
+ - Relative alignment for slopes not yet programmed. Relative
+ alignment for slopes will allow square aspect ratio for all
+ slopes of slopes.
+ - ALT-F code with passing loops would be nice.
+ - Visibility not implemented for slopes yet.
+ - Sometimes an annoying tiny wall is drawn at sector lines.
+
+ Don't call me to tell me about these bugs. I know about them.
+ And if I didn't list your favorite bug of the day, it will
+ probably be brought up by the 2 internal teams now working
+ with BUILD.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+9/4/95 - Made ALT-F select any wall of a sector, even crossing loops.
+ In 3D mode, ALT-F now sets the selected wall directly to the
+ first wall.
+
+ - Fixes related to slopes:
+ * Relative alignment now works. Use relative alignment on high
+ slopes if you don't like the way the texture is stretched
+ out.
+ * Flipping now works
+ * Panning now works
+ * Fixed seams for SOME (not all) slope borders
+
+ - My wonderful divide overflow bugs in wallmost aren't quite as
+ rare as they used to be. Wait a minute - I thought I was
+ supposed to document bug fixes here! This is what you get
+ for wanting BUILD tonight. As soon as I fix these darn
+ divide bugs, I'll put up a new version.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+9/5/95 - Fixed all known divide overflow bugs related to wallmost. I
+ haven't gotten a divide overflow yet in the last few hours,
+ but that doesn't guarantee that you'll never get one. Take a
+ look at GROULAND. It has a cool new cylindrical tunnel. On
+ the other side of the level is my house in Rhode Island.
+
+ Known bugs with slopes now:
+ - Hitscan does not hit slopes correctly.
+ - Visibility not implemented for slopes yet.
+ - Clipmove will not allow you to walk off high sloped cliffs.
+
+ - Also, I noticed a rare sprite drawing clipping bug. I
+ don't know if this is new or not.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+9/7/95 - Fixed an exception 0xe bug by using tsprite[MAXSPRITESONSCREEN-2]
+ instead of tsprite[MAXSPRITESONSCREEN-1]. I don't understand
+ why this fixed it so I expect that it will come back to haunt
+ me. Oh happy day. :(
+
+ - I forgot to document 2 new and useful functions in the engine:
+
+ long getceilzofslope(short sectnum, long x, long y); and
+ long getflorzofslope(short sectnum, long x, long y);
+
+ Returns the z coordinate of the ceiling/floor at that x, y
+ location. If the sector doesn't have a ceiling/floor slope
+ then it immediately returns the sector[].floorz or
+ sector[].ceilingz so it's not that slow. You may want to
+ check for slopes yourself ceilingstat&2/floorstat&2 if you
+ think the overhead of calling these functions are too slow.
+
+ - Made clipmove use getceilzofslope and getflorzofslope when
+ checking for overlapping.
+
+ - Cleaned up mirror code for non-chained modes a little bit. The
+ mirrors should no longer have a stay line on the right anymore
+ for these modes.
+
+ - Added Chain-Buffer mode. See my new SETUP.EXE. Chain-Buffer
+ is a combination of the chain and screen buffer modes - a
+ buffered chain mode. This mode is faster than standard chain
+ mode when a lot of screen memory is being read, for example
+ when you use transluscence or mirrors. Also, Chain-Buffer
+ mode is cleaner than screen-buffer mode since you don't see
+ memory being copied to the screen. Unfortunately, in most
+ cases, Chain-Buffer is the slowest of all modes. Actually,
+ Chain-Buffer mode sucks. There is a use for this mode,
+ however! In the future, I may make some kind of chain mode
+ automatically switch into chain-buffer mode for extra speed
+ when there is a large area of transluscence, etc.
+
+ ATTENTION PROGRAMMERS: Here is the new order of modes that
+ initengine accepts:
+
+ 0 = Chain mode
+ 1 = Chain-Buffer mode
+ 2 = Screen-Buffer/VESA mode
+ 3 = TSENG mode
+ 4 = Paradise mode
+ 5 = S3
+ 6 = Crystal Eyes mode
+ 7 = Red-Blue mode
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+9/9/95 - Fixed visibility for face sprites in high resolution modes.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+9/14/95 - Added a new bunch of graphics modes using the new VESA 2.0 linear
+ buffer. (I replaced the useless chain-buffer mode with VESA
+ 2.0 modes) See my new SETUP. Since most cards only support
+ VESA 1.2 right now, you will probably need a VESA 2.0 driver.
+ I have been using the UniVBE(tm) 5.1 from SciTech Software
+ (ftp: ftp.scitechsoft.com, www: http://www.scitechsoft.com)
+ Note that since I inserted the new modes between chained mode
+ and screen buffer mode, you will need to update your setup
+ program and fix your initengine calls.
+
+ - Programmed a LRU/MRU-style cacheing system. It should be fully
+ compatible with the old cache1d except for the locking byte.
+ The locking byte would be better described as a priority byte.
+ Priority byte:
+
+ 0 - non-cached memory, you NEVER set the byte to 0!
+ 1-199 - cached unlocked memory
+ 200-255 - cached locked memory
+
+ When the cacheing system needs to remove a memory block, it
+ will try to remove the FEWEST number of SMALLEST blocks with
+ the LOWEST priority.
+
+ Note: Never set the priority byte to a 0! Let the cacheing
+ system do that for you.
+컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴
+9/15/95 - Optimized hitscan a little and made it work with slopes.
+
+ - Made some internal things in the build edit