Sunday, September 30, 2018

Another devkitpro update

Another laptop update ... The previous one started to act pretty weird regarding AC power. I survived a couple of week with the old (2007) laptop, enjoyed the music collection it has and the larger screen. This one is more similar to the faulty one with a 1350x768 screen, but it has SSD.

Well, it was also the opportunity to try dsgametools with the latest devkitpro. And it was pretty disturbing. At first, you now have to install a package manager first before you install what you need. It could have been done with a custom apt-get setup but they opted for pacman with a binary package you have to pre-install from their github. Not really the way I believe open source should work ...

Pour bien démarrer le développement homebrew, que ce soit sur NDS ou GBA, une seule addresse: La procédure d'installation a pas mal bougé depuis la dernière fois, par contre. L'équipe de Wintermute est passé à un dépôt pacman (pour "PACket MANager", hein. Toute ressemblance avec une pizza au citron n'est que clin d'oeil de geek), avec la nécessité de télécharger leur version binaire de pacman (pourtant un outil fréquent dans les distributions linux) avant de continuer.

Les utilisateurs windows auront peut-être une expérience plus proche de leurs habitudes avec l'installateur .exe ... Un peu déboussolant pour un vieux briscard de sourceforge, mais j'ai fini par en venir à bout et mon laptop tournant un ubuntu bionic LTS 2018 est maintenant prêt à me râler dessus vu que les réglages par défaut de g++ 8 n'ont pas grand-chose à voir avec ce à quoi mon code était habitué.

I'll keep the new error messages and improved warnings of g++ 8.1.0 for another post. Here, I missed some headers or other stuff to rebuild everything

  • errno definition for dswifi ... that is likely an old one. manually installing sgIP_errno.h apparently fixed things. I'd prefer to get the sources of current dswifi to ensure everything is fine. Hope I'll find them.
  • load_bin,load_bin_size as well as bootstub_bin, bootstub_bin_size (for nds_loader_arm9, used in runME and self-upgrade features) are missing. Iirc, they should be built from .bin files ... They are still in libppp9/data ... I'll have to find out why they were not processed.
  • there's a weird warning about __sync_synchronize() which is invoked when I have a static object. I have a workaround, but I really wonder why they introduced that in newlib...

Friday, September 28, 2018


During my HTML Quest to find people interested in NDS development nowadays, I stumbled upon a discord channel named /r/NDSHacks. I'm not much into Discord, but since I made an account this summer to follow the gosh-sad-panda-put-Nectarine-offline discussions, I did my best to enter #homebrew_development ...

With some luck it might make my tutorial more meaningful and get some beta-testers more easily. We'll see.

Tuesday, September 11, 2018

Truly Testable Level Editor

There was one annoying thing with the scripts while adding 1-up, and  that was I had to add the new rules in every level. This is the kind of things that should be written only once, and as far as the script parser is concerned, it could be written once, in the "rules.gam" file. The problem is, this file would be ignored by the level editor, and thus is not used so far.

And unfortunately, there are some design flaws in the way LEDS' own parser is written, making any change in that part pretty tricky to do right. It would be nice to refactor that a bit, but such a refactory with no easy way to test things would be errors-prone. My next move must be towards testable LEDs logic.

And I realised my first idea for the tests, with modified readers and all, was over designed.

Instead, it would be interesting to have two simple programs that run checks on parsed levels (eg. what are the coordinates of game object #42 , or how to display special block#3) or that do simple changes and then write back the result. Test cases are then simple shell perl scripts combining calls to those tools and to standard file comparison tools.

What I still need to figure out is how I'll extract specific information (e.g. what gob another gob links to) out of the full data. And how to compare the extracted data.

Friday, September 07, 2018

Retro-game mechanics explain: golden!

I just went into a super video (link below) about how collision code can be exploited in Super Mario World to beat the game faster. I'm not much into speedrunning myself, but I love whatever can teach us how those old games where built and what is the logic behind their engine. And tool-assisted speedrunning quickly gets quite deep into those subjects. So let's go.

C'est du tout bon. Une vraie pépite. Une fois encore, "retro-game mechanics explained" confirme que même quand on a pas l'intention de pratiquer le speed-run intensif, les découvertes des speedrunners sont une mine d'or pour qui s'intéresse aux techniques de programmation utilisées par les anciens de l'ère 8/16-bit. Et cette fois, c'est Super Mario world qui s'y colle.

When a tile is activated, it is deleted, and a sprite version of the block will displayed in its place. When that sprite returns to its initial position, it is removed, and another tile is set in its place (usually a brown block).
Well, that was an expected one. And as he explains, it was already used in SMB3 (and probably also back in SMB1). It is something I'd like to put into my own game engine as well, although the closest I have so far is simply the "mapanim" to replace tiles of a specific location on the map along an animation triggered by a collision.

Si vous avez déjà un peu cogité la manière dont les consoles nintendo construisaient leurs images à base de mosaïques de "tiles" et des "sprites" par-dessus, vous aurez aussi deviné que pour faire sursauter un bloc-question quand on le touche, il faut effacer le bloc de décor (à base de tiles, donc) et le remplacer par un graphisme librement positionnable (un sprite) le temps de son sursaut, puis remettre à nouveau des tiles pour le bloc transformé. C'est sympa d'en avoir une confirmation depuis l'analyse du code (et oui, j'ajouterai ça dans ma todoux-liste un de ces quatres).

The next one is a bit more unexpected.

Which tile is activated during sprite/tile collision is determined by a point that is a mix (blue) between the the sprite's position (green) and its clipping box (red). If that point is not within the tile that was activated [...] there will be block duplication.
Of course, that duplication is the whole point in SMW - Level End Glitches video by RG Mech EX:  the location where to spawn the bopping block and set the new brown block won't match the original question block location, which will remain unchanged. Interrestingly, this is partly because sprites that are located inside a solid tile are ejected outwards so that they don't get stuck. I always thought that would be mario-specific, but actually no: it applies to all objects.

Un peu plus inattendu: en plus de leur zone active -- la hitbox, en rouge sur la carapace -- qui doit rester en-dehors des zones solides du jeu, les objets ont un point unique qui sert à déterminer quel bloc a été touché. Si on cogne un bloc-question avec une carapace lancée vers le haut, c'est d'abord le carré rouge qui va renseigner qu'il y a collision puis le point bleu servira à trouver avec quoi il y a collision. Chose intéressante, tous les objets subissent le traitement "repoussé par les murs" qui autorise Mario à contourner un bloc lors d'un saut plutôt que de s'y cogner méchamment comme une Giana sister.

En revanche, le fait d'avoir mis le point-test en dehors de la zone de collision m'intrigue. Quelle est la raison ? ou est-ce juste un bug ? et cette possibilité d'avoir changé de position entre les deux opérations du test de collision (boîte et point) trahit-elle une optimisation du genre "on ne teste les blocs-question qu'une frame sur 4" ?

A few wonders ...
- is there a good reason for that blue hot spot not being with the red box (other than saving computation cycles) ? It just sounds like a bug to my ears, since the red box is what triggers the collision.
- is that "ejected first but still triggering the initial block" linked to some lower rate for the collision code compared to the motion code ?

And did you know ?

In order to reduce the number of distinct objects, some power-up blocks have different contents depending on their X coordinate on screen.
The limit on the number of objects you can have in a game engine is a old opponent. I know him a bit too well myself. But still ... Thinking of editing your level and having to shift that key pick-up one block to the left or one to the right so that it actually contains a key feels just mind-blowing. Naturally, it might not have been a big deal for Miyamoto's team who already knew player needs wide enough areas to move their avatar around ... and possibly went for "aha! guess which of those 4 ?-blocks hold a key and which are mere coins ;-)". But still. That's pretty unexpected.

Mais il reste le plus croustillant. Le truc que explique qu'un bloc supposé contenir une clé peut tout d'un coup donner des ailes à yoshi. Visiblement, je ne suis pas le seul à avoir choisi trop peu d'information par bloc dans mon format de niveau, et pour pouvoir représenter tous les power-ups et bonus possibles dans Super Mario World, l'équipe de Myamoto a choisi d'utiliser la position du bloc au sein du niveau pour choisir quel objet serait offert au joueur. Pas la position absolue, hein, mais le fait qu'il soit sur un bloc pair, multiple de 4, impair, etc.

C'est à la fois génial et complètement déroutant. Dans un commander keen, je ne me serais jamais attendu à un truc du genre "si le bonus est au 2eme étage du building, alors c'est une glace à 2000 points. S'il est au 1er c'est un donuts à 1000 points et au 3eme un nounours à 5000". Mais ici, dans un contexte où les blocs-question sont souvents présentés alignés comme les gobelets d'un jeu de hasard, le truc prend tout son sens. Il reste à considérer le "numéro" stocké dans le niveau non plus comme un identifiant d'objet à créer mais plutôt comme l'identifiant du générateur d'objets correspondant. Au moins, ils ont évité les contraintes du genre "un niveau peut offrir soit les ailes, soit une clé, soit un ballon, mais jamais une combinaison de ceux-ci."

Wednesday, September 05, 2018

gimme a (control-)break!

Out of TheOffice unexpectedly. TheOffice runs Windows systems and recently decided that VPN solutions should be replaced by a remote desktop gateway. Oh yeah. Back then I had made a quick try with xfreerdp. It was quite ugly to setup (especially because xfreerdp **wants** you to provide your password on the command line) but it did worked.

Couldn't get it to work again in my sick-on-Monday mode. So I tried to find something better with remmina. After re-installing the software from vendor repositories (rather than distro repositories, which I typically prefer) to get access to the gateway-support plugin I managed again to connect. It wasn't nice (256 colors by default), it wasn't fast, but it did the trick. But unfortunately, i clicked "connect" rather than "save and connect" and my setup got lost.

Unfortunately, I couldn't set it up right again.

So let's try xfreerdp again

let $WUSER be my 'THEOFFICE\\brosp' domain/user name à la windows
let $WACHINE be the name of my machine at the office
let $GATEWAY be the name of the gateway like
and let's say get_a_password is a shell function that will just read one line of text and return it without showing it on screen ...


xfreerdp /u:$WUSER /p:$(get_a_password) /v:$WACHINE /g:$GATEWAY

did the trick.

It worked, it is nicer (i'd say I got true colors) but just scrolling to the output of the console is a pain. Give me a SSH login **please**. My firth thought of "yeah, I know, I'm going to run a SSH server at home (hopefully I can get my public IP address quite easily nowadays, although it won't be the same everyday) and I'll setup a reverse tunnel from work. The firewall/NAT on the ISP box might not like that as much as I do, though. I'll have to tweak it to give my laptop a fixed IP, etc. That won't be for today, I'm afraid.