mtrevival 0.3.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mtrevival-0.3.1/LICENSE +21 -0
- mtrevival-0.3.1/PKG-INFO +235 -0
- mtrevival-0.3.1/README.md +213 -0
- mtrevival-0.3.1/pyproject.toml +42 -0
- mtrevival-0.3.1/setup.cfg +4 -0
- mtrevival-0.3.1/src/mtrevival/__init__.py +3 -0
- mtrevival-0.3.1/src/mtrevival/__main__.py +95 -0
- mtrevival-0.3.1/src/mtrevival/bin/wmsource-shim.dll +0 -0
- mtrevival-0.3.1/src/mtrevival/d3denum.py +114 -0
- mtrevival-0.3.1/src/mtrevival/displays.py +115 -0
- mtrevival-0.3.1/src/mtrevival/fixpack.py +316 -0
- mtrevival-0.3.1/src/mtrevival/gameconfig.py +97 -0
- mtrevival-0.3.1/src/mtrevival/music.py +142 -0
- mtrevival-0.3.1/src/mtrevival.egg-info/PKG-INFO +235 -0
- mtrevival-0.3.1/src/mtrevival.egg-info/SOURCES.txt +21 -0
- mtrevival-0.3.1/src/mtrevival.egg-info/dependency_links.txt +1 -0
- mtrevival-0.3.1/src/mtrevival.egg-info/entry_points.txt +2 -0
- mtrevival-0.3.1/src/mtrevival.egg-info/top_level.txt +1 -0
- mtrevival-0.3.1/tests/test_cli.py +121 -0
- mtrevival-0.3.1/tests/test_d3denum.py +104 -0
- mtrevival-0.3.1/tests/test_fixpack.py +311 -0
- mtrevival-0.3.1/tests/test_gameconfig.py +156 -0
- mtrevival-0.3.1/tests/test_music.py +143 -0
mtrevival-0.3.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nasser Albusaidi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
mtrevival-0.3.1/PKG-INFO
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mtrevival
|
|
3
|
+
Version: 0.3.1
|
|
4
|
+
Summary: Make Monopoly Tycoon (2001) run on modern Windows
|
|
5
|
+
Author: Nasser Albusaidi
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/NasserAlbusaidi/monopoly-tycoon-revival
|
|
8
|
+
Project-URL: Issues, https://github.com/NasserAlbusaidi/monopoly-tycoon-revival/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/NasserAlbusaidi/monopoly-tycoon-revival/blob/main/CHANGELOG.md
|
|
10
|
+
Keywords: monopoly-tycoon,game-preservation,windows,directshow
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
16
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
+
Classifier: Topic :: Games/Entertainment
|
|
18
|
+
Requires-Python: >=3.12
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
|
|
23
|
+
# Monopoly Tycoon Revival
|
|
24
|
+
|
|
25
|
+
Make **Monopoly Tycoon** (2001, Deep Red Games / Infogrames) install and run on
|
|
26
|
+
Windows 10 and 11.
|
|
27
|
+
|
|
28
|
+
The game installs fine on modern Windows and then crashes on startup — usually
|
|
29
|
+
right after the studio logo, sometimes before anything appears. There are two
|
|
30
|
+
separate causes, both fixable in about a minute. No patched executable, no
|
|
31
|
+
compatibility mode. The soundtrack needs one small COM shim registered for
|
|
32
|
+
your user account; everything else is a text file.
|
|
33
|
+
|
|
34
|
+
**This repository contains no game content.** You need your own copy of the game.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Quick fix, by hand
|
|
39
|
+
|
|
40
|
+
### 1. Let the game write to its own folder
|
|
41
|
+
|
|
42
|
+
The game stores settings, profiles and savegames next to `mc.exe`. Under
|
|
43
|
+
`C:\Program Files (x86)` a standard user account cannot write there, so the game
|
|
44
|
+
silently fails to save anything — including the settings that fix the crash.
|
|
45
|
+
|
|
46
|
+
Run once in an **elevated** PowerShell:
|
|
47
|
+
|
|
48
|
+
```powershell
|
|
49
|
+
icacls "C:\Program Files (x86)\Infogrames\Monopoly Tycoon" /grant "$($env:USERNAME):(OI)(CI)M" /T
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 2. Create `config.cfg`
|
|
53
|
+
|
|
54
|
+
In the game folder, create a file named `config.cfg`:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
SysSetup api D3D
|
|
58
|
+
SysSetup device 1
|
|
59
|
+
SysSetup width 640
|
|
60
|
+
SysSetup height 480
|
|
61
|
+
SysSetup bitdepth 32
|
|
62
|
+
SysSetup texbitdepth 16
|
|
63
|
+
SysSetup music 1
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**`device` is the display adapter index and is specific to your machine.** Use
|
|
67
|
+
`0` if your primary display is a normal landscape monitor. Use `1` (or higher)
|
|
68
|
+
if your primary display is rotated to portrait, or does not offer a 640×480
|
|
69
|
+
mode. The tool below works this out for you.
|
|
70
|
+
|
|
71
|
+
`music 1` means music **off**. That is the safe setting without the shim
|
|
72
|
+
described under [Music](#music); the game runs, silently.
|
|
73
|
+
|
|
74
|
+
That is the whole fix. Launch `mc.exe`.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Working it out automatically
|
|
79
|
+
|
|
80
|
+
Requires Python 3.12 or newer. Standard library only.
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
py -m pip install mtrevival # or: pipx install mtrevival
|
|
84
|
+
mtrevival adapters # list adapters, show which support 640x480
|
|
85
|
+
mtrevival check # show what would be written, change nothing
|
|
86
|
+
mtrevival fix # write config.cfg, backing up any existing one
|
|
87
|
+
|
|
88
|
+
mtrevival fix --resolution 1920x1080 # any mode the adapter lists
|
|
89
|
+
mtrevival fix --resolution 1280x720 --windowed # windowed needs patch 1.2
|
|
90
|
+
mtrevival fix --music # restore the soundtrack
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`py -m mtrevival …` works too. From a git checkout use `py -m pip install .`;
|
|
94
|
+
the music shim then needs building (see `CONTRIBUTING.md`) or the DLL from a
|
|
95
|
+
[release](https://github.com/NasserAlbusaidi/monopoly-tycoon-revival/releases).
|
|
96
|
+
|
|
97
|
+
Example on a machine with a portrait primary display:
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
source: D3DEnum.txt
|
|
101
|
+
adapter 0 NVIDIA GeForce RTX 4080 modes=46 no 640x480 [portrait]
|
|
102
|
+
adapter 1 NVIDIA GeForce RTX 4080 modes=54 OK 640x480
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`fix` never overwrites an existing `config.cfg` without copying it to a
|
|
106
|
+
timestamped `.bak` first.
|
|
107
|
+
|
|
108
|
+
### Music
|
|
109
|
+
|
|
110
|
+
The game plays its WMA soundtrack through a DirectShow filter that Windows
|
|
111
|
+
dropped years ago. `fix --music` copies `wmsource-shim.dll` (built from
|
|
112
|
+
[`tools/wmsource-shim`](tools/wmsource-shim), source included) next to
|
|
113
|
+
`mc.exe`, registers it **for your user only** — no elevation, nothing outside
|
|
114
|
+
your profile — and writes `music 0`. The shim hands the game Windows' own
|
|
115
|
+
WM ASF Reader with the two adaptations the game needs. Details, evidence and
|
|
116
|
+
removal in [`docs/music.md`](docs/music.md).
|
|
117
|
+
|
|
118
|
+
Do not run the game "as administrator" with music on: an elevated process
|
|
119
|
+
cannot see per-user COM registrations. `fix --music` warns if that flag is set.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## What actually goes wrong
|
|
124
|
+
|
|
125
|
+
Both crashes are the same defect: the game creates an object, never checks
|
|
126
|
+
whether creation succeeded, and then dereferences the null pointer.
|
|
127
|
+
|
|
128
|
+
### Crash 1 — access violation at `mc.exe+0x000E792E`
|
|
129
|
+
|
|
130
|
+
Windows logs exception `0xC0000005`, fault offset `0x000E792E`, faulting module
|
|
131
|
+
`mc.exe`. The instruction is:
|
|
132
|
+
|
|
133
|
+
```asm
|
|
134
|
+
004E78FE call dword ptr [edx+0x3C] ; IDirect3D8::CreateDevice (vtable slot 15)
|
|
135
|
+
004E7901 mov eax, [ebp+0x44] ; ...continues without checking the HRESULT
|
|
136
|
+
004E792E mov ecx, [eax] ; <-- faults, EAX = 0
|
|
137
|
+
004E7932 call dword ptr [ecx+0xA0] ; IDirect3DDevice8::SetViewport (slot 40)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
The game requests **640×480 exclusive fullscreen** on adapter 0. Recovered
|
|
141
|
+
`D3DPRESENT_PARAMETERS` from a crash dump:
|
|
142
|
+
|
|
143
|
+
| Field | Value |
|
|
144
|
+
|---|---|
|
|
145
|
+
| BackBufferWidth / Height | 640 × 480 |
|
|
146
|
+
| BackBufferFormat | 22 (`D3DFMT_X8R8G8B8`) |
|
|
147
|
+
| Windowed | 0 — exclusive fullscreen |
|
|
148
|
+
| returned device | **NULL** |
|
|
149
|
+
|
|
150
|
+
For exclusive fullscreen, Direct3D 8 requires the width, height and format to
|
|
151
|
+
match an enumerated display mode. If your primary display is rotated to
|
|
152
|
+
portrait, its mode list contains `480 X 640` and **no** `640 X 480`.
|
|
153
|
+
`CreateDevice` fails, and the unchecked null device is dereferenced by
|
|
154
|
+
`SetViewport`.
|
|
155
|
+
|
|
156
|
+
The game writes its own evidence to `D3DEnum.txt` in the install folder. Look for
|
|
157
|
+
an adapter whose modes are all taller than they are wide — that is the culprit.
|
|
158
|
+
|
|
159
|
+
**Fix:** point `SysSetup device` at an adapter that offers 640×480.
|
|
160
|
+
|
|
161
|
+
### Crash 2 — access violation at `mc.exe+0x000A801B`
|
|
162
|
+
|
|
163
|
+
```asm
|
|
164
|
+
004A8007 call dword ptr [0x96E4E8] ; MultiByteToWideChar -> filename
|
|
165
|
+
004A800D mov eax, [ebx+0x2CE8] ; media interface -> NULL
|
|
166
|
+
004A801B mov edx, [eax] ; <-- faults, EAX = 0
|
|
167
|
+
004A801E call dword ptr [edx+0xC]
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
The filename recovered from the dump is
|
|
171
|
+
`gamedata\sound\music\music_intro.wma`. The game builds a DirectShow graph to
|
|
172
|
+
play its WMA soundtrack and asks for the 2001 Windows Media DirectShow source
|
|
173
|
+
filter by CLSID. Windows 11 keeps only a 5 KB stub of `dxmasf.dll` and no
|
|
174
|
+
longer registers the class, so `CoCreateInstance` fails. `quartz.dll` and
|
|
175
|
+
`devenum.dll` load; the Windows Media source does not. The interface comes
|
|
176
|
+
back null and is used anyway.
|
|
177
|
+
|
|
178
|
+
**Fix:** `SysSetup music 1` suppresses that path, and the game runs without
|
|
179
|
+
its music. `fix --music` restores it: the filter the game asks for,
|
|
180
|
+
`{6B6D0800-…}`, is answered by a shim that wraps Windows' WM ASF Reader,
|
|
181
|
+
creating a fresh reader per track (the reader refuses a second `Load`) and
|
|
182
|
+
mapping the game's `FindPin(L"Stream 1")` onto the reader's `Raw Audio 0`.
|
|
183
|
+
The 2001 Windows Media redistributable on the CD is not touched. See
|
|
184
|
+
[`docs/music.md`](docs/music.md).
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Compatibility notes
|
|
189
|
+
|
|
190
|
+
- Tested on Windows 11 Pro (build 26200), NVIDIA RTX 4080, English CD.
|
|
191
|
+
Verified with game version 1.0 and again after applying the official patch
|
|
192
|
+
1.2 — the same `config.cfg` works for both. Verified on one machine only.
|
|
193
|
+
- Patch 1.2 applies cleanly on Windows 11 when run **elevated**. It changes
|
|
194
|
+
`mc.exe`, three Lua scripts and the string tables, and leaves `config.cfg`
|
|
195
|
+
alone. Both crashes above are still present in the 1.2 executable. Details
|
|
196
|
+
in [`docs/patch-1.2.md`](docs/patch-1.2.md).
|
|
197
|
+
- Resolution is free. `SysSetup width` / `height` accept any mode the chosen
|
|
198
|
+
adapter enumerates; 1920×1080 exclusive fullscreen and 1280×720 windowed
|
|
199
|
+
(`SysSetup Window 1`, patch 1.2 only) were verified running with a sane UI.
|
|
200
|
+
The 1.0 key `windowed` is ignored; 1.2 renamed it.
|
|
201
|
+
- Music was verified on patch 1.2 (intro track by ear, all ten tracks and
|
|
202
|
+
repeated track changes in a DirectShow harness). It needs Windows Media,
|
|
203
|
+
which N editions get from the Media Feature Pack.
|
|
204
|
+
- Patch 1.2 drops an empty `MTS.txt` in the game folder while it runs and
|
|
205
|
+
removes it on exit. If the game is killed, delete that file, or the next
|
|
206
|
+
launch offers Safe Mode and overwrites `config.cfg`.
|
|
207
|
+
- GameSpy multiplayer is dead and out of scope.
|
|
208
|
+
|
|
209
|
+
## Modding
|
|
210
|
+
|
|
211
|
+
The game is unusually open for its age, and this is the reason the project
|
|
212
|
+
exists. All verified:
|
|
213
|
+
|
|
214
|
+
- **200 plain-text Lua scripts** in `scripts\`, across 56 namespaces —
|
|
215
|
+
`DEFAULT`, `MAPS`, `SCENARIO1`–`SCENARIO20`, `TUTORIAL1`–`TUTORIAL12`,
|
|
216
|
+
`NET0`–`NET8`. Economy tuning lives in `businesssettings.lua`,
|
|
217
|
+
`blocksettings.lua` and `commoditysettings.lua`.
|
|
218
|
+
- **Saves are Lua too.** `profiles\<name>\settings.lua` contains
|
|
219
|
+
`g_ProfileOptions.BoardName = "gb"`, which selects among **19 national
|
|
220
|
+
boards** shipped on the disc (`usa`, `f`, `ger`, `aus`, `swe`, and more).
|
|
221
|
+
- `parameters\*.prm` holds per-decade tuning, plus `aiparameter.prm` and
|
|
222
|
+
`consumer.prm`.
|
|
223
|
+
- The shipped executable still contains debug flags (`AIDEBUG`, `DEBUGTEXT`,
|
|
224
|
+
`SHOWALLCARS`, `CHEATINGGIT`) and remnants of the developers' block and
|
|
225
|
+
building editors.
|
|
226
|
+
|
|
227
|
+
See [`docs/phase-0-findings.md`](docs/phase-0-findings.md) for the full
|
|
228
|
+
investigation, and
|
|
229
|
+
[`docs/superpowers/specs/`](docs/superpowers/specs/) for the project design.
|
|
230
|
+
|
|
231
|
+
## Licence
|
|
232
|
+
|
|
233
|
+
MIT — see [LICENSE](LICENSE). This covers the tools and documentation in this
|
|
234
|
+
repository only. Monopoly Tycoon itself is the property of its rights holders
|
|
235
|
+
and is not distributed here.
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# Monopoly Tycoon Revival
|
|
2
|
+
|
|
3
|
+
Make **Monopoly Tycoon** (2001, Deep Red Games / Infogrames) install and run on
|
|
4
|
+
Windows 10 and 11.
|
|
5
|
+
|
|
6
|
+
The game installs fine on modern Windows and then crashes on startup — usually
|
|
7
|
+
right after the studio logo, sometimes before anything appears. There are two
|
|
8
|
+
separate causes, both fixable in about a minute. No patched executable, no
|
|
9
|
+
compatibility mode. The soundtrack needs one small COM shim registered for
|
|
10
|
+
your user account; everything else is a text file.
|
|
11
|
+
|
|
12
|
+
**This repository contains no game content.** You need your own copy of the game.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Quick fix, by hand
|
|
17
|
+
|
|
18
|
+
### 1. Let the game write to its own folder
|
|
19
|
+
|
|
20
|
+
The game stores settings, profiles and savegames next to `mc.exe`. Under
|
|
21
|
+
`C:\Program Files (x86)` a standard user account cannot write there, so the game
|
|
22
|
+
silently fails to save anything — including the settings that fix the crash.
|
|
23
|
+
|
|
24
|
+
Run once in an **elevated** PowerShell:
|
|
25
|
+
|
|
26
|
+
```powershell
|
|
27
|
+
icacls "C:\Program Files (x86)\Infogrames\Monopoly Tycoon" /grant "$($env:USERNAME):(OI)(CI)M" /T
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### 2. Create `config.cfg`
|
|
31
|
+
|
|
32
|
+
In the game folder, create a file named `config.cfg`:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
SysSetup api D3D
|
|
36
|
+
SysSetup device 1
|
|
37
|
+
SysSetup width 640
|
|
38
|
+
SysSetup height 480
|
|
39
|
+
SysSetup bitdepth 32
|
|
40
|
+
SysSetup texbitdepth 16
|
|
41
|
+
SysSetup music 1
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**`device` is the display adapter index and is specific to your machine.** Use
|
|
45
|
+
`0` if your primary display is a normal landscape monitor. Use `1` (or higher)
|
|
46
|
+
if your primary display is rotated to portrait, or does not offer a 640×480
|
|
47
|
+
mode. The tool below works this out for you.
|
|
48
|
+
|
|
49
|
+
`music 1` means music **off**. That is the safe setting without the shim
|
|
50
|
+
described under [Music](#music); the game runs, silently.
|
|
51
|
+
|
|
52
|
+
That is the whole fix. Launch `mc.exe`.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Working it out automatically
|
|
57
|
+
|
|
58
|
+
Requires Python 3.12 or newer. Standard library only.
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
py -m pip install mtrevival # or: pipx install mtrevival
|
|
62
|
+
mtrevival adapters # list adapters, show which support 640x480
|
|
63
|
+
mtrevival check # show what would be written, change nothing
|
|
64
|
+
mtrevival fix # write config.cfg, backing up any existing one
|
|
65
|
+
|
|
66
|
+
mtrevival fix --resolution 1920x1080 # any mode the adapter lists
|
|
67
|
+
mtrevival fix --resolution 1280x720 --windowed # windowed needs patch 1.2
|
|
68
|
+
mtrevival fix --music # restore the soundtrack
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`py -m mtrevival …` works too. From a git checkout use `py -m pip install .`;
|
|
72
|
+
the music shim then needs building (see `CONTRIBUTING.md`) or the DLL from a
|
|
73
|
+
[release](https://github.com/NasserAlbusaidi/monopoly-tycoon-revival/releases).
|
|
74
|
+
|
|
75
|
+
Example on a machine with a portrait primary display:
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
source: D3DEnum.txt
|
|
79
|
+
adapter 0 NVIDIA GeForce RTX 4080 modes=46 no 640x480 [portrait]
|
|
80
|
+
adapter 1 NVIDIA GeForce RTX 4080 modes=54 OK 640x480
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`fix` never overwrites an existing `config.cfg` without copying it to a
|
|
84
|
+
timestamped `.bak` first.
|
|
85
|
+
|
|
86
|
+
### Music
|
|
87
|
+
|
|
88
|
+
The game plays its WMA soundtrack through a DirectShow filter that Windows
|
|
89
|
+
dropped years ago. `fix --music` copies `wmsource-shim.dll` (built from
|
|
90
|
+
[`tools/wmsource-shim`](tools/wmsource-shim), source included) next to
|
|
91
|
+
`mc.exe`, registers it **for your user only** — no elevation, nothing outside
|
|
92
|
+
your profile — and writes `music 0`. The shim hands the game Windows' own
|
|
93
|
+
WM ASF Reader with the two adaptations the game needs. Details, evidence and
|
|
94
|
+
removal in [`docs/music.md`](docs/music.md).
|
|
95
|
+
|
|
96
|
+
Do not run the game "as administrator" with music on: an elevated process
|
|
97
|
+
cannot see per-user COM registrations. `fix --music` warns if that flag is set.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## What actually goes wrong
|
|
102
|
+
|
|
103
|
+
Both crashes are the same defect: the game creates an object, never checks
|
|
104
|
+
whether creation succeeded, and then dereferences the null pointer.
|
|
105
|
+
|
|
106
|
+
### Crash 1 — access violation at `mc.exe+0x000E792E`
|
|
107
|
+
|
|
108
|
+
Windows logs exception `0xC0000005`, fault offset `0x000E792E`, faulting module
|
|
109
|
+
`mc.exe`. The instruction is:
|
|
110
|
+
|
|
111
|
+
```asm
|
|
112
|
+
004E78FE call dword ptr [edx+0x3C] ; IDirect3D8::CreateDevice (vtable slot 15)
|
|
113
|
+
004E7901 mov eax, [ebp+0x44] ; ...continues without checking the HRESULT
|
|
114
|
+
004E792E mov ecx, [eax] ; <-- faults, EAX = 0
|
|
115
|
+
004E7932 call dword ptr [ecx+0xA0] ; IDirect3DDevice8::SetViewport (slot 40)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The game requests **640×480 exclusive fullscreen** on adapter 0. Recovered
|
|
119
|
+
`D3DPRESENT_PARAMETERS` from a crash dump:
|
|
120
|
+
|
|
121
|
+
| Field | Value |
|
|
122
|
+
|---|---|
|
|
123
|
+
| BackBufferWidth / Height | 640 × 480 |
|
|
124
|
+
| BackBufferFormat | 22 (`D3DFMT_X8R8G8B8`) |
|
|
125
|
+
| Windowed | 0 — exclusive fullscreen |
|
|
126
|
+
| returned device | **NULL** |
|
|
127
|
+
|
|
128
|
+
For exclusive fullscreen, Direct3D 8 requires the width, height and format to
|
|
129
|
+
match an enumerated display mode. If your primary display is rotated to
|
|
130
|
+
portrait, its mode list contains `480 X 640` and **no** `640 X 480`.
|
|
131
|
+
`CreateDevice` fails, and the unchecked null device is dereferenced by
|
|
132
|
+
`SetViewport`.
|
|
133
|
+
|
|
134
|
+
The game writes its own evidence to `D3DEnum.txt` in the install folder. Look for
|
|
135
|
+
an adapter whose modes are all taller than they are wide — that is the culprit.
|
|
136
|
+
|
|
137
|
+
**Fix:** point `SysSetup device` at an adapter that offers 640×480.
|
|
138
|
+
|
|
139
|
+
### Crash 2 — access violation at `mc.exe+0x000A801B`
|
|
140
|
+
|
|
141
|
+
```asm
|
|
142
|
+
004A8007 call dword ptr [0x96E4E8] ; MultiByteToWideChar -> filename
|
|
143
|
+
004A800D mov eax, [ebx+0x2CE8] ; media interface -> NULL
|
|
144
|
+
004A801B mov edx, [eax] ; <-- faults, EAX = 0
|
|
145
|
+
004A801E call dword ptr [edx+0xC]
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
The filename recovered from the dump is
|
|
149
|
+
`gamedata\sound\music\music_intro.wma`. The game builds a DirectShow graph to
|
|
150
|
+
play its WMA soundtrack and asks for the 2001 Windows Media DirectShow source
|
|
151
|
+
filter by CLSID. Windows 11 keeps only a 5 KB stub of `dxmasf.dll` and no
|
|
152
|
+
longer registers the class, so `CoCreateInstance` fails. `quartz.dll` and
|
|
153
|
+
`devenum.dll` load; the Windows Media source does not. The interface comes
|
|
154
|
+
back null and is used anyway.
|
|
155
|
+
|
|
156
|
+
**Fix:** `SysSetup music 1` suppresses that path, and the game runs without
|
|
157
|
+
its music. `fix --music` restores it: the filter the game asks for,
|
|
158
|
+
`{6B6D0800-…}`, is answered by a shim that wraps Windows' WM ASF Reader,
|
|
159
|
+
creating a fresh reader per track (the reader refuses a second `Load`) and
|
|
160
|
+
mapping the game's `FindPin(L"Stream 1")` onto the reader's `Raw Audio 0`.
|
|
161
|
+
The 2001 Windows Media redistributable on the CD is not touched. See
|
|
162
|
+
[`docs/music.md`](docs/music.md).
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## Compatibility notes
|
|
167
|
+
|
|
168
|
+
- Tested on Windows 11 Pro (build 26200), NVIDIA RTX 4080, English CD.
|
|
169
|
+
Verified with game version 1.0 and again after applying the official patch
|
|
170
|
+
1.2 — the same `config.cfg` works for both. Verified on one machine only.
|
|
171
|
+
- Patch 1.2 applies cleanly on Windows 11 when run **elevated**. It changes
|
|
172
|
+
`mc.exe`, three Lua scripts and the string tables, and leaves `config.cfg`
|
|
173
|
+
alone. Both crashes above are still present in the 1.2 executable. Details
|
|
174
|
+
in [`docs/patch-1.2.md`](docs/patch-1.2.md).
|
|
175
|
+
- Resolution is free. `SysSetup width` / `height` accept any mode the chosen
|
|
176
|
+
adapter enumerates; 1920×1080 exclusive fullscreen and 1280×720 windowed
|
|
177
|
+
(`SysSetup Window 1`, patch 1.2 only) were verified running with a sane UI.
|
|
178
|
+
The 1.0 key `windowed` is ignored; 1.2 renamed it.
|
|
179
|
+
- Music was verified on patch 1.2 (intro track by ear, all ten tracks and
|
|
180
|
+
repeated track changes in a DirectShow harness). It needs Windows Media,
|
|
181
|
+
which N editions get from the Media Feature Pack.
|
|
182
|
+
- Patch 1.2 drops an empty `MTS.txt` in the game folder while it runs and
|
|
183
|
+
removes it on exit. If the game is killed, delete that file, or the next
|
|
184
|
+
launch offers Safe Mode and overwrites `config.cfg`.
|
|
185
|
+
- GameSpy multiplayer is dead and out of scope.
|
|
186
|
+
|
|
187
|
+
## Modding
|
|
188
|
+
|
|
189
|
+
The game is unusually open for its age, and this is the reason the project
|
|
190
|
+
exists. All verified:
|
|
191
|
+
|
|
192
|
+
- **200 plain-text Lua scripts** in `scripts\`, across 56 namespaces —
|
|
193
|
+
`DEFAULT`, `MAPS`, `SCENARIO1`–`SCENARIO20`, `TUTORIAL1`–`TUTORIAL12`,
|
|
194
|
+
`NET0`–`NET8`. Economy tuning lives in `businesssettings.lua`,
|
|
195
|
+
`blocksettings.lua` and `commoditysettings.lua`.
|
|
196
|
+
- **Saves are Lua too.** `profiles\<name>\settings.lua` contains
|
|
197
|
+
`g_ProfileOptions.BoardName = "gb"`, which selects among **19 national
|
|
198
|
+
boards** shipped on the disc (`usa`, `f`, `ger`, `aus`, `swe`, and more).
|
|
199
|
+
- `parameters\*.prm` holds per-decade tuning, plus `aiparameter.prm` and
|
|
200
|
+
`consumer.prm`.
|
|
201
|
+
- The shipped executable still contains debug flags (`AIDEBUG`, `DEBUGTEXT`,
|
|
202
|
+
`SHOWALLCARS`, `CHEATINGGIT`) and remnants of the developers' block and
|
|
203
|
+
building editors.
|
|
204
|
+
|
|
205
|
+
See [`docs/phase-0-findings.md`](docs/phase-0-findings.md) for the full
|
|
206
|
+
investigation, and
|
|
207
|
+
[`docs/superpowers/specs/`](docs/superpowers/specs/) for the project design.
|
|
208
|
+
|
|
209
|
+
## Licence
|
|
210
|
+
|
|
211
|
+
MIT — see [LICENSE](LICENSE). This covers the tools and documentation in this
|
|
212
|
+
repository only. Monopoly Tycoon itself is the property of its rights holders
|
|
213
|
+
and is not distributed here.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "mtrevival"
|
|
3
|
+
version = "0.3.1"
|
|
4
|
+
description = "Make Monopoly Tycoon (2001) run on modern Windows"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = {text = "MIT"}
|
|
7
|
+
authors = [{name = "Nasser Albusaidi"}]
|
|
8
|
+
requires-python = ">=3.12"
|
|
9
|
+
dependencies = []
|
|
10
|
+
keywords = ["monopoly-tycoon", "game-preservation", "windows", "directshow"]
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Development Status :: 4 - Beta",
|
|
13
|
+
"Environment :: Console",
|
|
14
|
+
"Intended Audience :: End Users/Desktop",
|
|
15
|
+
"License :: OSI Approved :: MIT License",
|
|
16
|
+
"Operating System :: Microsoft :: Windows",
|
|
17
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
18
|
+
"Topic :: Games/Entertainment",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[project.urls]
|
|
22
|
+
Homepage = "https://github.com/NasserAlbusaidi/monopoly-tycoon-revival"
|
|
23
|
+
Issues = "https://github.com/NasserAlbusaidi/monopoly-tycoon-revival/issues"
|
|
24
|
+
Changelog = "https://github.com/NasserAlbusaidi/monopoly-tycoon-revival/blob/main/CHANGELOG.md"
|
|
25
|
+
|
|
26
|
+
[project.scripts]
|
|
27
|
+
mtrevival = "mtrevival.__main__:main"
|
|
28
|
+
|
|
29
|
+
[build-system]
|
|
30
|
+
requires = ["setuptools>=68"]
|
|
31
|
+
build-backend = "setuptools.build_meta"
|
|
32
|
+
|
|
33
|
+
[tool.setuptools.packages.find]
|
|
34
|
+
where = ["src"]
|
|
35
|
+
|
|
36
|
+
[tool.setuptools.package-data]
|
|
37
|
+
# The music shim, built from tools/wmsource-shim by build.ps1.
|
|
38
|
+
mtrevival = ["bin/wmsource-shim.dll"]
|
|
39
|
+
|
|
40
|
+
[tool.pytest.ini_options]
|
|
41
|
+
testpaths = ["tests"]
|
|
42
|
+
pythonpath = ["src", "tests"]
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""Command line entry point: ``python -m mtrevival``."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import re
|
|
7
|
+
import sys
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from . import fixpack
|
|
11
|
+
|
|
12
|
+
_RESOLUTION = re.compile(r"^(\d{3,4})x(\d{3,4})$")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def resolution(text: str) -> tuple[int, int]:
|
|
16
|
+
"""argparse type for WIDTHxHEIGHT."""
|
|
17
|
+
m = _RESOLUTION.match(text.strip().lower())
|
|
18
|
+
if not m:
|
|
19
|
+
raise argparse.ArgumentTypeError(
|
|
20
|
+
"expected WIDTHxHEIGHT such as 1920x1080, got %r" % text)
|
|
21
|
+
return int(m.group(1)), int(m.group(2))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def main(argv: list[str] | None = None) -> int:
|
|
25
|
+
parser = argparse.ArgumentParser(
|
|
26
|
+
prog="mtrevival",
|
|
27
|
+
description="Make Monopoly Tycoon (2001) run on modern Windows.")
|
|
28
|
+
sub = parser.add_subparsers(dest="command", required=True)
|
|
29
|
+
|
|
30
|
+
def common(p: argparse.ArgumentParser) -> None:
|
|
31
|
+
p.add_argument("--game-dir", type=Path, default=None,
|
|
32
|
+
help="install directory containing mc.exe")
|
|
33
|
+
p.add_argument("--resolution", type=resolution,
|
|
34
|
+
default=(fixpack.DEFAULT_WIDTH, fixpack.DEFAULT_HEIGHT),
|
|
35
|
+
metavar="WxH",
|
|
36
|
+
help="display mode, default %dx%d; the adapter must list it"
|
|
37
|
+
% (fixpack.DEFAULT_WIDTH, fixpack.DEFAULT_HEIGHT))
|
|
38
|
+
|
|
39
|
+
for name, help_text in (("check", "report what would be done, change nothing"),
|
|
40
|
+
("fix", "write config.cfg with a working adapter")):
|
|
41
|
+
p = sub.add_parser(name, help=help_text)
|
|
42
|
+
common(p)
|
|
43
|
+
p.add_argument("--windowed", action="store_true",
|
|
44
|
+
help="run in a window instead of fullscreen (needs patch 1.2)")
|
|
45
|
+
p.add_argument("--music", action="store_true",
|
|
46
|
+
help="restore the soundtrack: install the wmsource-shim "
|
|
47
|
+
"for this user and write music 0")
|
|
48
|
+
common(sub.add_parser("adapters", help="list adapters and whether they fit"))
|
|
49
|
+
|
|
50
|
+
args = parser.parse_args(argv)
|
|
51
|
+
width, height = args.resolution
|
|
52
|
+
windowed = getattr(args, "windowed", False)
|
|
53
|
+
with_music = getattr(args, "music", False)
|
|
54
|
+
|
|
55
|
+
try:
|
|
56
|
+
game_dir = fixpack.find_install(args.game_dir)
|
|
57
|
+
except fixpack.FixError as error:
|
|
58
|
+
print("error: %s" % error, file=sys.stderr)
|
|
59
|
+
return 2
|
|
60
|
+
|
|
61
|
+
if args.command == "adapters":
|
|
62
|
+
adapters, source = fixpack.read_adapters(game_dir)
|
|
63
|
+
print("source: %s" % source)
|
|
64
|
+
for adapter in adapters:
|
|
65
|
+
fits = adapter.supports(width, height)
|
|
66
|
+
print(" adapter %d %-34s modes=%-4d %s%s"
|
|
67
|
+
% (adapter.index, adapter.description or "(unnamed)",
|
|
68
|
+
len(adapter.modes),
|
|
69
|
+
("OK %dx%d" if fits else "no %dx%d") % (width, height),
|
|
70
|
+
" [portrait]" if adapter.is_portrait else ""))
|
|
71
|
+
return 0
|
|
72
|
+
|
|
73
|
+
plan = fixpack.build_plan(game_dir, width, height, windowed, with_music)
|
|
74
|
+
print(fixpack.describe(plan))
|
|
75
|
+
|
|
76
|
+
if args.command == "check":
|
|
77
|
+
return 0 if plan.ok else 1
|
|
78
|
+
|
|
79
|
+
try:
|
|
80
|
+
backup = fixpack.apply(plan)
|
|
81
|
+
except fixpack.FixError as error:
|
|
82
|
+
print("\nerror: %s" % error, file=sys.stderr)
|
|
83
|
+
return 1
|
|
84
|
+
|
|
85
|
+
if plan.music:
|
|
86
|
+
print("\nInstalled %s and registered it for this user." % plan.shim_target)
|
|
87
|
+
print("\nWrote %s" % plan.config_path)
|
|
88
|
+
if backup:
|
|
89
|
+
print("Backed up previous config to %s" % backup)
|
|
90
|
+
print("Launch the game with mc.exe.")
|
|
91
|
+
return 0
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
if __name__ == "__main__":
|
|
95
|
+
sys.exit(main())
|
|
Binary file
|