├── .github └── workflows │ ├── build-cross.yml │ ├── build-default.yml │ ├── build-win32.yml │ └── tests.yml ├── .gitignore ├── .vscode ├── omnispeak.code-workspace ├── settings.json └── tasks.json ├── AUTHORS ├── CMakeLists.txt ├── LICENSE ├── README ├── compile_flags.txt ├── contrib ├── sdl2-config-mingw.cmake └── sdl2-config-vc.cmake ├── data ├── keen4 │ ├── ACTION.CK4 │ ├── AUDINFOE.CK4 │ ├── AUDIODCT.CK4 │ ├── AUDIOHHD.CK4 │ ├── EGADICT.CK4 │ ├── EGAHEAD.CK4 │ ├── EPISODE.CK4 │ ├── GFXCHUNK.CK4 │ ├── GFXINFOE.CK4 │ ├── MAPHEAD.CK4 │ ├── STRINGS.CK4 │ └── TILEINFO.CK4 ├── keen5 │ ├── ACTION.CK5 │ ├── AUDINFOE.CK5 │ ├── AUDIODCT.CK5 │ ├── AUDIOHHD.CK5 │ ├── EGADICT.CK5 │ ├── EGAHEAD.CK5 │ ├── EPISODE.CK5 │ ├── GFXCHUNK.CK5 │ ├── GFXINFOE.CK5 │ ├── MAPHEAD.CK5 │ ├── STRINGS.CK5 │ └── TILEINFO.CK5 ├── keen6e14 │ ├── ACTION.CK6 │ ├── AUDINFOE.CK6 │ ├── AUDIODCT.CK6 │ ├── AUDIOHHD.CK6 │ ├── EGADICT.CK6 │ ├── EGAHEAD.CK6 │ ├── EPISODE.CK6 │ ├── GFXCHUNK.CK6 │ ├── GFXINFOE.CK6 │ ├── MAPHEAD.CK6 │ ├── STRINGS.CK6 │ └── TILEINFO.CK6 └── keen6e15 │ ├── ACTION.CK6 │ ├── AUDINFOE.CK6 │ ├── AUDIODCT.CK6 │ ├── AUDIOHHD.CK6 │ ├── EGADICT.CK6 │ ├── EGAHEAD.CK6 │ ├── EPISODE.CK6 │ ├── GFXCHUNK.CK6 │ ├── GFXINFOE.CK6 │ ├── MAPHEAD.CK6 │ ├── STRINGS.CK6 │ └── TILEINFO.CK6 ├── doc └── modding.md ├── src ├── .clang-format ├── Makefile ├── Makefile.osx ├── ck4_ep.h ├── ck4_map.c ├── ck4_misc.c ├── ck4_obj1.c ├── ck4_obj2.c ├── ck4_obj3.c ├── ck5_ep.h ├── ck5_map.c ├── ck5_misc.c ├── ck5_obj1.c ├── ck5_obj2.c ├── ck5_obj3.c ├── ck6_ep.h ├── ck6_map.c ├── ck6_misc.c ├── ck6_obj1.c ├── ck6_obj2.c ├── ck6_obj3.c ├── ck_act.c ├── ck_act.h ├── ck_config.h ├── ck_cross.c ├── ck_cross.h ├── ck_def.h ├── ck_ep.h ├── ck_game.c ├── ck_game.h ├── ck_inter.c ├── ck_keen.c ├── ck_main.c ├── ck_map.c ├── ck_misc.c ├── ck_obj.c ├── ck_phys.c ├── ck_phys.h ├── ck_play.c ├── ck_play.h ├── ck_quit.c ├── ck_text.c ├── ck_text.h ├── ck_us_2.c ├── icon.c ├── id_ca.c ├── id_ca.h ├── id_cfg.c ├── id_cfg.h ├── id_fs.c ├── id_fs.h ├── id_heads.h ├── id_in.c ├── id_in.h ├── id_in_dos.c ├── id_in_null.c ├── id_in_sdl.c ├── id_in_sdl3.c ├── id_mm.c ├── id_mm.h ├── id_rf.c ├── id_rf.h ├── id_sd.c ├── id_sd.h ├── id_sd_dos.c ├── id_sd_liboplhw.c ├── id_sd_null.c ├── id_sd_opl2.c ├── id_sd_opl2alsa.c ├── id_sd_opl2lpt.c ├── id_sd_sdl.c ├── id_sd_sdl3.c ├── id_str.c ├── id_str.h ├── id_ti.c ├── id_ti.h ├── id_us.h ├── id_us_1.c ├── id_us_2.c ├── id_us_textscreen.c ├── id_vh.c ├── id_vh.h ├── id_vl.c ├── id_vl.h ├── id_vl_dos.c ├── id_vl_null.c ├── id_vl_private.h ├── id_vl_sdl12.c ├── id_vl_sdl2.c ├── id_vl_sdl2gl.c ├── id_vl_sdl2vk.c ├── id_vl_sdl3.c ├── id_vl_sdl3gpu.c ├── id_vl_vk_shader.frag ├── id_vl_vk_shader.vert ├── opl │ ├── NUKEDOPL3-LICENSE │ ├── dbopl.c │ ├── dbopl.h │ ├── nuked_opl3.c │ └── nuked_opl3.h └── windowsres.rc ├── tests ├── demo0.dump4 ├── demo0.dump5 ├── demo0.dump6v14 ├── demo0.dump6v15 ├── demo1.dump4 ├── demo1.dump5 ├── demo1.dump6v14 ├── demo1.dump6v15 ├── demo2.dump4 ├── demo2.dump5 ├── demo2.dump6v14 ├── demo2.dump6v15 ├── demo3.dump4 ├── demo3.dump5 ├── demo3.dump6v14 ├── demo3.dump6v15 ├── demo4.dump4 ├── demo4.dump5 ├── demo4.dump6v14 ├── demo4.dump6v15 └── testdump.sh ├── tools ├── dumpprinter │ └── dumpprinter.c ├── kdumper │ ├── k4e14dmp.asm │ ├── k4e14dmp.pat │ ├── k5e14dmp.asm │ ├── k5e14dmp.pat │ ├── k6e14dmp.asm │ ├── k6e14dmp.pat │ ├── k6e15dmp.asm │ ├── k6e15dmp.pat │ └── kdumper.inc └── varparser │ └── main.c ├── unixicon.png └── win32icon.ico /.github/workflows/build-cross.yml: -------------------------------------------------------------------------------- 1 | name: "CI: Build (Cross-compilers)" 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: Dependencies 13 | run: | 14 | sudo apt update 15 | sudo apt install gcc-multilib-powerpc64-linux-gnu linux-libc-dev-ppc64-cross 16 | - name: Build (ppc64 gcc) 17 | working-directory: ./src 18 | run: | 19 | make BINPREFIX=powerpc64-linux-gnu- STATIC=1 BUILDASCPP=0 RENDERER=null 20 | -------------------------------------------------------------------------------- /.github/workflows/build-default.yml: -------------------------------------------------------------------------------- 1 | name: "CI: Build (Default)" 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: Dependencies 13 | run: | 14 | sudo apt update 15 | sudo apt install libsdl2-dev mingw-w64 libasound2-dev libieee1284-3-dev 16 | wget https://github.com/andrewwutw/build-djgpp/releases/download/v3.1/djgpp-linux64-gcc1020.tar.bz2 17 | sudo tar xf djgpp-linux64-gcc1020.tar.bz2 -C /usr/local 18 | wget -nc https://davidgow.net/stuff/csdpmi7b.zip 19 | mkdir csdpmi7b 20 | unzip csdpmi7b.zip -d csdpmi7b/ 21 | sudo mkdir -p /opt 22 | - name: Build (Linux) 23 | working-directory: ./src 24 | run: | 25 | make WITH_ALSA=1 WITH_IEEE1284=1 26 | - name: Build (Windows) 27 | working-directory: ./src 28 | run: | 29 | make PLATFORM=win32 30 | make PLATFORM=win64 31 | - name: Build (MS-DOS) 32 | working-directory: ./src 33 | run: | 34 | make PLATFORM=dos 35 | cp ../csdpmi7b/bin/CWSDPMI.EXE ../bin-dos 36 | - name: Upload (Linux) 37 | uses: actions/upload-artifact@v4 38 | with: 39 | name: Linux Build 40 | path: bin/ 41 | - name: Upload (Windows) 42 | uses: actions/upload-artifact@v4 43 | with: 44 | name: Windows Build 45 | path: bin-win*/ 46 | - name: Upload (MS-DOS) 47 | uses: actions/upload-artifact@v4 48 | with: 49 | name: MS-DOS Build 50 | path: bin-dos/ 51 | -------------------------------------------------------------------------------- /.github/workflows/build-win32.yml: -------------------------------------------------------------------------------- 1 | name: "CI: Build (Win32/MSVC)" 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: windows-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: Dependencies 13 | run: | 14 | curl "https://libsdl.org/release/SDL2-devel-2.26.1-VC.zip" -o contrib/SDL2-VC.zip 15 | 7z x contrib/SDL2-VC.zip -ocontrib/MSVC/ 16 | copy contrib/sdl2-config-vc.cmake contrib/MSVC/SDL2-2.26.1/sdl2-config.cmake 17 | curl "https://libsdl.org/release/SDL2-devel-2.26.1-mingw.tar.gz" -o contrib/SDL2-mingw.tar.gz 18 | 7z x contrib/SDL2-mingw.tar.gz -ocontrib/ 19 | 7z x contrib/SDL2-mingw.tar -ocontrib/mingw/ 20 | copy contrib/sdl2-config-mingw.cmake contrib/mingw/SDL2-2.26.1/sdl2-config.cmake 21 | 22 | - name: Build (Windows/MSVC/Debug/x86) 23 | shell: cmd 24 | run: | 25 | mkdir build32 26 | cd build32 27 | cmake .. -DSDL2_DIR="contrib/MSVC/SDL2-2.26.1" -A Win32 28 | cmake --build . --config Debug 29 | copy ..\contrib\MSVC\SDL2-2.26.1\lib\x86\SDL2.dll Debug 30 | 31 | - name: Build (Windows/MSVC/RelWithDebInfo/x86) 32 | shell: cmd 33 | run: | 34 | mkdir build32 35 | cd build32 36 | cmake .. -DSDL2_DIR="contrib/MSVC/SDL2-2.26.1" -A Win32 37 | cmake --build . --config RelWithDebInfo 38 | copy ..\contrib\MSVC\SDL2-2.26.1\lib\x86\SDL2.dll RelWithDebInfo 39 | 40 | - name: Build (Windows/MSVC/Debug/x64) 41 | shell: cmd 42 | run: | 43 | mkdir build64 44 | cd build64 45 | cmake .. -DSDL2_DIR="contrib/MSVC/SDL2-2.26.1" -A x64 46 | cmake --build . --config Debug 47 | copy ..\contrib\MSVC\SDL2-2.26.1\lib\x64\SDL2.dll Debug 48 | 49 | - name: Build (Windows/MSVC/RelWithDebInfo/x64) 50 | shell: cmd 51 | run: | 52 | mkdir build64 53 | cd build64 54 | cmake .. -DSDL2_DIR="contrib/MSVC/SDL2-2.26.1" -A x64 55 | cmake --build . --config RelWithDebInfo 56 | copy ..\contrib\MSVC\SDL2-2.26.1\lib\x64\SDL2.dll RelWithDebInfo 57 | 58 | - name: Build (Windows/mingw/RelWithDebInfo/i686) 59 | shell: cmd 60 | run: | 61 | SET PATH=C:\msys64\mingw32\bin;%PATH% 62 | mkdir build32-mingw 63 | cd build32-mingw 64 | cmake .. -G "MinGW Makefiles" -DSDL2_DIR="contrib/mingw/SDL2-2.26.1" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_COMPILER=i686-w64-mingw32-gcc.exe -DCMAKE_MAKE_PROGRAM=mingw32-make.exe 65 | cmake --build . 66 | copy ..\contrib\mingw\SDL2-2.26.1\i686-w64-mingw32\bin\SDL2.dll . 67 | 68 | - name: Build (Windows/mingw/RelWithDebInfo/x86_64) 69 | shell: cmd 70 | run: | 71 | mkdir build64-mingw 72 | cd build64-mingw 73 | cmake .. -G "MinGW Makefiles" -DSDL2_DIR="contrib/mingw/SDL2-2.26.1" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_COMPILER=x86_64-w64-mingw32-gcc.exe -DCMAKE_MAKE_PROGRAM=mingw32-make.exe 74 | cmake --build . 75 | copy ..\contrib\mingw\SDL2-2.26.1\x86_64-w64-mingw32\bin\SDL2.dll . 76 | 77 | - name: Upload (Windows/MSVC/Debug/x86) 78 | uses: actions/upload-artifact@v4 79 | with: 80 | name: Windows Build (MSVC-x86-Debug) 81 | path: build32/Debug 82 | - name: Upload (Windows/MSVC/RelWithDebInfo/x64) 83 | uses: actions/upload-artifact@v4 84 | with: 85 | name: Windows Build (MSVC-x86-RelWithDebInfo) 86 | path: build32/Debug 87 | - name: Upload (Windows/MSVC/Debug/x64) 88 | uses: actions/upload-artifact@v4 89 | with: 90 | name: Windows Build (MSVC-x64-Debug) 91 | path: build64/Debug 92 | - name: Upload (Windows/MSVC/RelWithDebInfo/x64) 93 | uses: actions/upload-artifact@v4 94 | with: 95 | name: Windows Build (MSVC-x64-RelWithDebInfo) 96 | path: build64/Debug 97 | - name: Upload (Windows/mingw/RelWithDebInfo/i686) 98 | uses: actions/upload-artifact@v4 99 | with: 100 | name: Windows Build (mingw-i686-RelWithDebInfo) 101 | path: build32-mingw 102 | - name: Upload (Windows/mingw/RelWithDebInfo/x86_64) 103 | uses: actions/upload-artifact@v4 104 | with: 105 | name: Windows Build (mingw-x86_64-RelWithDebInfo) 106 | path: build64-mingw 107 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: "CI: Demo Dump Tests" 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | demodumptest: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: Build (Linux) 13 | working-directory: ./src 14 | run: | 15 | make RENDERER=null DEBUG=1 16 | make dumpprinter 17 | - name: Get Datafiles 18 | working-directory: ./bin 19 | env: 20 | K56DATA_URL: ${{ secrets.k56dataUrl }} 21 | run: | 22 | wget https://davidgow.net/keen/4keen14.zip 23 | unzip 4keen14.zip AUDIO.CK4 Gamemaps.ck4 Egagraph.ck4 24 | wget "$K56DATA_URL" 25 | unzip k56data.zip 26 | - name: Run Tests (Keen 4) 27 | working-directory: ./bin 28 | run: | 29 | ../tests/testdump.sh 0 4 30 | ../tests/testdump.sh 1 4 31 | ../tests/testdump.sh 2 4 32 | ../tests/testdump.sh 3 4 33 | ../tests/testdump.sh 4 4 34 | - name: Run Tests (Keen 5) 35 | working-directory: ./bin 36 | run: | 37 | ../tests/testdump.sh 0 5 38 | ../tests/testdump.sh 1 5 39 | ../tests/testdump.sh 2 5 40 | ../tests/testdump.sh 3 5 41 | ../tests/testdump.sh 4 5 42 | - name: Run Tests (Keen 6 EGA v1.5) 43 | working-directory: ./bin 44 | run: | 45 | ../tests/testdump.sh 0 6v15 46 | ../tests/testdump.sh 1 6v15 47 | ../tests/testdump.sh 2 6v15 48 | ../tests/testdump.sh 3 6v15 49 | ../tests/testdump.sh 4 6v15 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | SDL2-2.* 2 | SDL-1.* 3 | ._SDL-1.* 4 | bin* 5 | obj* 6 | -------------------------------------------------------------------------------- /.vscode/omnispeak.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": ".." 5 | } 6 | ], 7 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.tabSize": 8, 3 | "editor.insertSpaces": false, 4 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "Build (Release)", 8 | "group": "build", 9 | "type": "process", 10 | "windows": { 11 | "command": "bash", 12 | "args": [ 13 | "-c", 14 | "make PLATFORM=win64 -j4" 15 | ] 16 | }, 17 | "linux": { 18 | "command": "make", 19 | "args": [ 20 | "-j4" 21 | ] 22 | }, 23 | "options": { 24 | "cwd": "${workspaceRoot}/src" 25 | }, 26 | "problemMatcher": { 27 | "base": "$gcc", 28 | "fileLocation": [ 29 | "relative", 30 | "${workspaceRoot}/src" 31 | ] 32 | } 33 | }, 34 | { 35 | "label": "Build (Debug)", 36 | "group": { 37 | "kind": "build", 38 | "isDefault": true 39 | }, 40 | "type": "process", 41 | "windows": { 42 | "command": "bash", 43 | "args": [ 44 | "-c", 45 | "make PLATFORM=win64 DEBUG=1 -j4" 46 | ] 47 | }, 48 | "linux": { 49 | "command": "make", 50 | "args": [ 51 | "DEBUG=1", 52 | "-j4" 53 | ] 54 | }, 55 | "options": { 56 | "cwd": "${workspaceRoot}/src" 57 | }, 58 | "problemMatcher": { 59 | "base": "$gcc", 60 | "fileLocation": [ 61 | "relative", 62 | "${workspaceRoot}/src" 63 | ] 64 | } 65 | }, 66 | { 67 | "label": "Clean", 68 | "group": "build", 69 | "type": "process", 70 | "windows": { 71 | "command": "bash", 72 | "args": [ 73 | "-c", 74 | "make PLATFORM=win64 clean" 75 | ] 76 | }, 77 | "linux": { 78 | "command": "make", 79 | "args": [ 80 | "clean" 81 | ] 82 | }, 83 | "options": { 84 | "cwd": "${workspaceRoot}/src" 85 | }, 86 | "problemMatcher": [], 87 | }, 88 | { 89 | "label": "Distribution-Clean", 90 | "group": "build", 91 | "type": "process", 92 | "command": "bash", 93 | "args": [ 94 | "-c", 95 | "make distclean" 96 | ], 97 | "options": { 98 | "cwd": "${workspaceRoot}/src" 99 | }, 100 | "problemMatcher": [], 101 | } 102 | ], 103 | } -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | David Gow 2 | NY00123 3 | lemm 4 | BSzili 5 | KeyJ 6 | 7 | Includes the DOSBox OPL2/3 Emulator: 8 | Copyright (C) 2002-2010 The DOSBox Team 9 | https://www.dosbox.com/ 10 | 11 | Includes the Nuked OPL3 Emulator: 12 | Copyright (C) 2013-2020 Nuke.YKT 13 | https://github.com/nukeykt/Nuked-OPL3 14 | See src/opl/NUKEDOPL3-LICENSE 15 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Omnispeak: An reimplementation of "Commander Keen in Goodbye Galaxy!" 2 | 3 | Omnispeak is an open-source reimplementation of Commander Keen episodes 4, 5, 4 | and 6. It aims to be a pixel-perfect, bug-for-bug clone of the original games, 5 | and is compatible with savegames from the DOS version. 6 | 7 | Omnispeak's homepage, including binary downloads, is available at: 8 | https://davidgow.net/keen/omnispeak.html 9 | 10 | Omnispeak's source code can be found on GitHub: 11 | https://github.com/sulix/omnispeak 12 | 13 | == INSTALLATION == 14 | To play, you'll need to include files from the original game. 15 | 16 | Omnispeak supports: 17 | - Keen 4 v1.4 EGA 18 | - Keen 5 v1.4 EGA 19 | - Keen 6 v1.4 EGA 20 | - Keen 6 v1.5 EGA 21 | 22 | These should be the easiest versions to get. For example, the Steam version and 23 | the GOG.com version are both version 1.4, as are all the previous downloadable 24 | versions from both id Software and 3D Realms / Apogee. Keen 6 is not easily 25 | available, but you should be able to find patches which convert one version of 26 | the game to another. Keen 6 v1.5 fixes a few bugs, so it's probably best to use 27 | it if you can. Note that the game will likely crash if you use any other version, 28 | including the CGA versions and the v1.0 releases, as well as the retail FormGen / 29 | GT Interative versions and the Keen 6 version bundled with the id Anthology. 30 | 31 | The shareware release of Keen 4 v1.4 EGA is available here: 32 | https://davidgow.net/keen/4keen14.zip 33 | 34 | 35 | You'll need to take the following files from your version of Keen, and place 36 | them in the same directory as the 'omnispeak' binary: 37 | * GAMEMAPS.CK? 38 | * EGAGRAPH.CK? 39 | * AUDIO.CK? 40 | 41 | You'll also need the files from the 'data' directory corresponding to your 42 | version of Keen. For Keen 6 in particular, you'll need to check if you have 43 | version 1.4 or version 1.5, and copy keen6e14 and keen6e15 accordingly. The 44 | initialisation screen contains the version of the game. 45 | 46 | To run the game, simply switch to the directory with the data files, and run: 47 | ./omnispeak 48 | 49 | Omnispeak supports several command-line options, some of which are: 50 | /EPISODE 51 | - Runs the given episode of Commander Keen 52 | This should be the filename of the 'EPISODE.CKx' file for the 53 | given episode. But just using the numbers 4, 5, and 6 work as 54 | well. 55 | /GAMEPATH 56 | - Sets the path to the game data files. 57 | /USERPATH 58 | - Sets the path to the savegame and config files. 59 | /FULLSCREEN 60 | - Starts the game in fullscreen mode 61 | /FILLED 62 | - Starts the game with aspect-ratio correction off. 63 | /NOBORDER 64 | - Starts the game with EGA overscan border emulation off. 65 | /INTEGER 66 | - Starts the game with integer scaling enabled. 67 | /NOJOYS 68 | - Disables Joystick detection. 69 | /NOCOPY 70 | - Bypasses the "Creature Question" screen in Keen 6. 71 | /AUDIOSYNC 72 | - When using SDL-based sound backends, use the audio clock 73 | rather than the system clock. Available as the 74 | 'sd_sdl_audioSync' config option. 75 | (Enabling this ensures perfect audio timing, at the expense 76 | of worse frame pacing.) 77 | /DEMOFILE 78 | - Plays the demo recorded with Keen's F10+D cheat in filename. 79 | 80 | == CONFIGURATION == 81 | 82 | Omnispeak can read settings from the 'OMNISPK.CFG' file in the "user path". 83 | This is a simple key/value file which looks something like this: 84 | 85 | --8<-- 86 | # Graphics settings 87 | fullscreen = true 88 | border = true 89 | integer = false 90 | 91 | # The OPL emulator used by the SDL audio backend 92 | # Valid values: "dbopl" (DOSBox), "nukedopl3" (NukedOPL3) 93 | oplEmulator = "dbopl" 94 | --8<-- 95 | 96 | Modifying settings from the ComputerWrist interface will update this config 97 | file with the new settings. 98 | 99 | Note that this file is not episode-specific. The settings are shared between 100 | all episodes. 101 | 102 | == COMPILING == 103 | 104 | The source code for Omnispeak is available on GitHub: 105 | https://github.com/sulix/omnispeak 106 | 107 | You'll find it in the src/ directory and built with make. 108 | 109 | Omnispeak should build fine on most Linux distributions. 110 | 111 | You'll need to have the Simple Directmedia Layer 2.0 installed, with the 112 | sdl2-config program somewhere in your path. 113 | 114 | When compiled, an 'omnispeak' binary will appear in 'bin/', along with 115 | the files from the 'data' directories. 116 | 117 | Cross-compilation for 32-bit and 64-bit Windows targets using MinGW32-Win64 118 | is also supported. Omnispeak can also be compiled using recent versions of 119 | Microsoft Visual C++ using the provided CMake build system. 120 | 121 | Cross-compilation for the GCW Zero is possible using the [GCW Zero 122 | toolchain](http://www.gcw-zero.com/develop). 123 | 124 | Cross-compilation for 32-bit MS-DOS using DJGPP is available, though the port 125 | is quite buggy. Simply run: 126 | make PLATFORM=dos 127 | A 486 and about 4MB of RAM are recommended to play Omnispeak under DOS. 128 | 129 | On Linux, real OPL2 compatible soundcards can be used in place of the Adlib 130 | emulation by building with either the WITH_ALSA=1 option (for most soundcards), 131 | or the WITH_IEEE1284=1 option (for the OPL2LPT). These require libasound and libieee1284 132 | respectively, and must be enabled at runtime by setting the "sd_backend" option 133 | to "alsa" or "opl2lpt". (The ALSA device can be configured with the 134 | "sd_alsa_device" option, and the parallel port for the OPL2LPT can be set with 135 | "sd_opl2lpt_port".) 136 | 137 | Packagers should note that it's possible to change the default KEEN and USER 138 | paths with the make KEENPATH= and make USERPATH= options. Similarly, savegames 139 | can be stored in the $XDG_DATA_HOME directory with the make XDGUSERPATH=1 option. 140 | Additional options can be found in the ``src/ck_config.h`` file. 141 | For example, you could build with: 142 | make KEENPATH=/usr/share/omnispeak XDGUSERPATH=1 143 | 144 | To see a full list of build options, just run `make help`. 145 | 146 | == NEW FEATURES == 147 | 148 | Omnispeak includes a new QuickLoad / QuickSave feature, which allows the game 149 | in the final save slot to be saved and loaded without needing to navigate 150 | the menu. This is done with the F5 and F9 keys by default: they can be changed 151 | in the Keyboard bindings menu. 152 | 153 | Omnispeak also greatly expands Keyboard and Joystick configuration over the 154 | original DOS games. Additional keys / buttons can be re-bound, and a 'modern' 155 | mode for the joystick is often easier to use, particularly when moving 156 | diagonally. 157 | 158 | == REPORTING BUGS == 159 | 160 | Please report bugs and feature requests on GitHub at: 161 | https://github.com/sulix/omnispeak/issues 162 | 163 | Alternatively, you can email me at: 164 | david@davidgow.net 165 | 166 | == END OF TEXT == 167 | 168 | That's all! Now go play Commander Keen! 169 | -------------------------------------------------------------------------------- /compile_flags.txt: -------------------------------------------------------------------------------- 1 | -g 2 | -O0 3 | -DCK_DEBUG 4 | -DWITH_KEEN4 5 | -DWITH_KEEN5 6 | -DWITH_KEEN6 7 | -c 8 | -------------------------------------------------------------------------------- /contrib/sdl2-config-mingw.cmake: -------------------------------------------------------------------------------- 1 | # This is a hacky sdl2-config.cmake implementation for the SDL mingw32 packages on libsdl.org 2 | # It's based loosely on the version contained in the tarball, combined with the MSVC one here: 3 | # https://trenki2.github.io/blog/2017/06/02/using-sdl2-with-cmake/ 4 | 5 | # Support both 32 and 64 bit builds 6 | if (${CMAKE_SIZEOF_VOID_P} MATCHES 8) 7 | set(SDL2_INCLUDE_DIRS "${CMAKE_CURRENT_LIST_DIR}/x86_64-w64-mingw32/include/SDL2") 8 | set(SDL2_LIBRARIES "-L${CMAKE_CURRENT_LIST_DIR}/x86_64-w64-mingw32/lib -lmingw32 -lSDL2main -lSDL2 -mwindows") 9 | else () 10 | set(SDL2_INCLUDE_DIRS "${CMAKE_CURRENT_LIST_DIR}/i686-w64-mingw32/include/SDL2") 11 | set(SDL2_LIBRARIES "-L${CMAKE_CURRENT_LIST_DIR}/i686-w64-mingw32/lib -lmingw32 -lSDL2main -lSDL2 -mwindows") 12 | endif () 13 | 14 | string(STRIP "${SDL2_LIBRARIES}" SDL2_LIBRARIES) 15 | -------------------------------------------------------------------------------- /contrib/sdl2-config-vc.cmake: -------------------------------------------------------------------------------- 1 | # This is a hacky sdl2-config.cmake implementation for the SDL MSVC packages on libsdl.org 2 | # I found it here: 3 | # https://trenki2.github.io/blog/2017/06/02/using-sdl2-with-cmake/ 4 | 5 | set(SDL2_INCLUDE_DIRS "${CMAKE_CURRENT_LIST_DIR}/include") 6 | 7 | # Support both 32 and 64 bit builds 8 | if (${CMAKE_SIZEOF_VOID_P} MATCHES 8) 9 | set(SDL2_LIBRARIES "${CMAKE_CURRENT_LIST_DIR}/lib/x64/SDL2.lib;${CMAKE_CURRENT_LIST_DIR}/lib/x64/SDL2main.lib") 10 | else () 11 | set(SDL2_LIBRARIES "${CMAKE_CURRENT_LIST_DIR}/lib/x86/SDL2.lib;${CMAKE_CURRENT_LIST_DIR}/lib/x86/SDL2main.lib") 12 | endif () 13 | 14 | string(STRIP "${SDL2_LIBRARIES}" SDL2_LIBRARIES) 15 | 16 | -------------------------------------------------------------------------------- /data/keen4/AUDINFOE.CK4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen4/AUDINFOE.CK4 -------------------------------------------------------------------------------- /data/keen4/AUDIODCT.CK4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen4/AUDIODCT.CK4 -------------------------------------------------------------------------------- /data/keen4/AUDIOHHD.CK4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen4/AUDIOHHD.CK4 -------------------------------------------------------------------------------- /data/keen4/EGADICT.CK4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen4/EGADICT.CK4 -------------------------------------------------------------------------------- /data/keen4/EGAHEAD.CK4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen4/EGAHEAD.CK4 -------------------------------------------------------------------------------- /data/keen4/GFXINFOE.CK4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen4/GFXINFOE.CK4 -------------------------------------------------------------------------------- /data/keen4/MAPHEAD.CK4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen4/MAPHEAD.CK4 -------------------------------------------------------------------------------- /data/keen4/STRINGS.CK4: -------------------------------------------------------------------------------- 1 | # 2 | # Strings for Keen 4 (v1.4) 3 | # 4 | 5 | # Common strings 6 | 7 | %string ck_str_gameOver "Game Over!" 8 | 9 | # Paddle War 10 | %string ck_str_paddleWarKeen "KEEN:" 11 | %string ck_str_paddleWarComp "COMP:" 12 | %string ck_str_paddleWarDefeat "You lost!" 13 | %string ck_str_paddleWarVictory "You won!" 14 | %string ck_str_paddleWarPressAKey "Press any key" 15 | 16 | # Loading box for demos 17 | %string ck_str_demo "DEMO" 18 | 19 | %string ck_str_tryAgainIntro "You didn't make it past" 20 | %string ck_str_tryAgainTryAgain "Try Again" 21 | 22 | 23 | #ck_play.c 24 | 25 | %string ck_str_itemCheat "Cheat Option!\n\nYou just got all\nthe keys, 99 shots,\nand an extra keen!" 26 | 27 | %string ck_str_godModeOn "God Mode ON" 28 | %string ck_str_godModeOff "God Mode OFF" 29 | 30 | %string ck_str_freeItems "Free Items!" 31 | 32 | %string ck_str_jumpCheatOn "\nJump cheat ON" 33 | %string ck_str_jumpCheatOff "\nJump cheat OFF" 34 | 35 | %string ck_str_noClippingOn "No clipping ON" 36 | %string ck_str_noClippingOff "No clipping OFF" 37 | 38 | %string ck_str_slowMotionOn "Slow motion ON" 39 | %string ck_str_slowMotionOff "Slow motion OFF" 40 | 41 | #TODO: Warp and some other debug cheats 42 | 43 | %string ck_str_debugKeysActive "Debug keys active" 44 | %string ck_str_levelWarp " Warp to which level(1-18):" 45 | 46 | 47 | %string ck_str_paused "PAUSED" 48 | 49 | #NOTE: QuickSave feature 50 | %string ck_str_gameQuickSaved "GAME SAVED" 51 | 52 | # Status window 53 | %string ck_str_statusLocation "LOCATION" 54 | %string ck_str_statusScore "SCORE" 55 | %string ck_str_statusExtra "EXTRA" 56 | %string ck_str_statusLevel "LEVEL" # Difficulty level 57 | %string ck_str_statusEasy "Easy" 58 | %string ck_str_statusNormal "Normal" 59 | %string ck_str_statusHard "Hard" 60 | %string ck_str_statusKeys "KEYS" 61 | %string ck_str_statusAmmo "AMMO" 62 | %string ck_str_statusLives "KEENS" 63 | 64 | # Keen 4 65 | %string ck_str_exitToMap "Exit to Shadowlands" 66 | 67 | %string ck_str_statusCentilives "DROPS" 68 | %string ck4_str_statusRescued "RESCUED" 69 | %string ck4_str_statusWetsuit "Wetsuit" 70 | %string ck4_str_statusNoWetsuit "???" 71 | 72 | %stringarray ck_str_levelNames 73 | "Shadowlands", 74 | "Border Village", 75 | "Slug Village", 76 | "The Perilous Pit", 77 | "Cave of the Descendents", 78 | "Chasm of Chills", 79 | "Crystalus", 80 | "Hilville", 81 | "Sand Yego", 82 | "Miragia", 83 | "Lifewater Oasis", 84 | "Pyramid of the Moons", 85 | "Pyramid of Shadows", 86 | "Pyramid of the\nGnosticene Ancients", 87 | "Pyramid of the Forbidden", 88 | "Isle of Tar", 89 | "Isle of Fire", 90 | "Well of Wishes", 91 | "Bean-with-Bacon\nMegarocket" 92 | 93 | 94 | 95 | 96 | %stringarray ck_str_levelEntryText 97 | "Keen enters the\n" 98 | "Shadowlands\n", 99 | 100 | "Keen makes a run for\n" 101 | "the Border Village", 102 | 103 | "Keen slips into\n" 104 | "Slug Village", 105 | 106 | "Keen plummets into\n" 107 | "the The Perilous Pit", 108 | 109 | "Keen plods down into\n" 110 | "the Cave of the\n" 111 | "Descendents", 112 | 113 | "Keen shivers along\n" 114 | "the Chasm of Chills", 115 | 116 | "Keen reflects upon\n" 117 | "entering Crystalus", 118 | 119 | "Keen stumbles upon\n" 120 | "Hillville", 121 | 122 | "Keen grits his teeth\n" 123 | "and enters Sand Yego", 124 | 125 | "Keen disappears into\n" 126 | "Miragia", 127 | 128 | "Keen crawls into\n" 129 | "Lifewater Oasis", 130 | 131 | "Keen backs into the\n" 132 | "Pyramid of the Moons", 133 | 134 | "Keen move silently in\n" 135 | "the Pyramid of Shadows", 136 | 137 | "Keen reverently enters\n" 138 | "the Pyramid of the\n" 139 | "Gnosticene Ancients", 140 | 141 | "Keen hesitantly crosses\n" 142 | "into the Pyramid of the\n" 143 | "Forbidden", 144 | 145 | "Keen mucks along the\n" 146 | "Isle of Tar", 147 | 148 | "Keen blazes across the\n" 149 | "Isle of Fire", 150 | 151 | "Keen hopefully enters\n" 152 | "the Well of Wishes", 153 | 154 | "Keen launches into the\n" 155 | "Bean-with-Bacon\n" 156 | "Megarocket" 157 | 158 | %string ck_str_storyText 159 | "Episode Four\n" 160 | "\n" 161 | "Secret of the Oracle\n" 162 | "\n" 163 | "After delivering a\n" 164 | "crippling blow to the\n" 165 | "plans of Mortimer\n" 166 | "McMire and receiving\n" 167 | "the praise of the\n" 168 | "Vorticon race,\n" 169 | "Commander Keen\n" 170 | "returned to his home in\n" 171 | "the suburbs.\n" 172 | "\n" 173 | "Here he was forced to\n" 174 | "go to bed at an early\n" 175 | "hour, and to eat mashed\n" 176 | "potatoes.\n" 177 | "\n" 178 | "Months later, Billy\n" 179 | "tinkered around with\n" 180 | "his latest invention,\n" 181 | "the Photachyon\n" 182 | "Transceiver, or faster-\n" 183 | "than-light radio. After\n" 184 | "picking up a lot of bad\n" 185 | "alien sitcoms, he\n" 186 | "stumbled upon a strange\n" 187 | "message of terrible\n" 188 | "importance....\n" 189 | 190 | 191 | # Princess Lindsay: 192 | 193 | %string ck4_str_lindsaySays "Princess Lindsey says:\n" 194 | %string ck4_str_lindsayMessage1 "There's gear to help\n" 195 | "you swim in Three-Tooth\n" 196 | "Lake. It is hidden in\n" 197 | "Miragia.\n" 198 | 199 | %string ck4_str_lindsayMessage2 "The way to the Pyramid\n" 200 | "of the Forbidden lines\n" 201 | "under the Pyramid of\n" 202 | "Moons.\n" 203 | 204 | %string ck4_str_lindsayThanks1 "Thanks, your Highness!" 205 | %string ck4_str_lindsayThanks2 "Thanks for the\n" 206 | "mysterious clue,\n" 207 | "Princess!\n" 208 | 209 | # Oracle Janitor: 210 | 211 | %string ck4_str_janitor1 "Thanks for going to all\n" 212 | "that trouble, but I'm\n" 213 | "just the janitor for the\n" 214 | "High Council." 215 | 216 | %string ck4_str_janitor2 "I tried to tell the\n" 217 | "Shikadi that but they\n" 218 | "just wouldn't listen..." 219 | 220 | %string ck4_str_janitor3 "This had better\n" 221 | "be a joke." 222 | 223 | %string ck4_str_janitor4 "Sorry. You aren't\n" 224 | "mad, are you?" 225 | 226 | # Wetsuit: 227 | 228 | %string ck4_str_cantSwim "I can't swim!" 229 | %string ck4_str_gotWetsuit "Cool! I can breathe\n" 230 | "under water now!" 231 | 232 | # Council members: 233 | 234 | %stringarray ck4_str_councilMessage 235 | "No sweat, oh guardian\n" 236 | "of wisdom!", 237 | 238 | "Sounds like a plan,\n" 239 | "bearded one!", 240 | 241 | "No problemo.", 242 | 243 | "Great. You known, you\n" 244 | "look a lot like the\n" 245 | "last guy I rescued...", 246 | 247 | "Good idea, Gramps.", 248 | 249 | "May the road rise\n" 250 | "to meet your feet,\n" 251 | "Mr. Member.", 252 | 253 | "Wise plan of action,\n" 254 | "your ancientness.", 255 | 256 | "You're the last one,\n" 257 | "fella. Let's both\n" 258 | "get back to the\n" 259 | "Oracle chamber!" 260 | 261 | %string ck4_str_councilThanks "Oh thank you so much\n" 262 | "for rescuing me!\n" 263 | "I'll return to the\n" 264 | "Oracle chamber\n" 265 | "immediately." 266 | 267 | %string ck4_str_councilThanks2 "Ggoh thig you sogh mg\n" 268 | "fgor regscuing mgge!\n" 269 | "I'gll regur tgo the\n" 270 | "Goracle chagber\n" 271 | "igmediatggely. Blub." 272 | -------------------------------------------------------------------------------- /data/keen4/TILEINFO.CK4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen4/TILEINFO.CK4 -------------------------------------------------------------------------------- /data/keen5/AUDINFOE.CK5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen5/AUDINFOE.CK5 -------------------------------------------------------------------------------- /data/keen5/AUDIODCT.CK5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen5/AUDIODCT.CK5 -------------------------------------------------------------------------------- /data/keen5/AUDIOHHD.CK5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen5/AUDIOHHD.CK5 -------------------------------------------------------------------------------- /data/keen5/EGADICT.CK5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen5/EGADICT.CK5 -------------------------------------------------------------------------------- /data/keen5/EGAHEAD.CK5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen5/EGAHEAD.CK5 -------------------------------------------------------------------------------- /data/keen5/GFXINFOE.CK5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen5/GFXINFOE.CK5 -------------------------------------------------------------------------------- /data/keen5/MAPHEAD.CK5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen5/MAPHEAD.CK5 -------------------------------------------------------------------------------- /data/keen5/STRINGS.CK5: -------------------------------------------------------------------------------- 1 | # 2 | # Strings for Keen 5 (v1.4) 3 | # 4 | 5 | # Common strings 6 | 7 | 8 | %string ck_str_gameOver "Game Over!" 9 | 10 | # Paddle War 11 | %string ck_str_paddleWarKeen "KEEN:" 12 | %string ck_str_paddleWarComp "COMP:" 13 | %string ck_str_paddleWarDefeat "You lost!" 14 | %string ck_str_paddleWarVictory "You won!" 15 | %string ck_str_paddleWarPressAKey "Press any key" 16 | 17 | 18 | # Loading box for demos 19 | %string ck_str_demo "DEMO" 20 | 21 | %string ck_str_tryAgainIntro "You didn't make it past" 22 | %string ck_str_tryAgainTryAgain "Try Again" 23 | 24 | 25 | #ck_play.c 26 | 27 | %string ck_str_itemCheat "Cheat Option!\n\nYou just got all\nthe keys, 99 shots,\nand an extra keen!" 28 | 29 | %string ck_str_godModeOn "God Mode ON" 30 | %string ck_str_godModeOff "God Mode OFF" 31 | 32 | %string ck_str_freeItems "Free Items!" 33 | 34 | %string ck_str_jumpCheatOn "\nJump cheat ON" 35 | %string ck_str_jumpCheatOff "\nJump cheat OFF" 36 | 37 | %string ck_str_noClippingOn "No clipping ON" 38 | %string ck_str_noClippingOff "No clipping OFF" 39 | 40 | %string ck_str_slowMotionOn "Slow motion ON" 41 | %string ck_str_slowMotionOff "Slow motion OFF" 42 | 43 | #TODO: Warp and some other debug cheats 44 | 45 | %string ck_str_debugKeysActive "Debug keys active" 46 | %string ck_str_levelWarp " Warp to which level(1-18):" 47 | 48 | 49 | %string ck_str_paused "PAUSED" 50 | 51 | #NOTE: QuickSave feature 52 | %string ck_str_gameQuickSaved "GAME SAVED" 53 | 54 | # Status window 55 | %string ck_str_statusLocation "LOCATION" 56 | %string ck_str_statusScore "SCORE" 57 | %string ck_str_statusExtra "EXTRA" 58 | %string ck_str_statusLevel "LEVEL" # Difficulty level 59 | %string ck_str_statusEasy "Easy" 60 | %string ck_str_statusNormal "Normal" 61 | %string ck_str_statusHard "Hard" 62 | %string ck_str_statusKeys "KEYS" 63 | %string ck_str_statusAmmo "AMMO" 64 | %string ck_str_statusLives "KEENS" 65 | 66 | # Keen 5 67 | 68 | %string ck5_str_korath3 "Keen steps out\nonto Korath III" 69 | %string ck_str_exitToMap "Exit to Armageddon" 70 | 71 | %string ck_str_statusCentilives "VITALIN" 72 | %string ck5_str_statusKeycard "KEYCARD" 73 | 74 | 75 | 76 | %stringarray ck_str_levelNames 77 | "Omegamatic", 78 | "Ion Ventilation System", 79 | "Security Center", 80 | "Defense Tunnel Vlook", 81 | "Energy Flow Systems", 82 | "Defense Tunnel Burrh", 83 | "Regulation\nControl Center", 84 | "Defense Tunnel Sorra", 85 | "Neutrino\nBurst Injector", 86 | "Defense Tunnel Teln", 87 | "Brownian\nMotion Inducer", 88 | "Gravitational\nDamping Hub", 89 | "Quantum\nExplosion Dynamo", 90 | "Korath III Base", 91 | "BWBMegarocket", 92 | "High Scores" 93 | 94 | %stringarray ck_str_levelEntryText 95 | "Keen purposefully\n" 96 | "wanders about the\n" 97 | "Omegamatic", 98 | 99 | "Keen investigates the\n" 100 | "Ion Ventilation System", 101 | 102 | "Keen struts through\n" 103 | "the Security Center", 104 | 105 | "Keen invades\n" 106 | "Defense Tunnel Vlook", 107 | 108 | "Keen engages\n" 109 | "Energy Flow Systems", 110 | 111 | "Keen barrels into\n" 112 | "Defense Tunnel Burrh", 113 | 114 | "Keen goes nuts in\n" 115 | "the Regulation\n" 116 | "Control Center", 117 | 118 | "Keen regrets entering\n" 119 | "Defense Tunnel Sorra", 120 | 121 | "Keen blows through\n" 122 | "the Neutrino\n" 123 | "Burst Injector", 124 | 125 | "Keen trots through\n" 126 | "Defense Tunnel Teln", 127 | 128 | "Keen breaks into\n" 129 | "the Brownian\n" 130 | "Motion Inducer", 131 | 132 | "Keen hurries through\n" 133 | "the Gravitational\n" 134 | "Damping Hub", 135 | 136 | "Keen explodes into\n" 137 | "the Quantum\n" 138 | "Explosion Dynamo", 139 | 140 | "Keen faces danger\n" 141 | "in the secret\n" 142 | "Korath III Base", 143 | 144 | "Keen will not be\n" 145 | "in the BWBMegarocket", 146 | 147 | "Keen unexplainedly\n" 148 | "find himself by\n" 149 | "theHigh Scores" 150 | 151 | %string ck_str_storyText 152 | "Episode Five\n" 153 | "\n" 154 | "The Armageddon Machine\n" 155 | "\n" 156 | "After learning the\n" 157 | "location of the secret\n" 158 | "Shikadi base, Keen\n" 159 | "jumped in the trusty\n" 160 | "Bean-with-Bacon\n" 161 | "Megarocket and blasted\n" 162 | "across interstellar\n" 163 | "space.\n" 164 | "\n" 165 | "Seventy-five furious\n" 166 | "games of Paddle War\n" 167 | "later, Keen dropped\n" 168 | "out of lightspeed near\n" 169 | " the Korath system.\n" 170 | "\n" 171 | "He flew toward the\n" 172 | "planet, keeping it\n" 173 | "between him and the\n" 174 | "base.\n" 175 | "\n" 176 | "Pulling up underside\n" 177 | "and docking at the\n" 178 | "Ion Ventilation System,\n" 179 | "Keen must destroy the\n" 180 | "Shikadi Armageddon\n" 181 | "Machine before it\n" 182 | "explodes and destroys\n" 183 | "the Milky Way! He\n" 184 | "steps into the dark\n" 185 | "ventilation duct and\n" 186 | "begins his most\n" 187 | "dangerous adventure\n" 188 | "yet...\n" 189 | 190 | # Fuse messages 191 | 192 | %string ck5_str_fuseDestroyed "One of the four\nmachines protecting the\nmain elevator shaft--\ntoast!\n" 193 | %string ck5_str_fuseDestroyedKorath "I wonder what that\nfuse was for....\n" 194 | -------------------------------------------------------------------------------- /data/keen5/TILEINFO.CK5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen5/TILEINFO.CK5 -------------------------------------------------------------------------------- /data/keen6e14/AUDINFOE.CK6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen6e14/AUDINFOE.CK6 -------------------------------------------------------------------------------- /data/keen6e14/AUDIODCT.CK6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen6e14/AUDIODCT.CK6 -------------------------------------------------------------------------------- /data/keen6e14/AUDIOHHD.CK6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen6e14/AUDIOHHD.CK6 -------------------------------------------------------------------------------- /data/keen6e14/EGADICT.CK6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen6e14/EGADICT.CK6 -------------------------------------------------------------------------------- /data/keen6e14/EGAHEAD.CK6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen6e14/EGAHEAD.CK6 -------------------------------------------------------------------------------- /data/keen6e14/GFXINFOE.CK6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen6e14/GFXINFOE.CK6 -------------------------------------------------------------------------------- /data/keen6e14/MAPHEAD.CK6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen6e14/MAPHEAD.CK6 -------------------------------------------------------------------------------- /data/keen6e14/STRINGS.CK6: -------------------------------------------------------------------------------- 1 | # 2 | # Strings for Keen 6 (v1.4) 3 | # 4 | 5 | # Common strings 6 | 7 | 8 | %string ck_str_gameOver "Game Over!" 9 | 10 | # Paddle War 11 | %string ck_str_paddleWarKeen "KEEN:" 12 | %string ck_str_paddleWarComp "COMP:" 13 | %string ck_str_paddleWarDefeat "You lost!" 14 | %string ck_str_paddleWarVictory "You won!" 15 | %string ck_str_paddleWarPressAKey "Press any key" 16 | 17 | # Loading box for demos 18 | %string ck_str_demo "DEMO" 19 | 20 | %string ck_str_tryAgainIntro "You didn't make it past" 21 | %string ck_str_tryAgainTryAgain "Try Again" 22 | 23 | 24 | #ck_play.c 25 | 26 | %string ck_str_itemCheat "Cheat Option!\n\nYou just got all\nthe keys, 99 shots,\nand an extra keen!" 27 | 28 | %string ck_str_godModeOn "God Mode ON" 29 | %string ck_str_godModeOff "God Mode OFF" 30 | 31 | %string ck_str_freeItems "Free Items!" 32 | 33 | %string ck_str_jumpCheatOn "\nJump cheat ON" 34 | %string ck_str_jumpCheatOff "\nJump cheat OFF" 35 | 36 | %string ck_str_noClippingOn "No clipping ON" 37 | %string ck_str_noClippingOff "No clipping OFF" 38 | 39 | %string ck_str_slowMotionOn "Slow motion ON" 40 | %string ck_str_slowMotionOff "Slow motion OFF" 41 | 42 | #TODO: Warp and some other debug cheats 43 | 44 | %string ck_str_debugKeysActive "Debug keys active" 45 | %string ck_str_levelWarp " Warp to which level(1-18):" 46 | 47 | 48 | %string ck_str_paused "PAUSED" 49 | 50 | #NOTE: QuickSave feature 51 | %string ck_str_gameQuickSaved "GAME SAVED" 52 | 53 | # Status window 54 | %string ck_str_statusLocation "LOCATION" 55 | %string ck_str_statusScore "SCORE" 56 | %string ck_str_statusExtra "EXTRA" 57 | %string ck_str_statusLevel "LEVEL" # Difficulty level 58 | %string ck_str_statusEasy "Easy" 59 | %string ck_str_statusNormal "Normal" 60 | %string ck_str_statusHard "Hard" 61 | %string ck_str_statusKeys "KEYS" 62 | %string ck_str_statusAmmo "AMMO" 63 | %string ck_str_statusLives "KEENS" 64 | 65 | # Keen 6 66 | 67 | # Creature Question 68 | %string ck6_str_creatureQuestion "What is the name of this creature?" 69 | %string ck6_str_copyWrong1 "Sorry, that's not quite right." 70 | %string ck6_str_copyWrong2 "Please check your manual and try again." 71 | 72 | %string ck_str_exitToMap "Exit to Fribbulus Xax" 73 | 74 | %string ck6_str_statusItems "ITEMS" 75 | %string ck_str_statusCentilives "VIVAS" 76 | 77 | 78 | 79 | %stringarray ck_str_levelNames 80 | "Fribbulus Xax", 81 | "Bloogwaters\nCrossing", 82 | "Guard Post One", 83 | "First Dome\nof Darkness", 84 | "Second Dome\nof Darkness", 85 | "The Bloogdome", 86 | "Bloogton Mfg.,\nIncorporated", 87 | "Bloogton Tower", 88 | "Bloogfoods, Inc.", 89 | "Guard Post Two", 90 | "Bloogville", 91 | "BASA", 92 | "Guard Post Three", 93 | "Bloogbase Rec\nDistrict", 94 | "Bloogbase Mgmt.\nDistrict", 95 | "Bloog Control Center", 96 | "Blooglab", 97 | "Bean-with-Bacon\nMegarocket", 98 | "High Scores" 99 | 100 | 101 | %stringarray ck_str_levelEntryText 102 | "Keen attacks\n" 103 | "Fribbulus Xax", 104 | 105 | "Keen hops across\n" 106 | "Bloogwaters\n" 107 | "Crossing", 108 | 109 | "Keen fights his way\n" 110 | "through Guard Post One", 111 | 112 | "Keen crosses into the\n" 113 | "First Dome of Darkness", 114 | 115 | "Keen dares to enter the\n" 116 | "Second Dome of Darkness", 117 | 118 | "Keen foolishly enters\n" 119 | "the Bloogdome", 120 | 121 | "Keen makes his way\n" 122 | "into Bloogton\n" 123 | "Manufacturing", 124 | 125 | "Keen ascends\n" 126 | "Bloogton Tower", 127 | 128 | "Keen hungrily enters\n" 129 | "Bloogfoods, Inc.", 130 | 131 | "Keen smashes through\n" 132 | "Guard Post Two", 133 | 134 | "Keen seeks thrills\n" 135 | "in Bloogville", 136 | 137 | "Keen rockets into the\n" 138 | "Bloog Aeronautics and\n" 139 | "Space Administration", 140 | 141 | "Keen boldly assaults\n" 142 | "Guard Post Three", 143 | 144 | "Keen whoops it up in\n" 145 | "the Bloogbae\n" 146 | "Recreational District", 147 | 148 | "Keen purposefully struts\n" 149 | "into the Bloogbase\n" 150 | "Management District", 151 | 152 | "Keen bravely enters the\n" 153 | "Bloog Control Center,\n" 154 | "looking for Molly", 155 | 156 | "Keen warily enters\n" 157 | "Blooglab Space\n" 158 | "Station", 159 | 160 | "Keen returns to the\n" 161 | "Bean-with-Bacon\n" 162 | "Megarocket", 163 | 164 | "Keen is in the High\n" 165 | "Score screen. Call Id!" 166 | 167 | 168 | %string ck_str_storyText 169 | "Episode Six\n" 170 | "\n" 171 | "Aliens Ate My\n" 172 | "Baby Sitter!\n" 173 | "\n" 174 | "While out in his\n" 175 | "backyard clubhouse,\n" 176 | "Billy's baby sitter\n" 177 | "Molly calls him for\n" 178 | "dinner. He continues\n" 179 | "working on his new\n" 180 | "wrist computer.\n" 181 | "\n" 182 | "Suddenly, there is a\n" 183 | "loud noise outside.\n" 184 | "\n" 185 | "Rushing out, Keen finds\n" 186 | "his baby sitter gone\n" 187 | "and a note on a patch\n" 188 | "of scorched grass. The\n" 189 | "Bloogs of Fribbulus Xax\n" 190 | "are going to make a\n" 191 | "meal out of Molly!\n" 192 | "\n" 193 | "You've got to rescue\n" 194 | "her, because your\n" 195 | "parents will never\n" 196 | "believe you when you\n" 197 | "tell them...\n" 198 | "\n" 199 | "\"Aliens Ate My\n" 200 | "Baby Sitter!\"\n" 201 | 202 | 203 | # Story items 204 | 205 | %string ck6_str_getSandwich 206 | "This is the second\n" 207 | "biggest sandwich\n" 208 | "I ever saw!\n" 209 | 210 | %string ck6_str_getRope 211 | "Wow! A rope and\n" 212 | "grappling hook!\n" 213 | "They look useful!\n" 214 | 215 | %string ck6_str_getPasscard 216 | "What's this? Cool!\n" 217 | "A passcard for\n" 218 | "the Bloogstar Rocket!\n" 219 | "(It can fly though\n" 220 | "their force field.)" 221 | 222 | # ck6_obj1.c 223 | %string ck6_str_grabbiterHungry 224 | "Oh no!\n" 225 | "It's a slavering\n" 226 | "Grabbiter! He says,\n" 227 | "\"Get me lunch and\n" 228 | "I'll tell ya a secret!\"" 229 | 230 | %string ck6_str_grabbiterFed 231 | "The Grabbiter grabs\n" 232 | "the gigantic sandwich,\n" 233 | "downs it in one bite,\n" 234 | "and says,\"Here's your\n" 235 | "secret. Big meals\n" 236 | "make me sleepy!\n" 237 | 238 | %string ck6_str_rocketNoPasscard 239 | "The door makes a loud\n" 240 | "blooping noise.\n" 241 | "It says,\n" 242 | "\"Passcard required\n" 243 | "for entry.\"" 244 | 245 | %string ck6_str_cliffNoRope 246 | "What a tall cliff!\n" 247 | "Wish I had a rope\n" 248 | "and grappling hook.\n" 249 | -------------------------------------------------------------------------------- /data/keen6e14/TILEINFO.CK6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen6e14/TILEINFO.CK6 -------------------------------------------------------------------------------- /data/keen6e15/AUDINFOE.CK6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen6e15/AUDINFOE.CK6 -------------------------------------------------------------------------------- /data/keen6e15/AUDIODCT.CK6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen6e15/AUDIODCT.CK6 -------------------------------------------------------------------------------- /data/keen6e15/AUDIOHHD.CK6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen6e15/AUDIOHHD.CK6 -------------------------------------------------------------------------------- /data/keen6e15/EGADICT.CK6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen6e15/EGADICT.CK6 -------------------------------------------------------------------------------- /data/keen6e15/EGAHEAD.CK6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen6e15/EGAHEAD.CK6 -------------------------------------------------------------------------------- /data/keen6e15/GFXINFOE.CK6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen6e15/GFXINFOE.CK6 -------------------------------------------------------------------------------- /data/keen6e15/MAPHEAD.CK6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen6e15/MAPHEAD.CK6 -------------------------------------------------------------------------------- /data/keen6e15/STRINGS.CK6: -------------------------------------------------------------------------------- 1 | # 2 | # Strings for Keen 6 (v1.5) 3 | # 4 | 5 | # Common strings 6 | 7 | 8 | %string ck_str_gameOver "Game Over!" 9 | 10 | # Paddle War 11 | %string ck_str_paddleWarKeen "KEEN:" 12 | %string ck_str_paddleWarComp "COMP:" 13 | %string ck_str_paddleWarDefeat "You lost!" 14 | %string ck_str_paddleWarVictory "You won!" 15 | %string ck_str_paddleWarPressAKey "Press any key" 16 | 17 | # Loading box for demos 18 | %string ck_str_demo "DEMO" 19 | 20 | %string ck_str_tryAgainIntro "You didn't make it past" 21 | %string ck_str_tryAgainTryAgain "Try Again" 22 | 23 | 24 | #ck_play.c 25 | 26 | %string ck_str_itemCheat "Cheat Option!\n\nYou just got all\nthe keys, 99 shots,\nand an extra keen!" 27 | 28 | %string ck_str_godModeOn "God Mode ON" 29 | %string ck_str_godModeOff "God Mode OFF" 30 | 31 | %string ck_str_freeItems "Free Items!" 32 | 33 | %string ck_str_jumpCheatOn "\nJump cheat ON" 34 | %string ck_str_jumpCheatOff "\nJump cheat OFF" 35 | 36 | %string ck_str_noClippingOn "No clipping ON" 37 | %string ck_str_noClippingOff "No clipping OFF" 38 | 39 | %string ck_str_slowMotionOn "Slow motion ON" 40 | %string ck_str_slowMotionOff "Slow motion OFF" 41 | 42 | #TODO: Warp and some other debug cheats 43 | 44 | %string ck_str_debugKeysActive "Debug keys active" 45 | %string ck_str_levelWarp " Warp to which level(1-18):" 46 | 47 | 48 | %string ck_str_paused "PAUSED" 49 | 50 | #NOTE: QuickSave feature 51 | %string ck_str_gameQuickSaved "GAME SAVED" 52 | 53 | # Status window 54 | %string ck_str_statusLocation "LOCATION" 55 | %string ck_str_statusScore "SCORE" 56 | %string ck_str_statusExtra "EXTRA" 57 | %string ck_str_statusLevel "LEVEL" # Difficulty level 58 | %string ck_str_statusEasy "Easy" 59 | %string ck_str_statusNormal "Normal" 60 | %string ck_str_statusHard "Hard" 61 | %string ck_str_statusKeys "KEYS" 62 | %string ck_str_statusAmmo "AMMO" 63 | %string ck_str_statusLives "KEENS" 64 | 65 | # Keen 6 66 | 67 | # Creature Question 68 | %string ck6_str_creatureQuestion "What is the name of this creature?" 69 | %string ck6_str_copyWrong1 "Sorry, that's not quite right." 70 | %string ck6_str_copyWrong2 "Please check your manual and try again." 71 | 72 | 73 | %string ck_str_exitToMap "Exit to Fribbulus Xax" 74 | 75 | %string ck6_str_statusItems "ITEMS" 76 | %string ck_str_statusCentilives "VIVAS" 77 | 78 | 79 | 80 | %stringarray ck_str_levelNames 81 | "Fribbulus Xax", 82 | "Bloogwaters\nCrossing", 83 | "Guard Post One", 84 | "First Dome\nof Darkness", 85 | "Second Dome\nof Darkness", 86 | "The Bloogdome", 87 | "Bloogton Mfg.,\nIncorporated", 88 | "Bloogton Tower", 89 | "Bloogfoods, Inc.", 90 | "Guard Post Two", 91 | "Bloogville", 92 | "BASA", 93 | "Guard Post Three", 94 | "Bloogbase Rec\nDistrict", 95 | "Bloogbase Mgmt.\nDistrict", 96 | "Bloog Control Center", 97 | "Blooglab", 98 | "Bean-with-Bacon\nMegarocket", 99 | "High Scores" 100 | 101 | 102 | %stringarray ck_str_levelEntryText 103 | "Keen attacks\n" 104 | "Fribbulus Xax", 105 | 106 | "Keen hops across\n" 107 | "Bloogwaters\n" 108 | "Crossing", 109 | 110 | "Keen fights his way\n" 111 | "through Guard Post One", 112 | 113 | "Keen crosses into the\n" 114 | "First Dome of Darkness", 115 | 116 | "Keen dares to enter the\n" 117 | "Second Dome of Darkness", 118 | 119 | "Keen foolishly enters\n" 120 | "the Bloogdome", 121 | 122 | "Keen makes his way\n" 123 | "into Bloogton\n" 124 | "Manufacturing", 125 | 126 | "Keen ascends\n" 127 | "Bloogton Tower", 128 | 129 | "Keen hungrily enters\n" 130 | "Bloogfoods, Inc.", 131 | 132 | "Keen smashes through\n" 133 | "Guard Post Two", 134 | 135 | "Keen seeks thrills\n" 136 | "in Bloogville", 137 | 138 | "Keen rockets into the\n" 139 | "Bloog Aeronautics and\n" 140 | "Space Administration", 141 | 142 | "Keen boldly assaults\n" 143 | "Guard Post Three", 144 | 145 | "Keen whoops it up in\n" 146 | "the Bloogbae\n" 147 | "Recreational District", 148 | 149 | "Keen purposefully struts\n" 150 | "into the Bloogbase\n" 151 | "Management District", 152 | 153 | "Keen bravely enters the\n" 154 | "Bloog Control Center,\n" 155 | "looking for Molly", 156 | 157 | "Keen warily enters\n" 158 | "Blooglab Space\n" 159 | "Station", 160 | 161 | "Keen returns to the\n" 162 | "Bean-with-Bacon\n" 163 | "Megarocket", 164 | 165 | "Keen is in the High\n" 166 | "Score screen. Call Id!" 167 | 168 | 169 | %string ck_str_storyText 170 | "Episode Six\n" 171 | "\n" 172 | "Aliens Ate My\n" 173 | "Baby Sitter!\n" 174 | "\n" 175 | "While out in his\n" 176 | "backyard clubhouse,\n" 177 | "Billy's baby sitter\n" 178 | "Molly calls him for\n" 179 | "dinner. He continues\n" 180 | "working on his new\n" 181 | "wrist computer.\n" 182 | "\n" 183 | "Suddenly, there is a\n" 184 | "loud noise outside.\n" 185 | "\n" 186 | "Rushing out, Keen finds\n" 187 | "his baby sitter gone\n" 188 | "and a note on a patch\n" 189 | "of scorched grass. The\n" 190 | "Bloogs of Fribbulus Xax\n" 191 | "are going to make a\n" 192 | "meal out of Molly!\n" 193 | "\n" 194 | "You've got to rescue\n" 195 | "her, because your\n" 196 | "parents will never\n" 197 | "believe you when you\n" 198 | "tell them...\n" 199 | "\n" 200 | "\"Aliens Ate My\n" 201 | "Baby Sitter!\"\n" 202 | 203 | 204 | # Story items 205 | 206 | %string ck6_str_getSandwich 207 | "This is the second\n" 208 | "biggest sandwich\n" 209 | "I ever saw!\n" 210 | 211 | %string ck6_str_getRope 212 | "Wow! A rope and\n" 213 | "grappling hook!\n" 214 | "They look useful!\n" 215 | 216 | %string ck6_str_getPasscard 217 | "What's this? Cool!\n" 218 | "A passcard for\n" 219 | "the Bloogstar Rocket!\n" 220 | "(It can fly though\n" 221 | "their force field.)" 222 | 223 | # ck6_obj1.c 224 | %string ck6_str_grabbiterHungry 225 | "Oh no!\n" 226 | "It's a slavering\n" 227 | "Grabbiter! He says,\n" 228 | "\"Get me lunch and\n" 229 | "I'll tell ya a secret!\"" 230 | 231 | %string ck6_str_grabbiterFed 232 | "The Grabbiter grabs\n" 233 | "the gigantic sandwich,\n" 234 | "downs it in one bite,\n" 235 | "and says,\"Here's your\n" 236 | "secret. Big meals\n" 237 | "make me sleepy!\n" 238 | 239 | %string ck6_str_rocketNoPasscard 240 | "The door makes a loud\n" 241 | "blooping noise.\n" 242 | "It says,\n" 243 | "\"Passcard required\n" 244 | "for entry.\"" 245 | 246 | %string ck6_str_cliffNoRope 247 | "What a tall cliff!\n" 248 | "Wish I had a rope\n" 249 | "and grappling hook.\n" 250 | -------------------------------------------------------------------------------- /data/keen6e15/TILEINFO.CK6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/data/keen6e15/TILEINFO.CK6 -------------------------------------------------------------------------------- /src/.clang-format: -------------------------------------------------------------------------------- 1 | Language: Cpp 2 | BreakBeforeBraces: Allman 3 | AlignAfterOpenBracket: false 4 | AlignConsecutiveAssignments: false 5 | AlignConsecutiveDeclarations: false 6 | AlignEscapedNewlines: false 7 | AlignOperands: false 8 | ColumnLimit: 0 9 | IndentCaseLabels: false 10 | IndentWidth: 8 11 | IncludeCategories: 12 | - Regex: '^"ck._' 13 | Priority: 3 14 | - Regex: '^"ck_' 15 | Priority: 2 16 | - Regex: '^"id_' 17 | Priority: 1 18 | - Regex: '.*' 19 | Priority: 0 20 | TabWidth: 8 21 | ContinuationIndentWidth: 8 22 | UseTab: Always 23 | -------------------------------------------------------------------------------- /src/Makefile.osx: -------------------------------------------------------------------------------- 1 | #Omnispeak: A Commander Keen Reimplementation 2 | #Copyright (C) 2012 David Gow 3 | #Omnispeak is available at http://davidgow.net/keen/omnispeak.html 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, write to the Free Software 17 | #Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | 19 | IDOBJECTS=ck_quit.o id_mm.o id_ca.o id_in.o id_rf.o id_sd.o id_ti.o id_us_1.o id_us_2.o id_us_textscreen.o id_vh.o id_vl.o id_str.o 20 | CKOBJECTS=ck_act.o ck_inter.o ck_keen.o ck_obj.o ck_map.o ck4_map.o ck5_map.o ck6_map.o ck4_obj1.o ck4_obj2.o ck4_obj3.o ck5_obj1.o ck5_obj2.o ck5_obj3.o ck6_obj1.o ck6_obj2.o ck6_obj3.o ck_phys.o ck_game.o ck_play.o ck_misc.o ck4_misc.o ck5_misc.o ck6_misc.o ck_main.o ck_text.o ck_cross.o icon.o 21 | OPLOBJECTS=opl/dbopl.o 22 | 23 | BUILDASCPP=0 24 | BINPREFIX= 25 | 26 | ifeq ($(BUILDASCPP), 1) 27 | CXX=$(BINPREFIX)g++ 28 | else 29 | CXX=$(BINPREFIX)gcc 30 | endif 31 | 32 | INTCXXFLAGS=-arch x86_64 -arch i386 -isysroot /Developer/SDKs/MacOSX10.6.sdk -mmacosx-version-min=10.6 33 | 34 | ifeq ($(BUILDASCPP), 0) 35 | INTCXXFLAGS+= -std=c99 36 | endif 37 | 38 | OUTBIN=../bin-osx/omnispeak$(EXE_EXT) 39 | 40 | LIBS= 41 | WITH_SDL2=1 42 | ifeq ($(WITH_SDL2), 1) 43 | IDOBJECTS+= id_vl_sdl2gl.o 44 | FRAMEWORKS= -framework SDL2 -framework OpenGL 45 | SDLINCLUDE= -I/Library/Frameworks/SDL2.framework/Headers 46 | else 47 | IDOBJECTS+= id_vl_sdl12.o 48 | FRAMEWORKS= -framework SDL 49 | SDLINCLUDE= -I/Library/Frameworks/SDL.framework/Headers 50 | endif 51 | 52 | OBJ := $(IDOBJECTS:%=../obj/%) 53 | OBJ += $(CKOBJECTS:%=../obj/%) 54 | OBJ += $(OPLOBJECTS:%=../obj/%) 55 | DEPS := $(OBJ:%.o=%.d) 56 | 57 | 58 | .PHONY: all clean 59 | 60 | all: $(OUTBIN) binfiles 61 | 62 | clean: 63 | rm -f $(OUTBIN) $(OBJ) $(DEPS) 64 | 65 | binfiles: ../data/keen5/ACTION.CK5 66 | cp -f ../data/keen5/ACTION.CK5 ../bin-osx/ACTION.CK5 67 | 68 | ../obj/%.o: %.c 69 | @mkdir -p $(dir $@) 70 | $(CXX) $(INTCXXFLAGS) $(SDLINCLUDE) $(CXXFLAGS) -g -c -MMD -o $@ $< 71 | 72 | $(OUTBIN): $(OBJ) 73 | @mkdir -p $(dir $@) 74 | $(CXX) $(INTCXXFLAGS) $(CXXFLAGS) -g -o $(OUTBIN) $(OBJ) $(FRAMEWORKS) -lm $(LIBS) 75 | 76 | -include $(DEPS) 77 | -------------------------------------------------------------------------------- /src/ck4_ep.h: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2012 David Gow 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef CK4_EP_H 21 | #define CK4_EP_H 22 | 23 | #include 24 | #include "ck_ep.h" 25 | 26 | /* 27 | * Contains definitions relevant only to Keen 5 28 | */ 29 | extern CK_EpisodeDef ck4_episode; 30 | 31 | /* Action functions setup */ 32 | void CK4_Obj1_SetupFunctions(void); 33 | void CK4_Obj2_SetupFunctions(void); 34 | void CK4_Obj3_SetupFunctions(void); 35 | void CK4_Map_SetupFunctions(void); 36 | void CK4_Misc_SetupFunctions(void); 37 | void CK4_SetupFunctions(void); 38 | bool CK4_IsPresent(void); 39 | void CK4_DefineConstants(void); 40 | 41 | void CK4_ScanInfoLayer(); 42 | 43 | /* Spawning functions */ 44 | 45 | /* ck4_misc.c */ 46 | void CK4_SpawnLevelEnd(void); 47 | CK_object *CK4_SpawnEnemyShot(int posX, int posY, CK_action *action); 48 | void CK4_SpawnScubaKeen(int tileX, int tileY); 49 | 50 | void CK4_ShowCouncilMessage(void); 51 | void CK4_ShowWetsuitMessage(void); 52 | void CK4_ShowCantSwimMessage(void); 53 | void CK4_ShowJanitorMessage(void); 54 | void CK4_ShowPrincessMessage(void); 55 | 56 | /* ck4_obj1.c */ 57 | void CK4_SpawnMiragia(int tileX, int tileY); 58 | void CK4_SpawnCouncilMember(int tileX, int tileY); 59 | void CK4_SpawnSlug(int tileX, int tileY); 60 | void CK4_SpawnMushroom(int tileX, int tileY); 61 | void CK4_SpawnEgg(int tileX, int tileY); 62 | void CK4_SpawnBird(int tileX, int tileY); 63 | void CK4_SpawnArachnut(int tileX, int tileY); 64 | void CK4_SpawnSkypest(int tileX, int tileY); 65 | 66 | /* ck4_obj2.c */ 67 | void CK4_SpawnWormmouth(int tileX, int tileY); 68 | void CK4_SpawnCloud(int tileX, int tileY); 69 | void CK4_SpawnBerkeloid(int tileX, int tileY); 70 | void CK4_SpawnInchworm(int tileX, int tileY); 71 | void CK4_SpawnFoot(int tileX, int tileY); 72 | void CK4_SpawnBounder(int tileX, int tileY); 73 | void CK4_SpawnLick(int tileX, int tileY); 74 | void CK4_SpawnAxisPlatform(int tileX, int tileY, int direction); 75 | 76 | /* ck4_obj3.c */ 77 | void CK4_SpawnSmirky(int tileX, int tileY); 78 | void CK4_SpawnMimrock(int tileX, int tileY); 79 | void CK4_SpawnDopefish(int tileX, int tileY); 80 | void CK4_SpawnSchoolfish(int tileX, int tileY); 81 | void CK4_SpawnMine(int tileX, int tileY, int direction); 82 | void CK4_SpawnSprite(int tileX, int tileY); 83 | void CK4_SpawnLindsey(int tileX, int tileY); 84 | void CK4_SpawnDartGun(int tileX, int tileY, int direction); 85 | void CK4_SpawnWetsuit(int tileX, int tileY); 86 | 87 | /* ck4_map.c */ 88 | void CK4_MapMiscFlagsCheck(CK_object *keen); 89 | 90 | /* Map functions */ 91 | void CK_MapMiscFlagsCheck(CK_object *keen); 92 | void CK_MapFlagSpawn(int tileX, int tileY); 93 | 94 | /* Misc functions */ 95 | 96 | /* ck4_misc.c */ 97 | void CK_StunCreature(CK_object *creature, CK_object *stunner, CK_action *new_creature_act); 98 | void CK4_EndingPurge(void); 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /src/ck4_map.c: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2012 David Gow 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include "id_ca.h" 21 | #include "id_in.h" 22 | #include "id_rf.h" 23 | #include "id_sd.h" 24 | #include "id_vl.h" 25 | #include "ck_act.h" 26 | #include "ck_def.h" 27 | #include "ck_game.h" 28 | #include "ck_phys.h" 29 | #include "ck_play.h" 30 | #include "ck4_ep.h" 31 | 32 | #include 33 | #include 34 | 35 | // ========================================================================= 36 | 37 | void CK4_MapKeenFoot(CK_object *obj) 38 | { 39 | int spriteSync = SD_GetSpriteSync(); 40 | obj->user1 -= spriteSync; 41 | ck_nextX = spriteSync * obj->velX; 42 | ck_nextY = spriteSync * obj->velY; 43 | if (obj->user1 <= 0) 44 | { 45 | ck_nextX -= obj->velX * -obj->user1; 46 | ck_nextY -= obj->velY * -obj->user1; 47 | obj->zLayer = PRIORITIES - 3; 48 | obj->user1 = 6; 49 | obj->user2 = 3; 50 | obj->user3 = 0; 51 | ck_keenObj->xDirection = ck_keenObj->yDirection = IN_motion_None; // use global pointer for some reason 52 | obj->currentAction = CK_ACTION(CK_ACT_MapKeenStart); 53 | obj->gfxChunk = 256; 54 | obj->clipped = CLIP_normal; 55 | } 56 | } 57 | 58 | static int ck4_swimFrames[] = {280, 288, 282, 290, 284, 292, 286, 294}; 59 | void CK4_MapKeenSwim(CK_object *obj) 60 | { 61 | if (obj->user3) 62 | { 63 | if ((obj->user3 -= 6) < 0) 64 | obj->user3 = 0; 65 | } 66 | else 67 | { 68 | obj->xDirection = ck_inputFrame.xDirection; 69 | obj->yDirection = ck_inputFrame.yDirection; 70 | 71 | if (ck_inputFrame.xDirection || ck_inputFrame.yDirection) 72 | obj->user1 = ck_inputFrame.dir; 73 | } 74 | 75 | obj->gfxChunk = ck4_swimFrames[obj->user1] + obj->user2; 76 | 77 | if (++obj->user2 == 2) 78 | obj->user2 = 0; 79 | 80 | SD_PlaySound(obj->user2 ? CK_SOUNDNUM(SOUND_KEENSWIMHI) : CK_SOUNDNUM(SOUND_KEENSWIMLO)); 81 | } 82 | 83 | static int ck4_wetsuitOffs[] = {4, 6, 0, 2}; 84 | static int ck4_wetsuitOffs2[] = {4, 5, 6, 7, 0, 1, 2, 3}; 85 | void CK4_MapMiscFlagsCheck(CK_object *obj) 86 | { 87 | if (!obj->user3) 88 | { 89 | int midX = obj->clipRects.tileXmid; 90 | int midY = RF_UnitToTile(obj->clipRects.unitY1 + (obj->clipRects.unitY2 - obj->clipRects.unitY1) / 2); 91 | int mf = TI_ForeMisc(CA_TileAtPos(midX, midY, 1)); 92 | 93 | if (mf == MF_WaterN || mf == MF_WaterE || mf == MF_WaterS || mf == MF_WaterW) 94 | { 95 | if (!ck_gameState.ep.ck4.wetsuit) 96 | { 97 | SD_PlaySound(CK_SOUNDNUM(SOUND_NEEDKEYCARD)); 98 | CK4_ShowCantSwimMessage(); 99 | // RF_ForceRefresh(); 100 | ck_nextX = -obj->deltaPosX; 101 | ck_nextY = -obj->deltaPosY; 102 | obj->xDirection = obj->yDirection = 0; 103 | CK_PhysUpdateNormalObj(obj); 104 | } 105 | else 106 | { 107 | obj->user1 = ck4_wetsuitOffs[mf - MF_WaterN]; 108 | 109 | if (obj->currentAction == CK_ACTION(CK4_ACT_MapKeenSwim0)) 110 | obj->user1 = ck4_wetsuitOffs2[obj->user1]; 111 | 112 | switch (obj->user1) 113 | { 114 | case 0: 115 | obj->xDirection = 0; 116 | obj->yDirection = -1; 117 | break; 118 | case 2: 119 | obj->xDirection = 1; 120 | obj->yDirection = 0; 121 | break; 122 | case 4: 123 | obj->xDirection = 0; 124 | obj->yDirection = 1; 125 | break; 126 | case 6: 127 | obj->xDirection = -1; 128 | obj->yDirection = 0; 129 | break; 130 | } 131 | 132 | obj->user2 = 0; 133 | obj->user3 = 18; 134 | 135 | if (obj->currentAction == CK_ACTION(CK4_ACT_MapKeenSwim0)) 136 | CK_SetAction2(obj, CK_ACTION(CK_ACT_MapKeenStart)); 137 | else 138 | CK_SetAction2(obj, CK_ACTION(CK4_ACT_MapKeenSwim0)); 139 | } 140 | } 141 | } 142 | } 143 | 144 | void CK4_Map_SetupFunctions() 145 | { 146 | CK_ACT_AddFunction("CK4_MapKeenFoot", &CK4_MapKeenFoot); 147 | CK_ACT_AddFunction("CK4_MapKeenSwim", &CK4_MapKeenSwim); 148 | CK_ACT_AddFunction("CK4_MapMiscFlagsCheck", &CK4_MapMiscFlagsCheck); 149 | } 150 | -------------------------------------------------------------------------------- /src/ck5_ep.h: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2012 David Gow 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef CK5_EP_H 21 | #define CK5_EP_H 22 | 23 | #include 24 | #include "ck_ep.h" 25 | 26 | /* 27 | * Contains definitions relevant only to Keen 5 28 | */ 29 | extern CK_EpisodeDef ck5_episode; 30 | 31 | /* Action functions setup */ 32 | void CK5_Obj1_SetupFunctions(void); 33 | void CK5_Obj2_SetupFunctions(void); 34 | void CK5_Obj3_SetupFunctions(void); 35 | void CK5_Map_SetupFunctions(void); 36 | void CK5_SetupFunctions(void); 37 | bool CK5_IsPresent(void); 38 | void CK5_DefineConstants(void); 39 | 40 | void CK5_ScanInfoLayer(); 41 | 42 | /* Spawning functions */ 43 | 44 | /* ck5_misc.c */ 45 | void CK5_SpawnFuseExplosion(int tileX, int tileY); 46 | void CK5_SpawnLevelEnd(void); 47 | void CK5_SpawnLightning(void); 48 | CK_object *CK5_SpawnEnemyShot(int posX, int posY, CK_action *action); 49 | void CK5_SpawnRedBlockPlatform(int tileX, int tileY, int direction, bool purple); 50 | void CK5_SpawnItem(int tileX, int tileY, int itemNumber); 51 | 52 | /* ck5_obj1.c */ 53 | void CK5_SpawnVolte(int tileX, int tileY); 54 | 55 | /* ck5_obj2.c */ 56 | void CK5_SpawnSparky(int tileX, int tileY); 57 | void CK5_SpawnAmpton(int tileX, int tileY); 58 | void CK5_SpawnSlice(int tileX, int tileY, int dir); 59 | void CK5_SpawnSliceDiag(int tileX, int tileY); 60 | void CK5_SpawnShelly(int tileX, int tileY); 61 | 62 | /* ck5_obj3.c */ 63 | void CK5_SpawnMine(int tileX, int tileY); 64 | void CK5_SpawnRobo(int tileX, int tileY); 65 | void CK5_SpawnSpirogrip(int tileX, int tileY); 66 | void CK5_SpawnSpindred(int tileX, int tileY); 67 | void CK5_SpawnMaster(int tileX, int tileY); 68 | void CK5_SpawnShikadi(int tileX, int tileY); 69 | void CK5_SpawnShocksund(int tileX, int tileY); 70 | void CK5_SpawnSphereful(int tileX, int tileY); 71 | void CK5_SpawnKorath(int tileX, int tileY); 72 | void CK5_QEDSpawn(int tileX, int tileY); 73 | 74 | /* ck5_map.c */ 75 | void CK5_MapMiscFlagsCheck(CK_object *keen); 76 | void CK_SpawnMapKeen(int tileX, int tileY); 77 | void CK5_MapKeenTeleSpawn(int tileX, int tileY); 78 | 79 | /* Map functions */ 80 | void CK5_AnimateMapTeleporter(int tileX, int tileY); 81 | void CK5_AnimateMapElevator(int tileX, int tileY, int dir); 82 | 83 | /* Misc functions */ 84 | 85 | /* ck5_misc.c */ 86 | void CK5_ExplodeGalaxy(); 87 | void CK5_FuseMessage(); 88 | 89 | #endif 90 | -------------------------------------------------------------------------------- /src/ck5_obj1.c: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2012 David Gow 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include "id_ca.h" 21 | #include "id_rf.h" 22 | #include "ck_act.h" 23 | #include "ck_def.h" 24 | #include "ck_phys.h" 25 | #include "ck_play.h" 26 | 27 | #include 28 | 29 | extern int ck_infoplaneArrowsX[]; 30 | extern int ck_infoplaneArrowsY[]; 31 | 32 | void CK5_PurpleGoPlatThink(CK_object *obj) 33 | { 34 | 35 | if (ck_nextX || ck_nextY) 36 | return; 37 | 38 | int16_t delta = SD_GetSpriteSync() * 12; 39 | 40 | // Will we reach a new tile? 41 | if (obj->user2 > delta) 42 | { 43 | // No... keep moving in the same direction. 44 | obj->user2 -= delta; 45 | 46 | int dirX = ck_infoplaneArrowsX[obj->user1]; 47 | if (dirX == 1) 48 | { 49 | // Moving right. 50 | ck_nextX += delta; 51 | } 52 | else if (dirX == -1) 53 | { 54 | // Moving left 55 | ck_nextX -= delta; 56 | } 57 | 58 | int dirY = ck_infoplaneArrowsY[obj->user1]; 59 | if (dirY == 1) 60 | { 61 | // Moving down 62 | ck_nextY += delta; 63 | } 64 | else if (dirY == -1) 65 | { 66 | // Moving up 67 | ck_nextY -= delta; 68 | } 69 | } 70 | else 71 | { 72 | // Move to next tile. 73 | int dirX = ck_infoplaneArrowsX[obj->user1]; 74 | if (dirX == 1) 75 | { 76 | // Moving right. 77 | ck_nextX += obj->user2; 78 | } 79 | else if (dirX == -1) 80 | { 81 | // Moving left 82 | ck_nextX -= obj->user2; 83 | } 84 | 85 | int dirY = ck_infoplaneArrowsY[obj->user1]; 86 | if (dirY == 1) 87 | { 88 | // Moving down 89 | ck_nextY += obj->user2; 90 | } 91 | else if (dirY == -1) 92 | { 93 | // Moving up 94 | ck_nextY -= obj->user2; 95 | } 96 | 97 | int tileX = RF_UnitToTile(obj->posX + ck_nextX + 0x40); 98 | int tileY = RF_UnitToTile(obj->posY + ck_nextY + 0x40); 99 | 100 | obj->user1 = CA_TileAtPos(tileX, tileY, 2) - 0x5B; 101 | 102 | if ((obj->user1 < 0) || (obj->user1 > 8)) 103 | { 104 | Quit("Goplat moved to a bad spot."); 105 | } 106 | 107 | delta -= obj->user2; 108 | obj->user2 = 256 - delta; 109 | 110 | // Move in the new direction. 111 | dirX = ck_infoplaneArrowsX[obj->user1]; 112 | if (dirX == 1) 113 | { 114 | // Moving right. 115 | ck_nextX += delta; 116 | } 117 | else if (dirX == -1) 118 | { 119 | // Moving left 120 | ck_nextX -= delta; 121 | } 122 | 123 | dirY = ck_infoplaneArrowsY[obj->user1]; 124 | if (dirY == 1) 125 | { 126 | // Moving down 127 | ck_nextY += delta; 128 | } 129 | else if (dirY == -1) 130 | { 131 | // Moving up 132 | ck_nextY -= delta; 133 | } 134 | } 135 | } 136 | 137 | void CK5_SpawnVolte(int tileX, int tileY) 138 | { 139 | 140 | int dir; 141 | 142 | CK_object *new_object = CK_GetNewObj(false); 143 | new_object->type = CT5_Volte; 144 | new_object->active = OBJ_ALWAYS_ACTIVE; 145 | new_object->zLayer = 2; 146 | new_object->posX = RF_TileToUnit(tileX); 147 | new_object->posY = RF_TileToUnit(tileY); 148 | new_object->clipped = CLIP_not; 149 | CK_SetAction(new_object, CK_ACTION(CK5_ACT_Volte0)); 150 | 151 | // Initialize Volte Direction 152 | // (Vanilla keen does this with far pointer arithmetic) 153 | if (CA_TileAtPos(tileX - 1, tileY, 2) == 0x5C) 154 | dir = 1; 155 | else if (CA_TileAtPos(tileX + 1, tileY, 2) == 0x5E) 156 | dir = 3; 157 | else if (CA_TileAtPos(tileX, tileY - 1, 2) == 0x5D) 158 | dir = 2; 159 | else if (CA_TileAtPos(tileX, tileY + 1, 2) == 0x5B) 160 | dir = 0; 161 | else 162 | Quit("Volte spawned at bad spot!"); // Not present in vanilla keen 163 | 164 | CA_SetTileAtPos(tileX, tileY, 2, dir + 0x5B); 165 | new_object->user1 = dir; 166 | new_object->user2 = 0x100; 167 | } 168 | 169 | // This is very similar to the GoPlat function 170 | // The only difference is the increased speed and the error message 171 | void CK5_VolteMove(CK_object *obj) 172 | { 173 | 174 | if (ck_nextX || ck_nextY) 175 | return; 176 | 177 | int16_t delta = SD_GetSpriteSync() * CK_INT(CK5_VolteSpeed, 32); 178 | 179 | // Will we reach a new tile? 180 | if (obj->user2 > delta) 181 | { 182 | // No... keep moving in the same direction. 183 | obj->user2 -= delta; 184 | 185 | int16_t dirX = ck_infoplaneArrowsX[obj->user1]; 186 | if (dirX == 1) 187 | { 188 | // Moving right. 189 | ck_nextX += delta; 190 | } 191 | else if (dirX == -1) 192 | { 193 | // Moving left 194 | ck_nextX -= delta; 195 | } 196 | 197 | int16_t dirY = ck_infoplaneArrowsY[obj->user1]; 198 | if (dirY == 1) 199 | { 200 | // Moving down 201 | ck_nextY += delta; 202 | } 203 | else if (dirY == -1) 204 | { 205 | // Moving up 206 | ck_nextY -= delta; 207 | } 208 | } 209 | else 210 | { 211 | // Move to next tile. 212 | int16_t dirX = ck_infoplaneArrowsX[obj->user1]; 213 | if (dirX == 1) 214 | { 215 | // Moving right. 216 | ck_nextX += obj->user2; 217 | } 218 | else if (dirX == -1) 219 | { 220 | // Moving left 221 | ck_nextX -= obj->user2; 222 | } 223 | 224 | int16_t dirY = ck_infoplaneArrowsY[obj->user1]; 225 | if (dirY == 1) 226 | { 227 | // Moving down 228 | ck_nextY += obj->user2; 229 | } 230 | else if (dirY == -1) 231 | { 232 | // Moving up 233 | ck_nextY -= obj->user2; 234 | } 235 | 236 | int16_t tileX = RF_UnitToTile(obj->posX + ck_nextX); 237 | int16_t tileY = RF_UnitToTile(obj->posY + ck_nextY); 238 | 239 | obj->user1 = CA_TileAtPos(tileX, tileY, 2) - 0x5B; 240 | 241 | if ((obj->user1 < 0) || (obj->user1 > 8)) 242 | { 243 | // TODO: Add printf style variable arg list to Quit() 244 | // and add the offending tile here 245 | Quit("Volte moved to a bad spot"); 246 | } 247 | 248 | delta -= obj->user2; 249 | obj->user2 = 256 - delta; 250 | 251 | // Move in the new direction. 252 | dirX = ck_infoplaneArrowsX[obj->user1]; 253 | if (dirX == 1) 254 | { 255 | // Moving right. 256 | ck_nextX += delta; 257 | } 258 | else if (dirX == -1) 259 | { 260 | // Moving left 261 | ck_nextX -= delta; 262 | } 263 | 264 | dirY = ck_infoplaneArrowsY[obj->user1]; 265 | if (dirY == 1) 266 | { 267 | // Moving down 268 | ck_nextY += delta; 269 | } 270 | else if (dirY == -1) 271 | { 272 | // Moving up 273 | ck_nextY -= delta; 274 | } 275 | } 276 | } 277 | 278 | void CK5_VolteCol(CK_object *volte, CK_object *other) 279 | { 280 | 281 | if (other->type == CT_Player) 282 | { 283 | CK_KillKeen(); 284 | } 285 | else if (other->type == CT_Stunner) 286 | { //stunner 287 | CK_ShotHit(other); 288 | CK_SetAction2(volte, CK_ACTION(CK5_ACT_VolteStunned)); 289 | } 290 | } 291 | 292 | /* 293 | * Setup all of the functions in this file. 294 | */ 295 | void CK5_Obj1_SetupFunctions() 296 | { 297 | CK_ACT_AddFunction("CK5_PurpleGoPlatThink", &CK5_PurpleGoPlatThink); 298 | 299 | // VolteFace 300 | CK_ACT_AddFunction("CK5_VolteMove", &CK5_VolteMove); 301 | CK_ACT_AddColFunction("CK5_VolteCol", &CK5_VolteCol); 302 | } 303 | -------------------------------------------------------------------------------- /src/ck6_ep.h: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2012 David Gow 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef CK6_EP_H 21 | #define CK6_EP_H 22 | 23 | #include 24 | #include "ck_ep.h" 25 | 26 | /* 27 | * Contains definitions relevant only to Keen 6 28 | */ 29 | extern CK_EpisodeDef ck6_episode; 30 | 31 | /* Action functions setup */ 32 | void CK6_Obj1_SetupFunctions(void); 33 | void CK6_Obj2_SetupFunctions(void); 34 | void CK6_Obj3_SetupFunctions(void); 35 | void CK6_Map_SetupFunctions(void); 36 | void CK6_SetupFunctions(void); 37 | bool CK6_IsPresent(void); 38 | void CK6_DefineConstants(void); 39 | 40 | void CK6_ScanInfoLayer(); 41 | 42 | /* Spawning functions */ 43 | 44 | /* ck6_misc.c */ 45 | CK_object *CK6_SpawnEnemyShot(int posX, int posY, CK_action *action); 46 | 47 | void CK6_ShowGetSandwich(); 48 | void CK6_ShowGetRope(); 49 | void CK6_ShowGetPasscard(); 50 | 51 | /* ck6_obj1.c */ 52 | void CK6_SpawnGrabbiter(int tileX, int tileY); 53 | void CK6_SpawnRocket(int tileX, int tileY, int dir); 54 | void CK6_SpawnMapCliff(int tileX, int tileY, int dir); 55 | void CK6_SpawnSatelliteLoading(int tileX, int tileY, int dir); 56 | void CK6_SpawnSatellite(int tileX, int tileY); 57 | 58 | void CK6_SpawnSandwich(int tileX, int tileY); 59 | void CK6_SpawnRope(int tileX, int tileY); 60 | void CK6_SpawnPasscard(int tileX, int tileY); 61 | void CK6_SpawnMolly(int tileX, int tileY); 62 | void CK6_SpawnBloog(int tileX, int tileY); 63 | void CK6_SpawnBloogguard(int tileX, int tileY); 64 | void CK6_SpawnBlooglet(int tileX, int tileY, int type); 65 | 66 | /* ck6_obj2.c */ 67 | void CK6_SpawnNospike(int tileX, int tileY); 68 | void CK6_SpawnGik(int tileX, int tileY); 69 | void CK6_SpawnOrbatrix(int tileX, int tileY); 70 | void CK6_SpawnBipship(int tileX, int tileY); 71 | void CK6_SpawnFlect(int tileX, int tileY); 72 | 73 | /* ck6_obj3.c */ 74 | void CK6_SpawnFleex(int tileX, int tileY); 75 | void CK6_SpawnBobba(int tileX, int tileY); 76 | void CK6_SpawnBabobba(int tileX, int tileY); 77 | void CK6_SpawnBlorb(int tileX, int tileY); 78 | void CK6_SpawnCeilick(int tileX, int tileY); 79 | 80 | /* ck6_map.c */ 81 | void CK6_MapMiscFlagsCheck(CK_object *keen); 82 | void CK_SpawnMapKeen(int tileX, int tileY); 83 | 84 | /* Map functions */ 85 | 86 | /* Misc functions */ 87 | 88 | /* ck6_misc.c */ 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /src/ck6_map.c: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2012 David Gow 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include "id_ca.h" 21 | #include "id_in.h" 22 | #include "id_rf.h" 23 | #include "id_sd.h" 24 | #include "id_vl.h" 25 | #include "ck_act.h" 26 | #include "ck_def.h" 27 | #include "ck_game.h" 28 | #include "ck_phys.h" 29 | #include "ck_play.h" 30 | #include "ck6_ep.h" 31 | 32 | #include 33 | #include 34 | 35 | // ========================================================================= 36 | 37 | void CK6_MapMiscFlagsCheck(CK_object *obj) 38 | { 39 | if (obj->user3 == 0) 40 | { 41 | int tileX = obj->clipRects.tileXmid; 42 | int tileY = RF_UnitToTile(obj->clipRects.unitY1 + 43 | (obj->clipRects.unitY2 - obj->clipRects.unitY1) / 2); 44 | uint16_t tile = CA_TileAtPos(tileX, tileY, 1); 45 | uint8_t miscValue = TI_ForeMisc(tile); 46 | 47 | if (miscValue == MISCFLAG_TELEPORT) 48 | CK_AnimateMapTeleporter(tileX, tileY); 49 | } 50 | } 51 | 52 | void CK6_Map_SetupFunctions() 53 | { 54 | CK_ACT_AddFunction("CK6_MapMiscFlagsCheck", &CK6_MapMiscFlagsCheck); 55 | } 56 | -------------------------------------------------------------------------------- /src/ck_act.h: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2012 David Gow 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef CK_ACT_H 21 | #define CK_ACT_H 22 | 23 | #include 24 | 25 | typedef struct CK_object CK_object; 26 | typedef struct CK_action CK_action; 27 | 28 | typedef void (*CK_ACT_Function)(CK_object *obj); 29 | typedef void (*CK_ACT_ColFunction)(CK_object *obj1, CK_object *obj2); 30 | 31 | void CK_ACT_SetupFunctions(); 32 | void CK_ACT_AddFunction(const char *fnName, CK_ACT_Function fn); 33 | void CK_ACT_AddColFunction(const char *fnName, CK_ACT_ColFunction fn); 34 | CK_ACT_Function CK_ACT_GetFunction(const char *fnName); 35 | CK_ACT_ColFunction CK_ACT_GetColFunction(const char *fnName); 36 | void CK_VAR_Startup(); 37 | const char *CK_VAR_GetString(const char *name, const char *def); 38 | intptr_t CK_VAR_GetInt(const char *name, intptr_t def); 39 | intptr_t *CK_VAR_GetIntArray(const char *name); 40 | intptr_t CK_VAR_GetIntArrayElement(const char *name, int index); 41 | const char **CK_VAR_GetStringArray(const char *name); 42 | const char *CK_VAR_GetStringArrayElement(const char *name, int index); 43 | CK_action *CK_GetActionByName(const char *name); 44 | CK_action *CK_GetOrCreateActionByName(const char *name); 45 | CK_action *CK_LookupActionFrom16BitOffset(uint16_t offset); // POTENTIALLY SLOW function - Use in game loading only! 46 | void CK_VAR_SetInt(const char *name, intptr_t val); 47 | void CK_VAR_SetString(const char *name, const char *val); 48 | void CK_VAR_LoadVars(const char *filename); 49 | 50 | #ifdef CK_STRINGS_LINKED 51 | // TODO: This is here in case we want to support building string values directly 52 | // into the executable again. (I have an in-progress tool to do this, though 53 | // it lacks support for a few things, so it's not workable at present.) 54 | #define CK_STRING(s) STRING_ ## s 55 | #else 56 | #define CK_STRING(s) CK_VAR_GetString(#s, #s) 57 | #endif 58 | 59 | #ifdef CK_VARS_LINKED 60 | #define CK_INT(name, def) INT_ ## name 61 | #define CK_CHUNKNUM(name) INT_ ## name 62 | #define CK_SOUNDNUM(name) INT_ ## name 63 | #define CK_ACTION(name) (&name) 64 | #define CK_FUNCTION(name) (&name) 65 | typedef int16_t chunk_id_t; 66 | #define CK_CHUNKID(name) CK_CHUNKNUM(name) 67 | #define CK_LookupChunk(id) (id) 68 | #define CK_INTARRAY(name) INTARRAY_ ## name 69 | #define CK_INTELEMENT(name, i) (CK_INTARRAY(name)[i]) 70 | #define CK_STRINGARRAY(name) STRARRAY_ ## name 71 | #define CK_STRINGELEMENT(name, i) (CK_STRINGARRAY(name)[i]) 72 | #define CK_FILENAME(name, def) STRINGS_ ## name 73 | #else 74 | #define CK_INT(name, default) CK_VAR_GetInt(#name, default) 75 | #define CK_CHUNKNUM(name) CK_VAR_GetInt(#name, 0) 76 | #define CK_SOUNDNUM(name) CK_VAR_GetInt(#name, 0) 77 | #define CK_ACTION(name) CK_GetActionByName(#name) 78 | #define CK_FUNCTION(name) CK_ACT_GetFunction(#name) 79 | typedef const char *chunk_id_t; 80 | #define CK_CHUNKID(name) #name 81 | #define CK_LookupChunk(id) CK_VAR_GetInt(id, 0) 82 | #define CK_INTARRAY(name) CK_VAR_GetIntArray(#name) 83 | #define CK_INTELEMENT(name, i) CK_VAR_GetIntArrayElement(#name, i) 84 | #define CK_STRINGARRAY(name) CK_VAR_GetStringArray(#name) 85 | #define CK_STRINGELEMENT(name, i) CK_VAR_GetStringArrayElement(#name, i) 86 | #define CK_FILENAME(name, def) CK_VAR_GetString(#name, FS_AdjustExtension(def)) 87 | #endif 88 | 89 | 90 | #endif 91 | 92 | -------------------------------------------------------------------------------- /src/ck_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2019 Omnispeak Authors 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef CK_CONFIG_H 21 | #define CK_CONFIG_H 22 | 23 | // ================================= 24 | // Episode Selection 25 | // ================================= 26 | 27 | // We always need at least one episode enabled. 28 | #if !defined(WITH_KEEN4) && !defined(WITH_KEEN5) && !defined(WITH_KEEN6) 29 | #error Need to enable at least one episode! 30 | #endif 31 | 32 | 33 | // ================================= 34 | // Always-enabled config options 35 | // ================================= 36 | 37 | // We now support dirty-rectangle drawing, so there's no need to always 38 | // redraw the whole screen on each frame. You can enable this, though, if you 39 | // prefer (e.g., to have something to compare the dirty-rectangle drawing 40 | // against.) 41 | // (NOTE: You'll need to enable this on double-buffered backends for accuracy 42 | // at the moment, as VL_SyncPages() isn't implemented. The performance hit on 43 | // DOS isn't really worth it, though.) 44 | //#define ALWAYS_REDRAW 45 | #define FS_MAX_FILENAME_LEN 24 46 | 47 | // ================================= 48 | // Episode-specific config options 49 | // ================================= 50 | #if defined(WITH_KEEN4) || defined(WITH_KEEN5) 51 | #define HAS_HELPSCREEN 52 | #endif 53 | 54 | // ================================= 55 | // Options for DEBUG builds only. 56 | // ================================= 57 | #ifdef CK_DEBUG 58 | // Enable all debug messages by default. 59 | #define CK_DEFAULT_LOG_LEVEL CK_LOG_MSG_NORMAL 60 | // Debug version of the ID_MM_Arena allocator. 61 | #define ID_MM_DEBUGARENA 62 | // Typechecking for variables. 63 | #ifndef CK_VAR_TYPECHECK // Might already be set for varparser 64 | #define CK_VAR_TYPECHECK 65 | #endif 66 | // Warn on use of unset variable 67 | #define CK_VAR_WARNONNOTSET 68 | // Warn on out-of-bounds access to tileinfo. 69 | #define CK_WARN_ON_TILEINFO_OOB 70 | // Support the /DUMPFILE option for the playloop dumper 71 | #define CK_ENABLE_PLAYLOOP_DUMPER 72 | #else 73 | // Release builds only show warnings and higher 74 | #define CK_DEFAULT_LOG_LEVEL CK_LOG_MSG_WARNING 75 | #endif 76 | 77 | // ================================= 78 | // Options for VANILLA builds only. 79 | // ================================= 80 | #ifndef CK_VANILLA 81 | 82 | // Define a boolean for new features 83 | #define CK_NEW_FEATURE_DEFAULT false 84 | 85 | // The Fullscreen/Aspect Ratio/etc options 86 | #define EXTRA_GRAPHICS_OPTIONS 87 | 88 | // Support for rebinding 'Status' 89 | #define EXTRA_KEYBOARD_OPTIONS 90 | 91 | // Joystick names, Joystick Configuration 92 | #define EXTRA_JOYSTICK_OPTIONS 93 | 94 | // QuickSave 95 | #define QUICKSAVE_ENABLED 96 | 97 | // Use all input devices by default 98 | #define DEFAULT_INPUT IN_ctrl_All 99 | #define FORCE_DEFAULT_INPUT 100 | #else 101 | 102 | // Otherwise, enable default new features 103 | #define CK_NEW_FEATURE_DEFAULT false 104 | #endif 105 | 106 | // ================================= 107 | // Filesystem (ID_FS) options. 108 | // ================================= 109 | 110 | // Default paths for Omni / Keen / User files. 111 | // (See the id_fs.h documentation for more info.) 112 | #ifndef FS_DEFAULT_KEEN_PATH 113 | #define FS_DEFAULT_KEEN_PATH "." 114 | #endif 115 | #ifndef FS_DEFAULT_OMNI_PATH 116 | #define FS_DEFAULT_OMNI_PATH FS_DEFAULT_KEEN_PATH 117 | #endif 118 | #ifndef FS_DEFAULT_USER_PATH 119 | #define FS_DEFAULT_USER_PATH "." 120 | #endif 121 | 122 | // Look for Omnispeak-specific files in the Keen directory first 123 | #ifndef FS_NO_PREFER_KEEN_PATH 124 | #define FS_PREFER_KEEN_PATH 125 | #endif 126 | 127 | // If the Omni path isn't valid, fall back to the directory 128 | // containing the executable. SDL 2.0.1 or higher required. 129 | #if !defined(FS_NO_OMNI_EXEDIR_FALLBACK) && defined(WITH_SDL) 130 | #define FS_OMNI_EXEDIR_FALLBACK 131 | #endif 132 | 133 | // Enable this to prefer XDG paths for the user directory to the "DEFAULT" 134 | // path above. This is disabled by default, in which case XDG paths are 135 | // used as a fallback. SDL 2.0.1 is required. 136 | //#define FS_USER_PATH_PREFER_XDG 137 | 138 | // Fallback to the XDG paths if the current user path is not writable. 139 | #ifdef WITH_SDL 140 | #define FS_USER_XDG_FALLBACK 141 | #endif 142 | 143 | #define FS_XDG_ORGANISATION "Commander Keen" 144 | #define FS_XDG_APPLICATION "Omnispeak" 145 | 146 | // ================================= 147 | // Cache Manager (ID_CA) options. 148 | // ================================= 149 | 150 | // Read uncompressed audio data (AUDIOT, AUDIOHED) 151 | //#define CA_AUDIOUNCOMPRESSED 152 | 153 | #endif //CK_CONFIG_H 154 | -------------------------------------------------------------------------------- /src/ck_cross.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "id_in.h" 5 | #include "id_sd.h" 6 | #include "id_us.h" 7 | #include "ck_cross.h" 8 | 9 | #ifdef CK_RAND_DEBUG 10 | #include 11 | #endif 12 | 13 | const char *ck_cross_logLevel_strings[] = { 14 | "normal", 15 | "warning", 16 | "error", 17 | "none" 18 | }; 19 | 20 | CK_Log_Message_Class_T ck_cross_logLevel = CK_DEFAULT_LOG_LEVEL; 21 | 22 | #ifdef VL_EGA 23 | #include 24 | extern bool vl_started; 25 | #endif 26 | 27 | void CK_PRINTF_FORMAT(2, 3) CK_Cross_LogMessage(CK_Log_Message_Class_T msgClass, const char *format, ...) 28 | { 29 | // TODO: For now we simply do this. 30 | va_list args; 31 | 32 | // Only print messages for the enabled log level. 33 | if (msgClass < ck_cross_logLevel) 34 | return; 35 | va_start(args, format); 36 | switch (msgClass) 37 | { 38 | case CK_LOG_MSG_NORMAL: 39 | #ifdef VL_EGA 40 | if (vl_started && isatty(STDOUT_FILENO)) break; 41 | #endif 42 | vprintf(format, args); 43 | break; 44 | case CK_LOG_MSG_WARNING: 45 | #ifdef VL_EGA 46 | if (vl_started && isatty(STDERR_FILENO)) break; 47 | #endif 48 | fprintf(stderr, "Warning: "); 49 | vfprintf(stderr, format, args); 50 | break; 51 | case CK_LOG_MSG_ERROR: 52 | #ifdef VL_EGA 53 | if (vl_started && isatty(STDERR_FILENO)) break; 54 | #endif 55 | fprintf(stderr, "Error: "); 56 | vfprintf(stderr, format, args); 57 | break; 58 | } 59 | va_end(args); 60 | } 61 | 62 | #ifdef CK_RAND_DEBUG 63 | 64 | void CK_Cross_StackTrace() 65 | { 66 | int numFunctions; 67 | char **strings; 68 | void *buffer[100]; 69 | 70 | numFunctions = backtrace(buffer, 100); 71 | strings = backtrace_symbols(buffer, numFunctions); 72 | for (int i = 0; i < numFunctions; ++i) 73 | CK_Cross_LogMessage(CK_LOG_MSG_NORMAL, "[BT] %s\n", strings[i]); 74 | } 75 | 76 | #endif 77 | 78 | void CK_Cross_puts(const char *str) 79 | { 80 | // Reason for this wrapper: Maybe a different 81 | // mechanism will be used in the future. 82 | puts(str); 83 | } 84 | 85 | int CK_Cross_toupper(int c) 86 | { 87 | return ((c >= 'a') && (c <= 'z')) ? (c - 'a' + 'A') : c; 88 | } 89 | 90 | int CK_Cross_strcasecmp(const char *s1, const char *s2) 91 | { 92 | unsigned char uc1, uc2; 93 | /* This one is easy. We don't care if a value is signed or not. */ 94 | /* All that matters here is consistency (everything is signed). */ 95 | for (; (*s1) && (CK_Cross_toupper(*s1) == CK_Cross_toupper(*s2)); s1++, s2++) 96 | ; 97 | /* But now, first we cast from int to char, and only *then* to */ 98 | /* unsigned char, so the correct difference can be calculated. */ 99 | uc1 = (unsigned char)((char)(CK_Cross_toupper(*s1))); 100 | uc2 = (unsigned char)((char)(CK_Cross_toupper(*s2))); 101 | /* We should still cast back to int, for a signed difference. */ 102 | /* Assumption: An int can store any unsigned char value. */ 103 | return ((int)uc1 - (int)uc2); 104 | } 105 | 106 | int CK_Cross_strncasecmp(const char *s1, const char *s2, size_t n) 107 | { 108 | unsigned char uc1, uc2; 109 | /* This one is easy. We don't care if a value is signed or not. */ 110 | /* All that matters here is consistency (everything is signed). */ 111 | n--; 112 | for (; n && (*s1) && (CK_Cross_toupper(*s1) == CK_Cross_toupper(*s2)); s1++, s2++, n--) 113 | ; 114 | /* But now, first we cast from int to char, and only *then* to */ 115 | /* unsigned char, so the correct difference can be calculated. */ 116 | uc1 = (unsigned char)((char)(CK_Cross_toupper(*s1))); 117 | uc2 = (unsigned char)((char)(CK_Cross_toupper(*s2))); 118 | /* We should still cast back to int, for a signed difference. */ 119 | /* Assumption: An int can store any unsigned char value. */ 120 | return ((int)uc1 - (int)uc2); 121 | } 122 | 123 | size_t CK_Cross_strscpy(char* dst, const char* src, size_t bufsiz) 124 | { 125 | for (int len = 0; len < bufsiz; ++len) 126 | { 127 | dst[len] = src[len]; 128 | if (!src[len]) 129 | return len; 130 | } 131 | Quit("strscpy: Buffer too small!"); 132 | }; 133 | -------------------------------------------------------------------------------- /src/ck_cross.h: -------------------------------------------------------------------------------- 1 | // Tools and definitions assisting with general cross-platform support 2 | 3 | #ifndef CK_CROSS_H 4 | #define CK_CROSS_H 5 | 6 | #include 7 | #include 8 | 9 | #ifdef WITH_SDL 10 | #if WITH_SDL == 3 11 | #include 12 | #else 13 | #include "SDL.h" 14 | #endif 15 | #if SDL_BYTEORDER == SDL_BIG_ENDIAN 16 | #define CK_CROSS_IS_BIGENDIAN 17 | #elif (SDL_BYTEORDER == SDL_LIL_ENDIAN) 18 | #define CK_CROSS_IS_LITTLEENDIAN 19 | #else 20 | #error "ck_cross.h - Unknown platform endianness!" 21 | #endif 22 | #else // WITH_SDL 23 | #if defined(__LITTLE_ENDIAN__) || (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) 24 | #define CK_CROSS_IS_LITTLEENDIAN 25 | #elif defined(__BIG_ENDIAN__) || (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) 26 | #define CK_CROSS_IS_BIGENDIAN 27 | #else 28 | #error "cl_cross.h - Couldn't determine platform endianness!" 29 | #endif 30 | #endif 31 | 32 | #define CK_Cross_Swap16(x) ((uint16_t)(((uint16_t)(x) << 8) | ((uint16_t)(x) >> 8))) 33 | 34 | #define CK_Cross_Swap32(x) ((uint32_t)(((uint32_t)(x) << 24) | (((uint32_t)(x) << 8) & 0x00FF0000) | (((uint32_t)(x) >> 8) & 0x0000FF00) | ((uint32_t)(x) >> 24))) 35 | 36 | #ifdef CK_CROSS_IS_LITTLEENDIAN 37 | #define CK_Cross_SwapLE16(x) (x) 38 | #define CK_Cross_SwapLE32(x) (x) 39 | #else 40 | #define CK_Cross_SwapLE16(x) CK_Cross_Swap16(x) 41 | #define CK_Cross_SwapLE32(x) CK_Cross_Swap32(x) 42 | #endif 43 | 44 | // We rely on the exact memory layout of some structures, which is not 45 | // standardised between compilers. This macro 'packs' a structure, and 46 | // should be implemented on all compilers we support. 47 | // Use it by wrapping the struct definition in the macro, e.g.: 48 | // typedef struct a { uint16_t a; uint32_t b; } a; 49 | // should become: 50 | // typedef CK_PACKED_STRUCT(a { uint16_t; uint32_t b; }) a; 51 | // This slightly weird syntax is required to make this work with some 52 | // compilers' weird pragmas/attributes for structure packing. 53 | #if defined(__GNUC__) 54 | #define CK_PACKED_STRUCT(...) struct __VA_ARGS__ __attribute__((packed)) 55 | #elif defined(_MSC_VER) 56 | #define CK_PACKED_STRUCT(...) __pragma(pack(push,1)) struct __VA_ARGS__ __pragma(pack(pop)) 57 | #elif defined(__WATCOMC__) 58 | #define CK_PACKED_STRUCT(...) _Packed struct __VA_ARGS__ 59 | #else 60 | #error Unknown compiler, no packed struct support 61 | #endif 62 | 63 | 64 | // Add printf format-string warnings on compilers which support them 65 | #if defined(__GNUC__) 66 | #define CK_PRINTF_FORMAT(fmtstridx, firstarg) __attribute__ ((format (printf, fmtstridx, firstarg))) 67 | #else 68 | #define CK_PRINTF_FORMAT(fmtstridx, firstarg) 69 | #endif 70 | 71 | typedef enum CK_Log_Message_Class_T 72 | { 73 | CK_LOG_MSG_NORMAL, 74 | CK_LOG_MSG_WARNING, 75 | CK_LOG_MSG_ERROR, 76 | CK_LOG_MSG_NONE 77 | } CK_Log_Message_Class_T; 78 | 79 | extern const char *ck_cross_logLevel_strings[]; 80 | 81 | // Log level. 82 | extern CK_Log_Message_Class_T ck_cross_logLevel; 83 | 84 | // Used for debugging 85 | void CK_PRINTF_FORMAT(2, 3) CK_Cross_LogMessage(CK_Log_Message_Class_T msgClass, const char *format, ...); 86 | 87 | // Emulates the functionality of the "puts" function in text mode 88 | void CK_Cross_puts(const char *str); 89 | 90 | // More standard C functions emulated, 91 | // taking English locale into account (and more, but NOT all) 92 | int CK_Cross_toupper(int c); 93 | // A bit less standard, but still done assuming English locale 94 | int CK_Cross_strcasecmp(const char *s1, const char *s2); 95 | int CK_Cross_strncasecmp(const char *s1, const char *s2, size_t n); 96 | 97 | // The C standard library doesn't have an implementation of min/max, which is sad. 98 | #define CK_Cross_max(x, y) ((x) < (y) ? (y) : (x)) 99 | #define CK_Cross_min(x, y) ((x) > (y) ? (y) : (x)) 100 | 101 | // Let's have our own definiton of ABS() as well 102 | #define CK_Cross_abs(x) ((x) > 0 ? (x) : (-(x))) 103 | 104 | // And a function to clamp the result. 105 | #define CK_Cross_clamp(x, a, b) CK_Cross_max(CK_Cross_min((x), (b)), (a)) 106 | 107 | // Safe strcpy variant which Quit()s if the buffer is too small. 108 | size_t CK_Cross_strscpy(char* dst, const char* src, size_t bufsiz); 109 | 110 | #endif 111 | -------------------------------------------------------------------------------- /src/ck_ep.h: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2013 David Gow 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef CK_EP_H 21 | #define CK_EP_H 22 | 23 | #include 24 | #include 25 | 26 | struct CK_object; 27 | 28 | typedef enum CK_Episode 29 | { 30 | EP_Nil, 31 | EP_CK4, 32 | EP_CK5, 33 | EP_CK6, 34 | } CK_Episode; 35 | 36 | //This structure defines an episode of Commander Keen, providing 37 | //function pointers to episode specific code and data. 38 | typedef struct CK_EpisodeDef 39 | { 40 | // Identifier 41 | CK_Episode ep; 42 | 43 | // Extension for data files 44 | char ext[4]; 45 | 46 | // Name of the EPISODE.CKx variable file. 47 | const char *episodeFile; 48 | 49 | // Scan the 'info layer' of a map. 50 | void (*scanInfoLayer)(); 51 | 52 | // Check if the episode's files are all present. 53 | bool (*isPresent)(); 54 | } CK_EpisodeDef; 55 | 56 | extern CK_EpisodeDef *ck_currentEpisode; 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/ck_game.h: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2012 David Gow 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef CK_GAME_H 21 | #define CK_GAME_H 22 | 23 | void CK_GameLoop(); 24 | void CK_LoadLevel(bool doCache, bool silent); 25 | 26 | void CK_BeginCacheBox(const char *title, int numChunks); 27 | void CK_UpdateCacheBox(); 28 | void CK_FinishCacheBox(); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/ck_phys.h: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2012 David Gow 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef CK_PHYS_H 21 | #define CK_PHYS_H 22 | 23 | #include 24 | #include 25 | 26 | #define SLOPEMASK 7 27 | 28 | typedef struct CK_objPhysData 29 | { 30 | // Unit cliping box 31 | uint16_t unitX1; 32 | uint16_t unitY1; 33 | uint16_t unitX2; 34 | uint16_t unitY2; 35 | uint16_t unitXmid; 36 | 37 | // Tile clipping box 38 | uint16_t tileX1; 39 | uint16_t tileY1; 40 | uint16_t tileX2; 41 | uint16_t tileY2; 42 | uint16_t tileXmid; 43 | } CK_objPhysData; 44 | 45 | typedef struct CK_objPhysDataDelta 46 | { 47 | int16_t unitX1; 48 | int16_t unitY1; 49 | int16_t unitX2; 50 | int16_t unitY2; 51 | int16_t unitXmid; 52 | } CK_objPhysDataDelta; 53 | 54 | struct CK_object; 55 | struct CK_action; 56 | 57 | extern bool ck_keenIgnoreVertClip; 58 | 59 | bool CK_NotStuckInWall(struct CK_object *obj); 60 | bool CK_PreviewClipRects(struct CK_object *obj, struct CK_action *act); 61 | 62 | void CK_PhysUpdateNormalObj(struct CK_object *obj); 63 | void CK_PhysFullClipToWalls(struct CK_object *obj); 64 | void CK_PhysUpdateSimpleObj(struct CK_object *obj); 65 | void CK_PhysPushX(struct CK_object *pushee, struct CK_object *pusher); 66 | void CK_PhysPushY(struct CK_object *pushee, struct CK_object *pusher); 67 | void CK_PhysPushXY(struct CK_object *pushee, struct CK_object *pusher, bool squish); 68 | void CK_SetAction(struct CK_object *obj, struct CK_action *act); 69 | void CK_SetAction2(struct CK_object *obj, struct CK_action *act); 70 | bool CK_ObjectVisible(struct CK_object *obj); 71 | void CK_PhysGravityHigh(struct CK_object *obj); 72 | void CK_PhysGravityMid(struct CK_object *obj); 73 | void CK_PhysGravityLow(struct CK_object *obj); 74 | void CK_PhysDampHorz(struct CK_object *obj); 75 | void CK_PhysAccelHorz(struct CK_object *obj, int16_t accX, int16_t velLimit); 76 | void CK_PhysAccelHorz2(struct CK_object *obj, int16_t accX, int16_t velLimit); 77 | void CK_PhysAccelVert1(struct CK_object *obj, int16_t accY, int16_t velLimit); 78 | 79 | void CK_ResetClipRects(struct CK_object *obj); 80 | #endif 81 | -------------------------------------------------------------------------------- /src/ck_play.h: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2012 David Gow 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef CK_PLAY_H 21 | #define CK_PLAY_H 22 | 23 | #include 24 | #include 25 | 26 | // Status window constants 27 | #define STATUS_W 192 // Width in pixels 28 | #define STATUS_H 152 // Height in pixels 29 | #define STATUS_X 64 // X-coord in pixels (without scroll adjustment) 30 | #define STATUS_Y 16 // Y-coord in pixels when fully down 31 | #define STATUS_BOTTOM (STATUS_H + STATUS_Y) // Bottom of status window 32 | 33 | struct CK_object; 34 | 35 | extern int ck_activeX0Tile; 36 | extern int ck_activeY0Tile; 37 | extern int ck_activeX1Tile; 38 | extern int ck_activeY1Tile; 39 | 40 | extern bool ck_scrollDisabled; 41 | 42 | extern bool ck_godMode; 43 | 44 | extern bool ck_debugActive; 45 | 46 | extern int16_t ck_invincibilityTimer; 47 | 48 | extern bool ck_scoreBoxEnabled; 49 | extern struct CK_object *ck_scoreBoxObj; 50 | 51 | extern bool ck_twoButtonFiring; 52 | 53 | extern bool ck_fixJerkyMotion; 54 | extern bool ck_svgaCompatibility; 55 | 56 | extern bool ck_gamePadEnabled; 57 | 58 | // Object Mgmt 59 | struct CK_object *CK_GetNewObj(bool nonCritical); 60 | void CK_SetupObjArray(); 61 | void CK_RemoveObj(struct CK_object *obj); 62 | 63 | // Actions/Camera 64 | void CK_RunAction(struct CK_object *obj); 65 | void CK_CentreCamera(struct CK_object *obj); 66 | void CK_MapCamera(struct CK_object *keen); 67 | void CK_NormalCamera(struct CK_object *obj); 68 | 69 | // Status Window 70 | extern void *ck_backupSurface; 71 | extern void *ck_statusSurface; 72 | void CK_ShowStatusWindow(void); 73 | 74 | // Playing 75 | void CK_PlayDemo(int demoChunk); 76 | void CK_PlayLoop(); 77 | 78 | #endif //!CK_PLAY_H 79 | -------------------------------------------------------------------------------- /src/ck_quit.c: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2012 David Gow 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include "id_heads.h" 24 | #include "ck_act.h" 25 | #include "ck_cross.h" 26 | #include "ck_def.h" 27 | 28 | void Quit(const char *msg) 29 | { 30 | // Shutdown VL early to return to text mode. 31 | VL_Shutdown(); 32 | if (!msg || !(*msg)) 33 | { 34 | // Avoid trying to re-print the order screen if caching it failed. 35 | static bool quitting = false; 36 | if (US_TerminalOk() && !quitting) 37 | { 38 | quitting = true; 39 | CA_CacheGrChunk(CK_CHUNKNUM(EXTERN_ORDERSCREEN)); 40 | // There is a 7-byte BSAVE header at the start of the 41 | // chunk, and we don't want to print the last row, as 42 | // originally it would be overwritten by DOS anyway. 43 | US_PrintB8000Text((uint8_t *)(ca_graphChunks[CK_CHUNKNUM(EXTERN_ORDERSCREEN)]) + 7, 2000 - 80); 44 | } 45 | else 46 | CK_Cross_LogMessage(CK_LOG_MSG_NORMAL, "Thanks for playing Commander Keen!\n"); 47 | CK_ShutdownID(); 48 | exit(0); 49 | } 50 | else 51 | { 52 | CK_Cross_puts(msg); 53 | CK_ShutdownID(); 54 | #ifdef WITH_SDL 55 | #if SDL_VERSION_ATLEAST(1, 3, 0) 56 | SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Omnispeak", msg, NULL); 57 | #endif 58 | #endif 59 | exit(-1); 60 | } 61 | } 62 | 63 | void QuitF(const char *msg, ...) 64 | { 65 | char msg_buf[512]; 66 | va_list args; 67 | va_start(args, msg); 68 | vsnprintf(msg_buf, sizeof(msg_buf), msg, args); 69 | va_end(args); 70 | Quit(msg_buf); 71 | } 72 | -------------------------------------------------------------------------------- /src/ck_text.h: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2012 David Gow 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef CK_TEXT_H 21 | #define CK_TEXT_H 22 | 23 | void HelpScreens(void); 24 | void help_endgame(void); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/id_ca.h: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2012 David Gow 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef ID_CA_H 21 | #define ID_CA_H 22 | 23 | #include 24 | #include 25 | 26 | #include "ck_cross.h" 27 | 28 | #include "id_mm.h" 29 | #include "id_sd.h" 30 | // -- Common -- 31 | void CA_Startup(void); 32 | void CA_Shutdown(void); 33 | 34 | // -- Audio -- 35 | 36 | #define CA_MAX_AUDIO_CHUNKS 256 37 | typedef struct ca_audinfo 38 | { 39 | uint16_t numSongs, numSounds, numSndChunks; 40 | uint16_t startPCSounds, startAdlibSounds, startDigiSounds, startMusic; 41 | } ca_audinfo; 42 | 43 | extern ca_audinfo ca_audInfoE; 44 | 45 | void CA_CacheAudioChunk(int16_t chunk); 46 | void CA_LoadAllSounds(void); 47 | 48 | // -- File IO -- 49 | 50 | size_t CA_GetFileSize(char *filename); 51 | bool CA_FarWrite(int handle, uint8_t *source, int length); 52 | bool CA_ReadFile(const char *filename, void *offset); 53 | bool CA_SafeReadFile(const char *filename, void *offset, int bufLength); 54 | bool CA_WriteFile(const char *filename, void *offset, int bufLength); 55 | bool CA_LoadFile(const char *filename, mm_ptr_t *ptr, int *memsize); 56 | int CAL_RLEWCompress(void *src, int expLength, void *dest, uint16_t rletag); 57 | void CAL_RLEWExpand(void *src, void *dest, int expLength, uint16_t rletag); 58 | 59 | // -- Graphics -- 60 | 61 | #define CA_MAX_GRAPH_CHUNKS 8192 62 | // The GFXINFOE structure containing info about the EGAGRAPH (see TED5) 63 | typedef struct ca_gfxinfo 64 | { 65 | uint16_t numTiles8, numTiles8m, numTiles16, numTiles16m, numTiles32, numTiles32m; 66 | uint16_t offTiles8, offTiles8m, offTiles16, offTiles16m, offTiles32, offTiles32m; 67 | uint16_t numBitmaps, numMasked, numSprites; 68 | uint16_t offBitmaps, offMasked, offSprites; 69 | uint16_t hdrBitmaps, hdrMasked, hdrSprites; 70 | uint16_t numBinaries, offBinaries; 71 | } ca_gfxinfo; 72 | 73 | extern uint8_t ca_levelnum, ca_levelbit; 74 | extern int16_t ca_mapOn; 75 | extern uint8_t ca_graphChunkNeeded[CA_MAX_GRAPH_CHUNKS]; 76 | extern ca_gfxinfo ca_gfxInfoE; 77 | 78 | extern mm_ptr_t ca_graphChunks[CA_MAX_GRAPH_CHUNKS]; 79 | 80 | mm_ptr_t CA_GetGrChunk(int base, int index, const char *chunkType, bool required); 81 | void CA_CacheGrChunk(int chunk); 82 | void CA_ClearMarks(void); 83 | void CA_SetGrPurge(void); 84 | void CA_MarkGrChunk(int chunk); 85 | void CA_LockGrChunk(int chunk); 86 | 87 | // For the score box. 88 | void CAL_ShiftSprite(uint8_t *srcImage, uint8_t *dstImage, int width, int height, int pxShift); 89 | 90 | void CA_CacheMarks(const char *msg); 91 | void CA_UpLevel(void); 92 | void CA_DownLevel(void); 93 | 94 | // -- Maps -- 95 | 96 | #define CA_NUMMAPPLANES 3 97 | #define CA_NUMMAPS 100 98 | 99 | typedef CK_PACKED_STRUCT(CA_MapHeader 100 | { 101 | uint32_t planeOffsets[CA_NUMMAPPLANES]; 102 | uint16_t planeLengths[CA_NUMMAPPLANES]; 103 | uint16_t width, height; 104 | char name[16]; 105 | char signature[4]; 106 | }) CA_MapHeader; 107 | 108 | extern CA_MapHeader *CA_MapHeaders[CA_NUMMAPS]; 109 | 110 | extern uint16_t *CA_mapPlanes[CA_NUMMAPPLANES]; 111 | 112 | extern uint8_t *CA_audio[CA_MAX_AUDIO_CHUNKS]; 113 | 114 | // Keen: custom cachebox hooks 115 | extern void (*ca_beginCacheBox)(const char *title, int numcache); 116 | extern void (*ca_updateCacheBox)(void); 117 | extern void (*ca_finishCacheBox)(void); 118 | 119 | void CA_CacheMap(int mapIndex); 120 | uint16_t *CA_TilePtrAtPos(int16_t x, int16_t y, int16_t plane); 121 | uint16_t CA_TileAtPos(int16_t x, int16_t y, int16_t plane); 122 | void CA_SetTileAtPos(int16_t x, int16_t y, int16_t plane, uint16_t value); 123 | uint16_t CA_GetMapHeight(); 124 | uint16_t CA_GetMapWidth(); 125 | 126 | // Omnispeak: Common lump marking code 127 | void CA_InitLumps(void); 128 | void CA_ClearLumps(void); 129 | void CA_ClearLumps(void); 130 | void CA_MarkLumpNeeded(int lump); 131 | void CA_MarkAllLumps(void); 132 | #define CA_MARKLUMP(name) CA_MarkLumpNeeded(CK_INT(name, -1)) 133 | 134 | #endif 135 | -------------------------------------------------------------------------------- /src/id_cfg.h: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2021 Omnispeak Authors 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef ID_CFG_H 21 | #define ID_CFG_H 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | typedef struct CFG_Variable 30 | { 31 | const char *name; 32 | const char *str_value; 33 | int int_value; 34 | bool is_boolean; 35 | bool saved; 36 | } CFG_Variable; 37 | 38 | void CFG_LoadConfig(const char *filename); 39 | void CFG_SaveConfig(const char *filename); 40 | 41 | bool CFG_ConfigExists(const char *name); 42 | int CFG_GetConfigInt(const char *name, int defValue); 43 | const char *CFG_GetConfigString(const char *name, const char *defValue); 44 | bool CFG_GetConfigBool(const char *name, bool defValue); 45 | int CFG_GetConfigEnum(const char *name, const char **strings, int defValue); 46 | 47 | void CFG_SetConfigInt(const char *name, int value); 48 | void CFG_SetConfigString(const char *name, const char *value); 49 | void CFG_SetConfigBool(const char *name, bool value); 50 | void CFG_SetConfigEnum(const char *name, const char **strings, int value); 51 | 52 | void CFG_Startup(); 53 | void CFG_Shutdown(); 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /src/id_fs.h: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2020 Omnispeak Authors 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef ID_FS_H 21 | #define ID_FS_H 22 | 23 | // This is the "Filesystem Manager", which handles all file I/O, and determines 24 | // which paths are used for which data files. 25 | 26 | #include "id_mm.h" 27 | 28 | #include 29 | #include 30 | 31 | typedef FILE *FS_File; 32 | 33 | bool FS_IsFileValid(FS_File file); 34 | 35 | size_t FS_GetFileSize(FS_File file); 36 | size_t FS_Read(void *ptr, size_t size, size_t nmemb, FS_File file); 37 | size_t FS_Write(const void *ptr, size_t size, size_t nmemb, FS_File file); 38 | size_t FS_SeekTo(FS_File file, size_t offset); 39 | void FS_CloseFile(FS_File file); 40 | 41 | // Omnispeak has three search paths, for three different kinds of data files: 42 | // - Keen Data (The original data files shipped with Keen) 43 | // - Omnispeak Data (The datafiles shipped with omnispeak: headers, huffman dictionaries, and scripts) 44 | // - User Data (Configs, Savegames, etc) 45 | // 46 | // These search paths may all point to the same directory, or they may 47 | // each be independent. The defaults can be configured at runtime. 48 | 49 | FS_File FS_OpenKeenFile(const char *fileName); 50 | FS_File FS_OpenOmniFile(const char *fileName); 51 | FS_File FS_OpenUserFile(const char *fileName); 52 | 53 | FS_File FS_CreateUserFile(const char *fileName); 54 | 55 | char *FS_AdjustExtension(const char *filename); 56 | 57 | bool FS_IsKeenFilePresent(const char *filename); 58 | bool FS_IsOmniFilePresent(const char *filename); 59 | bool FS_IsUserFilePresent(const char *filename); 60 | 61 | void FS_Startup(); 62 | 63 | // Used for reading buffers of a specific type, assuming Little-Endian 64 | // byte order in the file's data itself. It gets converted to native order. 65 | size_t FS_ReadInt8LE(void *ptr, size_t count, FS_File stream); 66 | size_t FS_ReadInt16LE(void *ptr, size_t count, FS_File stream); 67 | size_t FS_ReadInt32LE(void *ptr, size_t count, FS_File stream); 68 | // Used for writing buffers of a specific type, converting 69 | // native byte order to Little-Endian order within the file. 70 | size_t FS_WriteInt8LE(const void *ptr, size_t count, FS_File stream); 71 | size_t FS_WriteInt16LE(const void *ptr, size_t count, FS_File stream); 72 | size_t FS_WriteInt32LE(const void *ptr, size_t count, FS_File stream); 73 | // Similar methods for reading/writing bools from/to int16_t 74 | // (0 as false, 1 as true and any nonzero as true for reading.) 75 | // TODO: Maybe int16_t's should be used internally? (Same as vanilla Keen.) 76 | size_t FS_ReadBoolFrom16LE(void *ptr, size_t count, FS_File stream); 77 | size_t FS_WriteBoolTo16LE(const void *ptr, size_t count, FS_File stream); 78 | 79 | // fprintf() wrapper. 80 | int FS_PrintF(FS_File stream, const char *fmt, ...); 81 | 82 | // Load an entire file into memory. 83 | bool FS_LoadUserFile(const char *filename, mm_ptr_t *ptr, int *memsize); 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /src/id_heads.h: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2012 David Gow 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef ID_HEADS_H 21 | #define ID_HEADS_H 22 | 23 | // Header file to include all of the ID-engine 24 | 25 | #include "id_ca.h" 26 | #include "id_cfg.h" 27 | #include "id_in.h" 28 | #include "id_mm.h" 29 | #include "id_ti.h" 30 | #include "id_us.h" 31 | #include "id_vh.h" 32 | #include "id_vl.h" 33 | 34 | #endif //ID_HEADS_H 35 | -------------------------------------------------------------------------------- /src/id_in_dos.c: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2018 Omnispeak Authors 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include "id_in.h" 21 | #include "id_cfg.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | static bool in_dos_clearXTKeys = false; 29 | static bool in_dos_ackInt9 = true; 30 | 31 | static void INL_KeyService() 32 | { 33 | static bool isSpecial = false; 34 | bool interruptsWereEnabled = disable(); 35 | uint8_t scanCode = inportb(0x60); 36 | 37 | // Clear the key in the XT keyboard controller 38 | if (in_dos_clearXTKeys) 39 | { 40 | uint8_t temp = inportb(0x61); 41 | outportb(0x61, temp | 0x80); 42 | outportb(0x61, temp); 43 | } 44 | 45 | if (scanCode == 0xE0) 46 | { 47 | // We'll get another interrupt with the actual scancode, so 48 | // remember that it's a special scancode for later. 49 | isSpecial = true; 50 | } 51 | else if (scanCode & 0x80) 52 | { 53 | // Key is released. 54 | IN_HandleKeyUp(scanCode & 0x7F, isSpecial); 55 | isSpecial = false; 56 | } 57 | else 58 | { 59 | // Key is pressed. 60 | IN_HandleKeyDown(scanCode, isSpecial); 61 | isSpecial = false; 62 | } 63 | // TODO: Support falling through to the system interrupt handler. 64 | 65 | // Reset the interrupt. 66 | if (in_dos_ackInt9) 67 | outportb(0x20, 0x20); 68 | if (interruptsWereEnabled) 69 | enable(); 70 | } 71 | 72 | void IN_DOS_PumpEvents() 73 | { 74 | // Nothing, as this is all done in the background with interrupts (yay!) 75 | } 76 | 77 | void IN_DOS_WaitKey() 78 | { 79 | } 80 | 81 | _go32_dpmi_seginfo in_dos_oldISR, in_dos_newISR; 82 | 83 | void IN_DOS_Shutdown(void) 84 | { 85 | _go32_dpmi_set_protected_mode_interrupt_vector(9, &in_dos_oldISR); 86 | if (!CFG_GetConfigBool("in_dos_passKeysToBIOS", false)) 87 | _go32_dpmi_free_iret_wrapper(&in_dos_newISR); 88 | } 89 | 90 | void IN_DOS_Startup(bool disableJoysticks) 91 | { 92 | in_dos_ackInt9 = CFG_GetConfigBool("in_dos_ackInt9", true); 93 | in_dos_clearXTKeys = CFG_GetConfigBool("in_dos_clearXTKeys", true); 94 | in_dos_newISR.pm_offset = (intptr_t)&INL_KeyService; 95 | in_dos_newISR.pm_selector = _go32_my_cs(); 96 | 97 | _go32_dpmi_get_protected_mode_interrupt_vector(9, &in_dos_oldISR); 98 | if (CFG_GetConfigBool("in_dos_passKeysToBIOS", false)) 99 | { 100 | _go32_dpmi_chain_protected_mode_interrupt_vector(9, &in_dos_newISR); 101 | } 102 | else 103 | { 104 | _go32_dpmi_allocate_iret_wrapper(&in_dos_newISR); 105 | _go32_dpmi_set_protected_mode_interrupt_vector(9, &in_dos_newISR); 106 | } 107 | } 108 | 109 | bool IN_DOS_StartJoy(int joystick) 110 | { 111 | // No Joysticks present 112 | return false; 113 | } 114 | 115 | void IN_DOS_StopJoy(int joystick) 116 | { 117 | } 118 | 119 | bool IN_DOS_JoyPresent(int joystick) 120 | { 121 | return false; 122 | } 123 | 124 | void IN_DOS_JoyGetAbs(int joystick, int *x, int *y) 125 | { 126 | if (x) 127 | *x = 0; 128 | if (y) 129 | *y = 0; 130 | } 131 | 132 | uint16_t IN_DOS_JoyGetButtons(int joystick) 133 | { 134 | bool button0 = false; 135 | bool button1 = false; 136 | return (button0) | (button1 << 1); 137 | } 138 | 139 | const char* IN_DOS_JoyGetName(int joystick) 140 | { 141 | return NULL; 142 | } 143 | 144 | IN_Backend in_dos_backend = { 145 | .startup = IN_DOS_Startup, 146 | .shutdown = 0, 147 | .pumpEvents = IN_DOS_PumpEvents, 148 | .waitKey = IN_DOS_WaitKey, 149 | .joyStart = IN_DOS_StartJoy, 150 | .joyStop = IN_DOS_StopJoy, 151 | .joyPresent = IN_DOS_JoyPresent, 152 | .joyGetAbs = IN_DOS_JoyGetAbs, 153 | .joyGetButtons = IN_DOS_JoyGetButtons, 154 | .joyGetName = IN_DOS_JoyGetName, 155 | .joyGetButtonName = NULL, 156 | .startTextInput = NULL, 157 | .stopTextInput = NULL, 158 | .joyAxisMin = -1000, 159 | .joyAxisMax = 1000, 160 | .supportsTextEvents = false, 161 | }; 162 | 163 | IN_Backend *IN_Impl_GetBackend() 164 | { 165 | return &in_dos_backend; 166 | } 167 | -------------------------------------------------------------------------------- /src/id_in_null.c: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2018 Omnispeak Authors 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include "id_in.h" 21 | 22 | #include 23 | 24 | void IN_NULL_PumpEvents() 25 | { 26 | } 27 | 28 | void IN_NULL_WaitKey() 29 | { 30 | } 31 | 32 | void IN_NULL_Startup(bool disableJoysticks) 33 | { 34 | } 35 | 36 | bool IN_NULL_StartJoy(int joystick) 37 | { 38 | // No Joysticks present 39 | return false; 40 | } 41 | 42 | void IN_NULL_StopJoy(int joystick) 43 | { 44 | } 45 | 46 | bool IN_NULL_JoyPresent(int joystick) 47 | { 48 | return false; 49 | } 50 | 51 | void IN_NULL_JoyGetAbs(int joystick, int *x, int *y) 52 | { 53 | if (x) 54 | *x = 0; 55 | if (y) 56 | *y = 0; 57 | } 58 | 59 | uint16_t IN_NULL_JoyGetButtons(int joystick) 60 | { 61 | bool button0 = false; 62 | bool button1 = false; 63 | return (button0) | (button1 << 1); 64 | } 65 | 66 | const char* IN_NULL_JoyGetName(int joystick) 67 | { 68 | return NULL; 69 | } 70 | 71 | IN_Backend in_null_backend = { 72 | .startup = IN_NULL_Startup, 73 | .shutdown = 0, 74 | .pumpEvents = IN_NULL_PumpEvents, 75 | .waitKey = IN_NULL_WaitKey, 76 | .joyStart = IN_NULL_StartJoy, 77 | .joyStop = IN_NULL_StopJoy, 78 | .joyPresent = IN_NULL_JoyPresent, 79 | .joyGetAbs = IN_NULL_JoyGetAbs, 80 | .joyGetButtons = IN_NULL_JoyGetButtons, 81 | .joyGetName = IN_NULL_JoyGetName, 82 | .joyGetButtonName = NULL, 83 | .startTextInput = NULL, 84 | .stopTextInput = NULL, 85 | .joyAxisMin = -1000, 86 | .joyAxisMax = 1000, 87 | .supportsTextEvents = false, 88 | }; 89 | 90 | IN_Backend *IN_Impl_GetBackend() 91 | { 92 | return &in_null_backend; 93 | } 94 | -------------------------------------------------------------------------------- /src/id_mm.h: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2012 David Gow 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef ID_MM_H 21 | #define ID_MM_H 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #define BUFFERSIZE 0x1000 // Miscellaneous, always available buffer 28 | 29 | typedef void *mm_ptr_t; 30 | 31 | extern mm_ptr_t buffer; // Misc buffer 32 | 33 | void MM_Startup(void); 34 | void MM_Shutdown(void); 35 | void MM_MapEMS(void); 36 | 37 | void MM_GetPtr(mm_ptr_t *baseptr, unsigned long size); 38 | void MM_FreePtr(mm_ptr_t *baseptr); 39 | 40 | void MM_SetPurge(mm_ptr_t *baseptr, int purge); 41 | void MM_SetLock(mm_ptr_t *baseptr, bool locked); 42 | void MM_SortMem(void); 43 | 44 | void MM_ShowMemory(void); 45 | 46 | int MM_UsedMemory(); 47 | int MM_UsedBlocks(); 48 | int MM_PurgableBlocks(); 49 | long MM_UnusedMemory(void); 50 | long MM_TotalFree(void); 51 | 52 | void MM_BombOnError(bool bomb); 53 | 54 | void MML_UseSpace(void *off, intptr_t len); 55 | 56 | typedef struct ID_MM_Arena ID_MM_Arena; 57 | ID_MM_Arena *MM_ArenaCreate(size_t size); 58 | void *MM_ArenaAlloc(ID_MM_Arena *arena, size_t size); 59 | void *MM_ArenaAllocAligned(ID_MM_Arena *arena, size_t size, size_t alignment); 60 | char *MM_ArenaStrDup(ID_MM_Arena *arena, const char *str); 61 | void MM_ArenaReset(ID_MM_Arena *arena); 62 | void MM_ArenaDestroy(ID_MM_Arena *arena); 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /src/id_rf.h: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2012 David Gow 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef ID_RF_H 21 | #define ID_RF_H 22 | 23 | #include 24 | #include 25 | 26 | // Sprite Draw object 27 | typedef struct RF_SpriteDrawEntry 28 | { 29 | int chunk; 30 | int zLayer; 31 | int x, y; 32 | int sx, sy; 33 | int sw, sh; 34 | bool maskOnly; 35 | int updateCount; 36 | int shift; 37 | struct RF_SpriteDrawEntry **prevNextPtr; // Pointer to the previous entry's 'next' pointer. 38 | struct RF_SpriteDrawEntry *next; 39 | } RF_SpriteDrawEntry; 40 | 41 | // Width/Height of the screen buffers in-game. 42 | #define RF_BUFFER_WIDTH_TILES 21 43 | #define RF_BUFFER_HEIGHT_TILES 14 44 | 45 | #define RF_BUFFER_WIDTH_PIXELS (RF_BUFFER_WIDTH_TILES << 4) 46 | #define RF_BUFFER_HEIGHT_PIXELS (RF_BUFFER_HEIGHT_TILES << 4) 47 | 48 | #define RF_BUFFER_WIDTH_UNITS (RF_BUFFER_WIDTH_TILES << 8) 49 | #define RF_BUFFER_HEIGHT_UNITS (RF_BUFFER_HEIGHT_TILES << 8) 50 | 51 | // Width/Height of the visible screen in tiles. 52 | #define RF_SCREEN_WIDTH_TILES 20 53 | #define RF_SCREEN_HEIGHT_TILES 13 54 | 55 | #define PRIORITIES 4 56 | #define MASKEDTILEPRIORITY 3 // planes go: 0, 1, 2, MTILES, 3 57 | #define TILEGLOBAL 256 58 | #define PIXGLOBAL 16 59 | 60 | #define G_T_SHIFT 8 // global >> ?? = tile 61 | #define G_P_SHIFT 4 // global >> ?? = pixels 62 | #define P_T_SHIFT 4 // pixels >> ?? = tile 63 | 64 | #define RF_UnitToTile(u) ((u) >> G_T_SHIFT) 65 | #define RF_TileToUnit(t) ((t) << G_T_SHIFT) 66 | #define RF_UnitToPixel(u) ((u) >> G_P_SHIFT) 67 | #define RF_PixelToUnit(p) ((p) << G_P_SHIFT) 68 | #define RF_PixelToTile(p) ((p) >> P_T_SHIFT) 69 | #define RF_TileToPixel(t) ((t) << P_T_SHIFT) 70 | 71 | extern int rf_scrollXUnit, rf_scrollYUnit; 72 | extern int rf_scrollXMinUnit; 73 | extern int rf_scrollYMinUnit; 74 | extern int rf_scrollXMaxUnit; 75 | extern int rf_scrollYMaxUnit; 76 | 77 | extern void (*rf_drawFunc)(void); 78 | 79 | void RFL_MarkBlockDirty(int x, int y, int val, int page); 80 | uint8_t RFL_IsBlockDirty(int x, int y, int page); 81 | 82 | void RF_SetScrollBlock(int tileX, int tileY, bool vertical); 83 | void RF_MarkTileGraphics(); 84 | void RF_SetDrawFunc(void (*func)(void)); 85 | void RF_Startup(); 86 | void RF_Shutdown(); 87 | void RF_NewMap(void); 88 | void RF_RenderTile16(int x, int y, int tile); 89 | void RF_RenderTile16m(int x, int y, int tile); 90 | void RF_ForceRefresh(void); 91 | void RF_ReplaceTileBlock(int srcx, int srcy, int destx, int desty, int width, int height); 92 | void RF_ReplaceTiles(uint16_t *tilePtr, int plane, int dstX, int dstY, int width, int height); 93 | void RF_Reposition(int scrollXunit, int scrollYunit); 94 | void RF_SmoothScroll(int scrollXdelta, int scrollYdelta); 95 | void RF_RemoveSpriteDraw(RF_SpriteDrawEntry **drawEntry); 96 | void RF_AddSpriteDraw(RF_SpriteDrawEntry **drawEntry, int unitX, int unitY, int chunk, bool allWhite, int zLayer); 97 | void RF_RemoveSpriteDrawUsing16BitOffset(int16_t *drawEntryOffset); 98 | void RF_AddSpriteDrawUsing16BitOffset(int16_t *drawEntryOffset, int unitX, int unitY, int chunk, bool allWhite, int zLayer); 99 | void RF_Refresh(); 100 | /*** Used for dumper (and, partially, for saved games compatibility) ***/ 101 | RF_SpriteDrawEntry *RF_ConvertSpriteArray16BitOffsetToPtr(uint16_t drawEntryoffset); 102 | uint16_t RF_ConvertSpriteArrayPtrTo16BitOffset(RF_SpriteDrawEntry *drawEntry); 103 | 104 | #endif //ID_RF_H 105 | -------------------------------------------------------------------------------- /src/id_sd.h: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2020 Omnispeak Authors 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef ID_SD_H 21 | #define ID_SD_H 22 | 23 | #include 24 | #include 25 | 26 | typedef int16_t soundnames; 27 | typedef int16_t musicnames; 28 | 29 | typedef struct SD_MusicTrack SD_MusicTrack; 30 | 31 | typedef enum 32 | { 33 | sdm_Off, 34 | sdm_PC, 35 | sdm_AdLib, 36 | } SD_SoundMode; 37 | 38 | typedef enum 39 | { 40 | smm_Off, 41 | smm_AdLib 42 | } ID_MusicMode; 43 | 44 | bool SD_SetSoundMode(SD_SoundMode mode); 45 | bool SD_SetMusicMode(ID_MusicMode mode); 46 | SD_SoundMode SD_GetSoundMode(); 47 | ID_MusicMode SD_GetMusicMode(); 48 | void SD_SetQuietSfx(bool value); 49 | bool SD_GetQuietSfx(); 50 | bool SD_IsAdlibPresent(); 51 | void SD_Startup(void); 52 | void SD_Default(bool gotit, SD_SoundMode sd, ID_MusicMode sm); 53 | void SD_Shutdown(void); 54 | void SD_PlaySound(soundnames sound); 55 | uint16_t SD_SoundPlaying(void); 56 | void SD_StopSound(void); 57 | void SD_WaitSoundDone(void); 58 | void SD_MusicOn(void); 59 | void SD_MusicOff(void); 60 | void SD_StartMusic(SD_MusicTrack *music); 61 | void SD_FadeOutMusic(void); 62 | bool SD_MusicPlaying(void); // Actually return false for all time 63 | 64 | /* Adlib Register Definitions */ 65 | // Register addresses 66 | // Operator stuff 67 | #define SD_ADLIB_REG_CHAR 0x20 68 | #define SD_ADLIB_REG_VOLUME 0x40 69 | #define SD_ADLIB_REG_ATTACK 0x60 70 | #define SD_ADLIB_REG_SUSPEND 0x80 71 | #define SD_ADLIB_REG_WAVE 0xe0 72 | // Channel stuff 73 | #define SD_ADLIB_REG_NOTE_LO 0xa0 74 | #define SD_ADLIB_REG_NOTE_HI 0xb0 75 | #define SD_ADLIB_REG_CONNECTION 0xc0 76 | // Global stuff 77 | #define SD_ADLIB_REG_EFFECTS 0xbd 78 | 79 | #define SD_ADLIB_NUM_CHANNELS 10 80 | 81 | // Soundcard Detection (bitmasks) 82 | #define SD_CARD_PC_SPEAKER 1 // Has PC-speaker support 83 | #define SD_CARD_OPL2 2 // Has Adlib support 84 | #define SD_CARD_OPL3 4 // Has OPL3 (SB16/Adlib Gold) support 85 | #define SD_CARD_BLASTER 8 // Has Digitised Sound (Sound Blaster) support. 86 | 87 | 88 | typedef struct SD_Backend 89 | { 90 | void (*startup)(); 91 | void (*shutdown)(); 92 | void (*lock)(); 93 | void (*unlock)(); 94 | void (*alOut)(uint8_t reg, uint8_t val); 95 | void (*pcSpkOn)(bool on, int freq); 96 | void (*setTimer0)(int16_t int_8_divisor); 97 | void (*waitTick)(); 98 | unsigned int (*detect)(); 99 | void (*setOPL3)(bool on); 100 | } SD_Backend; 101 | 102 | SD_Backend *SD_Impl_GetBackend(); 103 | /* Timing related functions */ 104 | 105 | uint32_t SD_GetTimeCount(void); 106 | void SD_SetTimeCount(uint32_t newval); 107 | int32_t SD_GetLastTimeCount(void); 108 | void SD_SetLastTimeCount(int32_t newval); 109 | uint16_t SD_GetSpriteSync(void); 110 | void SD_SetSpriteSync(uint16_t newval); 111 | void SD_WaitTick(void); 112 | 113 | #endif 114 | -------------------------------------------------------------------------------- /src/id_sd_dos.c: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2018 Omnispeak Authors 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "id_sd.h" 29 | #include "id_cfg.h" 30 | #include "ck_cross.h" 31 | 32 | #define PC_PIT_RATE 1193182 33 | #define SD_SFX_PART_RATE 140 34 | /* In the original exe, upon setting a rate of 140Hz or 560Hz for some 35 | * interrupt handler, the value 1192030 divided by the desired rate is 36 | * calculated, to be programmed for timer 0 as a consequence. 37 | * For THIS value, it is rather 1193182 that should be divided by it, in order 38 | * to obtain a better approximation of the actual rate. 39 | */ 40 | #define SD_SOUND_PART_RATE_BASE 1192030 41 | 42 | #define SD_ADLIB_REG_PORT 0x388 43 | #define SD_ADLIB_DATA_PORT 0x389 44 | 45 | static int16_t ScaledTimerDivisor = 1; 46 | 47 | void SD_DOS_SetTimer0(int16_t int_8_divisor) 48 | { 49 | //Configure the PIT frequency. 50 | outportb(0x43, 0x36); 51 | outportb(0x40, int_8_divisor & 0xFF); 52 | outportb(0x40, int_8_divisor >> 8); 53 | ScaledTimerDivisor = ((int32_t)SD_SOUND_PART_RATE_BASE / (int32_t)int_8_divisor) & 0xFFFF; 54 | } 55 | 56 | void SD_DOS_alOut(uint8_t reg, uint8_t val) 57 | { 58 | int wereIntsEnabled = disable(); 59 | 60 | outportb(SD_ADLIB_REG_PORT, reg); 61 | 62 | // Delay 6 'in's to give the OPL2 some processing time. 63 | for (int timer = 6; timer; --timer) 64 | (void)inportb(SD_ADLIB_REG_PORT); 65 | 66 | outportb(SD_ADLIB_DATA_PORT, val); 67 | 68 | // And wait a lot more after sending the data. 69 | for (int timer = 35; timer; --timer) 70 | (void)inportb(SD_ADLIB_REG_PORT); 71 | 72 | if (wereIntsEnabled) 73 | enable(); 74 | } 75 | 76 | /* FIXME: The SDL prefix may conflict with SDL functions in the future(???) 77 | * Best (but hackish) solution, if it happens: Add our own custom prefix. 78 | */ 79 | 80 | void SDL_t0Service(void); 81 | 82 | static bool sd_dos_ackInt8 = true; 83 | void SD_DOS_t0InterruptProxy() 84 | { 85 | SDL_t0Service(); 86 | if (sd_dos_ackInt8) 87 | outportb(0x20, 0x20); 88 | } 89 | 90 | void SD_DOS_PCSpkOn(bool on, int freq) 91 | { 92 | if (on) 93 | { 94 | outportb(0x43, 0xb6); 95 | 96 | outportb(0x42, freq & 0xFF); 97 | outportb(0x42, freq >> 8); 98 | 99 | uint8_t oldPcState = inportb(0x61); 100 | outportb(0x61, oldPcState | 3); 101 | } 102 | else 103 | { 104 | uint8_t oldPcState = inportb(0x61); 105 | outportb(0x61, oldPcState & 0xFC); 106 | } 107 | } 108 | 109 | _go32_dpmi_seginfo sd_dos_oldISR, sd_dos_newISR; 110 | 111 | void SD_DOS_Startup(void) 112 | { 113 | sd_dos_newISR.pm_offset = (intptr_t)&SD_DOS_t0InterruptProxy; 114 | sd_dos_newISR.pm_selector = _go32_my_cs(); 115 | sd_dos_ackInt8 = CFG_GetConfigBool("sd_dos_ackInt8", true); 116 | 117 | _go32_dpmi_get_protected_mode_interrupt_vector(8, &sd_dos_oldISR); 118 | if (CFG_GetConfigBool("sd_dos_chainTimer", true)) 119 | { 120 | _go32_dpmi_chain_protected_mode_interrupt_vector(8, &sd_dos_newISR); 121 | } 122 | else 123 | { 124 | _go32_dpmi_allocate_iret_wrapper(&sd_dos_newISR); 125 | _go32_dpmi_set_protected_mode_interrupt_vector(8, &sd_dos_newISR); 126 | } 127 | } 128 | 129 | void SD_DOS_Shutdown(void) 130 | { 131 | SD_DOS_PCSpkOn(false, 0); 132 | _go32_dpmi_set_protected_mode_interrupt_vector(8, &sd_dos_oldISR); 133 | if (!CFG_GetConfigBool("sd_dos_chainTimer", true)) 134 | _go32_dpmi_free_iret_wrapper(&sd_dos_newISR); 135 | } 136 | 137 | bool SD_DOS_WereInterruptsEnabled = false; 138 | 139 | void SD_DOS_Lock() 140 | { 141 | SD_DOS_WereInterruptsEnabled = disable(); 142 | } 143 | 144 | void SD_DOS_Unlock() 145 | { 146 | if (SD_DOS_WereInterruptsEnabled) 147 | enable(); 148 | } 149 | 150 | unsigned int SD_DOS_Detect() 151 | { 152 | unsigned int card = SD_CARD_PC_SPEAKER; 153 | // TODO: Actually detect the Adlib 154 | card |= SD_CARD_OPL2; 155 | 156 | uint8_t reg0 = inportb(SD_ADLIB_REG_PORT); 157 | if ((reg0 & 0x06) == 0) 158 | card |= SD_CARD_OPL3; 159 | return card; 160 | } 161 | 162 | void SD_DOS_SetOPL3(bool on) 163 | { 164 | int wereIntsEnabled = disable(); 165 | 166 | outportb(SD_ADLIB_REG_PORT + 2, 0x05); 167 | 168 | // Delay 6 'in's to give the OPL2 some processing time. 169 | for (int timer = 6; timer; --timer) 170 | (void)inportb(SD_ADLIB_REG_PORT); 171 | 172 | outportb(SD_ADLIB_DATA_PORT + 2, on ? 0x01 : 0x00); 173 | 174 | // And wait a lot more after sending the data. 175 | for (int timer = 35; timer; --timer) 176 | (void)inportb(SD_ADLIB_REG_PORT); 177 | 178 | if (wereIntsEnabled) 179 | enable(); 180 | } 181 | 182 | SD_Backend sd_dos_backend = { 183 | .startup = SD_DOS_Startup, 184 | .shutdown = SD_DOS_Shutdown, 185 | .lock = SD_DOS_Lock, 186 | .unlock = SD_DOS_Unlock, 187 | .alOut = SD_DOS_alOut, 188 | .pcSpkOn = SD_DOS_PCSpkOn, 189 | .setTimer0 = SD_DOS_SetTimer0, 190 | .detect = SD_DOS_Detect, 191 | .setOPL3 = SD_DOS_SetOPL3 192 | }; 193 | 194 | SD_Backend *SD_Impl_GetBackend() 195 | { 196 | return &sd_dos_backend; 197 | } 198 | -------------------------------------------------------------------------------- /src/id_sd_liboplhw.c: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2021 Omnispeak Authors 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | #include "id_cfg.h" 31 | #include "id_sd.h" 32 | #include "id_us.h" 33 | #include "ck_cross.h" 34 | 35 | #define PC_PIT_RATE 1193182 36 | #define SD_SFX_PART_RATE 140 37 | /* In the original exe, upon setting a rate of 140Hz or 560Hz for some 38 | * interrupt handler, the value 1192030 divided by the desired rate is 39 | * calculated, to be programmed for timer 0 as a consequence. 40 | * For THIS value, it is rather 1193182 that should be divided by it, in order 41 | * to obtain a better approximation of the actual rate. 42 | */ 43 | #define SD_SOUND_PART_RATE_BASE 1192030 44 | 45 | static oplhw_device *sd_oplhw_device; 46 | 47 | static volatile int timerDivisor = 1; 48 | 49 | static SDL_mutex *soundSystemMutex = 0; 50 | static SDL_Thread *t0Thread = 0; 51 | 52 | static SDL_cond *SD_OPLHW_TimerConditionVar; 53 | static bool SD_OPLHW_WaitTicksSpin = false; 54 | 55 | void SD_OPLHW_SetTimer0(int16_t int_8_divisor) 56 | { 57 | //Configure the PIT frequency. 58 | timerDivisor = int_8_divisor; 59 | } 60 | 61 | void SDL_t0Service(void); 62 | 63 | static uint64_t SD_LastPITTickTime; 64 | 65 | static volatile bool soundSystemUp; 66 | 67 | int SD_OPLHW_t0InterruptThread(void *param) 68 | { 69 | while (soundSystemUp) 70 | { 71 | uint64_t currPitTicks = (uint64_t)(SDL_GetPerformanceCounter()) * PC_PIT_RATE / SDL_GetPerformanceFrequency(); 72 | uint32_t ticks = (currPitTicks - SD_LastPITTickTime) / timerDivisor; 73 | 74 | if (ticks) 75 | { 76 | if (SDL_LockMutex(soundSystemMutex)) 77 | continue; 78 | SDL_t0Service(); 79 | SDL_UnlockMutex(soundSystemMutex); 80 | if (!SD_OPLHW_WaitTicksSpin) 81 | SDL_CondBroadcast(SD_OPLHW_TimerConditionVar); 82 | SD_LastPITTickTime = currPitTicks; 83 | } 84 | } 85 | return 0; 86 | } 87 | 88 | void SD_OPLHW_alOut(uint8_t reg, uint8_t val) 89 | { 90 | if (sd_oplhw_device) 91 | { 92 | oplhw_Write(sd_oplhw_device, reg, val); 93 | } 94 | } 95 | 96 | void SD_OPLHW_PCSpkOn(bool on, int freq) 97 | { 98 | // Setup operator 99 | SD_OPLHW_alOut(SD_ADLIB_REG_CHAR, 0); 100 | SD_OPLHW_alOut(SD_ADLIB_REG_VOLUME, 0); 101 | SD_OPLHW_alOut(SD_ADLIB_REG_ATTACK, 0xFF); 102 | SD_OPLHW_alOut(SD_ADLIB_REG_SUSPEND, 0x0); 103 | SD_OPLHW_alOut(SD_ADLIB_REG_WAVE, 0); 104 | SD_OPLHW_alOut(SD_ADLIB_REG_CHAR + 3, 0); 105 | SD_OPLHW_alOut(SD_ADLIB_REG_VOLUME + 3, 0); 106 | SD_OPLHW_alOut(SD_ADLIB_REG_ATTACK + 3, 0xFF); 107 | SD_OPLHW_alOut(SD_ADLIB_REG_SUSPEND + 3, 0x0); 108 | SD_OPLHW_alOut(SD_ADLIB_REG_WAVE + 3, 0); 109 | 110 | // Setup channel 111 | SD_OPLHW_alOut(SD_ADLIB_REG_CONNECTION, 0xF0); 112 | 113 | uint64_t fNum = freq ? (((PC_PIT_RATE / (freq)) << 16) / 49716) : 0; 114 | 115 | uint8_t hibyte = ((fNum >> 8) & 3) | 12; 116 | if (on) 117 | hibyte |= 0x20; 118 | else 119 | hibyte = 0; 120 | SD_OPLHW_alOut(SD_ADLIB_REG_NOTE_LO, fNum & 0xFF); 121 | SD_OPLHW_alOut(SD_ADLIB_REG_NOTE_HI, hibyte); 122 | } 123 | 124 | void SD_OPLHW_Startup(void) 125 | { 126 | const char *deviceName = CFG_GetConfigString("sd_liboplhw_device", ""); 127 | for (int i = 0; i < us_argc; ++i) 128 | { 129 | if (!CK_Cross_strcasecmp(us_argv[i], "/OPLHW")) 130 | deviceName = us_argv[i + 1]; 131 | } 132 | 133 | // Setup a condition variable to signal threads waiting for timer updates. 134 | SD_OPLHW_WaitTicksSpin = CFG_GetConfigBool("sd_alsa_waitTicksSpin", false); 135 | if (!SD_OPLHW_WaitTicksSpin) 136 | SD_OPLHW_TimerConditionVar = SDL_CreateCond(); 137 | 138 | sd_oplhw_device = oplhw_OpenDevice(deviceName); 139 | if (!sd_oplhw_device) 140 | Quit("Couldn't open liboplhw device!"); 141 | 142 | soundSystemMutex = SDL_CreateMutex(); 143 | soundSystemUp = true; 144 | 145 | uint64_t currPitTicks = (uint64_t)(SDL_GetPerformanceCounter()) * PC_PIT_RATE / SDL_GetPerformanceFrequency(); 146 | SD_LastPITTickTime = currPitTicks; 147 | t0Thread = SDL_CreateThread(SD_OPLHW_t0InterruptThread, "ID_SD: t0 interrupt thread.", NULL); 148 | } 149 | 150 | void SD_OPLHW_Shutdown(void) 151 | { 152 | oplhw_CloseDevice(sd_oplhw_device); 153 | } 154 | 155 | bool SD_OPLHW_mutexLocked = false; 156 | 157 | void SD_OPLHW_Lock() 158 | { 159 | if (SD_OPLHW_mutexLocked) 160 | Quit("Attempted sound system re-entry (locking an already locked mutex)"); 161 | if (SDL_LockMutex(soundSystemMutex)) 162 | Quit("Couldn't lock sound system mutex."); 163 | SD_OPLHW_mutexLocked = true; 164 | } 165 | 166 | void SD_OPLHW_Unlock() 167 | { 168 | if (!SD_OPLHW_mutexLocked) 169 | Quit("Tried to unlock the already unlocked sound system mutex."); 170 | SDL_UnlockMutex(soundSystemMutex); 171 | SD_OPLHW_mutexLocked = false; 172 | } 173 | 174 | void SD_OPLHW_WaitTick() 175 | { 176 | SDL_mutex *mtx = SDL_CreateMutex(); 177 | SDL_LockMutex(mtx); 178 | // Timeout of 2ms, as the PIT rate is ~1.1ms.. 179 | SDL_CondWaitTimeout(SD_OPLHW_TimerConditionVar, mtx, 2); 180 | SDL_UnlockMutex(mtx); 181 | } 182 | 183 | unsigned int SD_OPLHW_Detect() 184 | { 185 | unsigned int cards = SD_CARD_OPL2; 186 | if (oplhw_IsOPL3(sd_oplhw_device)) 187 | cards |= SD_CARD_OPL3; 188 | return cards; 189 | } 190 | 191 | void SD_OPLHW_SetOPL3(bool on) 192 | { 193 | oplhw_Write(sd_oplhw_device, 0x105, on ? 1 : 0); 194 | // Reset any 4-OP registers 195 | oplhw_Write(sd_oplhw_device, 0x104, 0); 196 | } 197 | 198 | SD_Backend sd_liboplhw_backend = { 199 | .startup = SD_OPLHW_Startup, 200 | .shutdown = SD_OPLHW_Shutdown, 201 | .lock = SD_OPLHW_Lock, 202 | .unlock = SD_OPLHW_Unlock, 203 | .alOut = SD_OPLHW_alOut, 204 | .pcSpkOn = SD_OPLHW_PCSpkOn, 205 | .setTimer0 = SD_OPLHW_SetTimer0, 206 | .waitTick = SD_OPLHW_WaitTick, 207 | .detect = SD_OPLHW_Detect, 208 | .setOPL3 = SD_OPLHW_SetOPL3 209 | }; 210 | 211 | SD_Backend *SD_Impl_GetBackend_OPLHW() 212 | { 213 | return &sd_liboplhw_backend; 214 | } 215 | -------------------------------------------------------------------------------- /src/id_sd_null.c: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2018 Omnispeak Authors 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "id_sd.h" 26 | #include "ck_cross.h" 27 | 28 | #define PC_PIT_RATE 1193182 29 | #define SD_SFX_PART_RATE 140 30 | /* In the original exe, upon setting a rate of 140Hz or 560Hz for some 31 | * interrupt handler, the value 1192030 divided by the desired rate is 32 | * calculated, to be programmed for timer 0 as a consequence. 33 | * For THIS value, it is rather 1193182 that should be divided by it, in order 34 | * to obtain a better approximation of the actual rate. 35 | */ 36 | #define SD_SOUND_PART_RATE_BASE 1192030 37 | 38 | // Sort of replacements for x86 behaviors and assembly code 39 | 40 | static bool SD_NULL_AudioSubsystem_Up; 41 | 42 | /* NEVER call this from the SDL callback!!! (Or you want a deadlock?) */ 43 | void SD_NULL_SetTimer0(int16_t int_8_divisor) 44 | { 45 | } 46 | 47 | /* FIXME: The SDL prefix may conflict with SDL functions in the future(???) 48 | * Best (but hackish) solution, if it happens: Add our own custom prefix. 49 | */ 50 | 51 | void SDL_t0Service(void); 52 | 53 | void SD_NULL_alOut(uint8_t reg, uint8_t val) 54 | { 55 | } 56 | 57 | void SD_NULL_PCSpkOn(bool on, int freq) 58 | { 59 | } 60 | 61 | void SD_NULL_Startup(void) 62 | { 63 | 64 | SD_NULL_AudioSubsystem_Up = true; 65 | } 66 | 67 | void SD_NULL_Shutdown(void) 68 | { 69 | if (SD_NULL_AudioSubsystem_Up) 70 | { 71 | SD_NULL_AudioSubsystem_Up = false; 72 | } 73 | } 74 | 75 | bool SD_NULL_IsLocked = false; 76 | 77 | void SD_NULL_Lock() 78 | { 79 | if (SD_NULL_IsLocked) 80 | CK_Cross_LogMessage(CK_LOG_MSG_ERROR, "Tried to lock the audio system when it was already locked!\n"); 81 | SD_NULL_IsLocked = true; 82 | } 83 | 84 | void SD_NULL_Unlock() 85 | { 86 | if (!SD_NULL_IsLocked) 87 | CK_Cross_LogMessage(CK_LOG_MSG_ERROR, "Tried to unlock the audio system when it was already unlocked!\n"); 88 | SD_NULL_IsLocked = false; 89 | } 90 | 91 | void SD_NULL_WaitTick() 92 | { 93 | SDL_t0Service(); 94 | } 95 | 96 | unsigned int SD_NULL_Detect() 97 | { 98 | return 0; 99 | } 100 | 101 | void SD_NULL_SetOPL3(bool on) 102 | { 103 | } 104 | 105 | SD_Backend sd_null_backend = { 106 | .startup = SD_NULL_Startup, 107 | .shutdown = SD_NULL_Shutdown, 108 | .lock = SD_NULL_Lock, 109 | .unlock = SD_NULL_Unlock, 110 | .alOut = SD_NULL_alOut, 111 | .pcSpkOn = SD_NULL_PCSpkOn, 112 | .setTimer0 = SD_NULL_SetTimer0, 113 | .waitTick = SD_NULL_WaitTick, 114 | .detect = SD_NULL_Detect, 115 | .setOPL3 = SD_NULL_SetOPL3 116 | }; 117 | 118 | SD_Backend *SD_Impl_GetBackend() 119 | { 120 | return &sd_null_backend; 121 | } 122 | -------------------------------------------------------------------------------- /src/id_sd_opl2.c: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2019 Omnispeak Authors 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | // See https://github.com/DhrBaksteen/ArduinoOPL2 26 | // But that's C++, and we only use C, so reimplement it. 27 | #include 28 | #include 29 | 30 | #define OPL2_PIN_LATCH 1 // Pin 12 31 | #define OPL2_PIN_ADDR 4 // Pin 16 32 | #define OPL2_PIN_RESET 5 // Pin 18 33 | 34 | #define OPL2_SPI_SPEED 8000000 35 | #define OPL2_SPI_CHANNEL 0 36 | 37 | #include "id_sd.h" 38 | #include "id_us.h" 39 | #include "ck_cross.h" 40 | 41 | #define PC_PIT_RATE 1193182 42 | #define SD_SFX_PART_RATE 140 43 | /* In the original exe, upon setting a rate of 140Hz or 560Hz for some 44 | * interrupt handler, the value 1192030 divided by the desired rate is 45 | * calculated, to be programmed for timer 0 as a consequence. 46 | * For THIS value, it is rather 1193182 that should be divided by it, in order 47 | * to obtain a better approximation of the actual rate. 48 | */ 49 | #define SD_SOUND_PART_RATE_BASE 1192030 50 | 51 | #define SD_ADLIB_REG_PORT 0x388 52 | #define SD_ADLIB_DATA_PORT 0x389 53 | 54 | static volatile int timerDivisor = 1; 55 | 56 | static SDL_mutex *soundSystemMutex = 0; 57 | static SDL_Thread *t0Thread = 0; 58 | 59 | void SD_OPL2_SetTimer0(int16_t int_8_divisor) 60 | { 61 | //Configure the PIT frequency. 62 | timerDivisor = int_8_divisor; 63 | } 64 | 65 | void SD_OPL2_alOut(uint8_t reg, uint8_t val) 66 | { 67 | digitalWrite(OPL2_PIN_ADDR, LOW); 68 | 69 | wiringPiSPIDataRW(OPL2_SPI_CHANNEL, ®, 1); 70 | 71 | digitalWrite(OPL2_PIN_LATCH, LOW); 72 | delayMicroseconds(1); 73 | digitalWrite(OPL2_PIN_LATCH, HIGH); 74 | delayMicroseconds(4); 75 | 76 | digitalWrite(OPL2_PIN_ADDR, HIGH); 77 | wiringPiSPIDataRW(OPL2_SPI_CHANNEL, &val, 1); 78 | digitalWrite(OPL2_PIN_LATCH, LOW); 79 | delayMicroseconds(1); 80 | digitalWrite(OPL2_PIN_LATCH, HIGH); 81 | delayMicroseconds(23); 82 | } 83 | 84 | /* FIXME: The SDL prefix may conflict with SDL functions in the future(???) 85 | * Best (but hackish) solution, if it happens: Add our own custom prefix. 86 | */ 87 | 88 | void SDL_t0Service(void); 89 | 90 | static uint64_t SD_LastPITTickTime; 91 | 92 | static volatile bool soundSystemUp; 93 | 94 | int SD_OPL2_t0InterruptThread(void *param) 95 | { 96 | while (soundSystemUp) 97 | { 98 | uint64_t currPitTicks = (uint64_t)(SDL_GetPerformanceCounter()) * PC_PIT_RATE / SDL_GetPerformanceFrequency(); 99 | uint32_t ticks = (currPitTicks - SD_LastPITTickTime) / timerDivisor; 100 | 101 | if (ticks) 102 | { 103 | if (SDL_LockMutex(soundSystemMutex)) 104 | continue; 105 | SDL_t0Service(); 106 | SDL_UnlockMutex(soundSystemMutex); 107 | SD_LastPITTickTime = currPitTicks; 108 | } 109 | } 110 | return 0; 111 | } 112 | 113 | void SD_OPL2_PCSpkOn(bool on, int freq) 114 | { 115 | // No-op. 116 | } 117 | 118 | void SD_OPL2_Startup(void) 119 | { 120 | wiringPiSetup(); 121 | wiringPiSPISetup(OPL2_SPI_CHANNEL, OPL2_SPI_SPEED); 122 | 123 | pinMode(OPL2_PIN_LATCH, OUTPUT); 124 | pinMode(OPL2_PIN_ADDR, OUTPUT); 125 | pinMode(OPL2_PIN_RESET, OUTPUT); 126 | 127 | digitalWrite(OPL2_PIN_LATCH, HIGH); 128 | digitalWrite(OPL2_PIN_ADDR, LOW); 129 | digitalWrite(OPL2_PIN_RESET, HIGH); 130 | 131 | soundSystemMutex = SDL_CreateMutex(); 132 | soundSystemUp = true; 133 | 134 | uint64_t currPitTicks = (uint64_t)(SDL_GetPerformanceCounter()) * PC_PIT_RATE / SDL_GetPerformanceFrequency(); 135 | SD_LastPITTickTime = currPitTicks; 136 | t0Thread = SDL_CreateThread(SD_OPL2_t0InterruptThread, "ID_SD: t0 interrupt thread.", NULL); 137 | } 138 | 139 | void SD_OPL2_Shutdown(void) 140 | { 141 | soundSystemUp = false; 142 | SDL_WaitThread(t0Thread, NULL); 143 | SDL_DestroyMutex(soundSystemMutex); 144 | } 145 | 146 | bool SD_OPL2_mutexLocked = false; 147 | 148 | void SD_OPL2_Lock() 149 | { 150 | if (SD_OPL2_mutexLocked) 151 | Quit("Attempted sound system re-entry (locking an already locked mutex)"); 152 | if (SDL_LockMutex(soundSystemMutex)) 153 | Quit("Couldn't lock sound system mutex."); 154 | SD_OPL2_mutexLocked = true; 155 | } 156 | 157 | void SD_OPL2_Unlock() 158 | { 159 | if (!SD_OPL2_mutexLocked) 160 | Quit("Tried to unlock the already unlocked sound system mutex."); 161 | SDL_UnlockMutex(soundSystemMutex); 162 | SD_OPL2_mutexLocked = false; 163 | } 164 | 165 | unsigned int SD_OPL2_Detect() 166 | { 167 | return SD_CARD_OPL2; 168 | } 169 | 170 | void SD_OPL2_SetOPL3(bool on) 171 | { 172 | // This card is OPL2 only 173 | } 174 | 175 | SD_Backend sd_opl2_backend = { 176 | .startup = SD_OPL2_Startup, 177 | .shutdown = SD_OPL2_Shutdown, 178 | .lock = SD_OPL2_Lock, 179 | .unlock = SD_OPL2_Unlock, 180 | .alOut = SD_OPL2_alOut, 181 | .pcSpkOn = SD_OPL2_PCSpkOn, 182 | .setTimer0 = SD_OPL2_SetTimer0, 183 | .detect = SD_OPL2_Detect, 184 | .setOPL3 = SD_OPL2_SetOPL3 185 | }; 186 | 187 | SD_Backend *SD_Impl_GetBackend() 188 | { 189 | return &sd_opl2_backend; 190 | } 191 | -------------------------------------------------------------------------------- /src/id_str.h: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2012 David Gow 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef ID_STR_H 21 | #define ID_STR_H 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include "id_mm.h" 28 | /* String manager, allows objects to be indexed by strings */ 29 | 30 | typedef struct STR_Entry 31 | { 32 | const char *str; 33 | void *ptr; 34 | } STR_Entry; 35 | 36 | typedef struct STR_Table 37 | { 38 | size_t size; 39 | #ifdef CK_DEBUG 40 | size_t numElements; 41 | #endif 42 | STR_Entry arr[]; 43 | } STR_Table; 44 | 45 | void STR_AllocTable(STR_Table **tabl, size_t size); 46 | bool STR_DoesEntryExist(STR_Table *tabl, const char *str); 47 | void *STR_LookupEntryWithDefault(STR_Table *tabl, const char *str, void *def); 48 | void *STR_LookupEntry(STR_Table *tabl, const char *str); 49 | bool STR_AddEntry(STR_Table *tabl, const char *str, void *value); 50 | 51 | void *STR_GetNextEntry(STR_Table *tabl, size_t *index); 52 | 53 | // Gets the index where "str" either exists, or should be inserted. 54 | size_t STR_GetEntryIndex(STR_Table *tabl, const char *str); 55 | 56 | #define ID_STR_MAX_TOKEN_LENGTH 1024 57 | #define ID_STR_INVALID_INDEX ((size_t)-1) 58 | 59 | typedef enum STR_TokenType 60 | { 61 | STR_TOK_EOF, 62 | STR_TOK_Ident, 63 | STR_TOK_Number, 64 | STR_TOK_String 65 | } STR_TokenType; 66 | 67 | typedef struct STR_Token 68 | { 69 | STR_TokenType tokenType; 70 | const char *valuePtr; 71 | int valueLength; 72 | 73 | // These are the first byte index in the input of the token, and the 74 | // last byte index, respectively. These are used for saving modified 75 | // files out. 76 | int firstIndex; 77 | int lastIndex; 78 | } STR_Token; 79 | 80 | typedef struct STR_ParserState 81 | { 82 | char *data; 83 | int dataindex; 84 | int datasize; 85 | int linecount; 86 | // This is a token whose value has been PeekToken()ed. 87 | bool haveBufferedToken; 88 | STR_Token bufferedToken; 89 | } STR_ParserState; 90 | 91 | STR_Token STR_GetToken(STR_ParserState *ps); 92 | STR_Token STR_PeekToken(STR_ParserState *ps); 93 | size_t STR_GetStringValue(STR_Token tok, char *tokenBuf, size_t bufLen); 94 | size_t STR_GetString(STR_ParserState *ps, char *tokenBuf, size_t bufLen); 95 | size_t STR_GetIdent(STR_ParserState *ps, char *tokenBuf, size_t bufLen); 96 | bool STR_IsTokenIdent(STR_Token tok, const char *str); 97 | bool STR_IsTokenIdentCase(STR_Token tok, const char *str); 98 | int STR_GetIntegerValue(STR_Token tok); 99 | int STR_GetInteger(STR_ParserState *ps); 100 | bool STR_ExpectToken(STR_ParserState *ps, const char *str); 101 | 102 | #endif //ID_STR_H 103 | -------------------------------------------------------------------------------- /src/id_ti.c: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2012 David Gow 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include "ck_config.h" 21 | #include "ck_cross.h" 22 | #include "id_ca.h" 23 | 24 | #include 25 | 26 | #ifdef CK_WARN_ON_TILEINFO_OOB 27 | #define TI_WARN_ON_OOB() CK_Cross_LogMessage(CK_LOG_MSG_WARNING, "Out of bounds tileinfo access in %s (tile = %d, $%x)\n", __FUNCTION__, tile, tile) 28 | #else 29 | #define TI_WARN_ON_OOB() do { } while (0) 30 | #endif 31 | 32 | // Tileinfo 33 | 34 | //TODO: Split this up into several arrays? That would probably be _very_ smart. 35 | uint8_t *ti_tileInfo; 36 | 37 | int8_t TI_BackAnimTile(uint16_t tile) 38 | { 39 | const int index = tile + ca_gfxInfoE.numTiles16; 40 | if (tile > ca_gfxInfoE.numTiles16) 41 | { 42 | TI_WARN_ON_OOB(); 43 | return 0; 44 | } 45 | return ti_tileInfo[index]; 46 | } 47 | 48 | uint8_t TI_BackAnimTime(uint16_t tile) 49 | { 50 | if (tile > ca_gfxInfoE.numTiles16) 51 | { 52 | TI_WARN_ON_OOB(); 53 | return 0; 54 | } 55 | return ti_tileInfo[tile]; 56 | } 57 | 58 | uint8_t TI_ForeTop(uint16_t tile) 59 | { 60 | const int index = tile + ca_gfxInfoE.numTiles16 * 2; 61 | if (tile > ca_gfxInfoE.numTiles16m) 62 | { 63 | TI_WARN_ON_OOB(); 64 | return 0; 65 | } 66 | return ti_tileInfo[index]; 67 | } 68 | 69 | uint8_t TI_ForeBottom(uint16_t tile) 70 | { 71 | const int index = tile + ca_gfxInfoE.numTiles16 * 2 + ca_gfxInfoE.numTiles16m * 2; 72 | if (tile > ca_gfxInfoE.numTiles16m) 73 | { 74 | TI_WARN_ON_OOB(); 75 | return 0; 76 | } 77 | return ti_tileInfo[index]; 78 | } 79 | 80 | uint8_t TI_ForeLeft(uint16_t tile) 81 | { 82 | const int index = tile + ca_gfxInfoE.numTiles16 * 2 + ca_gfxInfoE.numTiles16m * 3; 83 | if (tile > ca_gfxInfoE.numTiles16m) 84 | { 85 | TI_WARN_ON_OOB(); 86 | return 0; 87 | } 88 | return ti_tileInfo[index]; 89 | } 90 | 91 | uint8_t TI_ForeRight(uint16_t tile) 92 | { 93 | const int index = tile + ca_gfxInfoE.numTiles16 * 2 + ca_gfxInfoE.numTiles16m; 94 | if (tile > ca_gfxInfoE.numTiles16m) 95 | { 96 | TI_WARN_ON_OOB(); 97 | return 0; 98 | } 99 | return ti_tileInfo[index]; 100 | } 101 | 102 | uint8_t TI_ForeMisc(uint16_t tile) 103 | { 104 | const int index = tile + ca_gfxInfoE.numTiles16 * 2 + ca_gfxInfoE.numTiles16m * 5; 105 | if (tile > ca_gfxInfoE.numTiles16m) 106 | { 107 | TI_WARN_ON_OOB(); 108 | return 0; 109 | } 110 | return ti_tileInfo[index]; 111 | } 112 | 113 | int8_t TI_ForeAnimTile(uint16_t tile) 114 | { 115 | const int index = tile + ca_gfxInfoE.numTiles16 * 2 + ca_gfxInfoE.numTiles16m * 4; 116 | if (tile > ca_gfxInfoE.numTiles16m) 117 | { 118 | TI_WARN_ON_OOB(); 119 | return 0; 120 | } 121 | return ti_tileInfo[index]; 122 | } 123 | 124 | uint8_t TI_ForeAnimTime(uint16_t tile) 125 | { 126 | const int index = tile + ca_gfxInfoE.numTiles16 * 2 + ca_gfxInfoE.numTiles16m * 6; 127 | if (tile > ca_gfxInfoE.numTiles16m) 128 | { 129 | TI_WARN_ON_OOB(); 130 | return 0; 131 | } 132 | return ti_tileInfo[index]; 133 | } 134 | -------------------------------------------------------------------------------- /src/id_ti.h: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2012 David Gow 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef ID_TI_H 21 | #define ID_TI_H 22 | 23 | #include 24 | 25 | int8_t TI_BackAnimTile(uint16_t tile); 26 | 27 | uint8_t TI_BackAnimTime(uint16_t tile); 28 | 29 | uint8_t TI_ForeTop(uint16_t tile); 30 | 31 | uint8_t TI_ForeLeft(uint16_t tile); 32 | 33 | uint8_t TI_ForeBottom(uint16_t tile); 34 | 35 | uint8_t TI_ForeRight(uint16_t tile); 36 | 37 | uint8_t TI_ForeMisc(uint16_t tile); 38 | 39 | int8_t TI_ForeAnimTile(uint16_t tile); 40 | 41 | uint8_t TI_ForeAnimTime(uint16_t tile); 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /src/id_us.h: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2012 David Gow 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef ID_US_H 21 | #define ID_US_H 22 | 23 | #include 24 | #include 25 | 26 | #include "ck_cross.h" 27 | // Needed for chunk_id_t 28 | #include "ck_act.h" 29 | 30 | #include "id_in.h" 31 | #include "id_fs.h" 32 | 33 | /* This keeps clang's static analyzer quiet. */ 34 | #ifdef __GNUC__ 35 | #define _NORETURN __attribute__((noreturn)) 36 | #else 37 | #define _NORETURN 38 | #endif 39 | 40 | // Record used to save & restore screen windows 41 | typedef struct 42 | { 43 | int x, y, w, h, px, py; 44 | } US_WindowRec; 45 | 46 | // In ck_quit.c, as it may be customized by individual games. 47 | void Quit(const char *msg) _NORETURN; 48 | void QuitF(const char *msg, ...) _NORETURN CK_PRINTF_FORMAT(1, 2); 49 | 50 | // id_us_1.c: 51 | // Parameter Checking 52 | int US_CheckParm(const char *parm, const char **strings); 53 | // UI functions 54 | void US_Print(const char *str); 55 | void US_PrintF(const char *str, ...); 56 | void US_PrintCentered(const char *str); 57 | void US_CPrintLine(const char *str); 58 | void US_CPrint(const char *str); 59 | void US_CPrintF(const char *str, ...); 60 | void US_ClearWindow(); 61 | void US_DrawWindow(int x, int y, int w, int h); 62 | void US_CenterWindow(int w, int h); 63 | void US_SaveWindow(US_WindowRec *win); 64 | void US_RestoreWindow(US_WindowRec *win); 65 | bool US_LineInput(uint16_t x, uint16_t y, char *buf, char *def, bool escok, uint16_t maxchars, uint16_t maxwidth); 66 | 67 | // Random Number Generation 68 | void US_InitRndT(bool randomize); 69 | int US_RndT(); 70 | void US_SetRndI(int index); 71 | int US_GetRndI(); 72 | 73 | // Getter and setter functions for print variables 74 | int US_GetWindowX(); 75 | int US_GetWindowY(); 76 | int US_GetWindowW(); 77 | int US_GetWindowH(); 78 | int US_GetPrintX(); 79 | int US_GetPrintY(); 80 | int16_t US_GetPrintFont(); 81 | int8_t US_GetPrintColour(); 82 | void US_SetWindowX(int parm); 83 | void US_SetWindowY(int parm); 84 | void US_SetWindowW(int parm); 85 | void US_SetWindowH(int parm); 86 | void US_SetPrintX(int parm); 87 | void US_SetPrintY(int parm); 88 | void US_SetPrintFont(int16_t parm); 89 | void US_SetPrintColour(int8_t parm); 90 | 91 | // Common 92 | extern bool us_noWait; // Debug mode enabled. 93 | extern bool us_tedLevel; // Launching a level from TED 94 | extern int us_tedLevelNumber; // Number of level to launch from TED 95 | 96 | // We need to steal these from main(). 97 | extern const char **us_argv; 98 | extern int us_argc; 99 | 100 | void US_Startup(void); 101 | void US_Setup(void); 102 | void US_Shutdown(void); 103 | 104 | // ID_US_2 105 | 106 | // Messages passed to the callback. 107 | typedef enum US_CardMsg 108 | { 109 | US_MSG_CardEntered, //The card has become the active card 110 | US_MSG_Draw, //Allows the callback to draw the card 111 | US_MSG_PostDraw, //Called after the card is drawn, for overlays 112 | US_MSG_DrawItemIcon, //Draws the icon of a single CardItem 113 | US_MSG_DrawItem, //Draws an item 114 | US_MSG_ItemEntered //An item was triggered 115 | } US_CardMsg; 116 | 117 | typedef enum US_CardItemType 118 | { 119 | US_ITEM_None, //An empty CardItem to end the list 120 | US_ITEM_Normal, //A normal item 121 | US_ITEM_Radio, //A 'radio' item, only one can be selected in a given card 122 | US_ITEM_Submenu //The item triggers a submenu when activated 123 | } US_CardItemType; 124 | 125 | // Used for storing flags, so not an enum (C++ doesn't like that) 126 | typedef uint16_t US_CardItemState; 127 | /*typedef*/ enum /*US_CardItemState*/ 128 | { 129 | US_IS_Checked = 0x01, 130 | US_IS_Selected = 0x02, 131 | US_IS_Disabled = 0x04, 132 | US_IS_Gap = 0x08 133 | } /*US_CardItemState*/; 134 | 135 | /* 136 | * Menu items can have 'commands', which cause the menu to quit, and something 137 | * to happen in the game. 138 | */ 139 | typedef enum US_CardCommand 140 | { 141 | US_Comm_None = 0, 142 | US_Comm_ReturnToGame = 1, 143 | US_Comm_EndGame = 2, 144 | US_Comm_Quit = 3, 145 | US_Comm_LoadGame = 4, 146 | US_Comm_NewEasyGame = 5, 147 | US_Comm_NewNormalGame = 6, 148 | US_Comm_NewHardGame = 7 149 | } US_CardCommand; 150 | 151 | struct US_Card; 152 | 153 | typedef struct US_CardItem 154 | { 155 | US_CardItemType type; 156 | US_CardItemState state; 157 | IN_ScanCode shortcutKey; 158 | const char *caption; 159 | US_CardCommand command; 160 | struct US_Card *subMenu; 161 | int x; 162 | int y; 163 | } US_CardItem; 164 | 165 | typedef bool (*US_CardCallbackFunc)(US_CardMsg, US_CardItem *); 166 | 167 | typedef struct US_Card 168 | { 169 | int x; 170 | int y; 171 | //int gfxChunk; 172 | chunk_id_t gfxChunk; 173 | // An unknown int 174 | int unknown; 175 | US_CardItem *items; //Pointer to item array. 176 | US_CardCallbackFunc msgCallback; 177 | int selectedItem; //Index of selected item. 178 | int unk1, unk2; 179 | } US_Card; 180 | 181 | void US_DrawCards(); 182 | void US_RunCards(); 183 | 184 | bool US_QuickSave(); 185 | bool US_QuickLoad(); 186 | 187 | // Related 188 | int USL_CtlDialog(const char *s1, const char *s2, const char *s3); 189 | 190 | // A few function pointers 191 | extern bool (*p_save_game)(FS_File handle); 192 | extern bool (*p_load_game)(FS_File handle, bool fromMenu); 193 | extern void (*p_exit_menu)(void); 194 | 195 | void US_SetMenuFunctionPointers(bool (*loadgamefunc)(FS_File, bool), bool (*savegamefunc)(FS_File), void (*exitmenufunc)(void)); 196 | 197 | 198 | typedef void (*US_MeasureStringFunc)(const char *string, uint16_t *width, uint16_t *height, int16_t chunk); 199 | typedef void (*US_DrawStringFunc)(const char *string, int x, int y, int chunk, int colour); 200 | 201 | void US_SetPrintRoutines(US_MeasureStringFunc measure, US_DrawStringFunc draw); 202 | // Savefiles 203 | 204 | #define US_MAX_SAVEDGAMENAME_LEN 32 205 | #define US_MAX_NUM_OF_SAVED_GAMES 6 206 | 207 | typedef CK_PACKED_STRUCT(US_Savefile 208 | { 209 | char id[4]; 210 | uint16_t printXOffset; 211 | bool used; 212 | char name[US_MAX_SAVEDGAMENAME_LEN + 1]; 213 | }) US_Savefile; 214 | 215 | extern US_Savefile us_savefiles[US_MAX_NUM_OF_SAVED_GAMES]; 216 | 217 | void US_GetSavefiles(void); 218 | 219 | // Text-mode order screen functions 220 | bool US_TerminalOk(); 221 | void US_PrintB8000Text(const uint8_t *textscreen, int numChars); 222 | 223 | #endif //ID_US_H 224 | -------------------------------------------------------------------------------- /src/id_us_textscreen.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "id_cfg.h" 7 | 8 | #ifdef _WIN32 9 | 10 | #include 11 | #include 12 | 13 | typedef enum US_Win32ConsoleMode 14 | { 15 | US_W32Console_Never, 16 | US_W32Console_IfAvailable, 17 | US_W32Console_PreferExisting, 18 | US_W32Console_CreateNew 19 | } US_Win32ConsoleMode; 20 | 21 | const char *US_Win32ConsoleMode_Strings[] = { 22 | "Never", 23 | "IfAvailable", 24 | "PreferExisting", 25 | "CreateNew" 26 | }; 27 | 28 | static bool us_console_createdW32Console = false; 29 | 30 | // Checks if the terminal is compatible with our B8000 text mode emulation. 31 | bool US_TerminalOk() 32 | { 33 | HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); 34 | DWORD consoleMode; 35 | US_Win32ConsoleMode mode = CFG_GetConfigEnum("win32_consoleMode", US_Win32ConsoleMode_Strings, US_W32Console_IfAvailable); 36 | 37 | if (mode == US_W32Console_Never) 38 | return false; 39 | 40 | if (mode == US_W32Console_CreateNew) 41 | FreeConsole(); 42 | 43 | // MSDN notes that this is a good way to check a console is a console. 44 | if (!GetConsoleMode(hConsole, &consoleMode)) 45 | { 46 | // Try to allocate a console if we don't have one. 47 | if (mode >= US_W32Console_PreferExisting) 48 | { 49 | if (!AllocConsole()) 50 | return false; 51 | us_console_createdW32Console = true; 52 | } 53 | else 54 | return false; 55 | } 56 | 57 | // Check if CP 437 is available 58 | UINT oldCP = GetConsoleOutputCP(); 59 | if (!SetConsoleOutputCP(437)) 60 | return false; 61 | 62 | SetConsoleOutputCP(oldCP); 63 | 64 | return true; 65 | } 66 | 67 | void US_PrintB8000Text(const uint8_t *textscreen, int numChars) 68 | { 69 | HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); 70 | CONSOLE_SCREEN_BUFFER_INFO oldInfo; 71 | DWORD oldMode; 72 | UINT oldCP = GetConsoleOutputCP(); 73 | GetConsoleScreenBufferInfo(hConsole, &oldInfo); 74 | GetConsoleMode(hConsole, &oldMode); 75 | SetConsoleOutputCP(437); 76 | SetConsoleMode(hConsole, oldMode & ~ENABLE_WRAP_AT_EOL_OUTPUT); 77 | 78 | for (int i = 0; i < numChars; ++i) 79 | { 80 | uint8_t ch = textscreen[i * 2]; 81 | uint8_t attrib = textscreen[i * 2 + 1]; 82 | 83 | SetConsoleTextAttribute(hConsole, attrib); 84 | WriteConsoleA(hConsole, &ch, 1, NULL, NULL); 85 | 86 | // We want to print a newline after every 80 characters 87 | if ((i % 80) == 79) 88 | { 89 | SetConsoleTextAttribute(hConsole, oldInfo.wAttributes); 90 | WriteConsoleA(hConsole, "\r\n", 2, NULL, NULL); 91 | } 92 | 93 | } 94 | SetConsoleOutputCP(oldCP); 95 | SetConsoleMode(hConsole, oldMode); 96 | SetConsoleTextAttribute(hConsole, oldInfo.wAttributes); 97 | if (CFG_GetConfigBool("us_pressKeyOnExit", us_console_createdW32Console)) 98 | { 99 | printf("Press any key to exit..."); 100 | _getch(); 101 | puts("\n"); 102 | } 103 | } 104 | 105 | #elif defined(__DJGPP__) 106 | 107 | #include 108 | #include 109 | 110 | bool US_TerminalOk() 111 | { 112 | return true; 113 | } 114 | 115 | void US_PrintB8000Text(const uint8_t *textscreen, int numChars) 116 | { 117 | dosmemput(textscreen, numChars * 2, 0xB8000); 118 | gotoxy(0, numChars / 80); 119 | } 120 | 121 | 122 | #else 123 | // Conversion for Codepage 437 (the IBM BIOS font character set) to unicode. 124 | uint32_t cp437[] = { 125 | // So called "non-printable" characters. 126 | 0x0000, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 127 | 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C, 128 | 0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8, 129 | 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC, 130 | // ASCII range 131 | 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 132 | 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 133 | 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 134 | 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, 135 | 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 136 | 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 137 | 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 138 | 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, 139 | 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 140 | 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 141 | 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 142 | 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x2302, 143 | // Accented and special characters 144 | 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 145 | 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 146 | 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 147 | 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, 148 | 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 149 | 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, 150 | // Box-drawing 151 | 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 152 | 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, 153 | 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 154 | 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 155 | 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 156 | 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 157 | // Greek letters and mathematical symbols. 158 | 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 159 | 0x03A6, 0x0398, 0x03A8, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 160 | 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 161 | 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0}; 162 | 163 | // Conversion table for EGA colours to ANSI. 164 | int colorconv[] = { 165 | 0, // Black, 166 | 4, // Blue, 167 | 2, // Green, 168 | 6, // Cyan, 169 | 1, // Red, 170 | 5, // Magenta, 171 | 3, // Yellow/Brown, 172 | 7 // White 173 | }; 174 | 175 | // Terminal types we support. 176 | const char *okterms[] = { 177 | "xterm", 178 | "xterm-16color", 179 | "xterm-88color", 180 | "xterm-256color", 181 | "ansi", 182 | "rxvt", 183 | "rxvt-16color", 184 | "rxvt-256color", 185 | "konsole", 186 | "konsole-16color", 187 | "konsole-256color", 188 | 0}; 189 | 190 | // Checks if the terminal is compatible with our B8000 text mode emulation. 191 | bool US_TerminalOk() 192 | { 193 | // We need a UTF-8 character encoding. 194 | const char *lang = getenv("LANG"); 195 | if (!lang) 196 | return false; 197 | if (!strstr(lang, "UTF-8")) 198 | return false; 199 | 200 | // We need a terminal which supports ANSI escape codes. 201 | const char *term = getenv("TERM"); 202 | if (!term) 203 | return false; 204 | for (int i = 0; okterms[i]; ++i) 205 | if (!strcmp(term, okterms[i])) 206 | return true; 207 | 208 | return false; 209 | } 210 | 211 | void US_PrintB8000Text(const uint8_t *textscreen, int numChars) 212 | { 213 | for (int i = 0; i < numChars; ++i) 214 | { 215 | uint8_t ch = textscreen[i * 2]; 216 | uint8_t attrib = textscreen[i * 2 + 1]; 217 | 218 | // Decode the attribute byte. 219 | int fgcol = colorconv[attrib & 7]; 220 | bool bold = attrib & 8; 221 | int bgcol = colorconv[(attrib >> 4) & 7]; 222 | bool blinking = attrib & 0x80; 223 | // Set colours 224 | printf("\x1b[%d;%dm", fgcol + 30, bgcol + 40); 225 | // Is bold? 226 | if (bold) 227 | printf("\x1b[1m"); 228 | // Is blinking 229 | if (blinking) 230 | printf("\x1b[5m"); 231 | 232 | uint32_t unich = cp437[ch]; 233 | 234 | // Output as UTF-8 ( 235 | if (unich < 0x80) 236 | printf("%c", unich); 237 | else if (unich < 0x800) 238 | printf("%c%c", (unich >> 6) | 0xC0, (unich & 0x3F) | 0x80); 239 | else if (unich < 0x10000) 240 | printf("%c%c%c", (unich >> 12) | 0xE0, ((unich >> 6) & 0x3F) | 0x80, (unich & 0x3F) | 0x80); 241 | else 242 | printf("HELP!"); 243 | 244 | // Reset 245 | printf("\x1b[0m"); 246 | 247 | // We want to print a newline after every 80 characters 248 | if ((i % 80) == 79) 249 | printf("\n"); 250 | } 251 | } 252 | #endif 253 | -------------------------------------------------------------------------------- /src/id_vh.h: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2012 David Gow 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef ID_VH_H 21 | #define ID_VH_H 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include "ck_cross.h" 28 | 29 | typedef CK_PACKED_STRUCT(VH_BitmapTableEntry 30 | { 31 | uint16_t width; 32 | uint16_t height; 33 | }) VH_BitmapTableEntry; 34 | 35 | typedef CK_PACKED_STRUCT(VH_SpriteTableEntry 36 | { 37 | uint16_t width, height; 38 | int16_t originX, originY; 39 | int16_t xl, yl, xh, yh; 40 | uint16_t shifts; 41 | }) VH_SpriteTableEntry; 42 | 43 | typedef CK_PACKED_STRUCT(VH_Font 44 | { 45 | uint16_t height; 46 | uint16_t location[256]; 47 | uint8_t width[256]; 48 | }) VH_Font; 49 | 50 | VH_BitmapTableEntry *VH_GetBitmapTableEntry(int bitmapNumber); 51 | VH_SpriteTableEntry *VH_GetSpriteTableEntry(int spriteNumber); 52 | 53 | #define VH_MAXSPRSHIFTS 4 54 | 55 | typedef struct VH_ShiftedSprite 56 | { 57 | size_t sprShiftOffset[VH_MAXSPRSHIFTS]; 58 | int sprShiftByteWidths[VH_MAXSPRSHIFTS]; 59 | uint8_t data[]; 60 | } VH_ShiftedSprite; 61 | 62 | VH_ShiftedSprite *VH_GetShiftedSprite(int chunk); 63 | int VH_GetShiftedSpriteWidth(VH_ShiftedSprite *shifted, int shift); 64 | 65 | void VH_Plot(int x, int y, int colour); 66 | void VH_HLine(int x1, int x2, int y, int colour); 67 | void VH_VLine(int y1, int y2, int x, int colour); 68 | void VH_Bar(int x, int y, int w, int h, int colour); 69 | void VH_DrawTile8(int x, int y, int tile); 70 | void VH_DrawTile8M(int x, int y, int tile); 71 | void VH_DrawTile16(int x, int y, int tile); 72 | void VH_DrawTile16M(int x, int y, int tile); 73 | void VH_DrawBitmap(int x, int y, int chunk); 74 | void VH_DrawMaskedBitmap(int x, int y, int chunk); 75 | void VH_DrawSprite(int x, int y, int chunk); 76 | void VH_DrawSpriteMask(int x, int y, int chunk, int colour); 77 | void VH_DrawShiftedSprite(int x, int y, int chunk, int shift); 78 | void VH_DrawShiftedSpriteMask(int x, int y, int chunk, int shift, int colour); 79 | void VH_DrawPropChar(int x, int y, int chunk, unsigned char c, int colour); 80 | void VH_MeasurePropString(const char *string, uint16_t *width, uint16_t *height, int16_t chunk); 81 | void VH_DrawPropString(const char *string, int x, int y, int chunk, int colour); 82 | 83 | bool VH_MarkUpdateBlock(int x1px, int y1px, int x2px, int y2px); 84 | 85 | void VHB_DrawTile8(int x, int y, int tile); 86 | void VHB_DrawTile8M(int x, int y, int tile); 87 | void VHB_DrawTile16(int x, int y, int tile); 88 | void VHB_DrawTile16M(int x, int y, int tile); 89 | void VHB_DrawBitmap(int x, int y, int chunk); 90 | void VHB_DrawMaskedBitmap(int x, int y, int chunk); 91 | void VHB_DrawSprite(int x, int y, int chunk); 92 | void VHB_Plot(int x, int y, int colour); 93 | void VHB_HLine(int x1, int x2, int y, int colour); 94 | void VHB_VLine(int y1, int y2, int x, int colour); 95 | void VHB_Bar(int x, int y, int w, int h, int colour); 96 | void VHB_DrawPropString(const char *string, int x, int y, int chunk, int colour); 97 | void VH_UpdateScreen(); 98 | #endif 99 | -------------------------------------------------------------------------------- /src/id_vl_private.h: -------------------------------------------------------------------------------- 1 | /* 2 | Omnispeak: A Commander Keen Reimplementation 3 | Copyright (C) 2012 David Gow 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, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | // A private header with contents used only by the VL code 21 | 22 | #ifndef ID_VL_PRIVATE_H 23 | #define ID_VL_PRIVATE_H 24 | 25 | #include 26 | 27 | #define VL_EGAVGA_GFX_WIDTH 320 28 | #define VL_EGAVGA_GFX_HEIGHT 200 29 | /* Graphics mode 0xD is scand-doubled on the VGA, so effectively a total of 30 | * 320x400 pixels consist of the displayed area. According to experimental 31 | * observations, the vertical overscan bars have the thickness of 8 pixels, 32 | * while each of the horizontal bars has 7 scanlines (after double-scanning). 33 | */ 34 | #define VL_VGA_GFX_SCALED_LEFTBORDER_WIDTH (vl_hasOverscanBorder ? 8 : 0) 35 | #define VL_VGA_GFX_SCALED_RIGHTBORDER_WIDTH (vl_hasOverscanBorder ? 8 : 0) 36 | #define VL_VGA_GFX_SCALED_TOPBORDER_HEIGHT (vl_hasOverscanBorder ? (vl_isIntegerScaled ? 8 : 7) : 0) 37 | #define VL_VGA_GFX_SCALED_BOTTOMBORDER_HEIGHT (vl_hasOverscanBorder ? (vl_isIntegerScaled ? 8 : 7) : 0) 38 | #define VL_VGA_GFX_WIDTH_SCALEFACTOR 1 39 | #define VL_VGA_GFX_HEIGHT_SCALEFACTOR 2 40 | /* If 320x200 is desired, then the bars should be 41 | * shrunken separately if symmetry is desired. 42 | */ 43 | #define VL_VGA_GFX_SHRUNK_LEFTBORDER_WIDTH (VL_VGA_GFX_SCALED_LEFTBORDER_WIDTH / VL_VGA_GFX_WIDTH_SCALEFACTOR) 44 | #define VL_VGA_GFX_SHRUNK_RIGHTBORDER_WIDTH (VL_VGA_GFX_SCALED_RIGHTBORDER_WIDTH / VL_VGA_GFX_WIDTH_SCALEFACTOR) 45 | #define VL_VGA_GFX_SHRUNK_TOPBORDER_HEIGHT (VL_VGA_GFX_SCALED_TOPBORDER_HEIGHT / VL_VGA_GFX_HEIGHT_SCALEFACTOR) 46 | #define VL_VGA_GFX_SHRUNK_BOTTOMBORDER_HEIGHT (VL_VGA_GFX_SCALED_BOTTOMBORDER_HEIGHT / VL_VGA_GFX_HEIGHT_SCALEFACTOR) 47 | 48 | #define VL_VGA_GFX_SCALED_WIDTH_PLUS_BORDER (VL_VGA_GFX_WIDTH_SCALEFACTOR * VL_EGAVGA_GFX_WIDTH + VL_VGA_GFX_SCALED_LEFTBORDER_WIDTH + VL_VGA_GFX_SCALED_RIGHTBORDER_WIDTH) 49 | #define VL_VGA_GFX_SCALED_HEIGHT_PLUS_BORDER (VL_VGA_GFX_HEIGHT_SCALEFACTOR * VL_EGAVGA_GFX_HEIGHT + VL_VGA_GFX_SCALED_TOPBORDER_HEIGHT + VL_VGA_GFX_SCALED_BOTTOMBORDER_HEIGHT) 50 | #define VL_VGA_GFX_SHRUNK_WIDTH_PLUS_BORDER (VL_EGAVGA_GFX_WIDTH + VL_VGA_GFX_SHRUNK_LEFTBORDER_WIDTH + VL_VGA_GFX_SHRUNK_RIGHTBORDER_WIDTH) 51 | #define VL_VGA_GFX_SHRUNK_HEIGHT_PLUS_BORDER (VL_EGAVGA_GFX_HEIGHT + VL_VGA_GFX_SHRUNK_TOPBORDER_HEIGHT + VL_VGA_GFX_SHRUNK_BOTTOMBORDER_HEIGHT) 52 | 53 | // Here is how the dimensions of the window are currently picked: 54 | // 1. The emulated 320x200 sub-window is first zoomed 55 | // by a factor of 3 (for each dimension) to 960x600. 56 | // 2. The height is then multiplied by 1.2, so the internal contents 57 | // (without the borders) have the aspect ratio of 4:3. 58 | // 59 | // There are a few more tricks in use to handle the overscan border 60 | // and VGA line doubling. 61 | #define VL_DEFAULT_WINDOW_WIDTH(n) (VL_VGA_GFX_SCALED_WIDTH_PLUS_BORDER * (n) / VL_VGA_GFX_WIDTH_SCALEFACTOR) 62 | #define VL_DEFAULT_WINDOW_HEIGHT(n) (6 * VL_VGA_GFX_SCALED_HEIGHT_PLUS_BORDER * (n) / ((vl_isIntegerScaled ? 6 : 5) * VL_VGA_GFX_HEIGHT_SCALEFACTOR)) 63 | 64 | #define VL_WINDOW_TITLE "Omnispeak" 65 | 66 | // EGA color table in RGB format (technically more can be chosen with the VGA) 67 | extern const uint8_t VL_EGARGBColorTable[16][3]; 68 | 69 | // TODO: Consider adding more fields (like panning) and having multiple 70 | // structs (emulated EGA/VGA adapter struct, SDL-specific struct, etc). 71 | typedef struct VL_EGAVGAAdapter 72 | { 73 | uint8_t bordercolor; 74 | uint8_t palette[16]; 75 | void *screen; 76 | } VL_EGAVGAAdapter; 77 | 78 | extern VL_EGAVGAAdapter vl_emuegavgaadapter; 79 | 80 | extern bool vl_isFullScreen; 81 | extern bool vl_isAspectCorrected; 82 | extern bool vl_isIntegerScaled; 83 | extern bool vl_hasOverscanBorder; 84 | extern int vl_swapInterval; 85 | 86 | // The full on-screen region, including overscan border. 87 | extern int vl_fullRgn_x; 88 | extern int vl_fullRgn_y; 89 | extern int vl_fullRgn_w; 90 | extern int vl_fullRgn_h; 91 | 92 | // The region of fullRgn, excluding overscan border. 93 | extern int vl_renderRgn_x; 94 | extern int vl_renderRgn_y; 95 | extern int vl_renderRgn_w; 96 | extern int vl_renderRgn_h; 97 | 98 | // The integer scaled render size. 99 | extern int vl_integerWidth; 100 | extern int vl_integerHeight; 101 | 102 | // Calculates render regions taking the integer scaling into account. 103 | void VL_CalculateRenderRegions(int realW, int realH); 104 | 105 | // Calculates a good default window size, given the desktop size. 106 | int VL_CalculateDefaultWindowScale(int desktopW, int desktopH); 107 | 108 | #endif 109 | -------------------------------------------------------------------------------- /src/id_vl_vk_shader.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | #extension GL_ARB_separate_shader_objects : enable 3 | 4 | layout(location = 0) out vec4 outColour; 5 | layout(location = 0) in vec2 texCoord; 6 | layout(set = 3, binding = 0) uniform FragUniforms 7 | { 8 | vec2 texOffs; 9 | vec4 pal[16]; 10 | } ubo; 11 | layout(set = 2, binding = 0, r8ui) uniform readonly uimage2D screen; 12 | 13 | void main() { 14 | ivec2 fixedTexCoord = ivec2(texCoord + ubo.texOffs); 15 | uint palIndex = imageLoad(screen, fixedTexCoord).r; 16 | outColour = ubo.pal[palIndex]; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /src/id_vl_vk_shader.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | #extension GL_ARB_separate_shader_objects : enable 3 | 4 | out gl_PerVertex { 5 | vec4 gl_Position; 6 | }; 7 | 8 | layout(location=0) out vec2 texCoord; 9 | 10 | vec2 positions[4] = vec2[]( 11 | vec2(-1.0, 1.0), 12 | vec2(1.0, 1.0), 13 | vec2(-1.0, -1.0), 14 | vec2(1.0, -1.0) 15 | ); 16 | 17 | vec2 texCoords[4] = vec2[]( 18 | vec2(0.0, 0.0), 19 | vec2(320.0, 0.0), 20 | vec2(0.0, 200.0), 21 | vec2(320.0, 200.0) 22 | ); 23 | 24 | void main() { 25 | texCoord = vec2(texCoords[gl_VertexIndex]); 26 | gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); 27 | } 28 | -------------------------------------------------------------------------------- /src/opl/dbopl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2002-2010 The DOSBox Team 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (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, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 | */ 18 | 19 | #include 20 | 21 | //Use 8 handlers based on a small logatirmic wavetabe and an exponential table for volume 22 | #define WAVE_HANDLER 10 23 | //Use a logarithmic wavetable with an exponential table for volume 24 | #define WAVE_TABLELOG 11 25 | //Use a linear wavetable with a multiply table for volume 26 | #define WAVE_TABLEMUL 12 27 | 28 | //Select the type of wave generator routine 29 | #define DBOPL_WAVE WAVE_TABLEMUL 30 | 31 | typedef struct _Chip Chip; 32 | typedef struct _Operator Operator; 33 | typedef struct _Channel Channel; 34 | 35 | typedef uintptr_t Bitu; 36 | typedef intptr_t Bits; 37 | typedef uint32_t Bit32u; 38 | typedef int32_t Bit32s; 39 | typedef uint16_t Bit16u; 40 | typedef int16_t Bit16s; 41 | typedef uint8_t Bit8u; 42 | typedef int8_t Bit8s; 43 | 44 | #if (DBOPL_WAVE == WAVE_HANDLER) 45 | typedef Bits ( DB_FASTCALL *WaveHandler) ( Bitu i, Bitu volume ); 46 | #endif 47 | 48 | #define DB_FASTCALL 49 | 50 | typedef Bits (*VolumeHandler)(Operator *self); 51 | typedef Channel* (*SynthHandler)(Channel *self, Chip* chip, Bit32u samples, Bit32s* output ); 52 | 53 | //Different synth modes that can generate blocks of data 54 | typedef enum { 55 | sm2AM, 56 | sm2FM, 57 | sm3AM, 58 | sm3FM, 59 | sm4Start, 60 | sm3FMFM, 61 | sm3AMFM, 62 | sm3FMAM, 63 | sm3AMAM, 64 | sm6Start, 65 | sm2Percussion, 66 | sm3Percussion, 67 | } SynthMode; 68 | 69 | //Shifts for the values contained in chandata variable 70 | enum { 71 | SHIFT_KSLBASE = 16, 72 | SHIFT_KEYCODE = 24, 73 | }; 74 | 75 | //Masks for operator 20 values 76 | enum { 77 | MASK_KSR = 0x10, 78 | MASK_SUSTAIN = 0x20, 79 | MASK_VIBRATO = 0x40, 80 | MASK_TREMOLO = 0x80, 81 | }; 82 | 83 | typedef enum { 84 | OFF, 85 | RELEASE, 86 | SUSTAIN, 87 | DECAY, 88 | ATTACK, 89 | } OperatorState; 90 | 91 | struct _Operator { 92 | VolumeHandler volHandler; 93 | 94 | #if (DBOPL_WAVE == WAVE_HANDLER) 95 | WaveHandler waveHandler; //Routine that generate a wave 96 | #else 97 | Bit16s* waveBase; 98 | Bit32u waveMask; 99 | Bit32u waveStart; 100 | #endif 101 | Bit32u waveIndex; //WAVE_BITS shifted counter of the frequency index 102 | Bit32u waveAdd; //The base frequency without vibrato 103 | Bit32u waveCurrent; //waveAdd + vibratao 104 | 105 | Bit32u chanData; //Frequency/octave and derived data coming from whatever channel controls this 106 | Bit32u freqMul; //Scale channel frequency with this, TODO maybe remove? 107 | Bit32u vibrato; //Scaled up vibrato strength 108 | Bit32s sustainLevel; //When stopping at sustain level stop here 109 | Bit32s totalLevel; //totalLevel is added to every generated volume 110 | Bit32u currentLevel; //totalLevel + tremolo 111 | Bit32s volume; //The currently active volume 112 | 113 | Bit32u attackAdd; //Timers for the different states of the envelope 114 | Bit32u decayAdd; 115 | Bit32u releaseAdd; 116 | Bit32u rateIndex; //Current position of the evenlope 117 | 118 | Bit8u rateZero; //Bits for the different states of the envelope having no changes 119 | Bit8u keyOn; //Bitmask of different values that can generate keyon 120 | //Registers, also used to check for changes 121 | Bit8u reg20, reg40, reg60, reg80, regE0; 122 | //Active part of the envelope we're in 123 | Bit8u state; 124 | //0xff when tremolo is enabled 125 | Bit8u tremoloMask; 126 | //Strength of the vibrato 127 | Bit8u vibStrength; 128 | //Keep track of the calculated KSR so we can check for changes 129 | Bit8u ksr; 130 | }; 131 | 132 | struct _Channel { 133 | Operator op[2]; 134 | SynthHandler synthHandler; 135 | Bit32u chanData; //Frequency/octave and derived values 136 | Bit32s old[2]; //Old data for feedback 137 | 138 | Bit8u feedback; //Feedback shift 139 | Bit8u regB0; //Register values to check for changes 140 | Bit8u regC0; 141 | //This should correspond with reg104, bit 6 indicates a Percussion channel, bit 7 indicates a silent channel 142 | Bit8u fourMask; 143 | Bit8s maskLeft; //Sign extended values for both channel's panning 144 | Bit8s maskRight; 145 | 146 | }; 147 | 148 | struct _Chip { 149 | //This is used as the base counter for vibrato and tremolo 150 | Bit32u lfoCounter; 151 | Bit32u lfoAdd; 152 | 153 | 154 | Bit32u noiseCounter; 155 | Bit32u noiseAdd; 156 | Bit32u noiseValue; 157 | 158 | //Frequency scales for the different multiplications 159 | Bit32u freqMul[16]; 160 | //Rates for decay and release for rate of this chip 161 | Bit32u linearRates[76]; 162 | //Best match attack rates for the rate of this chip 163 | Bit32u attackRates[76]; 164 | 165 | //18 channels with 2 operators each 166 | Channel chan[18]; 167 | 168 | Bit8u reg104; 169 | Bit8u reg08; 170 | Bit8u reg04; 171 | Bit8u regBD; 172 | Bit8u vibratoIndex; 173 | Bit8u tremoloIndex; 174 | Bit8s vibratoSign; 175 | Bit8u vibratoShift; 176 | Bit8u tremoloValue; 177 | Bit8u vibratoStrength; 178 | Bit8u tremoloStrength; 179 | //Mask for allowed wave forms 180 | Bit8u waveFormMask; 181 | //0 or -1 when enabled 182 | Bit8s opl3Active; 183 | 184 | }; 185 | 186 | /* 187 | struct Handler : public Adlib::Handler { 188 | DBOPL::Chip chip; 189 | virtual Bit32u WriteAddr( Bit32u port, Bit8u val ); 190 | virtual void WriteReg( Bit32u addr, Bit8u val ); 191 | virtual void Generate( MixerChannel* chan, Bitu samples ); 192 | virtual void Init( Bitu rate ); 193 | }; 194 | */ 195 | 196 | 197 | void Chip__Setup(Chip *self, Bit32u rate ); 198 | void DBOPL_InitTables( void ); 199 | void Chip__Chip(Chip *self); 200 | void Chip__WriteReg(Chip *self, Bit32u reg, Bit8u val ); 201 | void Chip__GenerateBlock2(Chip *self, Bitu total, Bit32s* output ); 202 | void Chip__GenerateBlock3(Chip *self, Bitu total, Bit32s* output ); 203 | 204 | // haleyjd 09/09/10: Not standard C. 205 | #ifdef _MSC_VER 206 | #define inline __inline 207 | #endif 208 | -------------------------------------------------------------------------------- /src/opl/nuked_opl3.h: -------------------------------------------------------------------------------- 1 | /* Nuked OPL3 2 | * Copyright (C) 2013-2020 Nuke.YKT 3 | * 4 | * This file is part of Nuked OPL3. 5 | * 6 | * Nuked OPL3 is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation, either version 2.1 9 | * of the License, or (at your option) any later version. 10 | * 11 | * Nuked OPL3 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 Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with Nuked OPL3. If not, see . 18 | 19 | * Nuked OPL3 emulator. 20 | * Thanks: 21 | * MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh): 22 | * Feedback and Rhythm part calculation information. 23 | * forums.submarine.org.uk(carbon14, opl3): 24 | * Tremolo and phase generator calculation information. 25 | * OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): 26 | * OPL2 ROMs. 27 | * siliconpr0n.org(John McMaster, digshadow): 28 | * YMF262 and VRC VII decaps and die shots. 29 | * 30 | * version: 1.8 31 | */ 32 | 33 | #ifndef OPL_OPL3_H 34 | #define OPL_OPL3_H 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | #include 41 | 42 | #ifndef OPL_ENABLE_STEREOEXT 43 | #define OPL_ENABLE_STEREOEXT 0 44 | #endif 45 | 46 | #define OPL_WRITEBUF_SIZE 1024 47 | #define OPL_WRITEBUF_DELAY 2 48 | 49 | typedef struct _opl3_slot opl3_slot; 50 | typedef struct _opl3_channel opl3_channel; 51 | typedef struct _opl3_chip opl3_chip; 52 | 53 | struct _opl3_slot { 54 | opl3_channel *channel; 55 | opl3_chip *chip; 56 | int16_t out; 57 | int16_t fbmod; 58 | int16_t *mod; 59 | int16_t prout; 60 | uint16_t eg_rout; 61 | uint16_t eg_out; 62 | uint8_t eg_inc; 63 | uint8_t eg_gen; 64 | uint8_t eg_rate; 65 | uint8_t eg_ksl; 66 | uint8_t *trem; 67 | uint8_t reg_vib; 68 | uint8_t reg_type; 69 | uint8_t reg_ksr; 70 | uint8_t reg_mult; 71 | uint8_t reg_ksl; 72 | uint8_t reg_tl; 73 | uint8_t reg_ar; 74 | uint8_t reg_dr; 75 | uint8_t reg_sl; 76 | uint8_t reg_rr; 77 | uint8_t reg_wf; 78 | uint8_t key; 79 | uint32_t pg_reset; 80 | uint32_t pg_phase; 81 | uint16_t pg_phase_out; 82 | uint8_t slot_num; 83 | }; 84 | 85 | struct _opl3_channel { 86 | opl3_slot *slots[2]; 87 | opl3_channel *pair; 88 | opl3_chip *chip; 89 | int16_t *out[4]; 90 | 91 | #if OPL_ENABLE_STEREOEXT 92 | int32_t leftpan; 93 | int32_t rightpan; 94 | #endif 95 | 96 | uint8_t chtype; 97 | uint16_t f_num; 98 | uint8_t block; 99 | uint8_t fb; 100 | uint8_t con; 101 | uint8_t alg; 102 | uint8_t ksv; 103 | uint16_t cha, chb; 104 | uint8_t ch_num; 105 | }; 106 | 107 | typedef struct _opl3_writebuf { 108 | uint64_t time; 109 | uint16_t reg; 110 | uint8_t data; 111 | } opl3_writebuf; 112 | 113 | struct _opl3_chip { 114 | opl3_channel channel[18]; 115 | opl3_slot slot[36]; 116 | uint16_t timer; 117 | uint64_t eg_timer; 118 | uint8_t eg_timerrem; 119 | uint8_t eg_state; 120 | uint8_t eg_add; 121 | uint8_t newm; 122 | uint8_t nts; 123 | uint8_t rhy; 124 | uint8_t vibpos; 125 | uint8_t vibshift; 126 | uint8_t tremolo; 127 | uint8_t tremolopos; 128 | uint8_t tremoloshift; 129 | uint32_t noise; 130 | int16_t zeromod; 131 | int32_t mixbuff[2]; 132 | uint8_t rm_hh_bit2; 133 | uint8_t rm_hh_bit3; 134 | uint8_t rm_hh_bit7; 135 | uint8_t rm_hh_bit8; 136 | uint8_t rm_tc_bit3; 137 | uint8_t rm_tc_bit5; 138 | 139 | #if OPL_ENABLE_STEREOEXT 140 | uint8_t stereoext; 141 | #endif 142 | 143 | /* OPL3L */ 144 | int32_t rateratio; 145 | int32_t samplecnt; 146 | int16_t oldsamples[2]; 147 | int16_t samples[2]; 148 | 149 | uint64_t writebuf_samplecnt; 150 | uint32_t writebuf_cur; 151 | uint32_t writebuf_last; 152 | uint64_t writebuf_lasttime; 153 | opl3_writebuf writebuf[OPL_WRITEBUF_SIZE]; 154 | }; 155 | 156 | void OPL3_Generate(opl3_chip *chip, int16_t *buf); 157 | void OPL3_GenerateResampled(opl3_chip *chip, int16_t *buf); 158 | void OPL3_Reset(opl3_chip *chip, uint32_t samplerate); 159 | void OPL3_WriteReg(opl3_chip *chip, uint16_t reg, uint8_t v); 160 | void OPL3_WriteRegBuffered(opl3_chip *chip, uint16_t reg, uint8_t v); 161 | void OPL3_GenerateStream(opl3_chip *chip, int16_t *sndptr, uint32_t numsamples); 162 | 163 | #ifdef __cplusplus 164 | } 165 | #endif 166 | 167 | #endif 168 | -------------------------------------------------------------------------------- /src/windowsres.rc: -------------------------------------------------------------------------------- 1 | id ICON "../win32icon.ico" 2 | 3 | 1 VERSIONINFO 4 | FILEVERSION 1,0,0,0 5 | PRODUCTVERSION 1,0,0,0 6 | BEGIN 7 | BLOCK "StringFileInfo" 8 | BEGIN 9 | BLOCK "080904E4" 10 | BEGIN 11 | VALUE "CompanyName", "Omnispeak Developers" 12 | VALUE "FileDescription", "A Commander Keen Reimplementation" 13 | VALUE "FileVersion", "1.0" 14 | VALUE "InternalName", "omnispeak" 15 | VALUE "LegalCopyright", "(C) 2012-2021 Omnispeak Developers. Commander Keen is (C) id Software." 16 | VALUE "OriginalFilename", "omnispeak.exe" 17 | VALUE "ProductName", "Omnispeak" 18 | VALUE "ProductVersion", "1.0" 19 | END 20 | END 21 | 22 | BLOCK "VarFileInfo" 23 | BEGIN 24 | VALUE "Translation", 0x809, 1252 25 | END 26 | END 27 | -------------------------------------------------------------------------------- /tests/demo0.dump4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/tests/demo0.dump4 -------------------------------------------------------------------------------- /tests/demo0.dump5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/tests/demo0.dump5 -------------------------------------------------------------------------------- /tests/demo0.dump6v14: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/tests/demo0.dump6v14 -------------------------------------------------------------------------------- /tests/demo0.dump6v15: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/tests/demo0.dump6v15 -------------------------------------------------------------------------------- /tests/demo1.dump4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/tests/demo1.dump4 -------------------------------------------------------------------------------- /tests/demo1.dump5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/tests/demo1.dump5 -------------------------------------------------------------------------------- /tests/demo1.dump6v14: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/tests/demo1.dump6v14 -------------------------------------------------------------------------------- /tests/demo1.dump6v15: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/tests/demo1.dump6v15 -------------------------------------------------------------------------------- /tests/demo2.dump4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/tests/demo2.dump4 -------------------------------------------------------------------------------- /tests/demo2.dump5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/tests/demo2.dump5 -------------------------------------------------------------------------------- /tests/demo2.dump6v14: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/tests/demo2.dump6v14 -------------------------------------------------------------------------------- /tests/demo2.dump6v15: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/tests/demo2.dump6v15 -------------------------------------------------------------------------------- /tests/demo3.dump4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/tests/demo3.dump4 -------------------------------------------------------------------------------- /tests/demo3.dump5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/tests/demo3.dump5 -------------------------------------------------------------------------------- /tests/demo3.dump6v14: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/tests/demo3.dump6v14 -------------------------------------------------------------------------------- /tests/demo3.dump6v15: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/tests/demo3.dump6v15 -------------------------------------------------------------------------------- /tests/demo4.dump4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/tests/demo4.dump4 -------------------------------------------------------------------------------- /tests/demo4.dump5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/tests/demo4.dump5 -------------------------------------------------------------------------------- /tests/demo4.dump6v14: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/tests/demo4.dump6v14 -------------------------------------------------------------------------------- /tests/demo4.dump6v15: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/tests/demo4.dump6v15 -------------------------------------------------------------------------------- /tests/testdump.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | EPISODE=$2 4 | OMNIDUMP=`mktemp` 5 | KEENDUMP="../tests/demo${1}.dump${EPISODE}" 6 | 7 | ./omnispeak /EPISODE $EPISODE /PLAYDEMO $1 /DUMPFILE "$OMNIDUMP" 8 | 9 | diff "$OMNIDUMP" "$KEENDUMP" 10 | RES=$? 11 | 12 | if [ $RES -ne 0 ] ; then 13 | mkdir -p ../log 14 | OMNIDUMPTXT="../log/omni${EPISODE}dump${1}.txt" 15 | KEENDUMPTXT="../log/keen${EPISODE}dump${1}.txt" 16 | echo "Dump was different for Episode $EPISODE, Demo $1" 17 | ./dumpprinter "$OMNIDUMP" $EPISODE > "$OMNIDUMPTXT" 18 | ./dumpprinter "$KEENDUMP" $EPISODE > "$KEENDUMPTXT" 19 | diff "$OMNIDUMPTXT" "$KEENDUMPTXT" > "../log/ep${EPISODE}demp${1}.diff" 20 | diff "$OMNIDUMPTXT" "$KEENDUMPTXT" 21 | else 22 | echo "Dump matched for Episode $EPISODE, Demo $1" 23 | fi 24 | 25 | exit $RES 26 | -------------------------------------------------------------------------------- /tools/dumpprinter/dumpprinter.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | /*** Some stuff was copied-and-pasted-and-modified from Omnispeak. ***/ 7 | /*** ALL fields are printed as unsigned, making it possible to ***/ 8 | /*** read and print each object as an array of 16-bit values. ***/ 9 | 10 | static size_t CK_Cross_freadInt16LE(void *ptr, size_t count, FILE *stream) 11 | { 12 | count = fread(ptr, 2, count, stream); 13 | #ifdef CK_CROSS_IS_BIGENDIAN 14 | for (size_t loopVar = 0; loopVar < count; loopVar++, ((uint16_t *) ptr)++) 15 | *(uint16_t *) ptr = CK_Cross_Swap16(*(uint16_t *) ptr); 16 | #endif 17 | return count; 18 | } 19 | 20 | static size_t CK_Cross_freadInt32LE(void *ptr, size_t count, FILE *stream) 21 | { 22 | count = fread(ptr, 4, count, stream); 23 | #ifdef CK_CROSS_IS_BIGENDIAN 24 | for (size_t loopVar = 0; loopVar < count; loopVar++, ((uint32_t *) ptr)++) 25 | *(uint32_t *) ptr = CK_Cross_Swap32(*(uint32_t *) ptr); 26 | #endif 27 | return count; 28 | } 29 | 30 | 31 | typedef struct CK_GameState 32 | { 33 | uint16_t mapPosX; 34 | uint16_t mapPosY; 35 | uint16_t levelsDone[25]; // Number of levels complete 36 | uint32_t/*int32_t*/ keenScore; // Keen's score. (This _is_ signed, by the looks of all the 'jl' instructions) 37 | uint32_t/*int32_t*/ nextKeenAt; // Score keen will get a new life at. 38 | uint16_t/*int16_t*/ numShots; 39 | uint16_t/*int16_t*/ numCentilife; 40 | 41 | // The episode-specific variables come here 42 | // They were probably conditionally compiled in the DOS version 43 | // so that the Gamestate struct is variably sized between eps. 44 | union 45 | { 46 | struct 47 | { 48 | uint16_t/*int16_t*/ wetsuit; 49 | uint16_t/*int16_t*/ membersRescued; 50 | } ck4; 51 | 52 | struct 53 | { 54 | uint16_t/*int16_t*/ securityCard; 55 | uint16_t/*int16_t*/ word_4729C; 56 | uint16_t/*int16_t*/ fusesRemaining; 57 | } ck5; 58 | 59 | struct 60 | { 61 | uint16_t/*int16_t*/ sandwich; 62 | uint16_t/*int16_t*/ rope; // 1 == collected, 2 == deployed on cliff 63 | uint16_t/*int16_t*/ passcard; 64 | uint16_t/*int16_t*/ inRocket; // true if flying 65 | } ck6; 66 | } ep; 67 | 68 | uint16_t/*int16_t*/ keyGems[4]; 69 | uint16_t/*int16_t*/ currentLevel; 70 | uint16_t/*int16_t*/ numLives; // Number of lives keen has. 71 | uint16_t/*int16_t*/ difficulty; // Difficulty level of current game 72 | uint16_t platformOffset; // This was a 16-bit pointer in DOS Keen5.exe 73 | } CK_GameState; 74 | 75 | /*** NOTE: There's no need for CK_object, we simply read object as an array ***/ 76 | 77 | static bool processTimeCount(FILE *fp) 78 | { 79 | uint32_t timecount; 80 | if (CK_Cross_freadInt32LE(&timecount, 1, fp) != 1) 81 | return false; 82 | printf("Timecount: %08X\n", timecount); 83 | return true; 84 | } 85 | 86 | static int g_episodeNum; 87 | 88 | static bool processGameState(FILE *fp) 89 | { 90 | CK_GameState state; 91 | int i; 92 | 93 | if ((CK_Cross_freadInt16LE(&state.mapPosX, 1, fp) != 1) 94 | || (CK_Cross_freadInt16LE(&state.mapPosY, 1, fp) != 1) 95 | || (CK_Cross_freadInt16LE(state.levelsDone, sizeof(state.levelsDone)/2, fp) != sizeof(state.levelsDone)/2) 96 | || (CK_Cross_freadInt32LE(&state.keenScore, 1, fp) != 1) 97 | || (CK_Cross_freadInt32LE(&state.nextKeenAt, 1, fp) != 1) 98 | || (CK_Cross_freadInt16LE(&state.numShots, 1, fp) != 1) 99 | || (CK_Cross_freadInt16LE(&state.numCentilife, 1, fp) != 1) 100 | || ((g_episodeNum == 4) && 101 | ( 102 | (CK_Cross_freadInt16LE(&state.ep.ck4.wetsuit, 1, fp) != 1) 103 | || (CK_Cross_freadInt16LE(&state.ep.ck4.membersRescued, 1, fp) != 1) 104 | ) 105 | ) 106 | || ((g_episodeNum == 5) && 107 | ( 108 | (CK_Cross_freadInt16LE(&state.ep.ck5.securityCard, 1, fp) != 1) 109 | || (CK_Cross_freadInt16LE(&state.ep.ck5.word_4729C, 1, fp) != 1) 110 | || (CK_Cross_freadInt16LE(&state.ep.ck5.fusesRemaining, 1, fp) != 1) 111 | ) 112 | ) 113 | || ((g_episodeNum == 6) && 114 | ( 115 | (CK_Cross_freadInt16LE(&state.ep.ck6.sandwich, 1, fp) != 1) 116 | || (CK_Cross_freadInt16LE(&state.ep.ck6.rope, 1, fp) != 1) 117 | || (CK_Cross_freadInt16LE(&state.ep.ck6.passcard, 1, fp) != 1) 118 | || (CK_Cross_freadInt16LE(&state.ep.ck6.inRocket, 1, fp) != 1) 119 | ) 120 | ) 121 | || (CK_Cross_freadInt16LE(state.keyGems, sizeof(state.keyGems)/2, fp) != sizeof(state.keyGems)/2) 122 | || (CK_Cross_freadInt16LE(&state.currentLevel, 1, fp) != 1) 123 | || (CK_Cross_freadInt16LE(&state.numLives, 1, fp) != 1) 124 | || (CK_Cross_freadInt16LE(&state.difficulty, 1, fp) != 1) 125 | || (CK_Cross_freadInt16LE(&state.platformOffset, 1, fp) != 1) // BACKWARDS COMPATIBILITY 126 | ) 127 | return false; 128 | 129 | printf("Gamestate: %04X %04X", state.mapPosX, state.mapPosY); 130 | 131 | for (i = 0; i < 25; ++i) 132 | printf(" %04X", state.levelsDone[i]); 133 | 134 | printf(" %08X %08X %04X %04X", state.keenScore, state.nextKeenAt, state.numShots, state.numCentilife); 135 | 136 | if (g_episodeNum == 4) 137 | printf(" %04X %04X", state.ep.ck4.wetsuit, state.ep.ck4.membersRescued); 138 | else if (g_episodeNum == 5) 139 | printf(" %04X %04X %04X", state.ep.ck5.securityCard, state.ep.ck5.word_4729C, state.ep.ck5.fusesRemaining); 140 | else if (g_episodeNum == 6) 141 | printf(" %04X %04X %04X %04X", state.ep.ck6.sandwich, state.ep.ck6.rope, state.ep.ck6.passcard, state.ep.ck6.inRocket); 142 | 143 | for (i = 0; i < 4; ++i) 144 | printf(" %04X", state.keyGems[i]); 145 | 146 | printf(" %04X %04X %04X %04X\n", state.currentLevel, state.numLives, state.difficulty, state.platformOffset); 147 | 148 | return true; 149 | } 150 | 151 | static bool processObjects(FILE *fp) 152 | { 153 | uint16_t objFields[38]; 154 | int i, j; 155 | for (j = 0; j < 100; ++j) 156 | { 157 | if (CK_Cross_freadInt16LE(&objFields, 38, fp) != 38) 158 | return false; 159 | 160 | printf("Obj %02X:", j); 161 | for (i = 0; i < 38; ++i) 162 | printf(" %04X", objFields[i]); 163 | printf("\n"); 164 | } 165 | return true; 166 | } 167 | 168 | int main(int argc, char **argv) 169 | { 170 | if (argc != 3) 171 | { 172 | fprintf(stderr, "Usage: %s \n", argv[0]); 173 | return 0; 174 | } 175 | g_episodeNum = atoi(argv[2]); 176 | if ((g_episodeNum < 4) || (g_episodeNum > 6)) 177 | { 178 | fprintf(stderr, " argument must be a number in the range 4-6.\n"); 179 | return 1; 180 | } 181 | FILE *fp = fopen(argv[1], "rb"); 182 | if (fp == NULL) 183 | { 184 | fprintf(stderr, "ERROR - Cannot open file %s for reading\n", argv[1]); 185 | return 1; 186 | } 187 | 188 | while (processTimeCount(fp) && processGameState(fp) && processObjects(fp)) 189 | ; 190 | 191 | fclose(fp); 192 | return 0; 193 | } 194 | -------------------------------------------------------------------------------- /tools/kdumper/k4e14dmp.asm: -------------------------------------------------------------------------------- 1 | ; Keen 4 EGA Apogee v1.4 2 | %define GAMESTATE_OFFSET 0x7A1A 3 | %define GAMESTATE_SIZE 0x56 4 | %define OBJLIST_OFFSET 0xA807 5 | %define OBJLIST_SIZE (0x64*0x4C) 6 | %define CA_FARWRITE_FUNC_FAR_PTR 0x12A6:0x0140 7 | %define OBJ_LOOP_FAR_PTR 0x06BD:0x2248 8 | %define OBJ_PAST_LOOP_FAR_PTR 0x06BD:0x233E 9 | %define TIMECOUNT_OFFSET 0xA53D 10 | 11 | %include "kdumper.inc" 12 | -------------------------------------------------------------------------------- /tools/kdumper/k4e14dmp.pat: -------------------------------------------------------------------------------- 1 | %ext ck4 2 | 3 | %version 1.4 4 | 5 | %patch $8F09 $EA $12A617BFRL # Jump to CAL_DialogUpdate 6 | 7 | # Replace CAL_DialogUpdate itself 8 | %patch $1421F $75 $3C 9 | $6A $00 10 | $6A $04 11 | $1E 12 | $68 $A53DW 13 | $6A $01 14 | $9A $12A60140RL 15 | $83 $C4 $0A 16 | $6A $00 17 | $6A $56 18 | $1E 19 | $68 $7A1AW 20 | $6A $01 21 | $9A $12A60140RL 22 | $83 $C4 $0A 23 | $6A $00 24 | $68 $1DB0W 25 | $1E 26 | $68 $A807W 27 | $6A $01 28 | $9A $12A60140RL 29 | $83 $C4 $0A 30 | $EA $06BD233ERL 31 | $EA $06BD2248RL 32 | 33 | %end 34 | -------------------------------------------------------------------------------- /tools/kdumper/k5e14dmp.asm: -------------------------------------------------------------------------------- 1 | ; Keen 5 EGA Apogee v1.4 2 | %define GAMESTATE_OFFSET 0x6F18 3 | %define GAMESTATE_SIZE 0x58 4 | %define OBJLIST_OFFSET 0x9E6F 5 | %define OBJLIST_SIZE (0x64*0x4C) 6 | %define CA_FARWRITE_FUNC_FAR_PTR 0x13A0:0x013D 7 | %define OBJ_LOOP_FAR_PTR 0x06B9:0x21FA 8 | %define OBJ_PAST_LOOP_FAR_PTR 0x06B9:0x22F0 9 | %define TIMECOUNT_OFFSET 0x9BA5 10 | 11 | %include "kdumper.inc" 12 | -------------------------------------------------------------------------------- /tools/kdumper/k5e14dmp.pat: -------------------------------------------------------------------------------- 1 | %ext ck5 2 | 3 | %version 1.4 4 | 5 | %patch $8E7B $EA $13A017BCRL # Jump to CAL_DialogUpdate 6 | 7 | # Replace CAL_DialogUpdate itself 8 | %patch $151BC $75 $3C 9 | $6A $00 10 | $6A $04 11 | $1E 12 | $68 $9BA5W 13 | $6A $01 14 | $9A $13A0013DRL 15 | $83 $C4 $0A 16 | $6A $00 17 | $6A $58 18 | $1E 19 | $68 $6F18W 20 | $6A $01 21 | $9A $13A0013DRL 22 | $83 $C4 $0A 23 | $6A $00 24 | $68 $1DB0W 25 | $1E 26 | $68 $9E6FW 27 | $6A $01 28 | $9A $13A0013DRL 29 | $83 $C4 $0A 30 | $EA $06B922F0RL 31 | $EA $06B921FARL 32 | 33 | %end 34 | -------------------------------------------------------------------------------- /tools/kdumper/k6e14dmp.asm: -------------------------------------------------------------------------------- 1 | ; Keen 6 EGA v1.4 2 | %define GAMESTATE_OFFSET 0x7552 3 | %define GAMESTATE_SIZE 0x5A 4 | %define OBJLIST_OFFSET 0xA995 5 | %define OBJLIST_SIZE (0x64*0x4C) 6 | %define CA_FARWRITE_FUNC_FAR_PTR 0x125A:0x0131 7 | %define OBJ_LOOP_FAR_PTR 0x069A:0x2252 8 | %define OBJ_PAST_LOOP_FAR_PTR 0x069A:0x2348 9 | %define TIMECOUNT_OFFSET 0xA6CB 10 | 11 | %include "kdumper.inc" 12 | -------------------------------------------------------------------------------- /tools/kdumper/k6e14dmp.pat: -------------------------------------------------------------------------------- 1 | %ext ck6 2 | 3 | %version 1.4 4 | 5 | %patch $8CE3 $EA $125A17B0RL # Jump to CAL_DialogUpdate 6 | 7 | # Replace CAL_DialogUpdate itself 8 | %patch $13D50 $75 $3C 9 | $6A $00 10 | $6A $04 11 | $1E 12 | $68 $A6CBW 13 | $6A $01 14 | $9A $125A0131RL 15 | $83 $C4 $0A 16 | $6A $00 17 | $6A $5A 18 | $1E 19 | $68 $7552W 20 | $6A $01 21 | $9A $125A0131RL 22 | $83 $C4 $0A 23 | $6A $00 24 | $68 $1DB0W 25 | $1E 26 | $68 $A995W 27 | $6A $01 28 | $9A $125A0131RL 29 | $83 $C4 $0A 30 | $EA $069A2348RL 31 | $EA $069A2252RL 32 | 33 | %end 34 | -------------------------------------------------------------------------------- /tools/kdumper/k6e15dmp.asm: -------------------------------------------------------------------------------- 1 | ; Keen 6 EGA v1.5 2 | %define GAMESTATE_OFFSET 0x9408 3 | %define GAMESTATE_SIZE 0x5A 4 | %define OBJLIST_OFFSET 0x75CE 5 | %define OBJLIST_SIZE (0x64*0x4C) 6 | %define CA_FARWRITE_FUNC_FAR_PTR 0x1254:0x0136 7 | %define OBJ_LOOP_FAR_PTR 0x06D6:0x212B 8 | %define OBJ_PAST_LOOP_FAR_PTR 0x06D6:0x2221 9 | %define TIMECOUNT_OFFSET 0xE6C2 10 | 11 | %include "kdumper.inc" 12 | -------------------------------------------------------------------------------- /tools/kdumper/k6e15dmp.pat: -------------------------------------------------------------------------------- 1 | %ext ck6 2 | 3 | %version 1.5 4 | 5 | %patch $8F7C $EA $12541719RL # Jump to CAL_DialogUpdate 6 | 7 | # Replace CAL_DialogUpdate itself 8 | %patch $13C59 $75 $3C 9 | $6A $00 10 | $6A $04 11 | $1E 12 | $68 $E6C2W 13 | $6A $01 14 | $9A $12540136RL 15 | $83 $C4 $0A 16 | $6A $00 17 | $6A $5A 18 | $1E 19 | $68 $9408W 20 | $6A $01 21 | $9A $12540136RL 22 | $83 $C4 $0A 23 | $6A $00 24 | $68 $1DB0W 25 | $1E 26 | $68 $75CEW 27 | $6A $01 28 | $9A $12540136RL 29 | $83 $C4 $0A 30 | $EA $06D62221RL 31 | $EA $06D6212BRL 32 | 33 | %end 34 | -------------------------------------------------------------------------------- /tools/kdumper/kdumper.inc: -------------------------------------------------------------------------------- 1 | ; Replace CAL_DialogUpdate with this code 2 | 3 | jnz ExecuteLoop 4 | 5 | push 0 6 | push 4 7 | push ds 8 | push TIMECOUNT_OFFSET 9 | push 1 ; STDOUT 10 | call CA_FARWRITE_FUNC_FAR_PTR 11 | add sp, 0xA 12 | 13 | push 0 14 | push GAMESTATE_SIZE 15 | push ds 16 | push GAMESTATE_OFFSET 17 | push 1 18 | call CA_FARWRITE_FUNC_FAR_PTR 19 | add sp, 0xA 20 | 21 | push 0 22 | push OBJLIST_SIZE 23 | push ds 24 | push OBJLIST_OFFSET 25 | push 1 26 | call CA_FARWRITE_FUNC_FAR_PTR 27 | add sp, 0xA 28 | 29 | jmp OBJ_PAST_LOOP_FAR_PTR ; Go past the initial PlayLoop objects loop 30 | 31 | ExecuteLoop: 32 | 33 | jmp OBJ_LOOP_FAR_PTR ; Go to the beginning of the initial PlayLoop objects loop 34 | -------------------------------------------------------------------------------- /unixicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/unixicon.png -------------------------------------------------------------------------------- /win32icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulix/omnispeak/e6c5fd710c1db9fd4cfe0b3c6cf325174d2aaded/win32icon.ico --------------------------------------------------------------------------------