Friday, September 28, 2007

Ready ? Set ... Go !


Pour un vieux de la vieille comme moi, ce genre d'image a quelque-chose de totalement surréaliste ! Sonic sur la nintendo DS ou la GBA, on en était déjà tout paf, mais bon, on a fini par s'en remettre. Un combat à mort entre Kirby et la princesse Zelda, on est surpris un instant, mais quand on a réalisé qu'il s'agissait juste d'une grande rencontre entre tous les personnages de Nintendo, bon, pas de quoi s'affoler.

Mais ici, on touche au délire qualifié d'irréalisable il y a 15 ans par nos parents: un décathlon où Mario et Sonic peuvent s'affronter (et comme ils ont tous eu pleins de potes depuis, Daisy vs. Knuckles ou Bowser vs. Dr. Eggman est aussi envisageable ^_^)

Tout ça sur la Wii, comme nous l'annonce Edgar de "4 colors Rebelion". Donc, on pourra même se faire un 400m sans démolir nos paddle comme du temps de Summer Games Challenge sur C64.

Sunday, September 23, 2007

Je jette l'éponge.

Un peu de rangements dans le living, ce week-end. Je suis retombé sur deux petits croquis préliminaires de "Bop L'éponge" qui doivent dater plus ou moins du déménagement. Du coup, je les ai rajouté au post initial du 21 février. L'occasion de se faire une rétrospective de la section level(/game/monster) design ?

Ce qui est sûr, c'est que ce sera plus fun que le coup des messages d'horreur ou du débugging de mikmod :P

was busy tidying up the living-room this last week-end (new fairy's desktop is here, shelves had to move to give it more room. And while moving stacks of sheets, i located a couple of preliminary drawings for "sponge bop". I'd say they're likely to date back from march when i was moving in our new house.

Well, anyway, i just added them to the 21th february's last post. Maybe it could be a good reason for reviewing the "level/game/monster design" section of the blog ? Well, i guess it will be funnier than those last post about C++ Horror Messages or deep-debugging of the libmikmod.

Friday, September 21, 2007

libmikmod deep test

I turned down the volume of my PC yesterday and let the DS be the music center, using a couple of updates on my "file server" (mostly truncating filenames and ungzipping on the fly submitted files). That was a fun time, but it revealed several oddities in the playback, so i have decided to delve deeper in the mikmod player library this lunch time to see whether i could improve playback.

The whole story is atm. only detailed in french, but to put it shortly, i mnaged to play a couple of .IT files from my brother thanks to a small patch (skip rendering in the first few ticks). I wish i could have opted for hardware playback, too, but this one seems completely buggy atm (understand: it completely locks down the system :P)


Hier, j'ai baissé le son de mon PC: c'est la DS qui a pris le relai, moyennant deux ou trois petits ajouts au programme servant de "serveur" côté PC (notamment, décompression à la volée et troncage approprié des noms de fichiers).

C'était sympa, mais le player a méchamment tendance à bugger, notamment au démarrage. J'ai essayé d'y voir un peu plus clair dans le code de mikmod (cf le post plus long). Il y a pas mal de positifs (j'arrive à jouer "Prehis2.it" de mon frère, par exemple ou la "pipe zone"), mais je crains que le player software ne devienne vite trop gourmand. Et le player hardware ? bin il crashe tout. oui, ma bonne dame.



note that while the job of hardware driver's update is straightforward, the software driver will actually try to fill the playout buffer at each step.



Software Mixing

Bon, le mixage hardware plante tout. comme ça au moins, c'est réglé. Dommage: le mixage software va être beaucoup plus tordu. Ici, le fonctionnement du mixeur est guidé par le playout buffer, une zone de mémoire dans lequel notre processeur principal construit un "wav" que le processeur secondaire (ARM7 et les circuits de la DS) transmettent vers nos oreilles.

Tout ce joue à l'aide de deux indicateurs de position (les "curseurs" dixit la bibliothèque mikmod) qui repère où en est l'écriture et où en est la lecture dans ce qu'il est commun d'appeler un buffer circulaire. Notre driver software va donc, à chaque appel de sa méthode Update(), calculer le nombre de bytes libres dans ce buffer et faire appel au virtual channel qui est chargé d'avancer dans le pattern et de produire des bytes.


#if 0
if (isfirst) {
isfirst--;
return;
}
#endif
il y avait dans Player_HandleTick() ce curieux bout de code avec comme commentaire "don't handle the very first ticks, this allows the other hardware to
settle down so we don't loose any starting notes"
. En clair, le "#if 0" désactive le bloc en question, qui avait pour effet de ne pas générer de données sur les "isfirst" premiers appels à HandleTick(). Comme quasiment tous mes mods démarraient de travers, je l'ai simplement réactivé, et je ne suis pas mécontent du résultat.


Mikmod_Update()


while(1) {
ge.handle();
MikMod_Update();
ge.animate();
}
Bion. Donc chaque appel à MikMod_Update(), pour la version "software mixing", le player va estimer combien de bytes du buffer ont déjà été joués et les remplacera par des nouveaux. Reste à quelle fréquence on va appeler cette fonction (plus elle sera appelée souvent, plus son temps d'exécution sera court, du coup).
La méthode la plus directe (et utilisée dans Tetris Attack) consiste à la placer après le traitement d'une nouvelle image.

Dans cette approche, le programme va alterner les tâches suivantes:
  1. lire l'état des boutons, de l'écran tactile, etc. et réagir en conséquence
  2. attendre le prochain rafraichissement (d'écran, hein. pas un soda-glacé)
  3. remettre à jour les tables de sprites (non, c'est pas non plus un rafraichissement. m'enfin)
  4. appeler mikmod_update pour produire plus de son dans le buffer
  5. traiter les animations
A première vue, c'est sous-optimal: on voudrait avoir le rendu du son comme tâche de fond, p.ex. pendant que l'on attend le rafraichissement d'écran (tant qu'à attendre, ...)


Wednesday, September 19, 2007

Message d'horreur

J'ai choisi C++ comme langage pour mes bricoles sur la console Nintendo. Principalement parce que c'est un langage que je ne maitrise pas, en fait. J'aime bien le côté "orienté objet" de la programmation: je trouve ça plus propre. La plupart de mes lignes de codes ont d'abord été cogitées sur papier en UML et petit à petit, je commence à m'y retrouver dans les std:: ...

Mais franchement, je me demande à quoi pensait Bjarne Stroustrup quand il a inventé ce langage. J'aurais tendance à proposer une règle d'or pour la programmation: ne jamais imposer au programmeur d'écrire deux fois quelque-chose à des endroits différents. C'est systématiquement dans ces cas-là qu'on se retrouve à modifier l'un en oubliant l'autre.

I chose C++ to implement my homebrew editors and game engines on NintendoDS, mostly because i'm curious of gaining some experience in that language, and of course, because i tend to think in OO whatever the language. If i was to design a language, my golden rule would be "never require the same thing to be written twice, for coders are lazy and it would produce bugs". It seems that C++ is the exact opposite. Sometimes, it's even worse: you have to declare all your variables in your class "header", but you may not initialize them there. You can give default values in the method prototypes, but not in their declaration. Etc.

Eh bien, C++ donne l'impression d'être construit sur le principe de faire faire systématiquement l'inverse! Pire, une partie de l'information ne peut apparaître que dans une des copies. Résultat: vous devez déclarer vos variables, mais vous ne pouvez pas en profiter pour les initialiser à ce moment-là! Vous pouvez aussi donner des valeurs par défaut à vos arguments, mais attention! pas dans le fichier qui contient le corps de la fonction.

Bref, c'est l'horreur. Et comme si ça ne suffisait pas, le compilateur en rajoute une couche en pondant des messages particulièrement impigeables (du moins, pas avant une longue discussion avec Candy sur ICQ ;)

Je vous le donne en mille:

SpriteSet.h: In copy constructor 'SpritePage::SpritePage(const SpritePage&)':
SpriteSet.h:47: error: invalid conversion from 'const SpritePage*' to 'unsigned int'
SpriteSet.h:47: error: initializing argument 1 of 'std::vector<_tp>::vector(size_t, const _Tp&, const _Alloc&) [with _Tp = short unsigned int, _Alloc = std::allocator]'
Déjà, les constructeurs de copie sont particulièrement pénibles à manoeuvrer, mais là, j'avais essayé d'en faire un pour une clase qui étend le "vecteur standard". Résultat, un message complètement opaque qui me donne tellement de détails que je n'en vois même plus le message principal.

Unfortunately, the compiler's error messages are cryptic at best. Hopefully enough, a friend of mine (Candy) was here to help with copy constructors ... Or maybe i shouldn't have tried to extend std::vector before i'm grown up to the wizard++ rank ?
main.cpp:485: undefined reference to `vtable for WConsumer'
main.cpp:485: more undefined references to `vtable for WConsumer' follow
(.rodata._ZTV12DumbConsumer[vtable for DumbConsumer]+0x14): undefined reference to `WConsumer::setFile(char*)'
collect2: ld returned 1 exit status
Là c'est encore mieux: les probèmes de fonctions virtuelles. Ici, vous avez la version "simple", où le compilateur détecte qu'il me manque une fonction "setFile" déclarée dans l'interface WConsumer, mais pas implémentée par DumbConsumer (un effet du refactory ;P). Dans sa version plus perverse, le message d'horreur se limite à répéter "undefined reference to 'vtable for WConsumer'" sans rien ajouter d'autre. Bin si c'est le cas, et si WConsumer était supposé être une interface, courrez bien vite vous assurer que toutes vos fonctions virtuelles sont assorties d'un "=0" dans la déclaration de la classe (qui devient du coup une classe virtuelle pure).

Another one that gave me headaches: troubles with virtual methods. Here, you're facing the "simplest" case, where the compiler detects i'm missing the "setFile" function of the WConsumer interface in the DumbConsumer implementation. In its 'advanced' evolution, this horror message just repeats "undefined reference to 'vtable for WConsumer'" without any additional information. If that's the case, and if WConsumer is supposed to be an interface (i guess i've got quite some experience with Java, after all), hurry up to your .h file and double-check you added "=0" to all your pure virtual methods to make your class a pure virtual class.

You guess'd it: i'm feeling like Alice in the rabbit's hole ... completely lost when the Mad Hatter throws at me "Moreover, if you want things to get right, you should declare your destructor to be virtual".

Bref, je suis comme alice dans le terrier du lapin, complètement paumé lorsque le chapelier fou me lache innocemment que "moreover, if you want things to get right, you should declare your destructor to be virtual"
"Alice: My what to be what !?"

Thursday, September 13, 2007

Supersized DS

La scène homebrew, ce ne sont pas seulement des petits programmeurs comme moi, c'est aussi une fameuse bande de félés du fer à souder qui vous branchent tout et n'importe quoi sur la console, le plus souvent via une cartouche GBA (la DSmotion, p.ex) ou le slot DS (DSSerial, avec interface RS232 (pour le midi, par exemple) et de l'USB). Mais là, je tire mon chapeau à loopy et son jumbotron Je me souviens de ces "gameboys surdimensionnés" où les gamins se suivaient dans les grandes surfaces. Voilà l'équivalent DS. 

DS Homebrewery is not only about software programming on unusual hardware. It's also the stunning world of soldering-iron-wizards who plug anything into your handheld console. Most of the time, they just integrate weird stuff in the GBA cartridge (such as accelerometers in DSmotion) or on the DS card (like a RS232 serial interface and a programmable microcontroller in DSserial). But this time, loopy did the stunning job of duplicating screen&touch I/O of the console to large tabletPC screens. hear! Enjoy the one and only Jumbotron DS, the device that will let all the kids around see how bad you are at zoo keeper :P 

 

edit: in 2021, Hackaday wonders why there hasn't been more NDS hacks. Here's my list of known (hardware) hacks.

Tuesday, September 11, 2007

Refactory

Re-thinking the .spr file format, writing command-line tools to manipulate sprite pages, extending "runme" application so that it can display and perform basic manipulations on both .spr and .pcx images, cleaning up the sources of the "wifi file transfer and self-update" component so that they can be later used in the 'refactored' version of SpriteEditor ... those things take time, plenty of little things to be modified, and requiring patches all over the source to keep the application working.

Well, at least now, i can merge all the "green"-related sprites in one single file, but i haven't most of the widgets that will be required to edit such file in SEDS.

That's progress, undoubtfully. Slow progress, but progress nonetheless.


Il faut repenser le format ".spr", écrire des petits outils en ligne de commande pour manipuler les tables de sprites (fusions/acquisition ... euh. je m'égare), ajouter des petites opérations de base sur les .spr et les .pcx dans "runme" pour en faire quelque chose d'utile. Ensuite, il faudra réintégrer tous les composants modifiés dans le Sprite Editor (j'ai bien pensé à un moment faire de runme le sprite editor, mais ça n'aurait pas de sens, un sprite editor avec un module player intégré :P).

Bref, bran-le-bas de combat: ça s'appelle du "code refactory". Réusinage de code ? Enfin, c'est le moment où on démonte tout pour le remonter (mieux) après, en espérant ne pas perdre l'état précédent qui ne marchait pas tout à fait si mal que ça, finalement :)

Wednesday, September 05, 2007

.: easy :: normal :: hard :.


Suite au commentaire de CJ sur "armageddon machine", j'ai cherché davantage de niveaux de Commander Keen 4 & 5. Je suis tombé sur une véritable mine d'or: les niveaux tels qu'ils seraient vus dans TEDEDIT 5, l'outil d'édition de niveaux de Apogee/ID Software, réalisés par "pleinair123". Le layout même de ces niveaux suggérait que pleinair123 avait accès pas uniquement à des screenshots réassemblés, mais bien à une reproduction de ce que donnerait un éditeur. J'en veux pour preuve les flèches transparentes, qui servent de guide aux plateformes mobiles et surtout, ces curieux blocs gris avec un B que vous voyez à gauche de l'image et qui, selont la légende, servent de "frontière" pour les objets qui rebondissent (étoiles à pointes, passerelles, etc.)

Intéressant de constater que, bien que les éléments du jeu soient nettement plus sophistiqués que ce qu'il y avait dans le GameMaker, ce simple "plan" supplémentaire contenant les ennemis et ce genre d'objets de contrôle invisible permet des fonctionnements bien plus riches en se prenant nettement moins la tête.

Déçu, par contre, par l'absence de map équivalentes pour "Secret of the Oracle", j'ai cherché tout ce qui pourrait m'aider à reverse-engineerer les fichiers .CK4. Bin j'étais pas le premier : http://files.keenmodding.org/mobydoc.txt

We've been playing Commander Keen 4 and 5 almost exhaustively with my brother. Or at least with thought we did, since he commented my tale of the Armageddon Machine level sounded completely new to him. Thing is: we were playing in easy mode. Were there more level maps I could compare and analyse ? Oh yeah. And even better, the maps show levels as they are in the editor. There, you can see for the same level, the amount of enemies you get in easy / normal /hard modes changes quite significantly. From 6 to 17 dash-when-spot-you "Sparkies", from 3 to 9 zooms-along-poles Ampton, and some invulnerable SliceStars including one you'll have to avoid while passing a set of blue "firewall" beams. The maps and the route may be the same, but the story you unroll while playing definitely won't.

We can then see that there is an additional tile layer, used for special things like platform guides, enemy-only walls, and things alike. While being conceptually simpler than RSD Game-Maker attributes, it seems to be much more powerful. (I couldn't find an equivalent set of maps for the Secret of the Oracle, unfortunately). But I did find files.keenmodding.org, where you can have all the help you want to break apart, modify and re-assemble the .CK4 files defining levels for that game. Does that mean I'm about to build KeenDS ? Not quite.

Tout est là. De quoi se faire son petit éditeur ou viewer pour Commander Keen. Maintenant, que ceux qui pensent que celà veut dire qu'on est à 2 doigts d'un KeenDS s'arrêtent tout de suite:
1. Commander Keen est toujours la propriété intellectuelle d'ID software
2. Son inventeur serait ravi de refaire des Keens s'il récupérait cette propriété intellectuelle
3. Tout utilisation non-privée des infos dans "mobydoc.txt" (comme un homebrew) constituerait une violation des droits d'auteurs de Apogee
4. Il resterait quand même le plus costaud: reconstruire le comportement de tous les monstres, la physique du jeu, etc.

Bref. Je pense que ça n'intéresserait pas grand monde un keen sur DS qui avance mal, qui saute de travers et où les robots roses ne montent pas aux barres. Donc, je vais rester sur mon Bilou et ses éditeurs de niveau (non, la structure des niveaux de Commander Keen - même si elle est source d'inspiration - n'est pas géniale au point de vouloir utiliser TED pour Bilou :P)

Oh, et pour ce qui est du titre, je prends le niveau "security" de Armageddon Machine (le 2eme du jeu), au pif.

Mode easy: 6 Sparky, 3 Ampton et 2 SliceStars.
Mode normal: 13 Sparky, 5 Ampton et 5 SliceStars
Mode hard: on rajoute 4 Sparky, 1 ampton et une SliceStar qui se balade horizontalement au milieu des écrans bleus ...

The thing is that Commander Keen IP isn't public domain. Even the character's original creator would love to give it spin offs if he could. And even the 'mobydoc.txt' file giving out the knowledge about how levels are packed warns users: this is for private use only. Modding: yes. Having fun with modded file: yes. Sharing modded game ? gray zone. Porting the game to other platforms: infringement.

Even if I wasn't concerned by such things (hint: I am), loading Goodbye Galaxy levels into NDS memory would only bring me a small chunk of what the game offers. I'd still have to reverse-engineer all of Keen's moves and every enemy's behaviour. This is not only a lot of work, this is also work where you aren't allowed the slightest deviation from the original gameplay. Noone wants to play a retro game where the character doesn't walk and jump as he used to do, and where enemies patterns are no longer quite what they were used to be. Do you?

Alors imaginez dans les niveaux plus loin, là où il faut commencer à rester sur les plateformes volantes pour ne pas mourru sous un feu crépitant de lasers, vous comprendrez vite que l'expérience n'est pas du tout la même.
Idem pour le niveau final. Ce que j'ai dit à propos des ennemis rebondissant dans un espace limité ne tient évidemment que s'il y en a (et il n'y en a aucun en mode easy dans cette partie du jeu). Le Shikadi Master est lui aussi réservé au mode "normal", et seule une rangée de lasers est activée, ce qui laisse au joueur le soin de passer à l'aide du pogo du côté d'où les lasers viennent sans être inquiété...

Donc, non, frérot: si t'as pas re-terminé les Commander Keen au moins en mode "normal", t'as jamais essayé plus que la "grande foire au bonus" réservée aux moins de 14 ans. Désolé.

edit: oh, et on ne sauvegarde pas au milieu d'un stage, hein ?

Tuesday, September 04, 2007

captcha!


Bon, j'ai une confession à vous faire: j'adore lire vos commentaires. Bin oui, voilà. C'est comme ça. Je bloggue mes trouvailles sur la DS en partie parce que c'est pas vraiment dans mon entourage direct que je vais recevoir moulte feedback sur cette espèce de "vie sous-terraine"...

Mais si le nombre de visites quotidiennes de mon blog est plutôt satisfaisant, il faut bien l'admettre: je ne croule pas sous vos commentaires (à part ceux de mon frère, et je l'en remercie ;)

Vous n'êtes peut-être pas du genre à blablater pour le plaisir. C'est le cas de Gédéon, par exemple, qui m'indique discrètement mes erreurs, mais qui se contentera de sourire derrière son écran la plupart du temps. Ou alors vous êtes ultra-overbookés au point que si je vous envoie un mail pour vous parler de mon blog, vous le lirez dimanche prochain -- comme Pierrick.

Et enfin, peut-être tout simplement que vous n'aimez pas les captchas. Vous savez, ces petits cryptogrammes qui apparaissent de plus en plus souvent sur le Web, où l'on vous demande de recopier des chiffres et des lettres pour prouver que vous n'êtes pas un zombie ou un vilain troyen, mais bien un honnête citoyen du web. Alors je me suis dit que j'allais faire le test, vu que blogger nous a sorti un widget "sondage". Que ceux qui trouvent que c'est bien de faire la guerre aux zombies avec les captchas votent "useful". Que ceux qui se foutent royalement des commentaires cliquent sur "i don't care".

J'en profite aussi pour savoir si vous n'auriez de toutes façon pas commenté du tout ("i wont comment anyway") ou si le seul fait d'avoir vu un captcha vous a fait froncer les sourcils ("annoying") ou tout simplement fermer la fenêtre de commentaires sans autre forme de procès ("comment-blocker").

voilà. C'est dit. Je me repens déjà d'être si curieux de vos préférence et je promets de ne pas abuser abusivement des sondages sur ce blog dans l'avenir.