Jump to content
Jet Set Willy & Manic Miner Community

How Fast Can Willy Play


Norman Sword

Recommended Posts

I have uploaded the Demo version of JSW 128 VL5.tap The slight name change is to JSW VL5 demo.tap. This is up loaded as a revision of JSW128 vl5.tap

This demonstrates a very very very fast version of Jet set willy.

This version also now plays music and not blips for the in game music. The tempo of the music is adjusted as the games speed is changed.. Since the basic music note is played twice, it was not possible to do step-less adjustment, for the faster versions. 

A large amount of extra graphics and routines added. All the graphics are displayed bit by bit in the extra title screens added. (over 21 variations on the title screen- based on the main five )

To see full speed, turn off the music. 

Since the option to upload is here (as well) I will attach the file here.

 

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

One note changed. Typing error.

The tune routine like most things was changed and speeded up. This meant all music data needed to go through a translation table to adjust its speed. The data had a misplaced digit. The note was only played once. 

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

I will attach the last version here (19th January 2019)


JSW VL5 DEMO revision 3b.tap




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

All the main screens. 
 

post-125-0-71770900-1546264125_thumb.png

post-125-0-37207000-1547464740_thumb.png

post-125-0-19523900-1547464756_thumb.png

post-125-0-04305200-1547464778_thumb.png

post-125-0-59175300-1547464797_thumb.png

post-125-0-04437700-1547464861_thumb.png

post-125-0-78511800-1547464887_thumb.png

post-125-0-72049800-1547465367_thumb.png

post-125-0-31173900-1547465379_thumb.png

post-125-0-24202000-1547465391_thumb.png

post-125-0-77189200-1547465405_thumb.png

post-125-0-92648100-1547465437_thumb.png

post-125-0-99571700-1547465452_thumb.png

post-125-0-86138300-1547465467_thumb.png

post-125-0-55187500-1547465485_thumb.png

post-125-0-70943000-1547465499_thumb.png

post-125-0-71257500-1547465513_thumb.png

post-125-0-06502000-1547465524_thumb.png

post-125-0-91599900-1547465534_thumb.png

post-125-0-60067000-1547465555_thumb.png

post-125-0-67196100-1547465567_thumb.png

post-125-0-08519800-1547465580_thumb.png

post-125-0-09088400-1547465593_thumb.png

post-125-0-21407200-1547465606_thumb.png

post-125-0-58019600-1547465617_thumb.png

post-125-0-87586100-1547465631_thumb.png

post-125-0-39599500-1547465642_thumb.png

post-125-0-36299900-1547465651_thumb.png

post-125-0-04379800-1547465660_thumb.png

post-125-0-27320100-1547465669_thumb.png

post-125-0-84907700-1547465678_thumb.png

post-125-0-14593000-1547465690_thumb.png

post-125-0-64772400-1547465703_thumb.png

post-125-0-70133800-1547465713_thumb.png

post-125-0-34365300-1547465723_thumb.png

post-125-0-43932900-1547465742_thumb.png

post-125-0-49792100-1547465753_thumb.png

post-125-0-50343700-1547465763_thumb.png

post-125-0-30210400-1547465778_thumb.png

post-125-0-98795800-1547465790_thumb.png

post-125-0-00588100-1547465804_thumb.png

post-125-0-64902300-1547465814_thumb.png

post-125-0-81169100-1547465829_thumb.png

post-125-0-50014500-1547465842_thumb.png

post-125-0-90222100-1547465854_thumb.png

post-125-0-95673300-1547465865_thumb.png

post-125-0-34706100-1547465881_thumb.png

post-125-0-22215700-1547465892_thumb.png

post-125-0-92617200-1547465904_thumb.png

post-125-0-28891200-1547465920_thumb.png

post-125-0-67215100-1547465938_thumb.png

post-125-0-67113800-1547465952_thumb.png

post-125-0-85452200-1547465969_thumb.png

post-125-0-69879200-1547465981_thumb.png

post-125-0-15748500-1547465993_thumb.png

post-125-0-42489900-1547466003_thumb.png

post-125-0-71758900-1547466014_thumb.png

post-125-0-64878000-1547466026_thumb.png

post-125-0-04265800-1547466041_thumb.png

post-125-0-26934700-1547466051_thumb.png

post-125-0-41114700-1547466063_thumb.png

post-125-0-37637300-1547466077_thumb.png

post-125-0-05971700-1547466090_thumb.png

post-125-0-66779400-1547466102_thumb.png

post-125-0-33901000-1547466116_thumb.png

post-125-0-15609400-1547466129_thumb.png

post-125-0-03392700-1547466143_thumb.png

post-125-0-95347200-1547466155_thumb.png

post-125-0-16152400-1547466168_thumb.png

post-125-0-81591400-1547466181_thumb.png

post-125-0-64334700-1547466192_thumb.png

post-125-0-34358200-1547466201_thumb.png

post-125-0-68825600-1547466211_thumb.png

post-125-0-10403600-1547466221_thumb.png

post-125-0-23476200-1547659356_thumb.png

post-125-0-24093900-1547659537_thumb.png

post-125-0-61457700-1547659545_thumb.png

post-125-0-47483400-1547659556_thumb.png

post-125-0-42162000-1547659567_thumb.png

post-125-0-40978800-1547659576_thumb.png

post-125-0-35428000-1547659589_thumb.png

post-125-0-94716700-1547659599_thumb.png

post-125-0-95615700-1547659608_thumb.png

post-125-0-86978900-1547659618_thumb.png

post-125-0-74456500-1547659626_thumb.png

post-125-0-20513800-1547659637_thumb.png

post-125-0-15719500-1547659644_thumb.png

post-125-0-28925100-1547659651_thumb.png

post-125-0-80606400-1547659658_thumb.png

post-125-0-53380400-1547659666_thumb.png

post-125-0-75889800-1547659676_thumb.png

post-125-0-58162800-1547659688_thumb.png

post-125-0-92105700-1547659698_thumb.png

post-125-0-45585600-1547659708_thumb.png

post-125-0-78194900-1547659723_thumb.png

post-125-0-10003700-1547659733_thumb.png

post-125-0-83260500-1547659742_thumb.png

post-125-0-42045000-1547659753_thumb.png

post-125-0-25839900-1547659762_thumb.png

post-125-0-85778000-1547659769_thumb.png

post-125-0-83597600-1547659780_thumb.png

post-125-0-26568700-1547659791_thumb.png

post-125-0-66610500-1547659804_thumb.png

post-125-0-01718500-1547659814_thumb.png

post-125-0-16068100-1547659822_thumb.png

post-125-0-74210700-1547659831_thumb.png

post-125-0-82646300-1547659840_thumb.png

post-125-0-23872100-1547659850_thumb.png

post-125-0-22986400-1547659861_thumb.png

post-125-0-98533800-1547659870_thumb.png

post-125-0-06733600-1547659881_thumb.png

post-125-0-20347600-1547659923_thumb.png

post-125-0-06946600-1547659934_thumb.png

post-125-0-30551700-1547659944_thumb.png

post-125-0-08290000-1547659955_thumb.png

post-125-0-34383400-1547659966_thumb.png

post-125-0-05319200-1547659978_thumb.png

post-125-0-20349500-1547659988_thumb.png

post-125-0-07670100-1547660000_thumb.png

post-125-0-66801600-1547660010_thumb.png

post-125-0-26094500-1547660021_thumb.png

post-125-0-76625700-1547660029_thumb.png

post-125-0-10403800-1547660040_thumb.png

post-125-0-86767900-1547660051_thumb.png

post-125-0-26380300-1547660061_thumb.png

post-125-0-17682100-1547660072_thumb.png

post-125-0-84333800-1547660085_thumb.png

post-125-0-83420100-1547660094_thumb.png

post-125-0-29031100-1547660104_thumb.png

post-125-0-34524800-1547660114_thumb.png

post-125-0-85702500-1547660124_thumb.png

post-125-0-71976600-1547660134_thumb.png

post-125-0-63710400-1547660144_thumb.png

post-125-0-46506200-1547660155_thumb.png

post-125-0-98177800-1547660166_thumb.png

post-125-0-28662400-1547660176_thumb.png

JSW VL5 DEMO revision3b.tap

Edited by Norman Sword
Link to comment
Share on other sites

I like the way that the portals animate - the top and bottom rows like conveyors, but the sides also 'rotate vertically', requiring a lot more than just the RL and RR commands.

 

There is a flat note (or consecutive pair of notes) in the 'Rich Man' in-game tune - just after half way through, there is an A# [byte value #48 according to Richard Hallas's tone chart] which used to be a B [#44] in the original game.

Edited by IRF
Link to comment
Share on other sites

  • 2 weeks later...

The first note of the in-game tune is skipped when you first fire up the game.  (i.e. The "If" of the line "If I were a rich man".)
 
I suspect that this occurs because the music note index (initialised to zero during the Title Screen routine) is incremented within the Main Loop before the indexed note is played during that pass through the Main Loop.
 
This also happens in the original JSW (and MM):
http://skoolkid.github.io/jetsetwilly/reference/bugs.html#missedNote
 
However, it is more noticeable here:
 
- In the original games, each note is played twice (i.e. there are two 'blips' of the same pitch, and of a fixed length), and so skipping the 'first' note in reality just means skipping the first 'blip' of the first note;
 
- Whereas in your rewrite, I gather that you have optimised the memory taken up by the tune data - by playing one note for a longer period, rather than having several consecutive notes of the same pitch?  This has the effect that when the first note is skipped (presumably by the same process outlined in the Skoolkid link above), it is equivalent to skipping both 'blips' of the first note of the tune in the original JSW game engine.
 
**
 
By the way, the increased speed at which your latest rewrite of the game runs is very impressive!

Edited by IRF
Link to comment
Share on other sites

The way this plays music bears little resemblance to the way Matthew played music. His was just an incremented pointer, playing at a fixed rate. Code wise :-

35648 LD A,(34273) Increment the in-game music note index at 34273
35651 INC A
35652 LD (34273),A
35655 AND 126 Point HL at the appropriate entry in the tune data table at 34399
35657 RRCA
35658 LD E,A
35659 LD D,0
35661 LD HL,34399
35664 ADD HL,DE

at this point (hl) holds the note data
"BC" will be set with a fixed value of 3

and my code --- minus most of the comments and data

; this plays variable length and variable note repeat and even mutes the music if needed

the call to STEP_INDEX- this adds "A" to "HL" and returns  the contents of "(HL)" :  A=(A+HL)

 

The routine below plays the in game music, changed from just being a variable delay.

snail_run:
    ld hl,var_flag ; this is the speed factor
    LD  a,(MUSIC) ; the music flag (on/off)
    bit 1,a
    ld a,(hl)
    LD D,0
    jr Nz,set1_version
    add a,4
    LD  D,#18
set1_version:
    or a
    ret z 
; this loop is repeated less than 20 times at maximum slow down
;(the speed to execute this code compared to the delay this is calculating, means it is insignificant)
; on a flat out game (music off and fastest speed) this code is not executed.
    ld e,a
    ld bc,$190 ; a delay value
    ld hl,0
sgk:
    add hl,bc  
    dec a
    jr nz,sgk
    ld c,l
    ld b,h   
    ld hl,repeating_note ; table of Blip values (how many times the note will blip)
    ld a,e
    call STEP_INDEX 
    LD E,A
S_M_C_RECHARGE:  EQU $+1
    ld a,2   
    dec a
    jr nz,se1_note
    inc (hl) 
    ld a,E
se1_note:
    ld (S_M_C_RECHARGE),a 
    ld a,(hl)
    and 63 
    LD HL,Music_data ; table of note data
    CALL STEP_INDEX
    ld e,a

E= note
BC= duration
L= mic toggle
D=mic toggle (the routine uses "L", so this must be copied, somewhere)

Note standard in all my code. if something starts with S_M_C_ it is indicating the value or variable is part of inline code that will be modified e.g. Self Modifying Code

;--------------------------------------------

The game notes are still played as designated minimum of two blips per note, However on the first pass the blip count is set to two and is similar to the problem in the original JSW. This is decremented and the first blip is played. This is one blip before the note index is moved to the next note.
 

On first game start up the speed index is set to very fast and in this instance the number of blips is set to 5 for all the subsequent notes and the blip counter should be set at 5 (or even 6) . Not as stated above at 2. 
 

Playing one blip is equivalent at the game start to playing 1/5 of a note, Which is more noticeable than the equivalent problem in the original. All the changes in speed reset the blip count after each note. The routine has no external counters and does not get updated outside of the music/delay routine. The note index is reset on each game.
 

The technical problem is the blip count, which was not reset and due historically to this being a two blip game was left as 2 (which would have still omitted the first half of the note, even if the game was started at the slowest speed). I thought it would take too much code to actually adjust the blip counter at reset to the required value on a game reset (I knew it was a problem- just was not bothered, to actually fix it--- this does have a great big banner on it saying DEMO of speed)
 

addendum to the paragraph above......( on subsequent slow speed game, playing, with 2 blips per note) Not resetting the blip count can make it either skip one blip on subsequent game resets or skip the whole note. The chances are 50-50

I have now fixed this problem and inserted a blip reset, and changed the note index to the last note. This ensures on the first pass the blip count is reset to the correct value for its speed, and the note is stepped to the next note, which will be the first note. This was done by changing  the data in a data reset list from (NOTE_INDEX ,0) to (NOTE_INDEX ,63) and inserting 2 more values (S_M_C_RECHARGE , 1). The modification was far easier than I thought at the time of writing the original. 

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

As I mentioned before I do not listen to the music, it is turned off. If the game had crashed or started playing very obvious long note sequences.I might have checked it a bit more or at least bothered to investigate how I could reset the data. It played and it was not the focus of what I was doing.

Edited by Norman Sword
Link to comment
Share on other sites

Thanks for the explanation Norman!

 

One other little thing that I noticed (if I recall correctly) is that when the game is running at its fastest speed (and possibly at other speeds), the dancing lives on the status bar no longer keep in time with the music?  (Unless your latest amendment has had the additional effect of correcting that; I haven't had chance to check it out yet.)

Edited by IRF
Link to comment
Share on other sites

The dancing was based on the games Ticker. This quick update--- updates from the games current playing note index. 

This keeps his dancing at a more fixed speed (in tempo to the music)

Now with a file actually attached:-

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

Addendum a couple of hours is a long time:- 

 jsw VL5 DEMO revision3.tap
The animation is based on the tempo of the music, and is too Manic (right frame of mind but wrong game). I could slow it down to look less Manic. (Tried it and was still not happy.) 

jsw VL5 DEMO revision3a.tap
The animation in this version is based instead on the note being played. So if a note is sustained, the animation will not change. The sequencing of the animation  is solely dependent on the value of the note played. So the animation is fixed by the music. I feel this whilst erratic frantic (not Manic) better suits the game.

Alas I am out of memory so the next addition I did corrupted a pile of data. Some visual screen data is deliberately placed at the end of available space, and if I exceed my code space. The data will be displayed on the screen as a mess. this indicates visually to me the limits of editing.
Whilst I had to delete this routine the idea was to actually play the wording of the tune across the bottom of the screen as Willy danced -- Looked interesting, just not interesting enough to accommodate into the space available. Something would need to be deleted and the routine was not exciting enough to progress any further.




 

Edited by Norman Sword
Link to comment
Share on other sites

The speed changes
 

The biggest factor in overall game speed is the four innocent looking LDIR instructions that copy the screens.

Those four ldir's move 9216 bytes of memory

mentioned numerous times:-

using ldir takes 21*9216 T states to copy the screens on each and every loop. A very big chunk of time.

Using LDI takes 16*9216 T states to copy the screen on each and every loop (idealized times) . A noticeable increase in speed.

Using stack copy can push the idealized times up to  11*9216 T states, a very noticable increase in speed.

At this point in speed increase we can make more and more changes in the games background speed, but we have hit a basic speed limit. The screen copies dwarf all other speed considerations.

There is however another factor that is adding a major slow down. One that is not looked at because the normal scope of editing does not bring into its remit the placement of the copy screens. ALL the copy screens sit below #8000 and this means all the screen data is written to contended memory. And all the copies to and fro are copies that are in contended memory. Every single sprite draw and screen copy is affected by the contended memory issue and this speed decrease is not within the scope of editing JSW.
 

The small program included here, just loops and draws to a dummy screen (filling it with data). it then copies the dummy screen to another dummy screen. And finally copies the 2nd dummy screen to the visible screen.(similar to the game copy routines in JSW)  Each loop of fill and double copy, moves a visible pointer on the screen, and a text line displays what memory is being copied.



The small routine does this copying using two sets of screens. The first set of screens is sat below #8000 and all the data is moved from contended memory to contended memory (which is how JSW is set up). The 2nd routine uses the same routine, but now the two copy screens are sat above #8000. This moves the same amount of data and it is only the final copy that is moving data into contended memory. (the copy to the visible screen)



What this small program shows is the speed decrease that contended memory gives

a 256 loop of this routine in contended memory 26.73 seconds
a 256 loop of this routine in high memory 23.13 seconds
 

A slowing down due to contended memory of 3.6 seconds.


The contended memory issues show that a speed increase of around 14% is available on LDIR just by moving the screens. Not a great deal of time on its own, but once the screens are moved. That 14% increase is mirrored by all the other methods of screen copy. A stack copy using un-contended memory is a lot faster than the same stack copy with contended memory.


So in the JSW GAMES version VK and version VL. I use un-contended memory for the copy screens. From version VK  and onward the whole game allocation is changed. And no amount of editing the basic game will achieve these speed increases, until they are also reconfigured in a similar way (or rewritten)

Vesion VL DEMO goes one stage  further and uses a change of strategy. This adds a great deal of code and complexity, but the result is evident in the speed increase.

 

CONTEN~1.tap

Link to comment
Share on other sites

I think I read somewhere about using a XOR method for updating moving sprites (to erase the old one and add the new one), so that instead of having to copy the whole screen twice, you only had to update the parts that had changed since the last pass through the Main Loop, and that can help to speed things up?

Link to comment
Share on other sites

Addendum a couple of hours is a long time:- 

 

 jsw VL5 DEMO revision3.tap

The animation is based on the tempo of the music, and is too Manic (right frame of mind but wrong game). I could slow it down to look less Manic. (Tried it and was still not happy.) 

 

jsw VL5 DEMO revision3a.tap

The animation in this version is based instead on the note being played. So if a note is sustained, the animation will not change. The sequencing of the animation  is solely dependent on the value of the note played. So the animation is fixed by the music. I feel this whilst erratic (not Manic) better suits the game.

 

That (rev3a dancing) looks really cool!

 

 

Alas I am out of memory so the next addition I did corrupted a pile of data. Some visual screen data is deliberately placed at the end of available space, and if I exceed my code space. The data will be displayed on the screen as a mess. this indicates visually to me the limits of editing.

Whilst I had to delete this routine the idea was to actually play the wording of the tune across the bottom of the screen as Willy danced -- Looked interesting, just not interesting enough to accommodate into the space available. Something would need to be deleted and the routine was not exciting enough to progress any further.

 

 

Do you mean the lyrics to the song?  That's another great idea!  The only drawback is that whoever wrote "Rich Man" just filled in half of the song with "diddle diddle dums", I'm not sure it would be worth going to the effort, for a song where the composer didn't make an effort to fill in all the words!

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.