Forums

Sega Master System / Mark III / Game Gear
SG-1000 / SC-3000 / SF-7000 / OMV
Home - Forums - Games - Scans - Maps - Cheats - Credits
Music - Videos - Development - Hacks - Translations - Homebrew

View topic - Learn how to create a game for Master System - by creating one with us.

Reply to topic
Author Message
  • Joined: 05 Sep 2013
  • Posts: 3758
  • Location: Stockholm, Sweden
Reply with quote
Learn how to create a game for Master System - by creating one with us.
Post Posted: Wed Oct 31, 2018 1:44 pm
This is a kind of an experiment, actually.
I thought we could create a (simple) game together, with each one (of those interested) providing some parts of code / graphics / music / SFXs.
We don't need to rush - the target is to learn, and to create a thread that can then be useful to newcomers. I'll assemble everything together, and coordinate if needed, and of course I will give any support.

My proposal is to create a minesweeper game, as that gives us a chance of creating a minimal running game and expand it later. Of course it'll be written in C and will use devkitSMS (unless someone can provide an ASM framework/library we can use instead).

For a start, I imagine we could do a 15x11 (max) grid where each box is 16x16 pixel (full screen with a 1-tile border) - we might create bigger play-fields later.

So, who wants to provide the first graphical assets and some code? :)
  View user's profile Send private message Visit poster's website
  • Joined: 08 Sep 2018
  • Posts: 270
Reply with quote
Post Posted: Wed Oct 31, 2018 2:21 pm
I could probably make all of the graphical assets if I got a list of objects needed.
  View user's profile Send private message
  • Site Admin
  • Joined: 19 Oct 1999
  • Posts: 14685
  • Location: London
Reply with quote
Post Posted: Wed Oct 31, 2018 2:38 pm
I wrote one of those! The biggest issue was that the recursive approach to opening up unused areas is likely to overflow your stack. I suspect drawing 8px squares will simplify the logic a bit too, and at 16x16 the grid is actually a bit small.

Assets are a grid, with squares depicting unopened, empty (or 0), numbers 1 to 8, and a flag. And a cursor.
  View user's profile Send private message Visit poster's website
  • Joined: 30 Mar 2009
  • Posts: 280
Reply with quote
Post Posted: Wed Oct 31, 2018 3:11 pm
Could be cool to it AKMW themed.
Grid could be rock tiles (unopened), grass tiles (opened / empty) and the cursor could be the same from akmw pause screen.
And the font could be the Sega one (you know the one they used on a lot of games, like Outrun Highscore).
  View user's profile Send private message Visit poster's website
  • Joined: 05 Sep 2013
  • Posts: 3758
  • Location: Stockholm, Sweden
Reply with quote
Post Posted: Wed Oct 31, 2018 3:45 pm
Maxim wrote
Assets are a grid, with squares depicting unopened, empty (or 0), numbers 1 to 8, and a flag. And a cursor.


the unopened, the opened empty, the opened with numbers 1 to 8, the flag - and the bomb - for the background, no need for a grid - maybe some border?

also, the cursor would be probably the only sprite here...

@tibone: love it! :D
  View user's profile Send private message Visit poster's website
  • Joined: 14 Sep 2018
  • Posts: 50
  • Location: Earth
Reply with quote
Post Posted: Wed Oct 31, 2018 7:00 pm
I might be able to contribute a BGM later if I have the time needed, ironically enough its a puzzle-themed BGM that was in the works at one point. Its in a rough draft state so it will need to be hammered out first before it sounds good but so far it shows promise. I hadn't bothered to finish it mostly because it wouldn't work out for my own project due to sound chip technicalities (it relies on periodic noise). PM me if you'd like to hear the rough draft though (it may or may not fit the setting for this game), but if it does than hell, maybe it will finally give me an excuse to finish it. :]
  View user's profile Send private message
  • Joined: 05 Sep 2013
  • Posts: 3758
  • Location: Stockholm, Sweden
Reply with quote
Post Posted: Wed Oct 31, 2018 7:22 pm
kaportza wrote
I might be able to contribute a BGM later if I have the time needed, [...]


Nice, so we just miss some code to start. I can provide some variables to get the ball rolling ;)

#define MAP_WIDTH   15
#define MAP_HEIGHT  11
unsigned char game_map[MAP_WIDTH][MAP_HEIGHT];


(we can swap the array's dimensions order if someone doesn't feel comfortable with this one...)
  View user's profile Send private message Visit poster's website
  • Joined: 24 Sep 2018
  • Posts: 66
Reply with quote
Post Posted: Wed Oct 31, 2018 9:24 pm
There's no need to use a recursive approach for opening up the grid; off the top of my head:

For each square store two values in addition to display state: "needs further investigation" and "this is already uncovered". Both are initially 0.

From the position of each click that doesn't end the game, proceed as far as possible to the far right as possible until one tile before you reach a mine or the boundary. Mark that tile as "needs further investigation".

Then, enter a loop. At each iteration of the loop:

  • check every tile in the grid from the top left to the bottom right for the "needs further investigation" flag;
  • if you search the entire grid without finding an instance of that flag, you're done. Exit loop, return to paying attention to the player;
  • otherwise proceed from the tile you found as far right as you can until you find another mine. At each square, compute the proper number for display, set the "this is already uncovered flag", reset "needs further investigation" and if either the tile directly above or the tile directly below that which you're inspecting both (i) does not have "this is already uncovered" set; and (ii) does not contain a bomb; then set "needs further investigation".

So it's a similar algorithm to a naive recursive span-filling search, except that you're using a fixed-size flat data structure to decide where to look next, at the cost of having to do a little more searching.
  View user's profile Send private message Visit poster's website
  • Site Admin
  • Joined: 19 Oct 1999
  • Posts: 14685
  • Location: London
Reply with quote
Post Posted: Thu Nov 01, 2018 5:03 am
Certainly any recursive algorithm can be converted to an iterative one, but the fine details of that are probably not something to try to introduce as a beginner programming task :) I mentioned it as something to be aware of to avoid getting caught later.

I may have the sources to my 2003 game around somewhere - I remember I was using a lot of stack and the recursive approach managed to use more than 8KB of stack at first, which was certainly a problem. I don't remember how I fixed it though.
  View user's profile Send private message Visit poster's website
  • Joined: 05 Sep 2013
  • Posts: 3758
  • Location: Stockholm, Sweden
Reply with quote
Post Posted: Thu Nov 01, 2018 2:24 pm
TomHarte wrote
For each square store two values in addition to display state: "needs further investigation" and "this is already uncovered".


I think a single unused bit (the msb for instance) in each of the unsigned chars in the game_map array is enough to mark the 'needs investigation' state. Thus I guess we can do:

#define NEEDS_INVESTIGATION  0x80


and go on :)

@TomHarte: do you want to provide code for the

uncover_location(x,y)


function? :)
  View user's profile Send private message Visit poster's website
  • Joined: 08 Sep 2018
  • Posts: 270
Reply with quote
Post Posted: Thu Nov 01, 2018 5:51 pm
tibone wrote
Could be cool to it AKMW themed.
Grid could be rock tiles (unopened), grass tiles (opened / empty) and the cursor could be the same from akmw pause screen.
And the font could be the Sega one (you know the one they used on a lot of games, like Outrun Highscore).


What is AKMW? so I can tune graphical assets around that style.
  View user's profile Send private message
  • Joined: 16 Aug 2005
  • Posts: 102
  • Location: Brazil
Reply with quote
Post Posted: Thu Nov 01, 2018 6:55 pm
That would be "Alex Kidd in Miracle World".
  View user's profile Send private message
  • Joined: 24 Sep 2018
  • Posts: 66
Reply with quote
Post Posted: Thu Nov 01, 2018 7:24 pm
sverx wrote
@TomHarte: do you want to provide code for the

uncover_location(x,y)


function? :)


I'm particularly terrible with setting up development environments, but it looks like SDCC supports plain old C99? If so then no problem! As in: I can try, at least.

Will you be establishing a repository?

After realising that my previous suggestion was based on a faulty memory of the rules of Minesweeper, I think the below, slightly modified version of the prior suggestion, should work.

#define MAP_WIDTH 15
#define MAP_HEIGHT 11

unsigned char game_map[MAP_WIDTH][MAP_HEIGHT];

/*
   The game_map comprises values in the range 0—9; where:

      * 0 means "uncovered, no neighbours";
      * 1 means "uncovered, one neighbour";
      * ... etc up to 8 ...; and
      * 9 means "still covered".

   Either of the two following flags may also be set:
*/
#define NEEDS_INVESTIGATION      0x80   // ephemerally used for search after a click
#define IS_BOMB            0x40   // used to indicate that a bomb is here

#define COVERED_TILE         9
#define COVERED_BOMB         (COVERED_TILE | IS_BOMB)

#define is_bomb(tile)         ((tile) & IS_BOMB)
#define is_covered(tile)      (((tile) & ~NEEDS_INVESTIGATION) >= 9)
#define is_covered_not_bomb(tile)   (((tile) & ~NEEDS_INVESTIGATION) == 9)
#define needs_investigation(tile)   ((tile) & NEEDS_INVESTIGATION)

#define set_needs_investigation(tile)   ((tile) |= NEEDS_INVESTIGATION)

/*!
   Performs a horizontal search for the next thing in the game map that is
   not an empty square.

   @param x The x position from which to start searching.
   @param y The y position from which to start searching.
   @param direction -1 to search left; +1 to search right.
*/
void scan_locations(int x, int y, int direction) {
   while(1) {
      // Stop if out of bounds.
      if(x < 0 || x >= MAP_WIDTH) {
         return;
      }

      // Calculate the proper count for this tile.
      // This is a bit long-winded, but hopefully straightforward.
      int neighbouring_bombs = 0;
      if(x > 0) {
         if(is_bomb(game_map[x-1][y])) ++neighbouring_bombs;
         if(y > 0 && is_bomb(game_map[x-1][y-1])) ++neighbouring_bombs;
         if(y+1 < MAP_HEIGHT && is_bomb(game_map[x-1][y+1])) ++neighbouring_bombs;
      }
      if(x+1 < MAP_WIDTH) {
         if(is_bomb(game_map[x+1][y])) ++neighbouring_bombs;
         if(y > 0 && is_bomb(game_map[x+1][y-1])) ++neighbouring_bombs;
         if(y+1 < MAP_HEIGHT && is_bomb(game_map[x+1][y+1])) ++neighbouring_bombs;
      }
      if(y > 0 && is_bomb(game_map[x][y-1])) ++neighbouring_bombs;
      if(y+1 < MAP_HEIGHT && is_bomb(game_map[x][y+1])) ++neighbouring_bombs;

      // Store the count, also implicitly resetting the NEEDS_INVESTIGATION flag.
      game_map[x][y] = neighbouring_bombs;

      // Stop now if this tile had any bombs in it.
      if(neighbouring_bombs) {
         return;
      }

      // Check whether above or below need to be flagged for further
      // investigation.
      if(y > 0 && is_covered_not_bomb(game_map[x][y-1])) {
         set_needs_investigation(game_map[x][y-1]);
      }
      if(y+1 < MAP_HEIGHT && is_covered_not_bomb(game_map[x][y+1])) {
         set_needs_investigation(game_map[x][y+1]);
      }

      // Move onwards.
      x += direction;
   }
}

/*!
   Searches the game map from the supplied location for all tiles that should be
   uncovered following a non-game-ending selection there.

   Assumed on entry: (x, y) is within the map's range, and map[x][y] has already
   been confirmed not to be a bomb, and this entry is currently still covered.
*/
void uncover_location(int x, int y) {
   // Set the needs-investigation flag on the initial location.
   set_needs_investigation(game_map[x][y]);

   // Continue indefinitely, or at least...
   while(1) {
      int start_x = -1, map_y;

      for(x = 0; x < MAP_WIDTH; ++x) {
         for(y = 0; y < MAP_HEIGHT; ++y) {
            if(needs_investigation(game_map[x][y])) {
               start_x = x;
               map_y = y;
               break;
            }
         }
      }

      // ... until no further tiles in need of investigation are found. Done!
      if(start_x == -1) {
         return;
      }

      // From start_x, start_y, proceed first to the left and then to the right,
      // computing the proper  values for all covered tiles and marking appropriate
      // tiles above and below as requiring further investigation.
      scan_locations(start_x, map_y, 1);
      scan_locations(start_x, map_y, -1);
   }
}
  View user's profile Send private message Visit poster's website
  • Joined: 08 Sep 2018
  • Posts: 270
Reply with quote
Post Posted: Fri Nov 02, 2018 2:53 am
Ive started drawing up some tiles and was wondering, How big should they be for each plot? 8x8 pixels or 16x16? I'm going along with the Alex Kidd style but making them new with a bit of my own style in it as well instead of just altering some Alex Kidd tiles.
  View user's profile Send private message
  • Site Admin
  • Joined: 19 Oct 1999
  • Posts: 14685
  • Location: London
Reply with quote
Post Posted: Fri Nov 02, 2018 6:38 am
16x16 will limit you to only very easy/quick games. 8x8 will make easy games kind of small, but allow more progression. Maybe you can make both?
  View user's profile Send private message Visit poster's website
  • Joined: 05 Sep 2013
  • Posts: 3758
  • Location: Stockholm, Sweden
Reply with quote
Post Posted: Fri Nov 02, 2018 9:05 am
IllusionOfMana wrote
8x8 pixels or 16x16?


I thought we would start with 16x16, that's why I set

#define MAP_WIDTH 15
#define MAP_HEIGHT 11


but of course we might already implement the 'hard' mode, with up to 31x24 8x8 blocks (first column is harldy visible on most TV so I wouldn't use that). Or we could even use scrolling - but I would start with something simple.

TomHarte wrote
Will you be establishing a repository?


Sure, if we need it!
  View user's profile Send private message Visit poster's website
  • Joined: 08 Sep 2018
  • Posts: 270
Reply with quote
Post Posted: Fri Nov 02, 2018 1:35 pm
I'll make both 8x8 and 16x16 tile plots the. Since graphically the game is rather simple, it shouldn't be too hard.
  View user's profile Send private message
  • Joined: 24 Sep 2018
  • Posts: 66
Reply with quote
Post Posted: Fri Nov 02, 2018 6:19 pm
Oh, l'esprit de l'escalier: those instances of & ~NEEDS_INVESTIGATION should probably be replaced with a more explicit inclusionary mask to get content type (so, a mask with explicit value 0xf) rather than use that exclusionary one.

You'll probably want to use one or more of the top bits for user annotations, at whatever extent you support those: user thinks this is a bomb, user thinks this might be a bomb, etc, and it's sort of silly to keep expanding and expanding on what you want to exclude in the contents test rather than just being explicit about what you want to include.
  View user's profile Send private message Visit poster's website
  • Joined: 08 Sep 2018
  • Posts: 270
Reply with quote
Post Posted: Fri Nov 02, 2018 8:17 pm
Ok, heavy Alex Kidd inspiration added, but I promise all tiles are new minus the font; even the the Alex face icon is new. I created two variants, one with just icon style plots and one themed off of an the environment you'd see in Alex Kidd. This is just a demo right now but it is done using the SMS color palette and is usable without too much effort, I hope you guys like it. Later on ill make a nice title screen set to compliment it all.

NOTE: some tiles can be flipped or removed because of duplicate, I hadn't put too much thought into space saving besides with a few tiles, like the map scroll which I though would make a nice boarder from smaller games or menus.
Test.png (118.41 KB)
Test.png

  View user's profile Send private message
  • Joined: 05 Sep 2013
  • Posts: 3758
  • Location: Stockholm, Sweden
Reply with quote
Post Posted: Fri Nov 02, 2018 10:15 pm
Lots of stuff! Would you mind to detail everything that's in there? I don't get most of the things what is supposed to be used for...
  View user's profile Send private message Visit poster's website
  • Joined: 08 Sep 2018
  • Posts: 270
Reply with quote
Post Posted: Fri Nov 02, 2018 11:14 pm
I can do that, I hope this helps.

EDIT: I've already found some issues with tiles and am fixing them as I go so these might look slightly different.
IconDescriptions.png (586.64 KB)
IconDescriptions.png

  View user's profile Send private message
  • Joined: 05 Sep 2013
  • Posts: 3758
  • Location: Stockholm, Sweden
Reply with quote
Post Posted: Mon Nov 05, 2018 8:22 am
OK, so we've got to change the two defines for the map
#define MAP_WIDTH 24
#define MAP_HEIGHT 20

and we should have two variables for the 'actual' size of the map, such as
unsigned char map_width, map_height

that we need to initialize when the game starts, according to the actual grid dimensions, and TomHarte has to change its code to use these.
Also, I guess we should have a flag that we will use to discriminate one format from the other, such as
bool large_map


Speaking about the graphics, they're nice, but I guess it's a little bit too hard to count the pebbles to infer how many bombs are around...
  View user's profile Send private message Visit poster's website
  • Joined: 08 Sep 2018
  • Posts: 270
Reply with quote
Post Posted: Mon Nov 05, 2018 2:17 pm
Understandable, I'll start refining everything a bit more so things are easier to see.
  View user's profile Send private message
  • Joined: 24 Sep 2018
  • Posts: 66
Reply with quote
Post Posted: Mon Nov 05, 2018 6:24 pm
sverx wrote
OK, so we've got to change the two defines for the map
#define MAP_WIDTH 24
#define MAP_HEIGHT 20

and we should have two variables for the 'actual' size of the map, such as
unsigned char map_width, map_height

that we need to initialize when the game starts, according to the actual grid dimensions, and TomHarte has to change its code to use these.


Will do, but not extemporaneously this time. It's a negligible difference but I'll actually compile and check it when I get home.

I'll also chuck in my current randomisation and the entire making-a-move code, seeing as how I've written them anyway for my text-mode test program.

I continue to assume somebody else is going to write the code for the graphical side of things as I have no prior experience with the framework.
  View user's profile Send private message Visit poster's website
  • Joined: 14 Sep 2018
  • Posts: 50
  • Location: Earth
Reply with quote
Post Posted: Tue Nov 06, 2018 7:46 am
Here's the early puzzle theme I mentioned earlier.

I'm a little embarrassed to show it due to how incomplete it is but I need to hear what others think first before deciding weather to work on it some more. Most importantly; would it work for this game or does it sound out of place? Thoughts anyone?
Puzzle Theme_a.vgm (12.18 KB)

  View user's profile Send private message
  • Joined: 05 Sep 2013
  • Posts: 3758
  • Location: Stockholm, Sweden
Reply with quote
Post Posted: Tue Nov 06, 2018 10:47 am
TomHarte wrote
I continue to assume somebody else is going to write the code for the graphical side of things as I have no prior experience with the framework.


somebody will stop by...

@kaportza: it's coming along nicely IMHO :)
  View user's profile Send private message Visit poster's website
  • Joined: 09 Apr 2013
  • Posts: 106
  • Location: Sydney Australia
Reply with quote
Post Posted: Tue Nov 06, 2018 12:32 pm
Hey,

Not sure if it's helpful or not but Niloct and I made a minesweeper game for the 2014 SMS coding comp.



http://www.smspower.org/Homebrew/Minesweeper-SMS

I've just chucked the source up on github.

https://github.com/yuv422/minesweeper-sms

Regards,
Eric
  View user's profile Send private message
  • Joined: 24 Sep 2018
  • Posts: 66
Reply with quote
Post Posted: Wed Nov 07, 2018 2:35 am
efry wrote
I've just chucked the source up on github.


That's pretty cool, and has cost me a proportion of my evening that I'm unwilling to disclose, but I guess sverx's intention is to keep things simple. Which I think is likely to mean no assembly?

Anyway, here's this:

#define MAX_MAP_WIDTH 24
#define MAX_MAP_HEIGHT 20

static unsigned char game_map[MAX_MAP_WIDTH][MAX_MAP_HEIGHT];
static unsigned char map_width, map_height;

/*
   The game_map comprises values in the range 0—9; where:

      * 0 means "uncovered, no neighbours";
      * 1 means "uncovered, one neighbour";
      * ... etc up to 8 ...; and
      * 9 means "still covered".

   Either of the two following flags may also be set:
*/
#define NEEDS_INVESTIGATION      0x80   // ephemerally used for search after a click
#define IS_BOMB            0x40   // used to indicate that a bomb is here

#define COVERED_TILE         9
#define COVERED_BOMB         (COVERED_TILE | IS_BOMB)

#define is_bomb(tile)         ((tile) & IS_BOMB)
#define is_covered(tile)      (((tile) & ~NEEDS_INVESTIGATION) >= 9)
#define is_covered_not_bomb(tile)   (((tile) & ~NEEDS_INVESTIGATION) == 9)
#define needs_investigation(tile)   ((tile) & NEEDS_INVESTIGATION)

#define set_needs_investigation(tile)   ((tile) |= NEEDS_INVESTIGATION)

/*!
   Performs a horizontal search for the next thing in the game map that is
   not an empty square.

   @param x The x position from which to start searching.
   @param y The y position from which to start searching.
   @param direction -1 to search left; +1 to search right.
*/
void scan_locations(int x, int y, int direction) {
   while(1) {
      // Stop if out of bounds.
      if(x < 0 || x >= map_width) {
         return;
      }

      // Calculate the proper count for this tile.
      // This is a bit long-winded, but hopefully straightforward.
      int neighbouring_bombs = 0;
      if(x > 0) {
         if(is_bomb(game_map[x-1][y])) ++neighbouring_bombs;
         if(y > 0 && is_bomb(game_map[x-1][y-1])) ++neighbouring_bombs;
         if(y+1 < map_height && is_bomb(game_map[x-1][y+1])) ++neighbouring_bombs;
      }
      if(x+1 < map_width) {
         if(is_bomb(game_map[x+1][y])) ++neighbouring_bombs;
         if(y > 0 && is_bomb(game_map[x+1][y-1])) ++neighbouring_bombs;
         if(y+1 < map_height && is_bomb(game_map[x+1][y+1])) ++neighbouring_bombs;
      }
      if(y > 0 && is_bomb(game_map[x][y-1])) ++neighbouring_bombs;
      if(y+1 < map_height && is_bomb(game_map[x][y+1])) ++neighbouring_bombs;

      // Store the count, also implicitly resetting the NEEDS_INVESTIGATION flag.
      game_map[x][y] = neighbouring_bombs;

      // Stop now if this tile had any bombs in it.
      if(neighbouring_bombs) {
         return;
      }

      // Check whether above or below need to be flagged for further
      // investigation.
      if(y > 0 && is_covered_not_bomb(game_map[x][y-1])) {
         set_needs_investigation(game_map[x][y-1]);
      }
      if(y+1 < map_height && is_covered_not_bomb(game_map[x][y+1])) {
         set_needs_investigation(game_map[x][y+1]);
      }

      // Move onwards.
      x += direction;
   }
}

/*!
   Searches the game map from the supplied location for all tiles that should be
   uncovered following a non-game-ending selection there.

   Assumed on entry: (x, y) is within the map's range, and map[x][y] has already
   been confirmed not to be a bomb, and this entry is currently still covered.
*/
void uncover_location(int x, int y) {
   // Set the needs-investigation flag on the initial location.
   set_needs_investigation(game_map[x][y]);

   // Continue indefinitely, or at least...
   while(1) {
      int start_x = -1, map_y;

      for(x = 0; x < map_width; ++x) {
         for(y = 0; y < map_height; ++y) {
            if(needs_investigation(game_map[x][y])) {
               start_x = x;
               map_y = y;
               break;
            }
         }
      }

      // ... until no further tiles in need of investigation are found. Done!
      if(start_x == -1) {
         return;
      }

      // From start_x, start_y, proceed first to the left and then to the right,
      // computing the proper  values for all covered tiles and marking appropriate
      // tiles above and below as requiring further investigation.
      scan_locations(start_x, map_y, 1);
      scan_locations(start_x, map_y, -1);
   }
}

/*!
   Sets the size of the map and the difficulty level;
   level 0 = no bombs, level 255 = virtually all bombs,
   levels in between = more sensible quantities of bombs.
*/
void setup_map(int width, int height, int difficulty) {
   map_width = width;
   map_height = height;

   const int rand_threshold = (RAND_MAX >> 8) * difficulty;
   srand(time(NULL));
   for(int x = 0; x < map_width; ++x) {
      for(int y = 0; y < map_height; ++y) {
         game_map[x][y] = (rand() > rand_threshold) ? COVERED_TILE : COVERED_BOMB;
      }
   }
}


... and, yes, I know, I should really multiply RAND_MAX by difficulty before shifting it rather than vice versa, but it's allowed to be a fuzzy result and that avoids having to involve a long.
  View user's profile Send private message Visit poster's website
  • Joined: 05 Sep 2013
  • Posts: 3758
  • Location: Stockholm, Sweden
Reply with quote
Post Posted: Wed Nov 07, 2018 12:59 pm
code it's missing this part:
#include <stdlib.h>
#include <time.h>

and SDCC would prefer you declared your local variables in the beginning of the function body.

Apart from these minor things, I suspect
srand(time(NULL));

won't work really well, as the SMS has no clock to source the random seed. We might use a counter that we can increment while the game it's showing the initial menu. Also, it would be nice to setup the map only when the first tile has been clicked, thus making that empty by default, by changing setup_map to
void setup_map(int width, int height, int difficulty, int start_x, int start_y)


Said all that, as the SMS processor (the Zilog Z80) is a 8 bit processor and it's way faster when it processes 8 bits variables (especially unsigned), as a general rule it's a good idea to switch ints to (unsigned) chars whenever possible. In our case for example:
void setup_map(unsigned char width, unsigned char height, unsigned char difficulty, unsigned char start_x, unsigned char start_y)


@efry: thanks! I remember that homebrew of yours - I really enjoyed that. We're doing this [for fun and] to learn together how to write a simple Master System game in C, but surely we can take your version as a reference :)
  View user's profile Send private message Visit poster's website
  • Site Admin
  • Joined: 19 Oct 1999
  • Posts: 14685
  • Location: London
Reply with quote
Post Posted: Wed Nov 07, 2018 3:30 pm
The Windows version moves any bomb under the first click to the first empty box in the array.
  View user's profile Send private message Visit poster's website
  • Joined: 05 Sep 2013
  • Posts: 3758
  • Location: Stockholm, Sweden
Reply with quote
Post Posted: Wed Nov 07, 2018 4:14 pm
Maxim wrote
The Windows version moves any bomb under the first click to the first empty box in the array.


we could do something slightly less lazy and move the bomb under the first click to a *random* empty box...
  View user's profile Send private message Visit poster's website
  • Joined: 24 Sep 2018
  • Posts: 66
Reply with quote
Post Posted: Wed Nov 07, 2018 4:24 pm
sverx wrote
code it's missing this part:
#include <stdlib.h>
#include <time.h>

and SDCC would prefer you declared your local variables in the beginning of the function body.


That's very C89. How strong is the preference? If it's just a performance thing then, well, you're the team leader so it's your call but having decided that we're using C because it's easier, might in-place declarations not still be preferred because they're much easier to read?

sverx wrote
Apart from these minor things, I suspect
srand(time(NULL));

won't work really well, as the SMS has no clock to source the random seed.


See, that's what one gets for just chucking in an extra function from the ASCII test without thinking very hard about the target. You're definitely right.

One other observation, compared to the ASM version, and this is my own interpretation, might say more about my prejudices than reality, might immediately be rebuffed, etc: it seems to use yet another approach to floodfill again, which does something a bit more like a sequence of full grid scans, at each scan looking for any tile that was uncovered in the previous iteration and uncovering the proper neighbours. Which if you run for a few iterations a frame rather than always to completion gives that animated effect, and once you're animating things via a fixed-cost per frame process you've alleviated any concern about being unresponsive.

So that might or might not be a better idea. It probably depends on a subjective judgment of performance. But what I've written could very easily be improved as an algorithm by adding some broader phases to the search. That's without even talking about the quality or language of implementation. It just starts to get a little more opaque. So I don't know what you'd prefer. Whatever makes sense.

sverx wrote
Maxim wrote
The Windows version moves any bomb under the first click to the first empty box in the array.


we could do something slightly less lazy and move the bomb under the first click to a *random* empty box...

Or just eliminate it entirely — unless Minesweeper players expect that difficulty X means exactly N bombs? But if so then obviously the suggested randomisation routine needs to be thrown out since it's purely locally random.
  View user's profile Send private message Visit poster's website
  • Joined: 05 Sep 2013
  • Posts: 3758
  • Location: Stockholm, Sweden
Reply with quote
Post Posted: Thu Nov 08, 2018 8:57 am
TomHarte wrote
That's very C89. How strong is the preference?


SDCC can use C89, C99 or C11 - or the SDCC 'relaxed' version of them. The point is that different SDCC versions were using different defaults, and level of compliance was (is?) very variable over the years so I usually did stick with what worked no matter what. But if you can compile your code properly with latest SDCC using a specific setting, for me it's absolutely not a problem - I'm not setting any nonsense limit. Just be aware that it possibly might return and byte you back later...
  View user's profile Send private message Visit poster's website
  • Joined: 14 Sep 2018
  • Posts: 50
  • Location: Earth
Reply with quote
Post Posted: Sun Nov 11, 2018 8:26 pm
Did some work on the puzzle theme, while still far from complete I think it does sound a little better now.

But now I'm wondering; should I continue with the current style with the way it sounds? or should I change course and try to do something different?

  View user's profile Send private message
  • Joined: 05 Sep 2013
  • Posts: 3758
  • Location: Stockholm, Sweden
Reply with quote
Post Posted: Thu Nov 15, 2018 1:25 pm
@kaportza: FWIW I like it!

So, who wants to code the screen logic part?
  View user's profile Send private message Visit poster's website
  • Joined: 08 Sep 2018
  • Posts: 270
Reply with quote
Post Posted: Fri Nov 16, 2018 4:05 pm
We seem to be stuck on creating the screen logic and no one seems to want to give it a go. How about we break down exactly what we need it to do here first and that might make it seem easier. Coding with a solid guideline is far better than just assuming what all is needed.
  View user's profile Send private message
  • Joined: 24 Sep 2018
  • Posts: 66
Reply with quote
Post Posted: Fri Nov 16, 2018 6:41 pm
I guess there needs to be:

  • a static part of the display, being the game border and any parts of a status panel that don't vary;
  • the parts of the status panel that do vary — score if we're doing it, time counter, etc;
  • the grid itself, which corresponds directly with the level map already established; and
  • a single moving object, the selection cursor. Which could be a simple 8x8 '+' or something like that rather than something that requires multiple hardware sprites for now if it is easier.

... and a first version could just launch straight into a game and run until that game's conclusion, kicking menus into the long grass.

It'd probably be easiest to decide up-front that we're just going to keep all tiles in VRAM for the entire duration of the whole program, not switch them in and out for menus and so on? So a fragment that uploads all assets, sets a fixed name table address, and returns without any additional context (no which tiles, to which section, etc) would do for getting started. No need even to worry about trying to be fast and the alignment that implies with end-of-frame, just go at the slowest speed and don't worry about it, since we're doing it only once at system startup.
  View user's profile Send private message Visit poster's website
  • Joined: 08 Sep 2018
  • Posts: 270
Reply with quote
Post Posted: Fri Nov 16, 2018 7:05 pm
I think I could program all of that actually. However I only know how to do it in ASM even so it may not(most likely won't) be the most efficient but it could do everything listed. Most of it all will just be updating the tilemap on screen and filling a portion of the screen with tiles based on the status of the playfeilds array. If everyone is fine with some ASM functions, I'll conduct a few tests to be sure but I think others should also try their hand at it as well.
  View user's profile Send private message
  • Joined: 05 Sep 2013
  • Posts: 3758
  • Location: Stockholm, Sweden
Reply with quote
Post Posted: Mon Nov 19, 2018 9:15 am
to start, we could simply make the following:

- a function that paints a single 'square' according to his state (and global flags)
void drawSquare (unsigned char x, unsigned char y)

- a function that draws the static parts of the background, as the border
void drawBorder (void)

- and finally a function that draws the whole initial map just by calling the above functions. I'm providing that just to take part ;)
void drawInit (void) {
  unsigned char x,y;
  drawBorder();
  for (y=0;y<map_height;y++)
    for (x=0;x<map_width;x++)
      drawSquare(x,y);
}

of course feel free to give better names to these functions, you know naming things is one of the hardest things to do...

all that is needed here can be done easily by using the two devkitSMS functions
- SMS_setNextTileatXY (unsigned char x, unsigned char y)
select the location for the coming SMS_setTile()
- SMS_setTile (unsigned int tile)
draw a tile at the currently selected location (the system auto-increments the location afterwards)

of course the tileset must be converted and loaded into VRAM - for instance you can use PSGcompression and load the whole tileset with
SMS_loadPSGaidencompressedTiles (void *src, unsigned int tilefrom)
where *src points to the compressed data in ROM and tilefrom is the first tile number where the tiles will be loaded (e.g. 0).

What's *not* so straightforward/automatic is creating the list of the defines for the VRAM contents - this should be done by hand, and usually it's made by the tileset creator.
Something like:
#define EMPTY_SQUARE_TILE   23
#define BOMB_TILE   37

and so on...
  View user's profile Send private message Visit poster's website
  • Joined: 05 Sep 2013
  • Posts: 3758
  • Location: Stockholm, Sweden
Reply with quote
Post Posted: Fri Dec 21, 2018 11:57 am
...you guys definitively dropped this?
  View user's profile Send private message Visit poster's website
  • Joined: 24 Sep 2018
  • Posts: 66
Reply with quote
Post Posted: Thu Dec 27, 2018 4:43 pm
I believed I was just helping to get the ball rolling; that it wasn't me specifically you wanted to teach to write Master System programs — especially as I've a background in assembly programming and am the author of a Master System emulator, so a decent amount of what's going on in a Master System isn't a mystery to me.

So I haven't so much dropped this, as believed that I was done.
  View user's profile Send private message Visit poster's website
  • Joined: 05 Sep 2013
  • Posts: 3758
  • Location: Stockholm, Sweden
Reply with quote
Post Posted: Fri Dec 28, 2018 8:56 am
thanks for your contribution - we'll see if someone wants to continue from where we are
  View user's profile Send private message Visit poster's website
Reply to topic



Back to the top of this page

Back to SMS Power!