Tuesday, October 19, 2021

Dangerous au magasin.

Premier écran. premier niveau. Un long corridor s'ouvre devant vous. Rien ne bouge. Rien ne brille. Un coup de stick a droite, vous faites quelques pas. Soudain, un bruit derrière vous: un énorme rocher rond vient de tomber sur le sol, et avance vers vous, implacable. Le temps de vous remettre de votre surprise, et vous êtes déjà en-dessous.


Bienvenue dans Rick Dangerous.

On reprend. On avance sans hésiter, On se jette dans le trou au bout du couloir : il n'y a pas grand-chose d'autre à faire. Ah-ça fait demi tour? stick à gauche... trop tard.Vous êtes de nouveau mort. 
On recommence. Avancer tomber, tac-demi-tour, avancer tomber, et là, il faudra des réflexes de jedi pour sortir du creux où se ballade votre premier ennemi (ou probablement quelques vies en plus). Bref, vous avez de la chance si vous atteignez le 2eme écran avant d'être game over.

Moi, je n'avais pas eu cette chance. J'ai posé le stick et je me suis remis au bout de la file pendant que celui derrière moi s'essayait à son tour au jeu. C'est la règle, à la maxithèque. Oh, je pourrais bien essayer d'aller attendre pour Sonic, le jeu qui vient de sortir sur la nouvelle console, mais tous les grands y sont, ou presque. J'en ai pour 45 minutes d'attente minimum. Côté Nintendo, bof. Cette semaine, c'est de nouveau les tortues ninja. Le look est sympa, mais impossible de comprendre ce qu'il faut faire dans le jeu. Je n'arrive même pas à comprendre pourquoi je meurs.
 
Non, j'aime autant rester ici et regarder par-dessus les épaules pour voir comment les autres s'y prennent après la grosse pierre. Ah ? on peut tirer. Il faut gérer son timing par rapport aux ennemis qui font des va-et-viens. On descend, on descend... Ça va, la 2eme partie à l'air moins méchante, en fait. Mais le niveau a l'air super-long.  Ah ? on peut mettre des bombes, aussi? Et voilà qu'on appelle notre joueur, plus qu'un et c'est de nouveau à moi. Reprendre le stick dans une partie en cours, c'est toujours chaud. La règle implicite c'est que soit on se fait game over rapidement pour pouvoir repartir de l'écran titre avec tout le stock de vie, soit on essaie de profiter de la situation du joueur précédent, mais au risque en cas de game over rapide-mais-pas-tant de s'entendre dire que 'eh mais non, c'est à moi, maintenant'. Ici, il était sur la salle mortelle du bloc fou, et visiblement il ne connait pas encore le truc. 
 
A moi donc, de nouveau. On élimine le premier ennemi. On descend s'occuper du deuxiEh !? il sait nous toucher depuis le bas de l'escalier ? Bon, heureusement il y a un check-point juste avant ce 2eme ennemi. Je l'élimine, je descends l'échelle je ... Mais!? il bouge, lui, maintenant ? Je reprends. Tirer.. Descendre. Tirer. Tirer. Descendre par l'échelle de droite. (ah ouais, avec le lance-flèche je comprends pourquoi), sauter dans le QUOI!? des pics qui sortent du sol au moment où j'atterris ? "ah ouais. 'faut serrer à gauche, là." fait-on dans mon dos. (un sympa, celui-là. Je me réjouis de voir jusqu'où il va).
 
Mais ça ne suffira pas. Ce n'est pas encore aujourd'hui que je verrai la fameuse chauve-souris qui bloquait mon frère. Je cale sur une sale avec des plate-formes en bois et des ennemis partout. Leur mouvements me déconcerte. Quoi que je fasse, ils finissent par me prendre en tenaille. En plus, quand j'arrive là, je n'ai pratiquement plus de munitions donc je perds presque d'office une vie pour pouvoir refaire le plein.
 
Vous l'aurez compris, regarder jouer les autres était une partie intégrante de l'expérience du jeu à l'époque, mais regarder un bon joueur, c'était aussi risquer de passer à côté de toute une série de pièges qu'il a subtilement évités. Il faudra non seulement apprendre la bonne route, mais aussi la taille des hit-box invisibles et les temps de réactions. Tout ça avec un jeu qui aurait mérité d'être sur une manette NES ou Megadrive pour que les actions soient directes, mais qui doit se contenter d'un stick Atari à 1 bouton avec des combinaisons douteuses comme "haut = saute", "feu + haut = tirer", "avant + feu = coup de baton", "bas + avant = ramper", "feu + bas = bombe". 

Bah, je suis out pour cette fois-ci. Et manque de pot, le "sympa" derrière moi connaissait la manip pour mettre le jeu de voiture également présent sur la cartouche. c'est foutu pour aujourd'hui. Je vais aller voir s'il n'y a pas une nouvelle M.A.S.K. sortie d'une boîte, puis j'irai me lire quelques Scrameustaches.

Retour en 2021. Rick Dangerous est resté un de mes titres-référence. Même si je n'essaierais pas d'en cloner l'esprit, j'apprécie toujours de le reprendre en main. La qualité audio-visuelle du titre était bluffante pour les possesseurs de Commodore plus habitué à un Zorro ou un Boulder Dash, mais je ne suis pas sûr que ça aurait suffi si on avait eu le jeu à la maison (donc 1/2h/j pendant les vacances scolaires uniquement) plutôt que de pouvoir y jouer "en société" au supermarché. Merci, la maxithèque ;)
 

Back to the 3 Rooms ... hopefully.

 

Most of what had been identified as faulty early this summer is now fixed. Even the mysterious way Bilou flickered while running has been understood (something cleared the VRAM slot of one of the head's sprites) and fixed (animation was using the wrong page). It's been quite time-consuming but at least it is done. It's time I start doing some [todo] pixel art to make proper 'doors' in each environment and [todo] craft the kind of rooms I actually need for my 3-rooms milestone.

But see, I've taken almost 1 hour editing that and commenting about it. So I've captured my description of the milestone in my notebook because it's much easier to take it and focus a bit on what I'm going to do next than it is with a blog. 

Anyway. Let's have all tools and runMe rebuilt. Let's have them installed on the cube so that I can use the latest build on the Real Thing before I start messing up with the maps and spritesets.

Many of the 'todo' items for last year had nothing more 'to do' on them.

In the milestone, each room had two doors, so it could communicate with both alternate world. [todo] the engine needs to be able to remember which world we come from and spawn Bilou at either left or right door based on that information. That requires at least an engine upgrade.

Friday, October 15, 2021

Coupez!

Imaginons qu'on ait envie de faire un peu de demoscene au milieu de Linux. Imaginons encore qu'on ait vraiment besoin qu'une partie du programme ne soit jamais interrompue par autre-chose. Difficile, hein ? J'ai fait un truc un peu du genre, un jour, mais il faut avoir accès à la configuration du bootloader. De même qu'on peut forcer le kernel Linux à n'utiliser qu'une partie de la mémoire, on peut restreindre l'ensemble de coeurs accessibles au scheduler grâce à isolcpus=0,1,2 (ou tout autre combinaison qui vous convienne, laisser un coeur sur 4 au système, c'était un peu extrême :-P). Quel est l'intérêt ? eh bien, c'est que si ces coeurs ne sont plus utilisés par les processus génériques, un programme ayant les droits suffisant peut toujours faire appel à sched_setaffinity() pour se lier à un coeur en particulier, y compris un coeur qui avait été 'isolé' du reste du système. Je me demande si ça donnerait quelque-chose d'intéressant sur le devterm. 'faudra que j'y exécute un lscpu ce soir, tiens...

Tuesday, September 28, 2021

just another breakpoint in the wall

Since last week, I've been tweaking the state machine of my meka-tester trying to make it better mimmic the behaviour of Bilou when it gets into the walls. I finally get the kind of error I wanted, but it makes little sense.

. . .  Well, I initially wanted to tell you about how it suddenly hops into the wall, 4 pixels further than it was without ever seeing the 'building up' delayed move explain anything of that. but I feel so tired. s/4f.f, S/ffe6.0 ... I'd have to dig up my notebook (page 14) to decode what that means. I just can't. my eyes don't want to look at the screen anymore. See you later.

Pendant près de deux semaines, j'ai fait des essais et des ajustements pour avoir un meka-apple qui reproduise les bugs et-vlan-me-n'là-dans-l'mur que je rencontre systématiquement dès que j'essaie de jouer dans le nouveau niveau de mon fiston. J'ai fini par y parvenir, mais on ne peut pas dire que ça m'aide à comprendre ce qui se passe. Une téléportation de 4 pixels d'un coup, alors que tout semblait aller bien jusque là...

Un peu de repos, un peu d'astuce, et j'ai des pistes pour améliorer la situation. Mais alors que je refais un essai dans "Dreams.nds", je me rends compte que le problème est toujours là. Et il est très facile à reproduire manette en main sur ce niveau, en plus. Est-ce que j'ai tenté de faire du unit-testing trop tôt ?

<later> over the week, I managed to identify some issues and possibly fix some, but it is still possible (and actually easy) to trigger. 

It makes me feel like I tried to unit-test the issue too early. Maybe what I actually need is a way to get a bunch of data out of the emulator, and monitor them when I'm done reproducing the issue.

Let's see what we would need ...

Je change d'approche, du coup : il existe dans l'organisation de mes jeux une classe indépendante du Game Engine, mais qui a accès aux objets du Game Script et qui peut exécuter une méthode à chaque frame, le HUD. Si je fais tourner mon niveau dans un émulateur avec débuggeur, et si je rajoute un break pointau cas où Bilou serait arrivé dans un mur, je devrais pouvoir creuser le problème.

  • [done] access game object position and variables.
  • [done] record them, e.g. in the GameObjectState structure defined in unit-tests
  • [done] check whether game object got into a wall (cando(0,0, PLAYER_THRU)
  • [done] switch to 'investigation' mode when we're in a wall
  • track state changes and controllers reports (through a custom inspector)

edit:A class deriving from iHud met all the criterion above. If I'm okay with using ddd to inspect the content of the last GameObjectState array, I can start investigating ...

Sauf que ça n'a pas été si simple. Même en ré-important le code des tests qui enregistre les mouvements des dernières seconde de jeu, l'information restait trop sommaire pour pouvoir retracer pas à pas ce qui ne "marchait" pas au cœur de la fonction do-slopes.
Mais Murad-dib m'a sauvé la mise  (oui, depuis qu'on est allé voir Dune avec les collègues, je me suis replongé dans le bouquin.) Et si comme lui je balayais de la main toutes les règles et les conventions (du c++, ici, pas du C.H.O.M.)... si je prenais avant chaque appel à bilan.PlaY Une copie de la mémoire contenant l'objet 'Bilou' ... je pourrais en cas de mur réappeler 'play' sur la copie ! le moteur de jeu est ainsi fait qu'il n'y verrait que du feu, et je pourrais faire mon débugging pas à pas en étant sûr que je suis dans un cas où le bug va se manifester

It wasn't quite sufficient, unfortunately. Hopefully, I was reading Dune again, and going through the moment when Muad'Dib decides to break all the rules so he could get victory, I realised that I could go for Muad'dibugging too: create an empty GameObject in addition to the real one for Bilou, and memcpy a snapshot of the current state before every 'play()' call. If we turn out to end up in a wall, I could just call 'play()' on the copied state to reproduce step-by-step what the first one had encountered.

Of course, that goes against all established rules about how to deal with C++ instances, and make the 'NOCOPY(GameObject);' macro look like a fool. But it worked.

And at last, on 2021-10-13, 22:**, I think I nailed that stuck-in-the-wall bug that had been since my kid drew his pyramid level.
 

Sunday, September 19, 2021

Eclipse Operating System

Un de mes objectifs en 1997, c'était de parvenir à maîtriser le mode 32-bits des PC. Windows était encore un hybride 16/32 à l'époque, et pas franchement convainquant pour la programmation de jeux. Tous les jeux dos parus sur les dernières années annonçaient "Dos4GW" ou quelque-chose de ce genre, et la taille toujours croissante des modules de mon frère me faisaient bien comprendre que "640Ko pour tout le monde", ça ne serait plus suffisant bien longtemps.

Seulement voilà: basculer du mode 16-bit au mode 32-bit (connu à l'époque sous le nom de 'mode protégé'), ça demande une rigueur à tout épreuve et ma documentation était malheureusement plutôt imprécise. En plus, les fonctions du BIOS et du MS-DOS deviennent du coup inaccessibles (plus de chargement de fichier ni de changement de mode graphique, par exemple). Et au milieu de tout ça, je tombe sur une pépite venant de la démoscène: Eclipse Operating System et son jeu-démo Greedy. Il me lancera à la recherche du Watcom C++ sans lequel on ne sait pas recompiler les exemples. Une chasse qui durera jusqu'à la Inscene, si ma mémoire est bonne.

Saturday, September 11, 2021

Wall walk test.

If I want to have An understanding of what causes Bilou to get into walls when he arrives straight into it, I need to find a way to reproduce that at will. I have to update my slopS unit tests to cover that new scenario.

The difficulty with that setup is that the mecha will have to keep walking towards the wall for some frames, and only then try to turn back. Scripting a fake game pad controller to force the mecha to do that sure won't be the easiest path to follow. But I have a plan.

ouais. Bon. 'faudra que je le traduise, lui

Let's have a second mecha that is walking "normally" on one large floor while another one, the Gob-Under-Test is tracking its position and tries to follow it, just like Berry Bats would do, except "walking". That should work, right ?

Well, reality is hitting me hard, here. I haven't managed to get the test cycle work properly. I'm caught in the process of navigating the history and running because even with the obvious sorted out, my new test gets a "memory is leaking" warning and the former 'slopes' test isn't working either.

I think from now on, I'll use the 'default' branch as a way to track what is properly passing automated tests and what isn't. Good news, commit 6ab9f8ca2931 dating from this year (April 13rd) pass the slopes tests.

Caveats when doing things like this:

  • Makefile does not detect whether I change devkitpro version, so things that used to work years ago on an older devkit may fail to build nowadays and you'll have to manually clean output/*.o
  • some tests depend on fakreoot/*.cmd, which is not automatically re-populated from SchoolTests/efsroot/ or AppleAssault/efsroot/. and in SchoolTests, the files are generated from SchoolTest/cmd/, which does not occur if you just rebuild unit tests.

18731874

edit: I identified a commit at which the TestBasicSlopes started failing. Surprisingly, it was not a side-effect or whatever: the commit directly does


       if ((cspeed&cp) && !cdata[0]) continue;// this testpoint only works with speed
-      if ((chkflr&cp) && !(checks[pos] & F_FLOOR)) {
+      if ((chkflr&cp) && (checks[pos] & F_FALLTHRU)) {
        if (isi) isi->TestPoint(xtile, ytile, pos, checks[pos], "floor");
        cdata[GOB_TESTPOINTS]|=cp;
       }

Which cannot have no effect on how testpoints behave in the slope tests. But if we compare how monsters in the green zone behave before (1873) and after (1874) this commit, it is clear that it has desirable effects. So I'm now sure I have to fix the tests, not the way testpoints are handled. 

edit++: okay. The leaking object was a 'builder' helper used by the GobState objets. The builder is a std::* object temporarily used while e.g. collecting transitions from a given state before they got 'flattened' into an array for the 'running' part. The array, just like GobStates are allocated in the 'tank', a larger memory chunk meant to host many small objects that all have the same lifetime: one level.

In the 'slope' tests, each state was used to spawn a GameObject using that state for the test. There were no transitions: we first use a forward-moving mecha to check things are fine when moving forward with the Forward state, and then a distinct backwards-moving-mecha. But for my new test, I need transitions. That means that I won't spawn for every states. That means some states are not 'frozen' into the tank, and hence still hold references to std::* objects like vectors or strings. These are the leaking ones. Let's get cracking!

Tuesday, August 31, 2021

Pyramid mechanics

Jusque là, j'avais prévu de me servir des "blocs poilus" pour servir de blocs destructibles dans la pyramide, mais je crois bien que j'ai trouvé mieux. Et tout simple, avec ça: des pots. Eh oui. Ils peuvent être brisés, ils peuvent libérer des trucs, ils peuvent bloquer le chemin de Bilou.

Bilou peut naturellement ramasser des trucs. Les pots aussi, mais on peut faciement dire que seuls ceux qui n'ont rien par-dessus. On peut construire plein de scènes sur cette base-là, où un 'mur' de pots bloque un accès, qu'on ne saura libérer qu'avec une carapace de scorpion.

What can play the role of breakable blocks in the pyramid ? I once thought it could be furry blocks, and possibly I'll keep them in some places ... but building walls with them ? or large structures like SMB3 "pyramidal stack" ? I finally found something that could work better. Okay, lifting up jars and throwing them against walls to get goodies isn't exactly an original mechanics, but it would work fine with the pyramid setup as well as with a shell from a scorpio.

On peut en imaginer des 'intacts' qui font faire demi-tour à la carapace et d'autres déjà fendus qui laissent passer d'un coup.

Enfin, on peut ranger des pots sur une étagères, on peut les faire tomber en cognant l'étagère ... bref, ils peuvent servir de 'briques en l'air' qu'on casse en tapant dedans par le bas.

L'autre truc qui ne me branchait pas, c'est les lanceurs de flèches. J'avais une note proposant 'des statues de chat pour les boules de feu, des statues d'aigle pour propulser vers le haut'. Mais des piafs embusqués qui tentent de becquer Bilou et dont on peut utiliser le cou comme tremplin-à-la-Ori, ça serait sans doute nettement mieux.

One other thing needed more thoughts: wall hasards. Like arrow throwers or spears pointing out and coming back. I loved the idea of them being helpful to climb up with the right timing, but we've been served the cliché of climbing up spears stuck into walls after you dodged them so many times ... It wasn't too clear what would throw them either.

But given how birds are expected to play a major role in the last world of "Bilou Dreamland", I thought "why not long-neck beaked baddies trying to snap Bilou and then getting stuck into the wall facing them, so we can use their neck to climb up ?

Monday, August 30, 2021

Trouver le thread fautif

Bon, ce coup-ci, j'étais sur un autre cas de figure: le programme fautif est toujours occupé à tourner, mais un de ses threads est mort, causant une attente infinie dans un autre. Je sais demander un .dmp au Task Manager, ouvrir le .dmp en question sur la machine de dev avec les bons chemins pour les serveurs de symboles (eh oui, moi du futur: tu as oublié mais sous Windows, il n'y a pas de .elf de debugging: les symboles de debug sont d'office dans un fichier séparé) et parcourir la liste des threads en espérant y voir apparaître KERNELBASE!UnhandledExceptionFilter dans la pile d'appels correspondante. 

Ce n'est pas trop dur de repérer l'adresse du crash, mais c'est une autre histoire de connaître l'état des registres au moment du plantage.

Il devrait y avoir une extension de windbg pour gérer ça, mais le site qui la proposait a disparu dans les limbes du temps. Par contre si je parviens à deviner où elle se trouve, la structure EXCEPTION_POINTERS devrait nous fournir toutes les infos nécessaires pour continuer à debugger.

Eh bien voilà: cette structure est produite dans le stack frame (les variables locales, NdT) de ntdll!_C_specific_handler (encadré en rouge dans la capture ci-contre) et référencée dans le stack frame de UnhandledExceptionFilter. J'ai utilisé les adresses renseignées par la colone 'Child-SP' et retracé ça à la main dans Gimp, hein. Ici, un seul candidat: 0x16bee7c0.

Reste à s'assurer que c'est bien la bonne adresse. Je peux utiliser la commande windbg dt 0x16bee7c0 EXCEPTION_POINTERS pour le coup: si je suis dans le bon, elle me donnera deux pointeurs valides

En cliquant sur le 'exception record', on devrait avoir un code valide (type 0xc000000*) et une adresse qui correspond à notre fonction fautive (aussi renseignée comme adresse de retour pour KiUserExceptionDispatch, soit ici à l'intérieur de MoveSmall).

Thursday, August 26, 2021

Trouver un core dump ...

bin oui, parce que coder, c'est aussi chercher pourquoi un programme s'est planté. Linux est assez sympa sur ce coup-là avec son ulimit -c unlimited qui permet d'autoriser la production de 'core dumps' dans le répertoire courant pour un shell donné sans que tout le système ne se mette à saturer le disque dur en cas de dysfonctionnement. Après, on ouvre le dump dans un débuggeur et en avant pour l'autopsie.

Mais là, pas'd'bol, je suis sous Windows. Le boulot, vous comprenez. Le frangin de Jigé me proposait de faire clic-droit-debug dans le gestionnaire de tâches (onglet 'détails' de préférence, apparemment) et hop youpi, visual studio prendrait en marche le programme fautif. ça m'arrangerait assez bien vu qu'il est appelé depuis du python au bout d'une séquence de 3 ou 4 programmes histoire que la caméra à l'autre bout du fil soit dans les bonnes dispositions pour les tests. 

Mais re-pas'd'bol, quand je fais ça, j'ai juste droit à "not responding" sur Visual Studio puis les deux programmes qui s'arrêtent avec pas plus d'infos. ça marchait mieux avec "create dump file", mais ce n'est pas ce qu'il me faut aujourd'hui.

Pour le coup, je vais devoir refaire appel à devenv /debug dans une console VSpéciale et croiser les doigts pour être dans les bonnes conditions pour reproduire le crash. 

  • c'est apparemment normal d'être accueilli dans un Visual Studio qui fait semblant de ne pas savoir ce que vous voulez. Debug>Start Debugging devrait nous mettre en route
  • ça devrait aussi être normal que la fenêtre qui s'ouvre quand le programme est démarré (après tous les téléchargements de symboles depuis les servers MS) se ferme automatiquement en cas d'arrêt du programme. On va mettre un p'tit breakpoint sur exit pour calmer un peu tout ça;
  • bon, par contre j'ai beau torturer ma ligne de commande, pas moyen de reproduire le crash dans cet environnement-là. Il va falloir trouver autre chose.

Et le plus agaçant, c'est que je sais que Windows peut le faire. Sur tant d'autres machines, il m'a saoûlé avec ses boîtes de dialogues ok/cancel/debug... ça pourrait être parce que Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug est vide, mais non: il me fait l'effet d'avoir bien tout ce qu'il faut là où il faut.

Ahmaisattends ... le programme de test mélange une bibliothèque C++ et du code compilé avec GHC, et le runtime haskell a un flag supplémentaire +RTS --generate-crash-dumps -RTS. On peut toujours essayer d'utiliser ça pendant notre debugging VS... Ah ? ... Bingo ?

On transfère bien son .pdb sur la machine de test ... Et voilà: j'ai un nom de fonction et un numéro de ligne. La méditation va pouvoir commencer.

Ah oui, il y a aussi le Windows Error Reporting (WER) system, et ses fichiers "planqués" dans C:\ProgramData\Microsoft\Windows. C'est ce qui ressemble le plus à mon ulimit. il faut créer la clé HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\Windows Error Reporting\LocalDumps et y définir "DumpType"=dword:00000002 (et plus si affinités. Attention, ça change le répertoire utiliser pour les dumps :-P)

Il y aura aussi procdump -e à tester, tiens.

Monday, August 23, 2021

walking kritter

A large part of the 'walk' effort is to have characters' feet sticking on the ground while walking. It may not always be a good idea but I always grimace when I see walking characters half-sliding on the ground in games with no obvious reason. At least for monsters, it should almost never occur.

In my current engine, this is achieved by hints in the animation sequence about how much pixels the character would travel with the new frame. Animator code then ensures the game character has already accumulated that much 'deferred moves' before switching simultaneously to both the next frame and the next position.

Quand je fais marcher un personnage, j'aime généralement mieux qu'il soit bien ancré dans le sol. Ce n'est pas toujours forcément une bonne idée, mais les personnage qui donnent l'impression de patiner au lieu de marcher alors qu'ils ne portent pas de patins, ce n'est pas ma tasse de thé. Du coup, mon moteur de jeu est prévu pour des animations qui contiennent des indices sur le nombre de pixels (plutôt que de frames) à attendre entre deux images.

But checking the walk cycle for the 'Kritter' monster in DKC makes me realise that there might be an easier approach, in which the motion speed for the character is constant while its animation still features a 'natural' motion where it speeds up and down: just offset the monster graphics within the buffer. This might sound like advice from a nightmare from a one-hardware-sprite-per-object point of view, where pixels would have to be effectively shifted in video memory to accomodate for the partly-moved object, but for a SNES-like sprite that re-codes the relative OAMs positions with every frame anyway, it could be nice to have.

Now there's a catch: the hitbox for your character will move at constant speed and your graphics will not. That might be source of other (Infogramesque) collision issues.

ça a aussi l'avantage de fonctionner avec des cycles de marche qui ne sont pas uniformes. Les boîteux, les excessifs, les discrets ... toutes catégories de personnages qui viendraient sans problème peupler l'univers de Bilou. Et où regarder après un exemple de ce genre de persos mieux que dans la série Donkey Kong Country ?

J'avais donc repris l'animation d'un Kritter et choisi un point de référence qui devrait rester ancré au sol (un orteil) pour voir comment il se déplaçait de frame en frame. Chose assez intéressante: on est souvent autour de la même valeur de 5 pixels par frame d'animation, mais pas tout le temps. Et vu les faibles déviations, vu aussi que l'image doit de toutes façon être reconstituée à partir de plusieurs sprites hardware, on pourrait probablement ici avoir un game object qui avance à vitesse constante et avoir un léger décalage sur la gauche ou la droite de l'image par rapport à la hitbox. Attention quand-même à ne pas pousser ça trop loin sous peine de créer des situations infogramesques.

Monday, August 16, 2021

DJLN.cmd

Faire des niveaux sur papier, ce n'est définitivement pas une activité à proposer à mon fiston. Au mieux, je peux lui proposer de me dicter un niveau que je ferais moi sur papier.

Par contre, prendre la Nintendo DS de papa et ajouter des blocs ici et là, ça ça lui plaît bien. Mais pas de chance, la branche "newmap/newmeta" n'est pas encore stabilisée au point qu'on puisse tenter de jouer au niveau ainsi construit.

Assez surprenemment, mon nouvel écran de patching m'indique que l'erreur se trouve sur la première ligne de pyram.spr, CMAP n'étant pas une commande valide pour les scripts. Enfin, ça c'est sur émulateur après avoir récupéré les fichiers présents sur DS avec le wifi remis en service.

En fait, ce serait la commande spr.more "pyram.spr" qui n'a pas été comprise par l'éditeur de niveau. Du coup, au moment de sauver, il en fait un input "pyram.spr" Si j'en crois les numéros de version, le bug a déjà été patché, c'est juste que la DS n'avait pas pu profiter de la nouvelle version. C'est J.L.N qui va être content...

  • invoking autoexec.cmd with the [run] button does not seem to allow PatchWindow to be invoked.

Saturday, August 14, 2021

Ultimate Game Maker

 There has been references to Ultimate Game Maker here and there in this blog, but if I want to explain what the project was, I'll need to detail a bit what I was doing just before.

Most of it was working on the early Clicker project, which was mostly meant to be a GUI library and desktop environment over a DOS extender, by then. It was also a mix between Nowan's C code and my assembly code so I had been defining every possible widget with a bit-level memory layout of how they would be managed as if the GUI handling code was a co-processor.

Meanwhile, I was more or less done with the RSD Game-Maker. It had too many limitations for the games I wanted to make. Games that could match Super Mario World.

Unlike Nowan, I had little interest in replacing Ms-Word with something better, but quite quickly, I started to use Clicker GUI project to revise the Game Maker I knew. There was little depart from RSD editor at that point. We see that on the 'monsters editor' screen that still has a grid to define monsters 'walking path'. But it already had a few critical extensions like "Monster is affected by gravity (needed for Bilou)" and "Monster can shoot" (needed for Badman III).

Ultimate Game Maker started while I was waiting for over 1 hour every morning for my university courses to start, and before the distance between Internet and classrooms shrunk.

I then started to cover a good deal of pages with a sort of class hierarchy starting with 'sprites' (purely decorative entities) up to playable characters (PERSO depicted here). Each of these class of game entity comes with a detailed set of "registers" and code pointers. They can detail things like attack and defence levels (inherited from RSD), invincibility frame counters, but also position and frame identifier within animation tables.

Like I did with Clicker, each of these 'registers' is carefully assigned an 8-, 16- or 32-bit size and the size of each set of registers is accounted. All of this is of course completely obsolete.

I also draw from Clicker's fonts rendering the idea that it is best to have generated code used to pset some pixels while others are left untouched on those pre-MMX, low-bandwidth video adapters.

That idea extended quite naturally to the fact that most characters in Bilou are meant to be made of small sprites. They are called 'blobs' in this work, and you'll have some 'registers' that identify the first and last 'blob' in the list that can receive hits and first/last blob that can give hits.

There is one hiatus, however, that will never be resolved: those strict hierarchies with pre-defined roles (a bonus - which can be collected - is not an object - which can be picked up) will never accomodate with koopas that switch roles between pick-me-up shell and self-moving ennemies.




Tuesday, August 10, 2021

NUC en maintenance...

Mon beau-frère a beau trouver que je le sous-exploite, ces 2 mois sans accès à mon NUC auront été douloureux. C'est qu'après le passage du technicien WiFi, il n'était plus sur le bon réseau (le gars m'ayant mis un SSID tout en MAJUSCULEs. Eh oui). Et avec d'autres paramètres de sécurité.

Et le truc, c'est que depuis son installation d'origine, le NUC était en mode "cube numérique dans son coin douillet à côté de la chaîne HiFi". soit je communiquais avec par SSH, soit par un p'tit service web perso pour trier les playlists au fur et à mesure qu'on les joue, que ce soit par tablette, laptop ou smartphone-de-ma-fée.

Pour une raison inconnue, les gars de chez Intel ont pensé qu'une prise HDMI n'aurait pas tenu sur la face multimédia de l'engin et donc j'avais un câble mini-HDMI <-> HDMI au chaud dans un tiroir et un adaptateur miniHDMI:M->HDMI:F qui m'avait servi lors du setup initial sur le setup Raspberry de mon filleul. J'avais d'ailleurs racheté le même adaptateur HDMI->VGA que lui (on le voit sur la droite de la photo).

Fort heureusement, j'ai aussi chez moi un apparail auquel j'ai programmé un mode "forward HDMI". Je peux donc y faire passer mon signal pour éviter de devoir brancher deux câbles HDMIs l'un avec l'autre.

sudo modprobe zd1201 ap=1 # /etc/modprobe.d/wlan did not seemed to have effect before reboot.
sudo iwconfig enx00cafe00babe essid "bilou"
sudo ifconfig enx00cafe00babe 192.168.7.1 netmask 255.255.255.0
sudo vim /etc/udhcpd.conf # fix 'interface', 'start' and 'end'.
sudo vim /etc/default/udhcpd # set DHCPD_ENABLED
sudo touch /var/lib/misc/udhcpd.leases
sudo service udhcpd reload
sudo service udhcpd restart

Et *enfin*, mes consoles DS ont pu recevoir une addresse IPv4 et transférer des fichiers vers/depuis le NUC avec server.pl et sink.pl... Par contre, pa encore moyen de faire les mises à jour automatique (de runMe, qui devrait recevoir son nouveau mécanisme de rapport de iScriptException) parce que ils ont été configurés pour contacter 192.168.0.11 et rien d'autre.

Donc on va commencer par ajuster EXTRAFLAGS et recompiler tout ça ...

  • [done] /etc/modprobe.d/wlan.conf instead of /etc/modprobe.d/wlan allowed ap=1 to be auto-assigned
  • [todo] trying to reload the module while stick is plugged in fails to upload firmware with ETIMEDOUT (-110) errcode
  • [done] wireless_essid under iface enx00cafe00babe inet in /etc/network/interfaces allows to define SSID properly.
  • [done] I had to manually ifup enx00cafe00babe until the interface was added to the auto list of /etc/network/interfaces
  • [done] using Ubuntu HWE allowed the TPLink USB stick to be supported on my laptop
  • [done] nmcli dev wifi connect "bilou" ifname wlx00deca00fbad let my laptop connect to the bilou wifi as well.
  • [todo] looks like nmcli has to be re-done when I plug the TPLink stick again...
  • [todo] uploading purposely buggy greent.cmd could trigger the PatchWindow, but J.L.N's level still produces a *** cannot parse line*** diagnose halt instead.

Friday, August 06, 2021

Testpoints and borders

 Testpoints are the oldest check technique I've been using to implement collisions in my games. From Calimero to Bilou and even Crazy Brix. The idea was simply to check the color of a specific point on screen to decide whether it is solid or not. In Calimero, white was solid, and black was not. In Bilou (QuickBasic), pixels with all their 4 lower bits set were non-solid. Everything else was.

But by 2000, it was no longer sounding sufficient. I had a long technical discussion with Gedeon by then, who was enthusiast about Crazy Brix, but pointed out that ball/bricks collisions were imperfect. I had found (by browsing and floppy-swapping- and printing and reading) mask-based techniques for sprite-to-sprites collisions through shifting and masking. But I was still missing a way to do the same for ground and walls.

Then I came up with a paradigm shift: instead of doing checks on a bitmap, I could have a vector-based description of the level boundary and wrote a letter to Gedeon to present him how I'd do it.

There are still testpoints associated with sprite positions, but now they can be attached to the closest level boundary. They can be split in 4 casts depending on whether they should block as floor, ceiling or walls. Once a testpoint is associated with one border, checking whether we're in or out is trivial. One test, and that's it.

My idea was that we could build a graph or a network of boundaries for each cast, so we can switch from one boundary to its neighbour.

I had high hope to use that in my Ultimate Game Maker, but it although I said to Gedeon that navigating the 'network' shouldn't be that hard, just having a Mario-pipe in the level and falling below its height would make our 'right wall' (initially far away) become very near, and possibly skipping many other obstacles that are "shadowed" by the pipe.

edit: by re-typing this on 2021, it turns out that the solution to boundaries network might simply be to use something inspired by the 'portals' used in 3D engines (Ogre ?): above my Mario-pipe, you'd have an "empty" right-wall. That means when you're jumping and have no walls in front of you, the scanning is halted by a 'right-portal' that just serves the purpose of saying 'there's a pipe right below me'. Only when you go past the horizontal position of the pipe, you unlock the wall-boundaries that are further away.

Ah. Bin c'était supposé être un post de traduction d'un vieux post pour le tag-de-la-semaine et à y re-réfléchir, j'en viens à me dire que la clé, pour pouvoir utiliser ces bordures, c'est de rajouter des bordures-portail pour prolonger les bordures réelles. ça conserve le potentiel de décrire la structure du niveau avec moins de données qu'une tilemap, mais par contre il risque d'y avoir du travail pour l'édition de niveaux...

Et en cherchant un peu (autre chose), je retombe sur des illustrations qui doivent dater d'après la lettre à Gédéon, mais d'avant la tentative de moteur 3D pour Bilou.





Yono

Yono, c'est en quelque sorte le chaînon manquant entre Zelda et Sokoban. A priori, on pourrait le croire plus proche de Zelda, avec son vaste monde, ses personnages secondaires, ses coffres, sa monnaie et ses monstres.

Sauf qu'en réalité il y a dans tout ça énormément d'habillage (sympathique au demeurant) autour d'une mécanique de jeu très fortement empruntée à ce jeu qui figure parmi les tout premiers auxquels j'ai pu m'essayer sur PC: Sokoban.

Mais si, souvenez-vous: ce jeu où il faut pousser des caisses pour les placer sur des dalles précises malgré un level design encombré. Allez, Adree nous en avait même fait une version DS.

Bref, ici pas de manutentionaire, mais un éléphant aventureux. Choix de personnage qui valide immédiatement un gameplay assez "rigide" où il ne sera pas question d'essayer de sauter par dessus un bloc. Mais notre éléphant peut aussi participer à des puzzles basés sur les éléments air/feu/eau, tirer des cacahuètes pour exploser les balons et j'en oublie si je ne me fais pas un schéma de toutes les interactions que J.L.N et *deline ont rencontrées pendant leurs partie.

Mais du coup, fallait-il s'encombrer de tous ces éléments annexes ? un menu de sélection de niveau et un design "à l'essentiel" n'aurait-il pas fait l'affaire ? Eh bien aussi étrange que ça puisse vous paraître, je dirais "pas forcément". Je dois admettre que ces petits interludes où on défonce un peu des monstres ou explore des villes offre un relâchement bienvenu de la tension et que mes têtes blondes sont allées plus loin dans Yono que je ne suis jamais allé dans Sokoban.

Notez aussi au passage le design "cubique" des niveaux et l'omniprésence d'un motif "en damier" au sol, qui permet de toujours pouvoir se repérer dans la grille de déplacement des caisses malgré une vue isométrique (qui passe sans problème avec les stick analogiques des joy-cons). Le seul hic du jeu, c'est cette physique supplémentaire pour certains objets à faire tomber (entre-autre les clés) et qui peut nous troller en projetant une clé à un endroit inaccessible à la fin d'une énigme. ça n'arrive heureusement pas trop souvent, mais c'est bien pénible quand ça nous tombe dessus.

Wednesday, August 04, 2021

In a cubical world ...

Clay-Zulah did what I had dismissed: a side-viewed, ortho-thing-ic 3D rendering of a 2D game. With a fairly nice result, I must add. The selection of objects is quite well done and there's some Kirby's Adventure vibe in the color and "textures" that manage to make us forget they are all cubes.

The perspective effect is a bit excessive to my taste, but once in motion, I must admit the result is one of the best I've seen so far for such things.

Dans la série des jeux indés dont je suis le développement sur Twitter, il y a le titre de Clay-Zulah, qui a justement opté pour un rendu orthochosique d'un monde 2D en 3D avec des objets très cubique. L'option que j'avais écartée pour un Bilou 3D à la fin du siècle dernier, donc. Et je dois dire qu'avec sa palette et son style "Kirby's Adventure", il s'en sort assez bien.

Sunday, July 25, 2021

I2C

Nah, not precisely that device, but quite close.

I've been lucky working on embedded systems over the last 7 years (wow. Yeah. that many already), and being part of the engineering of one for at least the last 4. I mean, my colleagues really put together chips on a multi-layer PCB following chipmaker's guidelines and their tools advice and their knowledge so that high-speed signals would arrive clean and timely where they are expected.

We eventually received a first batch of prototype and I felt like I was part of the Playstation design team while we were bringing up the board, one chip at a time, adding custom software scripts so that the hardware teams would have signals to monitor and assess whether the hardware produced was meeting the expected quality (sometimes it did, sometimes it didn't. Hopefully, there were plenty of 0-ohm resistor and not-stuffed-pull-up/low resistors on the PCB design to adjust things. Clever they).

Many of the chips we used (like HDMI receiver/transmitters, power management IC, audio CODEC and even the FPGA) are meant to work mostly standalone, but they still need to get configuration at some point. Like telling the codec which samplerate it should run at and whether it should produced 8-bit or 16-bit values. Sometimes we want to read information from them, like the board temperature or the signal resolution the HDMI receiver got. For all this, I had I2C.

And not quite that SoC, but an OMAP anyway...

I2C is a bus, connecting 2 or more chips. I has one master chip and multiple subordinate chips. Communication always happens when the master says so. It either reads (asks for data) or writes (sends data), but there is no 'interrupt' signal flowing back part of the I2C bus, nor can you have sub-to-sub communications over the bus. Unlike ISA that connected my soundBlaster and my trident SVGA cards to my 80386 CPU, the I2C uses only 2 lines: one clock line and one data line. The goal is obviously to make it as cheap as possible for chips to support it.

Let's think of it from a network guy perspective. ISA and PCI busses (and even USB) try to offer as much bandwidth as technically possible because they'll have to transmit bulks of data. I2C is the out-of-band technology you'd use next to a (r/h)igh(t) bandwidth solution you use for your data blasts. The audio CODEC chip had I2S lines dedicated to sound transport. The HDMI chip had BT1120 interface for the same purpose. At best these media busses had additional lines notifying 'start of frame', but you couldn't use them to deliver status information, and most of the time, chips using them were hard-wired as either transmitter or receiver on those lines, so using them to send configuration would be electrically dangerous to the chips.

The brilliant part in I2C is that the two chips using it don't need to agree on any speed nor be clocked with the same crystal: bits from the DATA line are sampled only when the CLK line rises. That gives the opportunity to have special 'START' and 'STOP' encoding that would otherwise be invalid. For instance, changing the DATA line while the CLK line is in a-priori requesting the DATA not to change.

Most of the systems I've worked with had dedicated I2C driving units that would handle bits transmission after you indicated one or more bytes in a FIFO buffer and the device identifier in another register. But you may also simply use a generic-purpose I/O line as DATA and another one as CLK. That will work whatever the speed of your CPU.

Much like ISA soundblaster cards would use only one of 0x220, 0x240, 0x260 or 0x280 port for their control register, an I2C-compatible sound chip would e.g. only react to chip ID 0x22, 0x24, 0x26 or 0x28. And much like you had jumpers on your soundblaster card to pick something else than 0x220 if you happened to have a tape reading device using that port as well (or too soundblaster, lucky weirdo :-D), your I2C chip will typically feature some configuration pin that you can wire to ground or VCC to pick one of the available IDs.

Friday, July 16, 2021

Il est où le wifi ?

Le portail Wifi qui nous connectait au monde de Bilou s'est effondré. Les forces de l'empire Télétravail ont fait intrusion, entendant stabiliser leur hyper-tunnel privé sécurisé contre les fluctuations de l'étoile 192.168.0.24. Résultat, tout le système stellaire a été basculé en WPA alors que l'astro-cruiser ne peut communiquer qu'en WEP.

J'avais envoyé sur place ma sonde ZD1201 qui m'avait déjà tiré d'affaire quelques fois, mais si la DS peut bien voir le nouveau réseau, par contre, je n'ai pas encore réussi à m'y connecter. Echec à la première tentative. Freeze de la DS à la seconde (dans runMe). Serait-ce lié au fait que je n'ai pas su définir de clé WEP pour le nouveau réseau ?

Je n'ai plus le concierge-Mario Kart, mais j'ai un menu de configuration wifi dans Phantom Hourglass ... qui ne fait guère mieux. Le pilote est maintenant maintenu par les gens du Noyau et son firmware est pré-distribué par la Fédération Ubuntu.

The WorkFromHome Empire has struck hard the WiFi portal that allowed me to communicate with Bilou and Bouli. I had to accept a new modem/router device so that their secured hyper-tunnel would get shielded against pulstar 192.168.0.24, but the result is that the whole stellar system now has to use WPA instead of WEP. And unfortunately, the DeepSpace cruiser of Bilou and Bouli only communicates over WEP.

I hopefully managed to recover my ZD1201 probe and dispatch it in the quadrant. It had proven effective to recover WiFi portals a couple of times already. The good news is that it is now part of Ubuntu Federation and their Kernel Teams' standard tools. It was quite trivial to confirm that the probe was accepted as an access point by the DeepSpace cruiser. Getting it in sync with that access point proved more complicated.

Wireshark restait muet. Ce n'est pas surprenant: si les paramètres de chiffrement sont incorrects, le stick wifi ne reconnaîtra pas les ondes comme étant un paquet pour lui et ne passera rien à la pile réseau Linux.

Mais ça c'était hier. Je viens de refaire un essai avec la tablette de ma fée d'abord, puis à nouveau avec Phantom Hourglass et je vois enfin des requêtes DHCP dans wireshark. Dont une avec une adresse MAC de chez Nintendo. Tout espoir n'est donc pas perdu.

Par contre, le logiciel que j'avais utilisé à l'époque pour le DHCP n'est plus distribué par Ubuntu qui lui a préféré UDHCPD, l'implémentation interne à BusyBox (dont il faudra que je vous reparle). Donc,

# The interface that udhcpd will use
interface enx00cafe00babe # default: eth0

devrait me permettre d'être serveur DHCP sur le stick wifi (à l'adresse MAC improbable 00:ca:fe:00:ba:be) tout en restant client sur les autres.

J'avais tenté d'utiliser une adresse statique hier, évidemment, mais sans succès. Au moindre test de connexion, le logiciel WFC sur la DS me lâchait juste un "paramètres incorrects". En réalité, si on désactive les requêtes DHCP sur la DS, il faut impérativement fournir *tous* les paramètres, y compris la passerelle à utiliser, le DNS, etc. j'ai probablement été un peu négligent là-dessus.

Running a similar test with my fairy's tablet proved it could be working, even without setting a WEP key (no clue how to define that with iwconfig properly, and not sure the ZD probe supports it). But if I try and use static IP address instead of configuring a DHCP server on the laptop attached to the probe, then I need to configure *all* the network parameter manually -- including Gateway and DNS -- else Phantom Hourglass' WFC manager would just shout "invalid parameters" and that's it.

So I finally got the MAC address of the Nintendo DS showing up in wireshark, proving that WEP handshaking worked. Now I'll have to find a way to mimmic the DHCP configuration I once used for udhcpd, the BusyBox-related tool Ubuntu Federation integrated to replace the legacy thing I knew. To be continued.

Affaire à suivre. Pourvu que nos héros tiennent bon.

Quand j'aurai pu vérifier que ça fonctionne, il me restera à créer une liste de règles iptables propres aux échanges avec les Nintendo DS (disons DSIN), y rediriger le traffic entrant venant d'une adresse MAC de NDS (/sbin/iptables -A INPUT -m mac --mac-source 00:0F:EA:91:04:08 -j DSIN) et jeter tout le reste qui vient de l'interface supplémentaire-et-non-protégée. (/sbin/iptables -A INPUT -i enx00cafe00babe -j DROP)

Saturday, July 10, 2021

Pas vraiment un Zelda ?

Bon, ça fait quelques semaines, maintenant que j'ai fini Breath of the Wild, et je dois bien dire que c'était un très bon jeu. Ça au moins, ça ne fait pas de doute. Par contre, est-ce vraiment un Zelda ? Les personnages sont là, c'est indéniables, mais la série Zelda, c'est un gameplay en plus d'un univers. La série a commencé avec un gameplay "sauce soja" avec des ennemis qui mettent l'accent sur la mobilité et des donjons à clés.

Occarina of Time a lancé un deuxième type de gameplay "au ketchup" avec des ennemis qui mettent l'accent sur la visée et des donjons tordus dans tous les sens. Mais que l'on soit dans l'un ou l'autre il y a un nombre significatif de mécaniques de jeu qui sont restées inchangées. Les petits coeurs dans les buissons ou les clés-du-boss. Les items qui servent à la fois d'arme et de moyen de transport, et qui doivent être acquis à la sueur de nos neurones dans les donjons.

Breath of the Wild donne un gros coup de pied dans tout ça. Tous les objets spéciaux sont concentrés dans le prélude (équivalent de la période "trois talismans" pour les habitués de LttP ou OoT). Des armes à durée limitée et un stock de plats cuisinés à partir d'objets ramassés pendant la quête qu'on peut manger même au milieu d'un combat de boss. J'ai commencé par penser qu'on était sur une troisième sauce (disons "moutarde  l'ancienne"), mais à voir un peu la diversité de la licence à l'occasion du Zeldathon, en particulier les "Hyrule Warriors", je me dis que Breath of the Wild est peut-être plus proche d'un nouveau plat que d'une nouvelle sauce.


Saturday, July 03, 2021

3-rooms todo board

The 'todo board' for School Zone worked quite well. Maybe I should make one for my "3 rooms" milestone, given how unlikely I am to do large amount of work for homebrew project these days...

(Well the milestone description for "3 rooms" is in itself a sort of todo-board; just focusing less on what is not going well right now)

And in case you see Bilou heads all over the place again, make sure you get a look back at that Bug Punch post...

Un montage graphique pour me rappeler de ce que j'ai à corriger, ça n'avait pas trop mal marché quand j'avais démarré la School Zone. Je me dis que ça pourrait marcher aussi pour mon challenge des "trois téléporteurs" ... Tentons, donc.

Tuesday, June 22, 2021

Je suis un n00b

J'ai découvert la guilde  NOOB de Fabien Fournier via twitter lors de l'appel à participer à leur levée de fonds pour créer un jeu vidéo. En soi un évènement assez banal, sauf que cette fois, les personnages du jeu étaient déjà connus depuis 6 saisons par les spectateurs de la Websérie - un concept qui, lui aussi, m'était inconnu. Intrigué, je lance l'intégrale de la saison 1, je regarde le présentation de Gaea qui crée son perso  avant de me souvenir que j'ai Une intervention prévue en salle des machines.

Quand je remonte, ma fée m'a chipé ma chaise de bureau et est en train de rigoler devant le Jack Céparou. c'est la période où on vient de changer de box, et le nouveau modèle permet de regarder des vidéos Youtube sur la télé. La guilde va donc se faire sa petite place au chaud dans nos soirées entre les Dr. Who et les épisodes de Castle. L'humour, la parodie et le second degré vont permettre de proposer un divertissement très réussi malgré un budget d'amateurs et les personnages bien croustillants, au juste équilibre entre réalisme et caricature nous auront définitivement convaincus.

Soyons clair: le jeu d'acteur de Gaëa, Omega Zell, Arthéon et Sparadrap est excellent. Le truc, c'est qu'ils n'ont pas à être crédible en tant qu'invocatrice ou assassin. Ils sont crédibles en tant que geeks qui incarnent des personnages. Et ça, ils le font superbement bien. Pareil pour les inévitables combats. Quand un JDG nous sort un épisode dans lequel il est supposé être CanardMan mais qu'il se bat plutôt comme léguman ... bin ... c'est mignon puis c'est tout.

Ici, plutôt que d'essayer de faire des combats de dingues à la Seigneur des Anneaux, la série joue sur le fait que c'est un combat dans un jeu vidéo. Oui, les coups sont ridiculement mous par moment et on tape dans le vide à d'autre, ce qui compte ce n'est pas le réalisme avec lequel l'acteur combat mais le petit '-200PV' (ou parfois '-2PV') qui accompagne pour nous envoyer un 'bin oui, on est dans un jeu! t'avais oublié?'

Quand ma fée est revenue de la bibliothèque avec le roman "La pierre des Âges (saison 1.5)", je savais déjà bien qu'il y avaient des 'produits-dérivés' de l'univers de Noob. Mais j'avoue qu'entre le graphisme pas franchement à mon goût de la BD, l'idée euh-ouais? de Néogicia et le fait que je ne suis pas un joueur de mmeuporgs, je ne m'étais pas précipité pour acheter les romans. Bin j'aurais peut-être bien dû. Parce que non, on ne verra pas Sparadrap faire l'andouille ni Omega Zell prendre la pose dans le roman, mais c'est toujours bien la même écriture et les même personnages. Fabien Fournier a réussi à choisir un style équilibré entre la narration classique, les dialogues comme-dans-la-série et les chapitres dans-la-tête-du-perso. Quand je lis les répliques, j'entends les voix de Sparadrap ou d'Arthéon dans ma tête. Je vois les grimaces de Gaëa qui cogite. J'aimerais entendre la voix de Zell, mais n'ayant pas l'acceng, c'est plus difficile.

En plus de ça, le "1.5" un peu troublant au départ prend tout son sens une fois la lecture entamée: chaque saison de la web-série démarre par une introduction en vitesse d'un nouveau contenu dans le jeu-qui-n'existe-pas Horizon. Au risque de voir le spectateur décontenancé par les références au sans-âmes, à la Pierre des âges, un nouveau continent, une nouvelle faction ou que sais-je encore. Les romans, eux, traitent justement du passage entre ces saisons, sur fond de quêtes-d'investigations, de rumeurs de forums et tutti quanti. Bien trouvé. Bref, j'ai accroché et ma fille a laissé de côté ses re-lectures de Harry Potter pour se plonger dedans (le "bin non les louloups, je ne vais pas vous mettre la saison 3 tant que *deline est occupée à lire le tome 2.5" n'y étant peut-être pas tout à fait étranger)
 


Sunday, June 20, 2021

Gris

J'ai eu pour switch. C'était en Mars. Et soyons clair, un jeu qui avait eu si bonne presse qui passe sous les 10 euros, ce serait pingre de passer à côté.

Si quelqu'un doute encore qu'un jeu vidéo puisse être une oeuvre d'art, Gris est la réponse à lui opposer. Dans de nombreux jeux, l'aspect 'mécanique', les règles du jeu et l'implication du joueur priment sur ce qui peu faire figure d'oeuvre d'art. Soyons clair, trouver une dimension artistique dans Tetris ou new Super Mario Bros, c'est loin d'être gagné. Dans gris, au contraire, les créateurs n'ont pas hésité à sacrifier à certains codes du jeu vidéo pour donner plus de puissance à la dimension artistique. Ainsi, pas de monstres à vaincre ou de pièces d'or à collecter. Ce qui importe, c'est le voyage, et à travers le voyage, le message qui est véhiculé par le partage d'une expérience plutôt que par des mots. J'en veux pour preuve l'introduction de ce 'compagnon cubique'

L'ambiance du voyage est sublimée par une bande son hors pair qui emprunte tantôt à Ori, tantôt à Fez, tantôt à Journey (que je n'ai toujours pas eu l'occasion d'essayer) sans que ces emprunts ne donnent l'impression d'être des plagiats pour autant. Ce n'est pas pour autant juste ... subordonné ? Prenez la mécanique de 'ground pound', par exemple. Dans Ori, elle permet des attaques plus puissantes ou de débloquer des zones inaccessibles. Assez logiquement, elle est placée au milieu du jeu qui met l'accent sur la mobilité (et du coup offre le double-saut presqu'immédiatement). Dans Yoshi's Island, elle fait partie des mécaniques centrales du jeu. Disponible à tout moment, mais aussi utilisable dans de nombreuses situations y compris contre le boss final qui possède une attaque tout à fait identique.

Ici, c'est un pouvoir à débloquer mais c'est le premier. Il est combiné avec la possibilité de se déplacer sous forme de rocher carré, ce qui produit un sentiment de lourdeur. Il ne constitue en rien une 'attaque plus puissante' comme c'était le cas dans Yoshi ni un 'sésame précieux' pour franchir des portes jusque là fermées (que l'on aurait déjà vu avant d'avoir le pouvoir, j'entends). C'est plus une sorte de gros caillou qu'on va utiliser comme outil en espérant trouver mieux plus tard. Et vu que le dernier pouvoir suggère l'harmonie et la reconstruction, je pense que c'est loin d'être un hasard. "We're broken, and all we can still do is break more".

Wednesday, June 16, 2021

Please Deflate your UI

 The last one to do it are Firefox people (dropping "compact" layout), but let's make it clear: using pixels of our screens (especially vertically) is becoming increasly difficult as touch screen get prevalent. I've been trying to avoid Adobe Acrobat Reader DC for as long as I could for that very reason too.

Please, once for all, make the padding-around-icons/text/UI elements a system-wide tunable feature. Stop having padding pre-built in your icons. It is not something you as a system designer should decide, just like you shouldn't decide whether I'll wear a tie or a bow. 

Look at that non-sense: there is so much ribbons and margins when I have a document to review that none of my screens would allow me to properly see an A4 page large enough so I could read the text effortless... unless I turn full-screen of course, in which case I no longer have access to people's comments.

(I truly wish there was an open-source alternative to adobe review system, but given that they now try to automatically upload reviewed documents on their cloud, I doubt that is about to come)

Hopefully, with Firefox, you can toggle browser.compactmode.show and have 'compact' option showing up again when you try to customize your menu bars.

Friday, June 11, 2021

Running like Mario

I had my 'Mario Story' book in hands again a few weeks ago and met a quote that I wasn't expecting from Miyamoto-sensei. He was explaining that Mario's walk/run cycles deliberately not match the speed at which they move on the ground. I'd have expected it to be linked to the first Mario Bros game where "ground is slippy", but actually, the ground truth is that if they tried to make Mario's feet stick to the ground like a lemming, controls feel less responsive and gameplay isn't that fun.

Yes. You read it well. Mario's frantic feet speed and instant flip may make him feel slipping, but at least he's instantaneously responding to our controls, unlike some Prince I wouldn't name. And unlike my own character, to some extent.

Amusing timing, somewhat later, I discover 'New Super Mario Land', a homebrew title trying to rebuild Super Mario Land (GB) for SNES using graphics from New Super Mario Bros and a custom engine.

Eh bin, y'a des gars qui sont passés maîtres dans l'art de mettre une ROM pour SNES dans la cartouche d'une autre. Et ils ne se limitent pas à en profiter pour avoir une version 'hardware' d'un jeu introuvable plutôt qu'une énième copie d'un nanard à grand tirage. Non: ils peuvent aussi décider de faire ça avec un mod d'un jeu existant (disons Secret of Mana II traduit en Anglais ou Kaizo Mario World), une ROM homebrew comme le dernier titre d'Alekmaul ou en l'occurence, un remake de Super Mario Land avec des graphismes tirés de New Super Mario Bros.

And Nagler-- the homebrew author -- did what Nintendon't: they adjusted animation speed to the pixels
Mario travels. It's tricky to to say anything about the feel without playing it ourselves, but from the look of it, it definitely seems heavier to control than our usual mustachied plumber.

So finally, I'm pretty glad on only used the 'stick-to-the-ground' for walking and went for a more Mario-styled dont-care-the-ground for the run cycle. Still, I prefer Bilou's bending feet over Mario/Kirby 3D models with feet that hit the ground at weird angles, unaffected as if they were walking __through__ the ground instead of __on__ it.
Nagler, à qui on doit ce homebrew, a repris les étapes d'animations de Mario telles qu'on les trouve dans la version NDS mais a recodé toute la partie 'moteur de jeu', et en partie 'quelle image jouer à quel moment'. On aurait pu trouver meilleure illustration du choix de Miyamoto-sensei rapporté dans l'Histoire de Mario (p. 240)

Lors du développement de Popeye, il avait d'abord tenté de reproduire les gestes du marin en calquant le dessin animé image par image, mais le rendu [...] ne convenait pas au rythme frénétique d'un jeu vidéo. Plutôt que de modifier son allure, Miyamoto décide d'accélérer le mouvement des jambes sans toucher à la vitesse.

 Tout l'inverse de ce que j'ai cherché à faire avec la marche de Bilou, en fait. Heureusement j'ai changé d'approche pour la course.

edit: eh bien par contre, si on fait bouger les jambes trop lentement plutôt que trop vite, ça donne vraiment des résultats peu convaincants.

Sunday, June 06, 2021

Critical Link : prends ça, la mandre!

Arrivé devant la "dernière" machine de ma partie de Breath of the Wild, j'ai vu débarquer des espèces de drones de surveillance le long d'un sentier escarpé. Et ce alors que je dois faire le trajet accompagné d'un goron un peu niais à qui je dois signaler "viens" ou "stop" en plus de me faufiler.

J'ai été pris d'une inquiétude: je les voyais venir avec leurs gros sabots nous rejouer le classique éculé du labyrinthe où il faut passer sans être vu tandis que des surveillants zélés (à défaut d'être fûtés) font inlassablement des allers-retours. J'ai laissé s'échapper un soupir et annoncé à mon fiston que c'était tout pour cette fois-ci: je ne me sentais pas d'humeur à me faire ramener à mon point de départ encore et encore jusqu'à avoir appris correctement les mouvements des drones. Pas avant le souper.

'faut dire qu'ils nous l'ont resservi ad nauseam, leur jeu de cache-cache, depuis le passage dans les jardins du château d'Hyrule (OoT). C'était passable à ce moment-là au niveau du scénario: un gamin n'a rien à faire là et un garde ne va pas blesser un gamin qui ne représente de toute évidence aucune menace sérieuse. Mais bon, on nous a remis le couvert dans Minish Cap, dans Spirit Track et même dans Link Between Worlds (cette fois pour s'approcher du Palais des Ténèbres).

Ce n'est pas l'aspect "infiltration" en soi qui m'ennuie -- j'ai d'ailleurs plutôt apprécié le Temple du Roi des Mers dans Phantom Hourglass -- mais plutôt que ces phases interdisent le plus souvent toute créativité dans le jeu.

Mais bonne nouvelle, si le premier obstacle nécessitait bien de la jouer "infiltration", le reste du parcours pour passer d'un canon à l'autre ne se répète finalement pas du point de vue du gameplay. Ici de l'escalade, là-bas un peu de manipulation de caisses métalliques, ensuite un peu de "gel d'ennemis" pour gagner du temps. Je suis finalement passé du premier coup et sans ressentir d'agacement ou de déjà-vu. BotW est donc ici fidèle à lui-même, avec un gameplay tout en variantes et pas trop en profondeur.

Cette liberté d'action parviendra-t'elle à convaincre mon frangin qui trouvait qu'il y avait trop de mouvements dans Super Princess Peach ?

edit: Ah, mais je sais pourquoi c'est passé avec Phantom Hourglass! C'est une histoire de ce-qu'on-perd-si-on-rate. Dans OOT et LBW, être repéré signifie un retour instantané au point de départ du jeu, comme si tous nos petits coeurs ne servaient en fait à rien. Au contraire, dans le temple du roi des mers, si un spectre vous voit, il passe l'étage en mode alerte et vous pourchasse, mais tant qu'il ne vous touche pas, tout n'est pas perdu. C'est stressant, certes. C'est technique indubitablement. Mais on reste dans la logique A-RPG où le jeu ne peut pas vous imposer une pénalité à moins que vous ne commettiez une erreur.