script: marked all unsafe pointer operations with `cast([unsafe])`
[k8vavoom.git] / progs / common / engine / LevelMapFixer.vc
blob50468d5f0bbe5e466d72ae591ce57aa0c87c07a4
1 // texture use types
2 enum {
3   TEXTYPE_Any,
4   TEXTYPE_WallPatch,
5   TEXTYPE_Wall,
6   TEXTYPE_Flat,
7   TEXTYPE_Overload,
8   TEXTYPE_Sprite,
9   TEXTYPE_SkyMap,
10   TEXTYPE_Skin,
11   TEXTYPE_Pic,
12   TEXTYPE_Autopage,
13   TEXTYPE_Null,
14   TEXTYPE_FontChar,
18 //==========================================================================
20 //  LdrSectorOffsetFloor
22 //==========================================================================
23 private static final void LdrSectorOffsetFloor (ref sector_t sec, float ofs) {
24   sec.floor.TexZ += ofs;
25   sec.floor.minz += ofs;
26   sec.floor.maxz += ofs;
30 //==========================================================================
32 //  LdrSectorOffsetCeiling
34 //==========================================================================
35 private static final void LdrSectorOffsetCeiling (ref sector_t sec, float ofs) {
36   sec.ceiling.TexZ += ofs;
37   sec.ceiling.minz += ofs;
38   sec.ceiling.maxz += ofs;
42 //==========================================================================
44 //  KnownMapBugFixer
46 //  based on GZDoom code; tnx!
48 //==========================================================================
49 void KnownMapBugFixer () {
50   // Doom: E1M4
51   if (MapHashMD5 == "5b26545ff21b051ca06d389ce535684c") {
52     // missing textures
53     Sides[Lines[693].sidenum[1]].TopTexture = LdrTexNumForName("BROWN1", TEXTYPE_Wall);
54     // fix HOM errors with sectors too low
55     LdrSectorOffsetFloor(ref Sectors[9], 8);
56     LdrSectorOffsetFloor(ref Sectors[105], 8);
57     LdrSectorOffsetFloor(ref Sectors[132], 8);
58     LdrSectorOffsetFloor(ref Sectors[137], 8);
59     printwarn("MAPFIX: Doom: E1M4 detected and fixed");
60     return;
61   }
63   // Doom: E2M2
64   if (MapHashMD5 == "a24fe135d5b6fd427fe27bef89717a65") {
65     // missing textures
66     Sides[Lines[947].sidenum[1]].TopTexture = LdrTexNumForName("BROWN1", TEXTYPE_Wall);
67     Sides[Lines[1596].sidenum[1]].TopTexture = LdrTexNumForName("WOOD1", TEXTYPE_Wall);
68     printwarn("MAPFIX: Doom: E2M2 detected and fixed");
69     return;
70   }
72   // Doom: E2M4
73   if (MapHashMD5 == "1bc04d646b32d3a3e411daf3c1a38ff8") {
74     // missing textures
75     Sides[Lines[551].sidenum[1]].TopTexture = LdrTexNumForName("PIPE4", TEXTYPE_Wall);
76     Sides[Lines[865].sidenum[1]].BottomTexture = LdrTexNumForName("STEP5", TEXTYPE_Wall);
77     Sides[Lines[1062].sidenum[0]].TopTexture = LdrTexNumForName("GSTVINE1", TEXTYPE_Wall);
78     Sides[Lines[1071].sidenum[0]].TopTexture = LdrTexNumForName("MARBLE1", TEXTYPE_Wall);
79     printwarn("MAPFIX: Doom: E2M4 detected and fixed");
80     return;
81   }
83   // Doom: E2M5
84   if (MapHashMD5 == "99c580ad8fabe923cab485cb7f3c5e5d") {
85     // missing textures
86     Sides[Lines[590].sidenum[1]].TopTexture = LdrTexNumForName("GRAYBIG", TEXTYPE_Wall);
87     Sides[Lines[590].sidenum[0]].BottomTexture = LdrTexNumForName("BROWN1", TEXTYPE_Wall);
88     printwarn("MAPFIX: Doom: E2M5 detected and fixed");
89     return;
90   }
92   // Doom: E2M6
93   if (MapHashMD5 == "3838ab29292587a7ee3ca71e7040868d") {
94     // missing textures
95     Sides[Lines[1091].sidenum[1]].TopTexture = LdrTexNumForName("COMPSPAN", TEXTYPE_Wall);
96     printwarn("MAPFIX: Doom: E2M6 detected and fixed");
97     return;
98   }
100   // Doom: E2M7
101   if (MapHashMD5 == "8590f489879870c098cd7029c3187159") {
102     // missing textures
103     Sides[Lines[1286].sidenum[0]].BottomTexture = LdrTexNumForName("SHAWN2", TEXTYPE_Wall);
104     printwarn("MAPFIX: Doom: E2M7 detected and fixed");
105     return;
106   }
108   // Doom: E2M9
109   if (MapHashMD5 == "8a6399faaa2e68649d4e4b16642074be") {
110     // missing textures
111     Sides[Lines[121].sidenum[1]].TopTexture = LdrTexNumForName("SW1LION", TEXTYPE_Wall);
112     Sides[Lines[123].sidenum[1]].TopTexture = LdrTexNumForName("GSTONE1", TEXTYPE_Wall);
113     Sides[Lines[140].sidenum[1]].TopTexture = LdrTexNumForName("GSTONE1", TEXTYPE_Wall);
114     printwarn("MAPFIX: Doom: E2M9 detected and fixed");
115     return;
116   }
118   // Doom: E3M7
119   if (MapHashMD5 == "5ac51ca9f1b57d4538049422a5e37291") {
120     // missing textures
121     Sides[Lines[971].sidenum[1]].TopTexture = LdrTexNumForName("SP_HOT1", TEXTYPE_Wall);
122     printwarn("MAPFIX: Doom: E3M7 detected and fixed");
123     return;
124   }
126   // Doom: E3M8
127   if (MapHashMD5 == "ef128313112110ed6c1549af96af26c9") {
128     // invalid line sectors
129     assert(Sides[Lines[21].sidenum[0]].Sector);
130     assert(Sides[Lines[57].sidenum[1]].Sector);
131     Lines[21].frontsector = cast([unsafe])(&Sectors[1]);
132     Sides[Lines[21].sidenum[0]].Sector = Lines[21].frontsector;
133     Lines[57].backsector = cast([unsafe])(&Sectors[1]);
134     Sides[Lines[57].sidenum[1]].Sector = Lines[57].backsector;
135     printwarn("MAPFIX: Doom: E3M8 detected and fixed");
136     return;
137   }
139   // Doom: E4M1
140   if (MapHashMD5 == "da0c8281ac70eec31127c228bcd7fe2c") {
141     // missing textures
142     Sides[Lines[470].sidenum[0]].TopTexture = LdrTexNumForName("GSTONE1", TEXTYPE_Wall);
143     printwarn("MAPFIX: Doom: E4M1 detected and fixed");
144     return;
145   }
147   // Doom: E4M4
148   if (MapHashMD5 == "aaecadd4d97970aff702d86fafac7d17") {
149     // missing textures
150     Sides[Lines[427].sidenum[1]].TopTexture = LdrTexNumForName("BROWNHUG", TEXTYPE_Wall);
151     Sides[Lines[558].sidenum[1]].TopTexture = LdrTexNumForName("BROWNHUG", TEXTYPE_Wall);
152     Sides[Lines[567].sidenum[0]].TopTexture = LdrTexNumForName("BROWNHUG", TEXTYPE_Wall);
153     Sides[Lines[572].sidenum[0]].TopTexture = LdrTexNumForName("BROWNHUG", TEXTYPE_Wall);
154     printwarn("MAPFIX: Doom: E4M4 detected and fixed");
155     return;
156   }
158   // Doom II: MAP02 (normal and BFG edition)
159   if (MapHashMD5 == "ab24ae6e2cb13cbdd04600a4d37f9189" || MapHashMD5 == "1ec0af1e3985650f0c9000319c599d0c") {
160     // missing textures
161     Sides[Lines[327].sidenum[0]].BottomTexture = LdrTexNumForName("STONE4", TEXTYPE_Wall);
162     Sides[Lines[328].sidenum[0]].BottomTexture = LdrTexNumForName("STONE4", TEXTYPE_Wall);
163     Sides[Lines[338].sidenum[0]].BottomTexture = LdrTexNumForName("STONE4", TEXTYPE_Wall);
164     Sides[Lines[339].sidenum[0]].BottomTexture = LdrTexNumForName("STONE4", TEXTYPE_Wall);
165     printwarn("MAPFIX: Doom II: MAP02 detected and fixed");
166     return;
167   }
169   // Doom II: MAP04
170   if (MapHashMD5 == "cec791136a83eec4b91d39718bdf9d82") {
171     // missing textures
172     Sides[Lines[456].sidenum[1]].TopTexture = LdrTexNumForName("SUPPORT3", TEXTYPE_Wall);
173     Sides[Lines[108].sidenum[0]].TopTexture = LdrTexNumForName("STONE", TEXTYPE_Wall);
174     Sides[Lines[109].sidenum[0]].TopTexture = LdrTexNumForName("STONE", TEXTYPE_Wall);
175     Sides[Lines[110].sidenum[0]].TopTexture = LdrTexNumForName("STONE", TEXTYPE_Wall);
176     Sides[Lines[111].sidenum[0]].TopTexture = LdrTexNumForName("STONE", TEXTYPE_Wall);
177     Sides[Lines[127].sidenum[0]].TopTexture = LdrTexNumForName("STONE", TEXTYPE_Wall);
178     Sides[Lines[128].sidenum[0]].TopTexture = LdrTexNumForName("STONE", TEXTYPE_Wall);
179     // remove erroneous blue keycard pickup ambush sector tags (nearby viewing windows, and the lights)
180     Sectors[19].sectorTag = 0;
181     Sectors[20].sectorTag = 0;
182     Sectors[23].sectorTag = 0;
183     Sectors[28].sectorTag = 0;
184     Sectors[33].sectorTag = 0;
185     Sectors[34].sectorTag = 0;
186     Sectors[83].sectorTag = 0;
187     Sectors[85].sectorTag = 0;
188     printwarn("MAPFIX: Doom II: MAP04 detected and fixed");
189     return;
190   }
192   // Doom II: MAP05
193   if (MapHashMD5 == "9e061ad7fbcd7fad968c976cb4aa3b9d") {
194     // fix bug with opening westmost door in door hallway - incorrect sector tagging - see doomwiki.org for more info
195     Sectors[4].sectorTag = 0;
196     Sectors[153].sectorTag = 0;
197     printwarn("MAPFIX: Doom II: MAP05 detected and fixed");
198     return;
199   }
201   // Doom II: MAP08
202   if (MapHashMD5 == "66c46385eb1a23d60839d1532522076b") {
203     // missing texture
204     Sides[Lines[101].sidenum[1]].TopTexture = LdrTexNumForName("BRICK7", TEXTYPE_Wall);
205     printwarn("MAPFIX: Doom II: MAP08 detected and fixed");
206     return;
207   }
209   // Doom II: MAP14
210   if (MapHashMD5 == "5bda34da60c0530794cc1ea2da017976") {
211     // missing texture
212     Sides[Lines[1259].sidenum[1]].TopTexture = LdrTexNumForName("BSTONE2", TEXTYPE_Wall);
213     Sides[Lines[1305].sidenum[1]].TopTexture = LdrTexNumForName("BSTONE2", TEXTYPE_Wall);
214     printwarn("MAPFIX: Doom II: MAP14 detected and fixed");
215     return;
216   }
218   // Doom II: MAP15
219   if (MapHashMD5 == "1a540ba717bf9ec85f8522594c352f2a") {
220     Sectors[147].special = 0; // this secret is possible, but meh...
221     printwarn("MAPFIX: Doom II: MAP15 detected and fixed");
222     return;
223   }
225   // Doom II: MAP18
226   if (MapHashMD5 == "0d491365c1b88b7d1b603890100dd03e") {
227     // missing texture
228     Sides[Lines[451].sidenum[0]].MidTexture = LdrTexNumForName("METAL", TEXTYPE_Wall);
229     Sides[Lines[459].sidenum[0]].MidTexture = LdrTexNumForName("METAL", TEXTYPE_Wall);
230     printwarn("MAPFIX: Doom II: MAP18 detected and fixed");
231     return;
232   }
234   // Doom II: MAP19
235   if (MapHashMD5 == "b5506b1e8f2fc272ad0c77b9e0df5491") {
236     // missing texture
237     Sides[Lines[355].sidenum[1]].TopTexture = LdrTexNumForName("STONE2", TEXTYPE_Wall);
238     Sides[Lines[736].sidenum[0]].TopTexture = LdrTexNumForName("SLADWALL", TEXTYPE_Wall);
239     printwarn("MAPFIX: Doom II: MAP19 detected and fixed");
240     return;
241   }
243   // Doom II: MAP21
244   if (MapHashMD5 == "ebdac00e9d25d884b2c8f4b1f0390539") {
245     // push ceiling down in glitchy sectors above the stair switches
246     LdrSectorOffsetCeiling(ref Sectors[50], -56);
247     LdrSectorOffsetCeiling(ref Sectors[54], -56);
248     printwarn("MAPFIX: Doom II: MAP21 detected and fixed");
249     return;
250   }
252   // Doom II: MAP27
253   if (MapHashMD5 == "110f84de041052b59307faf0293e6bc0") {
254     // missing texture
255     Sides[Lines[582].sidenum[1]].TopTexture = LdrTexNumForName("ZIMMER3", TEXTYPE_Wall);
256     Sectors[93].special = 0; // this secret is possible, but meh...
257     printwarn("MAPFIX: Doom II: MAP27 detected and fixed");
258     return;
259   }
261   // Doom II: MAP29
262   if (MapHashMD5 == "20251eda21b2f2ecf6ff5b8bbc00b26c") {
263     // missing textures on teleporters
264     for (int i = 0; i < 4; ++i) {
265       Sides[Lines[405+i].sidenum[1]].BottomTexture = LdrTexNumForName("SUPPORT3", TEXTYPE_Wall);
266       Sides[Lines[516+i].sidenum[1]].BottomTexture = LdrTexNumForName("SUPPORT3", TEXTYPE_Wall);
267       Sides[Lines[524+i].sidenum[1]].BottomTexture = LdrTexNumForName("SUPPORT3", TEXTYPE_Wall);
268       Sides[Lines[1146+i].sidenum[1]].BottomTexture = LdrTexNumForName("SUPPORT3", TEXTYPE_Wall);
269       Sides[Lines[1138+i].sidenum[1]].BottomTexture = LdrTexNumForName("SUPPORT3", TEXTYPE_Wall);
270     }
271     printwarn("MAPFIX: Doom II: MAP29 detected and fixed");
272     return;
273   }
275   // TNT:Evilution: MAP15
276   if (MapHashMD5 == "dfc18b92bf3e8142b8684ecd8bd2ef06") {
277     // raise up sector with its counterpart so 100% kills becomes possible
278     Sectors[330].sectorTag = 11;
279     printwarn("MAPFIX: TNT:Evilution: MAP15 detected and fixed");
280     return;
281   }
283   // TNT:Evilution: MAP29
284   if (MapHashMD5 == "2c4a3356c5eb3526d2c72a4aa4b18a36") {
285     // remove mancubus who always gets stuck in teleport tunnel, preventing 100% kills on HMP
286     Things[405].options = 0;
287     Things[17].SkillClassFilter &= ~(0x03|0x04|0x18);
288     printwarn("MAPFIX: TNT:Evilution: MAP29 detected and fixed");
289     return;
290   }
292   // TNT:Evilution: MAP31
293   if (MapHashMD5 == "a53ae580a4af2b5d0b0893f86914781e") {
294     // the famous missing yellow key...
295     Things[470].options |= LineSpecialLevelInfo::MTF_GSINGLE; // 0x07
296     Things[470].SkillClassFilter |= 0x03|0x04|0x18;
297     printwarn("MAPFIX: TNT:Evilution: MAP31 detected and fixed");
298     return;
299   }
301   // Plutonia: MAP26
302   if (MapHashMD5 == "abc4eb5a1535eccd0061ad14f3547908") {
303     Sectors[156].special = 0;
304     printwarn("MAPFIX: Plutonia: MAP26 detected and fixed");
305     return;
306   }
308   // Nerve: MAP04
309   if (MapHashMD5 == "ff635fb9a2f076566299910f8c78f707") {
310     Sectors[868].special = 0;
311     // missing bottom texture
312     Sides[Lines[2234].sidenum[1]].BottomTexture = LdrTexNumForName("GSTONE1", TEXTYPE_Wall);
313     Sides[Lines[3765].sidenum[1]].BottomTexture = LdrTexNumForName("GSTONE1", TEXTYPE_Wall);
314     Sides[Lines[3768].sidenum[1]].BottomTexture = LdrTexNumForName("GSTONE1", TEXTYPE_Wall);
315     printwarn("MAPFIX: Nerve: MAP04 detected and fixed");
316     return;
317   }
319   // Heretic: E1M2
320   if (MapHashMD5 == "d94587625ba779644d58151a87897cf1") {
321     // missing textures
322     Sides[Lines[477].sidenum[1]].TopTexture = LdrTexNumForName("MOSSRCK1", TEXTYPE_Wall);
323     Sides[Lines[478].sidenum[1]].TopTexture = LdrTexNumForName("MOSSRCK1", TEXTYPE_Wall);
324     Sides[Lines[479].sidenum[1]].TopTexture = LdrTexNumForName("MOSSRCK1", TEXTYPE_Wall);
325     Sides[Lines[1057].sidenum[0]].TopTexture = LdrTexNumForName("MOSSRCK1", TEXTYPE_Wall);
326     printwarn("MAPFIX: Heretic: E1M2 detected and fixed");
327     return;
328   }
330   // Heretic: E1M3
331   if (MapHashMD5 == "add0fac41afb0b3c9b9f3c0006f93805") {
332     // Broken door between the hallway that leads to a Torch
333     // and the passage that has a Bag of Holding at its end
334     LdrSectorOffsetFloor(ref Sectors[86], -128);
335     LdrSectorOffsetCeiling(ref Sectors[86], -128);
336     printwarn("MAPFIX: Heretic: E1M3 detected and fixed");
337     return;
338   }
340   // Heretic: E1M4
341   if (MapHashMD5 == "916318d8b06dac2d83424b23e4b66531") {
342     // wrong sector offsets
343     LdrSectorOffsetCeiling(ref Sectors[0], 8);
344     LdrSectorOffsetCeiling(ref Sectors[1], 8);
345     LdrSectorOffsetCeiling(ref Sectors[2], 8);
346     LdrSectorOffsetCeiling(ref Sectors[3], 8);
347     LdrSectorOffsetCeiling(ref Sectors[4], 8);
348     LdrSectorOffsetCeiling(ref Sectors[6], 8);
349     LdrSectorOffsetFloor(ref Sectors[6], 8);
350     LdrSectorOffsetCeiling(ref Sectors[17], 8);
351     // yellow key door
352     LdrSectorOffsetFloor(ref Sectors[284], -8);
353     LdrSectorOffsetCeiling(ref Sectors[284], -8);
354     // missing textures
355     Sides[Lines[490].sidenum[1]].BottomTexture = LdrTexNumForName("GRSTNPB", TEXTYPE_Wall);
356     Sides[Lines[722].sidenum[0]].BottomTexture = LdrTexNumForName("WOODWL", TEXTYPE_Wall);
357     Sides[Lines[911].sidenum[0]].BottomTexture = LdrTexNumForName("WOODWL", TEXTYPE_Wall);
358     Sides[Lines[1296].sidenum[0]].BottomTexture = LdrTexNumForName("WOODWL", TEXTYPE_Wall);
359     printwarn("MAPFIX: Heretic: E1M4 detected and fixed");
360     return;
361   }
363   // Heretic: E2M2
364   if (MapHashMD5 == "397a0e17a39542e4e8294e156fab0502") {
365     // missing green door statues on easy and hard difficulties
366     Things[17].options |= LineSpecialLevelInfo::MTF_GSINGLE; // 0x07
367     Things[17].SkillClassFilter |= 0x03|0x04|0x18;
368     Things[18].options |= LineSpecialLevelInfo::MTF_GSINGLE; // 0x07
369     Things[18].SkillClassFilter |= 0x03|0x04|0x18;
370     printwarn("MAPFIX: Heretic: E2M2 detected and fixed");
371     return;
372   }
374   // Heretic: E3M6
375   if (MapHashMD5 == "ca3773ed313e8899311f3dd0ca195a68") {
376     // quartz flask outside of map
377     Things[373].options = 0;
378     Things[373].SkillClassFilter &= ~(0x03|0x04|0x18);
379     // missing wall torch on hard difficulty
380     Things[448].options |= LineSpecialLevelInfo::MTF_GSINGLE; // 0x07
381     Things[448].SkillClassFilter |= 0x03|0x04|0x18;
382     // missing textures
383     Sides[Lines[343].sidenum[0]].TopTexture = LdrTexNumForName("MOSSRCK1", TEXTYPE_Wall);
384     Sides[Lines[370].sidenum[0]].TopTexture = LdrTexNumForName("MOSSRCK1", TEXTYPE_Wall);
385     printwarn("MAPFIX: Heretic: E2M2 detected and fixed");
386     return;
387   }
389   // Heretic: E4M7
390   if (MapHashMD5 == "5e3fcfde78310bb89f92b1626a47d0ad") {
391     // missing textures
392     Sides[Lines[1274].sidenum[0]].TopTexture = LdrTexNumForName("CSTLRCK", TEXTYPE_Wall);
393     Sides[Lines[1277].sidenum[1]].TopTexture = LdrTexNumForName("CSTLRCK", TEXTYPE_Wall);
394     Sides[Lines[1278].sidenum[0]].TopTexture = LdrTexNumForName("CSTLRCK", TEXTYPE_Wall);
395     printwarn("MAPFIX: Heretic: E4M7 detected and fixed");
396     return;
397   }
400   // Winter's Fury
401   if (MapHashMD5 == "369034113c5315b17cadfb11f730a571" ||
402       MapHashMD5 == "355695fadf065955f62ea993e942c35d" ||
403       MapHashMD5 == "253c286d243fdd6fae882b657b9ffc99" ||
404       MapHashMD5 == "2842ece024c5c7905f637c616fefc36e" ||
405       MapHashMD5 == "c3cd90a4d470b5413849e6341f245737")
406   {
407     SetCvar('r_max_portal_depth_override', 1);
408     //bForceAllowSeveralPObjInSubsector = true; // this is not used anymore, but kept for compatibility
409     printwarn("MAPFIX: Winter's Fury: reduced portals to 1, enabled pobj hack");
410     return;
411   }
413   // Skulldash EE first map and credits map, too many static lights, don't precalc
414   if (MapHashMD5 == "42389d0173031f6ffc8df2919d34fe16" ||
415       MapHashMD5 == "a8d2a336f0b8e77a84be9460743be70d") {
416     if (MapHashMD5 == "42389d0173031f6ffc8df2919d34fe16") {
417       // hub map
418       bForceNoTexturePrecache = true;
419       //bForceNoPrecalcStaticLights = true;
420     }
421     //ldr_extrasamples_override = 0;
422     printwarn("MAPFIX: SkullDash EE: disabled precalculated static lightmaps and texture precaching");
423     return;
424   }
426   // dmp2017 hub map
427   if (MapHashMD5 == "1c5f5371b392663e70c8c7b94ceeb82b") {
428     bForceNoTexturePrecache = true;
429     //bForceNoPrecalcStaticLights = true;
430     return;
431   }
432   //ldr_extrasamples_override = 0;
434   // Discharge! map04
435   // k8: actually, is looks better with dynamic lights:
436   //     there is a bug in static lightmap calculation that leaves unlit regions, and
437   //     for some mysterious reason dynamic lighting doesn't have it.
438   //     it would be event better when i'll do proper dynlight caching system
439   /*
440   if (MapHashMD5 == "d28e3374cd4d2a17a00bfe49fb6d48d8") {
441     bConvertSectorLightsToStatic = true;
442     printwarn("MAPFIX: Discharge MAP04: made sector lights static");
443     return;
444   }
445   */
447   // Project Remap
448   /*
449   if (MapHashMD5 == "2f40f5af09a1a6b9d257ef94303ee8a8" ||
450       MapHashMD5 == "0b83e5124ead265f8e63f7c2e759117e" ||
451       MapHashMD5 == "39ff9af2e7bfaaa55e78e7ec2a78db8f" ||
452       MapHashMD5 == "cb8f6cf20fb677a94fa2a9b18876303a"
453      )
454   {
455     bConvertSectorLightsToStatic = true;
456     printwarn("MAPFIX: Project Remap: made sector lights static");
457     return;
458   }
459   */
461   // DTWID: E1M2
462   if (MapHashMD5 == "27927a9ee6c29c38cd8fb42f54f16efa") {
463     // missing textures
464     Sides[Lines[82].sidenum[1]].TopTexture = LdrTexNumForName("STARTAN3", TEXTYPE_Wall);
465     printwarn("MAPFIX: DTWID: E1M2 detected and fixed");
466     return;
467   }
469   // Decade
470   if (MapHashMD5 == "77d1fc9f463239d3f117767854303241") {
471     // missing textures
472     Sides[Lines[9420].sidenum[1]].BottomTexture = LdrTexNumForName("SILVER1", TEXTYPE_Wall);
473     printwarn("MAPFIX: Decade detected and fixed");
474     return;
475   }
477   // Grove
478   if (MapHashMD5 == "076a4ff1c79459308886560338743eab") {
479     bForceNoDeepwaterFix = true;
480     //bForceNoFloorFloodfillFix = true;
481     //bForceNoCeilingFloodfillFix = true;
482     printwarn("MAPFIX: Grove detected and fixed");
483     return;
484   }
486   // Grove alt
487   if (MapHashMD5 == "b5733f760836dfc2e7c9745f80f90e79") {
488     bForceNoDeepwaterFix = true;
489     //bForceNoFloorFloodfillFix = true;
490     //bForceNoCeilingFloodfillFix = true;
491     printwarn("MAPFIX: Grove Alt detected and fixed");
492     return;
493   }
495   // Hell Revealed MAP23
496   // https://forum.zdoom.org/viewtopic.php?t=60181&p=1101976#p1101976
497   if (MapHashMD5 == "16e621e46f87418f6f8db71d68433ae0") {
498     // Arachnotrons near beginning sometimes don't spawn if imps block
499     // their one-time teleport. Make these teleports repeatable to ensure
500     // maxkills are always possible.
501     Lines[2036].flags |= ML_REPEAT_SPECIAL;
502     Lines[2038].flags |= ML_REPEAT_SPECIAL;
503     Lines[2039].flags |= ML_REPEAT_SPECIAL;
504     Lines[2040].flags |= ML_REPEAT_SPECIAL;
505     printwarn("MAPFIX: Hell Revealed MAP23 detected and fixed");
506     return;
507   }
509   // Venom MAP01, swap sides
510   if (MapHashMD5 == "36e85e1b6d8a6d7f11dfebd17a8d03d1") {
511     int sn0 = Lines[1238].sidenum[0];
512     int sn1 = Lines[1238].sidenum[1];
513     Sides[sn1].Top = Sides[sn0].Top;
514     Sides[sn1].Bot = Sides[sn0].Bot;
515     Sides[sn1].TopTexture = Sides[sn0].TopTexture;
516     Sides[sn1].BottomTexture = Sides[sn0].BottomTexture;
517     printwarn("MAPFIX: Venom MAP01 detected and fixed");
518     return;
519   }
521   //k8: this hack will make SS:R map05 turret work right in both versions
522   if (MapHashMD5 == "00b2077327e4f724f43d6f2f81cd47c4" ||
523       MapHashMD5 == "72a7f91eaa76187cc57bd6a017f49e96")
524   {
525     bool isV11 = (MapHashMD5 == "00b2077327e4f724f43d6f2f81cd47c4");
526     foreach (ref auto th; Things) {
527       if (th.type == 9001 && th.tid == 55) {
528         printwarn("MAPFIX: Silent Steel: Remastered v1.%s MAP05 detected and fixed", (isV11 ? 1 : 0));
529         th.y += (isV11 ? -1.0 : 1.0); // move this mapspot down a little, so it ends up in back sector
530         break;
531       }
532     }
533     return;
534   }
536   //k8: Maps Of Chaos (Overkill), MAP04 invalid player start
537   if (MapHashMD5 == "0b8884450521c30e5bc286e9b9d2b6dc" && Things.length == 289) {
538     printwarn("MAPFIX: Maps Of Chaos (Overkill), MAP04");
539     // fix invalid player 1 start (it should be DM start instead)
540     Things[286].type = 11;
541     Things[286].angle = 180;
542     return;
543   }
545   //k8: No End In Sight (v 1.4), E2M4, lift bug (found by steinkrauz)
546   if (MapHashMD5 == "648f8c13cc7f29abeb012f91641ae5af") {
547     printwarn("MAPFIX: No End In Sight, E2M4");
548     // fix missing bottom texture on back sidedef
549     Sides[Lines[3085].sidenum[1]].BottomTexture = LdrTexNumForName("PLAT1", TEXTYPE_Wall);
550     return;
551   }
553   //k8: Memento Mori MAP27 (found by steinkrauz)
554   if (MapHashMD5 == "c36ce8a28409625480541976c7bf1c0f") {
555     printwarn("MAPFIX: Memento Mori, MAP27");
556     // fix missing bottom texture on back sidedef
557     Sides[Lines[854].sidenum[1]].BottomTexture = LdrTexNumForName("STONE4", TEXTYPE_Wall);
558     Sides[Lines[1119].sidenum[1]].BottomTexture = LdrTexNumForName("STONE4", TEXTYPE_Wall);
559     return;
560   }
562   /* i changed door logic back to "tolerant", so it is not needed anymore
563   //k8: Maps Of Chaos (Overkill), MAP01 thing 131 (demon) is blocking a closet wall
564   if (MapHashMD5 == "920e8c47e172a6a265b6b57039c3f209" && Things.length == 360) {
565     printwarn("MAPFIX: Maps Of Chaos (Overkill), MAP01");
566     // move demon a little, so it won't block a wall
567     Things[131].x = -221;
568     return;
569   }
570   */
572   //k8: Retribution Trilogy MAP29
573   if (MapHashMD5 == "0a398978ac5eb714cf452912e5bebfbb") {
574     printwarn("MAPFIX: Retribution Trilogy, MAP29");
575     // move light changer to another tag, and change sector #3686 tag
576     int oldtag = Sectors[3686].sectorTag;
577     dictionary!(int, bool) tags;
578     foreach (auto idx, auto ref sec; Sectors) if (sec.sectorTag) tags.put(sec.sectorTag, true);
579     int newtag = 1;
580     for (;;) {
581       if (!tags.find(newtag)) break;
582       ++newtag;
583     }
584     //printdebug("NEWTAG: %s", newtag);
585     // fix sectors
586     foreach (auto idx, auto ref sec; Sectors) {
587       if (sec.sectorTag == oldtag && idx != 3686) {
588         //printdebug(" sector #%s has tag #%s", cast([unsafe])(&sec-&Sectors[0]), sec.sectorTag);
589         sec.sectorTag = newtag;
590       }
591     }
592     // fix lines
593     foreach (auto ref line; Lines) {
594       // for Boom compat, line tag is the same as arg1 (this is how the translation code works)
595       if (line.special == LNSPEC_DoorOpen && line.lineTag == oldtag && line.arg1 == oldtag) {
596         //printdebug("  fixing linedef #%s (spc=%s)", &line-&Lines[0], LineSpecial2Str(line.special));
597         line.lineTag = newtag;
598         line.arg1 = newtag;
599       }
600     }
601     return;
602   }
604   //k8: Zen Dynamics MAP01
605   if (MapHashMD5 == "c1e1d7b32905049ff6eedd971124c844") {
606     printwarn("MAPFIX: Zen Dynamics, MAP01");
607     // move player 1 start, it is stuck in a wall
608     Things[0].x -= 1;
609     return;
610   }
613   // maps from ikspcial.zip
614   // underwtr.wad
615   if (MapHashMD5 == "837f6ca0df891069b63580cc9ec0582e") {
616     printwarn("MAPFIX: ikspcial:underwtr");
617     bForceUseZDBSP = true;
618     return;
619   }
621   // cross.wad
622   if (MapHashMD5 == "4d2ebeebf5685d8dd8302da19b53bf70") {
623     printwarn("MAPFIX: ikspcial:cross");
624     bForceUseZDBSP = true;
625     return;
626   }
628   // undergnd
629   if (MapHashMD5 == "4c918a1eced8ed9d03bc42b011b680f7") {
630     printwarn("MAPFIX: ikspcial:undergnd");
631     bForceUseZDBSP = true;
632     return;
633   }
636   // Edge.wad
637   if (MapHashMD5 == "92a572490ef74d39a31620750ce45b5a") {
638     printwarn("MAPFIX: Execution Deathmatch MAP05 DM start fix");
639     // DM start
640     //assert(Things[23].type == 11);
641     Things[23].x -= 2;
642     Things[23].y -= 2;
643     // shotgun
644     //assert(Things[15].type == 82);
645     Things[15].x -= 6;
646     Things[15].y -= 6;
647   }