{"id":331,"date":"2026-07-21T18:23:36","date_gmt":"2026-07-21T18:23:36","guid":{"rendered":"https:\/\/blogs.scummvm.org\/mohit\/?p=331"},"modified":"2026-07-21T18:23:36","modified_gmt":"2026-07-21T18:23:36","slug":"dos-of-chaos","status":"publish","type":"post","link":"https:\/\/blogs.scummvm.org\/mohit\/2026\/07\/21\/dos-of-chaos\/","title":{"rendered":"DOS of Chaos"},"content":{"rendered":"<p>Hello and welcome back! This week I worked on the DOS version of the Dungeon Master engine, and a big part of that was getting the VGA colors right, since the DOS release used 256-color VGA graphics.<\/p>\n<p>I added DOS-specific palette index constants to the graphics header, letting the engine track different environment levels, menus, and spell fade states. With the correct colors generated, I hooked them up directly to ScummVM&#8217;s palette manager, enabling accurate rendering and smooth screen fades.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal\" dir=\"auto\">The palette changes depending on whether the game is running normally, paused, or displaying the inventory screen. I implemented this switching in <code class=\"bg-text-200\/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]\">drawViewport()<\/code> \u2014 accessing the inventory switches to the inventory palette, while drawing the dungeon uses the active environment palette.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal\" dir=\"auto\">Light levels also affect how bright the viewport is, from pitch black to fully lit. I updated the palette loading logic to read light levels directly from the runtime viewport palette <code>_palDungeonView<\/code>.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal\" dir=\"auto\">Next, I updated the <code>startEndFadeToPalette<\/code> method. In the original game, whenever the screen needs to change \u2014 opening the main menu, starting the game, entering a new area \u2014 the engine calls a transition function with a raw buffer of color data. On the Amiga, it would manually fade color-by-color. On DOS however, screens are displayed using the pre-defined full VGA palettes set up earlier.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal\" dir=\"auto\">So the matching logic looks at the incoming color buffer and figures out which game screen it corresponds to \u2014 is it blank black, the intro, the credits, or the main dungeon view? Once identified, the correct DOS VGA palette is applied immediately.<\/p>\n<p dir=\"auto\">\n<p dir=\"auto\">The DOS version organizes its wall and floor graphics quite differently from the Amiga version. On DOS, wall sets are much larger \u2014 40 graphics per set \u2014 starting at index 86, with floor\/ceiling sets beginning at index 78.<br \/>\nThe indices are spread out differently, to address which I added platform checks to load the correct offsets throughout. Memory allocation for all environmental graphic buffers \u2014 D1\/D2\/D3 walls, door frames \u2014 was also adjusted to dynamically compute sizes and locations using the correct platform-specific layout.<\/p>\n<h4 dir=\"auto\"><span style=\"color: #993300\">The IMG3 Decompressor<\/span><\/h4>\n<p class=\"font-claude-response-body break-words whitespace-normal\" dir=\"auto\">With the VGA color systems and palette tables fully in place, the final step to getting graphics on screen was writing the decompressor for the DOS version&#8217;s custom image format.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal\" dir=\"auto\">The DOS release compresses its graphic assets using the <code class=\"bg-text-200\/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]\">IMG3<\/code> RLE format, which differs significantly from the byte-oriented <code class=\"bg-text-200\/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]\">IMG2<\/code> format used on Amiga. I integrated an <code class=\"bg-text-200\/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]\">IMG3<\/code> decoder into <code class=\"bg-text-200\/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]\">loadIntoBitmap()<\/code>.<\/p>\n<p dir=\"auto\">DOS bitmaps also require every row of decompressed data to align to an even byte width. For odd-width graphics, the decompressor needs to inject a padding pixel at the end of each line. I added row wrapping, ensuring the decompressed output aligns correctly.<\/p>\n<p dir=\"auto\">Once the decompressor was running, we needed to make sure the game allocated enough memory for the decompressed graphics. Since the DOS decompressor pads odd-width graphics to even byte boundaries, I updated the memory allocation routines for all game assets, replacing standard pixel-width lookups with a new <code class=\"bg-text-200\/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]\">getDecompressedWidth()<\/code> function that returns the even-aligned width for DOS, preventing memory corruption when loading graphics.<\/p>\n<p dir=\"auto\">With all these changes in place, the DOS version now looks like this: <img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-334\" src=\"https:\/\/blogs.scummvm.org\/mohit\/wp-content\/uploads\/sites\/82\/2026\/07\/scummvm-dm-00000-1024x557.png\" alt=\"\" width=\"580\" height=\"315\" srcset=\"https:\/\/blogs.scummvm.org\/mohit\/wp-content\/uploads\/sites\/82\/2026\/07\/scummvm-dm-00000-1024x557.png 1024w, https:\/\/blogs.scummvm.org\/mohit\/wp-content\/uploads\/sites\/82\/2026\/07\/scummvm-dm-00000-300x163.png 300w, https:\/\/blogs.scummvm.org\/mohit\/wp-content\/uploads\/sites\/82\/2026\/07\/scummvm-dm-00000-768x418.png 768w, https:\/\/blogs.scummvm.org\/mohit\/wp-content\/uploads\/sites\/82\/2026\/07\/scummvm-dm-00000-1536x835.png 1536w, https:\/\/blogs.scummvm.org\/mohit\/wp-content\/uploads\/sites\/82\/2026\/07\/scummvm-dm-00000-1200x653.png 1200w, https:\/\/blogs.scummvm.org\/mohit\/wp-content\/uploads\/sites\/82\/2026\/07\/scummvm-dm-00000.png 1920w\" sizes=\"auto, (max-width: 580px) 100vw, 580px\" \/> <img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-335\" src=\"https:\/\/blogs.scummvm.org\/mohit\/wp-content\/uploads\/sites\/82\/2026\/07\/scummvm-dm-00001-1024x557.png\" alt=\"\" width=\"580\" height=\"315\" srcset=\"https:\/\/blogs.scummvm.org\/mohit\/wp-content\/uploads\/sites\/82\/2026\/07\/scummvm-dm-00001-1024x557.png 1024w, https:\/\/blogs.scummvm.org\/mohit\/wp-content\/uploads\/sites\/82\/2026\/07\/scummvm-dm-00001-300x163.png 300w, https:\/\/blogs.scummvm.org\/mohit\/wp-content\/uploads\/sites\/82\/2026\/07\/scummvm-dm-00001-768x418.png 768w, https:\/\/blogs.scummvm.org\/mohit\/wp-content\/uploads\/sites\/82\/2026\/07\/scummvm-dm-00001-1536x835.png 1536w, https:\/\/blogs.scummvm.org\/mohit\/wp-content\/uploads\/sites\/82\/2026\/07\/scummvm-dm-00001-1200x653.png 1200w, https:\/\/blogs.scummvm.org\/mohit\/wp-content\/uploads\/sites\/82\/2026\/07\/scummvm-dm-00001.png 1920w\" sizes=\"auto, (max-width: 580px) 100vw, 580px\" \/><\/p>\n<h4><span style=\"color: #993300\">Corrupted Graphics \u2014 What&#8217;s Left<\/span><\/h4>\n<p>The graphics are still corrupted due to two root causes (hopefully \ud83d\ude43):<\/p>\n<p>First, DOS has more database entries than Amiga, so all the hardcoded Amiga constants are pointing to the wrong data. The font, item icons, creatures, and pit\/ceiling graphics are all shifted on DOS, meaning the engine is currently reading from the wrong indices entirely.<\/p>\n<p>Second, <code class=\"bg-text-200\/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]\">unpackGraphics()<\/code> stops unpacking at index 532 \u2014 the Amiga limit \u2014 but DOS graphics continue up to 670, with sounds starting at 671. This leaves the font and item graphics completely uninitialized in memory.<\/p>\n<div data-rs-index=\"43\" data-index=\"43\" data-last-message=\"true\">\n<div role=\"article\" aria-label=\"Message 44 of 44\">\n<div data-test-render-count=\"1\">\n<div class=\"group\">\n<div class=\"contents\">\n<div class=\"group relative relative pb-[var(--msg-assistant-pb,0.75rem)]\" data-is-streaming=\"false\">\n<div class=\"font-claude-response relative leading-[1.65rem] [&amp;_pre&gt;div]:bg-bg-000\/50 [&amp;_pre&gt;div]:border-0.5 [&amp;_pre&gt;div]:border-border-400 [&amp;_.ignore-pre-bg&gt;div]:bg-transparent [&amp;_.standard-markdown_:is(p,blockquote,h1,h2,h3,h4,h5,h6)]:pl-2 [&amp;_.standard-markdown_:is(p,blockquote,ul,ol,h1,h2,h3,h4,h5,h6)]:pr-8 [&amp;_.progressive-markdown_:is(p,blockquote,h1,h2,h3,h4,h5,h6)]:pl-2 [&amp;_.progressive-markdown_:is(p,blockquote,ul,ol,h1,h2,h3,h4,h5,h6)]:pr-8\">\n<div>\n<div class=\"standard-markdown grid-cols-1 grid [&amp;_&gt;_*]:min-w-0 gap-3 [&amp;_&gt;_*:last-child]:mb-0 standard-markdown\">\n<p class=\"font-claude-response-body break-words whitespace-normal\" dir=\"auto\">These are what I&#8217;ll be focusing on next week, with the goal of bringing the DOS version to a fully playable state as soon as possible. That was it for this week \u2014 see you in the next one! \ud83d\udc4b<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hello and welcome back! This week I worked on the DOS version of the Dungeon Master engine, and a big part of that was getting the VGA colors right, since the DOS release used 256-color VGA graphics. I added DOS-specific palette index constants to the graphics header, letting the engine track different environment levels, menus, [&hellip;]<\/p>\n","protected":false},"author":30,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12],"tags":[],"class_list":["post-331","post","type-post","status-publish","format-standard","hentry","category-week-8"],"_links":{"self":[{"href":"https:\/\/blogs.scummvm.org\/mohit\/wp-json\/wp\/v2\/posts\/331","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.scummvm.org\/mohit\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.scummvm.org\/mohit\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.scummvm.org\/mohit\/wp-json\/wp\/v2\/users\/30"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.scummvm.org\/mohit\/wp-json\/wp\/v2\/comments?post=331"}],"version-history":[{"count":5,"href":"https:\/\/blogs.scummvm.org\/mohit\/wp-json\/wp\/v2\/posts\/331\/revisions"}],"predecessor-version":[{"id":338,"href":"https:\/\/blogs.scummvm.org\/mohit\/wp-json\/wp\/v2\/posts\/331\/revisions\/338"}],"wp:attachment":[{"href":"https:\/\/blogs.scummvm.org\/mohit\/wp-json\/wp\/v2\/media?parent=331"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.scummvm.org\/mohit\/wp-json\/wp\/v2\/categories?post=331"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.scummvm.org\/mohit\/wp-json\/wp\/v2\/tags?post=331"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}