BEJEWELED TWIST in 6502 ASSEMBLY: WATCH AS A MAN GOES NUTS

C64 scene events, programming, graphics and music. Open discussions and feel free to ask for help.

Moderator: Lemoners

Post Reply
User avatar
BleedingEdgeMonotone
Posts: 13
Joined: Mon Jan 12, 2026 9:47 am
Location: The United Vialists
Age: 19
Contact:

BEJEWELED TWIST in 6502 ASSEMBLY: WATCH AS A MAN GOES NUTS

Post by BleedingEdgeMonotone »

SO. Right now I am working on a port of Bejeweled Twist (the best Bejeweled game if I can be honest with you,) for the Commodore 64. Since Bejeweled is a fairly straight forward game, given that it's a match-3 puzzle game, I figured it'd be excellent to try my hand at since I still remember 6502 ASM. (Of course, not to the degree I used to. I still have to get help with functions every so often...) Did it go well?

Nope. This port (that's not even done yet, mind you) had me genuinely in the throes of turmoil with troubleshooting and debugging. Even now I'm still struggling after I overcame a massive flaw.

FIRSTLY, the game logic itself is entirely different than anything related to the normal Bejeweled. Instead of swapping pairs of gems in order to make a match, you (what else?) TWIST the gems clockwise into their matches. THIS itself already posed an extremely difficult challenge for me to pull off since a swap would be infinitely easier - spinning the gems would require setting up logic for rotation, the sprite for the rotator cursor itself, the recognition of matches, et cetera, et cetera.

So how exactly did I do it? Did I curl up and cry in the corner like a wimp?
Well maybe yeah I did. But it was just a LITTLE bit of ugly crying! Don't act like you wouldn't too!

ANYWAYS! Development of the game itself started with having to essentially re-learn 6502 ASM. Given that I already knew it prior to, but just needed a refresher, I got looking through my old documentation from 2019. I was just 11 at the time! (And boy, let me tell you. My handwriting was absolutely AWFUL.) Luckily my knowledge was simply buried underneath the sands of my memories so once I started feeling that flow again, I got to it right from the get go.

--------------------

The first thing I needed to do was set up a list of criteria. Obviously with Bejeweled Twist being released in 2008, it was GUARANTEED that I would not be able to include certain functions of the game, given that:

1. It is complex; it has 4 game modes, that being CLASSIC, ZEN, BLITZ and CHALLENGE. CHALLENGE mode itself would require having hundreds of challenge phases, which just wouldn't be possible with only 64 KB of memory. Maybe in the future if I learn bank-switching routines?
2. The original game has saving and loading which, with my current skill-set, isn't yet possible.
3. It also has a multitude of different gem types, some of which would be difficult at my current skill-set.

So, my initial criteria was simple; mainly to get the premise the whole game is centered around working. This was going to be a great challenge indeed. My first goal was to create a custom character set, as I wanted the high-resolution graphics mode that comes with it. (Also because I could not quite figure out the multi-color graphics mode when I started the project - but I'm too deep into it to undo it!)

Image

Right here was when I initially created my character set with the jewels, and set up the rendering itself. I was quite happy to see that I could still load in my own character data! (Although with C64Studio, this frankly wasn't that hard. I just had to set up a constant at the start telling me which address has my character data, then set up at the very end the !bin path my charset binary was located.)

The next thing to do was get multiple other tiles made and get a grid of 8 gems by 8 gems up on the screen. At this point in time I wasn't concerned about function so much as I was about getting things generally operational. This was easy enough to do, though, and I got this. The tileset looks a bit strange for Bejeweled, but this was because at the moment I hadn't yet made the rest and used placeholder tiles from another game I'm working on. Then, I set up a randomizer for the board itself using the SID Noise initialization I set up in the constants; that being, Bejeweled sets up the board with a random amount of each gem on the board. Again, this was easy enough to do, but lord if I wasn't totally sidewinded once this initially-smooth-sailing period was gone.

Image Image

At this point I was feeling pretty good about myself. I thought the rest of the game's coding was going to be smooth, clean, relaxing.

Well if that wasn't the most incorrect statement of the century then I haven't any idea what else IS!

---------------------------

It was at this point I wanted to get the actual rotation part of the game operational. I wasn't concerned yet with getting gem-gravity, matching logic or cascades to work (which was a catastrophic mistake as you'll see later,) so I turned my attention to the cursor system, inputs, et cetera. I went ahead and chose to use a sprite for the cursor, as it'd appear over the gems and could move independently.

Image

As you can see, it was very hastily thrown together as my main concern was getting the thing functional at all. It was at this time I also set up a score counter (which didn't work yet because I hadn't yet created matching logic to determine when and where to give points...) and began coding in the actual rotation part of the main code.

This is where sh*t hits the fan.

I assemble the code so far, and immediately I notice something wrong - which I later discovered was a result of accidentally overwriting the character set I had JUST written INTO memory in the initialization routine. I left the character set back to $2000 to give myself some extra room. I'm sure you can see where this goes.

Unknowingly I had created a situation where I was 'limited' by the position and address I had given the character set. My current game code was set to initiate at $0801, which as far as I know is fairly standard, but also forgot to update the VIC register beforehand! And with the advancement of my game code, it was beginning to creep up - going from $1000, to $2000 (uh oh!) and before I knew it, BAM! It crashed right into the character set's data in RAM, started reading it as game code and wouldn't work!

Image

I didn't yet realize, when I initially wrote everything in, that this was a significant mess up. But this wasn't even the biggest one - you'll see that here in a second. It took me a couple hours, maybe a few more than that, to figure out via process of elimination what it was I was doing wrong (because I stupidly had the console debugger closed on C64 Studio...) but eventually through lots of wasted time I ended up correcting it like I should've and set everything in the proper places so nothing got overwritten. It only got worse from here, as the game got better.

I then noticed the twist function stopped working at all - and I wasn't sure why. I now of course know this was because I had written an LDX instead of the LDA I had intended on using- which meant that my input for the FIRE button was being loaded from the register that had nothing meaningful to it inside of it - this kept causing me game crashes. Again, it took lots of time searching to figure that out and change that pesky little instruction to the one I wanted. At the time though it was driving me MAD!

--------------------

At this point, I rewrote the placeholder graphics and made them look like what the game was supposed to be; Bejeweled. I was happy with how they looked for now, and I'm not still concerned with adding any special effects. As you can see right here, it looked decent...
This is where that failure to write in the logic for the cascades in a timely manner REALLY came back to bite me in the ass.

Image

Gravity and cascades were not working, as I never coded them in to begin with. I didn't think this would be that big of a deal, but it turned out to be an issue that STILL plagues me! I had to write in a routine to check for gravity, bring gems down, deposit new ones onto the board - and make no mistake, it was not (and still isn't) pretty to write - and it barely works. But I've made my current code so dependent on this section not changing that it breaks the whole thing to try and rewrite it. Allow me to explain what I think is going on;

When the fire button is pressed on the joystick and the cursor rotates your selection of 4 gems, the game scans the whole board for if any matches of 3, 4 or 5 are made horizontally and vertically. If it detects any, it clears those, produces a little Plink! noise, and if it's a 4 or 5 match, creates special gems to put on the board. 4 gems creates what is called a Flame Gem, and it explodes in a 3x3 Gem area and destroys those gems when matched. What I failed to account for was gravity, and cascading - that being when gems drop automatically into a line of 3, 4, 5 or more. This resulted in cascades being calculated and executed INSTANTLY - which took the 3x3 area it was supposed to destroy...

Image

And takes a big chunk out of either vertical or horizontal bars of where other gems would have landed before the calculation completed.

I still haven't managed to figure out the true cause, not just speculation, of why or how this happens and for the life of me I still haven't been able to fix it, no matter what I do. But, at least it works... For now though, I've been directing my focus on polishing up some features, working on graphics and trying to figure out why my game won't play SID music no matter what kind of input I attempt to get out of it. I suspect I'm just being stupid again but if that changes I'll let you all know. Here's the current version of the game, updated for NTSC. I haven't tested this on an in-person system quite yet but once I get my SD2IEC device, I will do so.

As for the list of bugs I'm still trying to squash at the time of writing:
  • Sound Effects seem to un-randomize gemfall - I think this has to do with the SID and it's noise generator?
    Lightning Gems and Flame Gems take random chunks out of horizontal and vertical bars
    Cannot get SID files to play no matter what kind of thing I do with them or the code itself
    Holding down a direction on the joystick causes the game to stop execution - letting go continues it
    Board starts out with no gravity - pressing FIRE starts game function properly
    Score seems to be broken and tied to LEVEL for some reason I can't figure out
    Level Meter does not work
If any of you guys can point me in the right direction, give me some optimizations to make, or rewrite some faulty segments - please do so, I'm always open for advice!!

Image
https://drive.google.com/file/d/1_ul-cv ... sp=sharing
https://drive.google.com/file/d/1R9rsKR ... sp=sharing
https://drive.google.com/file/d/1A-7aLj ... sp=sharing
:)
" Unbounded. Unkillable. Unstoppable. "
User avatar
C64 Mat
BASIC dissector
BASIC dissector
Posts: 5188
Joined: Wed Nov 21, 2007 12:19 am
Location: On a other planet, it seems.

Re: BEJEWELED TWIST in 6502 ASSEMBLY: WATCH AS A MAN GOES NUTS

Post by C64 Mat »

Oh man, I love story like this, watching the breakdown of a one man journey into making something from scratch. BASIC or Assembly, it's always fascinating to me, starting with a simple POKE or LDA and getting to a full game.

Those points we reach, where we're bashing our head against a wall trying to do the simplest of things and not seeing the wood for the trees, or thinking "I'll do this bit later!" and later realising it has a knock on effect on everything before and after - overcoming those is just wonderful.

I really enjoyed reading this, I love that you've persevered relearning the code and pushing through! I'm really looking forward to version 1, and then maybe seeing it more polished up later. The hi-res graphics look good by the way!

Well done 👏🏻
I'm not arguing with you, it's just an opinion.
--------
C64U FTP Guide | C64U Custom READY Guide
C64U Patching Guide | C64U Saving To EF/CRT Guide
--------
Join the Monthly Competition!
Image
User avatar
BleedingEdgeMonotone
Posts: 13
Joined: Mon Jan 12, 2026 9:47 am
Location: The United Vialists
Age: 19
Contact:

Re: BEJEWELED TWIST in 6502 ASSEMBLY: WATCH AS A MAN GOES NUTS

Post by BleedingEdgeMonotone »

Thank you!! :) I'm still headstrong into this project and I don't plan on putting it down until it's absolutely perfect.
" Unbounded. Unkillable. Unstoppable. "
User avatar
didi_lxt
Trollie Wallie
Trollie Wallie
Posts: 368
Joined: Fri May 04, 2012 2:46 pm
Location: Germany

Re: BEJEWELED TWIST in 6502 ASSEMBLY: WATCH AS A MAN GOES NUTS

Post by didi_lxt »

Thanks for your effort! It already plays quite well. I still love the original game which is really much better than countless gem-swap games.
I always played "classic" mode, Will be quite a challenge to add the logic for the chains, bombs, bonusses, etc. Looking forward to it!
User avatar
Endurion
Lemon64 Game Champion
Lemon64 Game Champion
Posts: 2118
Joined: Thu Feb 19, 2004 8:38 am
Location: Right behind you
Contact:

Re: BEJEWELED TWIST in 6502 ASSEMBLY: WATCH AS A MAN GOES NUTS

Post by Endurion »

I've looked a bit into it and modified some parts. Hope you don't mind. You can download the package from https://www.georg-rottensteiner.de/webm ... dTwist.zip

What I did:
* Created a solution/project around it (just open the .s64 file in C64Studio)
* Replaced the binary inclusions of the charset, title, background and sprite with corresponding project files (the !media directives) -> now you can modify the screen in the editors and hit build and run right away, no need to export to intermediate data/files
-> the character set is included in both title.charscreen and background.charscreen, the charset is fetched from "background.charscreen" as well.
* Added a Goat Tracker example file as SID. Exported it to player address $8000, and zero page addresses $fe and $ff (do not use those in your code!) -> plays now fine, unless you rotate, which seems to take a hefty chunk of frame time
* replaced the !byte statements for the BASIC stub with the !basic directive
* on some places I've broken the assembly apart when you had several statements in one single line. The debugger is unfortunately not taking that into account, making debugging a lot harder.

What I fixed:
* Holding down a direction on the joystick causes the game to stop execution - letting go continues it
-> you had a small loop waiting for the release of the joystick. You can't do that as now you're not calling the main loop. I've set the direction bit in a variable JOY_RELEASE, which is checked in the joystick routine. If the direction is still pushed, the joystick movement part is skipped.
* Score seems to be broken and tied to LEVEL for some reason I can't figure out
-> When increasing the score you set the value to both the first and the third byte.
You also used the decimal mode, which is better not done. It interferes with interrupts, and is basically more trouble than it's worth. I've changed the SCORE_HEX to use 6 bytes (one byte for each digit) and replaced the decimal mode with plain addition. Also makes displaying the score a lot easier
* The level and remaining count display wrote a space onto your display, I've moved the display one char to the right and cut out the space.

What is still broken
* GOAL_REMAIN is set to a value > 9 once you level up. That's why the display is then showing some characters. You may want to change the display to several digits, or split the value.
* The SID playing is not stable when a lot of frame time is used. When you rotate a lot of calculation is going on, causing the next game loop miss at least one frame. That's when the SID is stuttering. You might want to look into setting up a simple IRQ routine for the music playing.
User avatar
reFLEX
Joe Blade
Joe Blade
Posts: 278
Joined: Sat Aug 26, 2023 9:31 pm
Location: Bavaria
Age: 54
Contact:

Re: BEJEWELED TWIST in 6502 ASSEMBLY: WATCH AS A MAN GOES NUTS

Post by reFLEX »

here's what I was thinking... "JonEgg could work his magic on that one - those Graphics could use an overhaul."
Other than that, nothing to complain about :)
💾6️⃣4️⃣ Download my C64 Covers @ https://reflexed.itch.io 6️⃣4️⃣💾
User avatar
the wolf
Trollie Wallie
Trollie Wallie
Posts: 330
Joined: Sun Feb 25, 2024 10:26 am

Re: BEJEWELED TWIST in 6502 ASSEMBLY: WATCH AS A MAN GOES NUTS

Post by the wolf »

Yep, maybe just a bit more... coloured. That black background is almost trivial with all those jewels! :)
User avatar
IsaacKuo
Jumpman
Jumpman
Posts: 3229
Joined: Sat Jul 31, 2021 11:05 pm
Location: Baton Rouge, Louisiana, USA
Age: 54

Re: BEJEWELED TWIST in 6502 ASSEMBLY: WATCH AS A MAN GOES NUTS

Post by IsaacKuo »

I like the classic black background and high resolution pixel art.

While it's true that a bit more pixel art skill might make it look more shaded, as well as use of differing quadrant colors within each tile, I like the classic look.

(For example, you often see different colors used for "diamonds" like in Giana Sisters. The top left char is, say, white, while the other quadrants get progressively darker.)
User avatar
reFLEX
Joe Blade
Joe Blade
Posts: 278
Joined: Sat Aug 26, 2023 9:31 pm
Location: Bavaria
Age: 54
Contact:

Re: BEJEWELED TWIST in 6502 ASSEMBLY: WATCH AS A MAN GOES NUTS

Post by reFLEX »

Nah, as it is, I don't quite like the look - this is not Bejeweled but somethin' else..
the wolf wrote: Sat Jul 25, 2026 10:28 am Yep, maybe just a bit more... coloured.
ex-actly.
💾6️⃣4️⃣ Download my C64 Covers @ https://reflexed.itch.io 6️⃣4️⃣💾
Post Reply

Who is online

Users browsing this forum: jc70 and 3 guests