{"id":70,"date":"2021-08-17T11:07:55","date_gmt":"2021-08-17T11:07:55","guid":{"rendered":"https:\/\/blogs.scummvm.org\/ayyg\/?p=70"},"modified":"2022-05-26T15:25:21","modified_gmt":"2022-05-26T06:25:21","slug":"progress-report-end","status":"publish","type":"post","link":"https:\/\/blogs.scummvm.org\/ayyg\/2021\/08\/17\/progress-report-end\/","title":{"rendered":"Progress Report (End?)"},"content":{"rendered":"\r\n<p>The coding phase of GSoC is basically over, so this will be the last GSoC-related progress post. We&#8217;ll be going over what has progressed since the last post and what challenges are left to face post-GSoC. With that in mind, the next post will be my actual last GSoC post.<\/p>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\">Playtesting<\/h2>\r\n\r\n\r\n\r\n<p>Playtesting is over! The ride was surprisingly smooth until around 50-60% of the game in, but I experienced a few issues during the second half. Here are the additional bugs and the way I fixed them:<\/p>\r\n\r\n\r\n\r\n<figure class=\"wp-block-table\">\r\n<table>\r\n<tbody>\r\n<tr>\r\n<td class=\"has-text-align-center\" data-align=\"center\">Bug<\/td>\r\n<td class=\"has-text-align-center\" data-align=\"center\">Steps to reproduce<\/td>\r\n<td class=\"has-text-align-center\" data-align=\"center\">Explanation<\/td>\r\n<td>Solved<\/td>\r\n<\/tr>\r\n<tr>\r\n<td class=\"has-text-align-center\" data-align=\"center\">Actors loading with the wrong appearance<\/td>\r\n<td class=\"has-text-align-center\" data-align=\"center\">?<\/td>\r\n<td class=\"has-text-align-center\" data-align=\"center\">Sometimes some actors seem to load with mismatched appearance (i.e., Frost Giant as Flame Giant, etc.)<\/td>\r\n<td>No<\/td>\r\n<\/tr>\r\n<tr>\r\n<td class=\"has-text-align-center\" data-align=\"center\">Return key not working on save dialog<\/td>\r\n<td class=\"has-text-align-center\" data-align=\"center\">\u00a0<\/td>\r\n<td class=\"has-text-align-center\" data-align=\"center\">The return key should save the file and close the dialog when pressed. This does not happen.<\/td>\r\n<td>Yes<\/td>\r\n<\/tr>\r\n<tr>\r\n<td class=\"has-text-align-center\" data-align=\"center\">The captain does not sail you to Tamnath Ruins<\/td>\r\n<td class=\"has-text-align-center\" data-align=\"center\">Defeat Maldavith and then talk to Captain Navis.<\/td>\r\n<td class=\"has-text-align-center\" data-align=\"center\">After killing Muybridge in the cave below Maldavith, Captain Navis should allow you passage to the Tamnath Ruins through his ship. This does not happen.<\/td>\r\n<td>Yes?<\/td>\r\n<\/tr>\r\n<tr>\r\n<td class=\"has-text-align-center\" data-align=\"center\">Crash when turning the lever inside Tamnath Ruins<\/td>\r\n<td class=\"has-text-align-center\" data-align=\"center\">Turn the leftmost lever inside the rightmost building.<\/td>\r\n<td class=\"has-text-align-center\" data-align=\"center\">Three levers need to be operated to get one of the Tapstones. One of these lavers causes the game to crash when interacted with.<\/td>\r\n<td>Yes<\/td>\r\n<\/tr>\r\n<tr>\r\n<td class=\"has-text-align-center\" data-align=\"center\">Audio crash in Underworld<\/td>\r\n<td class=\"has-text-align-center\" data-align=\"center\">Walk through the plane behind the huge door blocking passage to Sariloth&#8217;s place.<\/td>\r\n<td class=\"has-text-align-center\" data-align=\"center\">Walking through the passage that leads to Sariloth causes a crash.<\/td>\r\n<td>Yes<\/td>\r\n<\/tr>\r\n<tr>\r\n<td class=\"has-text-align-center\" data-align=\"center\">Timer Save error<\/td>\r\n<td class=\"has-text-align-center\" data-align=\"center\">?<\/td>\r\n<td class=\"has-text-align-center\" data-align=\"center\">Error when saving<\/td>\r\n<td>No<\/td>\r\n<\/tr>\r\n<tr>\r\n<td class=\"has-text-align-center\" data-align=\"center\">Some keys not working on document and automap<\/td>\r\n<td class=\"has-text-align-center\" data-align=\"center\">\u00a0<\/td>\r\n<td class=\"has-text-align-center\" data-align=\"center\">Arrow keys should control the pages when reading a document, and Home\/End\/PgUp\/PgDn should control the automap.<\/td>\r\n<td>Yes<\/td>\r\n<\/tr>\r\n<\/tbody>\r\n<\/table>\r\n<\/figure>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\">Return Key Not Working on Save Dialog<\/h2>\r\n\r\n\r\n\r\n<p>It was simply a matter of if\/else if logic order not making sense.<\/p>\r\n\r\n\r\n\r\n<p><em>Fix: Rearrange the conditionals.<\/em><\/p>\r\n\r\n\r\n\r\n<p><a href=\"https:\/\/github.com\/scummvm\/scummvm\/commit\/079330547048d11ab0151ef6e100d66e3902b96a\">https:\/\/github.com\/scummvm\/scummvm\/commit\/079330547048d11ab0151ef6e100d66e3902b96a<\/a><\/p>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\">Captain Does Not Sail You<\/h2>\r\n\r\n\r\n\r\n<p>This was (and still is) a mystery. I spent an entire day tracing the scripts to figure out what was going wrong, but this requires even further digging.<\/p>\r\n\r\n\r\n\r\n<p>I&#8217;ll explain briefly how the dialogue script flow goes:<\/p>\r\n\r\n\r\n\r\n<p>When you double click on an actor, the method <code>Actor::greetActor<\/code> is run. This, in turn, causes a <code>runObjectMethod<\/code> call that calls some scripts, which then calls <code>Actor::useKnowledge<\/code>. This is illustrated in the backtrace below.<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-code\"><code>#0  Saga2::Actor::useKnowledge(Saga2::scriptCallFrame&amp;) (this=0x6210007375b8, scf=...)\r\n    at engines\/saga2\/actor.cpp:3180\r\n#1  0x0000555555f33499 in Saga2::scriptActorUseKnowledge(short*) () at engines\/saga2\/sagafunc.cpp:1993\r\n#2  0x0000555555e23b1d in Saga2::Thread::interpret() (this=0x60b00005bc10) at engines\/saga2\/interp.cpp:877\r\n#3  0x0000555555e2b601 in Saga2::Thread::run() (this=0x60b00005bc10) at engines\/saga2\/interp.cpp:1653\r\n#4  0x0000555555e2ce43 in Saga2::runMethod(unsigned short, short, unsigned short, unsigned short, Saga2::scri\r\nptCallFrame&amp;) (scriptClassID=13, bType=-1, index=32800, methodNum=136, args=...)\r\n    at engines\/saga2\/interp.cpp:1875\r\n#5  0x0000555555e2d017 in Saga2::runObjectMethod(unsigned short, unsigned short, Saga2::scriptCallFrame&amp;)\r\n    (id=32800, methodNum=136, args=...) at engines\/saga2\/interp.cpp:1897\r\n#6  0x0000555555d7fa5e in Saga2::ActorProto::greetActor(unsigned short, unsigned short)\r\n    (this=0x608000044220, dObj=32800, enactor=32768) at engines\/saga2\/actor.cpp:355<\/code><\/pre>\r\n\r\n\r\n\r\n<p><code>Actor::useKnowledge<\/code> decides which dialogue response to give and calls the speech methods, again, through SAGA scripts.<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-code\"><code>res = runMethod(knowledge[i],\r\n                builtinAbstract,\r\n                0,\r\n                Method_KnowledgePackage_evalResponse,\r\n                scf);<\/code><\/pre>\r\n\r\n\r\n\r\n<p>The above code is a call to evaluate the given knowledge to decide which response to give. This is where the problem starts. The script that is called with <code>knowledge[2]<\/code> for Captain Navis has a conditional branch within it. Depending on the result of the conditional, the resulting dialogue changes.<\/p>\r\n\r\n\r\n\r\n<p>Here is a snippet of the script execution log:<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-code\"><code>[0241 0x00f1]: op_getint\r\nIMMED_WORD(130 0x0082)\r\nIMMED_WORD(2862 0x0b2e)\r\nbyteAddress: far[130:2862] = 0\r\nstack size: 3: [0 -32655 512 ]\r\n[0247 0x00f7]: op_jmp_true_v    &lt;-- if (getint(130, 2862)) jmp<\/code><\/pre>\r\n\r\n\r\n\r\n<p>The <code>jmp<\/code> instruction in the last line is the culprit. It takes in the leftmost (most recent) value in the stack, and if it is different than 0, it jumps. Here, the leftmost value is 0, so we do not branch out. However, if we actually take the true branch, the correct dialogue option appears.<\/p>\r\n\r\n\r\n\r\n<div class=\"wp-block-image\">\r\n<figure class=\"aligncenter\">\r\n<figure id=\"attachment_124\" aria-describedby=\"caption-attachment-124\" style=\"width: 513px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/blogs.scummvm.org\/ayyg\/wp-content\/uploads\/sites\/7\/2021\/08\/unknown.png\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-124\" src=\"https:\/\/blogs.scummvm.org\/ayyg\/wp-content\/uploads\/sites\/7\/2021\/08\/unknown.png\" alt=\"\" width=\"513\" height=\"385\" srcset=\"https:\/\/blogs.scummvm.org\/ayyg\/wp-content\/uploads\/sites\/7\/2021\/08\/unknown.png 513w, https:\/\/blogs.scummvm.org\/ayyg\/wp-content\/uploads\/sites\/7\/2021\/08\/unknown-300x225.png 300w, https:\/\/blogs.scummvm.org\/ayyg\/wp-content\/uploads\/sites\/7\/2021\/08\/unknown-480x360.png 480w\" sizes=\"auto, (max-width: 513px) 100vw, 513px\" \/><\/a><figcaption id=\"caption-attachment-124\" class=\"wp-caption-text\">Wrong dialogue option (false branch)<\/figcaption><\/figure>\r\n<\/figure>\r\n<\/div>\r\n\r\n\r\n\r\n<div class=\"wp-block-image\">\r\n<figure class=\"aligncenter\">\r\n<figure id=\"attachment_125\" aria-describedby=\"caption-attachment-125\" style=\"width: 513px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/blogs.scummvm.org\/ayyg\/wp-content\/uploads\/sites\/7\/2021\/08\/unknown_2.png\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-125\" src=\"https:\/\/blogs.scummvm.org\/ayyg\/wp-content\/uploads\/sites\/7\/2021\/08\/unknown_2.png\" alt=\"\" width=\"513\" height=\"385\" srcset=\"https:\/\/blogs.scummvm.org\/ayyg\/wp-content\/uploads\/sites\/7\/2021\/08\/unknown_2.png 513w, https:\/\/blogs.scummvm.org\/ayyg\/wp-content\/uploads\/sites\/7\/2021\/08\/unknown_2-300x225.png 300w, https:\/\/blogs.scummvm.org\/ayyg\/wp-content\/uploads\/sites\/7\/2021\/08\/unknown_2-480x360.png 480w\" sizes=\"auto, (max-width: 513px) 100vw, 513px\" \/><\/a><figcaption id=\"caption-attachment-125\" class=\"wp-caption-text\">Right dialogue option (true branch)<\/figcaption><\/figure>\r\n<\/figure>\r\n<\/div>\r\n\r\n\r\n\r\n<p>To figure out the reason for this miss, we&#8217;d have to dig further. Since we do not have that much time to waste, I decided to just implement a workaround for this particular issue since I didn&#8217;t experience any problem anywhere else.<\/p>\r\n\r\n\r\n\r\n<p><em>Fix: Implement workaround for method <code>byteAddress<\/code> when <code>seg = 130 &amp;&amp; offset == 2862<\/code>. <\/em><\/p>\r\n\r\n\r\n\r\n<p><a href=\"https:\/\/github.com\/scummvm\/scummvm\/commit\/876126f7b83ab8ae658b8278a6cf44128002e757\">https:\/\/github.com\/scummvm\/scummvm\/commit\/876126f7b83ab8ae658b8278a6cf44128002e757<\/a><\/p>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\">Tamnath Ruins Lever Crash<\/h2>\r\n\r\n\r\n\r\n<p>Here we had some nullptr accesses combined with uninitialized wild pointer accesses, so I just added checks.<\/p>\r\n\r\n\r\n\r\n<p><em>Fix: Add nullptr checks and initialize pointers.<\/em><\/p>\r\n\r\n\r\n\r\n<p><a href=\"https:\/\/github.com\/scummvm\/scummvm\/commit\/29c5f6e7494d46fa0b927507251d150b8b7879d6\">https:\/\/github.com\/scummvm\/scummvm\/commit\/29c5f6e7494d46fa0b927507251d150b8b7879d6<\/a><\/p>\r\n\r\n\r\n\r\n<p><a href=\"https:\/\/github.com\/scummvm\/scummvm\/commit\/fb15fce9d68c52a500a0832d2ee4419a83ecdc6d\">https:\/\/github.com\/scummvm\/scummvm\/commit\/fb15fce9d68c52a500a0832d2ee4419a83ecdc6d<\/a><\/p>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\">Audio Crash in Underworld<\/h2>\r\n\r\n\r\n\r\n<p>Here a track beyond our track limit was attempted to be played, resulting in a heap buffer overflow which ASAN detected. This would likely not result in anything significant for a normal playthrough (which is why it remained dormant so far).<\/p>\r\n\r\n\r\n\r\n<p>Fix: Add checks around the track number in <code>audioEnvironmentCheck<\/code>.<\/p>\r\n\r\n\r\n\r\n<p><a href=\"https:\/\/github.com\/scummvm\/scummvm\/commit\/87b1f858e5eddf3028ee8958074723c038fbdd69\">https:\/\/github.com\/scummvm\/scummvm\/commit\/87b1f858e5eddf3028ee8958074723c038fbdd69<\/a><\/p>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\">Document\/Automap Keys<\/h2>\r\n\r\n\r\n\r\n<p>There were still instances of the original keyboard detection method <code>SpecialKey<\/code> being used, so I replaced those.<\/p>\r\n\r\n\r\n\r\n<p>Fix: Replace <code>SpecialKey<\/code> by <code>Common::KeyState<\/code>.<\/p>\r\n\r\n\r\n\r\n<p><a href=\"https:\/\/github.com\/scummvm\/scummvm\/commit\/81909e6dabffe56949ff410c4c387aea4b71934a\">https:\/\/github.com\/scummvm\/scummvm\/commit\/81909e6dabffe56949ff410c4c387aea4b71934a<\/a><\/p>\r\n\r\n\r\n<hr class=\"wp-block-separator\" \/>\r\n\r\n\r\n<p>I fixed quite a few of the bugs we had discovered previously as well.<\/p>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\">Tooltip Clipping Off-screen<\/h2>\r\n\r\n\r\n\r\n<p>This was the result of <code>g_vm-&gt;_pointer<\/code>&#8216;s internal parameters not being adjusted properly.<\/p>\r\n\r\n\r\n\r\n<p>Fix: Call <code>gPointer::move<\/code> properly.<\/p>\r\n\r\n\r\n\r\n<p><a href=\"https:\/\/github.com\/scummvm\/scummvm\/commit\/9e894a82d63a5a69c299c4a620e63b182b87c607\">https:\/\/github.com\/scummvm\/scummvm\/commit\/9e894a82d63a5a69c299c4a620e63b182b87c607<\/a><\/p>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\">Staff Of Life Crash<\/h2>\r\n\r\n\r\n\r\n<p>The SAGA Script for the Staff Of Life called the method <code>Object2Actor<\/code>, which returned the ObjectID of the object if it was an actor, or 0 otherwise. This causes an error because the 0th object is a dummy without scripts.<\/p>\r\n\r\n\r\n\r\n<p><em>Fix: Make the Object2Actor method always return the ObjectID.<\/em><\/p>\r\n\r\n\r\n\r\n<p><a href=\"https:\/\/github.com\/scummvm\/scummvm\/commit\/0e6813338292fd0494eb2cc4f6b7dc4d7333bb38\">https:\/\/github.com\/scummvm\/scummvm\/commit\/0e6813338292fd0494eb2cc4f6b7dc4d7333bb38<\/a><\/p>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\">Midair Item Interaction Crash<\/h2>\r\n\r\n\r\n\r\n<p>When an object is in midair, it has no parents, so interacting with it in this state causes a crash.<\/p>\r\n\r\n\r\n\r\n<p><em>Fix: Change the <code>getMapNum<\/code> method to return the sibling&#8217;s parentID if the current one has no parent.<\/em><\/p>\r\n\r\n\r\n\r\n<p><a href=\"https:\/\/github.com\/scummvm\/scummvm\/commit\/974d4dd81eb92c7db1c66928dd841241b6ae0264\">https:\/\/github.com\/scummvm\/scummvm\/commit\/974d4dd81eb92c7db1c66928dd841241b6ae0264<\/a><\/p>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\">Book Text Missing Last Character<\/h2>\r\n\r\n\r\n\r\n<p>This was due to a wrong <code>strlycpy<\/code> range in <code>document.cpp<\/code>.<\/p>\r\n\r\n\r\n\r\n<p><em>Fix: Use the correct range for <code>strlcpy<\/code>.<\/em><\/p>\r\n\r\n\r\n\r\n<p><a href=\"https:\/\/github.com\/scummvm\/scummvm\/commit\/0bdf49fb71baac25f8c9856cdf55ce3127271e5a\">https:\/\/github.com\/scummvm\/scummvm\/commit\/0bdf49fb71baac25f8c9856cdf55ce3127271e5a<\/a><\/p>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\">Music Not Looping<\/h2>\r\n\r\n\r\n\r\n<p>The flag for music looping was not ever actually set. Is this due to differences in the binary executable distributed to us and the actual source we got?<\/p>\r\n\r\n\r\n\r\n<p><em>Fix: Set the loop flag to true.<\/em><\/p>\r\n\r\n\r\n\r\n<p><a href=\"https:\/\/github.com\/scummvm\/scummvm\/commit\/994ac18c52785e69213e2312f435f73fa76ef75b\">https:\/\/github.com\/scummvm\/scummvm\/commit\/994ac18c52785e69213e2312f435f73fa76ef75b<\/a><\/p>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\">SpellID Saves<\/h2>\r\n\r\n\r\n\r\n<p>Previously we discussed how I would have to find out the correct size for enums, but then never actually did. Turns out that is actually necessary since saving with spells present brings out compatibility issues with the original.<\/p>\r\n\r\n\r\n\r\n<p><em>Fix: Change saved SpellID size from 4 bytes to 1 byte.<\/em><\/p>\r\n\r\n\r\n\r\n<p><a href=\"https:\/\/github.com\/scummvm\/scummvm\/commit\/aac41f36f8347c94ce06c0505c6ca138f3c2331b\">https:\/\/github.com\/scummvm\/scummvm\/commit\/aac41f36f8347c94ce06c0505c6ca138f3c2331b<\/a><\/p>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\">Console Commands<\/h2>\r\n\r\n\r\n\r\n<p>I added two new debug commands, as well as extended an existing one:<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-code\"><code>\/\/ Input: &lt;1\/0&gt;. Sets whether you can teleport by right clicking on the screen.\r\nbool cmdTeleportOnClick(int argc, const char **argv);\r\n\r\n\/\/ Input: &lt;1\/0&gt;. Sets whether you can teleport by clicking on the map.\r\nbool cmdTeleportOnMap(int argc, const char **argv);\r\n\r\n\/\/ Input: &lt;1\/0&gt;. Sets the invisibility effect on the party.\r\nbool cmdInvisibility(int argc, const char **argv);<\/code><\/pre>\r\n\r\n\r\n\r\n<p><code>TeleportOnClick<\/code> now teleports the player with the right click (so we don&#8217;t have to continuously turn it on and off). Also, shift + right-click teleport the entire party.<\/p>\r\n\r\n\r\n\r\n<p><code>TeleportOnMap<\/code> causes the player to teleport to where they clicked on the map.<\/p>\r\n\r\n\r\n\r\n<p><code>Invisibility<\/code> sets the player characters invisible. Great for teleporting around the map without engaging in battle!<\/p>\r\n\r\n\r\n<hr class=\"wp-block-separator\" \/>\r\n\r\n\r\n<h2 class=\"wp-block-heading\">What is left?<\/h2>\r\n\r\n\r\n\r\n<p>I believe it is safe to say that most of the engine has complete functionality. However, work is still far from over in SAGA2. I will expand on this in a future post detailing the project&#8217;s progress as a whole and what needs to be done. However, a few examples are: code refactoring to comply with ScummVM&#8217;s naming conventions; playtesting on devices of different architecture; fixing existing issues that have only been remedied, like the scripts and further debugging of tasks.<\/p>\r\n\r\n\r\n\r\n<p>This was a fun ride, and I learned a whole ton. I am extremely grateful to my mentor and the other members of the ScummVM community. Although I can&#8217;t make any concrete promises, I plan on continuing to update SAGA2 outside of GSoC in my free time when possible since I believe this engine has much more to offer.<\/p>\r\n","protected":false},"excerpt":{"rendered":"<p>The coding phase of GSoC is basically over, so this will be the last GSoC-related progress post. We&#8217;ll be going over what has progressed since the last post and what challenges are left to face post-GSoC. With that in mind, the next post will be my actual last GSoC post. Playtesting Playtesting is over! The [&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-70","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/blogs.scummvm.org\/ayyg\/wp-json\/wp\/v2\/posts\/70","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=70"}],"version-history":[{"count":7,"href":"https:\/\/blogs.scummvm.org\/ayyg\/wp-json\/wp\/v2\/posts\/70\/revisions"}],"predecessor-version":[{"id":127,"href":"https:\/\/blogs.scummvm.org\/ayyg\/wp-json\/wp\/v2\/posts\/70\/revisions\/127"}],"wp:attachment":[{"href":"https:\/\/blogs.scummvm.org\/ayyg\/wp-json\/wp\/v2\/media?parent=70"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.scummvm.org\/ayyg\/wp-json\/wp\/v2\/categories?post=70"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.scummvm.org\/ayyg\/wp-json\/wp\/v2\/tags?post=70"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}