{"id":102,"date":"2026-08-17T13:15:55","date_gmt":"2026-08-17T13:15:55","guid":{"rendered":"https:\/\/blogs.scummvm.org\/andy\/?p=102"},"modified":"2026-08-18T11:02:26","modified_gmt":"2026-08-18T11:02:26","slug":"week-12","status":"publish","type":"post","link":"https:\/\/blogs.scummvm.org\/andy\/2026\/08\/17\/week-12\/","title":{"rendered":"Week 12"},"content":{"rendered":"<p data-path-to-node=\"4\">Last week I fixed the remaining problems with D<i data-path-to-node=\"4\" data-index-in-node=\"114\">\u00e9j\u00e0 Vu, and\u00a0<\/i> this week I opened <i data-path-to-node=\"4\" data-index-in-node=\"114\">D\u00e9j\u00e0 Vu II<\/i> and started again from the top, notebook in hand. It is the same engine, the same tooling, and the same approach as before, but a different game exercises different corners of the code \u2014 and it found plenty of them. This being the final week, it was also time to stop fixing and start packaging.<\/p>\n<h2 data-path-to-node=\"5\">Two crashes hiding in the same week<\/h2>\n<p data-path-to-node=\"6\">The first one turned up almost immediately. Using <code data-path-to-node=\"6\" data-index-in-node=\"50\">Hit<\/code> on an object that has no hit handler crashed the game outright. The <code data-path-to-node=\"6\" data-index-in-node=\"122\">CALL<\/code> opcode was popping the script list unconditionally once the callee had run, but the loader only pushes a script when the function actually exists. Call something that isn&#8217;t there, and the engine cheerfully popped the caller instead, leaving the reference the interpreter was still holding dangling \u2014 and the next assignment freed the same instruction array a second time. The original engine reserves the slot before the call and always removes that same slot, so the list stays balanced either way. Now the pop only happens when a script was really pushed.<\/p>\n<p data-path-to-node=\"7\">The second was much shorter to write down: the routine that asks the player for text deleted the open dialog without clearing the pointer, then called into code that begins by closing the dialog and deleting that very same pointer. Two lines removed, one double free gone.<\/p>\n<h2 data-path-to-node=\"8\">The flashlight that did nothing<\/h2>\n<p data-path-to-node=\"9\">This was my favourite bug of the week, because the fix was really an apology for an older workaround.<\/p>\n<p data-path-to-node=\"10\">In <i data-path-to-node=\"10\" data-index-in-node=\"3\">D\u00e9j\u00e0 Vu II<\/i> you find a flashlight, you click <code data-path-to-node=\"10\" data-index-in-node=\"47\">Operate<\/code>, you click the flashlight \u2014 and nothing happens. The cause went back a long way: the destination object was being pushed into the selection queue, so every two-object command also ran a second time on its own destination. Someone had patched around that by skipping the destination while running the queue, which does stop the duplicate \u2014 and also makes any command whose target is the source do precisely nothing.<\/p>\n<p data-path-to-node=\"11\">The real fix was to stop putting the destination in the queue in the first place and track it in the highlight list instead, which is what the original engine does. Operating an object on itself works again, and the duplicated command stays gone.<\/p>\n<h2 data-path-to-node=\"12\">Selecting more than one thing<\/h2>\n<p data-path-to-node=\"13\">Shift-clicking is supposed to add an object to the selection rather than replace it, so you can grab a handful of items and drag them together. Dragging already knew how to handle groups; only the selecting was missing, and it was missing in three places at once. The shift state never reached the engine because the cursor code always passed <code data-path-to-node=\"13\" data-index-in-node=\"343\">false<\/code>. The selection call passed its last two arguments in the wrong order, so the shift flag arrived where the double-click flag was expected. And the shift branch itself was still an empty stub.<\/p>\n<p data-path-to-node=\"14\">Fixing the argument order was the interesting part, because it immediately exposed a second call that had been quietly landing in that empty branch on the release of every single click. With the flags the right way round it suddenly started activating objects instead. It turned out to have no other purpose, so it is now gone.<\/p>\n<h2 data-path-to-node=\"15\">Small corrections, real consequences<\/h2>\n<p data-path-to-node=\"16\">Two one-liners worth mentioning. The <code data-path-to-node=\"16\" data-index-in-node=\"37\">random<\/code> opcode was returning a value between zero and the maximum inclusive, where the original returns a value strictly below it \u2014 which means every script indexing a table with that result had a chance of reading one entry past the end. And object updates were being dropped whenever the object already had an entry in the queue, except the queue also holds window entries, which are dispatched later. While one of those was pending, an object could change without its window ever being told, so the change only appeared once you re-entered the room.<\/p>\n<h2 data-path-to-node=\"17\">Buttons that feel like buttons<\/h2>\n<p data-path-to-node=\"18\">Dialog buttons were firing their action the instant the mouse went down, and never showed that they were being held. The original inverts a button while it is pressed, de-inverts it when the pointer leaves, and only acts on release inside the bounds \u2014 so a misplaced click can still be taken back by dragging away before letting go. The action is now also tied to a press that started on that same button, so a stray release left over from whatever opened the dialog can&#8217;t trigger one.<\/p>\n<h2 data-path-to-node=\"19\">The one that got away<\/h2>\n<p data-path-to-node=\"20\">Some sounds in <i data-path-to-node=\"20\" data-index-in-node=\"15\">D\u00e9j\u00e0 Vu II<\/i> still log &#8220;unrecognized sound type&#8221;. I spent a while on it before working out that those entries are not audio at all: they are <code data-path-to-node=\"20\" data-index-in-node=\"154\">68k CODE<\/code> resources, and the original played them by executing the code. Fifteen of the twenty sounds play correctly; the rest would need actual 68k emulation, which is well beyond a bug fix. It goes on the list as a known limitation rather than a regression.<\/p>\n<h2 data-path-to-node=\"21\">Shipping it<\/h2>\n<p data-path-to-node=\"22\">With the playtesting done, the last commits of the summer were the boring, satisfying ones: the MacVenture engine is now enabled by default in <code data-path-to-node=\"22\" data-index-in-node=\"143\">configure<\/code>, the Macintosh releases are promoted from unstable to testing, and my name went into the engine credits.<\/p>\n<h2 data-path-to-node=\"23\">That&#8217;s a wrap<\/h2>\n<p data-path-to-node=\"24\">And that is the twelfth and final week. I will be putting together a proper final report shortly \u2014 one page with everything I worked on this summer, every pull request, and an honest list of what is still left to do \u2014 and linking it from here.<\/p>\n<p data-path-to-node=\"24\"><a href=\"https:\/\/blogs.scummvm.org\/andy\/2026\/08\/18\/the-final-post\/\">Link to the final post<\/a><\/p>\n<p data-path-to-node=\"25\">Twelve weeks ago I had never touched either of these engines. <i data-path-to-node=\"25\" data-index-in-node=\"62\">Chamber of the Sci-Mutant Priestess<\/i> now runs in EGA, CGA, Hercules and on Amiga, and MacVenture is heading for a release. I have learned more about coordinate systems, byte order and other people&#8217;s workarounds than I expected to.<\/p>\n<p data-path-to-node=\"26\">Huge thanks to my mentors for the steady guidance and patience all summer \u2014 this was genuinely a great one.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Last week I fixed the remaining problems with D\u00e9j\u00e0 Vu, and\u00a0 this week I opened D\u00e9j\u00e0 Vu II and started again from the top, notebook in hand. It is the same engine, the same tooling, and the same approach as before, but a different game exercises different corners of the code \u2014 and it found [&hellip;]<\/p>\n","protected":false},"author":31,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-102","post","type-post","status-publish","format-standard","hentry","category-gsoc-2026"],"_links":{"self":[{"href":"https:\/\/blogs.scummvm.org\/andy\/wp-json\/wp\/v2\/posts\/102","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.scummvm.org\/andy\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.scummvm.org\/andy\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.scummvm.org\/andy\/wp-json\/wp\/v2\/users\/31"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.scummvm.org\/andy\/wp-json\/wp\/v2\/comments?post=102"}],"version-history":[{"count":6,"href":"https:\/\/blogs.scummvm.org\/andy\/wp-json\/wp\/v2\/posts\/102\/revisions"}],"predecessor-version":[{"id":115,"href":"https:\/\/blogs.scummvm.org\/andy\/wp-json\/wp\/v2\/posts\/102\/revisions\/115"}],"wp:attachment":[{"href":"https:\/\/blogs.scummvm.org\/andy\/wp-json\/wp\/v2\/media?parent=102"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.scummvm.org\/andy\/wp-json\/wp\/v2\/categories?post=102"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.scummvm.org\/andy\/wp-json\/wp\/v2\/tags?post=102"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}