DevBLOG

About Pyrdacor

Pyrdacor's DevBLOG




By Pyrdacor January 19, 2022
There are quite some hidden bugs in Ambermoon which never would have been noticed if it wasn't for the Ambermoon Advanced project. The cursed items feature is very cool in my opinion, but as there is only one single item in the game which is cursed, it left me with the impression of wasted potential. This is why I always wanted to add more of those cursed items. And so I decided to add another one to the mod. There might be more cursed items in later episodes as well of course. This blog article will be very technical. Having some basic knowledge about computers and how they work will definitely be helpful, but I'll try to explain the things that are needed for you to be able to follow. We will actually modify the original Ambermoon executable, add new code and fix two real bugs together. If you want to code/manipulate along, prepare a hex editor of your choice, maybe a decimal to hex and binary to hex converter and if you want to go the full mile, also install Ghidra which I can strongly recommend for reverse engineering. This all is optional of course. If you only want to read, you might skip some parts. As a general rule of thumb: if you don't understand something, first try to read a bit more. Maybe it becomes clearer then. I'll try to explain complex matter with examples. Ghidra can be downloaded at https://ghidra-sre.org . To work with Amiga assemblies I strongly recommend the Amiga hunk plugin in addition which you can find at https://github.com/lab313ru/ghidra_amiga_ld r . Setup Ghidra and install the plugin: Download and install Ghidra Pick the right plugin version from here https://github.com/lab313ru/ghidra_amiga_ldr/releases (download the zip file after expanding "Assets"). Open up Ghidra Select "File -> Install Extensions ..." and click the green plus symbol ("Add extension") Navigate to the downloaded plugin zip file If you picked the right version, the extension should be added Then create a new non-shared project At last you can just drag&drop the Ambermoon executables (e.g. AM2_CPU) from your filesystem into Ghidra If we modify code in this blog article, always use the hex editor. Ghidra is only used for analyzing the assembler instructions or to find something inside the code or data.
By Pyrdacor September 24, 2021
There is no doubt: Ambermoon is huge! Not only the world but also the things you can do. But there are many little details as well. Perhaps some of them are only noticed in the second or third playthrough, if ever. To achieve all this the developers were very creative. They had to, because resources were limited and expectations were high. In this blog we will talk about some cool ideas that made it into the game and especially one of them which partly backfired. Some more examples will follow in detail in later blogposts. While decoding more and more of the game data, some features still remained a mystery to me. And other things were just there unnoticed. It took quite a while to understand what was going on. Especially when multiple things came together. The first story will take place on Morag but on the other hand it will precisely not take place on Morag. And that is the problem. Sounds confusing? Don't worry. I'll take you with me on a trip to some crazy data tricks in Ambermoon. Decoding graphics Let's start with a bit of background information. Graphics are the bread and butter of Ambermoon. Beside the epic music, the lovely fantasy graphics create such a fantastic atmosphere. There are all kinds of graphics and they are stored in so many different files. At the beginning I had to find out where I would find specific graphics, which format they had, etc. The process of finding this out could fill a blogpost on its own, but let's assume I was able to do so somehow. For example at some point I managed to load and extract the graphics of the file Party_gfx.amb and in there I found 3 sequences of player graphics for the 2D indoor maps. Most of the time the filenames give a clue about the content. But Party_gfx could be anything from party member portraits over some party related stuff like HP bars or just the 2D sprites of the player. The latter was the case here, but the 3 sequences only represented the indoor 16x32 pixel frames. So what's about the world maps which use smaller 16x16 sprites? To be honest, I had no clue. I expected them in the same file of course. Was the file corrupt or a wrong version? Was my graphic reader broken? No, there definitely were no other graphics in there. And so... I faked them! Yes you heard right. For a long time I just faked the world map player sprites in the remake. Because I couldn't find them in the data files. I created them from screenshots of the original game. And luckily nobody noticed. Only much later I finally found them in another file: Travel_gfx.amb. I didn't understand the format of that file before that and only found the eagle sprite by accident in there. But I didn't make the connection from the eagle sprite to the normal 2D player sprites. Today I know that the world map uses some kind of travel type. So everything from riding a horse or on the back of an eagle, sailing on a boat or just swimming or walking. As you might see, decoding of every single file and implementing every single aspect of the game was an adventure in itself. But back to the 16x32 pixel party graphics. Those 3 frame sequences of course represent the sprites for each of the 3 worlds: Lyramion, Kire's Moon and Morag. They all look quite similar but the bed sprite was very different for the forest moon version, so you really saw that multiple versions were imporant.
By Pyrdacor September 22, 2021
Ambermoon savegames have a big potential for errors: They store redundant data. For example they store all the items, gold and food a character carries but in addition they also store the total weight. The weight could also be calculated from the other data, so what happens if the value is different from the calculated one? Where it matters the most is bonus stats . Some equipped items grant attributes like strength or skills like swimming or attacking. For example the necromancer dagger grants 2 points of anti-magic and an increase of successful scroll reading of 25%. So far so good. Each item of course stores the information what effects it grants. But now comes the problem. The savegame stores the current value, maximum value and bonus value of all attributes and skills. So if you add up the effects of all the equipped items, it should match the given bonus values. But what if it doesn't? Well, then you will have a problem when you unequip them. For example let's assume the initial savegame stores Targor with an equipped throwing sickle but with a bonus value for the attack skill of 0 (this is actually the case). The throwing sickle grants an attack skill bonus of 10. Now if you start a game, add Targor to your party and unequip the throwing sickle, his attack skill will be crippled by 10 as the game assumes that the bonus was added when equipping the item. Not to mention that he already has 10 attack less to begin with as the bonus value is not set. Another effect of this is that you can no longer maximize your stats. Take the poor Targor again. In-game the value is shown as the sum of current and bonus value, so for example if you currently have 30 attack and a bonus of 10, the game will just show 40. Let's say 40/50 with a max value of 50. You would now think that you can at least reach that 50. But when you have unequipped the item, you have a (hidden) bonus value of -10 (and you can't remove it! it is burnt into your savegame). When you now maximize your stat to the current value of 50, the game will still show only 40/50 as 50 + (-10) is exactly that. This is the reason why those issues were historically reported as "character X can not maximize his attribute/skill Y" instead of "his bonus values are wrong". The original savegames were full of those bonus value corruptions (and still are as we see in a minute). An easy fix would be to load the savegame, calculate all those values and override those redundant values. Unfortunately the original game does not. Interestingly though, it does this with the weight value! But still I consider this a data format issue rather than blaming the loading routine. Storing redundant data is only useful in very rare scenarios and is (as you can see) very error-prone. Not to mention that redundant data in the Ambermoon savegame is unnecessary. Savegame Editor Daniel Schulz created an online savegame editor for Ambermoon a few years ago. In case you don't know, you might want to check it out ( link ). You can edit all the party characters and there is even a nice button to apply equipment effects. The screenshot above is taken from his editor btw. He was aware of many issues regarding equipment bonuses and he fixed a lot of them. He also released his own german patch a while ago which he labeled 1.06. Daniel documented many savegame related fixes as well. As his version was the one with the most fixes, I based my own german patches on that version (therefore I started with 1.07 german). This will matter in a second. Ambermoon Advanced As most of you hopefully know, I started to create a mod for the original Ambermoon. This of course includes changes to the characters (#balancing). And as you can imagine, the mod should be available in all languages. Therefore I opened up my lovely hex editor and started to adjust some bytes. "Oh Selena is quite weak, she should become a bit more max critical strikes. Let's replace that 2 with a 5... Ha, piece of cake. Now move over to the german version and change it as well. Wait a second. There is a 5 already? What the ...?" At this point I noticed a difference in both languages. Shame on me that I never checked that before. The english patches are based on a patch by Meynaf which is itself based on the original english 1.07 version. It also fixes a few savegame issues (namely those which were reported till then). But I didn't know that Daniel Schulz changed so many character values and fixed so much more savegame issues. This was the time for a closer look. I took the english patch 1.10 and the german 1.09 and diffed the character data. Surprisingly there were a lot of differences. This was unexpected. First of all, Daniel changed 5 things which are debatable. All characters got a max swim skill of 99 instead of 95. Selena's max crit was raised from 2 to 5. Nelvin and Tar got higher read magic skill. Nelvin and Tar got higher use magic skill. Tar's current swim skill was raised from 90 to 99. He obviously thought that characters should be able to perfectly swim without getting hurt. At first sight a valid point. But you should know that in Ambermoon the value 95 is always used for the best skilled characters. My assumption is that Karsten Köper thought that even a master in his field can fail to some extent. And 95 is quite a high value in Ambermoon when you consider that your grandpa (the hero of Amberstar) only has an attack skill of 80. How I know that? Well, even every NPC in Ambermoon has their stats set nicely. Even though you can't see most of them in-game. This is commitment! Moreover a swim skill of 95 will still hurt you but mostly you will get only 1 point of damage. To actually die with 100+ HP you can swim all day. I would drown much faster in real life. :) I think the misconception here is that getting hurt is set equal to "you can't swim properly so you're punished". For me the hit points are more like some durability value. If you run out of it you'll kiss the ground and won't stand up anymore. Under that impression a swim skill of 95 makes you a super swimmer as you can swim for hours. Back in the days David Hasselhoff would have given you a red swimsuit and you would have appeared on Baywatch with such an ability. But back to the serious stuff now. The fact that Selena could need some more crit is legit (I also do this in the mod). But I am not sure if it was planned that way by the designers and I am not a big fan of changing values in original patches just to one's liking. Interestingly Daniel said things like "a thief has a maximum crit value of 5" or "a mage has a max use magic value of x". I am not sure where this information comes from but maybe there is something I missed. If he is right, then the changes would be valid. The same is true for the Nelvin and Tar adjustments mentioned above. I guess he just looked at Mando (the other thief - hi Jurie Horneman :D) who indeed has a max crit value of 5. But which value for thieves is correct now? Maybe I just skipped a section in the manual? I also wonder why he also changed the current swim skill value of Tar from 90 to 99. My guess is a story-based reason. At least the crazy dude managed to survive the great flood. But I wonder if such lucky occasion has really something to do with your ability to swim? I doubt it. Savegames fixes Ok back to the german savegames. Beside those debatable changes, Daniel fixed a lot of bonus value issues. He only documented a few but there are many more. I guess some were just fixed by accident through his savegame editor (loading -> apply equipment effects -> fixed bonus values -> save). For example in the english 1.10 version Gryban has 6 wrong bonus values and Chris even 10! There are only 8 attributes and 10 skills in total, just to emphasize this number. Ok HP and SP bonuses are counted as well so there are 20 bonus values in total. Still Chris has half of them wrong! Those wrong values include some twisted ones. For example sometimes the bonuses were added to the wrong attribute or skill which effectively leads to two corrupt values at once. Always adjacent attributes/skills were affected so I guess someone modified the wrong line/entry manually. To emphasize the amount of issues even more: those are only the differences to the fixed english version 1.10 which itself contains several of such bugfixes. So I don't want to know the total amount of issues in the original savegames. Coming patches So the next patches will revert some german savegame changes and add a lot of fixes to the english savegames. Of course along with some other stuff. ;) Even the current 1.10 english patch has still a lot of corrupted bonus values. Wouldn't I have started the Ambermoon Advanced project, I might have not noticed this. Now we have the possibility to fix this once and for all. :) Maybe I can also find some more information about these "class X has a maximum stat Y". If you have any input, be my guest. Pyrdacor - 22-09-2021

Share by: