Jump to content
Jet Set Willy & Manic Miner Community

Free space and code optimisation in "JSW"


jetsetdanny

Recommended Posts

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.

Edited by IRF
Link to comment
Share on other sites

However, I've just had a look in JSWED, in the Game tab, and it looks like both of these boxes (as well as *all* of the other ones *except* for "Black Willy") *cannot* be either ticked or unticked - they are filled with blue, sort of. I'm not quite sure how to interpret this...

 

It means that at least one byte in a location touched by the patch is neither the original one from JSW, nor the modified one from the patch. So JSWED cannot safely apply or deapply the patch.

Link to comment
Share on other sites

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!

Edited by IRF
Link to comment
Share on other sites

A few other tips about inserting Guardian Class 127:

 

- Since JSWED doesn't recognise G127, it has to be created manually using the hex editor, populating the eight bytes #A3F8-A3FF in the Entity Definitions section.  Thus it is most convenient to copy the eight bytes of an existing Arrow definition across to those addresses, and then create the new Guardian Class in the space where the Arrow definition used to sit (e.g. Class 45 in original JSW).  That way you can use JSWED's Graphical User Interface to create the new guardian in the normal way.

 

- Each instance of the newly-defined G127 Arrow has to be manually inserted into the Guardian List for each room where it appears, by altering the first specification byte from '45' [or whatever] to '7F'.  If you leave the second specification byte unchanged, then the y-coordinate of the G127 Arrows will be the same as before (including Invalid values if required).

 

- Arrows usually appear last in a Guardian List, which is another reason to use Class 127 for Arrows - to minimise the need to manually rearrange the other guardians in the list. (i.e. if you created a Vertical G127 Guardian in a room with an Arrow, you would have to place it before the Arrow and manually insert the Arrow afterwards in the hex code, to prevent a potential fatal collision).

 

- Finally, an 'FF' Terminator byte has to be manually added at the end of any Guardian List that has had a G127 inserted (unless the list is filled with the maximum of eight 'entities').  JSWED normally does this automatically to terminate the list, but it won't in this case - possibly because it thinks that '7F' will do the job of terminating the list (which, to be fair, it used to do prior to the application of the code changes set out in Post #20 of this thread).

 

- Additional point: Make sure you have the Adjacent Ropes Patch (New) in place, so that any data left 'lying around' in the Entity Buffer after the FF Terminator byte, can't trigger the Rope-Teleport Bug!

Edited by IRF
Link to comment
Share on other sites

  • 2 weeks later...

I would like to add another suggestion to this open thread, copying it from Ian (IRF)'s PM. This is Ian's "invention", which I would like to quote while at the same time testifying that it works just fine - I have applied it in the (soon-to-be-released) Special Edition of "Willy's New Mansion".

 

So here is Ian's idea:

 

---

More potential spare bytes: In any room where there is no Ramp or Conveyor (or Fire cells, etc) - the eight (contiguous) graphic bytes associated with each such unused room element.

This also applies where there are composite room elements (Ramp-Conveyors, etc), for the eight graphic bytes of whichever component is lower down the list (Conveyors in the example of Ramp-Conveyors). Because the pixel pattern of the earlier room component will be picked up and used to draw the composite cells (e.g. the Ramp graphic in the above example), the space in the code attibuted to the pixel pattern of the latter component (e.g. Conveyor) is unused.

However, in contrast, recycling the unused cell attribute bytes is not safe, since a Z80 command inserted therein might accidentally match an attribute byte of another room element, affecting the properties of such elements.

e.g. if Water cells on a particular, Ramp-less screen have colour attributes set to Blue Ink on Green Paper [00100001 - #21 in hex], and then a '21' (LD HL, $00) command were to be inserted into the attribute byte for Ramps on that screen, then all Water cells would become Water-Ramps!

N.B. It is only safe to use the eight spare graphic bytes if Stuart's Cell Graphics Bug Fix is in place (otherwise the same 'coincidence effect' mentioned above could take place!)

---

 

I would just rephrase the above saying that if the value of the new code does *not* match the cell attribute, it is safe to use the attribute byte as well. And, in fact, the probability of the two values matching is rather low, I believe. So in most cases you can have additional 9 spare bytes for each element if Air, Water, Earth, Fire or Ramp are not used in a room. Furthermore, you can have additional 12 bytes for the conveyor, because  after the 9 bytes analogous to the other cell types (at ... CD - ... D5) there follow immediately four more bytes specific to the coveyor (at ... D6 - ... D9) and the last of them is length. So I believe that as long as the length byte is set to 0, the other additional bytes (specifying the direction of the conveyor and its location in the attribute buffer) can be safely overwritten (if there is no conveyor, it doesn't matter what direction is has).

 

SkoolKid's disassembly illustrates the layout of this potential free space.

 

In one instance in the Special Edition of "Willy's New Mansion" (the room "Internet Cafe", where Fire, Ramp or Conveyor cells are not used) I had a continuous chunk of 30 spare bytes, which is quite a lot! 

 

Many thanks to Ian for his insightful coming up with this helpful idea!  :) 

Link to comment
Share on other sites

Danny, you could go even further with that approach! You could also use the first three of the following four bytes (Offsets #DA-DD - the Ramp definition bytes), as long as the preceding code happened to have a zero at Offset #D9 (corresponding to a Conveyor length of 0).

e.g. Consider the sequence of code that draws or writes attributes to an area of the screen, terminating in a LDIR command. If the length parameter of the LDIR loop is less than 256, and the penultimate* instruction is 'LD BC, $0000' which takes the Z80 format '01 XY 00' [length of loop is represented by C=XY; the higher byte B=00]. Thus if the last byte of that command sits at Offset #D9, then the LDIR command (2 bytes) and a terminating 'C9' Return could occupy Offsets #DA-DC.

Offset #DD would have to be set to 00 though, to ensure that the Ramp length is zero.

(* In some LDIR loops there is also a command such as LD (HL), $00 [Z80 opcode '36'] or LD (HL), A [Z80 opcode '77'] that sets an initial value for e.g. a colour attribute, prior to the loop commencing - but I believe that can be placed before the LD BC command, rather than afterwards, thus facilitating the above suggestion.)

Edited by IRF
Link to comment
Share on other sites

Thanks for the suggestion, Ian.

 

I guess it could also work if Offset #D9 was left as 00 as a break in the code (NOPPed out, so to speak). So, for example, there would be some meaningful code before it, then 00 at #D9 and then e.g. a jump to somewhere else (C3 .. .. ) at #DA - #DC.

 

I doubt I will apply it in "WNM SE" (there's no need for it), but it's something to keep in mind for the future...

Link to comment
Share on other sites

One other thought - if a room doesn't contain any collectable items [e.g. the Master Bedroom in most games tends to avoid having items, unless you want to potentially see Maria suddenly vanish if they are the last to be collected!], then the eight bytes that define the item graphic are spare and can be put to other uses.  That's Offsets #E1 to #E8.

Edited by IRF
Link to comment
Share on other sites

I would just rephrase the above saying that if the value of the new code does *not* match the cell attribute, it is safe to use the attribute byte as well. And, in fact, the probability of the two values matching is rather low, I believe.

 

Just to be on the safe side, you should double-check that any Z80 opcode, or operand, or data byte, that has been placed in a slot that is normally reserved for a room cell's attribute byte, does not match any of the attribute bytes for the other cell types for that particular room.

 

i.e. ensure that there is no match between Offsets #A0, #A9, #B2, #BB, #C4 or #CD [unless such a match has been deliberately implemented in a room, in order to create composite cells such as Water-Ramps etc.]

Edited by IRF
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...

Important Information

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