============================================= | Jet Set 40-40 | | | | Game Builders: Andy Ford & Daniel Gromann | | | | Technical Contribution: Ian Rushforth | | | | (jswmm.co.uk) | ============================================= 'Jet Set 40-40' is a redesign of Matthew Smith's classic ZX Spectrum 48K game 'Jet Set Willy'. It can be played on a real Spectrum, on the Sinclair ZX Spectrum Vega/Vega+ or on a computer, game console or another device using a ZX Spectrum emulator. The layout of 'Jet Set 40-40' is very similar to that of the original 'Jet Set Willy' (henceforth abbreviated as 'JSW'), but the number of rooms has been reduced to 40. There is one item per room, but the player has to collect four complete sets of items; once the last item of one set has been collected, the items of the next set will appear. The difficulty of the game will increase with each consecutive set of items, as more and more guardians threaten Willy's progress through his mansion and its surroundings. The player is offered a choice of rooms in which they can start the game. An option of playing without some of the most extreme challenges can also be chosen. We hope you will enjoy this 'quadruple quadragesimal' challenge! Contents I. Acknowledgements and thanks II. Instructions III. Game history IV. Technical information V. The legal bit VI. Closing remarks ---------------------------------------------------------------------- I. Acknowledgements and thanks The authors would like to express their gratitude to: - Matthew Smith, creator of the original 'JSW' and 'Manic Miner'. - John Elliott, for his excellent JSW Editor (JSWED, http://www.seasip.info/Jsw/jswed.html), which was the main tool used to create the game, and for JSWED's accompanying documentation. A modified version of John's solution, which defines Willy's facing direction and frame of animation at the start of each game, has been used in the Starting Room Selection Screen routine. - Richard Dymond ('SkoolKid'), for his complete JSW disassembly (http://skoolkid.github.io/jetsetwilly/ in hex and http://skoolkit.ca/disassemblies/jet_set_willy/index.html in decimal), which was of great assistance in implementing various code modifications and optimisations in 'Jet Set 40-40', as well as for his 'Skool Daze' disassembly (http://skoolkid.github.io/skooldaze/ in hex and http://skoolkit.ca/disassemblies/skool_daze/index.html in decimal), which made it easy to rip some sound effects from that game. - David S. Reidy and Keith Warrington, the authors of 'Skool Daze' (Microsphere, 1984), the game from which the sound effects audible after selecting the starting screen and upon reaching the bed just before the toilet run have been copied. - Jon R. Lemmon and Tim Kemp, the authors of 'Project-X: The Micro Man' (Compass Software, 1985), the game from which the font has been copied. - Richard Hallas, for coding 'Wheels', one of the in-game tunes, and the 'Radetzky March', used in the game as the 128-byte-long 'victory tune'. Furthermore, Richard's document 'A Miner Triad' (http://hallas.net/Software/music.htm) is an invaluable guide to creating music for JSW/Manic Miner games. - Andrew Broad, for his 'Lord of the Dance' coded in the JSW48 format, used as one of the in-game tunes, for his JSW-related technical documents and for establishing and managing the Manic Miner & Jet Set Willy Yahoo! Group (https://groups.yahoo.com/neo/groups/manicminerandjetsetwilly/info). - Stuart Brady, for his Cell-Graphics Bug Fix, which ensures that all cell graphics are drawn as the designer intended. - Norman Sword, for his optimised routine dealing with ropes, which freed up a sizable chunk of spare space, later used for other purposes. A discussion with Norman on jswmm.co.uk also inspired Ian Rushforth to carry out further optimisation of the item-handling code (with an additional benefit in terms of speeding up the program). - Jonathan Graham Harston, for his 'Full Z80 Opcode List Including Undocumented Opcodes' (http://www.z80.info/z80oplist.txt), for his 'JSW' related documentation (http://mdfs.net/Software/JSW/) and for his elegant Pause Bug Fix. - James Moxham, for his 'ZINT Z80 Interpreter' (http://www.z80.info/z80code.htm), which is a highly informative introduction to the Z80 instruction set. - The authors of Binary Hex Converter (http://www.binaryhexconverter.com/), which was the standard tool used to convert values back and forth between the decimal, binary and hexadecimal systems. The Bitwise Calculator at http://www.miniwebtool.com/bitwise-calculator/ was also a useful tool. - The ZX Spin team, for their ZX Spin (http://www.zophar.net/sinclair/zx-spin.html), which was used by Daniel Gromann in playtesting. - Jan Bobrowski, for his Qaop/JS HTML5 ZX Spectrum emulator, which was used by Ian Rushforth in playtesting. - Claus Jahn, for his ZX-Modules (http://www.zx-modules.de), particularly ZX-Paintbrush which was used during the creation of the loading and title screens, and ZX-Blockeditor which was used during the creation of the final TAP and TZX files. - The authors of the games from which various sprites have been borrowed (a detailed list is included below). The rooms Most of the rooms preserve their general layout from the original 'JSW'. Modifications (such as the diptych 'East Attic' - 'West Attic') are mainly the work of Andy Ford, who also defined the game's map (especially in where it differs from the original). The sprites The majority of the sprites in the game are Matthew Smith's classics from the original 'JSW'. The remaining ones are (only examples of where they appear in the game are given, the list of their appearances is by no means exhaustive): - The '1 ton' vertical guardians in 'Master Bedroom' and the 'penny-farthing' guardians in 'Front Door' were copied from 'Technician Ted' by Steve Marsden and David Cooke (Hewson Consultants Ltd, 1984). - The rightmost, red vertical guardian in 'Master Bedroom' was copied from 'The DrUnKeN mAsTeR!!!' by the DrUnKeN mAsTeR!!! (BaSe1 PrOdUcTiOnZ, 2002). - The white and yellow vertical guardians in 'Orangery' were copied from 'JSW (Sunday Afternoon Graphical Remix)' by Darren McCowan (2001). - The magenta vertical guardians in 'Orangery' were copied from 'Jet Set Willy II: The Final Frontier' by Derrick P. Rowson (Software Projects Ltd, 1985), originally created as an Amstrad version of 'JSW' by Derrick P. Rowson and Steve Wetherill. - The stationary 'forcefield' guardian in 'East Attic' was copied from 'The Deadly Mission' by Adam Britton (1985). - The bright green horizontal guardian in 'West Ballroom', the magenta horizontal guardians in 'Security Guard' and the red 'trap door' guardian in 'First Landing' were copied from 'Willy's Holiday' by Adam Britton (1985). - The green horizontal guardian in 'Back Stairway' is an upside-down version of a sprite copied from 'Technician Ted', tweaked by Ian Rushforth. - The magenta 'portcullis' guardian in 'The Chapel', the vertical 'insect' guardians in 'Conservatory Roof' and the blue 'periscope' guardian in 'First Landing' were designed by Daniel Gromann (the periscope being a modification of the 'periscope / Macaroni Ted' guardian from 'Jet Set Willy II: The Final Frontier'). - The swordfish sign was copied from 'Manic Miner' by Matthew Smith (Bug-Byte, 1983). The music The title-screen tune is the original tune from 'JSW', i.e. the 'Moonlight Sonata', coded by Matthew Smith, originally composed by Ludwig van Beethoven (the Piano Sonata No. 14 in C♯ minor 'Quasi una fantasia', Op. 27, No. 2, 1801). The game features six in-game tunes. They are: - The original tune from 'JSW' ('If I Were a Rich Man'), coded by Matthew Smith, originally written by Sheldon Harnick and Jerry Bock for the 1964 musical 'Fiddler on the Roof' (audible e.g. in 'The Bathroom'). - The original tune from 'Manic Miner' ('In the Hall of the Mountain King'), used also in 'Jet Set Willy II: The Final Frontier', coded by Matthew Smith, originally composed by Edvard Grieg (1875) (audible e.g. in 'Driveway'). - 'Lord of the Dance', coded by Andrew Broad (first released as an Easter egg in his 2004 game 'Party Willy'), originally written by Sydney Carter (1963), although the tune is, in fact, a traditional Shaker tune (audible e.g. in 'At the Top of the House'). - 'Wheels', coded by Richard Hallas, originally composed by Richard Stephens, Jimmy Torres and Norman Petty (1960) and released by the String-A-Longs on their first single (the tune has had over a hundred cover versions since, including by Joe Loss ['Wheels Cha-Cha'] and Billy Vaughn). An earlier adaptation of 'Wheels' was featured in Richard's 1985 classic 'Join the Jet-Set!' (it can be chosen as tune No. 7 before the start of the game). Richard coded the new note-perfect transcription especially for 'Jet Set 40-40' upon receiving a request from Ian. - A portion of the 'Moonlight Sonata', coded by Matthew Smith as the title-screen tune, played as the in-game tune in 'The Nightmare Room'. - 'Radetzky March', coded by Richard Hallas, originally composed by Johann Strauss Sr. (1848), used as the 'victory tune'. An earlier, shorter (64-byte) version of the 'Radetzky March' was scored by Richard for Philip Bee's game 'Jet-Set Willy Ivy' (Filsoft, 1998), while a longer (256-byte) version is featured in 'Jet Set Mini' by Ian Rushforth and Andy Ford (2017). The font The custom game font was added by Andy Ford. It was taken from 'Project-X: The Micro Man' by Jon R. Lemmon and Tim Kemp (Compass Software, 1985) with a few very minor alterations to its layout. The title screen The title screen was designed by Andy Ford. It was initially created in BASIC using the built-in graphics, and then modified using ZX-Paintbrush to create the final layout. The loading screen The loading screen was designed by Daniel Gromann, using ZX-Paintbrush and various other tools. Support for the Vega/Vega+ The ZXK file to map the Vega controls to the ZX Spectrum keys used by the game was created by Ian Rushforth. Ian also tested it on a real Vega to ensure it was fully functional. ---------------------------------------------------------------------- II. Instructions The object of the game is to guide Willy and collect all of the flashing items scattered around his mansion, avoiding the moving and unmoving guardians and the stationary nasties which may kill you (as will falling from an excessive height). With all the items collected, the player needs to go to 'Master Bedroom' where Maria will no longer be blocking access to Willy's bed. The whole process has to be completed before midnight. At the start, there is one item to collect in each of the 40 rooms of the game. After the last item of the first set has been collected, the items of the second set will appear (as will some additional guardians). This process will repeat after collecting the items of the second and third set. The fourth set of items is the final one. After pressing ENTER to start the game, the player is asked whether or not they want to face maximum difficulty. Choosing 'Y' will allow the game to be played in its most difficult permutation. Choosing 'N' will result in ten guardians (and one lethal arrow) which create the hardest challenges for the player being omitted, and one guardian being converted to a less threatening incarnation! These guardians will be restored if 'Y' is chosen at the start of the next game. The player is then presented with a 'Starting Room Selection' menu screen. Press a number key from 0 to 9 to choose the room in which the game will start and to launch it. Use O-Left, P-Right (or a combination of keys from the top row of letters) and SPACE or any of the letters from the bottom row to jump. A-G pauses the game; any other key unpauses it. H-ENTER/RETURN toggle the music ON/OFF. Pressing SHIFT+SPACE together at the same time abandons the current game. 'Jet Set 40-40' has been fully and extensively playtested by Daniel Gromann. It is possible to complete the game in either difficulty mode, before the in-game clock strikes noon, and without losing a single life! ---------------------------------------------------------------------- III. Game history The 'Jet Set 40-40' project was started by Andy Ford at the end of July 2017 as 'JSW with 40 objects and 40 rooms - that simple'. Apart from modifying the layout, Andy introduced various other tweaks such as: - a redesigned title screen; - a custom font; - 24-hour clock with the game ending at midnight; - minor adjustments to the 'lower screen' (the status area) display such as the lives colouring and the text positioning; - removal of unwanted routines such as the colour-code keypad and inactivity timer. At the end of July 2017 the project was presented in the Contributor Lounge of the Jet Set Willy & Manic Miner Community, where Ian Rushforth and Daniel Gromann joined in and became engaged in its further development. Daniel came up with the idea of having 4 sets of 40 items each, and a theoretical technical solution for it. Ian then created and implemented a different, much more efficient solution, as well as a tweak to have the guardians appear 'in instalments'. Andy and Daniel defined the placement of the additional Item Sets. Daniel added new guardians, some technical features (various in-game tunes, colourful arrows), the Starting Room Selection Screen, the choice of difficulty level at the start and a number of special effects related to the completion of the game. He also created the loading screen. Ian, in turn, added one more guardian (which appears in a room that is not normally accessible during gameplay…), an additional tune coded by Richard Hallas and some technical tweaks. Finally, Andy created a custom BASIC loader and the final TAP and TZX files of the game. Following Andy's initial decision to make room 40 ('Master Bedroom') the last screen in the game as far as the code is concerned, during the development of the project a part of its challenge was always keeping everything below room 40's code addresses. This has been achieved thanks to various optimisations and consolidation of the code when new features were added. By the time the project was ready for release, almost 1200 posts had been exchanged between the contributors in the pertinent topic at jswmm.co.uk. The game was released on Friday 26th January 2018, two years to the day after the release of the authors' first joint project, 'Jet Set Willy: The Nightmare Edition' (http://jswmm.co.uk/topic/161-file-jet-set-willy-the-nightmare-edition/). ---------------------------------------------------------------------- IV. Technical information The game contains a number of features which go beyond the standard JSW48 game engine (i.e. the game engine used by the original 'JSW'). Some of them are described below. 1. Multiple sets of items to collect This novelty was created by Ian Rushforth. Preamble: In the original 'JSW' game engine, the items are handled as follows: - The item definitions are stored in a table across pages #A4 and #A5 of the code (two definition bytes per item, one in each half of the table). The table is populated 'from the last entry downwards', i.e. Offset #FF (the addresses #A4FF/#A5FF), then Offset #FE, etc. - The address #A3FF is a fixed variable which is used as an index pointing at the first item. It holds the low byte of the address of the first entry defined in each half of the table (so for example, in a game with three items, #A3FF would hold the value #FD - meaning that the first item's definition bytes are found at the addresses #A4FD and #A5FD). - The 'Game initialisation' routine, which starts at #87CA, picks up the value of #A3FF and uses it to establish a loop, pointing the HL register-pair at each defined item entry in the half of the Item Table occupying page #A4 in turn, and setting Bit 6 for each byte. This bit acts as the item's Collection Flag. The L register is incremented during each pass through this loop, in order to point HL at the next item entry (H has a fixed value of #A4 throughout). The loop is sustained until L is incremented past #FF to #00 (thus setting the Zero Flag), at which point all items will have been marked as 'uncollected' (Bit 6 set). - The 'Game initialisation' routine also initialises the value of the address #85DE. This is a counter of the number of items remaining, expressed as a negative number in the range -256 (#00) to -1 (#FF). At the beginning of each game, the value of #A3FF is copied to #85DE, and then the former remains fixed during the course of the game, whilst the latter is incremented during runtime each time an item is collected. - The 'Game initialisation' routine initialises the values of the addresses #857C to #857E to #30. These three addresses are displayed on the physical screen as an ASCII counter of the number of items collected throughout the game (beginning with '000'). - The address #85DF acts as an indicator of the current Game Mode. This is initialised to zero, to indicate that there are items left scattered around Willy's house, and he cannot go to bed until he has collected them all. - Once the game is running, the routine at #93D1 is called during every pass through the game's Main Loop. This routine picks up the 'Index of the first item' from #A3FF, and then sets up a loop via HL, to consider each item defined in the game in turn. - If an item is located in the room currently occupied by Willy, AND if that item is flagged as still being uncollected, then the routine checks whether the cell in which the item is located (determined by the rest of the relevant entry in the Item Table at pages #A4 and #A5) contains white INK. This is used as an indicator that Willy (whose colour attribute is white) has touched the item under consideration. - If there is no white INK present, then the item remains uncollected and therefore its graphic is drawn at the appropriate coordinates. - If white INK is present, then the item is collected, which involves several aspects: the on-screen ASCII tally (#857C-#857E) is incremented, a sound effect takes place, the pertinent entry in page #A4 of the Item Table has its Bit 6 reset (marking it as 'collected'), and finally the value of the internal item counter (#85DE) is incremented. - If that last step has incremented the value of #85DE 'up' to #00, then the Zero Flag will be set, and this is interpreted by the code as a sign that there are no items remaining uncollected. Willy has finished tidying up his house and is now allowed to go to bed. The value of the Game Mode Indicator is set to #01, which means that Maria will no longer be present in the Master Bedroom, preventing Willy from reaching his bed! In the 'Jet Set 40-40' game engine, the items are handled as follows: - Each room, numbered from 1-40, contains exactly four items. - Items appear in the game in sets of 40 (one per room); each set has to be fully collected before the next set appears. - The item definitions are still stored in a table across pages #A4 and #A5 of the code, but the items are arranged sequentially in (reverse) room number order. If a room's number is expressed as a negative number, then this gives the index to point at the first item definition for each room, and then the entries for the next three items for that room can be accessed in turn by subtracting 40 from the entry for the previous item. - Thus the entries in the Item Table from #A460/#A560 to #A4FF/#A5FF are used to store the item definitions, e.g. the first data entry in the table, representing the fourth item in Room 40, is located at the addresses #A460 and #A560: -{40 + (4-1) x 40} = -160 = -#A0 ≡ #60: hence Offset #60. (Note that all addresses prior to that in the Item Table, which are not used for item data - i.e. the addresses #A400-#A45F and #A500-#A55F - have been 'recycled' and used by the program for various other purposes.) - The use of the address #A3FF as a fixed 'Index to the first item' variable is no longer needed. #A3FF is redesignated as a runtime variable, keeping track of the current Item Set that Willy is collecting. Its default value in the game file is still set to #60 (so that the JSWED editor, which isn't aware of the changes to the game engine, still respects #A3FF's old purpose and therefore displays all the items in its GUI). - However, as soon as the game is loaded, the 'Game initialisation' routine sets the value of #A3FF to #01 (representing Item Set 1). The routine then points the HL register-pair directly at the address #A460, before performing the same loop as occurs in the original 'JSW', to set the Collection Flag (Bit 6) for each item's entry in page #A4 of the code. - The 'Game initialisation' routine sets the value of #85DE to an initial value of #D8, which equates to a negative decimal value of -40. The variable at #85DE performs a similar role as it did in the original 'JSW', except that in 'Jet Set 40-40' it keeps a tally of the number of items remaining to be collected FROM THE CURRENT ITEM SET. - The 'Game initialisation' routine also initialises the values of the ASCII counters at #857C to #857E. However, the number of items in each set is limited to two digits, so only #857D and #857E are 'zeroed' to #30 and used for the purpose of tallying items collected. The address #857C is redefined as the ASCII counter of the current Item Set under consideration, and is therefore assigned an initial value of #31 (the ASCII character code for '1'). - As in the original 'JSW', the address #85DF acts as an indicator of the current Game Mode, and it is initialised with a value of #00. - Once the game is running, the routine at #93D1 is called during every pass through the game's Main Loop. This item-handling routine has been restructured, so that it only picks up the value of one pair of entries from the Item Table (the corresponding offsets in pages #A4/#A5), representing the single item from the current Item Set in the room that Willy is presently occupying (the current room number variable being stored at the address #85CB). This arrangement gives rise to a noticeable speeding up of the running of the game, since the program is no longer needlessly taking into consideration every single item in the whole game, during each time-frame of the game! - The drawing of items is handled in a similar manner to the original 'JSW', as is the situation when an item is picked up but other items remain uncollected from the current Item Set. - However, when Willy clears the final item from the Item Set currently under consideration, the program jumps to a new piece of code at #96F4, to handle the transition between Item Sets. Depending on the circumstances, flow of execution here branches off in two different directions: - If Willy has just finished collecting Item Set 1, 2 or 3, then the 'Current Item Set' variable at #A3FF is incremented, along with the on-screen ASCII 'Item Set' counter at #857C. But the 'Number of Items Remaining' counter (#85DE) is reset back to #D8 (-40), so that this variable can begin to count the next set of items, and the on-screen ASCII 'Items Cleared' tally (#857D-E) is reset back to '00' for the next Item Set. - If Willy has just finished collecting the final Item Set (Set 4), then his mission is complete, and the Game Mode Indicator at #85DF is incremented to #01 to move Maria out of the way of Willy's bed. - There are also some special effects which take place during the transition between Item Sets / Game Modes. There now follows a disassembly of the restructured item-handling routine and the 'Next Item Set' code. At #93D1, 'Draw the item in the current room, or collect it if Willy is touching it': #93D1 3A CB 85 LD A, (#85CB) Load up the 'Current Room Number' variable to the Accumulator #93D4 B7 OR A This command sets the Zero Flag if (and only if) A holds a value of zero #93D5 C8 RET Z If the Zero Flag is set, then return to the Main Loop (Room 00 is not one of the forty defined rooms) #93D6 6F LD L, A Otherwise, copy the room number to the L register #93D7 3A FF A3 LD A, (#A3FF) Pick up the 'Current Item Set' counter in A #93DA 3D DEC A Decrement it #93DB 28 06 JR Z, #93E3 Skip forward if Willy is still collecting Item Set 1 #93DD 47 LD B, A Copy [Item Set-1] to B #93DE AF XOR A Reset the Accumulator to zero #93DF C6 D8 ADD A, #D8 Subtract #28 (40 in decimal)… #93E1 10 FC DJNZ #93DF … for each Item Set already cleared #93E3 95 SUB A, L Subtract the current room number from A #93E4 6F LD L, A L now holds the offset for the correct item definition… #93E5 26 A4 LD H, #A4 … as stored in Page #A4 of the code #93E7 CB 76 BIT 6, (HL) Check the Collection Flag for the item under consideration #93E9 C8 RET Z Return to the Main Loop if the item has already been collected #93EA 7E LD A, (HL) Copy the item definition byte from page #A4 to A #93EB 07 RLCA Put Bit 7 into Bit 0… #93EC E6 01 AND #01 … and ignore all other bits #93EE C6 5C ADD A, #5C The attribute buffer is located at addresses #5C00-#5DFF #93F0 57 LD D, A D now holds the high byte of the item's attribute coordinates #93F1 24 INC H Point H at Page #A5 for the other item definition byte #93F2 5E LD E, (HL) E now holds the low byte of the current item's coordinates #93F3 25 DEC H Point H back to Page #A4 (in case we have to reset the Collection Flag later on) #93F4 1A LD A, (DE) Load the current item's attribute coordinates to A… #93F5 3C INC A … increment it… #93F6 E6 07 AND #07 … and select Bits 0-2; the Zero Flag will now be set if (and only if) the INK attribute at the item's location is white #93F8 20 37 JR NZ, #9431 If not, then jump forward to draw the item But if the item has encountered white INK, then the item is collected as flow of execution of the routine continues: #93FA DD 21 7D 85 LD IX, #857D Point IX at the ASCII counter of 'Items Cleared' (in the current Item Set) #93FE DD 34 01 INC (IX+#01) Increment the units digit #9401 DD 7E 01 LD A, (IX+#01) Load the units digit to A #9404 FE 3A CP #3A Has it just rolled past '9'? #9406 20 07 JR NZ, #940F If not, then skip forward #9408 DD 36 01 30 LD (IX+#01), #30 If so, then set the units digit to '0'… #940C DD 34 00 INC (IX+#00) … and increment the tens digit #940F 3A DE 80 LD A, (#80DE) Pick up the border colour for the current room #9412 0E 80 LD C, #80 S #9414 D3 FE OUT (#FE), A O #9416 EE 18 XOR #18 U #9418 5F LD E, A N #9419 3E 90 LD A, #90 D #941B 91 SUB A, C #941C 47 LD B, A E #941D 7B LD A, E F #941E 10 FE DJNZ #941E F #9420 0D DEC C E #9421 0D DEC C C #9422 20 F0 JR NZ, #9414 T #9424 3A DE 85 LD A, (#85DE) Load up the 'Number of Items Remaining' internal variable to A… #9427 3C INC A … increment it… #9428 32 DE 85 LD (#85DE), A … and update the variable #942B CB B6 RES 6, (HL) Clear the Collection Flag for the item under consideration #942D C0 RET NZ Return to the Main Loop UNLESS the 'Number of Items Remaining' value has just reached #00, thus setting the Zero Flag… #942E C3 F4 96 JP #96F4 … in which case Willy has just cleared the last item in the current set, so the program jumps to the 'Next Item Set' code #9431 3A E0 85 LD A, (#85E0) Load the 'Game Tick' counter to A #9434 E6 03 AND #03 Select Bits 0-1 of A #9436 C6 03 ADD A, #03 Generate a value representing an INK colour of magenta, green, cyan or yellow #9438 4F LD C, A Copy the value to the C register #9439 1A LD A, (DE) Load up the current colour attribute at the item's location #943A E6 F8 AND #F8 Select only the PAPER/BRIGHT/FLASH bits #943C B1 OR C Merge with the INK colour stored in C #943D 12 LD (DE), A Update the item's colour attribute in the attribute buffer #943E 7A LD A, D Copy the high byte of the attribute coordinates to A #943F 07 RLCA Rotate Bit 0 of A leftwards… #9440 07 RLCA … again… #9441 07 RLCA … and again… #9442 E6 08 AND #08 … until it's in Bit 3, and then filter out all other bits #9444 C6 60 ADD A, #60 The pixel-buffer is located at addresses #6000-#6FFF #9446 57 LD D, A DE now points at the item's address in the pixel-buffer #9447 21 E1 80 LD HL, #80E1 Pick up the address of the item graphic for the current room #944A C3 99 96 JP #9699 Jump to a late entry point in the subroutine at #9691, to draw the item at the appropriate location in the pixel-buffer The subroutine at #9691 ends in a RET, which returns flow of execution back to the Main Loop once the item has been drawn At #96F4, 'Next Item Set': #96F4 3A FF A3 LD A, #A3FF Load up the 'Current Item Set' counter to A #96F7 07 RLCA Multiply it… #96F8 07 RLCA … by… #96F9 07 RLCA … eight #96FA 32 CD 85 LD (#85CD), A … and then load the result up to the 'Screen Flash Counter' variable (causing the screen to flash X times through all eight PAPER colours, when Willy has just finished collecting Item Set X) #96FD FE 20 CP #20 If A now holds a value of #20, then this command sets the Zero Flag… #96FF 28 1E JR Z, #971F … meaning that all four Item Sets have now been cleared, so skip forwards in the code to move on to the next Game Mode If the command at #96FF did not have the effect of setting the Zero Flag, then flow of execution proceeds straight to #9701: #9701 21 FF A3 LD HL, #A3FF Point HL at the 'Current Item Set' counter… #9704 34 INC (HL) … and increment this internal variable #9705 3E D8 LD A, #D8 Moving onto the next Item Set… #9707 32 DE 85 LD (#85DE), A … reset the 'Number of Items Remaining' internal variable back to -#28 (-40) #970A 3A 1B 89 LD A, (#891B) Pick up the 'Maximum Guardians' parameter in A… #970D E6 FE AND #FE … disregard Bit 0 (to ensure an even number of guardians per room, after the initial Item Set 1 has been completed)… #970F C6 02 ADD A, #02 … add 2 to the value… #9711 32 1B 89 LD (#891B), A … and then update the 'Maximum Guardians' parameter (see the next section for more details) #9714 21 7C 85 LD HL, #857C Point HL at the ASCII 'Item Set' counter… #9717 34 INC (HL) … and increment it #9718 21 30 30 LD HL, #3030 Assign the ASCII character code for '00' to the HL register-pair… #971B 22 7D 85 LD (#857D), HL … and then reset the ASCII 'Items Cleared' counter, in preparation for the next Item Set #971E C9 RET Return to the Main Loop – Willy has moved on to start tidying up the next Item Set #971F 3E 01 LD A, #01 Willy has finally collected all four Item Sets… #9721 32 DF 85 LD (#85DF), A … so update the 'Game Mode Indicator' variable to shift Maria away from Willy's bed #9724 06 20 LD B, #20 Select 20 bytes to update the attributes… #9726 21 60 5A LD HL, #5A60 … of the relevant character row on the status bar… #9729 CB FE SET 7, (HL) … setting the FLASH Bit across the row… #972B 23 INC HL … to celebrate… #972C 10 FB DJNZ #9729 … Willy's success… #972E C9 RET Return to the Main Loop – Willy can now go to bed! 2. The guardians multiply as the game progresses This novelty was created by Ian Rushforth. In the original 'JSW' code, at #8929 in the 'Initialise the current room' routine, there is the following command: LD A, #08. The operand of this command determines the maximum number of entities (ropes/arrows/guardians – not including Maria) within each room in the game. In 'Jet Set 40-40', the 'Game initialisation' routine sets the operand of the equivalent command (which is now at #891A-B, due to code shuffling) to a value of #03 at the start of each game. This means that at the beginning of the game, there are a maximum of three entities per room. However, once each set of items has been cleared by Willy, this game parameter is increased (by editing the value of address #891B - see the disassembly in the previous section), so that the occupancy limit of each room expands when the game moves on to the next Item Set. This gives rise to a 'Multiplying Guardians' effect, ratcheting up the difficulty level of the game as the player progresses. The general rule is that two further guardians are added to each room, every time the game proceeds to the next Item Set. However, the initial occupancy rate during the first Item Set is three, rather than two guardians, to allow the tripartite 'Evil Priest' guardian in rooms such as 'The Chapel' to appear in all its glory from the outset. Note that after moving on to the next Item Set, the player will not observe an immediate increase in the number of guardians per room; the effect does not manifest itself until the next time that Willy moves into a different room (or he is 'respawned' after losing a life). 3. The in-game tune set individually in each room The way the in-game tune is chosen in each room in 'Jet Set 40-40' mirrors the solution created jointly by Daniel Gromann and Ian Rushforth which had first been applied in the Special Edition of 'Willy's New Mansion' (2016). Offsets #DF and #E0 in each room's data (which were unused in the original 'JSW') specify the (reversed) address of the in-game tune to be used in this room. The instruction at #8B4D - #8B4F (changed from LD HL,#865F [21 5F 86] to LD HL,(#80DF) [2A DF 80]) loads this address (from the room's data copied into the room buffer) so that the routine which plays a note of the in-game music knows where to look for the tune (instead of the permanent address #865F, the start of the tune is defined by the value of Offsets #DF and #E0 in the room buffer). The appropriate values for the start of each tune have been set in each room's data. 4. The colour of arrows set individually in each room The way the colour of arrows is defined in each room in 'Jet Set 40-40' mirrors the solution created jointly by Ian Rushforth and Daniel Gromann which had first been applied in the Special Edition of 'Willy's New Mansion' (2016). In the original 'JSW', all arrows are white. The following code sets the arrow's colour there: 9286 7E LD A,(HL) 9287 F6 07 OR #07 set the INK to #07 (white) regardless of the background's INK colour ('background' here meaning whatever character square the arrow is passing through) 9289 77 LD (HL),A set the INK to white at the arrow's location In 'Jet Set 40-40', the code has been modified in the following way: 9286 3A ED 80 LD A,(#80ED) pick up the arrow's attributes from Offset #ED in the room buffer 9289 77 LD (HL),A set these attributes at the arrow's location As a result, the arrow's attributes are defined in Offset #ED of each room (unused in the original 'JSW'). In rooms with no arrows the value of this offset has been set to #00 (it could be anything, as it has no bearing on the game). Please see the 'Willy's New Mansion Special Edition' Readme (http://www.jswcentral.org/download/Willy's_New_Mansion_-_Special_Edition.zip or https://xa.bi/jsw/download/Willy's_New_Mansion_-_Special_Edition.zip) for more details concerning this solution. 5. The choice of difficulty level at the start of the game The code which deals with this issue starts at #A50C. The code modifies the values of the first byte of (two-byte-long) guardian specifications within the room data (i.e. in the #..F0 - #..FF range). If the player chooses 'Y', proper values are written for twelve most difficult guardians (so that they will appear in this game, even if they had been wiped out by a choice of 'N' at the start of the previous one). If the player chooses 'N', the first byte of data of eleven of these guardians is NOPped out (so that they will not appear in this game, being replaced by 'blank guardians'), and the first byte of data of one guardian is modified (so that another entity appears in place of the one from the 'maximum difficulty' version). The screen which prompts the player with 'Maximum difficulty? Y/N' will also respond to the player pressing the '6' and '7' keys for the 'Y' and 'N' options, respectively. This has been implemented by Ian Rushforth in order to make it possible to map the Vega control buttons to all of the ZX Spectrum keys used by the game (the mapping had to be done for numerical keys for each of the ten starting rooms and the 'Y/N' difficulty options - twelve options in total, while there are only eleven buttons on the Vega unit). Ian also provided a code which checks whether the player is still holding the '6' or '7' keys, and does not allow them to proceed until they have let go of the key in question (the code is at #99CE - #99D9). This prevents a situation in which, due to one of these keys being pressed for too long, a starting screen of either 'Priest's Hole' (option 6) or 'Tree Top' (option 7) would be inadvertently selected on the Starting Room Selection Screen. 6. The Starting Room Selection Screen The code which deals with this screen starts at #86AA. When the starting room is chosen, not only is the current room number set (which in the original 'JSW' is done at #87EA - #87EE), but Willy's pixel y-coordinate (in the original 'JSW' initialised at #87E5 - #87E9), Willy's attribute coordinates (in the original 'JSW' initialised at #87EF - #87F4), Willy's facing direction (not initialised in the original 'JSW') and frame of animation (not initialised in the original 'JSW') are defined as well. As a result, for each of the rooms which may be selected, Willy always starts the game in exactly the same position and stance (in the original 'JSW', Willy's animation frame and the direction he is facing at the start of a game are whatever they were when he died in the previous game). Thanks to the code provided by Ian, mentioned above, after the player presses one of the numerical keys on this screen, the program will not proceed to load the starting room until the player has let go of that key. This prevents a situation in which, due to '0', '5', '6', '7' or '8' being pressed for too long, Willy would jump or move prematurely after the starting room has loaded. 7. Sound effects from 'Skool Daze' These were added to 'Jet Set 40-40' by Daniel. It was a relatively easy task thanks to Richard Dymond ('SkoolKid')'s disassembly of 'Skool Daze' (see the links in section I above). Some necessary adjustments were made to the code to accommodate it in 'Jet Set 40-40'. The routine which plays the tune is at #8356 - #837E and #B496 - #B4B0. The data for the tune played after the starting room has been selected is at #A400 - #A421, and the data for the tune played upon reaching the bed in 'Master Bedroom' after all items have been collected is at #A422 - #A444. Note duration and pitch data for the tunes is at #A500 - #A50B. The code which launches the tune after the starting room has been selected is at #99C2 - #99C7 (with a call to #B4AA) and the code which launches the tune played upon reaching the bed in 'Master Bedroom' after all items have been collected is at #B4B1 - #B4BE (with a relative jump to #B4AA). The latter makes sure that the tune is played only once, by checking the variable at #8FBF (otherwise the tune, which is triggered by Willy's x-coordinate, would be played twice before he changes his x-coordinate at the start of the toilet run - which would be too much). ---------------------------------------------------------------------- V. The legal bit 'Jet Set 40-40' is freeware, and all of its innovative elements may freely be reused in other projects. If you do so, please acknowledge their authorship. ---------------------------------------------------------------------- VI. Closing remarks We hope you enjoy playing 'Jet Set 40-40' as much as we did writing it! If you have any queries, comments or general feedback, please contact us on the email address below, or come and visit our Jet Set Willy & Manic Miner Community at jswmm.co.uk to join in with Willy-based discussions! Do let us know you've had a go at 'Jet Set 40-40', even without any specific comments - the biggest gratification and encouragement for anyone designing free games is to know that someone else has played them. Please check out our other projects, available for download at http://jswmm.co.uk/files/category/3-jswmm-releases/. Please visit also JSW Central (www.jswcentral.org), a source of information on JSW & MM games. Andy Ford, Daniel Gromann & Ian Rushforth, 26th January 2018 projects@jswmm.co.uk