Jump to content
Jet Set Willy & Manic Miner Community

The Invisible Man


jetsetdanny

Recommended Posts

 

The Invisible Man is JSW hacked by Lee Prince in 2002 so that that you play as an invisible sprite and guardians cannot therefore collide with you (but precision jumps are very difficult). It was an entry in the comp.sys.sinclair Crap Games Competition 2002.

The game has a custom BASIC loader and loading screen, and a modified title screen and scrolling message. The rooms are unmodified.

The game is impossible to complete due to the same bugs which make the original JSW incompletable. The official Software Projects POKEs take care of that, so it's not a problem.

I would like to record an RZX walkthrough of the game and make a video of it to be placed on the JSW Central YouTube channel. I've started the recording and got as far as "The Beach". However, I've come across a problem I don't seem to be able to solve satisfactorily.

Apparently - that's a general remark, concerning all games - Willy has to have some pixels in order to be able to land on a rope. If all frames of Willy's sprite are pixelless - as is the case in The Invisible Man - Willy cannot get hold of a rope, he goes right through it. Hence, rooms where Willy has to use the rope are impossible to complete/pass through.

I've had a look at SkoolKid's disassembly and as far as I can tell, the check in the code to see if Willy has landed on the rope is at #92C6 - #92D5:

image.png

I *think* that the problem must be that the code checks if a given segment of the rope is touching anything else that's been drawn so far, e.g. Willy, but since Willy hasn't been "drawn" (because he has no pixels), the check is negative and so the signal that Willy is on the rope is not set as it should. Please correct me if this explanation is inaccurate.

Now the question is: would anyone be able to suggest how to modify the original code so that Willy, while remaining invisible, would be able to get hold of the ropes as usual?

 

 

 

Link to comment
Share on other sites

Because this would always be attributed to the original person. I have no incentive to add code to what (as far as I can see) is a simple deletion of the willy definition.

So in the words used on Dragons den "I'm out"

-------------------------------
path that could be taken - just not by me

1) To collide with the rope, Willy needs a definition. The deletion of Willies definition, means that path is out.

2) If the definition is intact

modify the code that draws willy - instead of actually putting the pixels to the screen- instead save the draw definition and the draw position, and return

in the rope draw routine - add a routine to use Willies draw definition and Willies draw position to xor Willy to the screen
Draw the rope - using xor - Willy will be flagged as collided in the normal way - movement on rope etc will still occur.
on rope exit add a routine to use Willies definition and Willies draw position to xor Willy off the screen.

The xor routine is a very simple sprite draw routine. Which would need adding,

The above allows Willy to interact with the rope....
The original modification was simply deleting Willies definition. This is adding ten times the effort of the original person to try and fix his hack.

 

Addendum:- 
Just looked at this again - every reference to drawing willy elsewhere .. e.g the dancing Willies/ death screen etc. would need deleting. 
 

Edited by Norman Sword
Link to comment
Share on other sites

Thank you for taking the time to reply, Norman Sword! 👍

My current coding skills unfortunately aren't enough to write the code you've mentioned (simple as it may be).

I did give the issue some more thought, though, and came up with a suggestion for an alternative solution that apparently doesn't work, but I will present it here because I don't understand some of the results of what I've tried to do and would be happy to have some answers.

So I thought of the following solution looking at this part of the Main Loop:

image.png

I thought that after everything that needs to be done with Willy is done (Willy is moved, the items that he is touching are collected), the Screen buffer (room + Willy + entities + items) at #6000 gets copied to the display file at #89F5. My idea was to,  at this point, draw Willy to the #6000 Screen buffer again - before the buffer is copied to the display file - but this time using an empty sprite of Willy's. At #89F5, I inserted a call to #9700 where I copied the code from #95C8 ("Check and set the attribute bytes for Willy's sprite in the buffer at 5C00") and the code from #9637 ("Draw Willy to the screen buffer at 6000"), but (at #9772 and #977B in case of "The Nigthmare Room") pointing to an empty sprite instead of Willy's regular sprite. My idea was to erase Willy from the #6000 Screen buffer (by printing him again, but this time using an empty, pixelless sprite) right before the buffer was copied to the display file.

The result is that my additional code prints Willy (or whatever sprite I point the instruction to) once again on top of the already printed Willy. It doesn't erase the already printed Willy, it ads pixels on top of him, so to speak, preserving the filled pixels that are already in place.

Attached below are three experimental files that illustrate it, called TTMWI (trying to make Willy invisible).

In the file "TTMWI (empty)" my additional code at #9700 prints an empty sprite. This results in the game looking normal (as if nothing has changed), because an empty (pixelless) sprite is printed on top of the regular Willy, so all you see is the regular Willy.

In the file "TTMWI (bird)" my additional code prints the bird sprite from #BD00. What you see is a mixture of the regular Willy and the (backwards walking) bird, or, in "The Nightmare Room", of the flying pig and the bird (the latter is quite cool, actually).

In the file "TTMWI (inverted)" my additional code prints a sprite from #9F00 where I placed an inverted set of Willy's sprites. The result is a solid white block, which demonstrates clearly that the code prints the original Willy's sprite and, on top of it (without erasing it though) an additional sprite selected by my additional code.

What I don't understand is why the original Willy's sprite doesn't get erased - why its filled pixels stay in place instead of being wiped out by the empty pixels of the second sprite that is printed by my additional code.

An answer to this enigma would be appreciated, as well as an opinion on whether this approach to making Willy invisible could work and, if so, what should be changed in my code to make it work 🙂 .

TTMWI (inverted).tap TTMWI (bird).tap TTMWI (empty).tap

Link to comment
Share on other sites

because the sprite print routine adds pixels - it never erases pixels - similar to 1+4=5 or 1+3+2=6. The result never gets less  no matter how many positive numbers you add.Although technically the print routine gives the result as (1 or 4 =5) and (1 or 3 or 2=3)

NOTE - the routine I mentioned uses XOR - and any number xor'd with itself is always 0. So how difficult is the xor version of the sprite print routine.

Original hacked to xor - call once to draw and once to erase.

sprite_xor
ld b,#10
loop_xor:
ld a,(de)
xor (hl)
ld (hl),a
inc L
inc de
ld a,(de)
xor (hl)
ld (hl),a
dec L
inc de
Inc h
ld a,h
and #07
jr nz,legal_val
ld a,h
sub 8
ld h,a
ld a,L
add a,#20
ld L,a
legal_val:
djnz loop_xor
ret

 

Edited by Norman Sword
pet hate lower case "l" in code.. changing to "L"
Link to comment
Share on other sites

Just checked the code - was aware it seemed different from what I normally do - e.g. was part modifying someone elses code. I can see the layout does not adjust for the screen 1/3rds correctly. so here, is how I do it as opposed to modifying someone else's code --- Too much time doing this.

sprite_xor
ld b,#10
loop_xor:
ld a,(de)
xor (hl)
ld (hl),a
inc L
inc de
ld a,(de)
xor (hl)
ld (hl),a
dec L
inc de
    inc    h
    ld    a,h
    and    7
    jr    nz,legal_val
    ld    a,L
    add    a,#20
    ld    L,a
    jr    c,legal_val
    ld    a,h
    sub    8
    ld    h,a

legal_val:
djnz loop_xor
ret

 

Addendum:- just to show what I said works ---

1) no idea what version of jsw I have used - so no idea how many of the original bugs are present
2) deliberately not the same as the file you want to edit.
3) comes equiped with spray paint - Pause to show where willy is

4) due to the pause addition.... Can play by pressing pause to see where willy is and movement keys .eg hold "gh" and play as normal. Willy is treated as still invisible in the game code.

 Addendum 2:- with a ghostbuster's radar - we track the invisible man.

And that concludes my effort.

 

INVISIBLE.tap

INVISIBLE_Tracking.tap

Edited by Norman Sword
responding to theft of typed letters. I'll catch you one day Mr keyboard
Link to comment
Share on other sites

And to take all the work out of modification... The data needed is in my "INVISIBLE TAP" file

This is the minimum change needed  to interact with willy - NOTE this omits the other changes I added 

 

; to get this data look at these addresses in "INVISIBLE.TAP"-


; modification at start of rope draw - draw Willy to screen
at #92a4
    call    willy_draw_on (3 BYTES)
    nop                            (1 BYTE)
old
     LD IY,ytable             (4 BYTES)          


; with xor ??? if willy is present then no change here - leave to indicate looked at and aware of check
at #92c9
    and    (hl)
old    (no change - read comment)
        AND (HL)              


; the rope pixel changes from {or} to {xor}
at #9311
    xor    (hl)    (1 BYTE)
old
     OR (HL)   (1 BYTE)        


; the final rope mode modification - get rid of Willy
at #935e
    call    willy_draw_off (3 BYTES)
old
    LD A,(rope_status)    (3 BYTES)   

; Original Willy draw - now just saves data positions
at    #9660
    jp save_willy    (3 BYTES)      
old --- note 3 bytes which is the first instruction plus 1 byte from the next
    LD B,#10               (2 BYTES)
        LD A,(willy_att)  (3 BYTES- ONLY FIRST BYTE NEEDS TO BE CHANGED)   
 
; the code that is being called - 

    org #9f00

screen_pos    dw    0 
screen_def    dw    0


save_willy:
    ld    a,(willy_att)
    and    #1f
    or    (ix+0)        ; the x position
    ld    L,a
    ld    h,(ix+1)
    ld    (screen_pos),HL
    ld    (screen_def),de
    ret

willy_pause:
    ld    hl,(screen_pos)
; shift from #60 to #40
    res    5,h
    call    willy_xor1
    LD      DE,#0000         
    ret

willy_draw_on:
    call    willy_xor
    LD     IY,ytable
    ret

willy_draw_off
    call    willy_xor
    LD     A,(rope_status)     
    ret


willy_xor:
    ld    hl,(screen_pos)
willy_xor1:
    ld    de,(screen_def)
draw_xor:
    ld    b,#10
loop_xor:
    ld    a,(de)
    xor    (hl)
    ld    (hl),a
    inc    de
    inc    L
    ld    a,(de)
    xor    (hl)
    ld    (hl),a
    inc    de
    dec    L
    inc    h
    ld    a,h
    and    7
    jr    nz,legal_val
    ld    a,L
    add    a,#20
    ld    L,a
    jr    c,legal_val
    ld    a,h
    sub    8
    ld    h,a
legal_val:
    djnz    loop_xor
    ret
 

--------------------- PLUS
Stop dancing willy routine - delete call
remove Willy on plinth in death routine - delete call

-------------------------------

A lot of effort for something I am not doing --- 


 

 

Edited by Norman Sword
Link to comment
Share on other sites

Thank you so much, Norman Sword! 👍

I would definitely like to record a variant of JSW with an invisible Willy. However, I'm not sure how to proceed now. Lee Prince's "The Invisible Man" is incompletable. You have provided the code that allows to achieve the idea that Lee came up with. With this, I'm tempted to try to fix Lee's version with your code and make it available to anyone who might be interested as "The Invisible Man" - Bugfixed Version, with all due credit given to you in the accompanying Readme file, on this variant's page on JSW Central, in the JSW Central YouTube video description and in any announcements I would make about it.

Would you be OK with this solution?

 

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.