Jump to content
Jet Set Willy & Manic Miner Community

IRF

Contributor
  • Posts

    5,105
  • Joined

  • Last visited

Everything posted by IRF

  1. Obviously there was a typo there (in my previous post; now corrected). Although the notes do sound as though they are suffering!
  2. In the post linked to below (and the files attached to that post), I experimented with the Manic Miner theme tune. The 'pulse wave difference' which Norman refers to is caused by Mathew selecting pitch values for pairs of notes (the second and third byte in each group of three bytes which define the tune) that differ by a value of 1 (on the original game). Giving a disharmony quality to those notes that differ by 1. In the attached experimental files (see link), I changed those notes so that they differed by a value of 2/4/8/16. The resultant 'magnitude of disharmony'* increases accordingly. (*A good Manic Miner room name, perhaps?) http://jswmm.co.uk/topic/458-free-space-and-code-optimisation-in-manic-miner/page-2?do=findComment&comment=10459
  3. Actually, I've just noticed that the author of the above link is none other than J.G. Harston, occasional visitor to this parish! I wonder if Jonathan will read this, and if so, would he be able to explain the rationale behind the format of the operands which I referred to above?
  4. Further to the above, the Z80 Heaven website which I quoted makes no distinction between the number of T-States for LD HL, (xx) or LD IX, (xx) hl, (XX) 20 ix, (XX) 20 iy, (XX) 20 (XX), hl 20 (XX), rr 20 (XX), ix 20 (XX), iy 20 Clearly the source I quoted is wrong (and Norman's source was right), because the shift byte inevitably slows down the operation (by 4 T-States). The Z80 Heaven site also fails to give a T-State value (correct or otherwise) for LD rr, (XX) operations e.g. LD BC, (XX). Which presumably does take 20 T-States because again there's a shift opcode involved. (EDIT: Another source confirms this: http://z80.info/z80flag.htm ) **** An unrelated query: I've often wondered? why the operand of relative jumps is sometimes given in the format &4546 e.g. at http://www.z80.info/z80oplist.txt you see these examples: 10 DJNZ &4546 18 JR &4546 etc
  5. I forgot to add: the hidden message disappears when you exit from The Nghtmare Room of course, because the status bar's pixels are all wiped clear by the Room Setup routine upon entry to another room. But walk back into the Nightmare Room and the message will re-appear [unless you paused the game in the intervening period], because the status bar's attributes are NOT cleared by the Room Setup routine!
  6. I've just noticed that the two commands in the raster copy routine which you previously struck through: ld b,0 ; this was set for usage in a different routine ld c,32 ; this was set for usage in a different routine are no longer struck out in posts 59 and 60. Although the accompanying comment after the semicolon remains in place, suggesting that those commands are still not necessary (and from my interpretation of the code, they aren't needed). Perhaps the strikethrough font 'fell off' in the process of copying and pasting? **** The LDI subroutine in post 60 gets around the problem in the 'Lose a Life' routine (#8C01), whereby the screen attributes are updated repeatedly on a loop, whilst the A register is used to count down the INK colours (the 'fade to black' moment). :)
  7. Sorry, crossed wires - when you suggested "modify[ing] this routine to use a similar raster copy routine as the one posted above", I thought you were referring to amending the substantive raster routine, rather than self-modifying the subroutine to truncate it with a RET. Hence my reference in my previous post to: "if you are using a shared (and not self-modified) subroutine". ...except before and afterwards, where 'A' is used to self-modify the code (toggling an early RET in and then back out again). But I think that could be done using HL as a pointer instead (if necessary?): LD HL, S_M_C_New_Mod LD (HL), $C9 ; ;opcode for RET and LD HL, S_M_C_New_Mod LD (HL), $EA ;opcode for JP PE,xx
  8. Surely the raster copy code would have to revert back to your earlier method of using the Accumulator to keep track of when it is time to copy a row of attributes. Because if you are using the shared (and not self-modified) subroutine Shift_block32, then that subroutine always RETurns with the same conditionality of the Overflow Flag. e.g. use the same code as in this post, only replacing the two LDIR commands with CALLs to Shift_block32: http://jswmm.co.uk/topic/299-file-jsw-jagged-finger-effect-demo/page-4?do=findComment&comment=6069
  9. As I recall Danny, your preferred route through a standard Jet Set Willy 'mansion layout' (which this game has, broadly speaking, albeit laterally inverted) leads you to complete The Nightmare Room last of all, before making your way to the Master Bedroom for the Toilet Dash. Now, in Jet Set Mini, there is a double-height 'periscope' guardian in 'First Landing', which you can jump over from a high vantage point on the First Landing ramp in order to enter The Nightmare Room. But you can't jump back over the periscope if you exit from The Nightmare Room into First Landing. So that is - apparently - a one-way route, which appears to force you to go from The Nightmare Room via a circuitous route through The Banyan Tree, down the Back Stairway and through the Kitchen screens and the Main Stairway.
  10. The wall in The Nightmare Room appears to be entirely solid. However, upon entry to the room, a Room Setup Patch overwrites part of the wall with a different attribute value to that assigned to the rooms' Earth blocks, creating a pair of 'pseudo-Earth cells'. You can see the same process going on in the adjacent room 'The Banyan Tree', where there is another 'pseudo-Earth cell' (just under the ramp and above/to the left of the Barrel sprite). Note that this 'pseudo-Earth cell' has the same pixel pattern as the regular Earth cells, but a different colour attribute, meaning that Willy can pass through it [in either direction; not just because of the asymmetrical test for head height Earth blocks] - bear in mind that Water cell behaviour is the default status of all non-standard room blocks. However, whilst the pseudo-Earth cell in The Banyan Tree is visibly a different colour to the rest of the Earth cells, that is not the case in The Nightmare Room. Because in that room, there is also a Main Loop Patch which colours the two pseudo-Earth cells (at the level of the secondary attribute buffer) back to the same colour as the regular Earth cells! So there is no visible difference between any of the Earth cells. (The pixel patterns being identical because the pseudo-Earth cells started off as regular Earth cells, and the Room Setup Patch is implemented after the room data has been decompressed and the pixels for the block types have been expanded out.) But these pseudo-Earth cells behave differently, in terms of their ability to block Willy from passing through them [or in this case, their lack of being able to do so - Water cell behaviour being the default status of all non-standard room blocks], because the Main Loop Patch is implemented after the 'Move Willy' routine has been CALLed from the Main Loop. So at the moment when 'Move Willy' is executed, these cells hold a non-Earth attribute value 'behind the scenes', which is then overwritten by the Earth colour attribute prior to the physical screen update (so what you see, apparently, is regular Earth blocks). And then during the start of the next pass through the Main Loop, the cells in question are restored back to their default Water behaviour, when the primary attribute buffer is copied to the secondary attribute buffer (only for those cells to be 'disguised' again, after the next execution of 'Move Willy', by the Main Loop Patch. And so on.) **** All of the above led me to include this credit in the Readme file for 'Jet Set Mini': EDIT: You may also notice that there is another 'disguised' cell in 'The Banyan Tree': the cell underneath the uppermost item is a 'pseudo-Water cell' (it has the same pixel pattern as the regular Water cells, but with a different colour attribute) - but here it unexpectedly behaves as an Earth cell! At the level of the primary attribute buffer, this cell has the same red/yellow colour attributes as the Earth blocks (thanks to a Room Setup Patch), but that is then overwritten by the Main Loop Patch, giving it the cyan colour you see that distinguishes it from the regular, darker blue colour of the Water cells in the Banyan Tree.
  11. Explanation for Point 1 above: The message in 'The Nightmare Room' is printed across the top of the status bar, upon entry to the room. However, by default, the top character row of attributes for the status bar (addresses #5A00-#5A1F) hold the value zero. So the message is printed in black INK on black PAPER, and thus is normally invisible. **** Now, you may recall that in the Kitchen diptych of rooms, a flickering screen effect takes place - as you climb up through that pair of rooms, the screen flickers first in yellow, and then in red (it's hot in the kitchen, and heat rises!) That flickering effect is implemented by overwriting the physical screen attributes (addresses #5800-#59FF) with yellow or red INK during each game tick. (As opposed to the 'standard' screen flash [such as you see in Manic Miner when you gain an extra life], which is implemented by overwriting the secondary attribute buffer (addresses #5C00-#5DFF) before the secondary buffers are copied across to the physical screen.) However, when I wrote the patch for the Kitchen screens, I made sure that the overwriting of the screen attributes 'overshoots' the range of addresses that you would expect - instead of a LDIR length of #0200 (or rather #01FF) for the sixteen character rows of attributes of the playable screen, I used BC = #021F for the length of the LDIR loop, so it covers seventeen character rows. This causes the yellow or red INK also to be spread across addresses #5A00-#5A1F - although this is not noticeable in the Kitchens (because nothing is printed across that character row's pixels in that room). Now, unlike the top two-thirds of the screen attributes during the Kitchen flickering, which are all refreshed during the next tick of the game, the overwriting of the top character row of the status bar's attributes is semi-permanent. Therefore if you climb up through the Kitchen screens, emerge in the Banyan Tree and then proceed into The Nightmare Room, then the previously invisible message in that room becomes visible! (In red INK - although if you climb halfway up the Kitchen screens until the yellow flickering occurs, but then abandon that route and instead make your way back up the Main Stairway to approach The Nightmare Room from the other direction, then you can actually see the message printed in yellow INK!) **** Note that I said the change in colour of the top character row of the status is semi-permanent. If you abandon the game and start another game, then the black INK of that character row will be restored and so the Nightmare Room message reverts to invisible. The same is true if you pause and unpause the game ('in-game', so to speak, using keys A-G), since the Main Loop compensates when you come out of a pause for the colour-cycling which takes place during the pause, by restoring the attributes of the whole of the status bar back to their default values. (See #8B07-#8B11.) So if you try pausing and then resuming the game in The Nightmare Room at a time when the 'hidden' message is initially visible, you'll notice that the message promptly disappears - even if you don't actually pause for long enough for the colour-cycling effect to begin.
  12. Sorry if the above typo caused any confusion! :wacko: BTW, thanks for checking your code in post 49 works okay. :)
  13. I was just thinking in terms of the code which copies the 'master copies' to the 'working copies' [for pixels and for attributes], which would run faster* as you originally wrote it, with the countdown of raster lines embedded within the subroutine containing the chain of LDIs. (*For the reason which I outlined earlier today - despite my initial thoughts last night - that you only have to CALL the subroutine once for the pixels and once for the attributes. Whereas putting the loop counter commands in the Main Loop, as I suggested in post 54 44, means that you have to have execute multiple CALLs and RETs for copying each raster line in turn.) I assume that your 32-LDI subroutine is available as common code for both purposes [master buffers -> working buffers, and then working buffers -> physical screen]? It would seem wasteful to have 32 x LDI / RET in one subroutine, and a separate subroutine which goes 32 x LDI / DEC A / JR NZ / RET.
  14. Thanks for that explanation, Norman! Going back to your version of the LDI method, did you manage to get it to work in conjunction with the Jagged Finger fix (with the rows of attributes being updated alongside the associated pixel-rows)? Because if your subroutine is in the format (as you explained previously): BLOCK_MOVE32: rept 32 LDI endm DEC A JR NZ, BLOCK_MOVE32 RET ...then the DEC A would affect the Overflow Flag, and therefore the JP PE,n_raster in the main routine wouldn't be responding to BC having counted down to zero, but to the decrement of A to zero (and thus the Overflow Flag would always have the same status when the code RETurns back to the main routine). How do you get around that?
  15. On reflection, if I did want to use the same subroutine in the context of overwriting a block of code with a single value (e.g. to implement the Screen Flash effect), then it could be done like this (at the cost of five more bytes): ; 16 character rows to colour, so use A=#0F (15 in decimal) for the later loop. LD HL, xxxx LD DE. xxxx +1 ; No need to define BC; it's not used now LD (HL), colour_value ; Either copied from A, or a fixed value specified here LD A, #01 CALL subroutine_late_entry LD A, #0F loop: CALL subroutine DEC A JR NZ, loop subroutine: LDI subroutine_late_entry: rept 31 ; I presume "rept y" means 'repeat the following code (up to the end marker) y times'? LDI endm ; I presume this means 'end marker'? RET
  16. Thanks Norman! I believe that relies on the fact that the LDI command resets the Overflow Flag if (and only if) the value of BC reaches zero after the operation?
  17. Compare and contrast (for each pass through the Main Loop): Primary to secondary pixel buffer = 128 raster lines Primary to secondary attribute buffer = 16 character rows So my method uses 144 CALLs and RETs. Norman's method only requires 2 CALLs and RETs (for the pixel loop and for the attribute loop). Unconditional CALL = 17 T-States Unconditional RET = 10 T-States So the difference in T-States is 142 x 27 = 3888 T-States (the amount by which Norman's method is faster than mine). [There should be no difference in terms of the copying of the secondary buffers to the physical screen, because the Jagged Finger fix means that the data isn't copied contiguously (in terms of the way that it is stored in memory). So there are separate CALLs to the subroutine for each individual raster line, in both Norman's and my method.] **** However, that 3888 is only a modest difference when you compare it with the overall saving achieved by abandoning LDIR in favour of the 32-consecutive-LDI method. Norman worked out that copying the pixels (4096 bytes) between buffers is faster by 22528 T-States. For the 512 bytes of attributes across 16 character rows of the playable screen, there is an additional saving of 2816 T-States. So the total saving (per Main Loop pass) achieved is 25344 T-States before you account for the time taken to perform CALLs and RETs.
  18. ... And it seems I got completely the wrong end of the stick! The number of T-States for a conditional relative jump loop is based on how many times the relative jump has to be executed (here determined by counting down the value of A, which doesn't change between Norman's method and mine), rather than the distance back through the code that each relative jump spans (the operand of the JR command), as I had previously understood to be the case. :blush: So Norman's code (featuring only one CALL and RET per chunk of code copied) is certainly faster than my version!
  19. On reflection, my variant might not be faster after all - my subroutine is CALLed #10 or #80 times during every pass through each part of the Main Loop that performs a block copy operation. The number of T-States for that many CALL/RET commands (versus just one CALL/RET in Norman's code) may well outweigh the saving in T-States achieved by shortening the length of the relative jump! Further investigation is required...
  20. A query [EDIT: Which I think I've answered myself in subsequent posts!]: In the Main Loop of a recent project, I have this arrangement (repeated four times, for copying pixels twice and attributes twice - primary to secondary buffer and then buffer to physical screen): LD HL, source LD DE, destination ; No need to define BC; it's not used now, so LD BC, xxxx command has been deleted LD A, #80 or LD A, #10 ; For copying the pixels (128 raster lines) or attributes (16 character rows) respectively loop: CALL subroutine DEC A JR NZ, loop ; Once A reaches zero, flow of execution continues through the Main Loop The subroutine which is CALLed consists of 32 consecutive LDI commands, followed by a RET. This was obviously based on one of Norman Sword's suggestions (duly credited in the readme file for the project in question). However, there is a slight difference - Norman's subroutine incorporates the DEC A and JR NZ commands (after the final LDI and before the RET), whereas in my version, those commands are located in the Main Loop. In terms of memory, Norman's version is obviously more efficient (because I have to repeat the DEC A and JR NZ commands four times within the Main Loop, rather than just once in Norman's subroutine). However - and here is my query - would my version be slightly faster? [i don't mean the game as a whole - Norman has done lots of other things to speed up the game - I mean purely in terms of comparing the two variants of the LDI method like-for-like.] My thinking is that the number of T-States which it takes to perform a relative jump is proportional to the distance through the code which has to be jumped - 67 bytes in Norman's case, and only 5 bytes in mine. ? **** N.B. My method may complicate things in cases where a chunk of code is being overwritten with a single value - where the first byte is overwritten directly and then the number of bytes to which the same values is to be copied in a loop is minus one. e.g. for attribute update with a single value (such as for a screen flash effect), use #01FF instead of #0200 to define the size of the loop. Norman's code deals with such cases by CALLing a late entry point into his subroutine, coinciding with the second LDI command in the subroutine. (But the JR NZ at the end of the subroutine jumps back to the first LDI in the subroutine.) In such cases, I think my method would unavoidably end up 'overshooting', and overwriting one more byte than it should. (But in the aforementioned project, I didn't actually use an LDI method for 'block fill' purposes, only for 'block move'.) EDIT: For reference: http://jswmm.co.uk/topic/375-a-total-rewrite-of-jsw-in-48k-using-matthews-core-code/page-4?do=findComment&comment=7745 Note also my comment/query here about a couple of presumed typos: http://jswmm.co.uk/topic/375-a-total-rewrite-of-jsw-in-48k-using-matthews-core-code/page-6?do=findComment&comment=9047
  21. It's okay, I don't mind leaving the clues! By the way Andy, did you try to solve the rest of the puzzle yet (without watching Danny's recording)?
  22. Anyway, I'm glad you both enjoyed the puzzle! There are three things left for me to explain (at a later date): 1 - How the 'hidden' message is implemented (and why it is only visible sometimes); 2 - How the feature which it is alluding to is implemented; 3 - The implications for the most efficient route through the layout (Danny may figure this out for himself!)
  23. Since Andy has now grabbed Danny's recording, I've taken the liberty of removing it from his post. I'd rather it wasn't freely available as it's a bit of a giveaway when the sole focus of the recording is that manoeuvre. (I don't mind the manoeuvre being shown in the context of a complete walkthrough of the whole game to submit to the RZX Archive, where it would be 'buried in the mix'.)
  24. I think you've missed a whole page of 'developments' there, Andy!
  25. Well done on completing the third and final part of the puzzle, Danny! Hopefully Andy will also be able to independently perform this feat before he watches your recording. (Another little clue: .) It's more a case of 'getting you back on track' with your usual preferred route. You're welcome! :)
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.