digows/cosmo
GitHub: digows/cosmo
经典 DOS 游戏《Cosmo's Cosmic Adventure》的原生源码跨平台移植版,通过自研硬件模拟层在现代系统上脱离 DOSBox 直接运行。
Stars: 1 | Forks: 0
# Cosmo's Cosmic Adventure — 适用于 macOS、Linux 和 Windows 的原生移植版
这是 **Cosmo's Cosmic Adventure: Forbidden Planet**(Apogee
Software,1992年)的源码移植版,可在现代计算机上原生运行。无需 DOSBox,无需模拟器,
也无需虚拟机——直接使用游戏原始代码,为你的计算机编译而成。
[](https://github.com/digows/cosmo/actions/workflows/ci.yml)
[](LICENSE)


| | |
|:-:|:-:|
|  |  |
|  |  |
每张截图均由该移植版在 macOS 上使用原始 1992 年数据文件生成——并非从模拟器中截取。
## 下载与游玩
**[获取最新发布版](https://github.com/digows/cosmo/releases/latest)** —
支持 macOS、Windows 和 Linux。每个下载包都包含免费的 Episode 1,解压后即可直接游玩;
无需安装。如果你拥有 Episode 2 和 3,启动器会提示你指定它们的位置。
## 项目说明
项目的起点是游戏自身的代码,而非重新实现。该项目基于 [Cosmore](https://github.com/smitelli/cosmore),这是 Scott
Smitelli 对 v1.20 版本源码的复原,其来源于对 1992 年可执行文件的反汇编,字节级还原度高达 96.3%,且仅替换了原来与 PC 硬件交互的底层部分。
该层之上的所有内容都是 Todd Replogle 当年编写的原始风貌:物理效果、
角色活动、碰撞处理以及原始 Bug。而从零开始编写的部分是底层的
机器环境——一个模拟的 EGA 适配器、可编程间隔定时器、键盘控制器、PC 扬声器以及一个 AdLib。
如果你想了解开发过程中踩过的坑,可以阅读
**[docs/porting-notes.md](docs/porting-notes.md)**。
## 状态
| 子系统 | 状态 |
|---|---|
| 全部三个章节,内置游戏风格的启动器 | ✅ |
| 带图标的应用程序包,下载即可直接运行 | ✅ |
| 模拟的 EGA —— 写入模式、锁存器、位掩码、映射掩码、置位/复位 | ✅ 单元测试 |
| 平面解码、调色板、SDL3 呈现 | ✅ 单元测试 |
| 中断与时序控制层 —— int 8 / int 9、PIT、PIC | ✅ 140 Hz,经测量 |
| 地图加载、滚动、角色活动、吸引模式演示 | ✅ |
| 键盘控制,包括移动时跳跃 | ✅ 脚本验证 |
| 游戏保存与读取 | ✅ |
| PC 扬声器音效 | ✅ 已对照游戏原始音频数据进行验证 |
| AdLib (OPL2) 音乐,基于 [ymfm](https://github.com/aaronsgiles/ymfm) | ✅ |
| macOS、Linux 和 Windows 构建 | ✅ CI 状态为通过 |
| 摇杆 | ⬜ 未实现 |
| 与 DOSBox 进行逐帧对比 | ⬜ 最大的遗留差距 |
游戏可完整运行到底:`cosmo` 会在其独立的线程上启动原始的 `InnerMain()`,主线程扮演 PC 硬件的角色。它将以原版设定的 10.8 帧/秒的节奏,播放标题画面、职员表以及可玩的吸引模式演示。
## 构建
要求安装 CMake 3.21+、支持 C11 和 C++17 的编译器以及 SDL3。如果未安装
SDL3,CMake 会自动下载并构建它。项目中唯一的 C++ 代码是用于
包装 ymfm 的封装器,用于合成 AdLib 的 YM3812 音效。
```
git clone --recurse-submodules https://github.com/digows/cosmo.git
cd cosmo
cmake --preset default
cmake --build --preset default
ctest --preset default
```
**macOS** —— 使用 `brew install cmake sdl3`。这也是该移植版进行开发和测试的平台。
**Linux** —— 使用你系统发行版自带的 SDL3,或让 CMake 自动获取。
构建依赖项已在 [CI workflow](.github/workflows/ci.yml) 中列出。
**Windows** —— 使用 MinGW,可以通过 MSYS2 原生运行,或使用
[toolchain file](cmake/toolchain-mingw64.cmake) 进行交叉编译。目前尚未对 MSVC 进行过测试。
构建通用的 macOS 二进制文件时,由于 Homebrew 提供的软件包是单架构的,因此需要从源码为两种架构分别构建 SDL:
```
cmake --preset macos-universal && cmake --build --preset macos-universal
```
`-DCOSMO_BUNDLE=ON` 构建的是发布版所提供的内容,而非终端
程序:在 macOS 上会生成带图标的 `Cosmo.app`,在 Windows 上则会带有图标、隐藏控制台
窗口,并将 MinGW 运行时直接链接进去,而不是依赖于必须随程序一起携带的三个 DLL 文件。
### 无需消耗 CI 资源即可检查其他平台
提供了两套容器方案,可在任何装有
Docker 的机器上复现 Linux 和 Windows 的构建任务,这比从失败的流水线中发现问题更快捷,成本也更低:
```
docker build -f tools/checks/linux.Dockerfile .
docker build -f tools/checks/windows-mingw.Dockerfile .
```
第一个方案使用了与 CI 任务相同的发行版和包列表。第二个方案
使用 MinGW-w64 进行交叉编译,这也是 Windows 任务使用的编译器系列。
这两套方案都曾在代码推送到 CI 运行器之前发现过真实的缺陷。
## 游戏数据
游戏素材版权归 Apogee Software 所有,**不**包含在此仓库中。
发布的下载包中包含了 Apogee 免费分发的 Episode 1;如果你从源码构建,则需要手动将其放置到位。
程序会按以下顺序查找 `COSMO1.STN` 和 `COSMO1.VOL`:程序所在目录、macOS 应用程序包内部,以及游戏启动时的目录。
程序会使用最先找到的文件,如果该位置支持写入,存档文件也会保存在那里——因此解压后的文件夹可以自带数据。获取数据的途径及校验和请参见
[gamedata/README.md](gamedata/README.md)。
如果已存在 `COSMOn.CFG` 文件,它的优先级将高于本移植版的默认设置,
包括跳跃键——原版发行时自带了 ctrl 键设置。
删除该文件即可恢复默认设置,或在游戏中重新绑定按键。
## 运行
```
./build/default/cosmo
```
放置一分钟不动,游戏会自动播放吸引模式演示。
`cosmo` 是一个启动器:它会列出各章节,
标记出缺失数据的章节,并提供文件选择器来补充数据——而且列表使用游戏自带的字体绘制在游戏原始的标题背景上,通过同一套模拟的
EGA 显示。你可以直接指定章节名称以跳过菜单:
```
./build/default/cosmo 2
```
三个章节是独立的程序——`cosmo1`、`cosmo2`、`cosmo3`——这
并不是出于打包的考虑。它们通过预处理器条件指令包含或排除完整的角色实现,因此编译出的代码确实有所不同。出于同样的原因,Apogee 当年也发行了三个独立的可执行文件。
`imgview` 是一个独立用于测试视频层的工具,可方便地在未启动游戏的情况下检查全屏图像:
```
./build/default/imgview # browse them
./build/default/imgview gamedata TITLE1.MNI shot.png 2 # headless screenshot
```
## 操作说明
方向键移动,**Space** 跳跃,**Alt** 投掷炸弹。
原版游戏默认使用 ctrl 键跳跃,这在 1992 年很常见;而时至今日,空格键长期以来一直是平台跳跃类游戏的惯例,同时也是不会引起窗口管理器冲突的按键绑定。这是该移植版对游戏行为做出的唯一刻意更改——参见 [patches/0007](patches/)。炸弹按键未作更改。
这六个按键均可在游戏自带的主菜单中进行重新绑定:在主菜单选择 **G** 进入 Game Redefine,然后按 **K** 进行 Keyboard redefine。该选择将与音效设置和最高分一起写入
`COSMOn.CFG` 文件中,从而在多次运行间得以保留——但这仅在游戏正常退出时有效。请通过游戏菜单退出(按 **Q**,然后按 **Y**),而不要直接关闭窗口,这与 DOS 系统上的情况完全一致,在 DOS 中强制结束程序同样会导致该文件丢失。
在 macOS 上,Command 键会被识别为 Control。如果你将跳跃键重新绑定回
ctrl,这一点就很重要:macOS 默认会将 Control 与任意方向键组合用于触发 Mission Control,因此 ctrl 加方向键的输入根本不会传达给应用程序。Command 键未被系统占用,因此可以用来填补这一空缺。
## 工作原理
主线程扮演 PC 硬件的角色,而第二个线程扮演
CPU 的角色。Cosmo 的主循环从不主动让出控制权:它不断忙等一个由自身定时器中断递增的计数器,并读取由自身键盘中断填充的键盘状态。在真实硬件上,这些中断处理程序会在程序运行时于后台触发,因此在这里,主线程会按照游戏写入
PIT 的频率(140 Hz,开启音乐时为 560 Hz)触发这些中断,同时游戏在另一侧正常运行。
原版游戏通过 I/O 端口对 EGA 进行编程,并将数据写入段地址 0xA000 的视频内存中。该移植版并未重写绘图代码,而是模拟了
适配器:在普通内存中划出四个 64 KiB 的平面,并实现了游戏所依赖的写入模式、锁存器、
位掩码和置位/复位逻辑。
这种精确度非常重要。`DrawSolidTile` 在写入模式 1 下使用 `*dst = *src` 将场景从视频内存复制到
视频内存,此时 CPU 数据会被丢弃,真正送达屏幕的是由读取操作加载到锁存器中的内容。如果 EGA 模拟看起来正常,却跳过了锁存器操作,渲染出的将会是乱码。
本项目中完全避免了汇编代码。上游项目在 `C-DRAWING.md` 中发布了所有绘图例程的纯 C 实现,编写这些代码最初是出于好奇,因为它们在 286 处理器上运行得太慢了。但在现代 CPU 上,这种性能损耗可以忽略不计,并且使用纯 C 代码消除了对 Turbo Assembler 的依赖,毕竟 Borland 从未将其免费公开。
## 调试与自动化检查
`COSMO_SCRIPT` 指向一个包含定时按键事件的文件,从而可以在无人操作键盘的情况下驱动游戏。每行格式为
`<毫秒> <按键>`;具体示例请参见 [tests/scripts](tests/scripts/)。
| 变量 | 效果 |
|---|---|
| `COSMO_DEBUG=1` | 每秒输出一次定时器频率、中断发送情况,以及游戏自身的按键和命令状态 |
| `COSMO_SHOT_PATH=p COSMO_SHOT_MS=500,3000` | 在启动后的特定时间点自动截图。随时可按 `F12` 截图 |
| `COSMO_AUDIO_WAV=out.wav` | 录制音频硬件产生的所有声音。即使游戏被强制终止而非正常退出,文件头也能保持有效 |
| `COSMO_OPL_LOG=1` | 跟踪所有对 AdLib 寄存器的写入操作 |
| `COSMO_SCRIPT=file` | 回放定时的按键事件 |
正是借助这些工具,我们得以将音效与游戏自身的原始数据进行比对验证,并据此追踪到键盘输入 Bug 的根源在于窗口系统,而非模拟器本身。
## 目录结构
```
vendor/cosmore/ upstream submodule, pinned and never modified
vendor/ymfm/ YM3812 synthesiser, pinned and never modified
cmake/ source preparation, run at configure time
patches/ changes to upstream, one numbered patch each
include/cosmo/ platform layer headers
src/platform/ emulated EGA, video, audio, DOS runtime, hardware
src/launcher.c episode picker, drawn in the game's own font
tools/ validation harnesses and container checks
tests/ unit tests and input scripts
docs/ porting notes and screenshots
```
源码准备阶段对上游代码应用了三种机械转换:删除了在现代环境下没有等效替代的 Borland 头文件的 `#include` 行,注释掉了 16 位内联汇编代码,并将基础类型固定为其原始位宽——因为在 DOS 中 `unsigned int` 是 16 位的,而且游戏逻辑依赖于其溢出回绕特性。任何无法通过这些转换表达的内容,都以编号补丁的形式存放在
[`patches/`](patches/) 目录下,每个补丁都解释了对应的缺陷以及修改正确的理由。
所有这些操作均在 CMake 中而非 Shell 脚本中执行,因此在不同平台上的行为完全一致,并且每个补丁在应用前后都会进行指纹校验:如果某个补丁报告成功,但实际上没有做出任何更改,那么它将导致 configure 步骤失败,而不是静默地什么都不做。这并非假设性的场景——这种情况真实发生过,并在
[the notes](docs/porting-notes.md) 中有相关描述。
## 许可证与致谢
本仓库中的代码遵循 MIT 许可证,详见 [LICENSE](LICENSE)。
*Cosmo's Cosmic Adventure* 及其素材和商标版权归 © 1992 Apogee
Software, Ltd. 所有,本仓库不对其进行再分发。more 遵循 MIT 许可证,© Scott Smitelli
及贡献者所有;ymfm 遵循 BSD 3-Clause 许可证,© Aaron Giles 所有。完整的致谢名单(包括游戏的原始作者)请参见 [ATTRIBUTION.md](ATTRIBUTION.md)。
标签:Bash脚本, Gophish, 复古游戏, 客户端加密, 开源游戏, 游戏源码移植, 请求拦截