Fighting Fantasy gamebook engine

Share your games and programs with the community.

Re: Fighting Fantasy gamebook engine

Postby mougino » Mon Aug 17, 2015 3:38 pm

mougino wrote:
jonnection wrote:Amazingly fast work Nicolas

I downloaded the code and wanted to examine it to see if I would be able to get any ideas how to reduce memory use (in Operation Fox I had to do absolutely everything to get it to the 30kb size)

But, at least on this crappy old computer I have with me right now with Arduino ide 1.0.4 I am unable to compile the code
Are you sure that you compiled this package on your computer ? Perhaps there is some new features in Arduino IDE that make it work but at leas IDE 1.0.4 gave these errors.

Anyhow, I got it to compile by chucking everything into 1 ino file. Looking at it right now.

Hm yes you are right, it seems this happens only when you #define LNG ENG
If you keep the #define LNG FRA it compiles fine.
This must be a last minute change I made in this version with a misplaced #if or #endif somewhere. Unfortunately, I'm already sailing on new seas ;) I changed a big deal of code since yesterday and I'm a little reluctant to spend time looking for the ENG error in the old version :|
I'll make sure this doesn't happen in the new version I'm working on. Thanks for the feedback anyway!

Nicolas

Following up... I found the reason why the compilation is impossible, and a fix. But I'm not more advanced :oops:
With #define LNG ENG you need to define all the prototypes of the functions before the setup() and loop()
Not doing that, it says all functions are not in the scope of the sketch... I don't know why but anyhow that is fixed in the next version I'm working on (going well I must add :) ) let's cross fingers for a < 30 KB final sketch.

Nicolas
User avatar
mougino
 
Posts: 75
Joined: Sat Jul 25, 2015 8:15 am
Location: Paris, France

Re: Fighting Fantasy gamebook engine

Postby mougino » Wed Aug 19, 2015 1:32 pm

Continuing on my Gamebuino development adventure, and the heroic fighting it represents sometimes ;)

I wanted to share my experience, and hope it can be useful to others:

I spent literally hours having an erratic behaviour in my app: variables "disappearing" i.e. printing them on screen (bytes or ints) would display nothing, not even zero! and sometimes crashes of the app at random times. I looked mainly in buffer overflows (when using strcp or strcat of char arrays), I looked and I looked, now they have no secret for me :)

One of the greatest tip I discovered against buffer overflows: use strncat(tgt, src, sizeof(tgt)-strlen(tgt)-1) instead of the simpler strcat(tgt, src) when you concatenate strings. You'll make sure to never write beyong the space allocated to tgt. Explanation: sizeof(tgt) is the number of bytes given by the system to tgt, of which strlen(tgt) are already occupied by characters, and you need to copy an additional 1 character less to keep the room for the final NULL terminator.

Anyway, back to the erratic behaviour: all in all the problem came from the SRAM usage.
Even though Arduino IDE says it uses 1,860 bytes of a 2048 limit, don't let it fool you: it doesn't mean you're ok. This is only the SRAM used by your variables (global and local to functions). It doesn't take into account the SRAM needed internally, especially when copying big char of arrays for example, the system needs a temporary buffer for that, that can take several hundreds of kilo-bytes more, thus going over the 2048 limit...

Only by drastically reducing the variables sizes, and putting some strings (read: arrays of char) into PROGMEM, and when I finally fell around 1,560 bytes of SRAM used, was my app stable at last !

Hope it helps ;)

Nicolas
User avatar
mougino
 
Posts: 75
Joined: Sat Jul 25, 2015 8:15 am
Location: Paris, France

Re: Fighting Fantasy gamebook engine

Postby albertinjo » Wed Aug 19, 2015 11:51 pm

Are you using some method of determing the amount of free RAM on runtime? There are several arduino libraries made for this purpose.
I use this one: https://github.com/maniacbug/MemoryFree
It has proven useful to me a lot of times.
User avatar
albertinjo
 
Posts: 98
Joined: Wed Mar 26, 2014 2:26 pm

Re: Fighting Fantasy gamebook engine

Postby mougino » Sat Aug 22, 2015 7:13 am

Thanks for all the tips for analyzing memory guys!
I implemented a Memory Analyzer in a new version of gbsim+ (Flash and SRAM), using the avr tool mentioned by Jonne, and it is really useful!
I have been able to drastically reduce my FF engine footprint. We are very close to a v0.2 release ;)

Image

Nicolas
User avatar
mougino
 
Posts: 75
Joined: Sat Jul 25, 2015 8:15 am
Location: Paris, France

Re: Fighting Fantasy gamebook engine

Postby mougino » Mon Aug 24, 2015 11:51 am

Ok, so I think it's ready ;) or at least it's playable enough for field testing!
My v0.2 engine sketch size is 29,172 bytes out of 30,592 max, and it uses 1,441 bytes of SRAM out of 2,048 max.

So who is interested to beta-test The Warlock of Firetop Mountain on his/her Gamebuino :?:
The working book I have is in French actually, so until I adapt the English book (I have it, just need to format it, shouldn't take long...) it would be a beta-test of Le Sorcier de la Montagne de Feu!

Next improvement I want to push before releasing the code is EEPROM save! Current engine doesn't have it, so if you want to play the book seriously, make sure to remember your last paragraph (and stats) before switching off your Gamebuino.

What you'll find in the Gamebook engine:
  • stats management (skill, stamina, luck): randomly calculated when you start the adventure, then totally editable, and of course actions in the book have direct incidence on your stats!
  • management of gold, provisions (give +4 of stamina), and potions (choice of 3 potions at the beginning of the adventure: Potion of Skill - restores skill points ; Potion of Strength - restores stamina points ; Potion of Fortune - restores luck points and adds 1 to Initial luck)
  • dynamic equipment: you start your adventure with a sword, a leather armour, a rucksack and a lantern, then you can edit (add or remove) any item to your equipment!
  • special actions: roll 1 or 2 dice, test your luck, fight! and goto paragraph (can be used for cheating, but sometimes it's actually needed by the book)

In the book, use RIGHT and LEFT arrows to scroll through the pages, and use UP and DOWN to move the selection, or to scroll by a single line.
Button A is used to validate, B to go to Adventure Sheet (or back to the Book), or to cancel in all other screens.

I use a modified version of the Gamebuino library with sound and keyboard stripped off to save memory, and an enhanced gb.popup() that takes a (variable) SRAM char array as a parameter (the original one only takes a PROGMEM const char[] which I find too restrictive):
Code: Select all
void Gamebuino::popup(const char* text, uint8_t duration){
#if (ENABLE_GUI > 0)
   popupText = (reinterpret_cast <const __FlashStringHelper*> (text));
   popupTimeLeft = duration+12;
#endif
}


I also removed the gb.keyboard() and replaced it with 2 more ergonomic keyboards (but that's only my opinion!) a numeric keyboard, already seen a few posts back, and a new Qwerty keyboard (or Azerty for French users):
Image

For those interested, here is the code of this keyboard (less than 70 lines):
Code: Select all
PROGMEM const char keyboard[] =
#ifdef FRENCH
"azertyuiopqsdfghjklmwxcvbn_\030<";
#else
"qwertyuiopasdfghjkl<zxcvbnm_\030";
#endif

void printAlpha(boolean caps, byte i) {
  char c=(char)pgm_read_byte(&(keyboard[i])); // read char array in PROGMEM
  if(caps && c>='a' && c<='z') c=c&~(0x20); // if(caps) convert to upper case
  gb.display.print(c); gb.display.print(F(" "));
}

void alphaKeyboard(char* tgt, byte lmax) {
  byte x=0, y=0;
  boolean caps=false;
  while(1) {
    if (gb.update()) {
      // draw input bar
      gb.display.cursorY++; if(strlen(tgt)) gb.display.print(tgt);
      gb.display.cursorY--; if((gb.frameCount/4)%2) gb.display.print(F("_"));
      gb.display.drawFastHLine(0,gb.display.fontHeight+1,LCDWIDTH);
      // draw keyboard
      moveCursor(3, gb.display.fontHeight+5);
      for(byte i=0; i<10; i++) printAlpha(caps, i);
      moveCursor(3, CURRENT+gb.display.fontHeight+2);
      for(byte i=10; i<20; i++) printAlpha(caps, i);
      moveCursor(3, CURRENT+gb.display.fontHeight+2);
      for(byte i=20; i<29; i++) printAlpha(caps, i);
      gb.display.println(F("ok"));
      moveCursor(3, CURRENT+2);
      for(char c='0'; c<='9'; c++) { gb.display.print(c); gb.display.print(F(" ")); }
      // draw select box
      gb.display.drawRoundRect(2*x*gb.display.fontWidth+1, (y+1)*(gb.display.fontHeight+2)+(y?1:2), ((x==9 && y==2)?2:1)*gb.display.fontWidth+3, gb.display.fontHeight+3, 3);
      // draw legend
      #ifdef FRENCH
      moveCursor(LCDWIDTH-7*gb.display.fontWidth-6, LCDHEIGHT-gb.display.fontHeight+1);
      gb.display.print(F("annuler"));
      #else
      moveCursor(LCDWIDTH-6*gb.display.fontWidth-6, LCDHEIGHT-gb.display.fontHeight+1);
      gb.display.print(F("cancel"));
      #endif
      gb.display.print(F("\026"));
      // handle user input
      if(gb.buttons.pressed(BTN_RIGHT)) x=(x+1)%10;
      if(gb.buttons.pressed(BTN_LEFT)) { x--; if(x==255) x=9; }
      if(gb.buttons.pressed(BTN_DOWN)) y=(y+1)%4;
      if(gb.buttons.pressed(BTN_UP)) { y--; if(y==255) y=3; }
      if(gb.buttons.pressed(BTN_B)) { tgt[0]=NULL; break; } // Cancelled by user
      if(gb.buttons.pressed(BTN_A)) {
        byte l=strlen(tgt);
        if(x==9 && y==2) { // Ok
          break;
        } else if(y==3) { // 0-9
          if(l<lmax) { tgt[l++]=(char)'0'+x; tgt[l]=NULL; }
        } else { // Other key
          char c=(char)pgm_read_byte(&(keyboard[10*y+x])); // read char array in PROGMEM
          if(c=='<') { // Del
            if(l) tgt[l-1]=NULL;
          } else if(c=='\030' || c=='\031') { // Shift
            caps=!caps;
          } else if(l<lmax) { // a-z, A-Z
            if(c=='_') c=' '; else if(caps) c=c&~(0x20); // convert space +if(caps) put in upper case
            tgt[l++]=(char)c; tgt[l]=NULL;
          } // if(l<lmax)
        } // Other key
      } // if(gb.buttons.pressed(BTN_A))
    } // if (gb.update())
  } // while(1)
} // alphaKeyboard()


Among other interesting things: some functions to convert a char array to an int, and an int to a char array, other functions to build a char array by concatenating other char arrays to it (either from SRAM or from PROGMEM) or also concatenate integers... And a lot of other fun stuff ;)

So I'm waiting for applicants :!:
As I'm not sure about the legality of making public a raw copy of a copyrighted gamebook, I'll just send the app (INF+HEX+LDV) by private message to people who are interested in beta-testing (remember: French-speaking people only so far! désolé!)

Cheers,
Nicolas
User avatar
mougino
 
Posts: 75
Joined: Sat Jul 25, 2015 8:15 am
Location: Paris, France

Re: Fighting Fantasy gamebook engine

Postby mougino » Mon Aug 24, 2015 11:59 am

Oops, you'll need the accessory function moveCursor() to make use of above Qwerty keyboard! Here it is:
Code: Select all
#define NCHRX 21    // number of characters per line with font3x5
#define NCHRY 8     // number of lines per screen with font3x5
#define CURRENT 100
#define PREVLINE 150
#define NEXTLINE 200
void moveCursor(byte x, byte y) {
  gb.display.cursorX+=
    (x>=CURRENT-NCHRX?x-CURRENT // relative CURRENT +/- n
    :x-gb.display.cursorX); // absolute
  gb.display.cursorY+=
    (y>=NEXTLINE-NCHRY?y-NEXTLINE+gb.display.fontHeight: // relative NEXTLINE +/- n
    (y>=PREVLINE-NCHRY?y-PREVLINE-gb.display.fontHeight: // relative PREVLINE +/- n
    (y>=CURRENT?y-CURRENT // relative CURRENT +/- n
    :y-gb.display.cursorY))); // absolute
}
User avatar
mougino
 
Posts: 75
Joined: Sat Jul 25, 2015 8:15 am
Location: Paris, France

Re: Fighting Fantasy gamebook engine

Postby deeph » Mon Aug 24, 2015 2:00 pm

Cool :)

I'm ok to beta-test it, though I've never read/played those kind of books before.
deeph
 
Posts: 52
Joined: Mon Jul 13, 2015 6:09 am
Location: France

Re: Fighting Fantasy gamebook engine

Postby mougino » Mon Aug 24, 2015 5:10 pm

Good! I sent you a link by private message ;)

Also, I was able to implement savegames! Now you can save your stats and progress in the book either from the Adventure Sheet > Save game, or by pressing C button during the game, to go back to the title screen.

Nicolas
User avatar
mougino
 
Posts: 75
Joined: Sat Jul 25, 2015 8:15 am
Location: Paris, France

Re: Fighting Fantasy gamebook engine

Postby deeph » Mon Aug 24, 2015 7:35 pm

Thank you !

I've just sent you a quick report of my first game (and I can tell you this engine is already awesome so far :D).

As I was telling you I've been working on a custom variable-width extended ASCII font routine some weeks ago and even if it's not finished yet, it might be helpful for you to handle accents. Chars are adjoining on the memory and their widths are RLE encoded. The conversion is done using a PureBasic program.

Image

ascii.zip

As you can see on the screenshot, some chars are not rendered correctly and I don't know if it's either the encoder or the decoder fault.

If you think it can be helpful and maybe if I can get some help, I might be able to finish it.
deeph
 
Posts: 52
Joined: Mon Jul 13, 2015 6:09 am
Location: France

Re: Fighting Fantasy gamebook engine

Postby mougino » Mon Aug 24, 2015 8:04 pm

Thanks Deeph!

I can see 2 problems with using a custom variable-width extended ASCII font:

1) the variable width! :) as basic as my SD text browser is so far (as you noticed, it truncates words at the end of lines), it was already hard (for me!) to implement it... So making it more complex would maybe be out of my skills I'm afraid :?

2) the size of the sketch... I didn't open your code, but I guess the font is in PROGMEM? that could be a problem, as the latest EEPROM enhancements I made pushed my engine to the almost-at-the-limit size of 29,902 bytes, which leaves 690 bytes for possible enhancements...

I'll read the rest of your remarks and reply to your private message ;)

Nicolas
User avatar
mougino
 
Posts: 75
Joined: Sat Jul 25, 2015 8:15 am
Location: Paris, France

PreviousNext

Return to Games Gallery

Who is online

Users browsing this forum: No registered users and 16 guests

cron