CPCWiki forum

General Category => Programming => Topic started by: awergh on 08:36, 14 November 21

Title: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: awergh on 08:36, 14 November 21
Fitzroy Dives Deep
As per the ongoing tradition I wrote another Fitzroy game for CPCRetroDev.
The game disk and instructions can be found here:
https://awergh.itch.io/fitzroy-dives-deep (https://awergh.itch.io/fitzroy-dives-deep)
I have also attached the recent binary (v1.3) to the end of this post.

I also tried to use images in attachments but could not figure out how to add them inline so imgur it is.
Feel free to give me feedback and report some bugs as I am sure there are things to fix that I don't know about. It seemed like every time I added a new level I found a bunch of bugs.
If you don't want to read my long post just grab the disk file and play it (you have been warned that this post might go on for a while  :P ).

Fitzroy Dives Deep is unquestionably my most successful game with seventh place :D (last year was my least successful but I won't dwell on it too much).
This clearly means I did a lot more things right or less things wrong (whichever way you wish to look at it).

Rather than asking a bunch of questions (like I have some years) that no one seems to answer I will describe a bit more of my process as well as lessons learned.
I will try to add some screenshots because Gryzor said he likes having those.


A few things I learnt from the last few years for this game were:
1. Base the idea on a gameplay idea rather than a subject matter. When I decided to use sea mines I had no idea what the game was and spent a whole lot of time doing research without having a good idea on what sort of game I wanted to make. What I ended up was somewhat accurate to the idea but the core game was not that compelling.

2. Make sure the game is approachable, having some instructions is fine but avoid something really complicated.
Fitzroy in the Dark can be a little bit hard to understand how to use the inventory, but Fitzroy goes Sweeping is really hard to understand without instructions (Which I forgot to include in the submission arghh.).

3. Be careful not to make the levels barren or bare. Fitzroy in the dark has these big levels for you to explore but they aren't particularly distinct (at least not when its dark) and there isn't enough stuff or enemies to make them memorable.
I also effectively created a game that required you to make a map but I doubt many people have the patience for that.

4. Get the movement and controls right early on. Fitzroy in the dark was rather clunky initially with the selecting a square and then moving.
Fitzroy Dives Deep originally had up to jump which was OK originally but having a dedicated jump button made for a better experience. It also allowed me to use the jump key when in the water which made the water movement more interesting and faster.

That isn't to say my game is bug free. I haven't ever released a game without any bugs (like most people I expect) even if cpc-power only lists them for some games.


There are three bugs I know of that are intermittent.
1. A tile is sometimes drawn randomly on the screen, this is usually near the right edge but does not affect gameplay. (I very carefully made a video where this did not happen.)
I suspect it could be related to my backbuffer but I didn't really look into it. I haven't seen this happen when using wincpctelera.
There is a spot on the valves level where it is consistent, but I never got around to looking into it.

2. One of the snail's spawns in the wrong spot on the first level, I thought using memset on the enemy array before initialising would fix this, but it still sometimes happens. The memset fixed the game from crashing every time you reload a level though.

3. The game completely crashes at random (game breaking); I have no idea what causes this one as at other times it will be perfect playthrough which makes it hard to reproduce unless you happen to snapshot at the right time. I would have spent more time on this, but I didn't have much time and it was intermittent.
I am reasonably certain it is related to enemy initialisation issues. Intermittent CPC only bugs are always the hardest to figure out.


Not so intermittent bugs (workarounds exist)
1. When you boost upwards it doesn't always go to the right to top, I partially fixed this, but it does not work in all circumstances. Instead of Fitzroy going to the top of the screen he will be one pixel off. The workaround is that when the player boosts in water up to a solid block they also press up to get all the way to the top.
I feel this is a little bit inconvenient and adds a bit of an artificial difficulty to the game. It hopefully shouldn't be too hard to fix, I also assume no one would want me to keep this for the added difficulty?

2. On the last level there is a spot you change rooms where can you end up one pixel into a tile and seem stuck until you press up or left (can't remember which).
I considered this insignificant so haven't had a look at all why this happens.


A few things I learnt for this game:
1. How to use Arkos Tracker 2 (Thanks Arnaud and Targhan for their help), it is nice to finally have a game with sound and music.
Technically last years game had one sound but that doesn't count for much. Arkos 2 is also way better to use than Arkos 1.

2. How to use a backbuffer. Previously I have saved the video memory of an actor (player or enemy) as they move and then redraw it later. This time I used a backbuffer which was more reliable. However instead of sacrificing 16KB for the whole screen I used a backbuffer that was 4 tiles big (256 bytes).
This worked reasonably well and saved me some memory but there is a bit of slowdown because of the backbuffer.
Perhaps there is a better strategy of populating the backbuffer from the map where the actor was and drawing it at the actor's previous position and then doing the same thing at the actor's new position.
I suspect I have not got it completely right but at least there are no leftovers on the screen.

3. Limit adding new features near the end of the development time. I tried to avoid adding features in October.
This also applies to graphics where it worked out much better finalising the graphics and palette sooner (as usual I make sure to support the green screen even if I am the only person who ever uses this option).
I did spend more times on graphics this year which means they are better, but they remain fairly simple.
The more practice I have at making graphics the better I will get. I still managed to change the main character sprite and one of the interactable objects at the last minute, but I mostly stuck to this.

4. Try not to spend too much time on tools (more on that later).


More on the original idea
Back to the original game idea. The original idea was to build a game based around an underground cave system.
Some of it will be underwater and some of it will be dry. I specifically drew inspiration from Caves of Doom (A Mastertronic game that isn't that significant except that I got it with my 464)
(https://i.imgur.com/Wzs7j0r.png)

and Scubaventure (Not a CPC game but I played a lot of apogee platformers which is why I know this game).
(https://i.imgur.com/01TW8rZ.png)


I had thought of a game where you do the levels once without water and then come back a second time with them filled with water.
The idea was that you would have to navigate differently the second time because the environment changed.
I ended up building levels where bits of the level were empty and other parts were filled instead which was much easier to design.

I feel that drawing inspiration from some games that weren't considered classics means you can easily learn from deficiencies in those games and avoid ending up building an inferior clone of some other game.
My biggest gripe with Caves of Doom (besides it being impossible to play with the keyboard) is that it requires pixel perfect movement and just about everything you touch instantly kills you.
You get a lot of lives, but it isn't enough unless you have a lot of practice or modify the level with the in-game editor (this is a super neat feature of the game actually).
With my game I tried to make sure you didn't have to have pixel perfect movement but instead there is something you can use to line yourself up with.
If you want to have pixel perfect movement you can probably play the game a bit faster but that's up to you.


Difficulty
Overall, I am happy with how the game works and the progression through the levels but it has been suggested that the game is a little bit too hard. I have some ideas around adding a little bit more health and giving a way to replenish lives, but I'm open to ideas for this.

The challenge with difficulty is that I don't want the game to be too easy (Xyphoe commented on his stream that a lot of the games were a bit too easy) but I also want the game to be hard enough to give players a challenge without making it unapproachable or impossible for most people.
I feel that because the CPC has a lot of very hard games there are people who are very good at hard games but not everyone wants a near impossible challenge.


Editor
Now we get to a bit more on my process. Each year I create a map editor to design my game levels (Except for Fitzroy and the Infestation which had autogenerated levels.).
I have noticed that my editors are very iterative in that I build a very similar editor thus writing similar (improved but similar) code each year for the same thing.
In response to this I decided back in April to write a library for my editor so that the bulk of the functionality could be contained in the library, and I wouldn't have to rewrite it every year for each game editor.
This certainly helped reduce the amount of time I spent on the editor however I still spent a fair amount of time because it was not complete when I started work on the game in July.
Next year it will be even better as the library is far more complete then when I started using it.


This of course raises the question why don't I just use Tiled and save the effort of writing my own? Part of it is that I enjoy writing the editor, I also don't write much C++, so this is a good opportunity to do so.
The editor also fits into my process really well (or my process fits around my editor, not sure if it makes a difference).


This is what my editor looks like (we can see most of the test level in this screenshot). The level is made up of 3x3 Mode 0 screens.
Generally, how a level is designed is that I draw in major level features and then I fill in each individual screen with content until the level is completely filled in.
(https://i.imgur.com/9IrdGMG.png)

I then play the level and find its completely unplayable but that is simply how the process works out.
Sometimes I will test screens individually (this is what I did for later levels) rather than waiting for the whole level to be complete.
This is useful when I'm not sure if what I am trying to do is possible.
This is what one of my levels looked like early on:
(https://i.imgur.com/wojwucL.png)

The part of my process that the editor really helps with is how I design the graphics. I do all my graphics in Retro Game Asset Studio (RGAS).
The format it uses is a JSON file and as pointed out by someone on the forum (don't remember who) you can read the file for your own automation purposes.

Here we have the tiles RGAS file open in RGAS.
(https://i.imgur.com/CWtBeMy.png)

From the editor I can select any of the graphics I have created in RGAS from the tile menu.
(https://i.imgur.com/o5JiUdP.png)

I can then plop them into the editor as I see fit.
(https://i.imgur.com/UOaZCs4.png)


This year I extensively used it to try the graphics out as I was designing them as the colours match what you will see in the CPC reasonably closely.
(https://i.imgur.com/H2elz1J.png)

(https://i.imgur.com/m00J6jb.png)

Here is me trying out some metal tile designs to work out which look best.Here is me trying out some metal tile designs to work out which look best.
(https://i.imgur.com/Bub40k9.png)

Wincpctelera
I feel I can't mention my process without mentioning Arnaud's Wincpctelera.
This continues to be fantastic and makes it easy to quickly debug my game C code without having to drop down to the assembly.
It doesn't solve all the problems as some things don't happen that happen for the CPC version but it covers most things.

The wincpctelera version looks very similar as you can but it does play a bit faster which is both good and bad so you have to make sure it works on the CPC.
(https://i.imgur.com/bJhuQ6Y.png)

What's next
Looks like we made it almost to the end (or you skipped all the "boring stuff" to look at the what's next).
For next I would like to fix any bugs that I didn't fix in the initial development. Particularly the intermittent bugs which can result in the game crashing. I would also like to address the game difficulty which I think is a little bit too hard but without compromising the game thus making it too easy.
Also, there was one extra level I had hoped to make. If you look in the source code, you will find my test map that I showed earlier big1.c which is filling the space for a tenth level in the game. This might be a v1.2 but I plan to finish this map and add it to the game.

One final thought
While the editor works great for me to build levels in the game its even more interesting to see what other people can do with it. User generated content is often the best kind of content.
If people are interested, I can provide the editor and the RGAS graphics files and let people try build some levels.
If I had some complete levels, I could create a cpcwiki version of the game with a new set of levels, this would be something like an expansion or addon version of the game.
The only concern is that to really test the level you need to be able to compile the game which might be a bit of a barrier to entry.
An option would be to try extend the wincpctelera version of the game to read in my json map files but it does play a bit faster which while a reasonable way to test a level is possible it isn't perfect. Often a level is actually easier on the CPC version because it plays a bit slower.
Let me know if this is an interesting idea, graphics could possibly be enhanced this way to (I hope I can keep my green screen support though).


Change Log
v1.1 (Build 525)

v1.2 (Build 578)v1.3 (Build 598)
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: ervin on 12:18, 14 November 21
I wish I could give you more than one Like for that fantastic post.
Congratulations on finishing a very good game, and on your most successful game yet.
It's very encouraging to watch your games getting better each year.
Well done!!!
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: Arnaud on 15:05, 14 November 21
Congratulation once again for your 7th place, here small ideas or improvements :

Gameplay:

Visual:

If you make a sequel  ;D, I would have liked a game like Antiriad (or Metroid) where you unlock zones (and go back) as you acquire (and keep) equipment.
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: skylas on 01:18, 15 November 21
Congratulations! I think it is the best of your games so far!
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: awergh on 13:35, 15 November 21
Thats for all the kind words and suggestions. :)

I have a fix for the tile that randomly drew on the screen (usually to the right edge).
(https://i.imgur.com/swAIDGA.gif)



Turns out that because I was not setting futureYTileTop = 0 in Player.c as below that futureYTileTop would be 255 when processCell was called on the next line.
This would obviously get the wrong cell, in the first level where this happened you would jump and end up with the oxygen as well as the tile being drawn when it shouldn't be.



if (futureYTileTop == 255)
{
   // Check that the last cell in the room above is empty.
   if (processCellInRoom(occupiedXTileLeft, SCREEN_TILES_Y - 1, currentRoomX, currentRoomY - 1) == CELL_EMPTY &&
      processCellInRoom(occupiedXTileRight, SCREEN_TILES_Y - 1, currentRoomX, currentRoomY - 1) == CELL_EMPTY)
   {
....
   }
   else
   {
      // Set the position to the maximum position so you can scrape right against the top of the screen when jumping.
      player.object.position.y = 0;

      // Solid above the player so set velocity to 0 so they start falling.
      player.object.velocity.y = 0;

      // Reset futureYTile for the top of the screen.
      // Otherwise processCell will have a 255 which will get
      // the wrong cell and cause it to draw the wrong tiles on screen.
      futureYTileTop = 0;
   }
}

// Process the content of the future cells and perform collision detection.
occupiedXFutureYTopLeft = processCell(occupiedXTileLeft, futureYTileTop);
occupiedXFutureYTopRight = processCell(occupiedXTileRight, futureYTileTop);


Quote from: Arnaud on 15:05, 14 November 21Gameplay:
Avoid when changing rooms direct walking on trap / monster or death.
There shouldn't be any monsters when you walk into a room, I thought I avoided that.
I would have said there wasn't anywhere you could die instantly when changing rooms but you showed me otherwise yesterday.
Every trap should be avoidable as long as you know its there, I tried to avoid being unfair but I might not have succeeded every time.
I was probably particularly unforgiving in the last level.

Quote
Better identification of exits or add walls to the places where you can't get out the room.
Are you meaning places like this where you can't see where to go.
Perhaps that was a bit harsh for in the first level in this case.
(https://i.imgur.com/Z5sjwVA.png)

I do have space for a few more tile sprites, would an arrow be helpful or is there a more subtle way to do it?
I probably should have put the strawberry right next to it.

Quote
Remove some traps in the underwater areas, managing the limited oxygen is already complicated.
Add a small life bonus on some objects.
There is a health item, I have clearly been a bit stingy in using it.
I will have a look to add it in more than just two levels.

Quote
When we die, restart in the current room.
The trouble is I don't know what is a safe position.
I suppose I could save the position as soon as you change room though and then restore you to that position (but could that position still be safe).
While I have avoided putting enemies next to entrances it is perfectly possible to create levels that do that.
I was thinking more along the lines of letting you replenish your lives by getting sufficient score but I'm not quite sure how much and I don't think there is an equal amount of points available in each level.
Alternatively I decide that one item (such as the circuit board) gives you an extra life. I think Jazz Jackrabbit does that but I might be wrong there.

Quote
I think the Use key can be removed, the Shoot key can be used instead (and not shot if in front of interactive object).
At the moment I can't think of a time where you want to shoot when you're right next to a switch or something.
Even if there was it would probably be an acceptable difficulty for the player to manage.
Crystal Caves does a similar thing with using the shoot key for use as well with no noticeable down sides.
This would make the game playable with a two button joystick which would be nice (even if I don't have one).

Quote from: Arnaud on 15:05, 14 November 21
Visual:
Add a small animation for the movements.
I've never done animation in my games, it is something I should figure out.

Quote
Mirror enemy sprite according its direction.
Making enemies that are recognisable like snails means this is a bit obvious.
I thought about flipping a little but not enough to do anything about it (time running out and such).
I didn't want to store the sprite for every enemy as that is 15*64 bytes which seemed like too big a sacrifice.

I could have a temporary enemy variable (only 64 bytes) which I memcopy the enemy sprite into and flip the temporary variable before drawing it (depending on direction of the enemy).
I thought this might be slow but I didn't try it.

The other option I noticed was cpct_drawSpriteHFlip_at but that requires 256 bytes for the flip table but I didn't actually get around to trying it.

Quote
Make a little change of palette on interruption to make a visual effect of water.
Is it still a little change if I have to change many of the graphics though? I did something like this for Fitzroy in the dark but how many of my 16 colours would I have to sacrifice for this to work?

Quote
If you make a sequel  , I would have liked a game like Antiriad (or Metroid) where you unlock zones (and go back) as you acquire (and keep) equipment.


I've never made a direct sequel to one of my games. I do have an idea for a Fitzroy in the Dark sequel but I might have a completely different idea by the time July comes around next year.
In this game having not implemented carrying inventory items across levels I decided it allowed for more interesting level design when you had to go find items every level.
Haven't played Antiriad or Metroid but doing a game with zones that you come back to could be interesting. Not sure what you need to do in order to make the zones interesting the second time unless they are partly locked because you don't have sufficient items or the hoards of enemies are too challenging the first time.
It could always be your next game .
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: Arnaud on 19:53, 15 November 21
Hi,

Quote from: awergh on 13:35, 15 November 21Are you meaning places like this where you can't see where to go.
I do have space for a few more tile sprites, would an arrow be helpful or is there a more subtle way to do it?.

Exactly, you could make something like that :
[attach=1,msg209167]

Quote from: awergh on 13:35, 15 November 21I suppose I could save the position as soon as you change room though and then restore you to that position (but could that position still be safe).
Yes it's the good solution

Quote from: awergh on 13:35, 15 November 21
The other option I noticed was cpct_drawSpriteHFlip_at but that requires 256 bytes for the flip table but I didn't actually get around to trying it.
Use this compilation argument :
Z80CCFLAGS    := --peep-file ${CPCT_PATH}/tools/sdcc-3.6.8-r9946/peep/z88dk_speculative_peepholes.def --max-allocs-per-node 10000 --opt-code-size

Highest address   = 0000A59C
to
Highest address   = 0000A3E1

You have 443-Bytes free to use the flip table  :D

Quote from: awergh on 13:35, 15 November 21Is it still a little change if I have to change many of the graphics though? I did something like this for Fitzroy in the dark but how many of my 16 colours would I have to sacrifice for this to work?
Yes a color is sacrified, but it seems this color is used only for water.
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: awergh on 14:09, 16 November 21

Quote from: Arnaud on 19:53, 15 November 21[size=78%]Exactly, you could make something like that :[/size]
I will have a look to see if there are some places I should adjust in the earlier levels.
I don't think it is too unreasonable to do it occasionally during the harder levels though.
I think when I made the first couple of levels I had a greater intention to do secrets but later on I didn't bother.

Quote from: Arnaud on 19:53, 15 November 21Use this compilation argument :
Code: [Select]
Z80CCFLAGS    := --peep-file ${CPCT_PATH}/tools/sdcc-3.6.8-r9946/peep/z88dk_speculative_peepholes.def --max-allocs-per-node 10000 --opt-code-size

Highest address   = 0000A59C
to
Highest address   = 0000A3E1

You have 443-Bytes free to use the flip table 

Always happy to have extra memory especially if its easy :) but what does that command actually do? Usually you don't get extra free memory for free?

Quote from: Arnaud on 19:53, 15 November 21Yes a color is sacrified, but it seems this color is used only for water.
Are you suggesting to in the interrupt change the Cyan to Blue or a different blue (eg bright blue) or do you mean something slightly different.
I don't think cyan is used a lot but it is used a few times I think (without actually looking right now).
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: Arnaud on 18:39, 16 November 21
Quote from: awergh on 14:09, 16 November 21
Always happy to have extra memory especially if its easy :) but what does that command actually do? Usually you don't get extra free memory for free?
It uses peephole definition provided with sdcc (Wikipedia : Peephole optimization involves changing the small set of instructions to an equivalent set that has better performance)
and compilation code optimization for size

Quote from: awergh on 14:09, 16 November 21
Are you suggesting to in the interrupt change the Cyan to Blue or a different blue (eg bright blue) or do you mean something slightly different.
Yes that it.



Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: awergh on 14:01, 22 November 21
Quote from: Arnaud on 15:05, 14 November 21When we die, restart in the current room.
I had some more thoughts about this.
While enemies could be a problem I am going to assume map design will prevent this from happening and I can use activateCollisionTimer() to give the player temporary immunity in case there is an enemy there.

However I have a more difficult problem, if the initial cell in the room is underwater then it might be unsafe.
Is the best plan a compromise, when the player has no oxygen when they die to move back to the start of the level (the level is reset) but if they have oxygen then restart them at the start of the room (regardless of whether the cell is underwater or not).

Initially I had considered restarting the level if the start of the room is underwater but I need to take into account oxygen.
You could get into a position where you die from 0 oxygen and respawn at the start of a level where you are safe but everything else kills you if you move from there as oxygen may not be accessible from that point in the level.


I don't want to have to rely on level design to fix all my problems, after all someone else might design a level sometime :) .

Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: Arnaud on 19:27, 22 November 21
I haven't thought about oxygen underwater, there is not easy solution finally  ::)
Maybe a checkpoint ?
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: awergh on 13:57, 23 November 21
Quote from: Arnaud on 19:27, 22 November 21
I haven't think about oxygen underwater, there is not easy solution finally  ::)
Maybe a checkpoint ?
Yes seemed like a good idea and then you realise there is an edge case that makes it hard to implement without side effects.
However a checkpoint is an interesting idea. While I already have 31 interactable objects one of those is part of the machinery which could be changed to a tile (I think) which would free up the one we need.
It can't be like the most traditional checkpoint where you restore the game to the state at that checkpoint instead the player would move back to the location of the checkpoint when they die.
We would have to rely on map design to make sure the checkpoint is safe but I think this is an OK assumption.
If they have no oxygen when they died they will have no oxygen at the checkpoint. This is something that they will have to decide as the checkpoint would be optional.


I prefer the idea of making checkpoints only useable on easy and normal though so hard can remain the same challenge.
This would be a v1.2 feature I think. I am hoping to combine the shooting and use controls and then do a bit more testing and release that (mostly bug fixes) as v1.1.
Then more substantial things can go in v1.2.
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: Nesu on 22:03, 25 November 21
Congratulations for your improvements in game quality and contest results!
I think I've found some "secret screens" :
[attach=1,msg209577]
Just jumping to the right immediately at the beginning of the game (or a new life), FitzRoy can access to the secret area "Fitzroy Goes Wrongscreen" :)

Some random recomendations for your code:

I've noticed many calls to cpct_getScreenPtr using only constants as parameters. You only have to do the calculation in the CPC if any of the parameters is a variable.
When all parameters are constants use cpctm_screenPtr macro instead. Applying that to files Hud.c  Dialog.c and Menu.c, +160 bytes can be saved.

drawCellAtPositionSafe() function (at Map.c) is not used anywhere in the game. It's small but can be removed. Didn't check if there is more unused code.

I would not recommend making functions as long as logicPlayer() (at Player.c). SDCC does not like functions wich are too long or complex.
Maybe is because my PC is quite old, but it refused to compile logicPlayer. I had to split the function into two separate functions in order to succesfully compile the code.

Keep on improving! 
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: awergh on 12:10, 26 November 21
Quote from: Nesu on 22:03, 25 November 21Congratulations for your improvements in game quality and contest results!
I think I've found some "secret screens" :

Just jumping to the right immediately at the beginning of the game (or a new life), FitzRoy can access to the secret area "Fitzroy Goes Wrongscreen"
I like the idea of a secret area but yes clearly a bug there which I have fixed this evening (makes it into v1.1).
Perhaps Fitzroy goes Wrong is a future game title but I'm not sure what it would be about.

Quote
Some random recomendations for your code:

I've noticed many calls to cpct_getScreenPtr using only constants as parameters. You only have to do the calculation in the CPC if any of the parameters is a variable.
When all parameters are constants use cpctm_screenPtr macro instead. Applying that to files Hud.c  Dialog.c and Menu.c, +160 bytes can be saved.
Recommendations are good (my code doesn't get reviewed much). I didn't realise that I'll make sure to look into that soon and keep it in mind in the future.


Quote
drawCellAtPositionSafe() function (at Map.c) is not used anywhere in the game. It's small but can be removed. Didn't check if there is more unused code.
That is one I did know about, this was a leftover that didn't get completely removed because I didn't completely run out of memory but I have removed it recently.
Sometimes I use cppcheck to find things like this but it doesn't always give helpful suggestions.


Quote
I would not recommend making functions as long as logicPlayer() (at Player.c). SDCC does not like functions wich are too long or complex.
Maybe is because my PC is quite old, but it refused to compile logicPlayer. I had to split the function into two separate functions in order to succesfully compile the code.

Keep on improving!

Thanks thats the plan  ;D , yes logicPlayer() ballooned in size and I didn't really think about how big it might be getting.
Looks like I can't compile my game on a Linux VM with only 1GB RAM (it gets stuck at Player) so it might be the same problem as you have.




I have managed to reproduce the game crashing bug (I hope there is only the one) in the attached snapshot.
If you use the valve on the left and then pick up the oxygen it will corrupt the screen and crash.
Something is causing it to write over memory but I am not sure what.
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: awergh on 14:08, 28 November 21
Haven't made any progress with the bug.
It seems that you pickup the item and land on the solid tile there will then be screen corruption and or crashing.

If I put a breakpoint in inventorycontainsItem(CellType) 0x3BF3 it will stop as it picks up the item.
I then had a breakpoint at logicPlayer 0xCC7 and ran through that 5 times.
After that when it does a vsync it will crash.

I assume vsync is not actually the cause of the problem and instead something happened in the previous iterations of the game loop.
However no idea how to work it out. I assume something is writing to where it shouldn't which is OK for a little while but then results in catastrophic failure.
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: Nesu on 00:18, 29 November 21
Quote from: awergh on 12:10, 26 November 21
I have managed to reproduce the game crashing bug (I hope there is only the one) in the attached snapshot.
If you use the valve on the left and then pick up the oxygen it will corrupt the screen and crash.
Something is causing it to write over memory but I am not sure what.
I think the crash maybe is caused by corruption of the music. Using this snapshot in my PC I can't hear any sound using WinApe. Using RVM I can hear the music but it sounds bad.
At the point of the snapshot, changing soundMode (Address A574) to 1 (music off) allows the game to continue when picking the oxygen. Being more selective, just disabling the call for PLAYER_ARKOS_PLAYSOUNDEFFECT ( writing '0' to bytes 457C-4586 ) also seems to work . I think that the snapshot has already something corrupted about the sound.
While reviewing I found in interruptHandler() that you are playing sound every 7 interrupts, as you are using post-increment soundCounter_++. If you intended to play every 6 interrupts, I think the only consequence of this should be a slower music, not a corruption, but I'm not sure.
Also, same as with cpct_getScreenPtr, found several calls to cpct_px2byteM0 function with constants as parameters, instead of using cpctm_px2byteM0 macro
As a way to continue searching the problem I would suggest to compare the snapshot of the error, with a previously saved snapshot with the music playing properly. So you can find which memory addresses has changed.  Then use the map file to see what's in there.



Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: awergh on 11:22, 29 November 21
Quote from: Nesu on 00:18, 29 November 21
I think the crash maybe is caused by corruption of the music. Using this snapshot in my PC I can't hear any sound using WinApe. Using RVM I can hear the music but it sounds bad.
At the point of the snapshot, changing soundMode (Address A574) to 1 (music off) allows the game to continue when picking the oxygen. Being more selective, just disabling the call for PLAYER_ARKOS_PLAYSOUNDEFFECT ( writing '0' to bytes 457C-4586 ) also seems to work . I think that the snapshot has already something corrupted about the sound.
While reviewing I found in interruptHandler() that you are playing sound every 7 interrupts, as you are using post-increment soundCounter_++. If you intended to play every 6 interrupts, I think the only consequence of this should be a slower music, not a corruption, but I'm not sure.
Also, same as with cpct_getScreenPtr, found several calls to cpct_px2byteM0 function with constants as parameters, instead of using cpctm_px2byteM0 macro
As a way to continue searching the problem I would suggest to compare the snapshot of the error, with a previously saved snapshot with the music playing properly. So you can find which memory addresses has changed.  Then use the map file to see what's in there.


Oops I was testing with WinAPE muted so I didn't notice it wasn't working.
Comparing two binaries (should have done this programmatically but didn't) most of the differences are in Arkos or things that are expected to be different (counters, high scores, player)


I am using PlayerAkm.asm for music with a slight modification for volume as suggested by Targhan.
Does Arkos use self modifying code at all?
http://www.julien-nevo.com/arkostracker/index.php/forums/topic/adjusting-music-volume/ (http://www.julien-nevo.com/arkostracker/index.php/forums/topic/adjusting-music-volume/)


Yes looks like I made a mistake with music interrupts but can't change it now as that is the way the music is expected to be played (once the game is out that can't change  :) ). Thanks for pointing out yet more macros for me to look out for, I guess I haven't really looked into the macros in cpctelera.


I've attached the map file for reference.
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: Arnaud on 19:01, 29 November 21
Quote from: awergh on 11:22, 29 November 21
Does Arkos use self modifying code at all?

Yes Arkos2 use self modifying code
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: awergh on 11:25, 30 November 21
That makes it a bit harder to work out what has changed then.
Is it possible that I am using Arkos wrongly.

In runGameSession() I call initSound() which will call PLAYER_ARKOS_INITSOUNDEFFECTS.
Next I call playMusic() which will cause PLAYER_ARKOS_INIT to be called in the interrupt handler.

At the end of the game session stopSound which calls PLAYER_ARKOS_STOP will be run.

Is it possible I should only initialise once instead of doing it every game session?
I could have an empty subsong to stop the music but I assume that PLAYER_ARKOS_STOP should be enough.
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: Arnaud on 18:39, 30 November 21
You can try to initialize sound before starting your interruption, this is what is done in my games.

    // Disable the firmware to prevent it from interfering with setVideoMode.
    cpct_disableFirmware();

    // Set video mode to mode 0.
    cpct_setVideoMode(0);

    // Initialises arkos 2 sounds.
    initSound();

    // Starts playing the game music.
    playMusic(0);
   
    // Setup interruptHandler for keyboard scanning.
    cpct_setInterruptHandler(interruptHandler);
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: awergh on 14:14, 02 December 21
Still experimenting but maybe progressing.
It is possible to reproduce it if you start a game and exit straight away (proceeding to do that a few dozen times will eventually cause it to crash).
Return TRUE from exitDialog() and commenting out the press any key functions in displayEndScreen() helps make this faster (also speeding up WinAPE can help for this).

Now my first attempt to only initialise Arkos once didn't work as it still reproduced the problem.
When I commented out all Arkos functions it appeared that it worked no problems.
I haven't tested enough but when PLAYER_ARKOS_STOP() only was commented out it appeared to work but not fully sure on that.
Maybe the empty subsong instead of stopping arkos is the way to go instead of using the stop function.
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: Arnaud on 08:08, 03 December 21
I have not to reproduce the problem, but when in your menu you can just set  :

soundMode = NO_SOUND_DISPLAY_MENU;

to simply just not to call playSound() in your interruption.

And when game start, put the right value :

soundMode = SOUND_MODE_ON;

Thus not need for the function PLAYER_ARKOS_STOP()
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: awergh on 15:04, 03 December 21
I had a go with not using PLAYER_ARKOS_STOP() and updating soundMode to disable sound but it results in a hanging note which is much worse.
Tomorrow I will have a go with the empty subsong idea.
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: Nesu on 00:50, 05 December 21
Found that stopSound() calls PLAYER_ARKOS_STOP() outside interrupts. PLAYER_ARKOS_STOP() must be called only inside intrerrupts, as it changes the stack pointer for its calculations:_PLY_AKM_STOP::
PLY_AKM_STOP: ld (PLY_AKM_SENDPSGREGISTEREND+1),sp
  (...)
  jp PLY_AKM_SENDPSG

PLY_AKM_SENDPSG: ld sp,#PLY_AKM_TRACK3_DATA_END
(...)     
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: Arnaud on 10:17, 05 December 21
Well done @Nesu (https://www.cpcwiki.eu/forum/index.php?action=profile;u=4019)  :)

@awergh (https://www.cpcwiki.eu/forum/index.php?action=profile;u=249) I discover my C binding tutorial has big flaws  :'(

Like CPCTelera do, it shall have two functions type, interrupt safe (to use in interrupt) and other that disable interrupt :

extern void PLAYER_ARKOS_PLAY();
extern void PLAYER_ARKOS_STOP();

// Interrupt safe
extern void PLAYER_ARKOS_PLAY_IT();
extern void PLAYER_ARKOS_STOP_IT();


_PLAYER_ARKOS_STOP_IT::
    jp   PLY_AKM_STOP
_PLAYER_ARKOS_PLAY_IT::
    jp   PLY_AKM_PLAY
   
_PLAYER_ARKOS_STOP::
    di
    call PLY_AKM_STOP
    ei
    ret
_PLAYER_ARKOS_PLAY::
    di
    call PLY_AKM_PLAY
    ei
    ret


StopSound function modification :

void stopSound()
{
    if (soundMode)
    {
        // Turns off the sound if enabled.
        soundMode = SOUND_MODE_OFF;

#ifndef WINCPCTELERA
PLAYER_ARKOS_STOP();
#endif
    }
}


Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: awergh on 13:32, 05 December 21
Thanks both of you as I have now fixed the problem  ;D  (I really appreciate it as intermittent bugs are the hardest to fix.).
I didn't see your interrupt safe stop so I did without it but I'll have a look for v1.2.
I have updated the itch.io page with the binaries for v1.1 along with the source code.
I have not incorporated many the suggests as I wanted to fix the bugs first, for v1.2 I will be a bit more adventurous with the changes which is also much more fun  :) .

Change Log for v1.1 (Build 525)

- Fixed memory corruption crash from stopping Arkos sound outside an interrupt.
- Make sure you cannot go above top of screen.
- Combined shoot and use to a single control.
- Moved spike near top left entrance of middle right room to make room transition easier on second level.
- Expanded the right most wall in the centre middle room to make room boundary clearer on second level.
- Removed spike near bottom right room entrance on the intro level to make room change easier.
- Made centre middle exit more obvious on the intro level to make room change easier.
- Entrance to bottom mid room is now normal water on valves level to prevent instant death.
- Fixed clipping through solid blocks underwater.
- Added additional health to the game to make it slightly easier to play.
- Fixed water boosting just off block bug.
- Improved boost pixel off bug fix when water at top of screen.
- Fixed bug where a tile can be drawn seemingly randomly on screen due to a futureYTile value of 255 (-1).
- Fixed bug where a valve could be used multiple times to cheat valve objective action count.
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: Arnaud on 13:47, 05 December 21
Quote from: awergh on 13:32, 05 December 21
I didn't see your interrupt safe stop so I did without it but I'll have a look for v1.2.

The  function named PLAYER_ARKOS_STOP_IT in beginning of code example.
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: awergh on 14:02, 06 December 21
Quote from: Arnaud on 13:47, 05 December 21
The  function named PLAYER_ARKOS_STOP_IT in beginning of code example.
Ah yes, I think what actually happened is I did my post without checking to see if there were any further replies (excited to be finally done bug fixing I think).


I have updated the first post with the change log and a copy of the game binaries in case people are too lazy to look at the itch.io page.
I started finishing (or is it continued finishing) the level that I didn't finish on submission night but it seems I don't quite remember what my plan was whoops...


Thinking about checkpoints again I assume that the most logical thing to do is let you use a checkpoint as many times as you like (this makes sense if a map has multiple checkpoints) rather than making them single use. My thought is that I will track the position of the activated checkpoint and use that to draw an updated graphic rather than changing the interactable from ready checkpoint to activated checkpoint (requiring two interactables that I don't have). I also can support multiple checkpoints this way as I can only restore the player to the last activated checkpoint.
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: awergh on 11:35, 20 December 21
I am now ready to release the second update for the game focussing on improving the difficulty of the game and adding an additional level that did not get completed in the initial release.
See the itch.io page or the first post (for the lazy) for the game binaries.

The biggest change is the inclusion of checkpoints. When a checkpoint is activated you will be able to restore their position on death to the checkpoint that was activated. You will retain all their progress in the level up to the point of death. If the checkpoint is unfriendly (eg underwater with no oxygen) you can choose not to restore the checkpoint and instead restart the level (resetting the level and player items).


I did experiment with flipping the enemy graphics but it turns out because I add the graphic to the backbuffer I can't just use a fliptable.
My initial attempt copying the graphic, flipping and then adding it to the backbuffer was visibly slower (didn't seem to play much slower but the enemies definitely moved side by side when comparing with and without).


I am happy to do a v1.3 if you have any suggestions that I should really include or any new improved bugs I have included in this version.
I would like to do something with flipping the enemies still. I was thinking about caching the graphics in some way (really only ever have 2 enemies on screen at a time) but decided better to release it then to agonise over it too much. I'm probably a bit tired of the game at this point but feedback is still welcome. I'm still keen to release the map editor in some form if it could mean some new levels. It would be fun to see what other people could make.


Changes in v1.2 (Build 578)
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: awergh on 15:55, 21 January 22
Having had a bit of a break from this I thought it was time to have another look at flipping sprites.
I feel I am being a bit hopeful to try and use cpct_drawSpriteHFlip_at to draw to a backbuffer but thought I would try anyway.

Ignoring whether that is impossible or not I cannot seem to get it to compile.
I added the following the top of the C file.
cpctm_createPixelFlippingTable(g_flipTable, 0x7F00, M0);

However when trying to use the fliptable it fails to compile. According to the documentation this looks like what I am supposed to do but it isn't working so far.
cpct_drawSpriteHFlip_at(sprite, mapMemory, TILE_WIDTH_BYTES, TILE_HEIGHT, g_fliptable);

I haven't got any examples outside of the user manual, I probably should be doing this in a separate single file project but its late (because of course it is :P ) so I am being lazy.
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: SpDizzy on 17:52, 21 January 22
Hi awergh, what is exactly the error it shows on compile?

Maybe the flipping table is not declared on the file you are trying to use it?
If that's the case, you just need to declare it this way to be used:

cpctm_declarePixelFlippingTable(g_flipTable);
That's just a declaration to make it accessible from different code files, it does not generate any code.

Also take into account the flipping table ocuppies 256 bytes, so be carefull to not overlap parts of your code
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: Nesu on 18:27, 21 January 22
Quote from: awergh on 15:55, 21 January 22
cpctm_createPixelFlippingTable(g_flipTable, 0x7F00, M0);
...
cpct_drawSpriteHFlip_at(sprite, mapMemory, TILE_WIDTH_BYTES, TILE_HEIGHT, g_fliptable);
g_flipTable is not equal to g_fliptable (case sensitive)
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: SpDizzy on 18:55, 21 January 22
Quote from: Nesu on 18:27, 21 January 22g_flipTable is not equal to g_fliptable (case sensitive)
Damn!! That's the error :)
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: awergh on 01:34, 22 January 22
Well that is a little embarrassing :doh: , but I'm sure I'm not the only person who missed the obvious.
I didn't really think I would be able to use it to try to the backbuffer but worth trying anyway.

So given cpct_drawToSpriteBuffer doesn't take a fliptable do I have to copy the sprite flip it and then add it to the backbuffer?
I have tried this but it is visibly slower (side by side enemies move faster without it).





void addActorSpriteToBackbuffer(u8 x, u8 y, u8* sprite, u8 direction)
{
    // Determine the position within the backbuffer that the new sprite should be added to.
    u8 position = y * backbufferWidth + x;
    u8* mapMemory = backbuffer + position;
    u8 flippedSprite[64];


    cpct_memcpy(flippedSprite, sprite, 64);


    if (direction == DIRECTION_LEFT)
    {
        cpct_hflipSpriteM0(TILE_WIDTH_BYTES, TILE_HEIGHT, flippedSprite);
    }


    // Draw the specified sprite on the back buffer as pointed to by mapMemory.
    cpct_drawToSpriteBuffer(backbufferWidth, mapMemory, TILE_WIDTH_BYTES, TILE_HEIGHT, flippedSprite);
}




I don't have the memory to add a 64 byte buffer to the enemy struct as 15x64 is a lot of memory.
(There is probably plenty of memory to be reclaimed by 960 bytes seems like a bit much).
I don't think I ever have more than 2 (maybe 3) enemies on the screen at once so I could sacrifice 192 bytes and effectively cache the sprite but I feel like this will require a fair bit of code to get working correctly.
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: Arnaud on 10:20, 23 January 22
Hi @awergh (https://www.cpcwiki.eu/forum/index.php?action=profile;u=249),
here the function cpct_drawToSpriteBufferHFlipM0

Simply unzip in your cpctelera/src/sprites/drawToSpriteBuffer folder
then go to cpctelera folder and enter make.

I have tested with the softDoubleBuffer example, but it's a mode 1, not mode 0.

Arnaud
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: awergh on 13:06, 23 January 22
Thanks heaps Arnaud  ;D . It is slightly slower side by side but I think it is manageable and I see there is no flip table which is nice memorywise.
I think there might be a bug (see below) the player and the snail are both currently flipped but they are displayed one pixel into the block underneath.
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: Nesu on 20:21, 23 January 22
Quote from: Arnaud on 10:20, 23 January 22
here the function cpct_drawToSpriteBufferHFlipM0
I think when calculating the starting drawing point:146       ;; Make HL point to the right-most byte of the first row of the buffer to be drawn
147       dec  a                        ;; [1] A = width - 1
148       add_hl_a                      ;; [5] HL += width - 1 (Point to last byte at the buffer)
it should be as:  ld a,c  ;; A = sprite width
  dec a
  add_hl_a
as at that point of the code A was holding sprite_width+buffer_width

Also, in function explanation, input parameters A and B are swapped (also wrong in CPCtelera's cpct_drawToSpriteBuffer)
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: Arnaud on 21:03, 23 January 22
Thanks @Nesu (https://www.cpcwiki.eu/forum/index.php?action=profile;u=4019),
your correction is right  :)

Here the fixed version.
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: awergh on 13:55, 24 January 22
Thanks Arnaud and Nesu it is working now :).
I'm mostly done with flipping although I am keeping my memcpy solution for wincpctelera for now.
This means I am definitely doing v1.3.
So is there anything else I should be doing that I have overlooked as I don't really have much I was planning to change but am happy for some more suggestions.
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: Arnaud on 18:26, 24 January 22
Quote from: awergh on 13:55, 24 January 22
I'm mostly done with flipping although I am keeping my memcpy solution for wincpctelera for now.
I should have to make a pull request for this code on cpctelera github, but i am not sure it will be taken in account :'(

Quote from: awergh on 13:55, 24 January 22This means I am definitely doing v1.3.
So is there anything else I should be doing that I have overlooked as I don't really have much I was planning to change but am happy for some more suggestions.
Making animations for Fitzroy movements ?
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: awergh on 14:13, 25 January 22
Quote from: Arnaud on 18:26, 24 January 22
I should have to make a pull request for this code on cpctelera github, but i am not sure it will be taken in account :'(
Yes you should but it does seem that progress has been a little slow lately with cpctelera unfortunately.
I'll include your additions with the source code instructions to make it easier for anyone to build it.


Quote from: Arnaud on 18:26, 24 January 22
Making animations for Fitzroy movements ?
I was thinking about some simple animations for Fitzroy's movement.
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: awergh on 11:47, 02 February 22
I am now done with update number three (v1.3), this was a smaller release adding some extra sounds as well as some basic character animation and enemy sprite flipping.
See the itch.io page or the first post (for the lazy) for the game binaries.


I'm happy to consider work (mostly cosmetic changes in v1.3) on the game complete unless there are some bugs I need to fix.
I would like to provide the map editor and see if anyone wants to try making a level although it would need to be packaged up and instructions written.
It might be all too hard for other people to make levels (someone needs to compile the game to test the level) but I'll never know if I don't try.  ;D

Changes in v1.3 (Build 598)

Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: Arnaud on 20:18, 02 February 22
I find really better with player animation and flipping enemy sprites, it makes your game really more polished.

I'll try to finish this time your game with this version.
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: awergh on 09:41, 03 February 22
Quote from: Arnaud on 20:18, 02 February 22
I find really better with player animation and flipping enemy sprites, it makes your game really more polished.

I'll try to finish this time your game with this version.
Thanks, it certainly feels the most polished.
I'm still aiming to finish it from start to finish on brutal in one sitting but so far I've died on level 9.
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: ervin on 13:17, 03 February 22
I've finally given this game the playtime it deserves.
It's fantastic!
I think you've done a great job with the updates, and it is indeed much more polished now.
Title: Re: CPCRetrodev 2021 : Fitzroy Dives Deep
Post by: awergh on 13:56, 16 March 22
Quote from: ervin on 13:17, 03 February 22I've finally given this game the playtime it deserves.
It's fantastic!
I think you've done a great job with the updates, and it is indeed much more polished now.
Thanks, how far did you get?

Recently I set myself a goal to finish my game on brutal in a single sitting without any snapshots and I can now say on the 9th attempt I was successful ;D .
(It has been quite a while since I finished one of my games from start to finish, it is so much faster to play the levels individually.)
brutal-complete-score.png

WinAPE lets you record the play session so if you have a spare 1h 12m 21s spare you can see me play it not quite perfectly (there were a few mistakes) but pretty good as there were no deaths in the final attempt  :o .
Playback isn't quite as convenient as a video but this way I didn't have to worry about getting to the end only to discover the video broke.
fitzroy-dives-deep-v1.3-winape-recording-brutal-complete.zip

I'm guessing .snr files are not normally posted as its not one of the permitted attachments.
Powered by SMFPacks Menu Editor Mod