├── .gitignore ├── DOOMLIC.TXT ├── LICENSE ├── README.md ├── a_al_mid.c ├── a_al_mid.h ├── a_blast.c ├── a_blast.h ├── a_dma.c ├── a_dma.h ├── a_inter.h ├── a_ll_man.c ├── a_ll_man.h ├── a_midi.c ├── a_midi.h ├── a_mpu401.c ├── a_mpu401.h ├── a_multiv.c ├── a_multiv.h ├── a_music.c ├── a_music.h ├── a_musmid.c ├── a_mv_mix.asm ├── a_pcfx.c ├── a_pcfx.h ├── a_taskmn.c ├── a_taskmn.h ├── a_tsmapi.c ├── a_tsmapi.h ├── am_data.h ├── am_map.c ├── am_map.h ├── compdj.bat ├── compdm.bat ├── compiler.h ├── compoc.bat ├── compwc.bat ├── d_chex.h ├── d_french.h ├── d_main.c ├── d_net.c ├── dmx.c ├── dmx.h ├── doomdata.h ├── doomdef.h ├── dstrings.h ├── dutils.c ├── dutils.h ├── f_finale.c ├── g_game.c ├── gamever.h ├── hu_lib.c ├── hu_lib.h ├── hu_stuff.c ├── hu_stuff.h ├── i_ibm.c ├── i_main.c ├── i_sound.c ├── id_heads.h ├── info.c ├── info.h ├── m_menu.c ├── m_misc.c ├── makefile.wc ├── p_ceilng.c ├── p_doors.c ├── p_enemy.c ├── p_floor.c ├── p_inter.c ├── p_lights.c ├── p_local.h ├── p_map.c ├── p_maputl.c ├── p_mobj.c ├── p_plats.c ├── p_pspr.c ├── p_setup.c ├── p_sight.c ├── p_spec.c ├── p_spec.h ├── p_switch.c ├── p_telept.c ├── p_tick.c ├── p_user.c ├── planar.asm ├── r_bsp.c ├── r_data.c ├── r_draw.c ├── r_local.h ├── r_main.c ├── r_plane.c ├── r_segs.c ├── r_things.c ├── s_sound.c ├── setenvdj.bat ├── setenvdm.bat ├── setenvoc.bat ├── setenvwc.bat ├── sounds.c ├── sounds.h ├── soundst.h ├── st_lib.c ├── st_lib.h ├── st_stuff.c ├── st_stuff.h ├── tables.c ├── v_video.c ├── w_wad.c ├── wcdoom.lnk ├── wi_data.h ├── wi_stuff.c ├── wi_stuff.h └── z_zone.c /.gitignore: -------------------------------------------------------------------------------- 1 | /DJDM19 2 | /DMDM19 3 | /OCDM19 4 | /WCDM19 5 | -------------------------------------------------------------------------------- /DOOMLIC.TXT: -------------------------------------------------------------------------------- 1 | 2 | 3 | LIMITED USE SOFTWARE LICENSE AGREEMENT 4 | 5 | This Limited Use Software License Agreement (the "Agreement") 6 | is a legal agreement between you, the end-user, and Id Software, Inc. 7 | ("ID"). By downloading or purchasing the software material, which 8 | includes source code (the "Source Code"), artwork data, music and 9 | software tools (collectively, the "Software"), you are agreeing to 10 | be bound by the terms of this Agreement. If you do not agree to the 11 | terms of this Agreement, promptly destroy the Software you may have 12 | downloaded or copied. 13 | 14 | ID SOFTWARE LICENSE 15 | 16 | 1. Grant of License. ID grants to you the right to use the 17 | Software. You have no ownership or proprietary rights in or to the 18 | Software, or the Trademark. For purposes of this section, "use" means 19 | loading the Software into RAM, as well as installation on a hard disk 20 | or other storage device. The Software, together with any archive copy 21 | thereof, shall be destroyed when no longer used in accordance with 22 | this Agreement, or when the right to use the Software is terminated. 23 | You agree that the Software will not be shipped, transferred or 24 | exported into any country in violation of the U.S. Export 25 | Administration Act (or any other law governing such matters) and that 26 | you will not utilize, in any other manner, the Software in violation 27 | of any applicable law. 28 | 29 | 2. Permitted Uses. For educational purposes only, you, the 30 | end-user, may use portions of the Source Code, such as particular 31 | routines, to develop your own software, but may not duplicate the 32 | Source Code, except as noted in paragraph 4. The limited right 33 | referenced in the preceding sentence is hereinafter referred to as 34 | "Educational Use." By so exercising the Educational Use right you 35 | shall not obtain any ownership, copyright, proprietary or other 36 | interest in or to the Source Code, or any portion of the Source 37 | Code. You may dispose of your own software in your sole discretion. 38 | With the exception of the Educational Use right, you may not 39 | otherwise use the Software, or an portion of the Software, which 40 | includes the Source Code, for commercial gain. 41 | 42 | 3. Prohibited Uses: Under no circumstances shall you, the 43 | end-user, be permitted, allowed or authorized to commercially exploit 44 | the Software. Neither you nor anyone at your direction shall do any 45 | of the following acts with regard to the Software, or any portion 46 | thereof: 47 | 48 | Rent; 49 | 50 | Sell; 51 | 52 | Lease; 53 | 54 | Offer on a pay-per-play basis; 55 | 56 | Distribute for money or any other consideration; or 57 | 58 | In any other manner and through any medium whatsoever 59 | commercially exploit or use for any commercial purpose. 60 | 61 | Notwithstanding the foregoing prohibitions, you may commercially 62 | exploit the software you develop by exercising the Educational Use 63 | right, referenced in paragraph 2. hereinabove. 64 | 65 | 4. Copyright. The Software and all copyrights related thereto 66 | (including all characters and other images generated by the Software 67 | or depicted in the Software) are owned by ID and is protected by 68 | United States copyright laws and international treaty provisions. 69 | Id shall retain exclusive ownership and copyright in and to the 70 | Software and all portions of the Software and you shall have no 71 | ownership or other proprietary interest in such materials. You must 72 | treat the Software like any other copyrighted material. You may not 73 | otherwise reproduce, copy or disclose to others, in whole or in any 74 | part, the Software. You may not copy the written materials 75 | accompanying the Software. You agree to use your best efforts to 76 | see that any user of the Software licensed hereunder complies with 77 | this Agreement. 78 | 79 | 5. NO WARRANTIES. ID DISCLAIMS ALL WARRANTIES, BOTH EXPRESS 80 | IMPLIED, INCLUDING BUT NOT LIMITED TO, IMPLIED WARRANTIES OF 81 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE WITH RESPECT 82 | TO THE SOFTWARE. THIS LIMITED WARRANTY GIVES YOU SPECIFIC LEGAL 83 | RIGHTS. YOU MAY HAVE OTHER RIGHTS WHICH VARY FROM JURISDICTION TO 84 | JURISDICTION. ID DOES NOT WARRANT THAT THE OPERATION OF THE SOFTWARE 85 | WILL BE UNINTERRUPTED, ERROR FREE OR MEET YOUR SPECIFIC REQUIREMENTS. 86 | THE WARRANTY SET FORTH ABOVE IS IN LIEU OF ALL OTHER EXPRESS 87 | WARRANTIES WHETHER ORAL OR WRITTEN. THE AGENTS, EMPLOYEES, 88 | DISTRIBUTORS, AND DEALERS OF ID ARE NOT AUTHORIZED TO MAKE 89 | MODIFICATIONS TO THIS WARRANTY, OR ADDITIONAL WARRANTIES ON BEHALF 90 | OF ID. 91 | 92 | Exclusive Remedies. The Software is being offered to you 93 | free of any charge. You agree that you have no remedy against ID, its 94 | affiliates, contractors, suppliers, and agents for loss or damage 95 | caused by any defect or failure in the Software regardless of the form 96 | of action, whether in contract, tort, includinegligence, strict 97 | liability or otherwise, with regard to the Software. This Agreement 98 | shall be construed in accordance with and governed by the laws of the 99 | State of Texas. Copyright and other proprietary matters will be 100 | governed by United States laws and international treaties. IN ANY 101 | CASE, ID SHALL NOT BE LIABLE FOR LOSS OF DATA, LOSS OF PROFITS, LOST 102 | SAVINGS, SPECIAL, INCIDENTAL, CONSEQUENTIAL, INDIRECT OR OTHER 103 | SIMILAR DAMAGES ARISING FROM BREACH OF WARRANTY, BREACH OF CONTRACT, 104 | NEGLIGENCE, OR OTHER LEGAL THEORY EVEN IF ID OR ITS AGENT HAS BEEN 105 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM BY ANY 106 | OTHER PARTY. Some jurisdictions do not allow the exclusion or 107 | limitation of incidental or consequential damages, so the above 108 | limitation or exclusion may not apply to you. 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DJGPP Doom 2 | Download the executables [here](https://github.com/FrenkelS/djdoom/releases). 3 | 4 | The goal of this project is to: 5 | * Examine which compiler generates the fastest Doom code for DOS: 6 | - [DJGPP](https://github.com/andrewwutw/build-djgpp) 7 | - [Digital Mars](https://digitalmars.com) (with [X32](https://github.com/Olde-Skuul/KitchenSink/tree/master/sdks/dos/x32)) 8 | - [CC386](https://ladsoft.tripod.com/cc386_compiler.html) 9 | - [Watcom](https://github.com/open-watcom/open-watcom-v2) 10 | * Show the modifications required in the code for it to be compilable by the compilers. 11 | 12 | The code is based on [gamesrc-ver-recreation](https://bitbucket.org/gamesrc-ver-recreation/doom) 13 | and it took inspiration from 14 | [Apogee Sound System](https://bitbucket.org/gamesrc-ver-recreation/audiolib), 15 | [Apogee Sound System backed DMX wrapper](https://bitbucket.org/gamesrc-ver-recreation/apodmx), 16 | [doomgeneric](https://github.com/ozkl/doomgeneric), 17 | [Doom Vanille](https://github.com/AXDOOMER/doom-vanille), 18 | [Executor](https://github.com/ctm/executor), 19 | [FastDoom](https://github.com/viti95/FastDoom), 20 | [Quake](https://github.com/id-Software/Quake) and 21 | [Quake 2](https://github.com/id-Software/Quake-2). 22 | 23 | There is some assembly in the code that requires [NASM](https://www.nasm.us). 24 | To build Doom using only C code, look at the macro `C_ONLY`. 25 | To remove the visplanes limit, look at the macro `REMOVE_LIMITS`. 26 | 27 | Sound effects are supported through the PC speaker and Sound Blaster. 28 | And music is supported via Adlib, Sound Blaster, Pro Audio Spectrum, General MIDI, Wave Blaster and Sound Canvas. 29 | 30 | There's no support for joystick and Logitech Cyberman. 31 | 32 | ## How to add other compilers 33 | The differences between compilers specific to the Doom source code are in `a_blast.c`, `a_inter.h`, `a_multiv.c`, `a_taskmn.c`, `compiler.h`, `d_main.c` and `i_ibm.c`. 34 | Search in those files for the pre-defined compiler macros and start hacking. 35 | 36 | |Compiler |Set environment variables|Compile code|Pre-defined compiler macro| 37 | |------------|-------------------------|------------|--------------------------| 38 | |DJGPP |`setenvdj.bat` |`compdj.bat`|`__DJGPP__` | 39 | |Digital Mars|`setenvdm.bat` |`compdm.bat`|`__DMC__` | 40 | |CC386 |`setenvoc.bat` |`compoc.bat`|`__CCDL__` | 41 | |Watcom |`setenvwc.bat` |`compwc.bat`|`__WATCOMC__` | 42 | -------------------------------------------------------------------------------- /a_al_mid.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 1994-1995 Apogee Software, Ltd. 3 | Copyright (C) 2023 Frenkel Smeijers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | 14 | See the GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | 20 | */ 21 | #ifndef __AL_MIDI_H 22 | #define __AL_MIDI_H 23 | 24 | void AL_Shutdown(void); 25 | void AL_Init(void); 26 | void AL_NoteOff(int32_t channel, int32_t key, int32_t velocity); 27 | void AL_NoteOn(int32_t channel, int32_t key, int32_t velocity); 28 | void AL_ControlChange(int32_t channel, int32_t type, int32_t data); 29 | void AL_ProgramChange(int32_t channel, int32_t patch); 30 | void AL_SetPitchBend(int32_t channel, int32_t lsb, int32_t msb); 31 | boolean AL_DetectFM(void); 32 | void AL_RegisterTimbreBank(uint8_t *timbres); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /a_blast.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 1994-1995 Apogee Software, Ltd. 3 | Copyright (C) 2023 Frenkel Smeijers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | 14 | See the GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | 20 | */ 21 | /********************************************************************** 22 | module: BLASTER.H 23 | 24 | author: James R. Dose 25 | date: February 4, 1994 26 | 27 | Public header for BLASTER.C 28 | 29 | (c) Copyright 1994 James R. Dose. All Rights Reserved. 30 | **********************************************************************/ 31 | 32 | #ifndef __BLASTER_H 33 | #define __BLASTER_H 34 | 35 | typedef struct 36 | { 37 | uint32_t Address; 38 | uint32_t Interrupt; 39 | uint32_t Dma8; 40 | uint32_t Dma16; 41 | uint32_t Type; 42 | 43 | uint32_t MinSamplingRate; 44 | uint32_t MaxSamplingRate; 45 | uint32_t MaxMixMode; 46 | } BLASTER_CONFIG; 47 | 48 | enum BLASTER_ERRORS 49 | { 50 | BLASTER_Error = -1, 51 | BLASTER_Ok = 0 52 | }; 53 | 54 | #define STEREO 1 55 | #define SIXTEEN_BIT 2 56 | 57 | #define MONO_8BIT 0 58 | #define STEREO_8BIT ( STEREO ) 59 | #define STEREO_16BIT ( STEREO | SIXTEEN_BIT ) 60 | 61 | uint32_t BLASTER_GetPlaybackRate(void); 62 | int32_t BLASTER_GetDMAChannel(void); 63 | int32_t BLASTER_SetMixMode(int32_t mode); 64 | void BLASTER_StopPlayback(void); 65 | int32_t BLASTER_BeginBufferedPlayback(uint8_t *BufferStart, int32_t BufferSize, int32_t NumDivisions, uint32_t SampleRate, int32_t MixMode, void (*CallBackFunc)(void)); 66 | void BLASTER_GetEnv(int32_t *sbPort, int32_t *sbIrq, int32_t *sbDma8, int32_t *sbDma16); 67 | void BLASTER_SetCardSettings(BLASTER_CONFIG Config); 68 | void BLASTER_SetupWaveBlaster(void); 69 | boolean BLASTER_IsSwapLeftRight(void); 70 | void BLASTER_Init(void); 71 | void BLASTER_Shutdown(void); 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /a_dma.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 1994-1995 Apogee Software, Ltd. 3 | Copyright (C) 2023 Frenkel Smeijers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | 14 | See the GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | 20 | */ 21 | /********************************************************************** 22 | module: DMA.C 23 | 24 | author: James R. Dose 25 | date: February 4, 1994 26 | 27 | Low level routines to for programming the DMA controller for 8 bit 28 | and 16 bit transfers. 29 | 30 | (c) Copyright 1994 James R. Dose. All Rights Reserved. 31 | **********************************************************************/ 32 | 33 | #include 34 | #include 35 | #include "id_heads.h" 36 | #include "a_dma.h" 37 | 38 | #define DMA_MaxChannel 7 39 | 40 | #define VALID ( 1 == 1 ) 41 | #define INVALID ( !VALID ) 42 | 43 | #define BYTE 0 44 | #define WORD 1 45 | 46 | typedef struct 47 | { 48 | int32_t Valid; 49 | int32_t Width; 50 | int32_t Mask; 51 | int32_t Mode; 52 | int32_t Clear; 53 | int32_t Page; 54 | int32_t Address; 55 | int32_t Length; 56 | } DMA_PORT; 57 | 58 | static const DMA_PORT DMA_PortInfo[DMA_MaxChannel + 1] = 59 | { 60 | { VALID, BYTE, 0xA, 0xB, 0xC, 0x87, 0x0, 0x1}, 61 | { VALID, BYTE, 0xA, 0xB, 0xC, 0x83, 0x2, 0x3}, 62 | {INVALID, BYTE, 0xA, 0xB, 0xC, 0x81, 0x4, 0x5}, 63 | { VALID, BYTE, 0xA, 0xB, 0xC, 0x82, 0x6, 0x7}, 64 | {INVALID, WORD, 0xD4, 0xD6, 0xD8, 0x8F, 0xC0, 0xC2}, 65 | { VALID, WORD, 0xD4, 0xD6, 0xD8, 0x8B, 0xC4, 0xC6}, 66 | { VALID, WORD, 0xD4, 0xD6, 0xD8, 0x89, 0xC8, 0xCA}, 67 | { VALID, WORD, 0xD4, 0xD6, 0xD8, 0x8A, 0xCC, 0xCE} 68 | }; 69 | 70 | 71 | /*--------------------------------------------------------------------- 72 | Function: DMA_VerifyChannel 73 | 74 | Verifies whether a DMA channel is available to transfer data. 75 | ---------------------------------------------------------------------*/ 76 | 77 | int32_t DMA_VerifyChannel(int32_t channel) 78 | { 79 | if (!(0 <= channel && channel <= DMA_MaxChannel)) 80 | return DMA_Error; 81 | else if (DMA_PortInfo[channel].Valid == INVALID) 82 | return DMA_Error; 83 | else 84 | return DMA_Ok; 85 | } 86 | 87 | 88 | /*--------------------------------------------------------------------- 89 | Function: DMA_SetupTransfer 90 | 91 | Programs the specified DMA channel to transfer data. 92 | ---------------------------------------------------------------------*/ 93 | 94 | int32_t DMA_SetupTransfer(int32_t channel, uint8_t *address, int32_t length) 95 | { 96 | const DMA_PORT *Port; 97 | 98 | int32_t addr; 99 | int32_t ChannelSelect; 100 | int32_t Page; 101 | int32_t HiByte; 102 | int32_t LoByte; 103 | int32_t TransferLength; 104 | int32_t status; 105 | 106 | status = DMA_VerifyChannel(channel); 107 | 108 | if (status == DMA_Ok) 109 | { 110 | Port = &DMA_PortInfo[channel]; 111 | ChannelSelect = channel & 0x3; 112 | 113 | addr = ((int32_t)address) - __djgpp_conventional_base; 114 | 115 | if (Port->Width == WORD) 116 | { 117 | Page = (addr >> 16) & 255; 118 | HiByte = (addr >> 9) & 255; 119 | LoByte = (addr >> 1) & 255; 120 | 121 | // Convert the length in bytes to the length in words 122 | TransferLength = (length + 1) >> 1; 123 | 124 | // The length is always one less the number of bytes or words 125 | // that we're going to send 126 | TransferLength--; 127 | } else { 128 | Page = (addr >> 16) & 255; 129 | HiByte = (addr >> 8) & 255; 130 | LoByte = addr & 255; 131 | 132 | // The length is always one less the number of bytes or words 133 | // that we're going to send 134 | TransferLength = length - 1; 135 | } 136 | 137 | // Mask off DMA channel 138 | outp(Port->Mask, 4 | ChannelSelect); 139 | 140 | // Clear flip-flop to lower byte with any data 141 | outp(Port->Clear, 0); 142 | 143 | // Set DMA mode to AutoInitRead 144 | outp(Port->Mode, 0x58 | ChannelSelect); 145 | 146 | // Send address 147 | outp(Port->Address, LoByte); 148 | outp(Port->Address, HiByte); 149 | 150 | // Send page 151 | outp(Port->Page, Page); 152 | 153 | // Send length 154 | outp(Port->Length, LOBYTE(TransferLength)); 155 | outp(Port->Length, HIBYTE(TransferLength)); 156 | 157 | // enable DMA channel 158 | outp(Port->Mask, ChannelSelect); 159 | } 160 | 161 | return status; 162 | } 163 | 164 | 165 | /*--------------------------------------------------------------------- 166 | Function: DMA_EndTransfer 167 | 168 | Ends use of the specified DMA channel. 169 | ---------------------------------------------------------------------*/ 170 | 171 | int32_t DMA_EndTransfer(int32_t channel) 172 | { 173 | const DMA_PORT *Port; 174 | 175 | int32_t ChannelSelect; 176 | int32_t status; 177 | 178 | status = DMA_VerifyChannel(channel); 179 | if (status == DMA_Ok) 180 | { 181 | Port = &DMA_PortInfo[channel]; 182 | ChannelSelect = channel & 0x3; 183 | 184 | // Mask off DMA channel 185 | outp(Port->Mask, 4 | ChannelSelect); 186 | 187 | // Clear flip-flop to lower byte with any data 188 | outp(Port->Clear, 0); 189 | } 190 | 191 | return status; 192 | } 193 | 194 | 195 | /*--------------------------------------------------------------------- 196 | Function: DMA_GetCurrentPos 197 | 198 | Returns the position of the specified DMA transfer. 199 | ---------------------------------------------------------------------*/ 200 | 201 | uint8_t *DMA_GetCurrentPos(int32_t channel) 202 | { 203 | const DMA_PORT *Port; 204 | 205 | uint32_t addr = 0; 206 | int32_t status = DMA_VerifyChannel(channel); 207 | 208 | if (status == DMA_Ok) 209 | { 210 | Port = &DMA_PortInfo[channel]; 211 | 212 | if (Port->Width == WORD) 213 | { 214 | // Get address 215 | addr = inp(Port->Address) << 1; 216 | addr |= inp(Port->Address) << 9; 217 | 218 | // Get page 219 | addr |= inp(Port->Page) << 16; 220 | } else { 221 | // Get address 222 | addr = inp(Port->Address); 223 | addr |= inp(Port->Address) << 8; 224 | 225 | // Get page 226 | addr |= inp(Port->Page) << 16; 227 | } 228 | } 229 | 230 | return (uint8_t *)(addr + __djgpp_conventional_base); 231 | } 232 | -------------------------------------------------------------------------------- /a_dma.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 1994-1995 Apogee Software, Ltd. 3 | Copyright (C) 2023 Frenkel Smeijers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | 14 | See the GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | 20 | */ 21 | /********************************************************************** 22 | file: DMA.H 23 | 24 | author: James R. Dose 25 | date: February 4, 1994 26 | 27 | Public header file for DMA.C 28 | 29 | (c) Copyright 1994 James R. Dose. All Rights Reserved. 30 | **********************************************************************/ 31 | 32 | #ifndef __DMA_H 33 | #define __DMA_H 34 | 35 | enum DMA_ERRORS 36 | { 37 | DMA_Error = -1, 38 | DMA_Ok = 0 39 | }; 40 | 41 | int32_t DMA_VerifyChannel(int32_t channel); 42 | int32_t DMA_SetupTransfer(int32_t channel, uint8_t *address, int32_t length); 43 | int32_t DMA_EndTransfer(int32_t channel); 44 | uint8_t *DMA_GetCurrentPos(int32_t channel); 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /a_inter.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 1994-1995 Apogee Software, Ltd. 3 | Copyright (C) 2023 Frenkel Smeijers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | 14 | See the GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | 20 | */ 21 | /********************************************************************** 22 | module: INTERRUP.H 23 | 24 | author: James R. Dose 25 | date: March 31, 1994 26 | 27 | Inline functions for disabling and restoring the interrupt flag. 28 | 29 | (c) Copyright 1994 James R. Dose. All Rights Reserved. 30 | **********************************************************************/ 31 | 32 | static uint32_t DisableInterrupts(void); 33 | static void RestoreInterrupts(uint32_t flags); 34 | 35 | 36 | #if defined __DMC__ || defined __CCDL__ 37 | static uint32_t DisableInterrupts(void) 38 | { 39 | asm 40 | { 41 | pushfd 42 | pop eax 43 | cli 44 | } 45 | return _EAX; 46 | } 47 | 48 | static void RestoreInterrupts(uint32_t flags) 49 | { 50 | asm 51 | { 52 | mov eax, [flags] 53 | push eax 54 | popfd 55 | } 56 | } 57 | 58 | #elif defined __DJGPP__ 59 | static uint32_t DisableInterrupts(void) 60 | { 61 | uint32_t a; 62 | asm 63 | ( 64 | "pushfl \n" 65 | "popl %0 \n" 66 | "cli" 67 | : "=r" (a) 68 | ); 69 | return a; 70 | } 71 | 72 | static void RestoreInterrupts(uint32_t flags) 73 | { 74 | asm 75 | ( 76 | "pushl %0 \n" 77 | "popfl" 78 | : 79 | : "r" (flags) 80 | ); 81 | } 82 | 83 | #elif defined __WATCOMC__ 84 | #pragma aux DisableInterrupts = \ 85 | "pushfd", \ 86 | "pop eax", \ 87 | "cli" \ 88 | value [eax]; 89 | 90 | #pragma aux RestoreInterrupts = \ 91 | "push eax", \ 92 | "popfd" \ 93 | parm [eax]; 94 | #endif 95 | -------------------------------------------------------------------------------- /a_ll_man.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 1994-1995 Apogee Software, Ltd. 3 | Copyright (C) 2023 Frenkel Smeijers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | 14 | See the GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | 20 | */ 21 | /********************************************************************** 22 | module: LL_MAN.C 23 | 24 | author: James R. Dose 25 | date: January 1, 1994 26 | 27 | Linked list management routines. 28 | 29 | (c) Copyright 1994 James R. Dose. All Rights Reserved. 30 | **********************************************************************/ 31 | 32 | #include "id_heads.h" 33 | #include "a_ll_man.h" 34 | 35 | 36 | #define OFFSET( structure, offset ) \ 37 | ( *( ( uint8_t ** )&( structure )[ offset ] ) ) 38 | 39 | 40 | void LL_AddNode(uint8_t *item, uint8_t **head, uint8_t **tail, int32_t next, int32_t prev) 41 | { 42 | OFFSET(item, prev) = NULL; 43 | OFFSET(item, next) = *head; 44 | 45 | if (*head) 46 | OFFSET(*head, prev) = item; 47 | else 48 | *tail = item; 49 | 50 | *head = item; 51 | } 52 | 53 | 54 | void LL_RemoveNode(uint8_t *item, uint8_t **head, uint8_t **tail, int32_t next, int32_t prev) 55 | { 56 | if (OFFSET(item, prev) == NULL) 57 | *head = OFFSET(item, next); 58 | else 59 | OFFSET(OFFSET(item, prev), next) = OFFSET(item, next); 60 | 61 | if (OFFSET(item, next) == NULL) 62 | *tail = OFFSET(item, prev); 63 | else 64 | OFFSET(OFFSET(item, next), prev) = OFFSET(item, prev); 65 | 66 | OFFSET(item, next) = NULL; 67 | OFFSET(item, prev) = NULL; 68 | } 69 | -------------------------------------------------------------------------------- /a_ll_man.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 1994-1995 Apogee Software, Ltd. 3 | Copyright (C) 2023 Frenkel Smeijers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | 14 | See the GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | 20 | */ 21 | /********************************************************************** 22 | module: LL_MAN.H 23 | 24 | author: James R. Dose 25 | date: February 4, 1994 26 | 27 | Public header for LL_MAN.C. Linked list management routines. 28 | 29 | (c) Copyright 1994 James R. Dose. All Rights Reserved. 30 | **********************************************************************/ 31 | 32 | #ifndef __LL_MAN_H 33 | #define __LL_MAN_H 34 | 35 | void LL_AddNode( uint8_t *node, uint8_t **head, uint8_t **tail, int32_t next, int32_t prev); 36 | void LL_RemoveNode(uint8_t *node, uint8_t **head, uint8_t **tail, int32_t next, int32_t prev); 37 | 38 | #define LL_AddToTail(type, listhead, node) \ 39 | LL_AddNode( ( uint8_t * )( node ), \ 40 | ( uint8_t ** )&( ( listhead )->end ), \ 41 | ( uint8_t ** )&( ( listhead )->start ), \ 42 | ( int32_t )&( ( type * ) 0 )->prev, \ 43 | ( int32_t )&( ( type * ) 0 )->next ) 44 | 45 | #define LL_Remove( type, listhead, node ) \ 46 | LL_RemoveNode( ( uint8_t * )( node ), \ 47 | ( uint8_t ** )&( ( listhead )->start ), \ 48 | ( uint8_t ** )&( ( listhead )->end ), \ 49 | ( int32_t )&( ( type * ) 0 )->next, \ 50 | ( int32_t )&( ( type * ) 0 )->prev ) 51 | 52 | #define LL_Empty(a) ((a)->start == NULL) 53 | 54 | #define LL_Reset(list) (list)->start = NULL; (list)->end = NULL 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /a_midi.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 1994-1995 Apogee Software, Ltd. 3 | Copyright (C) 2023-2025 Frenkel Smeijers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | 14 | See the GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | 20 | */ 21 | /********************************************************************** 22 | module: MIDI.H 23 | 24 | author: James R. Dose 25 | date: May 25, 1994 26 | 27 | Public header for MIDI.C. Midi song file playback routines. 28 | 29 | (c) Copyright 1994 James R. Dose. All Rights Reserved. 30 | **********************************************************************/ 31 | 32 | #ifndef __MIDI_H 33 | #define __MIDI_H 34 | 35 | enum MIDI_Errors 36 | { 37 | MIDI_Error = -1, 38 | MIDI_Ok = 0, 39 | MIDI_NullMidiModule, 40 | MIDI_InvalidMidiFile, 41 | MIDI_UnknownMidiFormat, 42 | MIDI_NoTracks, 43 | MIDI_InvalidTrack, 44 | MIDI_NoMemory 45 | }; 46 | 47 | typedef struct 48 | { 49 | void (*NoteOff)(int32_t channel, int32_t key, int32_t velocity); 50 | void (*NoteOn)(int32_t channel, int32_t key, int32_t velocity); 51 | void (*PolyAftertouch)(int32_t channel, int32_t key, int32_t pressure); 52 | void (*ControlChange)(int32_t channel, int32_t number, int32_t value); 53 | void (*ProgramChange)(int32_t channel, int32_t program); 54 | void (*ChannelAftertouch)(int32_t channel, int32_t pressure); 55 | void (*PitchBend)(int32_t channel, int32_t lsb, int32_t msb); 56 | void (*SetVolume)(int32_t volume); 57 | int32_t (*GetVolume)(void); 58 | } midifuncs; 59 | 60 | void MIDI_SetVolume(int32_t volume); 61 | void MIDI_SetMidiFuncs(midifuncs *funcs, int32_t soundDevice); 62 | void MIDI_ContinueSong(void); 63 | void MIDI_PauseSong(void); 64 | void MIDI_StopSong(void); 65 | int32_t MIDI_PlaySong(uint8_t *song, int32_t loopflag); 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /a_mpu401.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 1994-1995 Apogee Software, Ltd. 3 | Copyright (C) 2023 Frenkel Smeijers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | 14 | See the GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | 20 | */ 21 | /********************************************************************** 22 | module: MPU401.C 23 | 24 | author: James R. Dose 25 | date: January 1, 1994 26 | 27 | Low level routines to support sending of MIDI data to MPU401 28 | compatible MIDI interfaces. 29 | 30 | (c) Copyright 1994 James R. Dose. All Rights Reserved. 31 | **********************************************************************/ 32 | 33 | #include 34 | #include 35 | #include "id_heads.h" 36 | #include "a_mpu401.h" 37 | 38 | #define MPU_NotFound -1 39 | #define MPU_UARTFailed -2 40 | 41 | #define MPU_ReadyToWrite 0x40 42 | #define MPU_ReadyToRead 0x80 43 | #define MPU_CmdEnterUART 0x3f 44 | #define MPU_CmdReset 0xff 45 | #define MPU_CmdAcknowledge 0xfe 46 | 47 | #define MIDI_NOTE_OFF 0x80 48 | #define MIDI_NOTE_ON 0x90 49 | #define MIDI_POLY_AFTER_TCH 0xA0 50 | #define MIDI_CONTROL_CHANGE 0xB0 51 | #define MIDI_PROGRAM_CHANGE 0xC0 52 | #define MIDI_AFTER_TOUCH 0xD0 53 | #define MIDI_PITCH_BEND 0xE0 54 | 55 | #define MPU_DefaultAddress 0x330 56 | static int32_t MPU_BaseAddr = MPU_DefaultAddress; 57 | 58 | #define MPU_Delay 0x5000; 59 | 60 | 61 | /*--------------------------------------------------------------------- 62 | Function: MPU_SendMidi 63 | 64 | Sends a byte of MIDI data to the music device. 65 | ---------------------------------------------------------------------*/ 66 | 67 | static void MPU_SendMidi(int32_t data) 68 | { 69 | int32_t port = MPU_BaseAddr + 1; 70 | uint32_t count = MPU_Delay; 71 | 72 | while (count > 0) 73 | { 74 | // check if status port says we're ready for write 75 | if (!(inp(port) & MPU_ReadyToWrite)) 76 | break; 77 | 78 | count--; 79 | } 80 | 81 | port--; 82 | 83 | // Send the midi data 84 | outp(port, data); 85 | } 86 | 87 | 88 | /*--------------------------------------------------------------------- 89 | Function: MPU_NoteOff 90 | 91 | Sends a full MIDI note off event out to the music device. 92 | ---------------------------------------------------------------------*/ 93 | 94 | void MPU_NoteOff(int32_t channel, int32_t key, int32_t velocity) 95 | { 96 | MPU_SendMidi(MIDI_NOTE_OFF | channel); 97 | MPU_SendMidi(key); 98 | MPU_SendMidi(velocity); 99 | } 100 | 101 | 102 | /*--------------------------------------------------------------------- 103 | Function: MPU_NoteOn 104 | 105 | Sends a full MIDI note on event out to the music device. 106 | ---------------------------------------------------------------------*/ 107 | 108 | void MPU_NoteOn(int32_t channel, int32_t key, int32_t velocity) 109 | { 110 | MPU_SendMidi(MIDI_NOTE_ON | channel); 111 | MPU_SendMidi(key); 112 | MPU_SendMidi(velocity); 113 | } 114 | 115 | 116 | /*--------------------------------------------------------------------- 117 | Function: MPU_PolyAftertouch 118 | 119 | Sends a full MIDI polyphonic aftertouch event out to the music device. 120 | ---------------------------------------------------------------------*/ 121 | 122 | void MPU_PolyAftertouch(int32_t channel, int32_t key, int32_t pressure) 123 | { 124 | MPU_SendMidi(MIDI_POLY_AFTER_TCH | channel); 125 | MPU_SendMidi(key); 126 | MPU_SendMidi(pressure); 127 | } 128 | 129 | 130 | /*--------------------------------------------------------------------- 131 | Function: MPU_ControlChange 132 | 133 | Sends a full MIDI control change event out to the music device. 134 | ---------------------------------------------------------------------*/ 135 | 136 | void MPU_ControlChange(int32_t channel, int32_t number, int32_t value) 137 | { 138 | MPU_SendMidi(MIDI_CONTROL_CHANGE | channel); 139 | MPU_SendMidi(number); 140 | MPU_SendMidi(value); 141 | } 142 | 143 | 144 | /*--------------------------------------------------------------------- 145 | Function: MPU_ProgramChange 146 | 147 | Sends a full MIDI program change event out to the music device. 148 | ---------------------------------------------------------------------*/ 149 | 150 | void MPU_ProgramChange(int32_t channel, int32_t program) 151 | { 152 | MPU_SendMidi(MIDI_PROGRAM_CHANGE | channel); 153 | MPU_SendMidi(program); 154 | } 155 | 156 | 157 | /*--------------------------------------------------------------------- 158 | Function: MPU_ChannelAftertouch 159 | 160 | Sends a full MIDI channel aftertouch event out to the music device. 161 | ---------------------------------------------------------------------*/ 162 | 163 | void MPU_ChannelAftertouch(int32_t channel, int32_t pressure) 164 | { 165 | MPU_SendMidi(MIDI_AFTER_TOUCH | channel); 166 | MPU_SendMidi(pressure); 167 | } 168 | 169 | 170 | /*--------------------------------------------------------------------- 171 | Function: MPU_PitchBend 172 | 173 | Sends a full MIDI pitch bend event out to the music device. 174 | ---------------------------------------------------------------------*/ 175 | 176 | void MPU_PitchBend(int32_t channel, int32_t lsb, int32_t msb) 177 | { 178 | MPU_SendMidi(MIDI_PITCH_BEND | channel); 179 | MPU_SendMidi(lsb); 180 | MPU_SendMidi(msb); 181 | } 182 | 183 | 184 | /*--------------------------------------------------------------------- 185 | Function: MPU_SendCommand 186 | 187 | Sends a command to the MPU401 card. 188 | ---------------------------------------------------------------------*/ 189 | 190 | static void MPU_SendCommand(int32_t data) 191 | { 192 | int32_t port = MPU_BaseAddr + 1; 193 | uint32_t count = 0xffff; 194 | 195 | while (count > 0) 196 | { 197 | // check if status port says we're ready for write 198 | if (!(inp(port) & MPU_ReadyToWrite)) 199 | break; 200 | 201 | count--; 202 | } 203 | 204 | outp(port, data); 205 | } 206 | 207 | 208 | /*--------------------------------------------------------------------- 209 | Function: MPU_Reset 210 | 211 | Resets the MPU401 card. 212 | ---------------------------------------------------------------------*/ 213 | 214 | int32_t MPU_Reset(void) 215 | { 216 | int32_t port = MPU_BaseAddr + 1; 217 | uint32_t count = 0xffff; 218 | 219 | // Output "Reset" command via Command port 220 | MPU_SendCommand(MPU_CmdReset); 221 | 222 | // Wait for status port to be ready for read 223 | while (count > 0) 224 | { 225 | if (!(inp(port) & MPU_ReadyToRead)) 226 | { 227 | port--; 228 | 229 | // Check for a successful reset 230 | if (inp(port) == MPU_CmdAcknowledge) 231 | return MPU_Ok; 232 | 233 | port++; 234 | } 235 | count--; 236 | } 237 | 238 | // Failed to reset : MPU-401 not detected 239 | return MPU_NotFound; 240 | } 241 | 242 | 243 | /*--------------------------------------------------------------------- 244 | Function: MPU_EnterUART 245 | 246 | Sets the MPU401 card to operate in UART mode. 247 | ---------------------------------------------------------------------*/ 248 | 249 | static int32_t MPU_EnterUART(void) 250 | { 251 | int32_t port = MPU_BaseAddr + 1; 252 | uint32_t count = 0xffff; 253 | 254 | // Output "Enter UART" command via Command port 255 | MPU_SendCommand(MPU_CmdEnterUART); 256 | 257 | // Wait for status port to be ready for read 258 | while (count > 0) 259 | { 260 | if (!(inp(port) & MPU_ReadyToRead)) 261 | { 262 | port--; 263 | 264 | // Check for a successful reset 265 | if (inp(port) == MPU_CmdAcknowledge) 266 | return MPU_Ok; 267 | 268 | port++; 269 | } 270 | count--; 271 | } 272 | 273 | // Failed to reset : MPU-401 not detected 274 | return MPU_UARTFailed; 275 | } 276 | 277 | 278 | /*--------------------------------------------------------------------- 279 | Function: MPU_Init 280 | 281 | Detects and initializes the MPU401 card. 282 | ---------------------------------------------------------------------*/ 283 | 284 | int32_t MPU_Init(int32_t addr) 285 | { 286 | int32_t status; 287 | int32_t count = 4; 288 | 289 | MPU_BaseAddr = addr; 290 | 291 | while (count > 0) 292 | { 293 | status = MPU_Reset(); 294 | if (status == MPU_Ok) 295 | return MPU_EnterUART(); 296 | 297 | count--; 298 | } 299 | 300 | return status; 301 | } 302 | -------------------------------------------------------------------------------- /a_mpu401.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 1994-1995 Apogee Software, Ltd. 3 | Copyright (C) 2023 Frenkel Smeijers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | 14 | See the GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | 20 | */ 21 | #ifndef __MPU401_H 22 | #define __MPU401_H 23 | 24 | #define MPU_Ok 0 25 | 26 | int32_t MPU_Reset(void); 27 | int32_t MPU_Init(int32_t addr); 28 | void MPU_NoteOff(int32_t channel, int32_t key, int32_t velocity); 29 | void MPU_NoteOn(int32_t channel, int32_t key, int32_t velocity); 30 | void MPU_PolyAftertouch(int32_t channel, int32_t key, int32_t pressure); 31 | void MPU_ControlChange(int32_t channel, int32_t number, int32_t value); 32 | void MPU_ProgramChange(int32_t channel, int32_t program); 33 | void MPU_ChannelAftertouch(int32_t channel, int32_t pressure); 34 | void MPU_PitchBend(int32_t channel, int32_t lsb, int32_t msb); 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /a_multiv.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 1994-1995 Apogee Software, Ltd. 3 | Copyright (C) 2023 Frenkel Smeijers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | 14 | See the GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | 20 | */ 21 | /********************************************************************** 22 | file: MULTIVOC.H 23 | 24 | author: James R. Dose 25 | date: December 20, 1993 26 | 27 | Public header for MULTIVOC.C 28 | 29 | (c) Copyright 1993 James R. Dose. All Rights Reserved. 30 | **********************************************************************/ 31 | 32 | #ifndef __MULTIVOC_H 33 | #define __MULTIVOC_H 34 | 35 | boolean MV_VoicePlaying(int32_t handle); 36 | void MV_Kill(int32_t handle); 37 | void MV_SetOrigin(int32_t handle, int32_t pitchoffset, int32_t vol, int32_t left, int32_t right); 38 | int32_t MV_PlayRaw(uint8_t *ptr, uint32_t length, uint32_t rate, int32_t pitchoffset, int32_t vol, int32_t left, int32_t right, int32_t priority); 39 | void MV_Init(int32_t soundcard, int32_t MixRate, int32_t Voices); 40 | void MV_Shutdown(void); 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /a_music.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 1994-1995 Apogee Software, Ltd. 3 | Copyright (C) 2023-2025 Frenkel Smeijers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | 14 | See the GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | 20 | */ 21 | /********************************************************************** 22 | module: MUSIC.C 23 | 24 | author: James R. Dose 25 | date: March 25, 1994 26 | 27 | Device independant music playback routines. 28 | 29 | (c) Copyright 1994 James R. Dose. All Rights Reserved. 30 | **********************************************************************/ 31 | 32 | #include "id_heads.h" 33 | #include "dmx.h" 34 | #include "a_al_mid.h" 35 | #include "a_blast.h" 36 | #include "a_midi.h" 37 | #include "a_mpu401.h" 38 | #include "a_music.h" 39 | #include "a_taskmn.h" 40 | 41 | static int32_t MUSIC_SoundDevice = AHW_NONE; 42 | 43 | static midifuncs MUSIC_MidiFunctions; 44 | 45 | static int32_t MUSIC_InitFM(midifuncs *Funcs); 46 | static int32_t MUSIC_InitMidi(midifuncs *Funcs, int32_t Address); 47 | 48 | 49 | /*--------------------------------------------------------------------- 50 | Function: MUSIC_Init 51 | 52 | Selects which sound device to use. 53 | ---------------------------------------------------------------------*/ 54 | 55 | int32_t MUSIC_Init(int32_t SoundCard, int32_t Address) 56 | { 57 | MUSIC_SoundDevice = SoundCard; 58 | 59 | switch (SoundCard) 60 | { 61 | case AHW_ADLIB: 62 | return MUSIC_InitFM(&MUSIC_MidiFunctions); 63 | 64 | case AHW_MPU_401: 65 | return MUSIC_InitMidi(&MUSIC_MidiFunctions, Address); 66 | 67 | default: 68 | return MUSIC_Error; 69 | } 70 | } 71 | 72 | 73 | /*--------------------------------------------------------------------- 74 | Function: MUSIC_Shutdown 75 | 76 | Terminates use of sound device. 77 | ---------------------------------------------------------------------*/ 78 | 79 | void MUSIC_Shutdown(void) 80 | { 81 | MIDI_StopSong(); 82 | 83 | switch (MUSIC_SoundDevice) 84 | { 85 | case AHW_ADLIB : 86 | AL_Shutdown(); 87 | break; 88 | 89 | case AHW_MPU_401: 90 | MPU_Reset(); 91 | break; 92 | } 93 | } 94 | 95 | 96 | /*--------------------------------------------------------------------- 97 | Function: MUSIC_SetVolume 98 | 99 | Sets the volume of music playback. 100 | ---------------------------------------------------------------------*/ 101 | 102 | void MUSIC_SetVolume(int32_t volume) 103 | { 104 | if (MUSIC_SoundDevice == AHW_NONE) 105 | return; 106 | 107 | if (volume < 0) 108 | volume = 0; 109 | else if (volume > 255) 110 | volume = 255; 111 | 112 | MIDI_SetVolume(volume); 113 | } 114 | 115 | 116 | /*--------------------------------------------------------------------- 117 | Function: MUSIC_Continue 118 | 119 | Continues playback of a paused song. 120 | ---------------------------------------------------------------------*/ 121 | 122 | void MUSIC_Continue(void) 123 | { 124 | MIDI_ContinueSong(); 125 | } 126 | 127 | 128 | /*--------------------------------------------------------------------- 129 | Function: MUSIC_Pause 130 | 131 | Pauses playback of a song. 132 | ---------------------------------------------------------------------*/ 133 | 134 | void MUSIC_Pause(void) 135 | { 136 | MIDI_PauseSong(); 137 | } 138 | 139 | 140 | /*--------------------------------------------------------------------- 141 | Function: MUSIC_StopSong 142 | 143 | Stops playback of current song. 144 | ---------------------------------------------------------------------*/ 145 | 146 | void MUSIC_StopSong(void) 147 | { 148 | MIDI_StopSong(); 149 | } 150 | 151 | 152 | /*--------------------------------------------------------------------- 153 | Function: MUSIC_PlaySong 154 | 155 | Begins playback of MIDI song. 156 | ---------------------------------------------------------------------*/ 157 | 158 | int32_t MUSIC_PlaySong(uint8_t *song, int32_t loopflag) 159 | { 160 | int32_t status; 161 | 162 | switch (MUSIC_SoundDevice) 163 | { 164 | case AHW_ADLIB: 165 | case AHW_MPU_401: 166 | MIDI_StopSong(); 167 | status = MIDI_PlaySong(song, loopflag); 168 | if (status != MIDI_Ok) 169 | return MUSIC_Warning; 170 | break; 171 | 172 | default: 173 | return MUSIC_Warning; 174 | } 175 | 176 | return MUSIC_Ok; 177 | } 178 | 179 | 180 | static int32_t MUSIC_InitFM(midifuncs *Funcs) 181 | { 182 | if (!AL_DetectFM()) 183 | return MUSIC_Error; 184 | 185 | // Init the fm routines 186 | AL_Init(); 187 | 188 | Funcs->NoteOff = AL_NoteOff; 189 | Funcs->NoteOn = AL_NoteOn; 190 | Funcs->PolyAftertouch = NULL; 191 | Funcs->ControlChange = AL_ControlChange; 192 | Funcs->ProgramChange = AL_ProgramChange; 193 | Funcs->ChannelAftertouch = NULL; 194 | Funcs->PitchBend = AL_SetPitchBend; 195 | Funcs->SetVolume = NULL; 196 | Funcs->GetVolume = NULL; 197 | 198 | MIDI_SetMidiFuncs(Funcs, MUSIC_SoundDevice); 199 | 200 | return MUSIC_Ok; 201 | } 202 | 203 | 204 | static int32_t MUSIC_InitMidi(midifuncs *Funcs, int32_t Address) 205 | { 206 | BLASTER_SetupWaveBlaster(); 207 | 208 | if (MPU_Init(Address) != MPU_Ok) 209 | return MUSIC_Error; 210 | 211 | Funcs->NoteOff = MPU_NoteOff; 212 | Funcs->NoteOn = MPU_NoteOn; 213 | Funcs->PolyAftertouch = MPU_PolyAftertouch; 214 | Funcs->ControlChange = MPU_ControlChange; 215 | Funcs->ProgramChange = MPU_ProgramChange; 216 | Funcs->ChannelAftertouch = MPU_ChannelAftertouch; 217 | Funcs->PitchBend = MPU_PitchBend; 218 | Funcs->SetVolume = NULL; 219 | Funcs->GetVolume = NULL; 220 | 221 | MIDI_SetMidiFuncs(Funcs, MUSIC_SoundDevice); 222 | 223 | return MUSIC_Ok; 224 | } 225 | -------------------------------------------------------------------------------- /a_music.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 1994-1995 Apogee Software, Ltd. 3 | Copyright (C) 2023-2025 Frenkel Smeijers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | 14 | See the GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | 20 | */ 21 | /********************************************************************** 22 | module: MUSIC.H 23 | 24 | author: James R. Dose 25 | date: March 25, 1994 26 | 27 | Public header for MUSIC.C 28 | 29 | (c) Copyright 1994 James R. Dose. All Rights Reserved. 30 | **********************************************************************/ 31 | 32 | #ifndef __MUSIC_H 33 | #define __MUSIC_H 34 | 35 | enum MUSIC_ERRORS 36 | { 37 | MUSIC_Warning = -2, 38 | MUSIC_Error = -1, 39 | MUSIC_Ok = 0 40 | }; 41 | 42 | typedef struct 43 | { 44 | uint32_t tickposition; 45 | uint32_t milliseconds; 46 | uint32_t measure; 47 | uint32_t beat; 48 | uint32_t tick; 49 | } songposition; 50 | 51 | int32_t MUSIC_Init(int32_t SoundCard, int32_t Address); 52 | void MUSIC_Shutdown(void); 53 | void MUSIC_SetVolume(int32_t volume); 54 | void MUSIC_Continue(void); 55 | void MUSIC_Pause(void); 56 | void MUSIC_StopSong(void); 57 | int32_t MUSIC_PlaySong(uint8_t *song, int32_t loopflag); 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /a_pcfx.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 1994-1995 Apogee Software, Ltd. 3 | Copyright (C) 2023-2025 Frenkel Smeijers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | 14 | See the GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | 20 | */ 21 | /********************************************************************** 22 | module: PCFX.C 23 | 24 | author: James R. Dose 25 | date: April 1, 1994 26 | 27 | Low level routines to support PC sound effects created by Muse. 28 | 29 | (c) Copyright 1994 James R. Dose. All Rights Reserved. 30 | **********************************************************************/ 31 | 32 | #include 33 | #include 34 | #include "id_heads.h" 35 | #include "a_inter.h" 36 | #include "a_pcfx.h" 37 | #include "a_taskmn.h" 38 | 39 | #define PCFX_MinVoiceHandle 1 40 | 41 | static void PCFX_Service(task *Task); 42 | 43 | static int32_t PCFX_LengthLeft; 44 | static uint8_t *PCFX_Sound = NULL; 45 | static int32_t PCFX_LastSample; 46 | static task *PCFX_ServiceTask = NULL; 47 | static int32_t PCFX_VoiceHandle = PCFX_MinVoiceHandle; 48 | 49 | static boolean PCFX_Installed = false; 50 | 51 | 52 | /*--------------------------------------------------------------------- 53 | Function: PCFX_Stop 54 | 55 | Halts playback of the currently playing sound effect. 56 | ---------------------------------------------------------------------*/ 57 | 58 | void PCFX_Stop(int32_t handle) 59 | { 60 | uint32_t flags; 61 | 62 | if ((handle != PCFX_VoiceHandle) || (PCFX_Sound == NULL)) 63 | return; 64 | 65 | flags = DisableInterrupts(); 66 | 67 | // Turn off speaker 68 | outp(0x61, inp(0x61) & 0xfc); 69 | 70 | PCFX_Sound = NULL; 71 | PCFX_LengthLeft = 0; 72 | PCFX_LastSample = 0; 73 | 74 | RestoreInterrupts(flags); 75 | } 76 | 77 | 78 | /*--------------------------------------------------------------------- 79 | Function: PCFX_Service 80 | 81 | Task Manager routine to perform the playback of a sound effect. 82 | ---------------------------------------------------------------------*/ 83 | 84 | static void PCFX_Service(task *Task) 85 | { 86 | uint32_t value; 87 | 88 | UNUSED(Task); 89 | 90 | if (PCFX_Sound) 91 | { 92 | value = *(int16_t *)PCFX_Sound; 93 | PCFX_Sound += sizeof(int16_t); 94 | 95 | if (value != PCFX_LastSample) 96 | { 97 | PCFX_LastSample = value; 98 | if (value) 99 | { 100 | outp(0x43, 0xb6); 101 | outp(0x42, LOBYTE(value)); 102 | outp(0x42, HIBYTE(value)); 103 | outp(0x61, inp(0x61) | 0x3); 104 | } else 105 | outp(0x61, inp(0x61) & 0xfc); 106 | } 107 | 108 | if (--PCFX_LengthLeft == 0) 109 | PCFX_Stop(PCFX_VoiceHandle); 110 | } 111 | } 112 | 113 | 114 | /*--------------------------------------------------------------------- 115 | Function: PCFX_Play 116 | 117 | Starts playback of a Muse sound effect. 118 | ---------------------------------------------------------------------*/ 119 | 120 | typedef struct 121 | { 122 | uint32_t length; 123 | uint8_t data[]; 124 | } PCSound; 125 | 126 | static int32_t ASS_PCFX_Play(PCSound *sound) 127 | { 128 | uint32_t flags; 129 | 130 | PCFX_Stop(PCFX_VoiceHandle); 131 | 132 | PCFX_VoiceHandle++; 133 | if (PCFX_VoiceHandle < PCFX_MinVoiceHandle) 134 | PCFX_VoiceHandle = PCFX_MinVoiceHandle; 135 | 136 | flags = DisableInterrupts(); 137 | 138 | PCFX_LengthLeft = sound->length; 139 | PCFX_Sound = &sound->data[0]; 140 | 141 | RestoreInterrupts(flags); 142 | 143 | return PCFX_VoiceHandle; 144 | } 145 | 146 | static const uint16_t divisors[] = { 147 | 0, 148 | 6818, 6628, 6449, 6279, 6087, 5906, 5736, 5575, 149 | 5423, 5279, 5120, 4971, 4830, 4697, 4554, 4435, 150 | 4307, 4186, 4058, 3950, 3836, 3728, 3615, 3519, 151 | 3418, 3323, 3224, 3131, 3043, 2960, 2875, 2794, 152 | 2711, 2633, 2560, 2485, 2415, 2348, 2281, 2213, 153 | 2153, 2089, 2032, 1975, 1918, 1864, 1810, 1757, 154 | 1709, 1659, 1612, 1565, 1521, 1478, 1435, 1395, 155 | 1355, 1316, 1280, 1242, 1207, 1173, 1140, 1107, 156 | 1075, 1045, 1015, 986, 959, 931, 905, 879, 157 | 854, 829, 806, 783, 760, 739, 718, 697, 158 | 677, 658, 640, 621, 604, 586, 570, 553, 159 | 538, 522, 507, 493, 479, 465, 452, 439, 160 | 427, 415, 403, 391, 380, 369, 359, 348, 161 | 339, 329, 319, 310, 302, 293, 285, 276, 162 | 269, 261, 253, 246, 239, 232, 226, 219, 163 | 213, 207, 201, 195, 190, 184, 179, 164 | }; 165 | 166 | typedef struct { 167 | uint32_t length; 168 | uint16_t data[0x10000]; 169 | } pcspkmuse_t; 170 | 171 | static pcspkmuse_t pcspkmuse; 172 | 173 | typedef struct { 174 | uint16_t type; // 0 = PC Speaker 175 | uint16_t length; 176 | uint8_t data[]; 177 | } dmxpcs_t; 178 | 179 | int32_t PCFX_Play(void *vdata) 180 | { 181 | dmxpcs_t *dmxpcs = (dmxpcs_t *)vdata; 182 | uint_fast16_t i; 183 | 184 | pcspkmuse.length = dmxpcs->length; 185 | for (i = 0; i < dmxpcs->length; i++) 186 | pcspkmuse.data[i] = divisors[dmxpcs->data[i]]; 187 | 188 | return ASS_PCFX_Play((PCSound *)&pcspkmuse); 189 | } 190 | 191 | /*--------------------------------------------------------------------- 192 | Function: PCFX_SoundPlaying 193 | 194 | Checks if a sound effect is currently playing. 195 | ---------------------------------------------------------------------*/ 196 | 197 | boolean PCFX_SoundPlaying(int32_t handle) 198 | { 199 | return (handle == PCFX_VoiceHandle) && (PCFX_LengthLeft > 0); 200 | } 201 | 202 | 203 | /*--------------------------------------------------------------------- 204 | Function: PCFX_Init 205 | 206 | Initializes the sound effect engine. 207 | ---------------------------------------------------------------------*/ 208 | 209 | void PCFX_Init(int32_t ticrate) 210 | { 211 | if (PCFX_Installed) 212 | return; 213 | 214 | PCFX_Stop(PCFX_VoiceHandle); 215 | PCFX_ServiceTask = TS_ScheduleTask(&PCFX_Service, ticrate, 2); 216 | TS_Dispatch(); 217 | 218 | PCFX_Installed = true; 219 | } 220 | 221 | 222 | /*--------------------------------------------------------------------- 223 | Function: PCFX_Shutdown 224 | 225 | Ends the use of the sound effect engine. 226 | ---------------------------------------------------------------------*/ 227 | 228 | void PCFX_Shutdown(void) 229 | { 230 | if (PCFX_Installed) 231 | { 232 | PCFX_Stop(PCFX_VoiceHandle); 233 | TS_Terminate(PCFX_ServiceTask); 234 | PCFX_Installed = false; 235 | } 236 | } 237 | -------------------------------------------------------------------------------- /a_pcfx.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 1994-1995 Apogee Software, Ltd. 3 | Copyright (C) 2023 Frenkel Smeijers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | 14 | See the GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | 20 | */ 21 | /********************************************************************** 22 | module: PCFX.H 23 | 24 | author: James R. Dose 25 | date: April 1, 1994 26 | 27 | Public header for PCFX.C 28 | 29 | (c) Copyright 1994 James R. Dose. All Rights Reserved. 30 | **********************************************************************/ 31 | 32 | #ifndef __PCFX_H 33 | #define __PCFX_H 34 | 35 | void PCFX_Stop(int32_t handle); 36 | int32_t PCFX_Play(void *vdata); 37 | boolean PCFX_SoundPlaying(int32_t handle); 38 | void PCFX_Init(int32_t ticrate); 39 | void PCFX_Shutdown(void); 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /a_taskmn.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 1994-1995 Apogee Software, Ltd. 3 | Copyright (C) 2023-2025 Frenkel Smeijers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | 14 | See the GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | 20 | */ 21 | /********************************************************************** 22 | module: TASK_MAN.H 23 | 24 | author: James R. Dose 25 | date: July 25, 1994 26 | 27 | Public header for TASK_MAN.C, a low level timer task scheduler. 28 | 29 | (c) Copyright 1994 James R. Dose. All Rights Reserved. 30 | **********************************************************************/ 31 | 32 | #ifndef __TASK_MAN_H 33 | #define __TASK_MAN_H 34 | 35 | typedef struct task 36 | { 37 | struct task *next; 38 | struct task *prev; 39 | void (*TaskService)(struct task *); 40 | int32_t rate; 41 | volatile int32_t count; 42 | int32_t priority; 43 | boolean active; 44 | } task; 45 | 46 | void TS_Shutdown(void); 47 | task *TS_ScheduleTask(void (*Function)(task *), int32_t rate, int32_t priority); 48 | void TS_Terminate(task *ptr); 49 | void TS_Dispatch(void); 50 | void TS_SetTaskRate(task *Task, int32_t rate); 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /a_tsmapi.c: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // Copyright (C) 2023-2025 Frenkel Smeijers 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | 19 | #include "id_heads.h" 20 | #include "a_taskmn.h" 21 | #include "a_tsmapi.h" 22 | 23 | static task *t; 24 | static void (*callback)(void); 25 | 26 | 27 | void TSM_Install(uint32_t rate) 28 | { 29 | UNUSED(rate); 30 | } 31 | 32 | static void tsm_funch(task *t) 33 | { 34 | UNUSED(t); 35 | callback(); 36 | } 37 | 38 | int32_t TSM_NewService(void(*function)(void), int32_t rate, int32_t priority, int32_t pause) 39 | { 40 | UNUSED(pause); 41 | 42 | callback = function; 43 | t = TS_ScheduleTask(tsm_funch, rate, priority); 44 | TS_Dispatch(); 45 | return 0; 46 | } 47 | 48 | void TSM_DelService(int32_t taskId) 49 | { 50 | UNUSED(taskId); 51 | TS_Terminate(t); 52 | t = NULL; 53 | } 54 | 55 | void TSM_Remove(void) 56 | { 57 | TS_Shutdown(); 58 | } 59 | -------------------------------------------------------------------------------- /a_tsmapi.h: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // Copyright (C) 2023 Frenkel Smeijers 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | 19 | #ifndef _TSMAPI_H_ 20 | #define _TSMAPI_H_ 21 | 22 | void TSM_Install(uint32_t rate); 23 | int32_t TSM_NewService(void(*timerISR)(void), int32_t rate, int32_t priority, int32_t pause); 24 | void TSM_DelService(int32_t taskId); 25 | void TSM_Remove(void); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /am_data.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 1993-1996 Id Software, Inc. 3 | // Copyright (C) 2023 Frenkel Smeijers 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | 19 | // AM_data.h : The vector graphics for the automap 20 | 21 | #ifndef __AMDATA_H__ 22 | #define __AMDATA_H__ 23 | 24 | #pragma once 25 | 26 | // a line drawing of the player pointing right, starting from the middle. 27 | 28 | #define R ((8*PLAYERRADIUS)/7) 29 | 30 | static mline_t player_arrow[] = { 31 | { { -R+R/8, 0 }, { R, 0 } }, // ----- 32 | { { R, 0 }, { R-R/2, R/4 } }, // -----> 33 | { { R, 0 }, { R-R/2, -R/4 } }, 34 | { { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >----> 35 | { { -R+R/8, 0 }, { -R-R/8, -R/4 } }, 36 | { { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>---> 37 | { { -R+3*R/8, 0 }, { -R+R/8, -R/4 } } 38 | }; 39 | 40 | #undef R 41 | #define NUMPLYRLINES (sizeof(player_arrow)/sizeof(mline_t)) 42 | 43 | #define R ((8*PLAYERRADIUS)/7) 44 | static mline_t cheat_player_arrow[] = { 45 | { { -R+R/8, 0 }, { R, 0 } }, // ----- 46 | { { R, 0 }, { R-R/2, R/6 } }, // -----> 47 | { { R, 0 }, { R-R/2, -R/6 } }, 48 | { { -R+R/8, 0 }, { -R-R/8, R/6 } }, // >-----> 49 | { { -R+R/8, 0 }, { -R-R/8, -R/6 } }, 50 | { { -R+3*R/8, 0 }, { -R+R/8, R/6 } }, // >>-----> 51 | { { -R+3*R/8, 0 }, { -R+R/8, -R/6 } }, 52 | { { -R/2, 0 }, { -R/2, -R/6 } }, // >>-d---> 53 | { { -R/2, -R/6 }, { -R/2+R/6, -R/6 } }, 54 | { { -R/2+R/6, -R/6 }, { -R/2+R/6, R/4 } }, 55 | { { -R/6, 0 }, { -R/6, -R/6 } }, // >>-dd--> 56 | { { -R/6, -R/6 }, { 0, -R/6 } }, 57 | { { 0, -R/6 }, { 0, R/4 } }, 58 | { { R/6, R/4 }, { R/6, -R/7 } }, // >>-ddt-> 59 | { { R/6, -R/7 }, { R/6+R/32, -R/7-R/32 } }, 60 | { { R/6+R/32, -R/7-R/32 }, { R/6+R/10, -R/7 } } 61 | }; 62 | #undef R 63 | #define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow)/sizeof(mline_t)) 64 | 65 | #define R (FRACUNIT) 66 | static mline_t thintriangle_guy[] = { 67 | { { -.5*R, -.7*R }, { R, 0 } }, 68 | { { R, 0 }, { -.5*R, .7*R } }, 69 | { { -.5*R, .7*R }, { -.5*R, -.7*R } } 70 | }; 71 | #undef R 72 | #define NUMTHINTRIANGLEGUYLINES (sizeof(thintriangle_guy)/sizeof(mline_t)) 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /am_map.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 1993-1996 Id Software, Inc. 3 | // Copyright (C) 2023 Frenkel Smeijers 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | 19 | #ifndef __AMMAP_H__ 20 | #define __AMMAP_H__ 21 | 22 | // For use if I do walls with outsides/insides 23 | #define REDS (256-5*16) 24 | #define REDRANGE 16 25 | #define BLUES (256-4*16+8) 26 | #define BLUERANGE 8 27 | #define GREENS (7*16) 28 | #define GRAYS (6*16) 29 | #define GRAYSRANGE 16 30 | #define BROWNS (4*16) 31 | #define BROWNRANGE 16 32 | #define YELLOWS (256-32+7) 33 | #define YELLOWRANGE 1 34 | #define BLACK 0 35 | #define WHITE (256-47) 36 | 37 | // Automap colors 38 | #define BACKGROUND BLACK 39 | #define YOURCOLORS WHITE 40 | #define YOURRANGE 0 41 | #define WALLCOLORS REDS 42 | #define WALLRANGE REDRANGE 43 | #define TSWALLCOLORS GRAYS 44 | #define TSWALLRANGE GRAYSRANGE 45 | #define FDWALLCOLORS BROWNS 46 | #define FDWALLRANGE BROWNRANGE 47 | #define CDWALLCOLORS YELLOWS 48 | #define CDWALLRANGE YELLOWRANGE 49 | #define THINGCOLORS GREENS 50 | #define SECRETWALLCOLORS WALLCOLORS 51 | #define SECRETWALLRANGE WALLRANGE 52 | #define GRIDCOLORS (GRAYS + GRAYSRANGE/2) 53 | #define GRIDRANGE 0 54 | #define XHAIRCOLORS GRAYS 55 | 56 | // drawing stuff 57 | #define FB 0 58 | 59 | #define AM_PANDOWNKEY KEY_DOWNARROW 60 | #define AM_PANUPKEY KEY_UPARROW 61 | #define AM_PANRIGHTKEY KEY_RIGHTARROW 62 | #define AM_PANLEFTKEY KEY_LEFTARROW 63 | #define AM_ZOOMINKEY '=' 64 | #define AM_ZOOMOUTKEY '-' 65 | #define AM_STARTKEY KEY_TAB 66 | #define AM_ENDKEY KEY_TAB 67 | #define AM_GOBIGKEY '0' 68 | #define AM_FOLLOWKEY 'f' 69 | #define AM_GRIDKEY 'g' 70 | #define AM_MARKKEY 'm' 71 | #define AM_CLEARMARKKEY 'c' 72 | 73 | #define AM_NUMMARKPOINTS 10 74 | 75 | #define AM_MSGHEADER (('a'<<24)+('m'<<16)) 76 | #define AM_MSGENTERED (AM_MSGHEADER | ('e'<<8)) 77 | #define AM_MSGEXITED (AM_MSGHEADER | ('x'<<8)) 78 | // scale on entry 79 | #define INITSCALEMTOF (.2*FRACUNIT) 80 | // how much the automap moves window per tic in frame-buffer coordinates 81 | // moves 140 pixels in 1 second 82 | #define F_PANINC 4 83 | // how much zoom-in per tic 84 | // goes to 2x in 1 second 85 | #define M_ZOOMIN ((int32_t) (1.02*FRACUNIT)) 86 | // how much zoom-out per tic 87 | // pulls out to 0.5x in 1 second 88 | #define M_ZOOMOUT ((int32_t) (FRACUNIT/1.02)) 89 | 90 | // translates between frame-buffer and map distances 91 | #define FTOM(x) FixedMul(((x)<<16),scale_ftom) 92 | #define MTOF(x) (FixedMul((x),scale_mtof)>>16) 93 | // translates between frame-buffer and map coordinates 94 | #define CXMTOF(x) (MTOF((x)-m_x)) 95 | #define CYMTOF(y) (SCREENHEIGHT-ST_HEIGHT - MTOF((y)-m_y)) 96 | 97 | // the following is crap 98 | #define LINE_NEVERSEE ML_DONTDRAW 99 | 100 | typedef struct 101 | { 102 | int32_t x, y; 103 | } fpoint_t; 104 | 105 | typedef struct 106 | { 107 | fpoint_t a, b; 108 | } fline_t; 109 | 110 | typedef struct 111 | { 112 | fixed_t x,y; 113 | } mpoint_t; 114 | 115 | typedef struct 116 | { 117 | mpoint_t a, b; 118 | } mline_t; 119 | 120 | typedef struct 121 | { 122 | fixed_t slp, islp; 123 | } islope_t; 124 | 125 | #endif 126 | -------------------------------------------------------------------------------- /compdj.bat: -------------------------------------------------------------------------------- 1 | if "%DJDIR%" == "" goto error 2 | 3 | mkdir DJDM19 4 | 5 | nasm a_mv_mix.asm -f coff 6 | nasm planar.asm -f coff 7 | 8 | set CFLAGS=-Ofast -march=i386 -flto -fwhole-program -fomit-frame-pointer -funroll-loops -fgcse-sm -fgcse-las -fipa-pta -mpreferred-stack-boundary=2 -Wno-attributes -Wpedantic 9 | @rem set CFLAGS=%CFLAGS% -Wall -Wextra 10 | 11 | set GLOBOBJS=dmx.c a_al_mid.c a_blast.c a_dma.c a_ll_man.c a_midi.c a_mpu401.c a_multiv.c a_music.c a_musmid.c a_mv_mix.o a_pcfx.c a_taskmn.c a_tsmapi.c i_main.c i_ibm.c i_sound.c planar.o tables.c f_finale.c d_main.c d_net.c g_game.c m_menu.c m_misc.c am_map.c p_ceilng.c p_doors.c p_enemy.c p_floor.c p_inter.c p_lights.c p_map.c p_maputl.c p_plats.c p_pspr.c p_setup.c p_sight.c p_spec.c p_switch.c p_mobj.c p_telept.c p_tick.c p_user.c r_bsp.c r_data.c r_draw.c r_main.c r_plane.c r_segs.c r_things.c w_wad.c wi_stuff.c v_video.c st_lib.c st_stuff.c hu_stuff.c hu_lib.c s_sound.c z_zone.c info.c sounds.c dutils.c 12 | gcc -DAPPVER_EXEDEF=DM19 %GLOBOBJS% %CFLAGS% -o DJDM19/djdoom.exe 13 | strip -s DJDM19/djdoom.exe 14 | stubedit DJDM19/djdoom.exe dpmi=CWSDPR0.EXE 15 | 16 | del a_mv_mix.o 17 | del planar.o 18 | 19 | goto end 20 | 21 | :error 22 | @echo Set the environment variables before running this script! 23 | 24 | :end 25 | -------------------------------------------------------------------------------- /compdm.bat: -------------------------------------------------------------------------------- 1 | mkdir DMDM19 2 | 3 | nasm a_mv_mix.asm -f obj 4 | nasm planar.asm -f obj 5 | 6 | set GLOBOBJS=dmx.c a_al_mid.c a_blast.c a_dma.c a_ll_man.c a_midi.c a_mpu401.c a_multiv.c a_music.c a_musmid.c a_mv_mix.obj a_pcfx.c a_taskmn.c a_tsmapi.c i_main.c i_ibm.c i_sound.c planar.obj tables.c f_finale.c d_main.c d_net.c g_game.c m_menu.c m_misc.c am_map.c p_ceilng.c p_doors.c p_enemy.c p_floor.c p_inter.c p_lights.c p_map.c p_maputl.c p_plats.c p_pspr.c p_setup.c p_sight.c p_spec.c p_switch.c p_mobj.c p_telept.c p_tick.c p_user.c r_bsp.c r_data.c r_draw.c r_main.c r_plane.c r_segs.c r_things.c w_wad.c wi_stuff.c v_video.c st_lib.c st_stuff.c hu_stuff.c hu_lib.c s_sound.c z_zone.c info.c sounds.c dutils.c 7 | dmc %GLOBOBJS% -mx X32.LIB -3 -o+all -DAPPVER_EXEDEF=DM19 -oDMDM19\dmdoom.exe 8 | 9 | del *.obj 10 | del dmdoom.map 11 | -------------------------------------------------------------------------------- /compiler.h: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // Copyright (C) 2023-2024 Frenkel Smeijers 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | 19 | #ifndef __COMPILER__ 20 | #define __COMPILER__ 21 | 22 | #if defined __DJGPP__ 23 | //DJGPP 24 | #include 25 | #include 26 | #include 27 | 28 | #define mkdir(x) mkdir(x,0) 29 | 30 | //DJGPP doesn't inline inp, outp and outpw, 31 | //but it does inline inportb, outportb and outportw 32 | #define inp(port) inportb(port) 33 | #define outp(port,data) outportb(port,data) 34 | #define outpw(port,data) outportw(port,data) 35 | 36 | #define _interrupt 37 | #define _far 38 | 39 | #define replaceInterrupt(OldInt,NewInt,vector,handler) \ 40 | _go32_dpmi_get_protected_mode_interrupt_vector(vector, &OldInt); \ 41 | \ 42 | NewInt.pm_selector = _go32_my_cs(); \ 43 | NewInt.pm_offset = (int32_t)handler; \ 44 | _go32_dpmi_allocate_iret_wrapper(&NewInt); \ 45 | _go32_dpmi_set_protected_mode_interrupt_vector(vector, &NewInt) 46 | 47 | #define restoreInterrupt(vector,OldInt,NewInt) \ 48 | _go32_dpmi_set_protected_mode_interrupt_vector(vector, &OldInt); \ 49 | _go32_dpmi_free_iret_wrapper(&NewInt) 50 | 51 | #define _chain_intr(OldInt) \ 52 | asm \ 53 | ( \ 54 | "cli \n" \ 55 | "pushfl \n" \ 56 | "lcall *%0" \ 57 | : \ 58 | : "m" (OldInt.pm_offset) \ 59 | ) 60 | 61 | 62 | 63 | #elif defined __DMC__ 64 | //Digital Mars 65 | #include 66 | #define int386 int86 67 | #define __djgpp_conventional_base ((int32_t)_x386_zero_base_ptr) 68 | #define __attribute__(x) 69 | #define _Noreturn /* see #pragma noreturn(identifier) */ 70 | 71 | #define replaceInterrupt(OldInt,NewInt,vector,handler) int_intercept(vector,handler,0) 72 | 73 | #define restoreInterrupt(vector,OldInt,NewInt) int_restore(vector) 74 | 75 | #define _chain_intr(OldInt) return(0) 76 | 77 | 78 | 79 | #elif defined __CCDL__ 80 | //CC386 81 | #include 82 | #include 83 | 84 | #define int386 _int386 85 | #define __djgpp_conventional_base 0 86 | #define __attribute__(x) 87 | #define _Noreturn 88 | 89 | typedef struct 90 | { 91 | uint32_t pm_offset; 92 | uint16_t pm_selector; 93 | } _go32_dpmi_seginfo; 94 | 95 | #define replaceInterrupt(OldInt,NewInt,vector,handler) \ 96 | { \ 97 | struct SREGS segregs; \ 98 | \ 99 | _segread(&segregs); \ 100 | dpmi_get_protected_interrupt(&OldInt.pm_selector, &OldInt.pm_offset, vector); \ 101 | dpmi_set_protected_interrupt(vector, segregs.cs, (uint32_t)handler); \ 102 | } 103 | 104 | #define restoreInterrupt(vector,OldInt,NewInt) dpmi_set_protected_interrupt(vector,OldInt.pm_selector,OldInt.pm_offset) 105 | 106 | //TODO call OldInt() instead of acknowledging the interrupt 107 | #define _chain_intr(OldInt) \ 108 | outp(0x20,0x20); \ 109 | return 110 | 111 | 112 | 113 | #elif defined __WATCOMC__ 114 | //Watcom 115 | #define __djgpp_conventional_base 0 116 | #define __attribute__(x) 117 | #define _Noreturn __declspec(aborts) 118 | 119 | #define replaceInterrupt(OldInt,NewInt,vector,handler) \ 120 | OldInt = _dos_getvect(vector); \ 121 | _dos_setvect(vector, handler) 122 | 123 | #define restoreInterrupt(vector,OldInt,NewInt) _dos_setvect(vector,OldInt) 124 | 125 | typedef union { 126 | struct { 127 | uint32_t edi, esi, ebp, reserved, ebx, edx, ecx, eax; 128 | } d; 129 | struct { 130 | uint16_t di, di_hi; 131 | uint16_t si, si_hi; 132 | uint16_t bp, bp_hi; 133 | uint16_t res, res_hi; 134 | uint16_t bx, bx_hi; 135 | uint16_t dx, dx_hi; 136 | uint16_t cx, cx_hi; 137 | uint16_t ax, ax_hi; 138 | uint16_t flags, es, ds, fs, gs, ip, cs, sp, ss; 139 | } x; 140 | } __dpmi_regs; 141 | 142 | typedef struct { 143 | uint32_t largest_available_free_block_in_bytes; 144 | uint32_t maximum_unlocked_page_allocation_in_pages; 145 | uint32_t maximum_locked_page_allocation_in_pages; 146 | uint32_t linear_address_space_size_in_pages; 147 | uint32_t total_number_of_unlocked_pages; 148 | uint32_t total_number_of_free_pages; 149 | uint32_t total_number_of_physical_pages; 150 | uint32_t free_linear_address_space_in_pages; 151 | uint32_t size_of_paging_file_partition_in_pages; 152 | uint32_t reserved[3]; 153 | } __dpmi_free_mem_info; 154 | 155 | #if !defined C_ONLY 156 | #pragma aux FixedMul = \ 157 | "imul ecx", \ 158 | "shrd eax, edx, 16" \ 159 | value [eax] \ 160 | parm [eax] [ecx] \ 161 | modify [edx] 162 | 163 | typedef int32_t fixed_t; 164 | fixed_t FixedDiv2 (fixed_t a, fixed_t b); 165 | #pragma aux FixedDiv2 = \ 166 | "cdq", \ 167 | "shld edx, eax, 16", \ 168 | "shl eax, 16", \ 169 | "idiv ecx" \ 170 | value [eax] \ 171 | parm [eax] [ecx] \ 172 | modify [edx] 173 | #endif 174 | 175 | 176 | 177 | #endif 178 | 179 | #endif 180 | -------------------------------------------------------------------------------- /compoc.bat: -------------------------------------------------------------------------------- 1 | if "%LADSOFT%" == "" goto error 2 | 3 | mkdir OCDM19 4 | 5 | nasm a_mv_mix.asm -f obj 6 | nasm planar.asm -f obj 7 | 8 | set GLOBOBJS=dmx.c a_al_mid.c a_blast.c a_dma.c a_ll_man.c a_midi.c a_mpu401.c a_multiv.c a_music.c a_musmid.c a_mv_mix.obj a_pcfx.c a_taskmn.c a_tsmapi.c i_main.c i_ibm.c i_sound.c planar.obj tables.c f_finale.c d_main.c d_net.c g_game.c m_menu.c m_misc.c am_map.c p_ceilng.c p_doors.c p_enemy.c p_floor.c p_inter.c p_lights.c p_map.c p_maputl.c p_plats.c p_pspr.c p_setup.c p_sight.c p_spec.c p_switch.c p_mobj.c p_telept.c p_tick.c p_user.c r_bsp.c r_data.c r_draw.c r_main.c r_plane.c r_segs.c r_things.c w_wad.c wi_stuff.c v_video.c st_lib.c st_stuff.c hu_stuff.c hu_lib.c s_sound.c z_zone.c info.c sounds.c dutils.c 9 | cc386 %GLOBOBJS% /Wa /DAPPVER_EXEDEF=DM19 /oOCDM19\ocdoom.exe 10 | 11 | del *.obj 12 | 13 | goto end 14 | 15 | :error 16 | @echo Set the environment variables before running this script! 17 | 18 | :end 19 | -------------------------------------------------------------------------------- /compwc.bat: -------------------------------------------------------------------------------- 1 | if "%WATCOM%" == "" goto error 2 | 3 | mkdir WCDM19 4 | wmake -f makefile.wc WCDM19\wcdoom.exe 5 | del *.err 6 | goto end 7 | 8 | :error 9 | @echo Set the environment variables before running this script! 10 | 11 | :end 12 | -------------------------------------------------------------------------------- /dmx.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2005-2014 Simon Howard 3 | // Copyright (C) 2015-2017 Alexey Khokholov (Nuke.YKT) 4 | // Copyright (C) 2023-2025 Frenkel Smeijers 5 | // 6 | // This program is free software; you can redistribute it and/or 7 | // modify it under the terms of the GNU General Public License 8 | // as published by the Free Software Foundation; either version 2 9 | // of the License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | 20 | #include "id_heads.h" 21 | #include "dmx.h" 22 | #include "a_al_mid.h" 23 | #include "a_blast.h" 24 | #include "a_mpu401.h" 25 | #include "a_multiv.h" 26 | #include "a_music.h" 27 | #include "a_pcfx.h" 28 | 29 | static BLASTER_CONFIG dmx_blaster; 30 | 31 | static void *mus_data = NULL; 32 | static uint8_t *mid_data = NULL; 33 | 34 | static int32_t mus_loop = 0; 35 | static int32_t dmx_mus_port = 0; 36 | static int32_t dmx_sdev = AHW_NONE; 37 | static int32_t dmx_mdev = AHW_NONE; 38 | static int32_t mus_rate = 140; 39 | static int32_t mus_mastervolume = 127; 40 | 41 | void MUS_PauseSong(int32_t handle) 42 | { 43 | UNUSED(handle); 44 | MUSIC_Pause(); 45 | } 46 | 47 | void MUS_ResumeSong(int32_t handle) 48 | { 49 | UNUSED(handle); 50 | MUSIC_Continue(); 51 | } 52 | 53 | void MUS_SetMasterVolume(int32_t volume) 54 | { 55 | mus_mastervolume = volume; 56 | MUSIC_SetVolume(volume * 2); 57 | } 58 | 59 | int32_t MUS_RegisterSong(uint8_t *data) 60 | { 61 | FILE *mus; 62 | FILE *mid; 63 | uint32_t midlen; 64 | uint16_t len = ((uint16_t*)data)[2] + ((uint16_t*)data)[3]; 65 | extern boolean mus2mid(FILE *musinput, FILE *midioutput, int32_t rate, boolean adlibhack); 66 | 67 | mus_data = NULL; 68 | 69 | if (mid_data) 70 | free(mid_data); 71 | 72 | if (memcmp(data, "MThd", 4)) 73 | { 74 | mus = fopen("temp.mus", "wb"); 75 | if (!mus) 76 | return 0; 77 | 78 | fwrite(data, 1, len, mus); 79 | fclose(mus); 80 | mus = fopen("temp.mus", "rb"); 81 | if (!mus) 82 | return 0; 83 | 84 | mid = fopen("temp.mid", "wb"); 85 | if (!mid) 86 | { 87 | fclose(mus); 88 | return 0; 89 | } 90 | if (mus2mid(mus, mid, mus_rate, dmx_mdev == AHW_ADLIB)) 91 | { 92 | fclose(mid); 93 | fclose(mus); 94 | return 0; 95 | } 96 | fclose(mid); 97 | fclose(mus); 98 | mid = fopen("temp.mid", "rb"); 99 | if (!mid) 100 | return 0; 101 | 102 | fseek(mid, 0, SEEK_END); 103 | midlen = ftell(mid); 104 | rewind(mid); 105 | mid_data = malloc(midlen); 106 | if (!mid_data) 107 | { 108 | fclose(mid); 109 | return 0; 110 | } 111 | fread(mid_data, 1, midlen, mid); 112 | fclose(mid); 113 | mus_data = mid_data; 114 | remove("temp.mid"); 115 | remove("temp.mus"); 116 | } else { 117 | mus_data = data; 118 | } 119 | 120 | return 0; 121 | } 122 | 123 | void MUS_UnregisterSong(int32_t handle) {UNUSED(handle);} 124 | 125 | void MUS_StopSong(int32_t handle) 126 | { 127 | UNUSED(handle); 128 | MUSIC_StopSong(); 129 | } 130 | 131 | void MUS_ChainSong(int32_t handle, int32_t to) 132 | { 133 | mus_loop = (to == handle); 134 | } 135 | 136 | void MUS_PlaySong(int32_t handle, int32_t volume) 137 | { 138 | int32_t status; 139 | 140 | UNUSED(handle); 141 | UNUSED(volume); 142 | 143 | if (mus_data == NULL) 144 | return; 145 | 146 | status = MUSIC_PlaySong((uint8_t*)mus_data, mus_loop); 147 | if (status == MUSIC_Ok) 148 | MUSIC_SetVolume(mus_mastervolume * 2); 149 | } 150 | 151 | 152 | int32_t SFX_PlayPatch(void *data, int32_t pitch, int32_t sep, int32_t volume, int32_t flags, int32_t priority) 153 | { 154 | uint16_t type = ((uint16_t*)data)[0]; 155 | 156 | UNUSED(flags); 157 | 158 | if (type == 0) 159 | return PCFX_Play(data); 160 | else if (type == 3) 161 | { 162 | uint16_t rate = ((uint16_t*)data)[1]; 163 | uint32_t length = ((uint32_t*)data)[1]; 164 | 165 | length -= 32; // 16 pre pad bytes + 16 post pad bytes 166 | return MV_PlayRaw((uint8_t*)data + 0x18, length, rate, ((pitch - 128) * 2400) / 128, volume * 2, ((254 - sep) * volume) / 63, ((sep) * volume) / 63, 127 - priority); 167 | } 168 | else 169 | return -1; 170 | } 171 | 172 | void SFX_StopPatch(int32_t handle) 173 | { 174 | if (dmx_sdev == AHW_PC_SPEAKER) 175 | PCFX_Stop(handle); 176 | else if (dmx_sdev == AHW_SOUND_BLASTER) 177 | MV_Kill(handle); 178 | } 179 | 180 | int32_t SFX_Playing(int32_t handle) 181 | { 182 | if (dmx_sdev == AHW_PC_SPEAKER) 183 | return PCFX_SoundPlaying(handle); 184 | else if (dmx_sdev == AHW_SOUND_BLASTER) 185 | return MV_VoicePlaying(handle); 186 | else 187 | return false; 188 | } 189 | 190 | void SFX_SetOrigin(int32_t handle, int32_t pitch, int32_t sep, int32_t volume) 191 | { 192 | if (dmx_sdev == AHW_SOUND_BLASTER) 193 | MV_SetOrigin(handle, ((pitch - 128) * 2400) / 128, volume * 2, ((254 - sep) * volume) / 63, ((sep) * volume) / 63); 194 | } 195 | 196 | 197 | int32_t ENS_Detect(void) {return -1;} 198 | int32_t CODEC_Detect(int32_t *sbPort, int32_t *sbDma) {UNUSED(sbPort); UNUSED(sbDma); return -1;} 199 | int32_t GF1_Detect(void) {return -1;} 200 | void GF1_SetMap(uint8_t *dmxlump, int32_t size) {UNUSED(dmxlump); UNUSED(size);} 201 | 202 | 203 | int32_t SB_Detect(int32_t *sbPort, int32_t *sbIrq, int32_t *sbDma, uint16_t *dspVersion) 204 | { 205 | int32_t sbDma16; 206 | 207 | UNUSED(dspVersion); 208 | 209 | BLASTER_GetEnv(sbPort, sbIrq, sbDma, &sbDma16); 210 | dmx_blaster.Address = *sbPort; 211 | dmx_blaster.Interrupt = *sbIrq; 212 | dmx_blaster.Dma8 = *sbDma; 213 | dmx_blaster.Dma16 = sbDma16; 214 | 215 | return 0; 216 | } 217 | 218 | void SB_SetCard(int32_t iBaseAddr, int32_t iIrq, int32_t iDma) 219 | { 220 | UNUSED(iBaseAddr); 221 | UNUSED(iIrq); 222 | UNUSED(iDma); 223 | 224 | BLASTER_SetCardSettings(dmx_blaster); 225 | } 226 | 227 | 228 | int32_t AL_Detect(int32_t *wait, int32_t *type) 229 | { 230 | UNUSED(wait); 231 | UNUSED(type); 232 | return !AL_DetectFM(); 233 | } 234 | 235 | void AL_SetCard(int32_t wait, void *data) 236 | { 237 | uint8_t *cdata; 238 | uint8_t *tmb; 239 | int32_t i; 240 | 241 | UNUSED(wait); 242 | 243 | cdata = (uint8_t *)data; 244 | tmb = malloc(13 * 256); 245 | if (!tmb) 246 | return; 247 | 248 | memset(tmb, 0, 13 * 256); 249 | for (i = 0; i < 128; i++) 250 | { 251 | tmb[i * 13 + 0] = cdata[8 + i * 36 + 4 + 0]; 252 | tmb[i * 13 + 1] = cdata[8 + i * 36 + 4 + 7]; 253 | tmb[i * 13 + 2] = cdata[8 + i * 36 + 4 + 4] 254 | | cdata[8 + i * 36 + 4 + 5]; 255 | tmb[i * 13 + 3] = cdata[8 + i * 36 + 4 + 11] & 192; 256 | tmb[i * 13 + 4] = cdata[8 + i * 36 + 4 + 1]; 257 | tmb[i * 13 + 5] = cdata[8 + i * 36 + 4 + 8]; 258 | tmb[i * 13 + 6] = cdata[8 + i * 36 + 4 + 2]; 259 | tmb[i * 13 + 7] = cdata[8 + i * 36 + 4 + 9]; 260 | tmb[i * 13 + 8] = cdata[8 + i * 36 + 4 + 3]; 261 | tmb[i * 13 + 9] = cdata[8 + i * 36 + 4 + 10]; 262 | tmb[i * 13 + 10] = cdata[8 + i * 36 + 4 + 6]; 263 | tmb[i * 13 + 11] = cdata[8 + i * 36 + 4 + 14] + 12; 264 | tmb[i * 13 + 12] = 0; 265 | } 266 | for (i = 128; i < 175; i++) 267 | { 268 | tmb[(i + 35) * 13 + 0] = cdata[8 + i * 36 + 4 + 0]; 269 | tmb[(i + 35) * 13 + 1] = cdata[8 + i * 36 + 4 + 7]; 270 | tmb[(i + 35) * 13 + 2] = cdata[8 + i * 36 + 4 + 4] 271 | | cdata[8 + i * 36 + 4 + 5]; 272 | tmb[(i + 35) * 13 + 3] = cdata[8 + i * 36 + 4 + 11] & 192; 273 | tmb[(i + 35) * 13 + 4] = cdata[8 + i * 36 + 4 + 1]; 274 | tmb[(i + 35) * 13 + 5] = cdata[8 + i * 36 + 4 + 8]; 275 | tmb[(i + 35) * 13 + 6] = cdata[8 + i * 36 + 4 + 2]; 276 | tmb[(i + 35) * 13 + 7] = cdata[8 + i * 36 + 4 + 9]; 277 | tmb[(i + 35) * 13 + 8] = cdata[8 + i * 36 + 4 + 3]; 278 | tmb[(i + 35) * 13 + 9] = cdata[8 + i * 36 + 4 + 10]; 279 | tmb[(i + 35) * 13 + 10] = cdata[8 + i * 36 + 4 + 6]; 280 | tmb[(i + 35) * 13 + 11] = cdata[8 + i * 36 + 3] 281 | + cdata[8 + i * 36 + 4 + 14] + 12; 282 | tmb[(i + 35) * 13 + 12] = 0; 283 | } 284 | AL_RegisterTimbreBank(tmb); 285 | free(tmb); 286 | } 287 | 288 | 289 | int32_t MPU_Detect(int32_t *mPort, int32_t *type) 290 | { 291 | UNUSED(type); 292 | 293 | if (mPort == NULL) 294 | return -1; 295 | else 296 | return MPU_Init(*mPort); 297 | } 298 | 299 | void MPU_SetCard(int32_t mPort) 300 | { 301 | dmx_mus_port = mPort; 302 | } 303 | 304 | 305 | int32_t DMX_Init(int32_t ticrate, int32_t maxsongs, uint32_t musicDevice, uint32_t sfxDevice) 306 | { 307 | UNUSED(maxsongs); 308 | 309 | // Sound effects 310 | dmx_sdev = sfxDevice; 311 | 312 | if (dmx_sdev == AHW_PC_SPEAKER) 313 | PCFX_Init(ticrate); 314 | else if (dmx_sdev == AHW_SOUND_BLASTER) 315 | BLASTER_Init(); 316 | 317 | 318 | // Music 319 | mus_rate = ticrate; 320 | dmx_mdev = musicDevice; 321 | 322 | if (dmx_mdev == AHW_ADLIB || dmx_mdev == AHW_MPU_401) 323 | { 324 | int32_t status = MUSIC_Init(dmx_mdev, dmx_mus_port); 325 | if (status == MUSIC_Ok) 326 | MUSIC_SetVolume(0); 327 | } 328 | 329 | return musicDevice | sfxDevice; 330 | } 331 | 332 | void DMX_DeInit(void) 333 | { 334 | MUSIC_Shutdown(); 335 | 336 | if (dmx_sdev == AHW_PC_SPEAKER) 337 | PCFX_Shutdown(); 338 | else if (dmx_sdev == AHW_SOUND_BLASTER) 339 | MV_Shutdown(); 340 | 341 | if (mid_data) 342 | free(mid_data); 343 | } 344 | 345 | 346 | void WAV_PlayMode(int32_t channels, uint16_t sampleRate) 347 | { 348 | if (dmx_sdev == AHW_SOUND_BLASTER) 349 | MV_Init(dmx_sdev, sampleRate, channels); 350 | } 351 | -------------------------------------------------------------------------------- /dmx.h: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // Copyright (C) 2023 Frenkel Smeijers 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | 19 | #ifndef _DMX_H_ 20 | #define _DMX_H_ 21 | 22 | #include "a_tsmapi.h" 23 | 24 | void MUS_PauseSong(int32_t handle); 25 | void MUS_ResumeSong(int32_t handle); 26 | void MUS_SetMasterVolume(int32_t volume); 27 | int32_t MUS_RegisterSong(uint8_t *data); 28 | void MUS_UnregisterSong(int32_t handle); 29 | void MUS_StopSong(int32_t handle); 30 | void MUS_ChainSong(int32_t handle, int32_t to); 31 | void MUS_PlaySong(int32_t handle, int32_t volume); 32 | 33 | int32_t SFX_PlayPatch(void *data, int32_t pitch, int32_t sep, int32_t volume, int32_t flags, int32_t priority); 34 | void SFX_StopPatch(int32_t handle); 35 | int32_t SFX_Playing(int32_t handle); 36 | void SFX_SetOrigin(int32_t handle, int32_t pitch, int32_t sep, int32_t volume); 37 | 38 | int32_t ENS_Detect(void); 39 | int32_t CODEC_Detect(int32_t *sbPort, int32_t *sbDma); 40 | int32_t GF1_Detect(void); 41 | void GF1_SetMap(uint8_t *dmxlump, int32_t size); 42 | int32_t SB_Detect(int32_t *sbPort, int32_t *sbIrq, int32_t *sbDma, uint16_t *dspVersion); 43 | void SB_SetCard(int32_t iBaseAddr, int32_t iIrq, int32_t iDma); 44 | int32_t AL_Detect(int32_t *wait, int32_t *type); 45 | void AL_SetCard(int32_t wait, void *genmidi); 46 | int32_t MPU_Detect(int32_t *mPort, int32_t *type); 47 | void MPU_SetCard(int32_t mPort); 48 | 49 | #define AHW_NONE 0x0000L 50 | #define AHW_PC_SPEAKER 0x0001L 51 | #define AHW_ADLIB 0x0002L 52 | #define AHW_AWE32 0x0004L 53 | #define AHW_SOUND_BLASTER 0x0008L 54 | #define AHW_MPU_401 0x0010L 55 | #define AHW_ULTRA_SOUND 0x0020L 56 | #define AHW_MEDIA_VISION 0x0040L 57 | 58 | #define AHW_ENSONIQ 0x0100L 59 | #define AHW_CODEC 0x0200L 60 | 61 | int32_t DMX_Init(int32_t ticrate, int32_t maxsongs, uint32_t musicDevice, uint32_t sfxDevice); 62 | void DMX_DeInit(void); 63 | 64 | void WAV_PlayMode(int32_t channels, uint16_t sampleRate); 65 | #endif 66 | -------------------------------------------------------------------------------- /doomdata.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 1993-1996 Id Software, Inc. 3 | // Copyright (C) 2023 Frenkel Smeijers 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | 19 | // DoomData.h 20 | 21 | // all external data is defined here 22 | // most of the data is loaded into different structures at run time 23 | 24 | #ifndef __DOOMDATA__ 25 | #define __DOOMDATA__ 26 | 27 | /* 28 | =============================================================================== 29 | 30 | map level types 31 | 32 | =============================================================================== 33 | */ 34 | 35 | // lump order in a map wad 36 | enum {ML_LABEL, ML_THINGS, ML_LINEDEFS, ML_SIDEDEFS, ML_VERTEXES, ML_SEGS, 37 | ML_SSECTORS, ML_NODES, ML_SECTORS , ML_REJECT, ML_BLOCKMAP}; 38 | 39 | 40 | typedef struct 41 | { 42 | int16_t x,y; 43 | } mapvertex_t; 44 | 45 | typedef struct 46 | { 47 | int16_t textureoffset; 48 | int16_t rowoffset; 49 | char toptexture[8], bottomtexture[8], midtexture[8]; 50 | int16_t sector; // on viewer's side 51 | } mapsidedef_t; 52 | 53 | typedef struct 54 | { 55 | int16_t v1, v2; 56 | int16_t flags; 57 | int16_t special, tag; 58 | int16_t sidenum[2]; // sidenum[1] will be -1 if one sided 59 | } maplinedef_t; 60 | 61 | #define ML_BLOCKING 1 62 | #define ML_BLOCKMONSTERS 2 63 | #define ML_TWOSIDED 4 // backside will not be present at all 64 | // if not two sided 65 | 66 | // if a texture is pegged, the texture will have the end exposed to air held 67 | // constant at the top or bottom of the texture (stairs or pulled down things) 68 | // and will move with a height change of one of the neighbor sectors 69 | // Unpegged textures allways have the first row of the texture at the top 70 | // pixel of the line for both top and bottom textures (windows) 71 | #define ML_DONTPEGTOP 8 72 | #define ML_DONTPEGBOTTOM 16 73 | 74 | #define ML_SECRET 32 // don't map as two sided: IT'S A SECRET! 75 | #define ML_SOUNDBLOCK 64 // don't let sound cross two of these 76 | #define ML_DONTDRAW 128 // don't draw on the automap 77 | #define ML_MAPPED 256 // set if allready drawn in automap 78 | 79 | 80 | typedef struct 81 | { 82 | int16_t floorheight, ceilingheight; 83 | char floorpic[8], ceilingpic[8]; 84 | int16_t lightlevel; 85 | int16_t special, tag; 86 | } mapsector_t; 87 | 88 | typedef struct 89 | { 90 | int16_t numsegs; 91 | int16_t firstseg; // segs are stored sequentially 92 | } mapsubsector_t; 93 | 94 | typedef struct 95 | { 96 | int16_t v1, v2; 97 | int16_t angle; 98 | int16_t linedef, side; 99 | int16_t offset; 100 | } mapseg_t; 101 | 102 | enum {BOXTOP,BOXBOTTOM,BOXLEFT,BOXRIGHT}; // bbox coordinates 103 | 104 | #define NF_SUBSECTOR 0x8000 105 | typedef struct 106 | { 107 | int16_t x,y,dx,dy; // partition line 108 | int16_t bbox[2][4]; // bounding box for each child 109 | uint16_t children[2]; // if NF_SUBSECTOR its a subsector 110 | } mapnode_t; 111 | 112 | typedef struct 113 | { 114 | int16_t x,y; 115 | int16_t angle; 116 | int16_t type; 117 | int16_t options; 118 | } mapthing_t; 119 | 120 | #define MTF_EASY 1 121 | #define MTF_NORMAL 2 122 | #define MTF_HARD 4 123 | #define MTF_AMBUSH 8 124 | 125 | /* 126 | =============================================================================== 127 | 128 | texture definition 129 | 130 | =============================================================================== 131 | */ 132 | 133 | typedef struct 134 | { 135 | int16_t originx; 136 | int16_t originy; 137 | int16_t patch; 138 | int16_t stepdir; 139 | int16_t colormap; 140 | } mappatch_t; 141 | 142 | typedef struct 143 | { 144 | char name[8]; 145 | boolean masked; 146 | int16_t width; 147 | int16_t height; 148 | void **columndirectory; // OBSOLETE 149 | int16_t patchcount; 150 | mappatch_t patches[1]; 151 | } maptexture_t; 152 | 153 | 154 | /* 155 | =============================================================================== 156 | 157 | graphics 158 | 159 | =============================================================================== 160 | */ 161 | 162 | // posts are runs of non masked source pixels 163 | typedef struct 164 | { 165 | byte topdelta; // -1 is the last post in a column 166 | byte length; 167 | // length data bytes follows 168 | } post_t; 169 | 170 | // column_t is a list of 0 or more post_t, (byte)-1 terminated 171 | typedef post_t column_t; 172 | 173 | // a patch holds one or more columns 174 | // patches are used for sprites and all masked pictures 175 | typedef struct 176 | { 177 | int16_t width; // bounding box size 178 | int16_t height; 179 | int16_t leftoffset; // pixels to the left of origin 180 | int16_t topoffset; // pixels below the origin 181 | int32_t columnofs[8]; // only [width] used 182 | // the [0] is &columnofs[width] 183 | } patch_t; 184 | 185 | // a pic is an unmasked block of pixels 186 | typedef struct 187 | { 188 | byte width,height; 189 | byte data; 190 | } pic_t; 191 | 192 | 193 | 194 | 195 | /* 196 | =============================================================================== 197 | 198 | status 199 | 200 | =============================================================================== 201 | */ 202 | 203 | 204 | 205 | 206 | #endif // __DOOMDATA__ 207 | 208 | -------------------------------------------------------------------------------- /dutils.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 1993-1996 Id Software, Inc. 3 | // Copyright (C) 2023 Frenkel Smeijers 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | 19 | // DUtils.c 20 | #include "doomdef.h" 21 | #include "dutils.h" 22 | 23 | // 24 | // CHEAT SEQUENCE PACKAGE 25 | // 26 | 27 | static boolean firsttime = true; 28 | static uint8_t cheat_xlate_table[256]; 29 | 30 | 31 | // 32 | // Called in st_stuff module, which handles the input. 33 | // Returns true if the cheat was successful, false if failed. 34 | // 35 | boolean cht_CheckCheat(cheatseq_t *cht, char key) 36 | { 37 | int32_t i; 38 | boolean rc = false; 39 | 40 | if (firsttime) 41 | { 42 | firsttime = false; 43 | for (i=0;i<256;i++) cheat_xlate_table[i] = SCRAMBLE(i); 44 | } 45 | 46 | if (!cht->p) 47 | cht->p = cht->sequence; // initialize if first time 48 | 49 | if (*cht->p == 0) 50 | *(cht->p++) = key; 51 | else if 52 | (cheat_xlate_table[(uint8_t)key] == *cht->p) cht->p++; 53 | else 54 | cht->p = cht->sequence; 55 | 56 | if (*cht->p == 1) 57 | cht->p++; 58 | else if (*cht->p == 0xff) // end of sequence character 59 | { 60 | cht->p = cht->sequence; 61 | rc = true; 62 | } 63 | 64 | return rc; 65 | } 66 | 67 | void cht_GetParam(cheatseq_t *cht, char *buffer) 68 | { 69 | uint8_t *p, c; 70 | 71 | p = cht->sequence; 72 | while (*(p++) != 1) 73 | { 74 | } 75 | 76 | do 77 | { 78 | c = *p; 79 | *(buffer++) = c; 80 | *(p++) = 0; 81 | } 82 | while (c && *p!=0xff ); 83 | 84 | if (*p==0xff) 85 | *buffer = 0; 86 | } 87 | 88 | // 89 | // SCREEN WIPE PACKAGE 90 | // 91 | 92 | // when false, stop the wipe 93 | static boolean go = false; 94 | 95 | static byte *wipe_scr_start, *wipe_scr_end, *wipe_scr; 96 | 97 | 98 | static void wipe_shittyColMajorXform(int16_t *array) 99 | { 100 | int32_t x, y; 101 | int16_t *dest; 102 | 103 | dest = (int16_t*) Z_Malloc(SCREENWIDTH*SCREENHEIGHT, PU_STATIC, 0); 104 | 105 | for(y=0;y not ready to scroll yet) 128 | y = (int32_t *) Z_Malloc(SCREENWIDTH*sizeof(int32_t), PU_STATIC, 0); 129 | y[0] = -(M_Random()%16); 130 | for (i=1;i 0) y[i] = 0; 135 | else if (y[i] == -16) y[i] = -15; 136 | } 137 | } 138 | 139 | static boolean wipe_doMelt(int32_t ticks) 140 | { 141 | int32_t i, j, dy, idx; 142 | int16_t *s, *d; 143 | boolean done = true; 144 | 145 | while (ticks--) 146 | { 147 | for (i=0;i= SCREENHEIGHT) dy = SCREENHEIGHT - y[i]; 157 | s = &((int16_t *)wipe_scr_end)[i*SCREENHEIGHT+y[i]]; 158 | d = &((int16_t *)wipe_scr)[y[i]*SCREENWIDTH/2+i]; 159 | idx = 0; 160 | for (j=dy;j;j--) 161 | { 162 | d[idx] = *(s++); 163 | idx += SCREENWIDTH/2; 164 | } 165 | y[i] += dy; 166 | s = &((int16_t *)wipe_scr_start)[i*SCREENHEIGHT]; 167 | d = &((int16_t *)wipe_scr)[y[i]*SCREENWIDTH/2+i]; 168 | idx = 0; 169 | for (j=SCREENHEIGHT-y[i];j;j--) 170 | { 171 | d[idx] = *(s++); 172 | idx += SCREENWIDTH/2; 173 | } 174 | done = false; 175 | } 176 | } 177 | } 178 | 179 | return done; 180 | } 181 | 182 | void wipe_StartScreen(void) 183 | { 184 | wipe_scr_start = screens[2]; 185 | I_ReadScreen(wipe_scr_start); 186 | } 187 | 188 | void wipe_EndScreen(void) 189 | { 190 | wipe_scr_end = screens[3]; 191 | I_ReadScreen(wipe_scr_end); 192 | V_DrawBlock(wipe_scr_start); // restore start scr. 193 | } 194 | 195 | boolean wipe_ScreenWipe(int32_t ticks) 196 | { 197 | boolean rc; 198 | 199 | void V_MarkRect(int32_t, int32_t, int32_t, int32_t); 200 | 201 | // initial stuff 202 | if (!go) 203 | { 204 | go = true; 205 | wipe_scr = screens[0]; 206 | wipe_initMelt(); 207 | } 208 | 209 | // do a piece of wipe-in 210 | V_MarkRect(0, 0, SCREENWIDTH, SCREENHEIGHT); 211 | rc = wipe_doMelt(ticks); 212 | 213 | // final stuff 214 | if (rc) 215 | { 216 | go = false; 217 | Z_Free(y); 218 | } 219 | 220 | return !go; 221 | } 222 | -------------------------------------------------------------------------------- /dutils.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 1993-1996 Id Software, Inc. 3 | // Copyright (C) 2023 Frenkel Smeijers 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | 19 | #ifndef __DUTILSH__ 20 | #define __DUTILSH__ 21 | 22 | // 23 | // CHEAT SEQUENCE PACKAGE 24 | // 25 | 26 | #define SCRAMBLE(a) ((((a)&1)<<7) + (((a)&2)<<5) + ((a)&4) + (((a)&8)<<1) \ 27 | + (((a)&16)>>1) + ((a)&32) + (((a)&64)>>5) + (((a)&128)>>7)) 28 | 29 | typedef struct 30 | { 31 | uint8_t *sequence, *p; 32 | } cheatseq_t; 33 | 34 | boolean cht_CheckCheat(cheatseq_t *cht, char key); 35 | void cht_GetParam(cheatseq_t *cht, char *buffer); 36 | 37 | // 38 | // SCREEN WIPE PACKAGE 39 | // 40 | 41 | void wipe_StartScreen(void); 42 | void wipe_EndScreen(void); 43 | boolean wipe_ScreenWipe(int32_t ticks); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /gamever.h: -------------------------------------------------------------------------------- 1 | // *** VERSIONS RESTORATION *** 2 | #ifndef GAMEVER_H 3 | #define GAMEVER_H 4 | 5 | // It is assumed here that: 6 | // 1. The compiler is set up to appropriately define APPVER_EXEDEF 7 | // as an EXE identifier. 8 | // 2. This header is included (near) the beginning of every compilation unit, 9 | // in order to have an impact in any place where it's expected to. 10 | 11 | // APPVER_DOOMREV definitions 12 | #define AV_DR_DM1666P 199408250 13 | #define AV_DR_DM1666E 199408300 14 | #define AV_DR_DM1666 199409010 15 | #define AV_DR_DM17 199409210 16 | #define AV_DR_DM17A 199410180 17 | #define AV_DR_DM18FR 199412010 18 | #define AV_DR_DM18 199501200 19 | #define AV_DR_DM19 199502010 20 | #define AV_DR_DM19UP 199503280 21 | #define AV_DR_DM19U 199505250 22 | #define AV_DR_DM19F 199606100 23 | #define AV_DR_DM19F2 199610090 24 | #define AV_DR_CHEX 199610310 25 | 26 | // Now define APPVER_DOOMREV to one of the above, based on APPVER_EXEDEF 27 | 28 | #define APPVER_CONCAT1(x,y) x ## y 29 | #define APPVER_CONCAT2(x,y) APPVER_CONCAT1(x,y) 30 | #define APPVER_DOOMREV APPVER_CONCAT2(AV_DR_,APPVER_EXEDEF) 31 | 32 | // Convenience macro 33 | #if (APPVER_DOOMREV == AV_DR_CHEX) 34 | #define APPVER_CHEX 1 35 | #endif 36 | 37 | #endif // GAMEVER_H 38 | -------------------------------------------------------------------------------- /hu_lib.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 1993-1996 Id Software, Inc. 3 | // Copyright (C) 2023 Frenkel Smeijers 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | 19 | // HU_lib.c 20 | #include 21 | #include "doomdef.h" 22 | #include "r_local.h" 23 | #include "hu_lib.h" 24 | 25 | // boolean : whether the screen is always erased 26 | #define noterased viewwindowx 27 | 28 | extern boolean automapactive; // in AM_map.c 29 | 30 | // clear a line of text 31 | static void HUlib_clearTextLine(hu_textline_t *t) 32 | { 33 | t->len = 0; 34 | t->l[0] = 0; 35 | t->needsupdate = true; 36 | } 37 | 38 | void HUlib_initTextLine(hu_textline_t *t, int32_t x, int32_t y, patch_t **f, int32_t sc) 39 | { 40 | t->x = x; 41 | t->y = y; 42 | t->f = f; 43 | t->sc = sc; 44 | HUlib_clearTextLine(t); 45 | } 46 | 47 | void HUlib_addCharToTextLine(hu_textline_t *t, char ch) 48 | { 49 | 50 | if (t->len != HU_MAXLINELENGTH) 51 | { 52 | t->l[t->len++] = ch; 53 | t->l[t->len] = 0; 54 | t->needsupdate = 4; 55 | } 56 | 57 | } 58 | 59 | static void HUlib_delCharFromTextLine(hu_textline_t *t) 60 | { 61 | 62 | if (t->len) 63 | { 64 | t->l[--t->len] = 0; 65 | t->needsupdate = 4; 66 | } 67 | 68 | } 69 | 70 | void HUlib_drawTextLine(hu_textline_t *l, boolean drawcursor) 71 | { 72 | 73 | int32_t i, w, x; 74 | uint8_t c; 75 | 76 | // draw the new stuff 77 | x = l->x; 78 | for (i=0;ilen;i++) 79 | { 80 | c = toupper(l->l[i]); 81 | if (c != ' ' && c >= l->sc && c <= '_') 82 | { 83 | w = SHORT(l->f[c - l->sc]->width); 84 | if (x+w > SCREENWIDTH) 85 | break; 86 | V_DrawPatchDirect(x, l->y, l->f[c - l->sc]); 87 | x += w; 88 | } 89 | else 90 | { 91 | x += 4; 92 | if (x >= SCREENWIDTH) 93 | break; 94 | } 95 | } 96 | 97 | // draw the cursor if requested 98 | if (drawcursor && x + SHORT(l->f['_' - l->sc]->width) <= SCREENWIDTH) 99 | V_DrawPatchDirect(x, l->y, l->f['_' - l->sc]); 100 | } 101 | 102 | 103 | // sorta called by HU_Erase and just better darn get things straight 104 | void HUlib_eraseTextLine(hu_textline_t *l) 105 | { 106 | int32_t lh, y, yoffset; 107 | 108 | // Only erases when NOT in automap and the screen is reduced, 109 | // and the text must either need updating or refreshing 110 | // (because of a recent change back from the automap) 111 | 112 | if (!automapactive && viewwindowx && l->needsupdate) 113 | { 114 | lh = SHORT(l->f[0]->height) + 1; 115 | for (y=l->y,yoffset=y*SCREENWIDTH ; yy+lh ; y++,yoffset+=SCREENWIDTH) 116 | { 117 | if (y < viewwindowy || y >= viewwindowy + viewheight) 118 | R_VideoErase(yoffset, SCREENWIDTH); // erase entire line 119 | else 120 | { 121 | R_VideoErase(yoffset, viewwindowx); // erase left border 122 | R_VideoErase(yoffset + viewwindowx + viewwidth, viewwindowx); // erase right border 123 | } 124 | } 125 | } 126 | 127 | if (l->needsupdate) l->needsupdate--; 128 | 129 | } 130 | 131 | void HUlib_initSText(hu_stext_t *s, int32_t x, int32_t y, int32_t h, patch_t **font, int32_t startchar, boolean *on) 132 | { 133 | 134 | int32_t i; 135 | 136 | s->h = h; 137 | s->on = on; 138 | s->laston = true; 139 | s->cl = 0; 140 | for (i=0;il[i], x, y - i*(SHORT(font[0]->height)+1), 142 | font, startchar); 143 | 144 | } 145 | 146 | // add a new line 147 | static void HUlib_addLineToSText(hu_stext_t *s) 148 | { 149 | 150 | int32_t i; 151 | 152 | // add a clear line 153 | if (++s->cl == s->h) 154 | s->cl = 0; 155 | HUlib_clearTextLine(&s->l[s->cl]); 156 | 157 | // everything needs updating 158 | for (i=0 ; ih ; i++) 159 | s->l[i].needsupdate = 4; 160 | 161 | } 162 | 163 | void HUlib_addMessageToSText (hu_stext_t *s, char *prefix, char *msg) 164 | { 165 | HUlib_addLineToSText(s); 166 | if (prefix) 167 | while (*prefix) 168 | HUlib_addCharToTextLine(&s->l[s->cl], *(prefix++)); 169 | 170 | while (*msg) 171 | HUlib_addCharToTextLine(&s->l[s->cl], *(msg++)); 172 | } 173 | 174 | void HUlib_drawSText(hu_stext_t *s) 175 | { 176 | int32_t i, idx; 177 | hu_textline_t *l; 178 | 179 | if (!*s->on) 180 | return; // if not on, don't draw 181 | 182 | // draw everything 183 | for (i=0 ; ih ; i++) 184 | { 185 | idx = s->cl - i; 186 | if (idx < 0) 187 | idx += s->h; // handle queue of lines 188 | 189 | l = &s->l[idx]; 190 | 191 | // need a decision made here on whether to skip the draw 192 | HUlib_drawTextLine(l, false); // no cursor, please 193 | } 194 | 195 | } 196 | 197 | void HUlib_eraseSText(hu_stext_t *s) 198 | { 199 | 200 | int32_t i; 201 | 202 | for (i=0 ; ih ; i++) 203 | { 204 | if (s->laston && !*s->on) 205 | s->l[i].needsupdate = 4; 206 | HUlib_eraseTextLine(&s->l[i]); 207 | } 208 | s->laston = *s->on; 209 | 210 | } 211 | 212 | void HUlib_initIText(hu_itext_t *it, int32_t x, int32_t y, patch_t **font, int32_t startchar, boolean *on) 213 | { 214 | it->lm = 0; // default left margin is start of text 215 | it->on = on; 216 | it->laston = true; 217 | HUlib_initTextLine(&it->l, x, y, font, startchar); 218 | } 219 | 220 | 221 | // The following deletion routines adhere to the left margin restriction 222 | static void HUlib_delCharFromIText(hu_itext_t *it) 223 | { 224 | if (it->l.len != it->lm) 225 | HUlib_delCharFromTextLine(&it->l); 226 | } 227 | 228 | // Resets left margin as well 229 | void HUlib_resetIText(hu_itext_t *it) 230 | { 231 | it->lm = 0; 232 | HUlib_clearTextLine(&it->l); 233 | } 234 | 235 | // wrapper function for handling general keyed input. 236 | // returns true if it ate the key 237 | boolean HUlib_keyInIText(hu_itext_t *it, uint8_t ch) 238 | { 239 | 240 | if (ch >= ' ' && ch <= '_') 241 | HUlib_addCharToTextLine(&it->l, (char) ch); 242 | else if (ch == KEY_BACKSPACE) 243 | HUlib_delCharFromIText(it); 244 | else if (ch != KEY_ENTER) 245 | return false; // did not eat key 246 | 247 | return true; // ate the key 248 | 249 | } 250 | 251 | void HUlib_drawIText(hu_itext_t *it) 252 | { 253 | 254 | hu_textline_t *l = &it->l; 255 | 256 | if (!*it->on) 257 | return; 258 | HUlib_drawTextLine(l, true); // draw the line w/ cursor 259 | 260 | } 261 | 262 | void HUlib_eraseIText(hu_itext_t *it) 263 | { 264 | if (it->laston && !*it->on) 265 | it->l.needsupdate = 4; 266 | HUlib_eraseTextLine(&it->l); 267 | it->laston = *it->on; 268 | } 269 | -------------------------------------------------------------------------------- /hu_lib.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 1993-1996 Id Software, Inc. 3 | // Copyright (C) 2023 Frenkel Smeijers 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | 19 | #ifndef __HULIB__ 20 | #define __HULIB__ 21 | 22 | 23 | // foreground screen number 24 | #define FG 0 25 | 26 | // font stuff 27 | #define HU_CHARERASE KEY_BACKSPACE 28 | 29 | #define HU_MAXLINES 4 30 | #define HU_MAXLINELENGTH 80 31 | 32 | // 33 | // Typedefs of widgets 34 | // 35 | 36 | // Text Line widget 37 | // (parent of Scrolling Text and Input Text widgets) 38 | typedef struct 39 | { 40 | // left-justified position of scrolling text window 41 | int32_t x, y; 42 | 43 | patch_t **f; // font 44 | int32_t sc; // start character 45 | char l[HU_MAXLINELENGTH+1]; // line of text 46 | int32_t len; // current line length 47 | 48 | // whether this line needs to be udpated 49 | int32_t needsupdate; 50 | 51 | } hu_textline_t; 52 | 53 | 54 | 55 | // Scrolling Text window widget 56 | // (child of Text Line widget) 57 | typedef struct 58 | { 59 | hu_textline_t l[HU_MAXLINES]; // text lines to draw 60 | int32_t h; // height in lines 61 | int32_t cl; // current line number 62 | 63 | // pointer to boolean stating whether to update window 64 | boolean *on; 65 | boolean laston; // last value of *->on. 66 | 67 | } hu_stext_t; 68 | 69 | 70 | 71 | // Input Text Line widget 72 | // (child of Text Line widget) 73 | typedef struct 74 | { 75 | hu_textline_t l; // text line to input on 76 | 77 | // left margin past which I am not to delete characters 78 | int32_t lm; 79 | 80 | // pointer to boolean stating whether to update window 81 | boolean *on; 82 | boolean laston; // last value of *->on; 83 | 84 | } hu_itext_t; 85 | 86 | 87 | // 88 | // Widget creation, access, and update routines 89 | // 90 | 91 | // 92 | // textline code 93 | // 94 | 95 | void HUlib_initTextLine(hu_textline_t *t, int32_t x, int32_t y, patch_t **f, int32_t sc); 96 | 97 | void HUlib_addCharToTextLine(hu_textline_t *t, char ch); 98 | 99 | // draws tline 100 | void HUlib_drawTextLine(hu_textline_t *l, boolean drawcursor); 101 | 102 | // erases text line 103 | void HUlib_eraseTextLine(hu_textline_t *l); 104 | 105 | 106 | // 107 | // Scrolling Text window widget routines 108 | // 109 | 110 | void HUlib_initSText(hu_stext_t *s, int32_t x, int32_t y, int32_t h, patch_t **font, int32_t startchar, boolean *on); 111 | 112 | void HUlib_addMessageToSText (hu_stext_t *s, char *prefix, char *msg); 113 | 114 | // draws stext 115 | void HUlib_drawSText(hu_stext_t *s); 116 | 117 | // erases all stext lines 118 | void HUlib_eraseSText(hu_stext_t *s); 119 | 120 | // Input Text Line widget routines 121 | void HUlib_initIText(hu_itext_t *it, int32_t x, int32_t y, patch_t **font, int32_t startchar, boolean *on); 122 | 123 | // resets line and left margin 124 | void HUlib_resetIText(hu_itext_t *it); 125 | 126 | // whether eaten 127 | boolean HUlib_keyInIText(hu_itext_t *it, uint8_t ch); 128 | 129 | void HUlib_drawIText(hu_itext_t *it); 130 | 131 | // erases all itext lines 132 | void HUlib_eraseIText(hu_itext_t *it); 133 | 134 | #endif 135 | -------------------------------------------------------------------------------- /hu_stuff.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 1993-1996 Id Software, Inc. 3 | // 4 | // This program is free software; you can redistribute it and/or 5 | // modify it under the terms of the GNU General Public License 6 | // as published by the Free Software Foundation; either version 2 7 | // of the License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | // 17 | 18 | #ifndef __HU_STUFF_H__ 19 | #define __HU_STUFF_H__ 20 | 21 | // 22 | // Locally used constants, shortcuts. 23 | // 24 | #define HU_TITLE (mapnames[(gameepisode-1)*9+gamemap-1]) 25 | #define HU_TITLE2 (mapnames2[gamemap-1]) 26 | #if (APPVER_DOOMREV >= AV_DR_DM19F) 27 | #define HU_TITLEP (mapnamesp[gamemap-1]) 28 | #define HU_TITLET (mapnamest[gamemap-1]) 29 | #endif 30 | #define HU_TITLEHEIGHT 1 31 | #define HU_TITLEX 0 32 | #define HU_TITLEY (167 - SHORT(hu_font[0]->height)) 33 | 34 | #define HU_INPUTTOGGLE 't' 35 | #define HU_INPUTX HU_MSGX 36 | #define HU_INPUTY (HU_MSGY + HU_MSGHEIGHT*(SHORT(hu_font[0]->height) +1)) 37 | #define HU_INPUTWIDTH 64 38 | #define HU_INPUTHEIGHT 1 39 | 40 | // 41 | // Globally visible constants. 42 | // 43 | #define HU_FONTSTART '!' // the first font characters 44 | #define HU_FONTEND '_' // the last font characters 45 | 46 | // Calculate # of glyphs in font. 47 | #define HU_FONTSIZE (HU_FONTEND - HU_FONTSTART + 1) 48 | 49 | #define HU_BROADCAST 5 50 | 51 | #define HU_MSGREFRESH KEY_ENTER 52 | #define HU_MSGX 0 53 | #define HU_MSGY 0 54 | #define HU_MSGWIDTH 64 // in characters 55 | #define HU_MSGHEIGHT 1 // in lines 56 | 57 | #define HU_MSGTIMEOUT (4*TICRATE) 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /i_main.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 1993-1996 Id Software, Inc. 3 | // Copyright (C) 2023 Frenkel Smeijers 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | 19 | #include "doomdef.h" 20 | 21 | int main(int argc, char **argv) 22 | { 23 | myargc = argc; 24 | myargv = argv; 25 | D_DoomMain(); 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /id_heads.h: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // Copyright (C) 2023 Frenkel Smeijers 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | 19 | // Header files, typedefs and macros that are used both in Doom and DMX. 20 | 21 | #ifndef __ID_HEADS__ 22 | #define __ID_HEADS__ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "compiler.h" 29 | 30 | #ifndef __BYTEBOOL__ 31 | #define __BYTEBOOL__ 32 | typedef enum {false, true} boolean; 33 | typedef uint8_t byte; 34 | #endif 35 | 36 | #define UNUSED(x) (x = x) // for pesky compiler / lint warnings 37 | 38 | #define LOBYTE(w) (((uint8_t *)&w)[0]) 39 | #define HIBYTE(w) (((uint8_t *)&w)[1]) 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /makefile.wc: -------------------------------------------------------------------------------- 1 | 2 | # WCDOOM.EXE makefile 3 | 4 | # -------------------------------------------------------------------------- 5 | # 6 | # 4r use 80486 timings and register argument passing 7 | # c compile only 8 | # d1 include line number debugging information 9 | # d2 include full sybolic debugging information 10 | # ei force enums to be of type int 11 | # j change char default from unsigned to signed 12 | # oa relax aliasing checking 13 | # od do not optimize 14 | # oe[=#] expand functions inline, # = quads (default 20) 15 | # oi use the inline library functions 16 | # om generate inline 80x87 code for math functions 17 | # ot optimize for time 18 | # ox maximum optimization 19 | # s remove stack overflow checks 20 | # zp1 align structures on bytes 21 | # zq use quiet mode 22 | # /i=dir add include directories 23 | # 24 | # -------------------------------------------------------------------------- 25 | 26 | CCOPTS = -dAPPVER_EXEDEF=DM19 -omaxtnrih -ol+ -oe=32 -zp4 -3r -ei -j -zq -zc -wx 27 | 28 | GLOBOBJS = & 29 | dmx.obj & 30 | a_al_mid.obj & 31 | a_blast.obj & 32 | a_dma.obj & 33 | a_ll_man.obj & 34 | a_midi.obj & 35 | a_mpu401.obj & 36 | a_multiv.obj & 37 | a_music.obj & 38 | a_musmid.obj & 39 | a_mv_mix.obj & 40 | a_pcfx.obj & 41 | a_taskmn.obj & 42 | a_tsmapi.obj & 43 | i_main.obj & 44 | i_ibm.obj & 45 | i_sound.obj & 46 | planar.obj & 47 | tables.obj & 48 | f_finale.obj & 49 | d_main.obj & 50 | d_net.obj & 51 | g_game.obj & 52 | m_menu.obj & 53 | m_misc.obj & 54 | am_map.obj & 55 | p_ceilng.obj & 56 | p_doors.obj & 57 | p_enemy.obj & 58 | p_floor.obj & 59 | p_inter.obj & 60 | p_lights.obj & 61 | p_map.obj & 62 | p_maputl.obj & 63 | p_plats.obj & 64 | p_pspr.obj & 65 | p_setup.obj & 66 | p_sight.obj & 67 | p_spec.obj & 68 | p_switch.obj & 69 | p_mobj.obj & 70 | p_telept.obj & 71 | p_tick.obj & 72 | p_user.obj & 73 | r_bsp.obj & 74 | r_data.obj & 75 | r_draw.obj & 76 | r_main.obj & 77 | r_plane.obj & 78 | r_segs.obj & 79 | r_things.obj & 80 | w_wad.obj & 81 | wi_stuff.obj & 82 | v_video.obj & 83 | st_lib.obj & 84 | st_stuff.obj & 85 | hu_stuff.obj & 86 | hu_lib.obj & 87 | s_sound.obj & 88 | z_zone.obj & 89 | info.obj & 90 | sounds.obj & 91 | dutils.obj 92 | 93 | WCDM19\wcdoom.exe : $(GLOBOBJS) 94 | cd WCDM19 95 | wlink @..\wcdoom.lnk 96 | wstrip wcdoom.exe 97 | cd.. 98 | 99 | .obj : WCDM19 100 | 101 | .c.obj : 102 | wcc386 $(CCOPTS) $[* /fo=WCDM19\$^& 103 | 104 | .asm.obj : 105 | nasm $[@ -f obj -o WCDM19\$^. 106 | -------------------------------------------------------------------------------- /p_ceilng.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 1993-1996 Id Software, Inc. 3 | // Copyright (C) 2023 Frenkel Smeijers 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | 19 | #include "doomdef.h" 20 | #include "p_local.h" 21 | #include "soundst.h" 22 | 23 | static void P_RemoveActiveCeiling(ceiling_t *c); 24 | static void P_ActivateInStasisCeiling(line_t *line); 25 | 26 | //================================================================== 27 | //================================================================== 28 | // 29 | // CEILINGS 30 | // 31 | //================================================================== 32 | //================================================================== 33 | 34 | ceiling_t *activeceilings[MAXCEILINGS]; 35 | 36 | //================================================================== 37 | // 38 | // T_MoveCeiling 39 | // 40 | //================================================================== 41 | void T_MoveCeiling (ceiling_t *ceiling) 42 | { 43 | result_e res; 44 | 45 | switch(ceiling->direction) 46 | { 47 | case 0: // IN STASIS 48 | break; 49 | case 1: // UP 50 | res = T_MovePlane(ceiling->sector,ceiling->speed, 51 | ceiling->topheight,false,1,ceiling->direction); 52 | if(!(leveltime&7)) 53 | { 54 | switch(ceiling->type) 55 | { 56 | case silentCrushAndRaise: break; 57 | default: 58 | S_StartSound((mobj_t *)&ceiling->sector->soundorg, sfx_stnmov); 59 | } 60 | } 61 | if (res == pastdest) 62 | switch(ceiling->type) 63 | { 64 | case raiseToHighest: 65 | P_RemoveActiveCeiling(ceiling); 66 | break; 67 | case silentCrushAndRaise: 68 | S_StartSound((mobj_t *)&ceiling->sector->soundorg, sfx_pstop); 69 | case fastCrushAndRaise: 70 | case crushAndRaise: 71 | ceiling->direction = -1; 72 | break; 73 | default: 74 | break; 75 | } 76 | break; 77 | case -1: // DOWN 78 | res = T_MovePlane(ceiling->sector,ceiling->speed, 79 | ceiling->bottomheight,ceiling->crush,1,ceiling->direction); 80 | if (!(leveltime&7)) 81 | { 82 | switch(ceiling->type) 83 | { 84 | case silentCrushAndRaise: break; 85 | default: 86 | S_StartSound((mobj_t *)&ceiling->sector->soundorg, sfx_stnmov); 87 | } 88 | } 89 | if (res == pastdest) 90 | switch(ceiling->type) 91 | { 92 | case silentCrushAndRaise: 93 | S_StartSound((mobj_t *)&ceiling->sector->soundorg, sfx_pstop); 94 | case crushAndRaise: 95 | ceiling->speed = CEILSPEED; 96 | case fastCrushAndRaise: 97 | ceiling->direction = 1; 98 | break; 99 | case lowerAndCrush: 100 | case lowerToFloor: 101 | P_RemoveActiveCeiling(ceiling); 102 | break; 103 | default: 104 | break; 105 | } 106 | else 107 | if (res == crushed) 108 | switch(ceiling->type) 109 | { 110 | case silentCrushAndRaise: 111 | case crushAndRaise: 112 | case lowerAndCrush: 113 | ceiling->speed = CEILSPEED / 8; 114 | break; 115 | default: 116 | break; 117 | } 118 | break; 119 | } 120 | } 121 | 122 | //================================================================== 123 | // 124 | // EV_DoCeiling 125 | // Move a ceiling up/down and all around! 126 | // 127 | //================================================================== 128 | boolean EV_DoCeiling (line_t *line, ceiling_e type) 129 | { 130 | int32_t secnum; 131 | boolean rtn; 132 | sector_t *sec; 133 | ceiling_t *ceiling; 134 | 135 | secnum = -1; 136 | rtn = false; 137 | 138 | // 139 | // Reactivate in-stasis ceilings...for certain types. 140 | // 141 | switch(type) 142 | { 143 | case fastCrushAndRaise: 144 | case silentCrushAndRaise: 145 | case crushAndRaise: 146 | P_ActivateInStasisCeiling(line); 147 | default: 148 | break; 149 | } 150 | 151 | while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) 152 | { 153 | sec = §ors[secnum]; 154 | if (sec->specialdata) 155 | continue; 156 | 157 | // 158 | // new door thinker 159 | // 160 | rtn = true; 161 | ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVSPEC, 0); 162 | P_AddThinker (&ceiling->thinker); 163 | sec->specialdata = ceiling; 164 | ceiling->thinker.function = T_MoveCeiling; 165 | ceiling->sector = sec; 166 | ceiling->crush = false; 167 | switch(type) 168 | { 169 | case fastCrushAndRaise: 170 | ceiling->crush = true; 171 | ceiling->topheight = sec->ceilingheight; 172 | ceiling->bottomheight = sec->floorheight + (8*FRACUNIT); 173 | ceiling->direction = -1; 174 | ceiling->speed = CEILSPEED * 2; 175 | break; 176 | case silentCrushAndRaise: 177 | case crushAndRaise: 178 | ceiling->crush = true; 179 | ceiling->topheight = sec->ceilingheight; 180 | case lowerAndCrush: 181 | case lowerToFloor: 182 | ceiling->bottomheight = sec->floorheight; 183 | if (type != lowerToFloor) 184 | ceiling->bottomheight += 8*FRACUNIT; 185 | ceiling->direction = -1; 186 | ceiling->speed = CEILSPEED; 187 | break; 188 | case raiseToHighest: 189 | ceiling->topheight = P_FindHighestCeilingSurrounding(sec); 190 | ceiling->direction = 1; 191 | ceiling->speed = CEILSPEED; 192 | break; 193 | } 194 | 195 | ceiling->tag = sec->tag; 196 | ceiling->type = type; 197 | P_AddActiveCeiling(ceiling); 198 | } 199 | return rtn; 200 | } 201 | 202 | //================================================================== 203 | // 204 | // Add an active ceiling 205 | // 206 | //================================================================== 207 | void P_AddActiveCeiling(ceiling_t *c) 208 | { 209 | int32_t i; 210 | for (i = 0; i < MAXCEILINGS;i++) 211 | if (activeceilings[i] == NULL) 212 | { 213 | activeceilings[i] = c; 214 | return; 215 | } 216 | } 217 | 218 | //================================================================== 219 | // 220 | // Remove a ceiling's thinker 221 | // 222 | //================================================================== 223 | static void P_RemoveActiveCeiling(ceiling_t *c) 224 | { 225 | int32_t i; 226 | 227 | for (i = 0;i < MAXCEILINGS;i++) 228 | if (activeceilings[i] == c) 229 | { 230 | activeceilings[i]->sector->specialdata = NULL; 231 | P_RemoveThinker (&activeceilings[i]->thinker); 232 | activeceilings[i] = NULL; 233 | break; 234 | } 235 | } 236 | 237 | //================================================================== 238 | // 239 | // Restart a ceiling that's in-stasis 240 | // 241 | //================================================================== 242 | static void P_ActivateInStasisCeiling(line_t *line) 243 | { 244 | int32_t i; 245 | 246 | for (i = 0;i < MAXCEILINGS;i++) 247 | if (activeceilings[i] && (activeceilings[i]->tag == line->tag) && 248 | (activeceilings[i]->direction == 0)) 249 | { 250 | activeceilings[i]->direction = activeceilings[i]->olddirection; 251 | activeceilings[i]->thinker.function = T_MoveCeiling; 252 | } 253 | } 254 | 255 | //================================================================== 256 | // 257 | // EV_CeilingCrushStop 258 | // Stop a ceiling from crushing! 259 | // 260 | //================================================================== 261 | void EV_CeilingCrushStop(line_t *line) 262 | { 263 | int32_t i; 264 | 265 | for (i = 0;i < MAXCEILINGS;i++) 266 | if (activeceilings[i] && (activeceilings[i]->tag == line->tag) && 267 | (activeceilings[i]->direction != 0)) 268 | { 269 | activeceilings[i]->olddirection = activeceilings[i]->direction; 270 | activeceilings[i]->thinker.function = NULL; 271 | activeceilings[i]->direction = 0; // in-stasis 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /p_lights.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 1993-1996 Id Software, Inc. 3 | // Copyright (C) 2023 Frenkel Smeijers 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | 19 | #include "doomdef.h" 20 | #include "p_local.h" 21 | 22 | //================================================================== 23 | //================================================================== 24 | // 25 | // FIRELIGHT FLICKER 26 | // 27 | //================================================================== 28 | //================================================================== 29 | 30 | //================================================================== 31 | // 32 | // T_FireFlicker 33 | // 34 | //================================================================== 35 | static void T_FireFlicker (lightflash_t *flash) 36 | { 37 | int32_t amount; 38 | 39 | if (--flash->count) 40 | return; 41 | 42 | amount = (P_Random()&3)*16; 43 | 44 | if (flash->sector->lightlevel - amount < flash->minlight) 45 | flash->sector->lightlevel = flash->minlight; 46 | else 47 | flash->sector->lightlevel = flash->maxlight - amount; 48 | 49 | flash->count = 4; 50 | } 51 | 52 | //================================================================== 53 | // 54 | // P_SpawnFireFlicker 55 | // 56 | //================================================================== 57 | void P_SpawnFireFlicker (sector_t *sector) 58 | { 59 | fireflicker_t *flick; 60 | 61 | sector->special = 0; // nothing special about it during gameplay 62 | 63 | flick = Z_Malloc ( sizeof(*flick), PU_LEVSPEC, 0); 64 | P_AddThinker (&flick->thinker); 65 | flick->thinker.function = T_FireFlicker; 66 | flick->sector = sector; 67 | flick->maxlight = sector->lightlevel; 68 | flick->minlight = P_FindMinSurroundingLight(sector)+16; 69 | flick->count = 4; 70 | } 71 | 72 | 73 | //================================================================== 74 | //================================================================== 75 | // 76 | // BROKEN LIGHT FLASHING 77 | // 78 | //================================================================== 79 | //================================================================== 80 | 81 | //================================================================== 82 | // 83 | // T_LightFlash 84 | // 85 | // After the map has been loaded, scan each sector for specials 86 | // that spawn thinkers 87 | // 88 | //================================================================== 89 | void T_LightFlash (lightflash_t *flash) 90 | { 91 | if (--flash->count) 92 | return; 93 | 94 | if (flash->sector->lightlevel == flash->maxlight) 95 | { 96 | flash-> sector->lightlevel = flash->minlight; 97 | flash->count = (P_Random()&flash->mintime)+1; 98 | } 99 | else 100 | { 101 | flash-> sector->lightlevel = flash->maxlight; 102 | flash->count = (P_Random()&flash->maxtime)+1; 103 | } 104 | 105 | } 106 | 107 | 108 | //================================================================== 109 | // 110 | // P_SpawnLightFlash 111 | // 112 | // After the map has been loaded, scan each sector for specials that spawn thinkers 113 | // 114 | //================================================================== 115 | void P_SpawnLightFlash (sector_t *sector) 116 | { 117 | lightflash_t *flash; 118 | 119 | sector->special = 0; // nothing special about it during gameplay 120 | 121 | flash = Z_Malloc ( sizeof(*flash), PU_LEVSPEC, 0); 122 | P_AddThinker (&flash->thinker); 123 | flash->thinker.function = T_LightFlash; 124 | flash->sector = sector; 125 | flash->maxlight = sector->lightlevel; 126 | 127 | flash->minlight = P_FindMinSurroundingLight(sector); 128 | flash->maxtime = 64; 129 | flash->mintime = 7; 130 | flash->count = (P_Random()&flash->maxtime)+1; 131 | } 132 | 133 | //================================================================== 134 | // 135 | // STROBE LIGHT FLASHING 136 | // 137 | //================================================================== 138 | 139 | //================================================================== 140 | // 141 | // T_StrobeFlash 142 | // 143 | // After the map has been loaded, scan each sector for specials that spawn thinkers 144 | // 145 | //================================================================== 146 | void T_StrobeFlash (strobe_t *flash) 147 | { 148 | if (--flash->count) 149 | return; 150 | 151 | if (flash->sector->lightlevel == flash->minlight) 152 | { 153 | flash-> sector->lightlevel = flash->maxlight; 154 | flash->count = flash->brighttime; 155 | } 156 | else 157 | { 158 | flash-> sector->lightlevel = flash->minlight; 159 | flash->count =flash->darktime; 160 | } 161 | 162 | } 163 | 164 | //================================================================== 165 | // 166 | // P_SpawnLightFlash 167 | // 168 | // After the map has been loaded, scan each sector for specials that spawn thinkers 169 | // 170 | //================================================================== 171 | void P_SpawnStrobeFlash (sector_t *sector,int32_t fastOrSlow, int32_t inSync) 172 | { 173 | strobe_t *flash; 174 | 175 | flash = Z_Malloc ( sizeof(*flash), PU_LEVSPEC, 0); 176 | P_AddThinker (&flash->thinker); 177 | flash->sector = sector; 178 | flash->darktime = fastOrSlow; 179 | flash->brighttime = STROBEBRIGHT; 180 | flash->thinker.function = T_StrobeFlash; 181 | flash->maxlight = sector->lightlevel; 182 | flash->minlight = P_FindMinSurroundingLight(sector); 183 | 184 | if (flash->minlight == flash->maxlight) 185 | flash->minlight = 0; 186 | sector->special = 0; // nothing special about it during gameplay 187 | 188 | if (!inSync) 189 | flash->count = (P_Random()&7)+1; 190 | else 191 | flash->count = 1; 192 | } 193 | 194 | //================================================================== 195 | // 196 | // Start strobing lights (usually from a trigger) 197 | // 198 | //================================================================== 199 | void EV_StartLightStrobing(line_t *line) 200 | { 201 | int32_t secnum; 202 | sector_t *sec; 203 | 204 | secnum = -1; 205 | while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) 206 | { 207 | sec = §ors[secnum]; 208 | if (sec->specialdata) 209 | continue; 210 | 211 | P_SpawnStrobeFlash (sec,SLOWDARK, 0); 212 | } 213 | } 214 | 215 | //================================================================== 216 | // 217 | // TURN LINE'S TAG LIGHTS OFF 218 | // 219 | //================================================================== 220 | void EV_TurnTagLightsOff(line_t *line) 221 | { 222 | int32_t i; 223 | int32_t j; 224 | int32_t min; 225 | sector_t *sector; 226 | sector_t *tsec; 227 | line_t *templine; 228 | 229 | sector = sectors; 230 | for (j = 0;j < numsectors; j++, sector++) 231 | if (sector->tag == line->tag) 232 | { 233 | min = sector->lightlevel; 234 | for (i = 0;i < sector->linecount; i++) 235 | { 236 | templine = sector->lines[i]; 237 | tsec = getNextSector(templine,sector); 238 | if (!tsec) 239 | continue; 240 | if (tsec->lightlevel < min) 241 | min = tsec->lightlevel; 242 | } 243 | sector->lightlevel = min; 244 | } 245 | } 246 | 247 | //================================================================== 248 | // 249 | // TURN LINE'S TAG LIGHTS ON 250 | // 251 | //================================================================== 252 | void EV_LightTurnOn(line_t *line, int32_t bright) 253 | { 254 | int32_t i; 255 | int32_t j; 256 | sector_t *sector; 257 | sector_t *temp; 258 | line_t *templine; 259 | 260 | sector = sectors; 261 | 262 | for (i=0;itag == line->tag) 264 | { 265 | // 266 | // bright = 0 means to search for highest 267 | // light level surrounding sector 268 | // 269 | if (!bright) 270 | { 271 | for (j = 0;j < sector->linecount; j++) 272 | { 273 | templine = sector->lines[j]; 274 | temp = getNextSector(templine,sector); 275 | if (!temp) 276 | continue; 277 | if (temp->lightlevel > bright) 278 | bright = temp->lightlevel; 279 | } 280 | } 281 | sector-> lightlevel = bright; 282 | } 283 | } 284 | 285 | //================================================================== 286 | // 287 | // Spawn glowing light 288 | // 289 | //================================================================== 290 | void T_Glow(glow_t *g) 291 | { 292 | switch(g->direction) 293 | { 294 | case -1: // DOWN 295 | g->sector->lightlevel -= GLOWSPEED; 296 | if (g->sector->lightlevel <= g->minlight) 297 | { 298 | g->sector->lightlevel += GLOWSPEED; 299 | g->direction = 1; 300 | } 301 | break; 302 | case 1: // UP 303 | g->sector->lightlevel += GLOWSPEED; 304 | if (g->sector->lightlevel >= g->maxlight) 305 | { 306 | g->sector->lightlevel -= GLOWSPEED; 307 | g->direction = -1; 308 | } 309 | break; 310 | } 311 | } 312 | 313 | void P_SpawnGlowingLight(sector_t *sector) 314 | { 315 | glow_t *g; 316 | 317 | g = Z_Malloc( sizeof(*g), PU_LEVSPEC, 0); 318 | P_AddThinker(&g->thinker); 319 | g->sector = sector; 320 | g->minlight = P_FindMinSurroundingLight(sector); 321 | g->maxlight = sector->lightlevel; 322 | g->thinker.function = T_Glow; 323 | g->direction = -1; 324 | 325 | sector->special = 0; 326 | } 327 | 328 | -------------------------------------------------------------------------------- /p_local.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 1993-1996 Id Software, Inc. 3 | // Copyright (C) 2023 Frenkel Smeijers 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | 19 | // P_local.h 20 | 21 | #ifndef __P_LOCAL__ 22 | #define __P_LOCAL__ 23 | 24 | #ifndef __R_LOCAL__ 25 | #include "r_local.h" 26 | #endif 27 | 28 | #define FLOATSPEED (FRACUNIT*4) 29 | 30 | 31 | #define MAXHEALTH 100 32 | #define VIEWHEIGHT (41*FRACUNIT) 33 | 34 | // mapblocks are used to check movement against lines and things 35 | #define MAPBLOCKUNITS 128 36 | #define MAPBLOCKSIZE (MAPBLOCKUNITS*FRACUNIT) 37 | #define MAPBLOCKSHIFT (FRACBITS+7) 38 | #define MAPBMASK (MAPBLOCKSIZE-1) 39 | #define MAPBTOFRAC (MAPBLOCKSHIFT-FRACBITS) 40 | 41 | // player radius for movement checking 42 | #define PLAYERRADIUS 16*FRACUNIT 43 | 44 | // MAXRADIUS is for precalculated sector block boxes 45 | // the spider demon is larger, but we don't have any moving sectors 46 | // nearby 47 | #define MAXRADIUS 32*FRACUNIT 48 | 49 | #define GRAVITY FRACUNIT 50 | #define MAXMOVE (30*FRACUNIT) 51 | 52 | #define USERANGE (64*FRACUNIT) 53 | #define MELEERANGE (64*FRACUNIT) 54 | #define MISSILERANGE (32*64*FRACUNIT) 55 | 56 | typedef enum 57 | { 58 | DI_EAST, 59 | DI_NORTHEAST, 60 | DI_NORTH, 61 | DI_NORTHWEST, 62 | DI_WEST, 63 | DI_SOUTHWEST, 64 | DI_SOUTH, 65 | DI_SOUTHEAST, 66 | DI_NODIR, 67 | NUMDIRS 68 | } dirtype_t; 69 | 70 | #define BASETHRESHOLD 100 // follow a player exlusively for 3 seconds 71 | 72 | /* 73 | =============================================================================== 74 | 75 | P_TICK 76 | 77 | =============================================================================== 78 | */ 79 | 80 | extern thinker_t thinkercap; // both the head and tail of the thinker list 81 | 82 | 83 | void P_InitThinkers (void); 84 | void P_AddThinker (thinker_t *thinker); 85 | void P_RemoveThinker (thinker_t *thinker); 86 | 87 | /* 88 | =============================================================================== 89 | 90 | P_PSPR 91 | 92 | =============================================================================== 93 | */ 94 | 95 | void P_SetupPsprites (player_t *curplayer); 96 | void P_MovePsprites (player_t *curplayer); 97 | 98 | void P_DropWeapon (player_t *player); 99 | 100 | /* 101 | =============================================================================== 102 | 103 | P_USER 104 | 105 | =============================================================================== 106 | */ 107 | 108 | void P_PlayerThink (player_t *player); 109 | 110 | /* 111 | =============================================================================== 112 | P_MOBJ 113 | =============================================================================== 114 | */ 115 | 116 | #define ONFLOORZ MININT 117 | #define ONCEILINGZ MAXINT 118 | 119 | // Time interval for item respawning. 120 | #define ITEMQUESIZE 128 121 | 122 | extern int32_t iquehead, iquetail; 123 | 124 | 125 | void P_RespawnSpecials (void); 126 | 127 | mobj_t *P_SpawnMobj (fixed_t x, fixed_t y, fixed_t z, mobjtype_t type); 128 | 129 | void P_RemoveMobj (mobj_t *th); 130 | boolean P_SetMobjState (mobj_t *mobj, statenum_t state); 131 | void P_MobjThinker (mobj_t *mobj); 132 | 133 | void P_SpawnPuff (fixed_t x, fixed_t y, fixed_t z); 134 | void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, int32_t damage); 135 | mobj_t *P_SpawnMissile (mobj_t *source, mobj_t *dest, mobjtype_t type); 136 | void P_SpawnPlayerMissile (mobj_t *source, mobjtype_t type); 137 | 138 | /* 139 | =============================================================================== 140 | 141 | P_ENEMY 142 | 143 | =============================================================================== 144 | */ 145 | 146 | void P_NoiseAlert (mobj_t *target, mobj_t *emmiter); 147 | 148 | /* 149 | =============================================================================== 150 | 151 | P_MAPUTL 152 | 153 | =============================================================================== 154 | */ 155 | 156 | typedef struct 157 | { 158 | fixed_t x, y, dx, dy; 159 | } divline_t; 160 | 161 | typedef struct 162 | { 163 | fixed_t frac; // along trace line 164 | boolean isaline; 165 | union { 166 | mobj_t *thing; 167 | line_t *line; 168 | } d; 169 | } intercept_t; 170 | 171 | #define MAXINTERCEPTS 128 172 | typedef boolean (*traverser_t) (intercept_t *in); 173 | 174 | 175 | fixed_t P_AproxDistance (fixed_t dx, fixed_t dy); 176 | int32_t P_PointOnLineSide (fixed_t x, fixed_t y, line_t *line); 177 | int32_t P_BoxOnLineSide (fixed_t *tmbox, line_t *ld); 178 | 179 | extern fixed_t opentop, openbottom, openrange; 180 | extern fixed_t lowfloor; 181 | void P_LineOpening (line_t *linedef); 182 | 183 | boolean P_BlockLinesIterator (int32_t x, int32_t y, boolean(*func)(line_t*) ); 184 | boolean P_BlockThingsIterator (int32_t x, int32_t y, boolean(*func)(mobj_t*) ); 185 | 186 | #define PT_ADDLINES 1 187 | #define PT_ADDTHINGS 2 188 | #define PT_EARLYOUT 4 189 | 190 | extern divline_t trace; 191 | void P_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, 192 | int32_t flags, boolean (*trav) (intercept_t *)); 193 | 194 | void P_UnsetThingPosition (mobj_t *thing); 195 | void P_SetThingPosition (mobj_t *thing); 196 | 197 | /* 198 | =============================================================================== 199 | 200 | P_MAP 201 | 202 | =============================================================================== 203 | */ 204 | 205 | extern boolean floatok; // if true, move would be ok if 206 | extern fixed_t tmfloorz; // within tmfloorz - tmceilingz 207 | 208 | extern line_t *ceilingline; 209 | 210 | 211 | boolean P_CheckPosition (mobj_t *thing, fixed_t x, fixed_t y); 212 | boolean P_TryMove (mobj_t *thing, fixed_t x, fixed_t y); 213 | boolean P_TeleportMove (mobj_t *thing, fixed_t x, fixed_t y); 214 | void P_SlideMove (mobj_t *mo); 215 | boolean P_CheckSight (mobj_t *t1, mobj_t *t2); 216 | void P_UseLines (player_t *player); 217 | 218 | boolean P_ChangeSector (sector_t *sector, boolean crunch); 219 | 220 | extern mobj_t *linetarget; // who got hit (or NULL) 221 | fixed_t P_AimLineAttack (mobj_t *t1, angle_t angle, fixed_t distance); 222 | 223 | void P_LineAttack (mobj_t *t1, angle_t angle, fixed_t distance, fixed_t slope, int32_t damage); 224 | 225 | void P_RadiusAttack (mobj_t *spot, mobj_t *source, int32_t damage); 226 | 227 | /* 228 | =============================================================================== 229 | 230 | P_SETUP 231 | 232 | =============================================================================== 233 | */ 234 | 235 | extern byte *rejectmatrix; // for fast sight rejection 236 | extern int16_t *blockmaplump; // offsets in blockmap are from here 237 | extern int16_t *blockmap; 238 | extern int32_t bmapwidth, bmapheight; // in mapblocks 239 | extern fixed_t bmaporgx, bmaporgy; // origin of block map 240 | extern mobj_t **blocklinks; // for thing chains 241 | 242 | /* 243 | =============================================================================== 244 | 245 | P_INTER 246 | 247 | =============================================================================== 248 | */ 249 | 250 | extern int32_t maxammo[NUMAMMO]; 251 | 252 | void P_TouchSpecialThing (mobj_t *special, mobj_t *toucher); 253 | 254 | void P_DamageMobj (mobj_t *target, mobj_t *inflictor, mobj_t *source, int32_t damage); 255 | 256 | void P_SetMessage(player_t *player, char *message, boolean ultmsg); 257 | void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher); 258 | void P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, 259 | int32_t damage); 260 | boolean P_GivePower(player_t *player, powertype_t power); 261 | 262 | #include "p_spec.h" 263 | 264 | #endif // __P_LOCAL__ 265 | -------------------------------------------------------------------------------- /p_plats.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 1993-1996 Id Software, Inc. 3 | // Copyright (C) 2023 Frenkel Smeijers 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | 19 | // P_plats.c 20 | 21 | #include "doomdef.h" 22 | #include "p_local.h" 23 | #include "soundst.h" 24 | 25 | plat_t *activeplats[MAXPLATS]; 26 | 27 | //================================================================== 28 | // 29 | // Move a plat up and down 30 | // 31 | //================================================================== 32 | 33 | static void P_RemoveActivePlat(plat_t *plat); 34 | 35 | void T_PlatRaise(plat_t *plat) 36 | { 37 | result_e res; 38 | 39 | switch(plat->status) 40 | { 41 | case up: 42 | res = T_MovePlane(plat->sector,plat->speed, 43 | plat->high,plat->crush,0,1); 44 | if(plat->type == raiseAndChange 45 | || plat->type == raiseToNearestAndChange) 46 | { 47 | if(!(leveltime&7)) 48 | { 49 | S_StartSound((mobj_t *)&plat->sector->soundorg, 50 | sfx_stnmov); 51 | } 52 | } 53 | if (res == crushed && (!plat->crush)) 54 | { 55 | plat->count = plat->wait; 56 | plat->status = down; 57 | S_StartSound((mobj_t *)&plat->sector->soundorg, sfx_pstart); 58 | } 59 | else 60 | if (res == pastdest) 61 | { 62 | plat->count = plat->wait; 63 | plat->status = waiting; 64 | S_StartSound((mobj_t *)&plat->sector->soundorg, sfx_pstop); 65 | switch(plat->type) 66 | { 67 | case blazeDWUS: 68 | case downWaitUpStay: 69 | P_RemoveActivePlat(plat); 70 | break; 71 | case raiseAndChange: 72 | case raiseToNearestAndChange: 73 | P_RemoveActivePlat(plat); 74 | break; 75 | default: 76 | break; 77 | } 78 | } 79 | break; 80 | case down: 81 | res = T_MovePlane(plat->sector,plat->speed,plat->low,false,0,-1); 82 | if (res == pastdest) 83 | { 84 | plat->count = plat->wait; 85 | plat->status = waiting; 86 | S_StartSound((mobj_t *)&plat->sector->soundorg, sfx_pstop); 87 | } 88 | break; 89 | case waiting: 90 | if (!--plat->count) 91 | { 92 | if (plat->sector->floorheight == plat->low) 93 | plat->status = up; 94 | else 95 | plat->status = down; 96 | S_StartSound((mobj_t *)&plat->sector->soundorg, sfx_pstart); 97 | } 98 | case in_stasis: 99 | break; 100 | } 101 | } 102 | 103 | //================================================================== 104 | // 105 | // Do Platforms 106 | // "amount" is only used for SOME platforms. 107 | // 108 | //================================================================== 109 | 110 | static void P_ActivateInStasis(int32_t tag); 111 | 112 | boolean EV_DoPlat(line_t *line,plattype_e type,int32_t amount) 113 | { 114 | plat_t *plat; 115 | int32_t secnum; 116 | boolean rtn; 117 | sector_t *sec; 118 | 119 | secnum = -1; 120 | rtn = false; 121 | 122 | // 123 | // Activate all plats that are in_stasis 124 | // 125 | switch(type) 126 | { 127 | case perpetualRaise: 128 | P_ActivateInStasis(line->tag); 129 | break; 130 | default: 131 | break; 132 | } 133 | 134 | while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) 135 | { 136 | sec = §ors[secnum]; 137 | if (sec->specialdata) 138 | continue; 139 | 140 | // 141 | // Find lowest & highest floors around sector 142 | // 143 | rtn = true; 144 | plat = Z_Malloc( sizeof(*plat), PU_LEVSPEC, 0); 145 | P_AddThinker(&plat->thinker); 146 | 147 | plat->type = type; 148 | plat->sector = sec; 149 | plat->sector->specialdata = plat; 150 | plat->thinker.function = T_PlatRaise; 151 | plat->crush = false; 152 | plat->tag = line->tag; 153 | switch(type) 154 | { 155 | case raiseToNearestAndChange: 156 | plat->speed = PLATSPEED/2; 157 | sec->floorpic = sides[line->sidenum[0]].sector->floorpic; 158 | plat->high = P_FindNextHighestFloor(sec); 159 | plat->wait = 0; 160 | plat->status = up; 161 | sec->special = 0; // NO MORE DAMAGE, IF APPLICABLE 162 | S_StartSound((mobj_t *)&sec->soundorg, sfx_stnmov); 163 | break; 164 | case raiseAndChange: 165 | plat->speed = PLATSPEED/2; 166 | sec->floorpic = sides[line->sidenum[0]].sector->floorpic; 167 | plat->high = sec->floorheight + amount*FRACUNIT; 168 | plat->wait = 0; 169 | plat->status = up; 170 | S_StartSound((mobj_t *)&sec->soundorg, sfx_stnmov); 171 | break; 172 | case downWaitUpStay: 173 | plat->speed = PLATSPEED * 4; 174 | plat->low = P_FindLowestFloorSurrounding(sec); 175 | if (plat->low > sec->floorheight) 176 | plat->low = sec->floorheight; 177 | plat->high = sec->floorheight; 178 | plat->wait = TICRATE*PLATWAIT; 179 | plat->status = down; 180 | S_StartSound((mobj_t *)&sec->soundorg, sfx_pstart); 181 | break; 182 | case blazeDWUS: 183 | plat->speed = PLATSPEED * 8; 184 | plat->low = P_FindLowestFloorSurrounding(sec); 185 | if (plat->low > sec->floorheight) 186 | plat->low = sec->floorheight; 187 | plat->high = sec->floorheight; 188 | plat->wait = TICRATE*PLATWAIT; 189 | plat->status = down; 190 | S_StartSound((mobj_t *)&sec->soundorg, sfx_pstart); 191 | break; 192 | case perpetualRaise: 193 | plat->speed = PLATSPEED; 194 | plat->low = P_FindLowestFloorSurrounding(sec); 195 | if (plat->low > sec->floorheight) 196 | plat->low = sec->floorheight; 197 | plat->high = P_FindHighestFloorSurrounding(sec); 198 | if (plat->high < sec->floorheight) 199 | plat->high = sec->floorheight; 200 | plat->wait = TICRATE*PLATWAIT; 201 | plat->status = P_Random()&1; 202 | S_StartSound((mobj_t *)&sec->soundorg, sfx_pstart); 203 | break; 204 | } 205 | P_AddActivePlat(plat); 206 | } 207 | return rtn; 208 | } 209 | 210 | static void P_ActivateInStasis(int32_t tag) 211 | { 212 | int32_t i; 213 | 214 | for (i = 0;i < MAXPLATS;i++) 215 | if (activeplats[i] && 216 | (activeplats[i])->tag == tag && 217 | (activeplats[i])->status == in_stasis) 218 | { 219 | (activeplats[i])->status = (activeplats[i])->oldstatus; 220 | (activeplats[i])->thinker.function = T_PlatRaise; 221 | } 222 | } 223 | 224 | void EV_StopPlat(line_t *line) 225 | { 226 | int32_t j; 227 | 228 | for (j = 0;j < MAXPLATS;j++) 229 | if (activeplats[j] && ((activeplats[j])->status != in_stasis) && 230 | ((activeplats[j])->tag == line->tag)) 231 | { 232 | (activeplats[j])->oldstatus = (activeplats[j])->status; 233 | (activeplats[j])->status = in_stasis; 234 | (activeplats[j])->thinker.function = NULL; 235 | } 236 | } 237 | 238 | void P_AddActivePlat(plat_t *plat) 239 | { 240 | int32_t i; 241 | for (i = 0;i < MAXPLATS;i++) 242 | if (activeplats[i] == NULL) 243 | { 244 | activeplats[i] = plat; 245 | return; 246 | } 247 | I_Error ("P_AddActivePlat: no more plats!"); 248 | } 249 | 250 | static void P_RemoveActivePlat(plat_t *plat) 251 | { 252 | int32_t i; 253 | for (i = 0;i < MAXPLATS;i++) 254 | if (plat == activeplats[i]) 255 | { 256 | (activeplats[i])->sector->specialdata = NULL; 257 | P_RemoveThinker(&(activeplats[i])->thinker); 258 | activeplats[i] = NULL; 259 | return; 260 | } 261 | I_Error ("P_RemoveActivePlat: can't find plat!"); 262 | } 263 | -------------------------------------------------------------------------------- /p_sight.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 1993-1996 Id Software, Inc. 3 | // Copyright (C) 2023 Frenkel Smeijers 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | 19 | // P_sight.c 20 | 21 | #include "doomdef.h" 22 | #include "p_local.h" 23 | 24 | /* 25 | ============================================================================== 26 | 27 | P_CheckSight 28 | 29 | ============================================================================== 30 | */ 31 | 32 | static fixed_t sightzstart; // eye z of looker 33 | fixed_t topslope; 34 | fixed_t bottomslope; // slopes to top and bottom of target 35 | 36 | static divline_t strace; // from t1 to t2 37 | static fixed_t t2x; 38 | static fixed_t t2y; 39 | 40 | 41 | /* 42 | ============== 43 | = 44 | = P_DivlineSide 45 | = 46 | = Returns side 0 (front), 1 (back), or 2 (on) 47 | = 48 | ============== 49 | */ 50 | 51 | static int32_t P_DivlineSide (fixed_t x, fixed_t y, divline_t *node) 52 | { 53 | fixed_t dx, dy; 54 | fixed_t left, right; 55 | 56 | if (!node->dx) 57 | { 58 | if (x==node->x) 59 | return 2; 60 | if (x <= node->x) 61 | return node->dy > 0; 62 | return node->dy < 0; 63 | } 64 | if (!node->dy) 65 | { 66 | if (x==node->y) 67 | return 2; 68 | if (y <= node->y) 69 | return node->dx < 0; 70 | return node->dx > 0; 71 | } 72 | 73 | dx = (x - node->x); 74 | dy = (y - node->y); 75 | 76 | left = (node->dy>>FRACBITS) * (dx>>FRACBITS); 77 | right = (dy>>FRACBITS) * (node->dx>>FRACBITS); 78 | 79 | if (right < left) 80 | return 0; // front side 81 | if (left == right) 82 | return 2; 83 | return 1; // back side 84 | } 85 | 86 | 87 | /* 88 | ============== 89 | = 90 | = P_InterceptVector2 91 | = 92 | = Returns the fractional intercept point along the first divline 93 | = 94 | = This is only called by the addthings and addlines traversers 95 | = 96 | ============== 97 | */ 98 | 99 | static fixed_t P_InterceptVector2 (divline_t *v2, divline_t *v1) 100 | { 101 | fixed_t frac, num, den; 102 | 103 | den = FixedMul (v1->dy>>8,v2->dx) - FixedMul(v1->dx>>8,v2->dy); 104 | if (den == 0) 105 | return 0; 106 | 107 | num = FixedMul ( (v1->x - v2->x)>>8 ,v1->dy) + 108 | FixedMul ( (v2->y - v1->y)>>8 , v1->dx); 109 | frac = FixedDiv (num , den); 110 | 111 | return frac; 112 | } 113 | 114 | /* 115 | ============== 116 | = 117 | = P_CrossSubsector 118 | = 119 | = Returns true if strace crosses the given subsector successfully 120 | = 121 | ============== 122 | */ 123 | 124 | static boolean P_CrossSubsector (int32_t num) 125 | { 126 | seg_t *seg; 127 | line_t *line; 128 | int32_t s1, s2; 129 | int32_t count; 130 | subsector_t *sub; 131 | sector_t *front, *back; 132 | fixed_t opentop, openbottom; 133 | divline_t divl; 134 | vertex_t *v1, *v2; 135 | fixed_t frac, slope; 136 | 137 | #ifdef RANGECHECK 138 | if (num>=numsubsectors) 139 | I_Error ("P_CrossSubsector: ss %i with numss = %i", num, numsubsectors); 140 | #endif 141 | 142 | sub = &subsectors[num]; 143 | 144 | // 145 | // check lines 146 | // 147 | count = sub->numlines; 148 | seg = &segs[sub->firstline]; 149 | 150 | for ( ; count ; seg++, count--) 151 | { 152 | line = seg->linedef; 153 | 154 | if (line->validcount == validcount) 155 | continue; // allready checked other side 156 | line->validcount = validcount; 157 | 158 | v1 = line->v1; 159 | v2 = line->v2; 160 | s1 = P_DivlineSide (v1->x,v1->y, &strace); 161 | s2 = P_DivlineSide (v2->x, v2->y, &strace); 162 | 163 | if (s1 == s2) 164 | continue; // line isn't crossed 165 | 166 | divl.x = v1->x; 167 | divl.y = v1->y; 168 | divl.dx = v2->x - v1->x; 169 | divl.dy = v2->y - v1->y; 170 | s1 = P_DivlineSide (strace.x, strace.y, &divl); 171 | s2 = P_DivlineSide (t2x, t2y, &divl); 172 | 173 | if (s1 == s2) 174 | continue; // line isn't crossed 175 | 176 | // stop because it is not two sided anyway 177 | // might do this after updating validcount? 178 | if ( !(line->flags & ML_TWOSIDED) ) 179 | return false; 180 | 181 | // 182 | // crosses a two sided line 183 | // 184 | front = seg->frontsector; 185 | back = seg->backsector; 186 | 187 | if (front->floorheight == back->floorheight 188 | && front->ceilingheight == back->ceilingheight) 189 | continue; // no wall to block sight with 190 | 191 | // possible occluder 192 | // because of ceiling height differences 193 | if (front->ceilingheight < back->ceilingheight) 194 | opentop = front->ceilingheight; 195 | else 196 | opentop = back->ceilingheight; 197 | // because of ceiling height differences 198 | if (front->floorheight > back->floorheight) 199 | openbottom = front->floorheight; 200 | else 201 | openbottom = back->floorheight; 202 | 203 | if (openbottom >= opentop) // quick test for totally closed doors 204 | return false; // stop 205 | 206 | frac = P_InterceptVector2 (&strace, &divl); 207 | 208 | if (front->floorheight != back->floorheight) 209 | { 210 | slope = FixedDiv (openbottom - sightzstart , frac); 211 | if (slope > bottomslope) 212 | bottomslope = slope; 213 | } 214 | 215 | if (front->ceilingheight != back->ceilingheight) 216 | { 217 | slope = FixedDiv (opentop - sightzstart , frac); 218 | if (slope < topslope) 219 | topslope = slope; 220 | } 221 | 222 | if (topslope <= bottomslope) 223 | return false; // stop 224 | 225 | } 226 | 227 | 228 | return true; // passed the subsector ok 229 | } 230 | 231 | 232 | 233 | /* 234 | ============== 235 | = 236 | = P_CrossBSPNode 237 | = 238 | = Returns true if strace crosses the given node successfully 239 | = 240 | ============== 241 | */ 242 | 243 | static boolean P_CrossBSPNode (int32_t bspnum) 244 | { 245 | node_t *bsp; 246 | int32_t side; 247 | 248 | if (bspnum & NF_SUBSECTOR) 249 | { 250 | if (bspnum == -1) 251 | return P_CrossSubsector (0); 252 | else 253 | return P_CrossSubsector (bspnum&(~NF_SUBSECTOR)); 254 | } 255 | 256 | bsp = &nodes[bspnum]; 257 | 258 | // 259 | // decide which side the start point is on 260 | // 261 | side = P_DivlineSide (strace.x, strace.y, (divline_t *)bsp); 262 | if (side == 2) 263 | side = 0; // an "on" should cross both sides 264 | 265 | // cross the starting side 266 | 267 | if (!P_CrossBSPNode (bsp->children[side]) ) 268 | return false; 269 | 270 | // the partition plane is crossed here 271 | 272 | if (side == P_DivlineSide (t2x, t2y,(divline_t *)bsp)) 273 | return true; // the line doesn't touch the other side 274 | 275 | // cross the ending side 276 | return P_CrossBSPNode (bsp->children[side^1]); 277 | } 278 | 279 | 280 | 281 | /* 282 | ===================== 283 | = 284 | = P_CheckSight 285 | = 286 | = Returns true if a straight line between t1 and t2 is unobstructed 287 | = look from eyes of t1 to any part of t2 288 | = 289 | ===================== 290 | */ 291 | 292 | boolean P_CheckSight (mobj_t *t1, mobj_t *t2) 293 | { 294 | int32_t s1, s2; 295 | int32_t pnum, bytenum, bitnum; 296 | 297 | // 298 | // check for trivial rejection 299 | // 300 | s1 = (t1->subsector->sector - sectors); 301 | s2 = (t2->subsector->sector - sectors); 302 | pnum = s1*numsectors + s2; 303 | bytenum = pnum>>3; 304 | bitnum = 1 << (pnum&7); 305 | 306 | if (rejectmatrix[bytenum]&bitnum) 307 | { 308 | return false; // can't possibly be connected 309 | } 310 | 311 | validcount++; 312 | 313 | sightzstart = t1->z + t1->height - (t1->height>>2); 314 | topslope = (t2->z+t2->height) - sightzstart; 315 | bottomslope = (t2->z) - sightzstart; 316 | 317 | strace.x = t1->x; 318 | strace.y = t1->y; 319 | t2x = t2->x; 320 | t2y = t2->y; 321 | strace.dx = t2->x - t1->x; 322 | strace.dy = t2->y - t1->y; 323 | return P_CrossBSPNode (numnodes-1); // the head node is the last node output 324 | } 325 | 326 | 327 | -------------------------------------------------------------------------------- /p_telept.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 1993-1996 Id Software, Inc. 3 | // Copyright (C) 2023 Frenkel Smeijers 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | 19 | // P_telept.c 20 | 21 | #include "doomdef.h" 22 | #include "p_local.h" 23 | #include "soundst.h" 24 | 25 | //================================================================== 26 | // 27 | // TELEPORTATION 28 | // 29 | //================================================================== 30 | void EV_Teleport( line_t *line, int32_t side, mobj_t *thing ) 31 | { 32 | int32_t i; 33 | int32_t tag; 34 | mobj_t *m,*fog; 35 | uint32_t an; 36 | thinker_t *thinker; 37 | sector_t *sector; 38 | fixed_t oldx, oldy, oldz; 39 | 40 | if (thing->flags & MF_MISSILE) 41 | return; // don't teleport missiles 42 | 43 | if (side == 1) // don't teleport if hit back of line, 44 | return; // so you can get out of teleporter 45 | 46 | tag = line->tag; 47 | for (i = 0; i < numsectors; i++) 48 | if (sectors[ i ].tag == tag ) 49 | { 50 | thinker = thinkercap.next; 51 | for (thinker = thinkercap.next; thinker != &thinkercap; 52 | thinker = thinker->next) 53 | { 54 | if (thinker->function != P_MobjThinker) 55 | continue; // not a mobj 56 | m = (mobj_t *)thinker; 57 | if (m->type != MT_TELEPORTMAN ) 58 | continue; // not a teleportman 59 | sector = m->subsector->sector; 60 | if (sector-sectors != i ) 61 | continue; // wrong sector 62 | 63 | oldx = thing->x; 64 | oldy = thing->y; 65 | oldz = thing->z; 66 | if (!P_TeleportMove (thing, m->x, m->y)) 67 | return; 68 | #if (APPVER_DOOMREV != AV_DR_DM19F) 69 | thing->z = thing->floorz; //fixme: not needed? 70 | #endif 71 | if (thing->player) 72 | thing->player->viewz = thing->z+thing->player->viewheight; 73 | // spawn teleport fog at source and destination 74 | fog = P_SpawnMobj (oldx, oldy, oldz, MT_TFOG); 75 | S_StartSound (fog, sfx_telept); 76 | an = m->angle >> ANGLETOFINESHIFT; 77 | fog = P_SpawnMobj (m->x+20*finecosine[an], m->y+20*finesine[an] 78 | , thing->z, MT_TFOG); 79 | S_StartSound (fog, sfx_telept); 80 | if (thing->player) 81 | thing->reactiontime = 18; // don't move for a bit 82 | thing->angle = m->angle; 83 | thing->momx = thing->momy = thing->momz = 0; 84 | return; 85 | } 86 | } 87 | } 88 | 89 | -------------------------------------------------------------------------------- /p_user.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 1993-1996 Id Software, Inc. 3 | // Copyright (C) 2023 Frenkel Smeijers 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | 19 | // P_user.c 20 | 21 | #include "doomdef.h" 22 | #include "p_local.h" 23 | #include "soundst.h" 24 | 25 | /* 26 | =============================================================================== 27 | 28 | movement 29 | 30 | =============================================================================== 31 | */ 32 | 33 | #define MAXBOB 0x100000 // 16 pixels of bob 34 | 35 | static boolean onground; 36 | 37 | /* 38 | ================== 39 | = 40 | = P_Thrust 41 | = 42 | = moves the given origin along a given angle 43 | = 44 | ================== 45 | */ 46 | 47 | static void P_Thrust (player_t *player, angle_t angle, fixed_t move) 48 | { 49 | angle >>= ANGLETOFINESHIFT; 50 | player->mo->momx += FixedMul(move,finecosine[angle]); 51 | player->mo->momy += FixedMul(move,finesine[angle]); 52 | } 53 | 54 | 55 | /* 56 | ================== 57 | = 58 | = P_CalcHeight 59 | = 60 | =Calculate the walking / running height adjustment 61 | = 62 | ================== 63 | */ 64 | 65 | static void P_CalcHeight (player_t *player) 66 | { 67 | int32_t angle; 68 | fixed_t bob; 69 | 70 | 71 | // 72 | // regular movement bobbing (needs to be calculated for gun swing even 73 | // if not on ground) 74 | // OPTIMIZE: tablify angle 75 | player->bob = FixedMul (player->mo->momx, player->mo->momx)+ 76 | FixedMul (player->mo->momy,player->mo->momy); 77 | player->bob >>= 2; 78 | if (player->bob>MAXBOB) 79 | player->bob = MAXBOB; 80 | 81 | if ((player->cheats & CF_NOMOMENTUM) || !onground) 82 | { 83 | player->viewz = player->mo->z + VIEWHEIGHT; 84 | if (player->viewz > player->mo->ceilingz-4*FRACUNIT) 85 | player->viewz = player->mo->ceilingz-4*FRACUNIT; 86 | player->viewz = player->mo->z + player->viewheight; 87 | return; 88 | } 89 | 90 | angle = (FINEANGLES/20*leveltime)&FINEMASK; 91 | bob = FixedMul ( player->bob/2, finesine[angle]); 92 | 93 | // 94 | // move viewheight 95 | // 96 | if (player->playerstate == PST_LIVE) 97 | { 98 | player->viewheight += player->deltaviewheight; 99 | if (player->viewheight > VIEWHEIGHT) 100 | { 101 | player->viewheight = VIEWHEIGHT; 102 | player->deltaviewheight = 0; 103 | } 104 | if (player->viewheight < VIEWHEIGHT/2) 105 | { 106 | player->viewheight = VIEWHEIGHT/2; 107 | if (player->deltaviewheight <= 0) 108 | player->deltaviewheight = 1; 109 | } 110 | 111 | if (player->deltaviewheight) 112 | { 113 | player->deltaviewheight += FRACUNIT/4; 114 | if (!player->deltaviewheight) 115 | player->deltaviewheight = 1; 116 | } 117 | } 118 | player->viewz = player->mo->z + player->viewheight + bob; 119 | if (player->viewz > player->mo->ceilingz-4*FRACUNIT) 120 | player->viewz = player->mo->ceilingz-4*FRACUNIT; 121 | } 122 | 123 | /* 124 | ================= 125 | = 126 | = P_MovePlayer 127 | = 128 | ================= 129 | */ 130 | 131 | static void P_MovePlayer (player_t *player) 132 | { 133 | ticcmd_t *cmd; 134 | 135 | cmd = &player->cmd; 136 | player->mo->angle += (cmd->angleturn<<16); 137 | 138 | // don't let the player control movement if not onground 139 | onground = (player->mo->z <= player->mo->floorz); 140 | 141 | if (cmd->forwardmove && onground) 142 | P_Thrust (player, player->mo->angle, cmd->forwardmove*2048); 143 | if (cmd->sidemove && onground) 144 | P_Thrust (player, player->mo->angle-ANG90, cmd->sidemove*2048); 145 | 146 | if ( (cmd->forwardmove || cmd->sidemove) 147 | && player->mo->state == &states[S_PLAY] ) 148 | P_SetMobjState (player->mo, S_PLAY_RUN1); 149 | 150 | } 151 | 152 | /* 153 | ================= 154 | = 155 | = P_DeathThink 156 | = 157 | ================= 158 | */ 159 | 160 | #define ANG5 (ANG90/18) 161 | 162 | static void P_DeathThink (player_t *player) 163 | { 164 | angle_t angle, delta; 165 | 166 | P_MovePsprites (player); 167 | 168 | // fall to the ground 169 | if (player->viewheight > 6*FRACUNIT) 170 | player->viewheight -= FRACUNIT; 171 | if (player->viewheight < 6*FRACUNIT) 172 | player->viewheight = 6*FRACUNIT; 173 | player->deltaviewheight = 0; 174 | onground = (player->mo->z <= player->mo->floorz); 175 | P_CalcHeight (player); 176 | 177 | if (player->attacker && player->attacker != player->mo) 178 | { 179 | angle = R_PointToAngle2 (player->mo->x, player->mo->y 180 | , player->attacker->x, player->attacker->y); 181 | delta = angle - player->mo->angle; 182 | if (delta < ANG5 || delta > (uint32_t)-ANG5) 183 | { // looking at killer, so fade damage flash down 184 | player->mo->angle = angle; 185 | if (player->damagecount) 186 | player->damagecount--; 187 | } 188 | else if (delta < ANG180) 189 | player->mo->angle += ANG5; 190 | else 191 | player->mo->angle -= ANG5; 192 | } 193 | else if (player->damagecount) 194 | player->damagecount--; 195 | 196 | 197 | if (player->cmd.buttons & BT_USE) 198 | player->playerstate = PST_REBORN; 199 | } 200 | 201 | 202 | 203 | /* 204 | ================= 205 | = 206 | = P_PlayerThink 207 | = 208 | ================= 209 | */ 210 | 211 | void P_PlayerThink (player_t *player) 212 | { 213 | ticcmd_t *cmd; 214 | weapontype_t newweapon; 215 | 216 | // fixme: do this in the cheat code 217 | if (player->cheats & CF_NOCLIP) 218 | player->mo->flags |= MF_NOCLIP; 219 | else 220 | player->mo->flags &= ~MF_NOCLIP; 221 | 222 | // 223 | // chain saw run forward 224 | // 225 | cmd = &player->cmd; 226 | if (player->mo->flags & MF_JUSTATTACKED) 227 | { 228 | cmd->angleturn = 0; 229 | cmd->forwardmove = 0xc800/512; 230 | cmd->sidemove = 0; 231 | player->mo->flags &= ~MF_JUSTATTACKED; 232 | } 233 | 234 | 235 | if (player->playerstate == PST_DEAD) 236 | { 237 | P_DeathThink (player); 238 | return; 239 | } 240 | 241 | // 242 | // move around 243 | // reactiontime is used to prevent movement for a bit after a teleport 244 | if (player->mo->reactiontime) 245 | player->mo->reactiontime--; 246 | else 247 | P_MovePlayer (player); 248 | P_CalcHeight (player); 249 | if (player->mo->subsector->sector->special) 250 | P_PlayerInSpecialSector (player); 251 | 252 | // 253 | // check for weapon change 254 | // 255 | if (cmd->buttons & BT_SPECIAL) 256 | cmd->buttons = 0; // A special event has no other buttons 257 | 258 | if (cmd->buttons & BT_CHANGE) 259 | { 260 | // The actual changing of the weapon is done 261 | // when the weapon psprite can do it 262 | // (read: not in the middle of an attack). 263 | newweapon = (cmd->buttons&BT_WEAPONMASK)>>BT_WEAPONSHIFT; 264 | 265 | if (newweapon == wp_fist && player->weaponowned[wp_chainsaw] && 266 | !(player->readyweapon == wp_chainsaw && player->powers[pw_strength])) 267 | newweapon = wp_chainsaw; 268 | if (commercial && newweapon == wp_shotgun && player->weaponowned[wp_supershotgun] && 269 | player->readyweapon != wp_supershotgun) 270 | newweapon = wp_supershotgun; 271 | 272 | if (player->weaponowned[newweapon] 273 | && newweapon != player->readyweapon) 274 | { // Do not go to plasma or BFG in shareware, even if cheated. 275 | if ((newweapon != wp_plasma && newweapon != wp_bfg) || !shareware ) 276 | player->pendingweapon = newweapon; 277 | } 278 | } 279 | 280 | // 281 | // check for use 282 | // 283 | if (cmd->buttons & BT_USE) 284 | { 285 | if (!player->usedown) 286 | { 287 | P_UseLines (player); 288 | player->usedown = true; 289 | } 290 | } 291 | else 292 | player->usedown = false; 293 | 294 | // 295 | // cycle psprites 296 | // 297 | P_MovePsprites (player); 298 | 299 | 300 | // 301 | // counters 302 | // 303 | if (player->powers[pw_strength]) 304 | player->powers[pw_strength]++; // strength counts up to diminish fade 305 | 306 | if (player->powers[pw_invulnerability]) 307 | player->powers[pw_invulnerability]--; 308 | 309 | if (player->powers[pw_invisibility]) 310 | if (! --player->powers[pw_invisibility] ) 311 | player->mo->flags &= ~MF_SHADOW; 312 | 313 | if (player->powers[pw_infrared]) 314 | player->powers[pw_infrared]--; 315 | 316 | if (player->powers[pw_ironfeet]) 317 | player->powers[pw_ironfeet]--; 318 | 319 | if (player->damagecount) 320 | player->damagecount--; 321 | 322 | if (player->bonuscount) 323 | player->bonuscount--; 324 | 325 | if (player->powers[pw_invulnerability]) 326 | { 327 | if (player->powers[pw_invulnerability] > 4*32 328 | || (player->powers[pw_invulnerability]&8) ) 329 | player->fixedcolormap = INVERSECOLORMAP; 330 | else 331 | player->fixedcolormap = 0; 332 | } 333 | else if (player->powers[pw_infrared]) 334 | { 335 | if (player->powers[pw_infrared] > 4*32 336 | || (player->powers[pw_infrared]&8) ) 337 | { // almost full bright 338 | player->fixedcolormap = 1; 339 | } 340 | else 341 | player->fixedcolormap = 0; 342 | } 343 | else 344 | player->fixedcolormap = 0; 345 | } 346 | 347 | 348 | -------------------------------------------------------------------------------- /setenvdj.bat: -------------------------------------------------------------------------------- 1 | SET PATH=C:\Progs\nasm-2.16.01;%PATH% 2 | C:\Progs\djgpp\setenv.bat 3 | -------------------------------------------------------------------------------- /setenvdm.bat: -------------------------------------------------------------------------------- 1 | SET PATH=C:\Progs\nasm-2.16.01;C:\Progs\DM\BIN;%PATH% 2 | -------------------------------------------------------------------------------- /setenvoc.bat: -------------------------------------------------------------------------------- 1 | SET LADSOFT=C:\Progs\cc386 2 | SET PATH=C:\Progs\nasm-2.16.01;%LADSOFT%\bin;%PATH% 3 | -------------------------------------------------------------------------------- /setenvwc.bat: -------------------------------------------------------------------------------- 1 | SET WATCOM=C:\DOS\PROGTAAL\WATCOM 2 | SET INCLUDE=%WATCOM%\H 3 | SET PATH=C:\Progs\nasm-2.16.01;%WATCOM%\BINNT64;%WATCOM%\BINNT;%PATH% 4 | -------------------------------------------------------------------------------- /sounds.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 1993-1996 Id Software, Inc. 3 | // Copyright (C) 2023 Frenkel Smeijers 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | 19 | // sounds.c 20 | 21 | #include "doomdef.h" 22 | #include "sounds.h" 23 | 24 | // Music info 25 | 26 | musicinfo_t S_music[] = 27 | { 28 | { 0 }, 29 | { "e1m1", 0 }, 30 | { "e1m2", 0 }, 31 | { "e1m3", 0 }, 32 | { "e1m4", 0 }, 33 | { "e1m5", 0 }, 34 | { "e1m6", 0 }, 35 | { "e1m7", 0 }, 36 | { "e1m8", 0 }, 37 | { "e1m9", 0 }, 38 | { "e2m1", 0 }, 39 | { "e2m2", 0 }, 40 | { "e2m3", 0 }, 41 | { "e2m4", 0 }, 42 | { "e2m5", 0 }, 43 | { "e2m6", 0 }, 44 | { "e2m7", 0 }, 45 | { "e2m8", 0 }, 46 | { "e2m9", 0 }, 47 | { "e3m1", 0 }, 48 | { "e3m2", 0 }, 49 | { "e3m3", 0 }, 50 | { "e3m4", 0 }, 51 | { "e3m5", 0 }, 52 | { "e3m6", 0 }, 53 | { "e3m7", 0 }, 54 | { "e3m8", 0 }, 55 | { "e3m9", 0 }, 56 | { "inter", 0 }, 57 | { "intro", 0 }, 58 | { "bunny", 0 }, 59 | { "victor", 0 }, 60 | { "introa", 0 }, 61 | { "runnin", 0 }, 62 | { "stalks", 0 }, 63 | { "countd", 0 }, 64 | { "betwee", 0 }, 65 | { "doom", 0 }, 66 | { "the_da", 0 }, 67 | { "shawn", 0 }, 68 | { "ddtblu", 0 }, 69 | { "in_cit", 0 }, 70 | { "dead", 0 }, 71 | { "stlks2", 0 }, 72 | { "theda2", 0 }, 73 | { "doom2", 0 }, 74 | { "ddtbl2", 0 }, 75 | { "runni2", 0 }, 76 | { "dead2", 0 }, 77 | { "stlks3", 0 }, 78 | { "romero", 0 }, 79 | { "shawn2", 0 }, 80 | { "messag", 0 }, 81 | { "count2", 0 }, 82 | { "ddtbl3", 0 }, 83 | { "ampie", 0 }, 84 | { "theda3", 0 }, 85 | { "adrian", 0 }, 86 | { "messg2", 0 }, 87 | { "romer2", 0 }, 88 | { "tense", 0 }, 89 | { "shawn3", 0 }, 90 | { "openin", 0 }, 91 | { "evil", 0 }, 92 | { "ultima", 0 }, 93 | { "read_m", 0 }, 94 | { "dm2ttl", 0 }, 95 | { "dm2int", 0 } 96 | }; 97 | 98 | // Sound info 99 | 100 | sfxinfo_t S_sfx[] = 101 | { 102 | { 0 }, 103 | { "pistol", false, 64, 0, -1, -1, 0 }, 104 | { "shotgn", false, 64, 0, -1, -1, 0 }, 105 | { "sgcock", false, 64, 0, -1, -1, 0 }, 106 | { "dshtgn", false, 64, 0, -1, -1, 0 }, 107 | { "dbopn", false, 64, 0, -1, -1, 0 }, 108 | { "dbcls", false, 64, 0, -1, -1, 0 }, 109 | { "dbload", false, 64, 0, -1, -1, 0 }, 110 | { "plasma", false, 64, 0, -1, -1, 0 }, 111 | { "bfg", false, 64, 0, -1, -1, 0 }, 112 | { "sawup", false, 64, 0, -1, -1, 0 }, 113 | { "sawidl", false, 118, 0, -1, -1, 0 }, 114 | { "sawful", false, 64, 0, -1, -1, 0 }, 115 | { "sawhit", false, 64, 0, -1, -1, 0 }, 116 | { "rlaunc", false, 64, 0, -1, -1, 0 }, 117 | { "rxplod", false, 70, 0, -1, -1, 0 }, 118 | { "firsht", false, 70, 0, -1, -1, 0 }, 119 | { "firxpl", false, 70, 0, -1, -1, 0 }, 120 | { "pstart", false, 100, 0, -1, -1, 0 }, 121 | { "pstop", false, 100, 0, -1, -1, 0 }, 122 | { "doropn", false, 100, 0, -1, -1, 0 }, 123 | { "dorcls", false, 100, 0, -1, -1, 0 }, 124 | { "stnmov", false, 119, 0, -1, -1, 0 }, 125 | { "swtchn", false, 78, 0, -1, -1, 0 }, 126 | { "swtchx", false, 78, 0, -1, -1, 0 }, 127 | { "plpain", false, 96, 0, -1, -1, 0 }, 128 | { "dmpain", false, 96, 0, -1, -1, 0 }, 129 | { "popain", false, 96, 0, -1, -1, 0 }, 130 | { "vipain", false, 96, 0, -1, -1, 0 }, 131 | { "mnpain", false, 96, 0, -1, -1, 0 }, 132 | { "pepain", false, 96, 0, -1, -1, 0 }, 133 | { "slop", false, 78, 0, -1, -1, 0 }, 134 | { "itemup", true, 78, 0, -1, -1, 0 }, 135 | { "wpnup", true, 78, 0, -1, -1, 0 }, 136 | { "oof", false, 96, 0, -1, -1, 0 }, 137 | { "telept", false, 32, 0, -1, -1, 0 }, 138 | { "posit1", true, 98, 0, -1, -1, 0 }, 139 | { "posit2", true, 98, 0, -1, -1, 0 }, 140 | { "posit3", true, 98, 0, -1, -1, 0 }, 141 | { "bgsit1", true, 98, 0, -1, -1, 0 }, 142 | { "bgsit2", true, 98, 0, -1, -1, 0 }, 143 | { "sgtsit", true, 98, 0, -1, -1, 0 }, 144 | { "cacsit", true, 98, 0, -1, -1, 0 }, 145 | { "brssit", true, 94, 0, -1, -1, 0 }, 146 | { "cybsit", true, 92, 0, -1, -1, 0 }, 147 | { "spisit", true, 90, 0, -1, -1, 0 }, 148 | { "bspsit", true, 90, 0, -1, -1, 0 }, 149 | { "kntsit", true, 90, 0, -1, -1, 0 }, 150 | { "vilsit", true, 90, 0, -1, -1, 0 }, 151 | { "mansit", true, 90, 0, -1, -1, 0 }, 152 | { "pesit", true, 90, 0, -1, -1, 0 }, 153 | { "sklatk", false, 70, 0, -1, -1, 0 }, 154 | { "sgtatk", false, 70, 0, -1, -1, 0 }, 155 | { "skepch", false, 70, 0, -1, -1, 0 }, 156 | { "vilatk", false, 70, 0, -1, -1, 0 }, 157 | { "claw", false, 70, 0, -1, -1, 0 }, 158 | { "skeswg", false, 70, 0, -1, -1, 0 }, 159 | { "pldeth", false, 32, 0, -1, -1, 0 }, 160 | { "pdiehi", false, 32, 0, -1, -1, 0 }, 161 | { "podth1", false, 70, 0, -1, -1, 0 }, 162 | { "podth2", false, 70, 0, -1, -1, 0 }, 163 | { "podth3", false, 70, 0, -1, -1, 0 }, 164 | { "bgdth1", false, 70, 0, -1, -1, 0 }, 165 | { "bgdth2", false, 70, 0, -1, -1, 0 }, 166 | { "sgtdth", false, 70, 0, -1, -1, 0 }, 167 | { "cacdth", false, 70, 0, -1, -1, 0 }, 168 | { "skldth", false, 70, 0, -1, -1, 0 }, 169 | { "brsdth", false, 32, 0, -1, -1, 0 }, 170 | { "cybdth", false, 32, 0, -1, -1, 0 }, 171 | { "spidth", false, 32, 0, -1, -1, 0 }, 172 | { "bspdth", false, 32, 0, -1, -1, 0 }, 173 | { "vildth", false, 32, 0, -1, -1, 0 }, 174 | { "kntdth", false, 32, 0, -1, -1, 0 }, 175 | { "pedth", false, 32, 0, -1, -1, 0 }, 176 | { "skedth", false, 32, 0, -1, -1, 0 }, 177 | { "posact", true, 120, 0, -1, -1, 0 }, 178 | { "bgact", true, 120, 0, -1, -1, 0 }, 179 | { "dmact", true, 120, 0, -1, -1, 0 }, 180 | { "bspact", true, 100, 0, -1, -1, 0 }, 181 | { "bspwlk", true, 100, 0, -1, -1, 0 }, 182 | { "vilact", true, 100, 0, -1, -1, 0 }, 183 | { "noway", false, 78, 0, -1, -1, 0 }, 184 | { "barexp", false, 60, 0, -1, -1, 0 }, 185 | { "punch", false, 64, 0, -1, -1, 0 }, 186 | { "hoof", false, 70, 0, -1, -1, 0 }, 187 | { "metal", false, 70, 0, -1, -1, 0 }, 188 | { "chgun", false, 64, &S_sfx[sfx_pistol], 150, 0, 0 }, 189 | { "tink", false, 60, 0, -1, -1, 0 }, 190 | { "bdopn", false, 100, 0, -1, -1, 0 }, 191 | { "bdcls", false, 100, 0, -1, -1, 0 }, 192 | { "itmbk", false, 100, 0, -1, -1, 0 }, 193 | { "flame", false, 32, 0, -1, -1, 0 }, 194 | { "flamst", false, 32, 0, -1, -1, 0 }, 195 | { "getpow", false, 60, 0, -1, -1, 0 }, 196 | { "bospit", false, 70, 0, -1, -1, 0 }, 197 | { "boscub", false, 70, 0, -1, -1, 0 }, 198 | { "bossit", false, 70, 0, -1, -1, 0 }, 199 | { "bospn", false, 70, 0, -1, -1, 0 }, 200 | { "bosdth", false, 70, 0, -1, -1, 0 }, 201 | { "manatk", false, 70, 0, -1, -1, 0 }, 202 | { "mandth", false, 70, 0, -1, -1, 0 }, 203 | { "sssit", false, 70, 0, -1, -1, 0 }, 204 | { "ssdth", false, 70, 0, -1, -1, 0 }, 205 | { "keenpn", false, 70, 0, -1, -1, 0 }, 206 | { "keendt", false, 70, 0, -1, -1, 0 }, 207 | { "skeact", false, 70, 0, -1, -1, 0 }, 208 | { "skesit", false, 70, 0, -1, -1, 0 }, 209 | { "skeatk", false, 70, 0, -1, -1, 0 }, 210 | { "radio", false, 60, 0, -1, -1, 0 } 211 | }; 212 | -------------------------------------------------------------------------------- /sounds.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 1993-1996 Id Software, Inc. 3 | // 4 | // This program is free software; you can redistribute it and/or 5 | // modify it under the terms of the GNU General Public License 6 | // as published by the Free Software Foundation; either version 2 7 | // of the License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | // 17 | 18 | // sounds.h 19 | 20 | #ifndef __SOUNDSH__ 21 | #define __SOUNDSH__ 22 | 23 | #include "soundst.h" 24 | 25 | // Music identifiers 26 | 27 | typedef enum 28 | { 29 | mus_None, 30 | mus_e1m1, 31 | mus_e1m2, 32 | mus_e1m3, 33 | mus_e1m4, 34 | mus_e1m5, 35 | mus_e1m6, 36 | mus_e1m7, 37 | mus_e1m8, 38 | mus_e1m9, 39 | mus_e2m1, 40 | mus_e2m2, 41 | mus_e2m3, 42 | mus_e2m4, 43 | mus_e2m5, 44 | mus_e2m6, 45 | mus_e2m7, 46 | mus_e2m8, 47 | mus_e2m9, 48 | mus_e3m1, 49 | mus_e3m2, 50 | mus_e3m3, 51 | mus_e3m4, 52 | mus_e3m5, 53 | mus_e3m6, 54 | mus_e3m7, 55 | mus_e3m8, 56 | mus_e3m9, 57 | mus_inter, 58 | mus_intro, 59 | mus_bunny, 60 | mus_victor, 61 | mus_introa, 62 | mus_runnin, 63 | mus_stalks, 64 | mus_countd, 65 | mus_betwee, 66 | mus_doom, 67 | mus_the_da, 68 | mus_shawn, 69 | mus_ddtblu, 70 | mus_in_cit, 71 | mus_dead, 72 | mus_stlks2, 73 | mus_theda2, 74 | mus_doom2, 75 | mus_ddtbl2, 76 | mus_runni2, 77 | mus_dead2, 78 | mus_stlks3, 79 | mus_romero, 80 | mus_shawn2, 81 | mus_messag, 82 | mus_count2, 83 | mus_ddtbl3, 84 | mus_ampie, 85 | mus_theda3, 86 | mus_adrian, 87 | mus_messg2, 88 | mus_romer2, 89 | mus_tense, 90 | mus_shawn3, 91 | mus_openin, 92 | mus_evil, 93 | mus_ultima, 94 | mus_read_m, 95 | mus_dm2ttl, 96 | mus_dm2int, 97 | NUMMUSIC 98 | } musicenum_t; 99 | 100 | // Sound identifiers 101 | 102 | typedef enum 103 | { 104 | sfx_None, 105 | sfx_pistol, 106 | sfx_shotgn, 107 | sfx_sgcock, 108 | sfx_dshtgn, 109 | sfx_dbopn, 110 | sfx_dbcls, 111 | sfx_dbload, 112 | sfx_plasma, 113 | sfx_bfg, 114 | sfx_sawup, 115 | sfx_sawidl, 116 | sfx_sawful, 117 | sfx_sawhit, 118 | sfx_rlaunc, 119 | sfx_rxplod, 120 | sfx_firsht, 121 | sfx_firxpl, 122 | sfx_pstart, 123 | sfx_pstop, 124 | sfx_doropn, 125 | sfx_dorcls, 126 | sfx_stnmov, 127 | sfx_swtchn, 128 | sfx_swtchx, 129 | sfx_plpain, 130 | sfx_dmpain, 131 | sfx_popain, 132 | sfx_vipain, 133 | sfx_mnpain, 134 | sfx_pepain, 135 | sfx_slop, 136 | sfx_itemup, 137 | sfx_wpnup, 138 | sfx_oof, 139 | sfx_telept, 140 | sfx_posit1, 141 | sfx_posit2, 142 | sfx_posit3, 143 | sfx_bgsit1, 144 | sfx_bgsit2, 145 | sfx_sgtsit, 146 | sfx_cacsit, 147 | sfx_brssit, 148 | sfx_cybsit, 149 | sfx_spisit, 150 | sfx_bspsit, 151 | sfx_kntsit, 152 | sfx_vilsit, 153 | sfx_mansit, 154 | sfx_pesit, 155 | sfx_sklatk, 156 | sfx_sgtatk, 157 | sfx_skepch, 158 | sfx_vilatk, 159 | sfx_claw, 160 | sfx_skeswg, 161 | sfx_pldeth, 162 | sfx_pdiehi, 163 | sfx_podth1, 164 | sfx_podth2, 165 | sfx_podth3, 166 | sfx_bgdth1, 167 | sfx_bgdth2, 168 | sfx_sgtdth, 169 | sfx_cacdth, 170 | sfx_skldth, 171 | sfx_brsdth, 172 | sfx_cybdth, 173 | sfx_spidth, 174 | sfx_bspdth, 175 | sfx_vildth, 176 | sfx_kntdth, 177 | sfx_pedth, 178 | sfx_skedth, 179 | sfx_posact, 180 | sfx_bgact, 181 | sfx_dmact, 182 | sfx_bspact, 183 | sfx_bspwlk, 184 | sfx_vilact, 185 | sfx_noway, 186 | sfx_barexp, 187 | sfx_punch, 188 | sfx_hoof, 189 | sfx_metal, 190 | sfx_chgun, 191 | sfx_tink, 192 | sfx_bdopn, 193 | sfx_bdcls, 194 | sfx_itmbk, 195 | sfx_flame, 196 | sfx_flamst, 197 | sfx_getpow, 198 | sfx_bospit, 199 | sfx_boscub, 200 | sfx_bossit, 201 | sfx_bospn, 202 | sfx_bosdth, 203 | sfx_manatk, 204 | sfx_mandth, 205 | sfx_sssit, 206 | sfx_ssdth, 207 | sfx_keenpn, 208 | sfx_keendt, 209 | sfx_skeact, 210 | sfx_skesit, 211 | sfx_skeatk, 212 | sfx_radio, 213 | NUMSFX 214 | } sfxenum_t; 215 | 216 | #endif 217 | -------------------------------------------------------------------------------- /soundst.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 1993-1996 Id Software, Inc. 3 | // Copyright (C) 2023 Frenkel Smeijers 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | 19 | // soundst.h 20 | 21 | #ifndef __SOUNDSTH__ 22 | #define __SOUNDSTH__ 23 | 24 | #define S_MAX_VOLUME 127 25 | 26 | // when to clip out sounds 27 | // Doesn't fit the large outdoor areas. 28 | #define S_CLIPPING_DIST (1200*0x10000) 29 | 30 | // when sounds should be max'd out 31 | #define S_CLOSE_DIST (200*0x10000) 32 | 33 | 34 | #define S_ATTENUATOR ((S_CLIPPING_DIST-S_CLOSE_DIST)>>FRACBITS) 35 | 36 | #define NORM_PITCH 128 37 | 38 | #define NORM_SEP 128 39 | #define S_STEREO_SWING (96*0x10000) 40 | 41 | typedef struct 42 | { 43 | char *name; // up to 6-character name 44 | int32_t lumpnum; // lump number of music 45 | void *data; // music data 46 | int32_t handle; // music handle once registered 47 | } musicinfo_t; 48 | 49 | typedef struct sfxinfo_s 50 | { 51 | char *name; // up to 6-character name 52 | int32_t singularity; // Sfx singularity (only one at a time) 53 | int32_t priority; // Sfx priority 54 | struct sfxinfo_s *link; // referenced sound if a link 55 | int32_t pitch; // pitch if a link 56 | int32_t volume; // volume if a link 57 | void *data; // sound data 58 | int32_t usefulness; // Determines when a sound should be cached out 59 | int32_t lumpnum; // lump number of sfx 60 | } sfxinfo_t; 61 | 62 | typedef struct 63 | { 64 | sfxinfo_t *sfxinfo; // sound information (if null, channel avail.) 65 | void *origin; // origin of sound 66 | int32_t handle; // handle of the sound being played 67 | } channel_t; 68 | 69 | 70 | 71 | void S_Start(void); 72 | void S_StartSound(void *origin, int32_t sound_id); 73 | void S_StopSound(void *origin); 74 | void S_StartMusic(int32_t music_id); 75 | void S_ChangeMusic(int32_t music_id, boolean looping); 76 | void S_PauseSound(void); 77 | void S_ResumeSound(void); 78 | void S_UpdateSounds(void *listener); 79 | void S_SetMusicVolume(int32_t volume); 80 | void S_SetSfxVolume(int32_t volume); 81 | void S_Init(int32_t,int32_t); 82 | 83 | //-------- 84 | //SOUND IO 85 | //-------- 86 | void I_SetMusicVolume(int32_t volume); 87 | 88 | // 89 | // MUSIC I/O 90 | // 91 | void I_PauseSong(int32_t handle); 92 | void I_ResumeSong(int32_t handle); 93 | 94 | // 95 | // Called by anything that wishes to start music. 96 | // plays a song, and when the song is done, 97 | // starts playing it again in an endless loop. 98 | // Horrible thing to do, considering. 99 | void I_PlaySong(int32_t handle, boolean looping); 100 | 101 | 102 | // stops a song over 3 seconds. 103 | void I_StopSong(int32_t handle); 104 | 105 | // registers a song handle to song data 106 | int32_t I_RegisterSong(void *data); 107 | 108 | // see above then think backwards 109 | void I_UnRegisterSong(int32_t handle); 110 | 111 | 112 | // 113 | // SFX I/O 114 | // 115 | void I_SetChannels(int32_t channels); 116 | 117 | int32_t I_GetSfxLumpNum (sfxinfo_t*); 118 | 119 | 120 | // Starts a sound in a particular sound channel. 121 | int32_t I_StartSound(void *data, int32_t vol, int32_t sep, int32_t pitch); 122 | 123 | 124 | // Updates the volume, separation, 125 | // and pitch of a sound channel. 126 | void I_UpdateSoundParams(int32_t handle, int32_t vol, int32_t sep, int32_t pitch); 127 | 128 | 129 | // Stops a sound channel. 130 | void I_StopSound(int32_t handle); 131 | 132 | // Called by S_*()'s to see if a channel is still playing. 133 | // Returns false if no longer playing, true if playing. 134 | boolean I_SoundIsPlaying(int32_t handle); 135 | 136 | 137 | // the complete set of sound effects 138 | extern sfxinfo_t S_sfx[]; 139 | 140 | // the complete set of music 141 | extern musicinfo_t S_music[]; 142 | 143 | #endif 144 | -------------------------------------------------------------------------------- /st_lib.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 1993-1996 Id Software, Inc. 3 | // Copyright (C) 2023 Frenkel Smeijers 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | 19 | // ST_lib.c 20 | #include "doomdef.h" 21 | #include "st_lib.h" 22 | 23 | 24 | // in AM_map.c 25 | extern boolean automapactive; 26 | 27 | static patch_t *sttminus; 28 | 29 | void STlib_init(void) 30 | { 31 | sttminus = (patch_t *) W_CacheLumpName("STTMINUS", PU_STATIC); 32 | } 33 | 34 | 35 | void STlib_initNum (st_number_t *n, int32_t x, int32_t y, patch_t **pl, int32_t *num, boolean *on, int32_t width) 36 | { 37 | n->x = x; 38 | n->y = y; 39 | n->oldnum = 0; 40 | n->width = width; 41 | n->num = num; 42 | n->on = on; 43 | n->p = pl; 44 | } 45 | 46 | 47 | static void STlib_drawNum (st_number_t *n) 48 | { 49 | 50 | int32_t numdigits = n->width; 51 | int32_t num = *n->num; 52 | 53 | int32_t w = SHORT(n->p[0]->width); 54 | int32_t h = SHORT(n->p[0]->height); 55 | int32_t x = n->x; 56 | 57 | boolean neg; 58 | 59 | n->oldnum = *n->num; 60 | 61 | neg = num < 0; 62 | 63 | if (neg) 64 | { 65 | if (numdigits == 2 && num < -9) 66 | num = -9; 67 | else if (numdigits == 3 && num < -99) 68 | num = -99; 69 | 70 | num = -num; 71 | } 72 | 73 | // clear the area 74 | x = n->x - numdigits*w; 75 | 76 | if (n->y - ST_Y < 0) 77 | I_Error("drawNum: n->y - ST_Y < 0"); 78 | 79 | V_CopyRect(x, n->y - ST_Y, w*numdigits, h, n->y); 80 | 81 | // if non-number, do not draw it 82 | if (num == 1994) 83 | return; 84 | 85 | x = n->x; 86 | 87 | // in the special case of 0, you draw 0 88 | if (!num) 89 | V_DrawPatch(x - w, n->y, FG, n->p[ 0 ]); 90 | 91 | // draw the new number 92 | while (num && numdigits--) 93 | { 94 | x -= w; 95 | V_DrawPatch(x, n->y, FG, n->p[ num % 10 ]); 96 | num /= 10; 97 | } 98 | 99 | // draw a minus sign if necessary 100 | if (neg) 101 | V_DrawPatch(x - 8, n->y, FG, sttminus); 102 | } 103 | 104 | 105 | void STlib_updateNum (st_number_t *n) 106 | { 107 | if (*n->on) STlib_drawNum(n); 108 | } 109 | 110 | 111 | void STlib_initPercent (st_percent_t *p, int32_t x, int32_t y, patch_t **pl, int32_t *num, boolean *on, patch_t *percent) 112 | { 113 | STlib_initNum(&p->n, x, y, pl, num, on, 3); 114 | p->p = percent; 115 | } 116 | 117 | 118 | 119 | 120 | void STlib_updatePercent (st_percent_t *per, boolean refresh) 121 | { 122 | if (refresh && *per->n.on) 123 | V_DrawPatch(per->n.x, per->n.y, FG, per->p); 124 | 125 | STlib_updateNum(&per->n); 126 | } 127 | 128 | 129 | 130 | void STlib_initMultIcon (st_multicon_t *mi, int32_t x, int32_t y, patch_t **il, int32_t *inum, boolean *on) 131 | { 132 | mi->x = x; 133 | mi->y = y; 134 | mi->oldinum = -1; 135 | mi->inum = inum; 136 | mi->on = on; 137 | mi->p = il; 138 | } 139 | 140 | 141 | 142 | void STlib_updateMultIcon (st_multicon_t *mi, boolean refresh) 143 | { 144 | int32_t w, h, x, y; 145 | 146 | if (*mi->on && (mi->oldinum != *mi->inum || refresh) && (*mi->inum!=-1)) 147 | { 148 | if (mi->oldinum != -1) 149 | { 150 | x = mi->x - SHORT(mi->p[mi->oldinum]->leftoffset); 151 | y = mi->y - SHORT(mi->p[mi->oldinum]->topoffset); 152 | w = SHORT(mi->p[mi->oldinum]->width); 153 | h = SHORT(mi->p[mi->oldinum]->height); 154 | 155 | if (y - ST_Y < 0) 156 | I_Error("updateMultIcon: y - ST_Y < 0"); 157 | 158 | V_CopyRect(x, y-ST_Y, w, h, y); 159 | } 160 | V_DrawPatch(mi->x, mi->y, FG, mi->p[*mi->inum]); 161 | mi->oldinum = *mi->inum; 162 | } 163 | } 164 | 165 | 166 | 167 | void STlib_initBinIcon (st_binicon_t *b, int32_t x, int32_t y, patch_t *i, boolean *val, boolean *on) 168 | { 169 | b->x = x; 170 | b->y = y; 171 | b->oldval = 0; 172 | b->val = val; 173 | b->on = on; 174 | b->p = i; 175 | } 176 | 177 | 178 | 179 | void STlib_updateBinIcon (st_binicon_t *bi, boolean refresh) 180 | { 181 | int32_t w, h, x, y; 182 | 183 | if (*bi->on && (bi->oldval != *bi->val || refresh)) 184 | { 185 | x = bi->x - SHORT(bi->p->leftoffset); 186 | y = bi->y - SHORT(bi->p->topoffset); 187 | w = SHORT(bi->p->width); 188 | h = SHORT(bi->p->height); 189 | 190 | if (y - ST_Y < 0) 191 | I_Error("updateBinIcon: y - ST_Y < 0"); 192 | 193 | if (*bi->val) 194 | V_DrawPatch(bi->x, bi->y, FG, bi->p); 195 | else 196 | V_CopyRect(x, y-ST_Y, w, h, y); 197 | 198 | bi->oldval = *bi->val; 199 | } 200 | 201 | } 202 | -------------------------------------------------------------------------------- /st_lib.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 1993-1996 Id Software, Inc. 3 | // Copyright (C) 2023 Frenkel Smeijers 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | 19 | #ifndef __STLIB__ 20 | #define __STLIB__ 21 | 22 | // 23 | // Background and foreground screen numbers 24 | // 25 | #define BG 4 26 | #define FG 0 27 | 28 | // 29 | // Typedefs of widgets 30 | // 31 | 32 | // Number widget 33 | 34 | typedef struct 35 | { 36 | // upper right-hand corner 37 | // of the number (right-justified) 38 | int32_t x, y; 39 | 40 | // max # of digits in number 41 | int32_t width; 42 | 43 | // last number value 44 | int32_t oldnum; 45 | 46 | // pointer to current value 47 | int32_t *num; 48 | 49 | // pointer to boolean stating 50 | // whether to update number 51 | boolean *on; 52 | 53 | // list of patches for 0-9 54 | patch_t **p; 55 | 56 | // user data 57 | int32_t data; 58 | 59 | } st_number_t; 60 | 61 | 62 | 63 | // Percent widget ("child" of number widget, 64 | // or, more precisely, contains a number widget.) 65 | typedef struct 66 | { 67 | // number information 68 | st_number_t n; 69 | 70 | // percent sign graphic 71 | patch_t *p; 72 | 73 | } st_percent_t; 74 | 75 | 76 | 77 | // Multiple Icon widget 78 | typedef struct 79 | { 80 | // center-justified location of icons 81 | int32_t x, y; 82 | 83 | // last icon number 84 | int32_t oldinum; 85 | 86 | // pointer to current icon 87 | int32_t *inum; 88 | 89 | // pointer to boolean stating 90 | // whether to update icon 91 | boolean *on; 92 | 93 | // list of icons 94 | patch_t **p; 95 | 96 | // user data 97 | int32_t data; 98 | 99 | } st_multicon_t; 100 | 101 | 102 | 103 | 104 | // Binary Icon widget 105 | 106 | typedef struct 107 | { 108 | // center-justified location of icon 109 | int32_t x, y; 110 | 111 | // last icon value 112 | int32_t oldval; 113 | 114 | // pointer to current icon status 115 | boolean *val; 116 | 117 | // pointer to boolean 118 | // stating whether to update icon 119 | boolean *on; 120 | 121 | 122 | patch_t *p; // icon 123 | int32_t data; // user data 124 | 125 | } st_binicon_t; 126 | 127 | 128 | 129 | // 130 | // Widget creation, access, and update routines 131 | // 132 | 133 | // Initializes widget library. 134 | // More precisely, initialize STMINUS, 135 | // everything else is done somewhere else. 136 | // 137 | void STlib_init(void); 138 | 139 | 140 | 141 | // Number widget routines 142 | void STlib_initNum (st_number_t *n, int32_t x, int32_t y, patch_t **pl, int32_t *num, boolean *on, int32_t width); 143 | 144 | void STlib_updateNum (st_number_t *n); 145 | 146 | 147 | // Percent widget routines 148 | void STlib_initPercent (st_percent_t *p, int32_t x, int32_t y, patch_t **pl, int32_t *num, boolean *on, patch_t *percent); 149 | 150 | void STlib_updatePercent (st_percent_t *per, boolean refresh); 151 | 152 | 153 | // Multiple Icon widget routines 154 | void STlib_initMultIcon (st_multicon_t *mi, int32_t x, int32_t y, patch_t **il, int32_t *inum, boolean *on); 155 | 156 | void STlib_updateMultIcon (st_multicon_t *mi, boolean refresh); 157 | 158 | // Binary Icon widget routines 159 | void STlib_initBinIcon (st_binicon_t *b, int32_t x, int32_t y, patch_t *i, boolean *val, boolean *on); 160 | 161 | void STlib_updateBinIcon (st_binicon_t *bi, boolean refresh); 162 | 163 | #endif 164 | -------------------------------------------------------------------------------- /wcdoom.lnk: -------------------------------------------------------------------------------- 1 | 2 | # wcdoom.EXE Linker directive file 3 | 4 | option quiet 5 | option map 6 | option stack=65536 7 | option stub=wstub 8 | option static 9 | debug all 10 | libpath %WATCOM%\lib386 11 | libpath %WATCOM%\lib386\dos 12 | lib noemu387.lib 13 | format os2 le 14 | name wcdoom 15 | alias MV_Mix8BitMono_=_MV_Mix8BitMono, MV_Mix8BitStereo_=_MV_Mix8BitStereo, MV_Mix16BitMono_=_MV_Mix16BitMono, MV_Mix16BitStereo_=_MV_Mix16BitStereo 16 | alias R_DrawColumn_=_R_DrawColumn, R_DrawColumnLow_=_R_DrawColumnLow, R_DrawSpan_=_R_DrawSpan, R_DrawSpanLow_=_R_DrawSpanLow 17 | 18 | file dmx.obj 19 | file a_al_mid.obj 20 | file a_blast.obj 21 | file a_dma.obj 22 | file a_ll_man.obj 23 | file a_midi.obj 24 | file a_mpu401.obj 25 | file a_multiv.obj 26 | file a_music.obj 27 | file a_musmid.obj 28 | file a_mv_mix.obj 29 | file a_pcfx.obj 30 | file a_taskmn.obj 31 | file a_tsmapi.obj 32 | file i_main.obj 33 | file i_ibm.obj 34 | file i_sound.obj 35 | file planar.obj 36 | file tables.obj 37 | file f_finale.obj 38 | file d_main.obj 39 | file d_net.obj 40 | file g_game.obj 41 | file m_menu.obj 42 | file m_misc.obj 43 | file am_map.obj 44 | file p_ceilng.obj 45 | file p_doors.obj 46 | file p_enemy.obj 47 | file p_floor.obj 48 | file p_inter.obj 49 | file p_lights.obj 50 | file p_map.obj 51 | file p_maputl.obj 52 | file p_plats.obj 53 | file p_pspr.obj 54 | file p_setup.obj 55 | file p_sight.obj 56 | file p_spec.obj 57 | file p_switch.obj 58 | file p_mobj.obj 59 | file p_telept.obj 60 | file p_tick.obj 61 | file p_user.obj 62 | file r_bsp.obj 63 | file r_data.obj 64 | file r_draw.obj 65 | file r_main.obj 66 | file r_plane.obj 67 | file r_segs.obj 68 | file r_things.obj 69 | file w_wad.obj 70 | file v_video.obj 71 | file z_zone.obj 72 | file st_stuff.obj 73 | file st_lib.obj 74 | file hu_stuff.obj 75 | file hu_lib.obj 76 | file wi_stuff.obj 77 | file s_sound.obj 78 | file sounds.obj 79 | file dutils.obj 80 | file info.obj 81 | -------------------------------------------------------------------------------- /wi_data.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 1993-1996 Id Software, Inc. 3 | // Copyright (C) 2023 Frenkel Smeijers 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | 19 | #ifndef __WIDATAH__ 20 | #define __WIDATAH__ 21 | 22 | static point_t lnodes[NUMEPISODES][NUMMAPS] = 23 | { 24 | // Episode 0 World Map 25 | { 26 | { 185, 164 }, // location of level 0 (CJ) 27 | { 148, 143 }, // location of level 1 (CJ) 28 | { 69, 122 }, // location of level 2 (CJ) 29 | { 209, 102 }, // location of level 3 (CJ) 30 | { 116, 89 }, // location of level 4 (CJ) 31 | #if !APPVER_CHEX 32 | { 166, 55 }, // location of level 5 (CJ) 33 | { 71, 56 }, // location of level 6 (CJ) 34 | { 135, 29 }, // location of level 7 (CJ) 35 | { 71, 24 } // location of level 8 (CJ) 36 | #endif 37 | }, 38 | 39 | #if !APPVER_CHEX 40 | // Episode 1 World Map should go here 41 | { 42 | { 254, 25 }, // location of level 0 (CJ) 43 | { 97, 50 }, // location of level 1 (CJ) 44 | { 188, 64 }, // location of level 2 (CJ) 45 | { 128, 78 }, // location of level 3 (CJ) 46 | { 214, 92 }, // location of level 4 (CJ) 47 | { 133, 130 }, // location of level 5 (CJ) 48 | { 208, 136 }, // location of level 6 (CJ) 49 | { 148, 140 }, // location of level 7 (CJ) 50 | { 235, 158 } // location of level 8 (CJ) 51 | }, 52 | 53 | // Episode 2 World Map should go here 54 | { 55 | { 156, 168 }, // location of level 0 (CJ) 56 | { 48, 154 }, // location of level 1 (CJ) 57 | { 174, 95 }, // location of level 2 (CJ) 58 | { 265, 75 }, // location of level 3 (CJ) 59 | { 130, 48 }, // location of level 4 (CJ) 60 | { 279, 23 }, // location of level 5 (CJ) 61 | { 198, 48 }, // location of level 6 (CJ) 62 | { 140, 25 }, // location of level 7 (CJ) 63 | { 281, 136 } // location of level 8 (CJ) 64 | } 65 | #endif // !APPVER_CHEX 66 | 67 | }; 68 | 69 | 70 | // 71 | // Animation locations for episode 0 (1). 72 | // Using patches saves a lot of space, 73 | // as they replace 320x200 full screen frames. 74 | // 75 | static anim_t epsd0animinfo[] = 76 | { 77 | { ANIM_ALWAYS, TICRATE/3, 3, { 224, 104 } }, 78 | { ANIM_ALWAYS, TICRATE/3, 3, { 184, 160 } }, 79 | { ANIM_ALWAYS, TICRATE/3, 3, { 112, 136 } }, 80 | { ANIM_ALWAYS, TICRATE/3, 3, { 72, 112 } }, 81 | { ANIM_ALWAYS, TICRATE/3, 3, { 88, 96 } }, 82 | { ANIM_ALWAYS, TICRATE/3, 3, { 64, 48 } }, 83 | { ANIM_ALWAYS, TICRATE/3, 3, { 192, 40 } }, 84 | { ANIM_ALWAYS, TICRATE/3, 3, { 136, 16 } }, 85 | { ANIM_ALWAYS, TICRATE/3, 3, { 80, 16 } }, 86 | { ANIM_ALWAYS, TICRATE/3, 3, { 64, 24 } } 87 | }; 88 | 89 | static anim_t epsd1animinfo[] = 90 | { 91 | { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 1 }, 92 | { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 2 }, 93 | { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 3 }, 94 | { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 4 }, 95 | { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 5 }, 96 | { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 6 }, 97 | { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 7 }, 98 | { ANIM_LEVEL, TICRATE/3, 3, { 192, 144 }, 8 }, 99 | { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 8 } 100 | }; 101 | 102 | static anim_t epsd2animinfo[] = 103 | { 104 | { ANIM_ALWAYS, TICRATE/3, 3, { 104, 168 } }, 105 | { ANIM_ALWAYS, TICRATE/3, 3, { 40, 136 } }, 106 | { ANIM_ALWAYS, TICRATE/3, 3, { 160, 96 } }, 107 | { ANIM_ALWAYS, TICRATE/3, 3, { 104, 80 } }, 108 | { ANIM_ALWAYS, TICRATE/3, 3, { 120, 32 } }, 109 | { ANIM_ALWAYS, TICRATE/4, 3, { 40, 0 } } 110 | }; 111 | 112 | static int32_t NUMANIMS[NUMEPISODES] = 113 | { 114 | sizeof(epsd0animinfo)/sizeof(anim_t), 115 | #if !APPVER_CHEX 116 | sizeof(epsd1animinfo)/sizeof(anim_t), 117 | sizeof(epsd2animinfo)/sizeof(anim_t) 118 | #endif 119 | }; 120 | 121 | static anim_t *anims[NUMEPISODES] = 122 | { 123 | epsd0animinfo, 124 | #if !APPVER_CHEX 125 | epsd1animinfo, 126 | epsd2animinfo 127 | #endif 128 | }; 129 | 130 | #endif 131 | -------------------------------------------------------------------------------- /wi_stuff.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 1993-1996 Id Software, Inc. 3 | // Copyright (C) 2023 Frenkel Smeijers 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | 19 | #ifndef __WISTUFFH__ 20 | #define __WISTUFFH__ 21 | #if APPVER_CHEX 22 | #define NUMEPISODES 1 23 | #define NUMMAPS 5 24 | #else 25 | #if (APPVER_DOOMREV < AV_DR_DM19UP) 26 | #define NUMEPISODES 3 27 | #else 28 | #define NUMEPISODES 4 29 | #endif 30 | #define NUMMAPS 9 31 | #endif // APPVER_CHEX 32 | 33 | 34 | // in tics 35 | #define PAUSELEN (TICRATE*2) 36 | #define SCORESTEP 100 37 | #define ANIMPERIOD 32 38 | // pixel distance from "(YOU)" to "PLAYER N" 39 | #define STARDIST 10 40 | #define WK 1 41 | 42 | 43 | // GLOBAL LOCATIONS 44 | #define WI_TITLEY 2 45 | #define WI_SPACINGY 33 46 | 47 | // SINGPLE-PLAYER STUFF 48 | #define SP_STATSX 50 49 | #define SP_STATSY 50 50 | 51 | #define SP_TIMEX 16 52 | #define SP_TIMEY (SCREENHEIGHT-32) 53 | 54 | 55 | // NET GAME STUFF 56 | #define NG_STATSY 50 57 | #define NG_STATSX (32 + SHORT(star->width)/2 + 32*!dofrags) 58 | 59 | #define NG_SPACINGX 64 60 | 61 | 62 | // DEATHMATCH STUFF 63 | #define DM_MATRIXX 42 64 | #define DM_MATRIXY 68 65 | 66 | #define DM_SPACINGX 40 67 | 68 | #define DM_TOTALSX 269 69 | 70 | #define DM_KILLERSX 10 71 | #define DM_KILLERSY 100 72 | #define DM_VICTIMSX 5 73 | #define DM_VICTIMSY 50 74 | 75 | 76 | 77 | 78 | typedef enum 79 | { 80 | ANIM_ALWAYS, 81 | ANIM_RANDOM, 82 | ANIM_LEVEL 83 | 84 | } animenum_t; 85 | 86 | typedef struct 87 | { 88 | int32_t x; 89 | int32_t y; 90 | 91 | } point_t; 92 | 93 | 94 | // 95 | // Animation. 96 | // There is another anim_t used in p_spec. 97 | // 98 | typedef struct 99 | { 100 | animenum_t type; 101 | 102 | // period in tics between animations 103 | int32_t period; 104 | 105 | // number of animation frames 106 | int32_t nanims; 107 | 108 | // location of animation 109 | point_t loc; 110 | 111 | // ALWAYS: n/a, 112 | // RANDOM: period deviation (<256), 113 | // LEVEL: level 114 | int32_t data1; 115 | 116 | // ALWAYS: n/a, 117 | // RANDOM: random base period, 118 | // LEVEL: n/a 119 | int32_t data2; 120 | 121 | // actual graphics for frames of animations 122 | patch_t* p[3]; 123 | 124 | // following must be initialized to zero before use! 125 | 126 | // next value of bcnt (used in conjunction with period) 127 | int32_t nexttic; 128 | 129 | // last drawn animation frame 130 | int32_t lastdrawn; 131 | 132 | // next frame number to animate 133 | int32_t ctr; 134 | 135 | // used by RANDOM and LEVEL when animating 136 | int32_t state; 137 | 138 | } anim_t; 139 | 140 | #endif 141 | -------------------------------------------------------------------------------- /z_zone.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 1993-1996 Id Software, Inc. 3 | // Copyright (C) 2023 Frenkel Smeijers 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | 19 | // Z_zone.c 20 | 21 | #include "doomdef.h" 22 | 23 | /* 24 | ============================================================================== 25 | 26 | ZONE MEMORY ALLOCATION 27 | 28 | There is never any space between memblocks, and there will never be two 29 | contiguous free memblocks. 30 | 31 | The rover can be left pointing at a non-empty block 32 | 33 | It is of no value to free a cachable block, because it will get overwritten 34 | automatically if needed 35 | 36 | ============================================================================== 37 | */ 38 | 39 | #define ZONEID 0x1d4a11 40 | 41 | typedef struct 42 | { 43 | int32_t size; // total bytes malloced, including header 44 | memblock_t blocklist; // start / end cap for linked list 45 | memblock_t *rover; 46 | } memzone_t; 47 | 48 | 49 | 50 | static memzone_t *mainzone; 51 | 52 | /* 53 | ======================== 54 | = 55 | = Z_Init 56 | = 57 | ======================== 58 | */ 59 | 60 | void Z_Init (void) 61 | { 62 | memblock_t *block; 63 | int32_t size; 64 | 65 | mainzone = (memzone_t *)I_ZoneBase (&size); 66 | mainzone->size = size; 67 | 68 | // set the entire zone to one free block 69 | 70 | mainzone->blocklist.next = mainzone->blocklist.prev = block = 71 | (memblock_t *)( (byte *)mainzone + sizeof(memzone_t) ); 72 | mainzone->blocklist.user = (void *)mainzone; 73 | mainzone->blocklist.tag = PU_STATIC; 74 | mainzone->rover = block; 75 | 76 | block->prev = block->next = &mainzone->blocklist; 77 | block->user = NULL; // free block 78 | block->size = mainzone->size - sizeof(memzone_t); 79 | } 80 | 81 | 82 | /* 83 | ======================== 84 | = 85 | = Z_Free 86 | = 87 | ======================== 88 | */ 89 | 90 | void Z_Free (void *ptr) 91 | { 92 | memblock_t *block, *other; 93 | 94 | block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t)); 95 | if (block->id != ZONEID) 96 | I_Error ("Z_Free: freed a pointer without ZONEID"); 97 | 98 | if (block->user > (void **)0x100) // smaller values are not pointers 99 | *block->user = 0; // clear the user's mark 100 | block->user = NULL; // mark as free 101 | block->tag = 0; 102 | block->id = 0; 103 | 104 | other = block->prev; 105 | if (!other->user) 106 | { // merge with previous free block 107 | other->size += block->size; 108 | other->next = block->next; 109 | other->next->prev = other; 110 | if (block == mainzone->rover) 111 | mainzone->rover = other; 112 | block = other; 113 | } 114 | 115 | other = block->next; 116 | if (!other->user) 117 | { // merge the next free block onto the end 118 | block->size += other->size; 119 | block->next = other->next; 120 | block->next->prev = block; 121 | if (other == mainzone->rover) 122 | mainzone->rover = block; 123 | } 124 | } 125 | 126 | 127 | /* 128 | ======================== 129 | = 130 | = Z_Malloc 131 | = 132 | = You can pass a NULL user if the tag is < PU_PURGELEVEL 133 | ======================== 134 | */ 135 | 136 | #define MINFRAGMENT 64 137 | 138 | void *Z_Malloc (int32_t size, int32_t tag, void *user) 139 | { 140 | int32_t extra; 141 | memblock_t *start, *rover, *new, *base; 142 | 143 | size = (size + 3) & ~3; 144 | // 145 | // scan through the block list looking for the first free block 146 | // of sufficient size, throwing out any purgable blocks along the way 147 | // 148 | size += sizeof(memblock_t); // account for size of block header 149 | 150 | 151 | // 152 | // if there is a free block behind the rover, back up over them 153 | // 154 | base = mainzone->rover; 155 | if (!base->prev->user) 156 | base = base->prev; 157 | 158 | rover = base; 159 | start = base->prev; 160 | 161 | do 162 | { 163 | if (rover == start) // scanned all the way around the list 164 | I_Error("Z_Malloc: failed on allocation of %i bytes", size); 165 | if (rover->user) 166 | { 167 | if (rover->tag < PU_PURGELEVEL) 168 | // hit a block that can't be purged, so move base past it 169 | base = rover = rover->next; 170 | else 171 | { 172 | // free the rover block (adding the size to base) 173 | base = base->prev; // the rover can be the base block 174 | Z_Free ((byte *)rover+sizeof(memblock_t)); 175 | base = base->next; 176 | rover = base->next; 177 | } 178 | } 179 | else 180 | rover = rover->next; 181 | } while (base->user || base->size < size); 182 | 183 | // 184 | // found a block big enough 185 | // 186 | extra = base->size - size; 187 | if (extra > MINFRAGMENT) 188 | { // there will be a free fragment after the allocated block 189 | new = (memblock_t *) ((byte *)base + size ); 190 | new->size = extra; 191 | new->user = NULL; // free block 192 | new->tag = 0; 193 | new->prev = base; 194 | new->next = base->next; 195 | new->next->prev = new; 196 | base->next = new; 197 | base->size = size; 198 | } 199 | 200 | if (user) 201 | { 202 | base->user = user; // mark as an in use block 203 | *(void **)user = (void *) ((byte *)base + sizeof(memblock_t)); 204 | } 205 | else 206 | { 207 | if (tag >= PU_PURGELEVEL) 208 | I_Error ("Z_Malloc: an owner is required for purgable blocks"); 209 | base->user = (void *)2; // mark as in use, but unowned 210 | } 211 | base->tag = tag; 212 | 213 | mainzone->rover = base->next; // next allocation will start looking here 214 | 215 | base->id = ZONEID; 216 | return (void *) ((byte *)base + sizeof(memblock_t)); 217 | } 218 | 219 | 220 | /* 221 | ======================== 222 | = 223 | = Z_FreeTags 224 | = 225 | ======================== 226 | */ 227 | 228 | void Z_FreeTags (int32_t lowtag, int32_t hightag) 229 | { 230 | memblock_t *block, *next; 231 | 232 | for (block = mainzone->blocklist.next ; block != &mainzone->blocklist 233 | ; block = next) 234 | { 235 | next = block->next; // get link before freeing 236 | if (!block->user) 237 | continue; // free block 238 | if (block->tag >= lowtag && block->tag <= hightag) 239 | Z_Free ( (byte *)block+sizeof(memblock_t)); 240 | } 241 | } 242 | 243 | /* 244 | ======================== 245 | = 246 | = Z_CheckHeap 247 | = 248 | ======================== 249 | */ 250 | 251 | void Z_CheckHeap (void) 252 | { 253 | memblock_t *block; 254 | 255 | for (block = mainzone->blocklist.next ; ; block = block->next) 256 | { 257 | if (block->next == &mainzone->blocklist) 258 | break; // all blocks have been hit 259 | if ( (byte *)block + block->size != (byte *)block->next) 260 | I_Error ("Z_CheckHeap: block size does not touch the next block\n"); 261 | if ( block->next->prev != block) 262 | I_Error ("Z_CheckHeap: next block doesn't have proper back link\n"); 263 | if (!block->user && !block->next->user) 264 | I_Error ("Z_CheckHeap: two consecutive free blocks\n"); 265 | } 266 | } 267 | 268 | 269 | /* 270 | ======================== 271 | = 272 | = Z_ChangeTag 273 | = 274 | ======================== 275 | */ 276 | 277 | void Z_ChangeTag2 (void *ptr, int32_t tag) 278 | { 279 | memblock_t *block; 280 | 281 | block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t)); 282 | if (block->id != ZONEID) 283 | I_Error ("Z_ChangeTag: freed a pointer without ZONEID"); 284 | if (tag >= PU_PURGELEVEL && (uint32_t)block->user < 0x100) 285 | I_Error ("Z_ChangeTag: an owner is required for purgable blocks"); 286 | block->tag = tag; 287 | } 288 | --------------------------------------------------------------------------------