Saturday, December 29, 2018

Wformat-truncation

Pretty impressive new feature of gcc/g++ available in the latest devkitarm.
Look at that.


MapWindow.cxx:377:23: warning: %i directive output may be truncated writing 
    between 1 and 2 bytes into a region of size between 0 and 9 [-Wformat-truncation]
snprintf(msg, 32, "@%i,%i : %s [%ix%i]",xpos, ypos, why,
                   ^~~~~~~~~~~~~~~~~~~~~
MapWindow.cxx:689:12:      report("editing meta-layer");
                                  ~~~~~~~~~~~~~~~~~~~~
MapWindow.cxx:377:23: note: directive argument in the range [8, 16] 
MapWindow.cxx:377:23: note: directive argument in the range [8, 16]
 note: 'snprintf' output between 32 and 42 bytes into a destination of size 32

- gcc detected that I'm calling that snprintf function with a value of 'why' that is actually the "editing meta-layer" string, which is 18 bytes long
- it understood that this and some numbers had to fit within 32-bytes output
- the format characters only take 9 bytes
- xpos and ypos are 16-bit values, needing at most 5 characters to be rendered on-screen
- 18 + 9 + 4 = 31. that's the case where all the numbers take only 1 byte. We have barely enough room to display the message (and its terminating zero character)
- 18 + 9 + 5 + 5 + 2 + 2 = 41. That's the case where we have all numbers using their maximum size. Note that GCC/G++ could guess that we'll only use numbers between 8 and 16 by looking at  blockop?16:8 argument!

Having such thing can be super precious when you know what's going on and want to harden your software. Hopefully, there is no overflow expected here. Only truncation. And since the purpose is to put a message on a 32-bytes wide line, I'm fine with truncation here. I'll have to tell that to the compiler the best possible way with some #pragma.

edit: oh, actually the compiler is even smarter than I thought: it can tell whether you checked for the return value and won't bother you if you handled truncation with an if (needed > sizeof(msg) - 1)
If the output was truncated due to this limit, then the return value is the number of characters (excluding the terminating NUL byte)  which would have been written to the final string if enough space had been available.
Oh, and by the way,
*snprintf() write at most size bytes (including the terminating null byte) to str.
So in my code where I want 32 characters on the 32-char-wide screen, I should have a 33-bytes buffer and pass 33 to snprintf.

Friday, December 28, 2018

How to choose the best cat

There is a post on Winter Mute's blog that really feels like it's been written for me. It is about people who build up their own solutions to problems that are researched to death and will stick to them even when being told that better solutions exist, whatever the drawbacks of their current solution. Somehow, it is not that far from the "not invented here" syndrom, explained from the point of view of someone who's been working hard to promote a unified way of doing things.

If I think about it, the very fact that I'm using a Nintendo DS to make games in 2018 feels like using a cat to clean up windows. I've been asked why not doing it with construct 2 quite a number of times, and people who know me would likely tell you that "oh, but he likes doing it for DS so much..." . I did have a look at a few construct 2 tutos, but they never made me feel like I'd love to do that instead of what I'm doing.

I've been asked too why I wouldn't buy a wacom tablet and save my assets as .png files. Granted, I could follow some online tutorials and grow some knowledge about some tools really used in the gaming industry. Yet, I insist on updating my sprite editor and yes, if someone insist that l should really try ASEsprite or something alike, I'm gonna be quite sceptical and likely argue that it's gonna be complicated. (like having to install Windows or Steam first, having to ensure I have a good mouse or be next to my PC to do pixel art, etc.)

I'm afraid it's not just about programming ...
And apparently, yes, I could be using MaxMod -- the cross-platform sound library shipped by devkitpro -- instead of the unpopular libNTXM with all those odd extensions I've been adding over the years. Possibly wintermute could have put something like "oh, but you know, I'm no professional window cleaner. I'm mostly doing this on my spare time" in his rant, and it would look even more like myself. I don't really have any excuse for this one. It's just that I've been investing time to master the code in libNTXM. It feels a bit like it's mine now. I feel home with it and I'm reluctant to leave that home and move to somewhat uncharted territories.

I know there is one thing for which I do not want to make compromises, and that's the quality of the end result. Be it a hobby or not, I do not want the game to feel half-baked. But when it comes to picking either library, using design patterns or learning new tools... well, I don't want anybody to feel offended or sad. But yeah, I'm doing that after my work hours. After my clean-the-mess hours, because aside all the amazing things I do at work, I still wonder if the game ideas I have would work great. Because there was something about C64 programming I loved.

None of this make Wintermute any less right that buckets and mops are better tool to clean windows, of course.

Thursday, December 27, 2018

Todo list update

La "todo map" pour le projet "School Rush" a pas mal progressé depuis sa mise en ligne en 2015. Heureusement, me direz vous, et sans doute aurez-vous raison.

Maintenant que l'objectif "School Rush" est atteint, il va falloir que je reprenne ça, et que j'y ajoute les révisions souhaitées pour le moteur de jeu (gestion des coordonnées relatives pour pouvoir se promener à dos de 'blador correctement).

Back in 2015, I drew a 'todo map' for my School Rush game, trying to capture the 'todo' items scattered over this blog, prioritizing them according to the 'finish the School Rush game' objective and show how they relate to that objective altogether. Now that the game is complete, I've found myself wondering what I should do next ... so let's proceed with a new and fresh list. 

There are a few engine revisions I'd like to do, there are tool updates to be done and tool updates to be validated (esp. regarding the level editor). There is the level map format that needs to evolve in order to allow more flexible multi-palette updates. I also would like to find time to review the scripting language so that we can (at last) edit characters behaviours directly on the NDS.

Il y a aussi des mises à jours d'outil (le fameux "rules.gam" et la supression des ennemis hors-cadre lorsqu'on redimensionne une map) qui n'ont pas encore été suffisamment testés à mon goût sur DS, et un ou deux remaniements du format des niveaux (pour permettre l'utilisation de 16 palettes sur tous les blocs du niveau) qui affectent aussi bien le moteur de jeu que l'éditeur de niveau.

Après, j'aimerais bien pouvoir m'attaquer à une adaptation du langage de script pour qu'on puisse les éditer directement depuis la DS. nom de code: beds / geds3.

Wednesday, December 26, 2018

virtual tilesets

How should I handle tilesets larger than the 1024 tiles the NDS hardware is designed to use? Quick maths show that with 16K unique tiles, I'm already consuming 1MB of RAM. Full 16-bit tile identifiers would address the whole 4 MB of RAM the NDS has.

Unlike in Eric's games, I cannot assume here that the RAM is just a cache for the whole game data (ROM) because the game data may only be accessed through the SD card interface, abstracted through DLDI which -- afaik - - does not support asynchronous reads. And the score-table l implemented lately suffered noticeable lag while accessing the filesystem.


So there will be only main memory and video memory. Echoing what happens on x86 CPUs Virtual memory management, I'll use "logical" for the identifiers related to the full tileset and "physical" for the identifiers related to (temporary) video memory locations.The two functions that deal with translation between the two  sets of tiles are linked to the scrolling updates: since the level map is made of logical identifiers, we need logical-to-physical conversion there. The other(new) function kicks out trees that no longer need to be in VRAM.

I haven't really found a use for a physical-to- logical map. And all my plans for a smart combine-bitmaps system to decide which tile to evict fell flat when I realised it would be smaller to just keep an integer counter for every physical tile. So I will avoid over-complicating things and just go for the array of counters.

I know the logical-to-physical map could use a hash table implementation. It would have at most 1k items present, i'd say that means the main table should be at least 2k entries large. One important thing to consider is that we will have to remove items quite often, which means resolving collisions with chained list would work better than by using the next available entry in the table. Especially given that we will likely find consecutive tiles present, for instance when we have a large structure on screen. Good thing is that since there is an upper limit to the amount of items present, we know an extra 1 k entries for the chained list with always be enough.

Now, one entry in such a table is at least 16-bit logical id + 16-bit physical id + 16-bit next pointer. that takes us close to 18kB for the table, while a plain array of physical identifiers indexed by logical id would take at most 32 kB. Granted, the diffeence is critical for SNEs deving, and likely significant for GBA deving. But here? is it really worth the extra memory lookups ? Is it worth doing divisions to get a good hash function? We'll look into that if I ever need more than 8192 unique tiles in a level.

Saturday, December 22, 2018

November playtesting

You might think a 16-years-old wouldn’t have interest in School Rush anymore, this is not the case for A. She will ask me whether I have my DS with Bilou’s game almost every time we spend more than half an hour in the same room. So whenever I know I’ll be visiting her family, I try to speed up coding so I can have fresh play-testing feedback.

As you have guessed, it happened on the 1st of November, with the “game over” release candidate. She had to leave early, so I couldn’t gather the level completion times I hoped to have. But as she was playing, most of the kids in the house gathered around the sofa, and asked whether they could play the game too.

For most of them, it was their first time with the game, although I presume most of them had prior experience with a gamepad. They seemed to enjoy the game, did not show excessive frustration, and globally favoured the “float” power-up over the punch.

Interestingly, they intuitively named the inkers “the lifts”, meaning that they considered them as useful feature to beat the level rather than as some opponents (possibly because they’ve seen their elder using them in first place).

One of them even made it until the pencils-in-a-cave challenge of level 3 before asking for help… and then failing with the three-sponges-over-the-ink challenge.

Sunday, December 16, 2018

One last fix.

I'm pretty pleased to hear my 5-year old asking me to play School Rush. But for some reason, j.l.n has a fascination about power. And in School Rush, he wants to get the power-ups. He knows the pendats hold them and so he wants the pendats down.

"Papa, je peux jouer à Bilou?" .. Celle-là, je l'ai attendue ! Et voici donc J.l.n qui, du haut de ses presque-6-ans s'attaque au niveau qui avait été dessiné sous la direction de sa grande soeur. Mais pour une raison que je n'ai pas encore identifiée, mon p'tit bonhomme est plus ou moins fasciné par la puissance. Et dans school rush, la puissance, c'est le power-up du "gros poing". Il veut l'avoir et donc il veut éliminer les crayons qui le détiennent ...

remember your first pendat ?
But the thing is, the first encounter was designed to let the player easily avoid the pen, not to easily dispatch it. So he tries, again and again, asking for help when he's out of bladors (amno) because he's so scared to get down in the pencil' lair, grabbing them back. He's wishing so hard that you could throw a sponge at the pencil instead, wich would turn its harmful spike into a friendly moving platform (yeah, he's been watching me playing some Rayman, too).

Oui, mais l'endroit où on rencontre son premier pendat n'a pas vraiment été pensé pour qu'il soit facile de vaincre le pendat. Bien que ce soit tout à fait possible, on nous invite plutôt à le contourner en passant par les crayons. Mais ça, J.l.n ne veut pas en entendre parler. Il me demande de l'aider en lançant le taille-crayon pour lui (jusqu'ici j'ai refusé) ou d'aller récupérer le taille-crayon tombé à côté du crayon (le "trou" du crayon lui fait peur. Il m'invente des solutions où on peut lancer une éponge -- moins effrayante -- sur la pointe du crayon pour le transformer en une inoffensive plate-forme mobile (je garde ça pour l'encourager à essayer de faire du gobscript lui-même l'an prochain), etc.

I'm not going to grant that wish, partly because that could affect the gameplay balance too deeply, and partly because doing that himself could be a powerful motivation to learn letters, words and numbers...
But there is one more thing, something I can -- and did change : fixing a collision bug with the pendat. See, every time J.l.n makes a successful throw, the game never triggers the collision. He always manages to throw the blador at the exact time where the pendat bounces back and before it turns back. And during those few frames, the pendat is unfortunately unvulnerable in "aftermaths" version.
This is clearly a bug, an easy to fix one, and I'm quite surprised that it never annoyed anyone else so far. Anyway, that makes one more release to make one little kid's life easier.


Mais bon, il y a quand même un truc que je peux -- ai que j'ai -- corrigé: un bug de collision jusque là passé inaperçu et qui permet au taille-crayon de passer à travers le crayon sans le toucher quand celui-ci est dans son animation "rebondit en arrière après s'être cogné à un mur en courant".

Thursday, December 06, 2018

16 couleurs.

Bon, c'est un peu inévitable: à présenter Bilou sur un forum de dévelopeurs NES arrive la question des "demakes" sur GBA, SNES et autres MegaDrive. J'avais déjà un peu regardé ce que ça pourrait donner suite à un commentaire de MonsieurL sur UltimateConsole, mais ni la SNES ni la MegaDrive n'est vraiment convaincante. Pourtant, il y a déjà des bibliothèques pour les aspects bas-niveau qui auraient pu être intéressantes.

Pour commencer, la MegaDrive n'a que 4 palettes de 15 couleurs, décors et  sprites inclus. Ici, dans Bilou, j'ai travaillé avec 8 palettes de 256 couleurs. Bon, on est bien d'accord, je n'utilise pas l'entièreté des possiblités, mais j'ai quand même au moins 6 couleurs de pieds (2 pour Bilou, 2 pour les Pendats et 2 pour les Dumbladors), 4 couleurs de mains, plus des livres et des fardes qui font pas mal dans le color swap. Bref, il faudrait presque considérer une réduction à 60 couleurs fixes. Il y a bien quelques palettes sympa dans ces eaux-là, ce n'est quand même pas top-sexy, comme résultat.

La SuperNES, de son côté a quand-même droit à 8 palettes de 15 couleurs pour les sprites et 8 autres pour le décor. On est déjà nettement plus à l'aise. Jusqu'à 1024 tiles par plan de décor et 512 pour les sprites (moitié moins que sur DS. On ne s'en sortira pas sans une technique façon Zmiro ou Perry) pour un total de 64KB de mémoire vidéo ... presque 10 fois moins que sur la DS. Il faudra aussi compter avec un maximum de 34 sprites 8x8 par scanline (or je fais pas mal de recouvrement) mais bon, c'est pas un bullet hell non plus. Lors des tests automatiques, j'ai au plus 70 objets actifs (pas forcément tous visibles) en même temps.

Un autre élément à prendre en compte, c'est que sur la planète PAL, la gravité est 224/192 fois plus forte que sur la planète DS. tout y est donc un peu plus tassé. Ce n'est pas vraiment un problème pour les indigènes, mais Bilou a tendance à se tasser, ce qui nuit à son charisme. J'utiliserais probablement les lignes de pixels transparents (le corps de Bilou fait plutôt 16x13  pixels au sol et 16x14 en chute libre)

Il y a donc 32 lignes inutilisées (en noir sur l'image) que je pourrais exploiter pour insérer un HUD, vu qu'on perd l'écran du bas.

Bref, Piet, si ça t'inspire, il faudrait que la musique tienne en 64K (disons 48K pour les samples, 16 pour les patterns et le player) et n'utilise que 8 pistes au maximum.

Et pour rire, avec une seule palette de 16 couleurs, on arrive à  ... quelque chose de pas complètement moche, mais quand même fort loin de l'original (bon, c'est de la conversion automatique, évidemment).

Par contre, le homebrew sur GBA serait légal dans certains pays où le homebrew NDS est frappé d'interdiction ... ça mérite qu'on y réfléchisse ...

edit : bon, j'ai pas pu m'empêcher de faire un gros montage de plein de screenshots de SchoolRush, de retirer tous les sprites et de faire "conversion en mode indexé" pour voir où on en est (avec les différentes variantes de teintes pour les livres, le sol, etc). Bin ça fait 190 couleurs en tout. Alors que la SuperNES n'en a que 120 à me proposer ... sur GBA, par contre, ça passerait sans soucis.

 edit again: oui, mais une SuperNES, ça sort un signal analogique. Et sur un signal analogique, le dithering passe beaucoup mieux que sur écran LCD. Je peux donc avoir une variante du contenu qui passera pas trop mal (moyennant quelques retouches sur les crayons qui peuvent se passer des petits pixels isolés et prendre une teinte légèrement différente de celle utilisée sur DS ... ce genre de choses).

A suivre, donc, finalement. Mais attention: la SuperNES n'a au mieux que 3 plans et ne pourra pas faire les vagues avec des sprites parce qu'elle n'autorise au mieux que 34 sprites de 8x8 sur une ligne horizontale, l'image en faisant 32 de large.

strtrololol


All of sudden, we realised that we had plenty of 'strtoul' that weren't checking they were actually receiving a number as argument. So we went for fixes and have a few more conditions that could trigger an exception.

If instead you suggest to go for stringstream, remember: it will expect either '.' or ',' depending on the value of LC_NUMERIC ... Maybe it isn't that bad I'm using mostly sscanf() in GEDS code :P Well, as long as I remember not to use %i when I mean %d, that is.

Saturday, December 01, 2018

School Zone: aftermaths

Five year ago, I released a single-level "anniversary" game featuring Bilou in a school zone settings. A bit later, in early November, I had the opportunity to have it play-tested by my nephews, who were 7 to 13 years old by then. From there difficulties to approach the game, I added one "preliminary" level that is now level 1 in school Rush.

Voici 5 ans, je vous faisais un jeu-anniversaire avec Bilou dans la zone de l'école. Quelques semaines plus tard, en septembre, mes p'tits n'veux me faisaient me rendre compte qu'il me fallait quelque-chose d'autre comme niveau pour introduire les mécaniques du jeu. Ce niveau non-tutoriel est depuis devenu le premier niveau de School Rush.

Download SchoolRush - JLN build.

So yeah, the 5 levels I'm releasing today for Bilou's 25th  anniversary took me long time to make. And it doesn't even feature the level that started it all. Because meanwhile, I grew interest in speedruns, and I wanted the game to focus on going as fast as we could and save the books. Things with a focus on wandering, discovering, solving or exploring will happen in another small game.

I'm proud I could get feedback from several professionals with the 2016 release. I hope the game is better now. May there be many of you finding it, may you have a fun time playing it. This is my gift to whoever makes free software, free music, or free videos. Thank you all for making coding possible/enjoyable


The engine code is LGPL, the tools 'used to make it (animations and level editors) are GPL, the art and level design remain my copyrights, but they are free to play, and free to share unmodified as part as this School Rush release.

Aujourd'hui, le développement de School Rush prend fin. Ce fut long, parfois fastidieux, mais je voulais l'amener jusqu'au bout. Comme dans tout jeu, il y a des choses qui ont été abandonnées en cours de route. Soit qu'elles ne convenaient pas, soit qu'elles m'écartaient du but premier du jeu... soit qu'elles promettaient de devenir un gouffre de développement rendant irréaliste toute sortie tant que je serais en solo sur le développement. Que ce jeu soit mon cadeau à tous ceux qui ont écrit du code free software que j'utilise tous les jours, les musiques que j'écoute en codant, les vidéos sympa qui m'ont donné envie de continuer. Merci à tous pour votre travail.

I'll just update November post with the link to December contents, if you don't mind. How-to-play etc. is there. If you're looking for a changes list, it's been posted already ;)

Featured on PDRoms.de

History tracked on playeradvance, tigsource, homebrewlegends

Sunday, November 18, 2018

Finishing School Rush ...

Bon, après une série de pépins sur la voiture, c'est visiblement à la maison d'y aller avec ses revendications d'entretiens. Le lave-vaisselle, l'aspirateur, même le porte-manteaux. On se croirait dans l'intro d'une video de la développeuse du dimanche!
Avec tout ça, j'ai un peu du mal à me souvenir en fin de journée si j'ai des choses en attente pour finir school Rush ou non. Donc, retour de la todo-list.

  • [done] provide a TypeName widget that do not require users training
  • [done] only let the players enter their name when they beat some high score.
  • [unneeded, but done anyway] sleepy eraser
  • [done] preload "forever heroes" with SD card file
  • [done] do something useful with the pointing hand.
  • [done] Save new scores [on demand].
These are the things that are still pending to get the final build of School Rush, iirc. I've started converting some 'todo' items into 'newfeatures' (to be addressed out of the 'finish that game' track) because the 'todo' tag was starting to be quite unhelpful.
on the other hand, maybe it isn't that wise to think about starting to edit code on evenings where I feel too tired to remember what are the things that still need my attention before the final School Rush release...

Saturday, November 17, 2018

They won't show up in School Rush (?)

a few post-mortem sketches of ideas for the good-ending of Bilou: School Rush that didn't make it to the game.

since early in the redesign of the game on NDS, I tried to work with the idea that most foes we encounter while playing a Bilou game are not really evil, although they can be quite dangerous.
I hope I made it clear enough with the ink.jets who are trying to defend their realm against a pendats invasion but may occasionally help Bilou.

The comic shows the bopping erasers speechless quick to anger when disturbed during nap time. The theory in School Rush was that the sudden ink rise made them very nervous. The secret ending should have shown them relaxed again, being taught that pendats are dangerous, but that they should behave friendly with Bilou.
Unlike bladors, erasers aren't speechless, although I'm not sure I've ever published any of my sketches about the "erasers bridge", and you'll have to dig deep into this blog to see some evidence that they can speak (or trust the picture shown just nearby).

All my attemps so fan to draw those erasers as pixel art were unsatisfying once I reached the "animate them" step. But I was trying to just reuse the sprites from "normal" erasers, with some overlaid sleepy eyes or snoring mouth. I was about to just write "I'll just use regular eraser instead" burl had my DS in my pocket, so I tried another approach.

First I used a draft 32x32 blocks page to draw a few keyframes for a sleeping eraser. I used SEDS limited animation features to check it was fun and only then I split them into 16x16 blocks for AnimEDS. This way i keep only 2 sprites for the animation, but I can do squashes, stretches and wobbles to make the animation look smoother.

Friday, November 16, 2018

rez x-factor 2

Let this be my official "I love (idea I have of) the demoscene" post. (better late than sorry)

back in '96, demoscener REZ wrote a stunning .mod track featuring about 1'30" of chiptune within 3x64 lines of 5-track (amiga-compatible?) patterns ... He did so by pushing the use of loop commands to an extreme. I love that spirit of taking something that was meant to work within some constraints and pushing it far out of its limits.

He also used very pleasing waveforms (reminding me of Namco's wavetables), of 16 to 64 bytes plus a few larger (300 and 700 bytes) drums. The result is a stunning 8.8K chiptune. Of course, by now, we have 4K compos with songs twice the lenght, but REZ did it without requiring a custom player. Chapeau.

Je l'avoue: j'aime la démoscène. Cet esprit de faire-plus-avec-moins qui a conduit en '96 REZ à faire un morceau entier en 3 patterns, usant et abusant des commandes 'boucle-moi-ça', utilisant des sons de 16 à 64 bytes tenant plus de la WaveTable façon Namco que du véritable sample. Le tout pour une taille record (à l'époque) de 8.8Ko.


Sunday, November 11, 2018

B-trees

i was thinking a bit more about my handscript recognition system for the NDS this week-end, and i figured out that the sorting techique might not need to be as complex as I initially thought.

The plan is to support the 128 characters of the ASCII charset. There should be a way to define multiple models for the same character — e.g. you might have the ‘d’ character done in either 1 or 2 strokes — but I doubt I would ever need much more than 4 model of each one. That means at most 1K models to sort.

In my technique they can all be indexed with a 16-bit code, but even then storing 64 K pointers would be overkill. I had plans for techniques that find the most discriminating bit(s) for a subset of the models an make an optimal radix tree, but then I realised that with only 1K entries, it might even not be required: a simple B-tree structure would index all the keys with just 64 index blocks of 16 pointers each, plus 4 super_index blocks and one top-level index. This is a perfectly sustainable amount of overhead. Plus I already have a B-tree implementation from my Clicker32 operating system project. . .

Friday, November 09, 2018

InteRLude

eh oui. La VTJ se la joue parfois VDM. Et quand ton lave-vaisselle a décidé de ne plus se mettre en route quand tu pousse sur le bouton power, tu te dis qu'il va de nouveau y avoir un creux dans les progrès du homebrew. Comme en plus tout ça se produit pendant la phase de post-release blues typique depuis la disparition de dev-fr et de la communauté nds :-/

Espérons que j'arriverai quand-même à boucler School Rush cette année ... je viens de me rendre compte que c'était le 25eme anniversaire de Bilou.

edit: le remplaçant est arrivé le 7/12. Evidemment, j'ai encore craqué pour la garantie étendue à 5 ans ... 

Friday, November 02, 2018

School Rush : Post your score

it has been almost one year since the last release of Bilou : School Rush. Through unpractical ideas, oversophistication and deep engine refactories, I finally get something to share with you. Here is maybe the penultimate release bringing 1-UPs and hi-score tables to School Rush.

Download

Voici enfin une nouvelle release de School Rush. Je laisse donc tomber les options trop complexes pour me concentrer sur ce qui compte vraiment pour le jeu: les 1-UPs, le calcul du score (distance parcourue si on ne finit pas le jeu ou temps écoulé si on le termine).

So, compared to the previous builds,

  • you can get 1-UPs by collecting letters. Everytime you get one, the next one will be more "expensive", though.
  • every loading screen show how long it took you to get there and how far was that "there".
  • there is a "congratulations" level at the end of the 'secret, good ending'
  • there is a "game over" screen
  • in both case, a hiscore table will show up. You'll compete for the shortest time if you found the good exist, and for going as far as possible (in pixels) if you're game over.
  • no new levels this time. Core gameplay unchanged.
I do not have yet the code to let you enter your own name at the end of it though (that will likely be for the latest release). The purpose of this one is to ensure that the arbitrary scores mentioned as "special thanks" can be beaten. So you'll always be "Player One" and the pointing hand will not yet help you to see where you are.

J'ai un début de table des scores, aussi, mais pas encore la possibilité d'y enregistrer son nom. ça, ce sera pour la dernière release.

The times are shown as MINUTES:SECONDS:FRAMES, btw. I managed to get to the end in about 10'50", while losing 2 lives (which took me about 2 minutes). So beating KirbyKid will ask you at least deathless play through and beating Wintermute will almost certainly require to pull off some emergent gameplay and speedrunner skills... which isn't necessarily bad.

gameplay

You're controlling Bilou, a blue, ball-shaped explorer. You make him JUMP with the (A) button and grab things (or throw them) with (B). Your goal is to reach the right of each level before you're caught by the ever-raising ink.
You'll need to be quick, too. Use (R) or double-tap in left/right directions as if you were a pink, living vacuum cleaner.

You can stomp some monsters, you can throw sharpeners at others. Remember: the pencil soldats are the only real threat here, and they must be stopped from pouring even more ink for their autoritarist plans. Everything else that looks dangerous is mostly acting on fear and may prove very useful if you keep your head cold. Think about how useful a bobbing sponge could be if you could ride it (B). or how high an inkwell could shoot you ...

There are rumours of magical artifacts that could help you. The Fist of Justice, that noone can stand against (double-B) and the Floating Twister (hold A), that let you reach far away places. It's unlikely the pendats will let you recover them without a fight, though.

Story

At the far east of this school-like country, there is a gauge that will stop the ink. Rush for it! The books city is close to be destroyed once for all, and the elders' knowledge will be lost. This must be another plot from Square Root, who decided that mathematics are the only thing worth of being written down.
Everyone here seems to believe that Bilou is a sort of legendary hero...


How to play

Get the NDS image and play it on your homebrew-ready console or in an emulator, such as DeSmuME. See this page if you need extra explanation/instructions for running homebrews.

NB: download links have been updated to point towards "aftermath" version, and finally 'jln' version (gameplay fix). The "Gameover" version they were initialiiy pointing to is still downloadable, if you really want to.

Sunday, October 28, 2018

Petit test de TomDroïd

Parce que oui, Tomboy, mon outil de post-its virtuels a références croisées existe pour Androïd et même tourne sur ma tablette e-Ink "onyx boox". C'est une version Beta (>_<) et open-source (^_^) mais pas encore vraiment utilisable à l'heure actuelle.

- parce que saisir des WikiWords avec un système de reconnaissance d'écriture manuscrite qui pense que "Une phrase commence par une majuscule et se termine par un point.", c'est pas top
- parce que modifier un wikiword pour en faire un WikiWord avec un stylet, c'est très moyennement précis
- parce que de toutes façons, il ne suffit pas d'avoir un WikiWord inconnu pour qu'en cliquant dessus on puisse faire une nouvelle note sur ce sujet (contrairement à Tomboy)
- parce que de temps en temps, l'application se dit que ce serait bien de faire une sauvegarde de secours de la note en cours d'édition et qu'elle me renvoie du coup au début de la note. En plus de quoi, le système de reconnaissance de google me sucre les traîts tracés pendant la sauvegarde en question >_<

Donc bravo à ceux qui ont travaillé là-dessus, ne vous étonnez pas si je consomme quelques soirées à m'installer un devkit Androïd quand-même, hein ;)

Saturday, October 27, 2018

1 heure par jour

C'est en gros le temps que je peux encore consacrer au développement homebrew ces temps-ci, avec les déplacements supplémentaires pour les activités des enfants et l'entretien minimum de la maison. Une heure ou je réouvre mon vieux laptop "grizzly" de 2007 qui surchauffe et s'éteint quand on regarde plus de 15 minutes de vidéo youtube en plein écran, qui a besoin d'être sur secteur à chaque cycle d'horloge mais qui offre le confort d'un écran 1680x1050 et d'un clavier avec le bloc "insert/home/pgup/del/end/pgdn" identique à un clavier classique qui s'est révélé plus important qu'un pad numérique.

Une heure par jour pour ajouter une petite brique par-ci par-là. Ou pour constater que ce que j'ai planifié à coup de tablette-à-encre-électronique pendant les creux où j'attends qu'*deline ait fini ses activités ne va pas se combiner avec les autres composants.

Si j'essaie d'ajouter une demie-heure supplémentaire par-derrière pour blogger des micro-succès, je ne tiens pas la distance...

A l'unif, je prenais facilement une demie-heure sur mon temps de midi pour essayer un truc ou l'autre, entre autres grâce à la connexion SSH quasi-automatique entre le PC du bureau et celui à la maison. Mais je faisais régulièrement les trajets en basket+bus, voire à vélo. Avec les loupiots à déposer, je ne marche quasiment plus dehors en semaine à moins de le faire sur le temps de midi. Et moi, si je ne marche pas, je disjoncte. Donc je marche. Tant pis pour les lignes de code homebrew que j'aurais pu mettre (ou les traductions de post) pendant ce moment-là.

Thursday, October 25, 2018

stop using %i!

Hey me-from-the-past. Here is you-from-the-future. Stop using %i. I know you're used to it because your re-implementation of printf for your own x86 microkernel had only %i for printing numbers instead of the standard %d. I know as well that even in my world, printing %d and printing %i produces the same result, but listen, here's the catch:

scanning for %i enables automated base conversion while scanning for %d guarantees digits are interpreted as decimal numbers and nothing else. You don't want "${width}x${height}" to fail being recognized by "%ix%i" just because it looks so much like a single hex number as soon as width is null, right ?

right.

So stay safe, and stop using it.

GameScript vs. Hud

The HUD is a bit special in libgeds in that the engine doesn't know what it is, nor what it does. All it knows is how to pass it informations, more in the LUA spirit (afaik).

so when you type

  • hud.load "somefile.spr"
noone ever checks that there is a file. All it does it passing that string untouched (*) to some iHud::showScreen() function. 'hud.show' works similarly, and simply change one boolean argument so that the iHud-derived class knows it should make the picture visible immediately.

The other kind of command,
  • hud.mode=menu
 Will just be recording the first letter ('m') and make that available when the parsing is over through a call to iHud::setup(). The engine doesn't even know how to build such a iHud-derived object: instead it receives it from the rest of the program.

 So the HUD is something that the advanced programmer sets up and that can interprete freely that string that is meant to be a filename. In other words, rather than hacking "let's show the score" when the 'show now' bit was passed, we could have a more explicit
  • hud.show "chapter2.spr" // only while loading
  • hud.show "+score"
  • // all the level setup goes here
  • hud.show "-score"
  • hud.load "hud-basic.spr" // what goes on the bottom screen during one level.
 (*) Well, not exactly untouched. It actually prepends some stuff to make it an absolute path. Like "efs:/" or so. I'll have to work that out.

Monday, October 22, 2018

Showing the score

If I want to have a "leader board" shown in the game won / game over screens, it would be nice too if the player can have a look at her performance. My idea is that you're evaluated either on the distance you covered (when game over) or on the time you took to beat the game (when congratulated). A good time to report that to the player is when we're loading the level, but by then the screen settings are fairly locked.

It looks however, that if I hack the 'window control register' WIN_OUT while we're updating the picture shown on the bottom screen, I could use sprites on the top screen to render some digits without messing up with the scene setup. That's only part of the solution (I'll also need some tiles with digits, which I haven't in the sprites tileset atm), but it's better than nothing.

And it looks like I should be able to use the last 16 tiles of the spriteset to put some 8x8 digits font... We'll see that some tomorrow.

Tuesday, October 16, 2018

Final Scene

Immense pardon d'avance à tous les développeurs de jeux que j'ai terminés (pas si nombreux que ça, donc) et dont la séquence de fin m'a déçu. J'en suis à l'étape de faire la séquence de fin et je dois reconnaître que c'est extrêmement difficile de contourner les limites techniques pour parvenir à faire passer quelque-chose qui ressemble à l'idée que je m'étais faite de la séquence de fin qui soit fun pour le joueur sans devenir un casse-tête complet.

Donc, oui, il était prévu d'avoir un "centre de rééducations des gommes" où Pr. Gommaster moustachu leur montre qu'il faut se défendre des crayons, mais que Bilou est "un gentil", avec des gommes-élèves qui sont plus où moins attentives selon que le joueur a assommé plus ou moins de taille-crayons pendant son parcours. Et non, je n'essaie plus de faire rentrer ça dans ma "spritesheet" devenue trop étroite et le gobscript qui atteint ses limites en terme de maintenabilité.

Et évidemment, le blog n'aide plus vraiment à rester motivé pour terminer ça parce que 1) on est plus en 2006 et mes lecteurs sont nettements moins assidûs et 2) j'aimerais que ça reste une surprise, donc je ne peux pas vraiment faire du teasing avec les images.

13/10: une p'tite idée gribouillée sur papier pour l'écran "game over": un pendat arrive par le côté et pousse Bilou assomé dans un trou. Les lettres "G" et "O" de gameover se décrochent et viennent se placer pour faire le "GO" de l'écran titre. Retour à l'écran-titre.
14/10: bonne idée pour intégrer les derniers crédits et l'enregistrement des scores
15/10: mise au point d'un des derniers éléments interactifs qui sera quand-même dans la séquence de fin
16/10: nouvelle tentative pour la map correspondante (2x1 écrans). Peut-être un peu trop dense, par contre. La présentation de "Verso" y est simplifiée à l'extrême par rapport à l'idée de départ.
17/10: ajustements des compteur
18/10: soirée chargée IRL, mais j'ai quand-même trouvé 1/2h pour corriger les compteurs 
19/10: ça marche. J'ai du bricoler avec les propriétés de collisions pour pouvoir faire disparaître les reconstitués, mais ça y est. Je peux le mettre comme niveau après le niveau "secret". Aucune idée de la piste sonore choisie ... et toujours pas d'écran inférieur, par contre.
20/10: vidage de garage
21/10: Ultime Décathlon 6 -- tournoi de la dernière chance (oui, je sais, là aussi j'ai du retard).

Et il est temps de conclure, parce que

http://sylvainhb.blogspot.com/2015/03/il-faut-que-je-finisse-school-rush.html
http://sylvainhb.blogspot.com/2017/10/finishing-steps-for-school-rush.html
...

Et please, dites-moi que j'ai corrigé l'écran bleu dans la branche "démo", parce que sortir ddd et faire des backtrace juste pour connaître la ligne de script fautive ... bof.

Monday, October 15, 2018

Bug Punch

I have one last bug (hopefully) to fix in School Rush: with the latest builds, there is an unexpected additional Bilou head showing in addition to the big punch, and stays until the “shot sprite” takes over the regular animation..

Doing some more testing, it appears that the latest unaffected build is last year’s “xmas” release. It could be something that went wrong with the refactoring, or it could be an accidental modification of the site sheet itself.

Ce n'est pas si inhabituel de voir des têtes de Bilou partout, quand mon moteur de jeu buggue, et il a remis ça. La release-de-Noël est la dernière à ne pas en soufrir. Erreur de refactoring ? modification accidentelle de la spritesheet ? A moins que ça ne soit lié à la manière dont je gère les sprites "invisibles". Il faudra vraiment que je me rajoute une commande pour ça dans les animations.

A look at the source shows that I implemented an “invisible” sprite by not picking any sprite until the 6th frame. This isn’t clean and chances are that I was exploiting some undefined behaviour. I should definitely have a dedicated command that hides the sprite through the animation that works whatever the contents of the sprite page.

Well at last, in the refactored code, there is a clean INVALID_BLOCKNO value that is set to the frame number as the GOB is created. All I need now is to make sure the sprite remains hidden until we give it another value.

edit: likely the root cause is that I just used unassigned page entry to have a transparent image. Of course, if I accidentally add an image to that page, things that once were transparent might no longer be transparent.

Thursday, October 11, 2018

Amy Zing

It only took Ant a few days to include my little "Amy Zing" sprites into his neat labyrinth crawler homebrew, actually. For some reason, I completely missed it by then (March '18) and only realised that the game was released thanks to some anonymous internet folk who followed a link from simian zombie web site to mine, leaving a mark into the logging system which I tracked backwards to hit the page with the release.

So I grabbed the game, enjoyed it, enjoyed again, tried the various resolutions (normal is my favourite one) and smiled: that was my first ever homebrew collab as a spriter ^_^. And then started to wonder... Could such simple labyrinths work for Bilou, under gravity ?

I traced some of them in a notebook and started to check where I would put collectibles or hazards and why. In a platformer, you shouldn't (imho) try to make your labyrinth with individual blocks, because the player will need some room to manoeuver. If I pick 4x3 Bilou-sized blocks as a "maze cell" (3 blocks being a standard jump height), the maze now scrolls over 4x3 screens. You can no longer plan your move easily with that limited visibility, so you'll end up more often in dead ends and will have to back-track. Hence the rewards and hazards.

And well, Imho, with properly tuned jump distances and some wall-kick mechanics, you might not even need fancy ladders or similar tricks to support those labyrinths.

That's not quite "infinite pyramid", but it could be a nice step towards it.

edit: good news: my 5-year-old J.L.N wasn't afraid of the half-dead monkey and accepted the maze game as something to do when he's bored.

Monday, October 08, 2018

Trotôptimiser

Je voulais faire une pyramides de taille-crayons. Quelque-chose de fun, original et un peu inattendu pour récompenser les joueurs persévérant. Mais voilà. ça veut dire beaucoup de sprites ... beaucoup de collisions ... alors est-ce que le moteur de jeu va le supporter. J'ai passé déjà quelques après-midi et cogiter la chose.

Basculer entre tiles et sprites, peut-être ? ou simplement entre une version mono-sprite du taille-crayon assomé et une version trois-sprites comme celle utilisée dans le reste du jeu ? Oui, parce que les pieds de taille-crayon sont animés avec des sprites séparés histoire de pouvoir faire plus d'étape d'animations avec le même nombre de pixels, mais le moteur de jeu ne supporte pas qu'un objet existant doive acquérir ou libérer des sprites hardware au fil de son existence. Quand le taille-crayon est assommé, ses pieds sont cachés par-derrière lui alors que deux nouveaux objets d'un seul sprite sont créés pour les pieds projetés au loin.

J'aurais donc pu faire ma pyramide avec des tailles-crayons-d'un-seul-sprite. ça m'aurait permis d'en faire tenir jusqu'à trois fois plus à l'écran. Sauf que quand Bilou transporte un taille crayon, les pieds-cachés deviennent les mains de Bilou tandis que les sprites hardware de Bilou sont temporairement désactivés. Ce n'est donc pas quand le taille-crayon reprend ses pieds qu'il faudrait passer (en détruisant un objet pour en reconstruire un autre) à 3 sprites hardware, mais bien quand on ramasse le taille-crayon pour la première fois.

Oui mais et si le joueur réempile les taille-crayons ailleurs, alors ? on va se retrouver avec le même nombre d'objets mais cette fois à 3 sprites ? ça va mal finir ça.

Heureusement, un premier test montre qu'on tient toujours les 60 images secondes avec une trentaine de taille-crayons à l'écran rien qu'avec l'objet de base, tel qu'il intervient dans le jeu. Même les empilements ne posent pas de soucis, sans doute parce qu'en réalités, ils ne sont pas gérés comme des collisions.

A la place, c'est le mécanisme de plate-forme mobile qui entre en jeu, dans lequel on se contente de vérifier la relation avec l'objet auquel on s'était attaché précédemment. Les collisions proprement dites (nécessitant de comparer chacun des taille-crayons avec chacun des ennemis) n'aura lieu que depuis les tailles crayons qui tombent.

Je m'inquiétais donc pour rien. Par contre en en profitant pour mettre un générateur de pieds-baladeurs dans le niveau, J'ai compté jusqu'à 28 pieds générés sans que l'émulateur ne tombe sous les 55fps (la DS serait donc probablement toujours à 60), mais par contre après ça, il y a trop d'objets à gérer et certains d'entre eux ne sont tout simplement plus affichés (un bug bien connu du moteur de jeu actuel, contre lequel il n'y a pas grand chose à faire à part éviter d'en arriver là par le level design). Bon à savoir je calibrerai mes générateurs de pieds en conséquence, un peu comme j'avais fait avec les générateurs d'applemen dans Apple Assault.

edit: une jolie pile d'une 30aine de taille-crayons, un personnage de chaque autre type et quelques pieds baladeurs ... ça tient toujours.

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: devkitpro.org. 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

/r/NDSHacks

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 w-brosp-hb.example.org
let $GATEWAY be the name of the gateway like thegateway.example.org
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 ...

then

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.


Thursday, August 30, 2018

1-ups... At last.

Finally, something good does happen when you collect letters in School Rush. Nothing fancy, and not even anything original, I'm afraid: you just get an extra life. Yet, considering the difficulty of the -final level, this might be welcome.

It required some new tools, though. Lives, hit points and collectibles are managed through counters in the game engine. counters can normally get their value defined only when you parse the level script. Then, you would only increment or decrement the counter as game events occur. Then, you can define one or more actions that happen when the counter reaches zero.


Enfin! Ça vaut enfin la peine de faire la collecte des lettres dans "School Rush". Rien que du très conventionnel, j'en ai peur (on prend une vie supplémentaire), mais bon, vu la difficulté du dernier niveau, quelques vies supplémentaires ne seront sans doute pas de refus. Mais cela ne s'est pas fait sans de nouveaux outils.

When hit points counter gets to zero, for instance, a jingle and a death animation are played. We can even force a domino effect that decreases the "lives" counter then. But that mostly works because I load level" action also allow an expression to be defined, and because you're then allowed to reset the hit points value when reloading the level.

To provide 1-ups, I had to introduce a new elementary action dubbed "setcounters" that offers that freedom out of the level-loading machinery.


Les vies, les points de vie, les objets à récolter, tout cela est géré à travers des compteurs dans mon moteur de jeu. Normalement, on ne sait definir la valeur d'un compteur qu'au chargement du niveau. Durant le niveau, en revanche, on ne sait qu'augmenter ou diminuer la valeur petit à petit.

Le gros intérêt de ces compteurs, c'est qu'on peut forcer l'exécution d'une action lorsqu'ils arrivent à zéro. Comme redémarrer le niveau, changer la musique ou, faire apparaître un nouvel objet. Mais idéalement, ici, il faut surtout augmenter un autre compteur (les vies) et reprogrammer pe compteur arrivé à échéance (le nombre de lettres avant la prochaine vie). Bref, ce sera le rôle de l'action "setcounters", fraîchement ajoutée à la panoplie du parfait programmeur de GobScript.

Tuesday, August 07, 2018

Air Control

Bon, voyons un peu ces histoires de contrôle aérien, maintenant. Je sais qu'il y a des effets que je veux éviter et d'autres auxquels je tiens. Et ce à quoi je tiens par-dessus tout, c'est que le joueur ait la sensation qu'il tombe lorsque la gravité reprend le dessus. Pas question donc que le déplacement horizontal puisse devenir plus rapide que le déplacement vertical si ce n'était pas le cas au moment de commencer à sauter.

It's time to have a closer look at the mid-air player control. There are thing I want to have and others I want to avoid. And among them, my priority is that the player should feel Bilou is falling once the gravity pulls him back. No way the horizontal speed could grow higher than vertical speed, unless it was already the case at the jump impulse. If there is no wind, and if we can fall down for long enough, it shouldn't even be possible: air resistance is the same in all directions!

En fait, en l'absence de vent, et si on peut tomber suffisamment longtemps, ça ne devrait même tout simplement pas être possible: la friction de l'air est la même dans tous les sens. La seule chose qui peut faire qu'on se déplace plus vite horizontalement qu'on ne peut tomber, c'est le fait de planer. Et ça, j'ai déjà un power-up pour le gérer.

Maintenant, soyons honnètes: je viens de me repasser des vidéos de Super Meat Boy et de N+ jusqu'à plus-de-vaisselle-à-essuyer ce week-end et je n'ai jamais pu mettre en évidence ce "point d'inflexion" ou la vitesse horizontale accélèrerait plus vite que la vitesse verticale. Par contre, la gravité est tellement basse qu'on peut difficilement dire qu'on a l'impression de tomber.

The second key property is that we must be able to tell how far we can go with one jump. If Bilou is moving at top speed on the ground, there is no reason we seen in accelerate just because he jumped. So if it took us exactly 1 second to cover N blocks while walking, then it must also take us 1 second to clear a N-blocks hole, and we can only do it if the jump makes us stay in the air for at least a second.

Deuxième élément: la portée du saut doit être prévisible. Si Bilou se déplace à sa vitesse maximale au sol (soit en courant, soit en marchant), il n'y a aucune raison qu'il se mette à accélérer une fois en l'air. Si on met exactement 1 seconde à franchir N blocs en marchant, alors on prendra 1 seconde à franchir ces N blocs en sautant pendant la marche et on saura les franchir si et seulement si le saut dure au moins une seconde.

L'exception à ce principe, c'est le saut depuis l'arrêt. Ici, on ne sait pas conserver l'énergie d'origine du personnage. Par contre, il me semble important que le joueur ne puisse pas atteindre la vitesse de course à partir d'un saut-à-l'arrêt.

There is one important case where this rule is deliberately broken, and this is the case where we were initially standing still, but start moving sideways mid-air. Here, there is no initial energy we could preserve. I feel like we should not let Bilou gain running speed mid-air from a standing jump.

Jusqu'ici, on va plutôt dans le sens de garder ce qui a déjà été développé. Une chose que je voudrais améliorer, par contre, c'est le tuning du saut à plus grande vitesse.

Le simple fait de relacher la direction "avant" lors d'un saut permet dans Bilou de retomber à une vitesse horizontale nulle. Par contre, si la vitesse retombe en-dessous de celle de la marche, il est impossible de remonter de nouveau à une vitesse plus élevée...
J'aimerais mieux pouvoir moduler la vitesse en relachant puis ré-enfonçant le pad. On pourrait du coup avoir n'importe quelle vitesse entre la marche et la course.

All of this so far confirms the current implementation. There is one thing, though, that I'd like to see improved: high-speed jump tuning . I mean, by just releasing the forward direction mid-air, we allow Bilou's horizontal speed to fall down to zero. And once your horizontal speed falls below top walking speed mid-air, you are never allowed to be fast again. I would love to be able to modulate speeabgpressing and releasing the d-pad instead. we could then be moving mid-air at any speed between walk and run.

Grosse difference par rapport au contrôle de Super Mario, donc, où si on veut si arrêter son saut, il faudra faire demi-tour avant d'avoir atteint la hauteur maximale.

Finally, there is a significant difference between current Bilou air control and the one seen in Mario games : Bilou can make a complete turn-back mid-air. you do not even have to plan such a move ahead: if you press backwards before you reached the top of your jump, you will land back safely on the platform you just left. In Mario, instead, it already takes you a lot of effort just to cut the horizontal distance in half. No wonder why they imported Yoshi's rodeo arrack in the "New Super Mario"

Mais pour être franc, je dois admettre que j'aurais du mal à me séparer du comportement actuel. En particulier parce que ça donne la possibilité d'annuler un saut si jamais je n'avais pas assez de vitesse. un confort que Mario n'offre qu'aux plus ratons d'entre-nous.

Friday, August 03, 2018

Rolling Random Number.

I decided to map every known token of the GobExpressions onto the ASCII charset some other day. And it struck me that there was a pattern like "upper case for mostly side-effect actions" and "lower case for mostly functional actions". To some extent, the x being used to call eXtra functions such as spawning new game objects, triggering sound effects and the like should be replaced by X. Tracking that in all the command files won't be trivial, though.

It could be tempting to use S(for score) as a function since we have i(ncrement counter) and d(ecrement counter), but unlike game counters, the score cannot be read again. It's more a side effect to change it than really some functional extension to the core arithmetics.

So where should "roll a dice to get a random number" go ? likely r. What should be used to "get/set game state bit %n". That could be g and s. Pretty handy map.

edit: For long, I have delayed introducing OP_ROLL, and that was partly because I had no clear idea of what implementation to pick. Here is the one from Tetris, according to some gamedev talk. What is good for Tetris is good for me.

Et dans Wordpress ?

Peut-être qu'un jour je devrai migrer tout ceci hors de blogger. Avec google, qui peut savoir ? Ce qui est sûr, c'est que blogger depuis une tablette, c'est décevant. Et depuis un boox qui tourne un vieil androïd 4, c'est encore pire. Comme je suis tombé sur un autre bloggueur de homebrew sur wordpress et que je me suis rendu compte qu'il y avait une fonction "notification pour les (réponses aux) commentaires", j'ai voulu vérifier si le passage blogger->wordpress était possible. Un p'tit compte gratuit, un coup d'oeil dans les FAQs et en avant.

Côté PC, l'interface est assez chouette. Plus fonctionnelle et réactive la version dont je me souvenais pour l'avoir fait tourner sur le serveur de l'Université. Rien que les miniatures dans la liste des posts, c'est chouette et sympa.

Maybe I'll have to migrate this blog out of Goolge's services one day. One thing is certain: blogger on my fairy's Android pad is disappointing, and it's simply un-available on my Boox device that runs an old Androïd 4. But both could run wordpress application, so it was worth giving the export/import feature a try. Spoiler: it worked. And it imported much of the pictures I had on my blog (not all, or if it did, it doesn't mention the same count as Google's photo gallery)

The UI on PC for wordpress is quite nice. the one on pad, a bit less. Thumbs turned gigantic so you can hardly see more than 2 entries on-screen. Using it to decide what you're going to update in your sofa is as convenient as scrolling through one of Titus The Fox levels. With 158 drafts waiting for me, it could be better. But if I'm not afraid of raw HTML mode, I can input some stuff directly with my stylus. Huzzah!

Côté tablette, c'est un peu moins réussi. les miniatures sont devenues des images énormes: il y a à peine deux articles accessibles par écran. Aucun contrôle pour changer l'ordre, filtrer ni rien de ce genre ... Il faudrait scroller et scroller encore (avec la vitesse de rafraîchissement de l'écran à encre électronique qui ferait passer les pluies sahariennes pour un coup de karcher :-/). Et pour ne rien arranger, les posts brouillons sont mis en avant, dans un ordre que je peine encore à définir. Et des brouillons, j'en ai. 158. Enfin, au moins ça devrait m'encourager à en mettre plus au net.

Et la bonne nouvelle, c'est que le texte de tout ce petit monde semble avoir été téléchargé dans la tablette et que je peux donc éditer à l'envi tout ça du fond du jardin. Enfin, à condition de ne pas être rebuté par l'éditeur en version Andröid qui semble penser que juste de l'HTML brut, c'est assez pour tout le monde :-/

Mais bon, je peux le faire au stylet, écriture manuscrite et sans écran. Et ça, c'est présssscieux.

Mais le plus impressionnant dans l'aventure c'est sans doute que wordpress a ré-importé automatiquement les 500+ illustrations du blog. Difficile évidemment de s'assurer qu'elles y sont bien toutes, mais c'est déjà un énorme travail d'évité. Et la galerie fonctionne aussi sur tablette (à condition d'être connecté. 'faut pas trop en demander quand-même: 7.5% de 3Go, ça fait son poids dans la gestion de mémoire cache du boox.

Mais il doit en manquer parce que l'album google "photos de votre blog" en comptait pas loin de 1240...