{"id":66,"date":"2021-08-10T06:18:57","date_gmt":"2021-08-10T06:18:57","guid":{"rendered":"https:\/\/blogs.scummvm.org\/ayyg\/?p=66"},"modified":"2021-08-10T06:18:57","modified_gmt":"2021-08-10T06:18:57","slug":"the-middle-of-the-end-progress-report","status":"publish","type":"post","link":"https:\/\/blogs.scummvm.org\/ayyg\/2021\/08\/10\/the-middle-of-the-end-progress-report\/","title":{"rendered":"The Middle of The End (Progress Report)"},"content":{"rendered":"\n<p>Less than two weeks left of coding. My summer break officially started, so I can spend copious amounts of time playtesting the game now!<\/p>\n\n\n\n<p>So far, I&#8217;m about 9-10 hours into the game&#8217;s storyline (my save&#8217;s playtime says I&#8217;m 27 hours into it, but that&#8217;s due to me sidetracking into bug testing). This is around the halfway point of the game. Surprisingly, though, I did not find as many bugs as I thought I would, and most of the ones I did were harmless (except for one or two).<\/p>\n\n\n\n<p>I&#8217;ll first talk about the bugs from the last blog post that I was able to fix and then proceed to present the newly discovered bugs.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Sound Effects Not Syncrhonizing<\/h2>\n\n\n\n<p>The sound system worked in SAGA2 at the start in the following way: we queued all sounds played, be they voices, sound effects, or music, and played them every time in the game loop. Music was redesigned to not use the queue system, and it looks like sound effects needed the same treatment.<\/p>\n\n\n\n<p><em>Fix: Remove the check for when the sound effect handle is active.<\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\tdelete stream;\n\t}\n\n---\tif (_sfxQueue.size() &gt; 0 &amp;&amp; !_mixer-&gt;isSoundHandleActive(_sfxSoundHandle)) {\n+++\tif (_sfxQueue.size() &gt; 0) {\n\t\tSoundInstance si = _sfxQueue.pop();\n\n\t\tCommon::SeekableReadStream *stream = loadResourceToStream(soundRes, si.seg, \"sound data\");<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Doors Not Opening<\/h2>\n\n\n\n<p>This one is simple. Certain doors (read: ActiveItems) in the map were non-interactable because the algorithm for accessing their instance was wrong. The original implemented a linked hash map for accessing the ActiveItems. In the process of refactoring, I forgot to include the &#8220;linked&#8221; part, which means we were accessing the wrong ActiveItem when they had the same hash key.<\/p>\n\n\n\n<p>Fix: <em>Restore the linked hash map design.<\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\t\t\t           + ai-&gt;_data.instance.v + (ai-&gt;_data.instance.groupID &lt;&lt; 2))\n\t\t\t          % ARRAYSIZE(instHash);\n\n---\t\t\titemHash.setVal(hashVal, ai);\n+++\t\t\tai-&gt;_nextHash = instHash&#091;hashVal];\n+++\t\t\tinstHash&#091;hashVal] = ai;\n\t\t}\n\t}\n}<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>\tint16           hashVal = (((tp.u + tp.z) &lt;&lt; 4) + tp.v + (group &lt;&lt; 2))\n\t                          % ARRAYSIZE(instHash);\n\n\n---\tif (itemHash.contains(hashVal))\n---\t\treturn itemHash.getVal(hashVal);\n+++\tfor (ActiveItem *ai = instHash&#091;hashVal]; ai; ai = ai-&gt;_nextHash) {\n+++\t\tif (ai-&gt;_data.instance.u == tp.u &amp;&amp;\n+++\t\t    ai-&gt;_data.instance.v == tp.v &amp;&amp;\n+++\t\t    ai-&gt;_data.instance.h == tp.z &amp;&amp;\n+++\t\t    ai-&gt;_data.instance.groupID == group)\n+++\t\t\treturn ai;\n+++\t}\n\n\treturn nullptr;\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Crash After Saving<\/h2>\n\n\n\n<p>This one was difficult to debug because it crashed at places that seemed completely unrelated, and the ASAN report said the pointer that had tried to be accessed was wild. After some testing, though, I realized that it only occurred after saving the game. That meant it had to be something in the saving methods.<br>Turns out the cause was an array that I accidentally modified within <em>saveActiveItemStates<\/em>.<\/p>\n\n\n\n<p><em>Fix: Use a local buffer for saving<\/em>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\t\/\/  Get a pointer to the current active item's state\n\t\/\/  data in the archive buffer\n---\tstatePtr = &amp;stateArray&#091;i]&#091;activeItem-&gt;_data.instance.stateIndex];\n+++\tstatePtr = &amp;bufferedStateArray&#091;activeItem-&gt;_data.instance.stateIndex];\n\n\t\/\/  Set the high bit of the state value based upon the\n\t\/\/  active item's locked state<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Bugs<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td class=\"has-text-align-center\" data-align=\"center\">Bug<\/td><td class=\"has-text-align-center\" data-align=\"center\">Steps to reproduce<\/td><td class=\"has-text-align-center\" data-align=\"center\">Explanation<\/td><td>Solved<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">Speech not finishing before dialog to buy item starts.<\/td><td class=\"has-text-align-center\" data-align=\"center\">Talk to any merchant and select an item fast.<\/td><td class=\"has-text-align-center\" data-align=\"center\">The entire line of dialogue is supposed to be spoken before the dialogue proceeds.<\/td><td>Yes<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">Bands not loading correctly.<\/td><td class=\"has-text-align-center\" data-align=\"center\">Save and load the game when multiple bands are present.<\/td><td class=\"has-text-align-center\" data-align=\"center\">It crashes.<\/td><td>Yes<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">Tooltip for armor status clips off-screen.<\/td><td class=\"has-text-align-center\" data-align=\"center\"><\/td><td class=\"has-text-align-center\" data-align=\"center\">It should shift off-center to make space for the text.<\/td><td>No<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">Crash when using Staff of Life on non-PCs.<\/td><td class=\"has-text-align-center\" data-align=\"center\"><\/td><td class=\"has-text-align-center\" data-align=\"center\">When used on non-PCs, it should display the message &#8220;BreadStick only works on PC&#8217;s.&#8221;<\/td><td>No<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">Crash when interacting with items in midair.<\/td><td class=\"has-text-align-center\" data-align=\"center\">Throw a spell scroll\/potion and try learning\/drinking it while it is midair.<\/td><td class=\"has-text-align-center\" data-align=\"center\">The crash also occurs on DOSBox. Possibly a bug in the original.<\/td><td>No<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">Spell appearance not loading.<\/td><td class=\"has-text-align-center\" data-align=\"center\">Example: Fireball trap in the Goblin Cave. Minor Healing. Exception: Fireball<\/td><td class=\"has-text-align-center\" data-align=\"center\"><\/td><td>No<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">ScummVM sucking up lots of ram over time.<\/td><td class=\"has-text-align-center\" data-align=\"center\">Walk around Bilton.<\/td><td class=\"has-text-align-center\" data-align=\"center\">Memory leak.<\/td><td>Yes<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">The last character in a book&#8217;s text is missing.<\/td><td class=\"has-text-align-center\" data-align=\"center\"><\/td><td class=\"has-text-align-center\" data-align=\"center\">The last character on the last page is missing.<\/td><td>No<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">Task Stack limit of 32 reached.<\/td><td class=\"has-text-align-center\" data-align=\"center\">Walk around places with many actors. (Example: Bilton; Castle Jovang)<\/td><td class=\"has-text-align-center\" data-align=\"center\">The original ignores task\/task stacks that overflow. Expected behavior?<\/td><td>No<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">Task limit of 64 reached.<\/td><td class=\"has-text-align-center\" data-align=\"center\">\u2191<\/td><td class=\"has-text-align-center\" data-align=\"center\">\u2191<\/td><td>No<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Speech Not Finishing Before Dialogue<\/h2>\n\n\n\n<p>The problem is that a single line of dialogue may consist of multiple voice lines. This is especially true in the case of merchant dialogue lines. Our implementation of <code>stillDoingVoice<\/code> only checked for the first voice line in a dialogue, so we fix that.<\/p>\n\n\n\n<p>Fix: Allow <code>stillDoingVoice<\/code> to check for an arr<em>ay of voice lines.<\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>bool stillDoingVoice(uint32 s&#091;]);\n...\nbool stillDoingVoice(uint32 s&#091;]) {\n\tuint32 *p = s;\n\n\twhile (*p) {\n\t\tif (audio-&gt;saying(*p++))\n\t\t\treturn true;\n\t}\n\n\treturn false;\n}<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>bool Speech::longEnough(void) {\n\tif (speechFlags &amp; spHasVoice)\n---\t\treturn (!stillDoingVoice(sampleID&#091;0]));\n+++\t\treturn (!stillDoingVoice(sampleID));\n\telse\n\t\treturn (selectedButton != 0 || speechFinished.check());\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Bands Not Loading Correctly<\/h2>\n\n\n\n<p>The problem is that when loading bands, we add them twice to the global BandList, which causes a crash later on.<\/p>\n\n\n\n<p><em>Fix: Remove the line of code that adds the band to <code>g_vm-&gt;_bandLists<\/code> in <code>Band::Band(InSaveFile *in)<\/code>.<\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\t\tdebugC(4, kDebugSaveload , \"... id = %d\", id);\n\t}\n\n---\tg_vm-&gt;_bandList-&gt;addBand(this);\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Memory Leak<\/h2>\n\n\n\n<p>Over time my ScummVM was reaching 50% of RAM usage. This clearly indicated a resource leak somewhere. I spent some time thinking of ways to catch the memory leak before remembering ASAN reported the memory leaks when starting ScummVM without gdb.<\/p>\n\n\n\n<p>Turns out the cause was in <code>fetchPlatform<\/code>, where I forgot to delete the stream I loaded.<\/p>\n\n\n\n<p><em>Fix: Properly delete the resource in <code>fetchPlatform<\/code>.<\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\tif ((stream = loadResourceToStream(tileRes, platformID + mapNum, \"platform\"))) {\n\t\tif (stream-&gt;skip(plIndex * sizeof(Platform))) {\n\t\t\tpce-&gt;pl.load(stream);\n+++\t\t\tdelete stream;\n\t\t\treturn &amp;pce-&gt;pl;\n\t\t}\n\t}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Console Commands<\/h2>\n\n\n\n<p>I added some new console commands to ease testing:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Teleport the three brothers to the center actor\nbool cmdTeleportPartyHere(int argc, const char **argv);\n\n\/\/ Plays a music track\nbool cmdPlayMusic(int argc, const char **argv);\n\n\/\/ PLays a voice track\nbool cmdPlayVoice(int argc, const char **argv);<\/code><\/pre>\n\n\n\n<p>I&#8217;ve also extended the <code>add_obj<\/code> command to support specifying the number of items added.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>bool Console::cmdAddObj(int argc, const char **argv) {\n\tif (argc == 2) {\n\t\tActor *a = getCenterActor();\n\t\ta-&gt;placeObject(a-&gt;thisID(), atoi(argv&#091;1]));\n\t} else if (argc == 3) {\n\t\tActor *a = getCenterActor();\n\t\tint num = atoi(argv&#091;2]);\n\t\ta-&gt;placeObject(a-&gt;thisID(), atoi(argv&#091;1]), true, num);\n\t} else\n\t\tdebugPrintf(\"Usage: %s &lt;ObjectID&gt; &lt;num = 1&gt;\\n\", argv&#091;0]);\n\n\treturn true;\n}<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator\" \/>\n\n\n\n<p>Things are starting to get interesting. To be honest, I&#8217;d love to play this game completely by myself. Unfortunately, we&#8217;re tight on time, and this is playtesting, so I&#8217;m completely following the walkthrough. <em>Big thanks to the uploader, Sinatar.<\/em> Right now I&#8217;m near the end of his second session, which is 10 hours in. Let&#8217;s hope things remain a somewhat smooth ride until the end.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Less than two weeks left of coding. My summer break officially started, so I can spend copious amounts of time playtesting the game now! So far, I&#8217;m about 9-10 hours into the game&#8217;s storyline (my save&#8217;s playtime says I&#8217;m 27 hours into it, but that&#8217;s due to me sidetracking into bug testing). This is around [&hellip;]<\/p>\n","protected":false},"author":7,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-66","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/blogs.scummvm.org\/ayyg\/wp-json\/wp\/v2\/posts\/66","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.scummvm.org\/ayyg\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.scummvm.org\/ayyg\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.scummvm.org\/ayyg\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.scummvm.org\/ayyg\/wp-json\/wp\/v2\/comments?post=66"}],"version-history":[{"count":2,"href":"https:\/\/blogs.scummvm.org\/ayyg\/wp-json\/wp\/v2\/posts\/66\/revisions"}],"predecessor-version":[{"id":72,"href":"https:\/\/blogs.scummvm.org\/ayyg\/wp-json\/wp\/v2\/posts\/66\/revisions\/72"}],"wp:attachment":[{"href":"https:\/\/blogs.scummvm.org\/ayyg\/wp-json\/wp\/v2\/media?parent=66"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.scummvm.org\/ayyg\/wp-json\/wp\/v2\/categories?post=66"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.scummvm.org\/ayyg\/wp-json\/wp\/v2\/tags?post=66"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}