Jump to content
Jet Set Willy & Manic Miner Community

IRF

Contributor
  • Posts

    5,105
  • Joined

  • Last visited

Everything posted by IRF

  1. I think I have an answer to the conundrum posed by this speculative comment in the 'Through the Wall' entry of the Bugs section of the Manic Miner disassembly: Perhaps the assumption in this code is that if there is a nasty tile below Willy's sprite in step 16, then he will be killed by the nasty before reaching step 17; however, in this particular case Willy's x-coordinate decreases by one during step 16 (as he transitions from animation frame 0 to frame 3), which moves him out of the nasty's range. I think the reason why a positive response to the check for Fire cells under Willy, causes the jumps to #8BDD [in MM] or #8ED4 [in JSW] to be bypassed, is to stop Willy from bouncing sideways off Fire cells as he crosses a cell boundary. If this wasn't the case - i.e. if the relative jumps at #8B29 and #8B3D (in Manic Miner) or #8E4D and #8E54 (in JSW) weren't present in the code - then Willy would be able to perform the quirky manoeuvres seen in the attached rzx recordings! (which are based on modified files with the above bytes NOPped out). (Note that in the Manic Miner recording, Willy actually jumps briefly off the top of the screen!) MM Fire Bounce.rzx JSW Fire Bounce 1.rzx JSW Fire Bounce 2.rzx
  2. Further to my earlier post, I now can report that I have safely inserted a Guardian of Class 127 into a test file! Everything is working fine, including the Item Drawing and Item Collection loops (which no longer call up the value of #A3FF). However, JSWED doesn't display the first 25 items in the Item Table for some reason* - although they are present and collectable in the game. This occurred in a game with 256 items, so it may not affect games to the same extent where there are fewer items present. In any case, I recommend that you only make the enabling code changes to insert a Guardian Class 127, after you've got to the point where you're happy with the item distribution in a game. (Although subsequent changes to item distribution can of course be made via the hex editor.) * EDIT: I've just realised that it's happening because the last byte of the Guardian Class 127's definition just so happens to be #19 (25 in decimal) - JSWED is still picking up the value of #A3FF in order to display the items! As I said, it doesn't affect the game itself, but to prevent this glitch in JSWED, you could simply ensure that one of your Arrow Guardian Classes occupies slot 127 (#A3F8-A3FF), since the eighth byte of an Arrow's definition is unused. So you could insert the value [256 minus the number of items in the game] at #A3FF, just for the purpose of viewing all the items in JSWED, and it wouldn't affect the Arrows at all. (The eighth byte of an Arrow's definition is normally 0 by default anyway, which suits a game with 256 items, but it doesn't have to be.) Actually, that would negate the need to make the changes to the code at #8802 and #93D3 (although those changes can in themselves provide useful byte-efficiencies at pinch-points in the code). UPDATE: It is far safer to have an Arrow occupy Class 127, as otherwise if you alter the number of items in JSWED, the editor changes the value of the eighth byte of Class 127's definition - the maximum extent of the range of a horizontal/vertical guardian or rope - which could cause the guardian to collide with room elements! Arrows are absolutely fine as Class 127 though! So if you shift one of your existing arrow definitions to #A3F8-A3FF (quite easy to do as half of the bytes are 00), then you'll free up a slot that's easily editable in JSWED for your new guardian class! And then you can safely make changes to the number of items in JSWED; the redundant eighth byte of the Class 127 Arrow definition will be updated, with no impact whatsoever on the function of the Arrow!
  3. Oh, and one more point, returning to Danny's original enquiry: since only #A3FA is overwritten during the course of the game (for the reason described above), the other five unused guardian definition bytes (#A3F9 and #A3FB-E) should be perfectly safe to re-use.
  4. Regarding this post: http://jswmm.co.uk/topic/185-free-space-and-code-optimisation-in-jsw/page-1?do=findComment&comment=3701 I think I've got to the bottom of it! Contrary to the impression you might have got from my previous post, the third byte of each Entity Definition in the #A000-A3FF range is overwritten during the course of the game! (Whilst the third bytes of each entity definition are initialised to zero, and listed as such in the disassembly, you may find that the values are non-zero in snapshot files.) However, this doesn't normally matter, as the values of those bytes are 'instance-specific', and so are regularly updated using the second byte of the appropriate entry in the Entity Specification for each room, each time a guardian is inserted into a room. Now, whenever the routine at #8912 comes across a 'Terminator' byte in a room's Guardian List data, it treats it as a 'Class 127 [#7F]' guardian (because Bit 7 of the first byte of the entity specification is reset at #892E), and so the subsequent value (i.e. the 'Guardian Specification' byte immediately following the 'FF 'Terminator', which would usually be 00 by default - but Danny, if in your WNM-SE file you had 'recycled' some of the spare bytes in unfilled rooms' Guardian List data, for other purposes, then it could be anything and could vary as Willy moves from room to room!) is copied into the address #A3FA (which is the third byte of Guardian Class 127's eight Definition Bytes!) - mystery solved! The way to prevent this would be to tweak the routine at #8912. Immediately after the 'Pick up the first byte of the entity specification' LD L, (IX+$00), remove the RES 7, L and replace it with a check 'Is it #FF?': EX AF, AF'; LD A, L; CP $FF. [if not, skip the next three bytes.] If so, copy 'FF' to the address that is currently pointed at by the 'DE' register pair (i.e. the first byte of the Entity Buffer entry that is currently under consideration) and then jump forward to #894A, bypassing the loops which populate the rest of the entity buffer: JR NZ $03; LD (DE), A; JR $1B; EX AF, AF'. [The purpose of the two bookending EX AF, AF' commands is to retain, in A', the value of the A register which is counting down, from a starting value of 8, the number of entities being considered. Once the loop is exited early by the presence of an 'FF' Terminator byte, the value of A' no longer needs to be retained.] If the guardian specification byte under consideration isn't an 'FF' Terminator, then the existing code is resumed at #8930 (after passing through the second EX AF, AF' command to restore the 'entity counter' to A). N.B. the operand of the relative jump at #8948 would need to be changed accordingly, to ensure that it still loops back to #892B. [in Z80 code: remove 'CB BD' from #892E; insert '08 7D FE FF 20 03 12 18 1B 08'; replace '20 E1' previously at #8948 with '20 D9'.] The above would probably require some consolidation, although a relative jump could be squeezed into the space currently occupied by the RES 7, L command, which might help if the other few bytes could be located within 128 bytes of the source address. In which case, the operands of the new relative jumps above would need to be altered, and a new jump back to #8930 inserted at the end. Alternatively, the nearby efficiencies that we have already identified should just about be enough to allow the additional 8 bytes of code to be inserted in situ i.e. by setting the border colour more efficiently at #8980; swapping the absolute jump at #8988 for a relative jump; removing the 'DI' command at #8898; and swapping the absolute jumps at #8892 and #88AE for relative jumps. [With the above in place, when a 'Terminator' byte is encountered by the program whilst it is filling the entity buffer, the rest of the buffer may retain the data from the previous room, rather than being filled with '00's. However, that won't matter because the 'Move the guardians' and 'Draw the guardians' routines will in any case skip all subsequent addresses in the entity buffer as soon as they encounter a 'FF' value. EDIT: Although a Rope might pick up un-erased values in the second and fourth bytes of the next guardian in the list, potentially triggering the Rope-Teleport Bug, so you should ensure that John Elliott's Adjacent Ropes Patch (New) is in place - but then, I would strongly recommend that you have that in place in any game file in any case!] In theory, the suggested changes to the code would allow Guardian Class 127 to be safely defined, provided that #A3FF's use as an 'Item Index' is reallocated to another address*. It would be entered into a room's guardian list as Class #7F, and (with the RES 7, L command expunged) it would be treated differently to an 'FF' Terminator byte. (* Or the LD A, ($A3FF) commands at #8802 and #93D3 could be replaced with LD A, $00 [the operand being the previous value of #A3FF] - saving two bytes - or in a game with 256 items, simply replaced with XOR A instructions - saving four bytes.) {One other caveat: you would have to make sure that all the 'even' Entity Specification Bytes in every room were within the range 00-7F [apart from the FF Terminator, of course]; otherwise, higher values (with Bit 7 set) would cause the program to try and interpret data in the range #A400-A7FF [item Table data, Toilet graphic bytes, etc] as guardian definition bytes - which could be 'fun'!! There's no reason why that would happen, though, unless you deliberately - manually in the hex editor - enter a Guardian Class 128-254 into a room's Guardian List!}
  5. Don't worry, I just wondered if you could recall off the top of your head. My theory as to what was going on was probably wrong anyway, as it would have involved #A3FB being overwritten (I think!?) EDIT: Actually, I'm not even sure about that now! I was thinking in terms of a rope's data 'overspilling' its eight bytes, but that should only really affect the bytes just after the 'Entity Buffer' at #8100, not the Entity Definitions that are copied into the buffer upon entry to each room. FURTHER THOUGHT: Andrew Broad reported the 'Entity Specification' area of the Room Buffer being affected if Guardian Class 127 was defined (filling rooms that didn't already have 8 guardians with either Class 0 or Class 127 guardians), but again that involves corruption of areas of buffer code, not the 'source data' at #A0xx.
  6. I reckon the third page from the bottom (the one that starts with The Bathroom) is what Willy looks like if you ever see him head on (which we never do!)
  7. Actually, I think that the table is looked up on the 33rd pass through the rope-drawing loop, but the program doesn't actually implement anything with those values, other than 'behind the scenes' updating of a couple of variables, which aren't then used for anything (because immediately afterwards the relative jump at #9356 is triggered, before another pixel is drawn), and the two variables are re-initialised when the rope is redrawn in the next time-frame anyway. So it's probably safe enough to describe the bytes at #8356-83D6 as 'spare bytes'! EDIT: Playing Devil's Advocate, I think the worst that might happen, if the spare bytes were reused for other purposes, is that: If a high value (such as #FF) were to occupy #8356, then the DJNZ loop at #933D / #934E might take a while to bring the B register back down to zero, and that might cause a brief (~1 millisecond?) delay in the game, at the point when the rope reaches its point of maximum deviation from the vertical? Meanwhile, if an odd value were to be inserted at #83D6, then this could, theoretically, cause a similar effect to the Arrow that triggers the Attic Bug, with the 'Draw the Rope' routine overshooting the 'Screen Buffer Address Lookup Table', causing an address beyond the Screen Buffer to be overwritten. However, this would only have an impact on the game if the routine subsequently attempted to insert the Rope Segment Graphic Byte at such a misplaced address. And that won't happen, again because the relative jump at #9353 is triggered straight away, before the routine gets a chance to draw any more Rope segments! [Caveat: if a modified game had a Rope longer than 32 segments, without the maximum swing being reduced accordingly, then the above is something to be mindful of!!]
  8. More suggestions:- 'Display the Title Screen and play the theme tune' http://skoolkid.github.io/jetsetwilly/asm/87CA.html I think it's worth highlighting, in the adjacent sidebar, the role of the AND 01 command at #8872 - it selects which of each pair of Triangle UDGs to draw, depending on whether the current value of the attribute file address being considered is odd or even. Thus, two adjacent attribute bytes of the same value will select graphic bytes starting at #8431 and #8439 respectively, or else #8441 and #8449. Also, the jump at #8864 is quite cunning, as it ensures that all four Triangle UDGs can be drawn in 'Cyan Ink on Green Paper' attributes: - attribute bytes set to 'Green Ink on Cyan Paper' bypass the instruction at #886A, before their attributes are swapped round at #886E-8870; - in contrast, when 'Cyan Ink on Green Paper' attribute bytes are considered, the instruction at #886A is executed but #886E-8870 is bypassed. 'The game has just loaded' http://skoolkid.github.io/jetsetwilly/asm/8400.html The entry at #840C to 8414 - it would be helpful if it said "Set HL=8500 in a roundabout way, in preparation for the [redundant] instructions at #8415 to #841E". i.e. you have already highlighted the redundant nature of the latter chunk of code, but not the former.
  9. The way the rope-drawing loop works is that it draws a segment (initially the 0th segment), then increments the coordinates of the segment (using the table at #8300) in preparation for the next segment being drawn during the next pass through the rope-drawing loop. And at the end of the loop, the check "Have we drawn every segment of the rope yet?" is made before the Segment Counter is incremented. Therefore 33 segments (pixels) are drawn in total, for each value of the Rope Animation Frame Index, although the Rope Animation Table is only looked up 32 times in the process.
  10. Yes, I've thought about it, and in terms of how the algorithm works that points to the correct place in the table, you're right. My initial reading of your explanatory introduction was that the entries at #8355 and #83D5 were unused - but that is because I was thinking of the entries at #8300 and #8380 as being the first entries in their respective half of the table, whereas they are in fact the zeroeth entries. I think the wording in brackets gave rise to my confusion: "(one for each segment of rope)". Perhaps it could be amended to clarify the matter? Something along the lines of "(one for each segment of rope, apart from the 0th segment which is drawn at the top of the screen in the cell-column determined by the second byte* of the entity specification, and which does not have any 'offset' applied to its coordinates)" [* By which I mean Byte 1 of the entity specification for the room in which the rope is being drawn, given that the first byte which specifies that this is a rope is Byte 0!]
  11. Okay, perhaps it should read "From F+1 to F+32", as the table isn't used to calculate an offset when L=0.
  12. 32 offsets during each animation frame. #8300/8380 are used. #8356/83D6 are not. Think of it like this: there are 32 'lengths' of rope, and 33 points separating them (32 dots on the screen). The first 'length' spans between Point 0 (top of screen) and Point 1. The 32nd and final 'length' spans between Point 32 and 33.
  13. Segment 0 is drawn at the top of the screen, in the cell-column determined by the second byte of the Rope specification for the screen. Segment L has horizontal and vertical offsets applied according to F+L. F ranges from 0 to 54. L ranges from 1 to 32. So F+L ranges from 1 to 86. And there are 86 usable entries in each half of the table!
  14. One more thing on the above - Stuart Brady deserves the credit in the Changelog for spotting the phenomenon in the first paragraph, not me. Although I do get the credit for the point in the second paragraph, so if you decide it's worthy of mention in the disassembly, then 'Very Corrupted Conveyor' could have a joint credit! Oh, and one more point of trivia: with the bytes all in the right place, the Cell Graphics Bug doesn't kick in in the first place in The Nightmare Room, because the correct attribute byte for the conveyor doesn't match any of the screen's preceding graphics bytes!
  15. No, they are used. Segment Zero doesn't have an offset applied to it - it is at the top of the screen, in the same horizontal position regardless of the value of the Rope Animation Frame. Bytes #8300 and #8380 are picked up to determine where to draw Segment 1 when the Rope Animation Frame is at 0. It was initially my understanding that the last of the non-zero bytes in each half of the table were unused - until I realised that the Segment Counter increments to 32, not 31!
  16. JSW disassembly Rope animation table #8300: "For a given rope animation frame F (0<=F<=54), the 32 entries from F to F+31 inclusive (one for each segment of rope) in each half of the table are used; thus the batch of entries used 'slides' up and down the table as F increases and decreases." That should read "from F to F+32" - the first segment of the rope is Segment 0, so there are 33 in total, not 32.
  17. In Move Willy (1) of the JSW disassembly, at #8E39 the check determined by an AND #0E command is described as "Does Willy's sprite occupy six cells at the moment?" Now, when Willy is on a ramp (not cell-aligned), you would think that yes, his sprite does occupy six cells. But the check still gives a negative response, and the program proceeds through to #8E3D instead of jumping to #8E62. This is, of course, because what we see is Willy's sprite drawn at his true y-coordinate, whereas the check at #8E39 is looking at his pixel y-coordinate stored at #85CF (which isn't adjusted to account for his precise position on a ramp). Therefore I believe that the wording accompanying the command at #8E39 needs to be re-worded (although I'm not sure exactly what words should be used to clarify the matter!) Possibly the references in the subsequent entries to cells "below Willy's sprite" might need tweaking too (if he's on a ramp, the cells being pointed at may partially contain his legs!)
  18. Out of interest John, how did the 'Old' adjacent ropes patch work? (Or not, as the case may be!?)
  19. I look at the arrangement of characters in those lists of rooms and I see sprites! Page 2 is a sailboat! :blink: :lol:
  20. Willy enters the 'toilet dash' as soon as he reaches the foot of the bed, regardless of whether he walks or jumps to reach that point. His getting stuck on the bed is caused by the bed's Conveyor action 'cancelling out' Willy's automatic urge to run rightwards (there's an XOR command involved). The fact that the 'P' key doesn't release him from this predicament is probably a 'bug' (although Danny might disagree!). I guess the pillow is a Fire cell because there were no other cell types available when Matt Smith designed the room!
  21. April Showers and The Belfry are rooms 61 and 62 in TNE (I can't recall which one is which off the top of my head).
  22. Thanks John. It looks like my guess was spot on! I presume the lower 'unused Bits' of Guardian Definition Byte 0 are used for defining higher values of the Guardian Type? (i.e. beyond the standard horizontal/vertical/rope/arrow.)
  23. I'd be interested to know exactly how the adjacent ropes patch does work. Here's my best guess, without studying the relevant code: As I understand it, one of the 'regular' 8 bytes for the rope definition is unused in the original game, which is rather inefficient - perhaps you used that (Byte 6) for the 'Index of the segment of rope being drawn' (which populates Byte 9 in the original game)? Then the only other thing that would need to be shifted, to prevent an 'overspill' into the next guardian's definition data, is a single Bit of Byte 11, which in original JSW is used as an indicator of whether Willy is on the rope (as in this particular rope - otherwise the Airborne Status Indicator, which tells you whether Willy is on a rope, could do the job!) Perhaps you reassigned this function to one of the unused Bits of Byte 0 of the rope definition?
  24. If you walk along the top of The Hall in the Bug Fixed Edition you should hear the 'collect' noise when you get to the right place. :)
×
×
  • Create New...

Important Information

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