Unused Citadel bits

reminisce about classic bbc micro and acorn electron games here
Related forum: adventures


User avatar
streaks
Posts: 275
Joined: Thu Oct 13, 2005 3:08 pm
Contact:

Re: Unused Citadel bits

Post by streaks »

(Sorry to spam)

I'm looking at that hacked Citadel image with the screen browsing.. looking at the platform move I wonder I've noticed another characteristic that MAY be unique to it - when they're moving down and touch the floor their movement terminates at an irregular Y offset instead of when it's level with it's Y-cell offset. I don't know if the tile's small height is already accounted for in movement logics though.
streaksy (at) gmail (dot) com
User avatar
Diminished
Posts: 598
Joined: Fri Dec 08, 2017 9:47 pm
Contact:

Re: Unused Citadel bits

Post by Diminished »

6502 wrote:
Tue Oct 30, 2018 11:36 pm
Bits 0,1,2,3 - Seems to selects which frames are displayed during animation sequences.
Bits 4,5,6,7 - Speed of tile flipping in animations. 0 fastest, 16 slowest.
Yeah, I mentioned this. Bits 0-3 choose an "A-type" animation subroutine for the tile from this pair of tables:

Code: Select all

; note that these are all unique
.T_ANIM_A_SUBS_LOW
  equb (witch_thing_maybe   and &ff)
  equb (L3e90               and &ff)
  equb (L3e92               and &ff)
  equb (animation_thing_1   and &ff)
  equb (L3ea6               and &ff)
  equb (L3eb4               and &ff)
  equb (L3ec5               and &ff)
  equb (temple_moose_maybe  and &ff)
  equb (L3ee2               and &ff)
  equb (L3efb               and &ff)
  equb (temple_guardians    and &ff)
  
.T_ANIM_A_SUBS_HIGH
  equb (witch_thing_maybe   div &100)
  equb (L3e90               div &100)
  equb (L3e92               div &100)
  equb (animation_thing_1   div &100)
  equb (L3ea6               div &100)
  equb (L3eb4               div &100)
  equb (L3ec5               div &100)
  equb (temple_moose_maybe  div &100)
  equb (L3ee2               div &100)
  equb (L3efb               div &100)
  equb (temple_guardians    div &100)
Meanwhile the 4-7 bits pick an animation period from this table. Note that it's not a linear relationship:

Code: Select all

.T_ANIM_SPEEDS_MASTER    equb  &01, &02, &03, &04, &05, &07, &0a, &0d, &10, &14, &19, &1e, &28, &3c, &50, &64 
Bit 0 - Tile on horizontal or vertical set movement path flag. Such as rope climbers.
Bit 1 - Tile on diagonal irregular set movement path flag. Such as flying sparklies.
Bit 2 - Tile chase flag. Such as monks.
Bit 3 - Suspect not used. Only some wall tiles (81,88) have this flag set, for no obvious reason.
Technically these four bits are just a number which just pick another pair of animation subroutines (I called them "B-type" and "C-type") from another four tables:

Code: Select all

.T_ANIM_B_SUBS_LOW
  equb (anim_B_sub_hori       and &ff)
  equb (anim_B_sub_vert       and &ff)
  equb (anim_B_sub_hori_vert  and &ff)
  equb (anim_B_sub_4          and &ff)
  equb (anim_B_sub_chase      and &ff)
  equb (anim_B_sub_mummy      and &ff)
  equb (anim_B_sub_monk       and &ff)
  equb (anim_B_sub_fires      and &ff)
.T_ANIM_B_SUBS_HIGH
  equb (anim_B_sub_hori       div &100)
  equb (anim_B_sub_vert       div &100)
  equb (anim_B_sub_hori_vert  div &100)
  equb (anim_B_sub_4          div &100)
  equb (anim_B_sub_chase      div &100)
  equb (anim_B_sub_mummy      div &100)
  equb (anim_B_sub_monk       div &100)
  equb (anim_B_sub_fires      div &100)

[...]

.T_ANIM_C_SUBS_LOW
  equb (draw_room_7         and &ff)
  equb (selfmod3_special_1  and &ff)
  equb (selfmod3_special_2  and &ff)
  equb (anim_c_sub_1a       and &ff)
  equb (anim_c_sub_1        and &ff)
  equb (anim_c_sub_1        and &ff)
  equb (anim_c_sub_1        and &ff)
  equb (draw_room_7         and &ff)
.T_ANIM_C_SUBS_HIGH
  equb (draw_room_7         div &100)
  equb (selfmod3_special_1  div &100)
  equb (selfmod3_special_2  div &100)
  equb (anim_c_sub_1a       div &100)
  equb (anim_c_sub_1        div &100)
  equb (anim_c_sub_1        div &100)
  equb (anim_c_sub_1        div &100)
  equb (draw_room_7         div &100)
The subroutines could do with some naming improvements.

Note that the subroutine used to animate the fires has bit 2 set, but they don't chase the player, so it's not quite true to call bit 2 the "chase bit".

These tables only have 8 entries each, so if bit 3 is set then that's theoretically a bug -- it will overflow the table and very quickly crash the CPU. However, if it only applies to wall tiles, they're not animated, so this situation wouldn't actually come up.

These unused bits (3 and 4) are intriguing, and I wonder if there are any clues as to what they were for in Citadel-early.
streaks wrote:
Thu Nov 01, 2018 8:02 am
Only the platform tile has byte[1] bit 4 set? I thought you meant those two-colour platforms and I thought it accounted for that mysterious splash effect. Moving platforms? Maybe it's to make it respond to levers..? Or like... maybe it means, since they respond to levers, fewer things can be taken for granted in terms of static/mobile logic and certain hard-to-define shortcuts can't be applied to it..? Or maybe like.. it means use the regular movement logic bits to define the movement, but this bit indicates that there's more involved than just HOW it moves (also WHEN it moves)... I dunno.
The lever logic is hardcoded in the final version, for example in the West Wing:

Code: Select all

                    cpy #C_RID_WEST_WING_SWITCH_MONK ; &80
                    bne L2d27
                    lda #&4
                    ; bring lift online? why does it need two anim slots?
                    ; if (t_anims_y_velocities[0] != 0) {
                    ;   t_anims_y_velocities[0] = 0;
                    ;   t_anims_y_velocities[1] = 0;
                    ; } else {
                    ;   t_anims_y_velocities[0] = 4;
                    ;   t_anims_y_velocities[1] = 4;
                    ; }
                    ldx t_anims_y_velocities
                    beq L2d21
                    lda #&0
.L2d21              sta t_anims_y_velocities
                    sta t_anims_y_velocities + 1 ;&6c
                    bpl L2d44
So the lever just sets the y-velocity for a pair of tile slots to 4, or to 0, depending on whether it's being stopped or started, but there's no general mechanism to do it; it's coded specifically for the rooms where it's used. That's not to say that there wasn't a more general mechanism for lifts earlier in development; it may be that MJ realised that it would use less RAM to special-case lift code for the rooms where it was used rather than having a general case encoded in the tile data. So it might be an artifact of that.
The mystery crystal tile... I suspect that it was a prototype tile used while developing and tweaking the tile logic, and wasn't even nessecarily intended to be a crystal. It could just be that the five crystals (that don't actually look like crystals) adopted the shape of that test sprite because the shape was pleasing or had aquired sentiment. I've done things like that many times. Since it's deadly and garbled I suggest it was just a dev guinea pig tile that was kept as a reference or testing-ground for bitplay.
As 6502 pointed out, tiles 1-5 fetch their graphical data from tile 0, so it's the other way round; tile 5 can't actually exist without tile 0's data.
streaks wrote:
Thu Nov 01, 2018 8:06 am
Speaking of that splash effect... have you tried rendering that other mystery sprite that you thought was probably a discarded splash effect, but with different width? A new, more obvious shape/pattern might emerge like with the crystal..?
IIRC I was wrong about that and the discarded splash actually turned out to be something tangible, possibly the water surface tile, but I don't have my notes on this computer so I can't check. I forget.
streaks wrote:
Thu Nov 01, 2018 8:26 am
I'm looking at that hacked Citadel image with the screen browsing.. looking at the platform move I wonder I've noticed another characteristic that MAY be unique to it - when they're moving down and touch the floor their movement terminates at an irregular Y offset instead of when it's level with it's Y-cell offset. I don't know if the tile's small height is already accounted for in movement logics though.
It probably just uses the normal collision detection mechanism to decide when to reverse. I haven't checked this though.
Last edited by Diminished on Thu Nov 01, 2018 3:59 pm, edited 3 times in total.
User avatar
streaks
Posts: 275
Joined: Thu Oct 13, 2005 3:08 pm
Contact:

Re: Unused Citadel bits

Post by streaks »

Has anyone ever tried to track down Jakobsen?
streaksy (at) gmail (dot) com
User avatar
Diminished
Posts: 598
Joined: Fri Dec 08, 2017 9:47 pm
Contact:

Re: Unused Citadel bits

Post by Diminished »

Nope. I figured he'd chime in if he was interested in doing so.

No need to go stalking the guy.
6502
Posts: 41
Joined: Sat Mar 17, 2018 1:04 pm
Location: London
Contact:

Re: Unused Citadel bits

Post by 6502 »

@Diminished

Thank you for correcting my errors. Hope you don't mind me muscling in on your thread.

I've been busy converting the tile data part of the binary file into a beebasm assembly file. This .asm file making viewing and altering the tiles much easier. Thought better to be included as an external file to citadel.asm as it's quite long.

I've checked it outputs the correct binary with a hash function, and it does. I'll post it here when ready, just needs tidying up and commenting. You can add it to your project if you like, but if you don't, that's fine with me too.

Also, found out that if tile date byte[4] is zero then the height of the tile is increased to 32px. Only the monks use this function. Byte[5] then contains info that would of been in byte[4].
Last edited by 6502 on Sat Nov 03, 2018 9:01 am, edited 1 time in total.
6502
Posts: 41
Joined: Sat Mar 17, 2018 1:04 pm
Location: London
Contact:

Re: Unused Citadel bits

Post by 6502 »

streaks wrote:
Fri Nov 02, 2018 3:36 am
Has anyone ever tried to track down Jakobsen?
Personally I would of used a pseudonym name if it was me.
User avatar
Diminished
Posts: 598
Joined: Fri Dec 08, 2017 9:47 pm
Contact:

Re: Unused Citadel bits

Post by Diminished »

6502 wrote:
Sat Nov 03, 2018 8:53 am
Thank you for correcting my errors. Hope you don't mind me muscling in on your thread.
Nope, not a problem. Information is free, and more eyeballs are welcome. I don't claim any right to the game. But there are certain insights that you'll only get from the asm. (Equally, there are likely to be some things I've got wrong which can be tested by fiddling with the data).
6502
Posts: 41
Joined: Sat Mar 17, 2018 1:04 pm
Location: London
Contact:

Re: Unused Citadel bits

Post by 6502 »

davidb wrote:
Sat Dec 09, 2017 1:13 pm
The second item certainly looks like a gold bar. :)
In the early version of Citadel, once you took a cyan block to Stonehenge and walked under the arch, your energy increased and the cyan block turned into this gold one. Not sure what you was suppose to do with it after that.
User avatar
Diminished
Posts: 598
Joined: Fri Dec 08, 2017 9:47 pm
Contact:

Re: Unused Citadel bits

Post by Diminished »

6502 wrote:
Tue Nov 06, 2018 1:16 pm
davidb wrote:
Sat Dec 09, 2017 1:13 pm
The second item certainly looks like a gold bar. :)
In the early version of Citadel, once you took a cyan block to Stonehenge and walked under the arch, your energy increased and the cyan block turned into this gold one. Not sure what you was suppose to do with it after that.
Aha. Nice find.

I had a very quick look through Citadel-early to see if there was any clue about what the gold bar might have been for -- I didn't look too deeply into it, but quick searches don't reveal anything being done with tile 31 (&1F). So it doesn't look like MJ had any grand plan for those bars.

Here's the code (only in citadel-early) which performs the blue/gold bar swap:

Code: Select all

    2ECD: C9 65       CMP #65
    2ECF: D0 13       BNE 2EE4
    2ED1: A5 24       LDA 24
    2ED3: C9 32       CMP #32
    2ED5: D0 0C       BNE 2EE3
    2ED7: A9 1E       LDA #1E <- stone bar
    2ED9: A2 1F       LDX #1F <- gold bar
    2EDB: 20 34 40    JSR 4034 <- item consumption subroutine
    2EDE: 90 03       BCC 2EE3
    2EE0: 4C 0F 30    JMP 300F
    2EE3: 60          RTS
In the retail version it looks like this:

Code: Select all

                    ; CONSTANT: 0x65 is Stonehenge
.Lnot_witch         cmp #C_RID_STONEHENGE ; &65
                    bne Lnot_stonehenge
                    lda player_x
                    cmp #C_X_STONEHENGE ; &32
                    bne L2edb ; return
                    lda #C_TID_STONE_SLAB ;&1e
                    jsr consume_item_a
                    bcc L2edb ; return
                    ; CONSTANT: stone slabs are worth +40 energy? NOTE BCD
                    lda #C_E_STONEHENGE ; &40
                    jmp add_remove_energy_d
.L2edb              rts
Last edited by Diminished on Sun Nov 11, 2018 5:20 pm, edited 1 time in total.
6502
Posts: 41
Joined: Sat Mar 17, 2018 1:04 pm
Location: London
Contact:

Re: Unused Citadel bits

Post by 6502 »

Any clues in Citadel-early what the barrel was supposed to be for?
User avatar
Diminished
Posts: 598
Joined: Fri Dec 08, 2017 9:47 pm
Contact:

Re: Unused Citadel bits

Post by Diminished »

I always thought the barrel was intended for jumping onto the roof of the Witch's House. Trampolines may have been added later on (tile ID &3a for the trampos but &18 for the barrel); so I suspect this was the originally intended solution and the trampolines were added to the game later.
User avatar
Kecske Bak
Posts: 720
Joined: Wed Jul 13, 2005 8:03 am
Location: Treddle's Wharf, Chigley
Contact:

Re: Unused Citadel bits

Post by Kecske Bak »

I believe the barrel was originally intended for getting the crown in the cellar.
avengahM
Posts: 8
Joined: Mon May 28, 2018 5:07 am
Contact:

Re: Unused Citadel bits

Post by avengahM »

Wow, I just found a second Crown in Citadel-early!

The Witch's House in this version has a green crown instead of a yellow one. But there's actually a yellow one in screen (5,3)! Access it by putting a trampoline at the top right of the East Tower, on the very end of the wall. Then use that trampoline to jump to the right as high as possible. I used Escape to slow my fall down a couple of times but that may not be necessary.

So that means there are two Crowns in this version of the game, giving a possible total of 102 points if the game didn't automatically end at 99 (crowns are worth 3 points in this version).

There's also an annoying glitch whereby some items don't respawn when you start a new game. Crystals, the chicken, Egyptian heads, the skull and bones are amongst the items that don't respawn, this being after I completed the game with 99 points on the playthrough before I found the extra crown.
Last edited by avengahM on Wed Jun 12, 2019 8:45 pm, edited 2 times in total.
User avatar
Diminished
Posts: 598
Joined: Fri Dec 08, 2017 9:47 pm
Contact:

Re: Unused Citadel bits

Post by Diminished »

Cool find.

I sort of want to have a trawl through Citadel-early and identify what bits of code are different; there might be some interesting artifacts in there and I'm guessing the rendering code is probably identical since you'd have to have that working long before you could start putting a game together, but I'm probably too lazy to do it. That, and I don't really want to deal with the WFDIS disassembler again.
6502
Posts: 41
Joined: Sat Mar 17, 2018 1:04 pm
Location: London
Contact:

Re: Unused Citadel bits

Post by 6502 »

avengahM wrote:
Wed Jun 12, 2019 8:36 pm
But there's actually a yellow one in screen (5,3)! Access it by putting a trampoline at the top right of the East Tower, on the very end of the wall. Then use that trampoline to jump to the right as high as possible.
How on earth did you manage to find that little gem?
I can't imagine any scenario I would happen to be jumping that direction on a trampoline.
User avatar
Diminished
Posts: 598
Joined: Fri Dec 08, 2017 9:47 pm
Contact:

Re: Unused Citadel bits

Post by Diminished »

Unfinished business.

I think it's been a couple of years since last I visited my attempt to reimplement the room and tile decoders in a high-level language. At the time I got distracted by slightly more glamorous hacks such as the Randomiser and the Citadel reassembly (for some admittedly very broad definition of "glamorous").

However, I picked this back up a couple of days ago. As I recalled, the tile decoder was working somewhere close to 100%, but the room decoder was still in a bit of a state.

The first thing I wanted to do is get an idea for how many rooms the unpacker could currently handle. It turned out I'd never made a comprehensive list of which room IDs in the game were actually defined, so that was the first job.

I grabbed the screenshot map that's been floating around for a few years, and also dug out my own attract mode patch (the one that allows you to cycle through the rooms during the game's attract mode), and made a new map with the room IDs numbered in hex and decimal.
map3.png
This is probably the most logical way to lay out the rooms in terms of game logic. Going upwards from any room results in the room ID being decremented by 20. Going downwards results in the room ID being incremented by 20. Moving left and right causes the room ID to be decremented or incremented by 1. So, it makes some sense to lay the map out with a width of 20 cells. Meanwhile, you can have very long horizontal runs of rooms just by laying them out above and below one another. You can see this looking at room 8B/139 and 8C/140, which appear on opposite sides of the map, but are automatically connected in-game. Indeed, with this layout, only two connections needed to be special-cased in the game's code (79 <-> C9 and 64 <-> EF):

Code: Select all

; MAP FLOW HACKS
42ab: P_main_roomchange   cpx #$7a
                          ; if (room_id == 0x7a) then room_id = 0xc9;
42ad:                     bne L42b1
42af:                     ldx #$c9
                          ; if (room_id == 0xc8) then room_id = 0x79;
42b1: L42b1               cpx #$c8
42b3:                     bne L42b7
42b5:                     ldx #$79
                          ; if (room_id == 0x63) then room_id = 0xef;
42b7: L42b7               cpx #$63
42b9:                     bne L42bd
42bb:                     ldx #$ef
                          ; if (room_id == 0xf0) then room_id = 0x64;
42bd: L42bd               cpx #$f0
42bf:                     bne L42c3
42c1:                     ldx #$64
This is likely to be how Mike Jakobsen laid the rooms out on his piece of squared paper, so that's kind of interesting.

Next, I modified my PHP so that rather than just having the room ID to be displayed hard-coded, it took it as a command-line parameter. This then allowed me to write a shellscript containing all the defined room IDs. I also took this opportunity to modify the code to output proper PNG files rather than ad-hoc RGBA bitmaps. Now I could get an idea for the script's overall coverage just by running the shellscript. (It didn't do especially well.)

The parts of the room drawing code I currently have reimplemented are as follows:
  • tile flood fill
  • "N3X" decor, round one
  • rectangles
  • triangles
  • "N3X" decor, round two
The tile flood fill was only half implemented. Citadel plots the tile with which to flood the whole screen in the very top-left of the display, and then runs a VRAM/VRAM copy routine to duplicate this tile everywhere. I had implemented the first part of this to draw the tile, but left out the fill routine as I wanted to get on with other things. However, it was proving confusing to work out where issues were occurring in some rooms without the tile fill working, so the next job was to read the ASM for the flood routine and reimplement it. I got this working fairly quickly.

The next problem was that the PLOT 85 triangles were also unimplemented. The PHP to consume the room bytes and decode the triangles existed, but once again I had made no attempt actually to draw anything to the screen. The triangles were likely one of the reasons why I gave up working on this a couple of years ago, since the PLOT 85 code is obviously part of the MOS, and doesn't exist within Citadel itself at all. I really didn't fancy trying to crib parts of OS 1.2 and reimplement them.

PHP's GD extensions, which I was already using for PNG output, do offer a facility for drawing filled polygons. GD will not trivially draw the Model B-only, "out-of-band", ROM-overflow-exploiting triangles sporting fetching vertical stripes. Nevertheless, it seemed like GD's filled polygon code would at least be a good place to start.

There was a problem, though -- my code was rendering everything to a buffer which was laid out as a MODE 2 screen, rather than linearly (with the buffer being converted to a chunky bitmap immediately before export). I could not easily use GD to draw triangles to a MODE 2 buffer. Eventually I decided the most sensible course of action would be to ditch the MODE 2 back-end representation and just rework everything to use a linear RGBA buffer. All simulated 6502 VRAM operations would now have to go through a translation layer, and each MODE 2 bytewise read or write would have to address the appropriate pair of RGBA pixels instead. I made these modifications and they more or less worked first try, so now I could get the triangle code working.

The existing triangle code was a miasma of misapprehensions. One weirdness here is that vertices 1 and 2 are poked directly to MOS workspace, but vertex 3 is sent as a high level PLOT 85. This effectively means that the first two vertices use MOS internal 160-by-176 graphics coordinates, but the final vertex uses external 1280-by-1024 ones. (It didn't help that AllMem actually has this partially wrong). Another thing I had missed was that the game's setup code redefines the MOS graphics origin to (0, -32). Fortunately I was able to find this setup operation in a nicely readable form in my own BASIC loader for the Citadel reassembly, so I tracked this problem down without too much head-scratching. With the new GD triangle code in place, a small minority of rooms (e.g. Main Hall) now displayed triangles correctly, but many others still resembled abstract expressionist disasters.

A few modifications to beebjit later, I discovered that the triangle code was actually fine, but it was being wrong-footed by the fact that the prior rectangle decoder contained a bug which was leaving the room data pointer in the wrong place. This was caused by the rectangle loop having two ways of jumping back to the top. One 6502 code path decrements the "rectangles remaining" variable before jumping back to the top of the loop, but the other code path does not decrement the counter before jumping. My code was just using a for loop with the decrement operation in the for statement itself, and a continue to simulate the earlier of the two jumps back to the top, incorrectly decrementing the counter in the process. (That is what I get for prematurely replacing ASM-style do/while constructs.) Anyway, for now I just hacked this up by incrementing the counter before the continue statement, fixing both the rectangles and triangles in one go.

The rectangle routine currently uses simulated 6502 code translated stupidly from the disassembly. At some point I will strip this out and instead do rectangle drawing using GD, which will hopefully eliminate more hard-to-understand 6502 soup from the equation.

Lots of rooms are still being displayed wrongly, but this seems to be a bug in the "N3X" function which draws decor tiles, so that will be the next thing to track down. The rope/pillar/ladder code is still absent, so that will follow afterwards. After that, there are stars, item pads, items on those pads, flasks ...

As a curio, here is the Pyramid's lowest chamber, showing its subtractive triangles. I'm using a debug mode which only displays triangle outlines. (The ladder code obviously doesn't exist yet).
sarco.png
User avatar
davidb
Posts: 2949
Joined: Sun Nov 11, 2007 10:11 pm
Contact:

Re: Unused Citadel bits

Post by davidb »

Thanks for writing up your latest progress! I like decoding old map formats, so this is all very interesting stuff.

Now we know what the layout looks like, we can imagine where all those passages down the well could lead to. :)

And, to me, it looks like access to the title screen was an intentional Easter egg, too.
User avatar
Diminished
Posts: 598
Joined: Fri Dec 08, 2017 9:47 pm
Contact:

Re: Unused Citadel bits

Post by Diminished »

davidb wrote:
Fri Oct 09, 2020 3:29 pm
Now we know what the layout looks like, we can imagine where all those passages down the well could lead to. :)
I would dearly have loved to have found an unreachable room somewhere. Of course, it would already have been found by hackers decades ago. One slightly disappointing aspect of old Beeb games compared to those of their ROM-based console cousins is that Beeb RAM was so precious there was a much lower chance of unused assets making an appearance. I don't know precisely how much RAM this game has left over (which is a rather loosely-defined quantity anyway), but it is very, very little. The engine isn't at Elite or Exile levels of cunning, but it is viciously optimised by its own standards. I'm certain MJ spent months refining his routines for compactness, just so he could reclaim every last vestige of RAM to express the game world itself.
And, to me, it looks like access to the title screen was an intentional Easter egg, too.
I think so. The superfluous trampoline placed close by has been noted before. The logical positioning of the room itself is telling when you can clearly see all the other empty places he might have put it.

By the way, walking off the right side of the title screen puts you into the undefined room 209. You then fall through rooms 229 and 249, and a theoretical room 269; 8-bit wraparound turns 269 into (269 - 256) = 13, which is indeed exactly the room in which you reappear at the top of the map.

So there's no special case or anything there; being able to land on the battlements and skip the bucket puzzle just looks like serendipity.
User avatar
Diminished
Posts: 598
Joined: Fri Dec 08, 2017 9:47 pm
Contact:

Re: Unused Citadel bits

Post by Diminished »

That bug didn't last long. It wasn't a tile problem, it was another rectangle problem.

There is a check in the asm to make sure rectangular fills don't underflow video RAM and start merrily scribbling code. My code duplicates this check, but I was setting one of the rectangle loop variables wrongly as a side-effect. So rectangles that touch the top of the screen were being drawn much smaller than they should have been.

Here's the Star Port dish construction.
dish_construction.png
The green triangle here is a subtractive one that's used to destroy the dish after the statue is recovered from the alien planet.

Coverage is looking pretty good now! Maybe >80% of rooms are perfect (disregarding the parts that still lack code). Still a few strange problems in places, though.
User avatar
Diminished
Posts: 598
Joined: Fri Dec 08, 2017 9:47 pm
Contact:

Re: Unused Citadel bits

Post by Diminished »

Collision dumping is now properly implemented (I think).

Ever wonder why the moose head in the Temple only becomes aggressive after you walk past the centre of the room?
citadel-temple.gif
citadel-temple.gif (130.38 KiB) Viewed 1069 times
I assumed it was done with special code, but dumping the collision for this room reveals this invisible, impermeable rail:
temple-rail.png
temple-rail.png (1.2 KiB) Viewed 1069 times
User avatar
0xC0DE
Posts: 830
Joined: Tue Mar 19, 2019 7:52 pm
Location: The Netherlands
Contact:

Re: Unused Citadel bits

Post by 0xC0DE »

Just wanted to say that it's very interesting to read all of this about one of my favourite games =D>
0xC0DE
"I program my home computer / Beam myself into the future"
:arrow: Follow me on Twitter
:arrow: Visit my YouTube channel featuring my games and demos for Acorn Electron and BBC Micro
User avatar
Rich Talbot-Watkins
Posts: 1707
Joined: Thu Jan 13, 2005 5:20 pm
Location: Palma, Mallorca
Contact:

Re: Unused Citadel bits

Post by Rich Talbot-Watkins »

+1

Always happy when this thread resurfaces! Citadel has always been a standout game on the Beeb, and it's fascinating to learn some of its inner secrets.
User avatar
Dave Footitt
Posts: 935
Joined: Thu Jun 22, 2006 10:31 am
Location: Abandoned Uranium Workings
Contact:

Re: Unused Citadel bits

Post by Dave Footitt »

Yeah I love reading about this - Citadel was a fantastic game and it's really interesting to see some of the internals!

Keep up the good work =D>
User avatar
scarybeasts
Posts: 608
Joined: Tue Feb 06, 2018 7:44 am
Contact:

Re: Unused Citadel bits

Post by scarybeasts »

Love me some Citadel!
I think it's one of the few games I properly completed. I still remember the emotions from when I first accidentally blundered into one of the hidden crown rooms.

Very interesting to see how it works behind the scenes -- some of the level layout and renderer is quite unlike other platform games.

When beebjit hits v1.0 (timing model stable for all significant test cases), I'll be looking for a Citadel expert to record a replayable speedrun to see how fast a competent speed run takes when replayed at full emulator turbo speed :D


Cheers
Chris
User avatar
Diminished
Posts: 598
Joined: Fri Dec 08, 2017 9:47 pm
Contact:

Re: Unused Citadel bits

Post by Diminished »

Thanks, gents.

I have a few more notes -- nothing earth-shatteringly interesting but I'll write them down or I'll forget them.


MODE 2 AND COLLISIONS
MODE 2, as you know, maps one byte to a pixel pair, interleaving the bits. Each byte written to the screen in Citadel looks like this:

Code: Select all

&80 &40 &20 &10  &8  &4  &2  &1
 c1  c0  bL  bR  gL  gR  rL  rR
b, g and r are blue, green and red. L and R refer to "left pixel" and "right pixel". All fairly predictable. Rather than messing around endlessly shifting and masking to divorce the left pixel from the right one, MJ tended to take the approach of simply pre-defining a pool of two-pixel, single-byte building blocks from which everything was constructed (I believe I've referred to these as "base pairs" in some parts of the disassembly). So if you wanted to draw an object in black and white, you'd build it by choosing from four bytes: B/B, B/W, W/B and W/W. I imagine this wasn't an uncommon way of doing things.

With palettes selected so that the effects of bits 6 and 7 are invisible on-screen, those two digits c0 and c1 are employed to encode two bits of collision detection. Effectively this means that the collision detection operates at half the horizontal resolution of the graphics, since the high bits of both the left pixel and the right pixel are borrowed for this purpose.

The unpacker's collision dumper currently encodes c0 as red and c1 as green, yielding:

Code: Select all

 00  black   no collision
 01  red     climbable
 10  green   painful [*]
 11  yellow  impermeable
Green -- the pain collision type -- is weird. There may be a bug in what I have done, but it seems that all painful objects are striped, rather than solid "green".

Room 138:
138.png
138.png (2.23 KiB) Viewed 776 times
Collision:
138C.png
138C.png (1.09 KiB) Viewed 776 times
I am not sure why it is done that way -- I will need to revisit the collision detection routines to see exactly how the hit detection works.

One curiosity with this, though, is the Witch's House roof, which is (assuming no bugs) solidly "green".

House:
104.png
104.png (1.54 KiB) Viewed 776 times
Collision:
104C.png
104C.png (925 Bytes) Viewed 776 times
Solid green therefore seems to work similarly to yellow, in that you can stand on it. But if you've ever wondered why catching the edge of this roof a glancing blow causes you to lose energy, well, the above may be why:

(Note 3 energy loss)
witch-house-roof-dmg.gif
witch-house-roof-dmg.gif (29.06 KiB) Viewed 776 times
Bug? Feature? To be fair, jumping off a trampoline into the edge of a roof won't do you much good.


PYRAMID
PLOT 85 triangles may be drawn with alternative logical plot modes. The only room which seems to use anything other than the overwrite mode is the main Pyramid, which XORs the triangle in order that the door at the bottom (which is for some reason drawn first) remains visible.


ROM WRITES
Citadel gleefully scribbles the ROM area. I added a switch which extends the screen from 176 pixels high to 192, so you can see what's in the overwrite. It's not very interesting, but it seems it was a way of compacting some of the tile routines a little bit by omitting some boundary checking:
104_rom_write.png
104_rom_write.png (1.66 KiB) Viewed 776 times

PROGRESS
Now added:
- item pads
- ladders
- ropes
- stars (working, but not being displayed in some rooms yet for some reason)
User avatar
Diminished
Posts: 598
Joined: Fri Dec 08, 2017 9:47 pm
Contact:

Re: Unused Citadel bits

Post by Diminished »

scarybeasts wrote:
Thu Oct 15, 2020 8:45 am
When beebjit hits v1.0 (timing model stable for all significant test cases), I'll be looking for a Citadel expert to record a replayable speedrun to see how fast a competent speed run takes when replayed at full emulator turbo speed :D
I might be able to do this. I actually have some background in speed running, although I'm keeping quiet about the details...

A few notes on this:

I know that at normal speed the game can be done in a little under an hour. Basic strategies include exploiting pressing ESCAPE to backtrack quickly to room entry points, although you have to keep an eye on your energy budget. A question I'm not 100% sure on is what the fastest route is from the Main Hall out to the Wasteland (a trip that needs to be made a fair amount in completing the game). You can either go along the ground floor, or along the first floor, and timewise there's not much in it.

The observant may have noticed when playing this game that the initial position of enemies and lifts is to some degree randomised -- sometimes you have to wait for lifts and enemies to move into their needed positions before you can proceed, which can cost you seconds here and there. So, at the margin, there's also some scope there for what speed runners refer to as "RNG manipulation".
User avatar
Snuggsy187
Posts: 173
Joined: Wed Apr 03, 2019 9:53 pm
Contact:

Re: Unused Citadel bits

Post by Snuggsy187 »

Bug? Feature? To be fair, jumping off a trampoline into the edge of a roof won't do you much good.
Always wondered about that damage from the edge of the roof ! :lol:

Thanks for the description on the sprite storage - took me ages to vaguely understand this some years ago, and had since forgotten all about it !

Top work, glad you picked this up again, it's an excellent read. =D>
PUSH PARCHMENT > POKE LOCK > PULL PARCHMENT
j6wbs
Posts: 14
Joined: Tue Feb 02, 2016 8:11 am
Contact:

Re: Unused Citadel bits

Post by j6wbs »

Thank you so much for a fascinating thread.
I loved Citadel, these details you have uncovered are wonderful to know after all these years

I’ve dug out my old Citadel maps, which I painstakingly drew out ‘back then’ and popped them onto Flickr, as someone reading this thread might enjoy them too. https://www.flickr.com/gp/jez/7e04S2

Thanks again for your time delving into Citadel, maybe it’s time to play it through again on my trusty Beeb, feeling inspired.


It would be great to extract the sounds as well as the sprites. The sound design was simple but very distinctive.

Interesting side note on Citadel, when I play this on the MiSTer FPGA, when going between each room the whole screen flashes disturbingly, in the same colour of the room title text, as if it is changing mode or something and the LCD/HDMI does not mask this, but when I play the MiSTer through a CRT this does not happen. Do you know what exactly is happening between each screen transition?

Cheers,
Jez
User avatar
Diminished
Posts: 598
Joined: Fri Dec 08, 2017 9:47 pm
Contact:

Re: Unused Citadel bits

Post by Diminished »

j6wbs wrote:
Fri Oct 16, 2020 2:12 am
I’ve dug out my old Citadel maps, which I painstakingly drew out ‘back then’ and popped them onto Flickr, as someone reading this thread might enjoy them too. https://www.flickr.com/gp/jez/7e04S2
These are lovely. Fountain pen! Who still uses those?!

I had similar ones (albeit with less conscientious cartography) but they haven't survived unfortunately. I think mine ended up scrawled across multiple sheets.
Interesting side note on Citadel, when I play this on the MiSTer FPGA, when going between each room the whole screen flashes disturbingly, in the same colour of the room title text, as if it is changing mode or something and the LCD/HDMI does not mask this, but when I play the MiSTer through a CRT this does not happen. Do you know what exactly is happening between each screen transition?
This is interesting.

From memory, it does something like reprogram the CRTC to limit the visible screen area to the first few lines (the ones that contain the header text and inventory sprites) while it invisibly redraws the room. Then it switches it back to full screen afterwards. I'm not sure why this might cause different behaviour on an LCD compared to a CRT -- any theories, anyone?

Citadel is rebuildable now, so you can actually disable this behaviour and leave the CRTC configuration untouched during room redraw. Or you could probably change it to switch the screen off entirely rather than leaving the text and inventory lines visible.

I can probably produce some sort of modified version if it's a problem.
User avatar
0xC0DE
Posts: 830
Joined: Tue Mar 19, 2019 7:52 pm
Location: The Netherlands
Contact:

Re: Unused Citadel bits

Post by 0xC0DE »

Side note on the Electron version. I think it switches to MODE 6 with colour palette off between rooms to speed up drawing. MODE 2 is horribly slow on the Elk due to memory contention. It would be cool to investigate other differences between Elk and Beeb versions
0xC0DE
"I program my home computer / Beam myself into the future"
:arrow: Follow me on Twitter
:arrow: Visit my YouTube channel featuring my games and demos for Acorn Electron and BBC Micro
Post Reply

Return to “8-bit acorn software: classic games”