Jump to content
Jet Set Willy & Manic Miner Community

IRF

Contributor
  • Posts

    5,112
  • Joined

  • Last visited

Everything posted by IRF

  1. I'm not sure whether SkoolKid's response above applies only to all the cavern elements that are actually present when you play Manic Miner, or whether he also analysed all the unused cavern elements in the game. i.e. where Matthew Smith defined graphics for a block type but didn't actually place any instances of those blocks within a particular cavern. (There are plenty of examples of unused block graphics in a cavern which replicate identical block graphics from other caverns - e.g. the 'poisonous pansy' static nasties from 'Central Cavern' are also defined for 'Abandoned Uranium Workings' but are unused in that cavern - and even one example of a cell graphic which Matthew created but which doesn't appear anywhere in the game - the Crumbly graphic in 'Skylab Landing Bay'.) So it's possible that the Block Graphics Bug could manifest itself if you modified the layout of Manic Miner (without changing the game engine)? An analogy (which I discovered and reported earlier in this thread) would be the static nasties in JSW's The Nightmare Room: they have a defined graphic but none are present in the original game; however if you insert one into that room then the graphic gets corrupted when you playtest it, because of the influence of the BGB.
  2. You previously mentioned the trade-off between size versus speed when optimising code. The above quote highlights a third element to throw into the balance - flexibility (relocatability).
  3. Isn't it ADD A, L (to facilitate the multiple use of the subroutine, which is also used for decompressing the tune data)?
  4. I've got so used to thinking in hexadecimal that I thought at first you were colouring in the piano keys with yellow INK with that command! :lol:
  5. https://www.youtube.com/watch?v=B7yqu5VPQX4
  6. A most cunning rewrite, Norman! Especially the shared subroutine for decompressing the data and determining which piano key gets highlighted! I presume that this element (the bit in bold): is there to take into account the possibility that the 'time shift' and 'note shift' look-up tables might be in a position which straddles two pages of memory? That's a very useful technique; thanks for drawing my attention to it. Incidentally, I believe that the following would achieve the same thing (in the same number of bytes): ADD A, L LD L, A JR NC, grab_data INC H grab_data: LD A, (HL) ****** One subtle visual difference that your alternative code might produce - the pair of 'almost matching' notes at the start of the tune holds pitch values #80 and #81. With the original code, playing that pair of 'almost matching' notes only illuminates a single piano key (in cyan). With your version, I believe (without having tried it out yet) that two adjacent keys will be illuminated (one in red, one cyan). This is because the two notes end up on opposite sides of an 'octal boundary'. (Each piano key corresponds to an 'octet' of pitch values. i.e. for every increase in the pitch value of 8, we proceed from highlighting one piano key to the next). That discrepancy could be resolved by tweaking the data (so that the corresponding pitch values are #7F and #80, and a similar consideration could be given for other values that are close to an 'octal boundary'). I don't believe that the perceived difference in pitch would be audible. ** On the other hand, your code has the effect of fixing a little-known 'bug'* in the original game engine - namely that if you try to play a note of extremely high pitch (holding a value between #01 and #07), then the leftmost piano key gets highlighted, whereas you would expect the far right-hand piano key to be the one that is illuminated for such a high-pitched note. (*It's a 'theoretical bug', because of course no note of that pitch manifests itself in the title tune data.) The fix which I came up with for that is to replace the SUB A, #08 at #932B with a DEC A; I think your code will have the same effect in terms of determining when the transition from one highlighted key to another occurs. (Your previous comment about "design of the keyboard [looking] like it was constructed from several broken ones" is also relevant here!)
  7. So you're saying that you compressed the data, as well as optimising the Z80 code?
  8. It did strike me that there's still some repetition of code in my rewrite - the use of D and then E as pitch delay counters for the two notes could possibly utilise a shared subroutine, if the registers were swapped about carefully? Oh, I presume that there's a comma missing in the last post: "My final edit for the overall Manic Miner Music routine is around 57 bytes smaller than the Music routine from post #0" should read "My final edit for the overall Manic Miner Music routine is around 57 bytes, smaller than the Music routine from post #0" - unless you've managed to compress the routine down to 14 bytes in length! :o
  9. This doesn't relate to code optimisation, but it's an observation about a bug/glitch/peculiarity in the original Manic Miner. When the title screen tune is playing, there is a pause towards the end (enacted by having a pair of 'zero notes', at #8541 and #8542). You might expect that none of the piano keys are highlighted at that point, since no notes are being played, but in fact the left-most key of the piano is highlighted (in cyan). I know that the positioning of the coloured keys isn't actually representative of the notes that would be played on a real piano, but the above seems particularly incongruous.
  10. I thought I might create a similar 'optimisation' thread to the JSW one. I implemented a lot of code optimisations of the MM game engine in the recent release 'Manic Mixup'. However, this one slipped through the next (I've only just thought of it): It involves a rewrite of the routine at #92DC which plays the theme tune (Blue Danube). I think this saves around 12 bytes. EDIT: It actually saves eight bytes. (I forgot to count the CALL to test the Enter key, and the RET back to the Title Screen routine if Enter is pressed.) start: LD A, (IY+$00) INC A RET Z LD BC, #5028 CALL update_piano_keys LD B, #00 LD C, (IY+$00) LD H, D LD L, E tune_loop: OUT (#FE), A DEC D JR NZ, not_time_for_note_1 LD D, H XOR #18 not_time_for_note_1: DEC E JR NZ, not_time_for_note_2 LD E, L XOR #18 not_time_for_note_2: DJNZ tune_loop DEC C JR NZ, tune_loop LD BC, #3838 CALL update_piano_keys CALL #9337 Check whether ENTER or the fire button is being pressed RET NZ LD DE,#0003 ADD IY, DE JR start update_piano_keys: LD A, (IY+$01) LD D, A CALL #932B LD (HL), B LD A, (IY+$02) LD E, A CALL #932B LD (HL), C RET
  11. "JR NC,keyloop1" should read "JR C,keyloop1"? This entry: "IJKL ", should be "LKJH ", (with the Space character at the end, before the symbol shift entry)?
  12. Nice one Norman. :) That's a logical extension of what I did. Incidentally, in the experimental project I referred to, L is used to point at the previously-unused Offsets #EE-#EF in the definition for the chosen room (H), wherein a suitable starting location is stored (Willy's initial x- and y- coordinates, and initial frame of animation and facing direction, are all compressed into two bytes). The LD A, (HL) command is used to pick up the data. But that wouldn't preclude me from using L instead of E to count down the inner loop, in the way that you suggest.
  13. I've recently been working on an experimental project where a keypress is detected, and used to determine the starting room of the game (there are forty rooms in the game, and forty Spectrum keys). A partial disassembly is included below. I could adopt it to a similar method to Norman Sword's, by reversing the conditionality of the test of the Carry Flag from a JR NC to a JR C instruction. However, that would also require the insertion of a CPL command - I don't think it could be done without requiring that additional byte? Also, this method necessitates the use of the BC register-pair to read the ports via IN A, (C) - the Accumulator A is too 'busy' to use the IN A, (#FE) here, I believe. start_again: LD BC, #FEFE BC starts off pointing at the half-row of keys SHIFT-V (Bit 0 of B is reset) LD DE, #0805 D counts the eight half-rows; E counts the five keys in each half-row LD H, #C0 H keeps track of the room number keypress_loop_1: IN A, (C) If a key in the half-row currently being interrogated is depressed, then one of bits 0-4 of A will be reset keypress_loop_2: INC H RRCA A is rotated rightwards by the inner loop; JR NC, room_selected if a reset bit moves past Bit 0 then the Carry Flag is reset, indicating that a room has been chosen DEC E JR NZ, keypress_loop_2 LD E, #05 RLC B B is rotated leftwards by the outer loop, so that Bits 0-7 are reset in turn; this allows each half-row in turn to be interrogated by the inner loop DEC D JR NZ, keypress_loop_1 JR start_again None of the forty keys were pressed, so go back to the start to check again room_selected: If we reach here then a keypress has been detected, and the H register is now pointing at the corresponding page of memory (#C1 to #E8) where the chosen room's definition is stored. (N.B. Room 00 is not selected, corresponding to page #C0 of memory; that is a 'Cheat' screen.)
  14. Optimised code to check for any keypress: loop: XOR A AF IN A, (#FE) DB FE OR #E0 F6 E0 INC A 3C JR Z, loop 28 F8 Optimised code to check for no keypresses (i.e. to ensure that the player has let go of all keys before proceeding - this is useful to stop 'accidental selections' if a key is pressed for too long): loop: XOR A AF IN A, (#FE) DB FE OR #E0 F6 E0 INC A 3C JR NZ, loop 20 F8
  15. IRF

    Opening Walls in JSW64

    Fair enough. :) Although, after having come up with the code tweak that causes the alternative opening mechanism, I think I actually prefer it that way - it seems more 'natural' that the wall blocks turn to Air one at a time, and it facilitates interesting challenges such as the one which Willy encounters in the 'fixed'* test file attached to the first post in this thread. I wonder if there is a spare bit in the Opening Wall Guardian definition bytes, which could be used as a flag to determine which mechanism is used when a wall opens up? Either on an individual 'wall instance' basis, or else on a 'per room' basis (with the code change to switch between the two mechanisms implemented via a 'Room Setup' Patch). (*In hindsight, 'Fixed' and 'Unfixed' are inaccurate descriptions, in light of John's confirmation that the existing behaviour is as he intended. 'Changed ' and 'Unchanged' would be better; or 'Series' and 'Parallel' - the blocks turn to Air either in series or in parallel.)
  16. IRF

    Suggested new MM feature

    Are you referring to the 'forcefields'? Variations on them can be created using standard guardians that have fixed boundaries, with 'slow' animation settings, and most of the animation frames left blank. The non-blank animation frame appears once in every 16 time frames, so Willy has to carefully time his pass through the gap where the forcefield appears.
  17. IRF

    Opening Walls in JSW64

    It works differently in MM's Kong rooms - there are two blocks which open up in parallel, the upper block opens 'upwards' (the bottom pixel-row clears first, then the next one up, etc) whilst the lower block opens 'downwards' (from the top pixel-row downwards). Because both blocks become cleared of all pixels at the same time, they turn to Air at the same time. In JSW64 you can have a wall of arbitrary height (in terms of the number of Earth blocks), which opens from the top pixel-row downwards. Your code clears each pixel-row in turn, and then once the entire height of the wall is cleared of pixels, the attributes of each component block of the wall turn from Earth to Air. But the latter part of the code appears to allow for the possibility of turning each wall block to Air in turn, as each block's pixels become cleared. Indeed, reversing the conditionality of a single relative jump achieves this outcome, as I discovered. The Manic Miner code doesn't really give a precedent from which we can draw a conclusion - at no point is there a 'completely cleared' wall block that is left retaining its 'INKless Earth' status, pending the clearance of the pixels of a separate block of the wall. **** Incidentally, I have recently discovered a previously-undocumented bug in Matthew Smith's MM code: if you insert a blank pixel-row (00 graphic byte) midway down the Earth cell bitmap, then the opening wall turns to Air prematurely, leaving a 'ghost' of some remaining uncleared pixels - which the nearby horizontal guardian (whose range is edited once the wall has fully opened so that it passes through the gap created) promptly crashes into!
  18. Over on the World of Spectrum forum, 'Pgyuri' has just reported having completed Jet Set Mini! I've replied to some of his comments (as best I can given that there's a bit of a 'language barrier' :lol: ) https://www.worldofspectrum.org/forums/discussion/54931/a-jet-set-willy-double-bill
  19. Thanks Norman. I would just add that the T-state overheads are higher for setting up a greater number of parameters prior to the loop, in the case of LDIR. But of course that is outweighed by the faster loop (Unless the loop is very short e.g. The LDIR method at #8684-90 in Manic Miner wouldn't be much faster overall).
  20. At #8828-34 and #88B8-C4, the LDIR method of editing the attributes of a character row can be replaced with a simple loop which uses the LD (HL), xx command. The latter approach consumes fewer bytes, employs fewer registers and is probably marginally faster. EDIT: I removed that latter point, in light of Norman Sword's comments below. e.g. the original code at #8828-34 requires 13 bytes: LD HL, #5A60 LD DE, #5A61 LD BC, #001F LD (HL), #46 LDIR But the same thing could be achieved in 10 bytes: LD HL, #5A60 LD B, #20 Loop: LD (HL), #46 INC HL DJNZ Loop **** The LDIR method for copying the same value across multiple addresses is only necessary when updating #100 bytes or more, which is beyond what a single register can keep track of (e.g. see #8813-27). When updating fewer than #100 (256) bytes, LDIR is only necessary if different values are being copied across to the individual addresses (e.g. #88FC-#8906).
  21. The excerpt of the code that Andy (Spider) attached missed the end of the loop off. The loop is executed numerous times during each pass through the Main Loop, in order to draw the whole solar beam. See entry 36264 of the additional screenshot attached here - this is why it's '4 decrements per cell occupied by Willy', as discussed last night.
  22. IRF

    Opening Walls in JSW64

    Of course the escape route doesn't work in the 'unfixed' version, because Willy can't safely drop down one cell row at a time.
  23. IRF

    Opening Walls in JSW64

    Well done Danny on completing it the 'official' way, and well done Andy on spotting the 'loophole'! I've updated the files to prevent the latter, 'unofficial' solution (with a judiciously placed additional file cell), and reuploaded to the first post in this topic.
  24. Air supply is normally decremented once per time-frame (i.e. once per pass through the Main Loop). If the solar beams passes through Willy, it is usually decremented nine times per time-frame (the usual once, plus 4x2= eight extra), because Willy usually straddles two cell-rows. But if Willy happens to be jumping at the time that he passes through the solar beam*, then at certain points during the jump when he isn't cell aligned, he is straddling three cell-rows (i.e. character rows) on the screen. In those instances the air supply is decremented 13 times per time-frame (1+4x3). (*Unless the part of the solar beam through which he is passing is horizontal at the time - Willy never occupies more than two cell-columns.)
  25. Yes, four additional decrements of the air supply per cell which is occupied by Willy's colour attribute.
×
×
  • Create New...

Important Information

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