Norman Sword Posted January 11, 2018 Report Share Posted January 11, 2018 I amended the routine the handles depression into a block for ramps. It was not listed because it was another problem, separate from the ramp code. Plus my version can not be used because it uses subroutines and the routine itself is another subroutine. I would have needed to rewrite it. IRF 1 Quote Link to comment Share on other sites More sharing options...
IRF Posted January 11, 2018 Report Share Posted January 11, 2018 (edited) Yes, since I wrote my post last night I was playing around in one of your earlier test files, and I noted that the 'sinking into the wall' didn't occur as Willy walked along the top of the 'parapet' wall block towards the bottom of the ramp in 'On top of the house', so I assumed you must have also altered the 'Draw Willy' code in some way (not necessarily in the same way that I suggested above). Edited January 11, 2018 by IRF Spider 1 Quote Link to comment Share on other sites More sharing options...
IRF Posted January 11, 2018 Report Share Posted January 11, 2018 (edited) For clarity on your code it would benefit from a few additions regarding the usage of bit 7 (direction). This bit is being toggled in several places, with no mention as to why. e.g. XOR #80 ;restore direction (bit 7) which was inverted XOR #E0 ; invert direction (bit 7) and invert animation bits (6 and 5) It could appear to be an unnecessary duplication by toggling Bit 7 twice (which would leave it back where it started), but if you consider the possible paths through the code, this doesn't always occur. The XOR #80 is used when the animation frame has been incremented/decremented beyond the range of appropriate values for the current direction of travel (i.e. to bring it back into the correct half of the sprite-page). The XOR #E0 is used at the point when the horizontal guardian changes direction. It's effectively doing two things simultaneously: a XOR #80 (to swap to the other half of the sprite-page), and a XOR #60 (to toggle between left-most and right-most sprite-frames, without which the turnaround doesn't occur as smoothly). and finally for clarity , an explanation of what the carry bit is being used for. ; the direction bit (bit 7 = #80) must be taken into account ;animation right adding #20 #80, #a0, #c0, #e0 carry clear with each addition but not #eo+#20 = #00 ; left adding #e0 #60, #40, #20, #00 carry set with each addition but not #00+#eo = #eo You've hit the nail on the head. In the original code, the conditionality of the Carry Flag happens in the same way for both direction, but that's because left and right movements are handled via a SUB #20 and an ADD #20 respectively. But here we're using the same operation (an ADD), but changing the operands for left (#E0 = - #20 in two's complement) and right (#20 = +#20 in two's complement). Which means that the effect on Carry is polar opposite for left and right motion, so we have to use a CCF. Edited January 11, 2018 by IRF Quote Link to comment Share on other sites More sharing options...
IRF Posted January 11, 2018 Report Share Posted January 11, 2018 (edited) However, the following method eliminates the need to Complement the Carry Flag. Starting at #9133 (changes from previous code highlighted in bold): PUSH IX ; copy the address of Byte 0 of the guardian definition POP HL ; to the HL register-pair LD DE,#E0FF ; parameters for a LD B A,(IX+$06) ; guardian moving left BIT 7,(HL) JR NZ, left LD DE,#2001 ; parameters for a LD B A,(IX+$07) ; guardian moving right left: LD B,A LD A,(HL) ADD A,D ; increment animation-frame of guardian BIT 7,(HL) ; sets the Zero Flag for a left-moving guardian LD (HL),A ; update guardian definition Byte 0 with correct animation-frame JR Z,carry_okay CCF ; Complement the Carry Flag for a right-moving guardian carry_okay: JP PO,#91B6 ; not time to update the guardian's x-coordinate; proceed to Move the next guardian If we get here then the Overflow Flag has been set (for both directions of travel) XOR #80 LD (HL),A ; time to update the guardian's x-coordinate, so reset the animation-frame to the first one for the next cell-column LD A,(IX+$02) ; guardian definition byte 2 LD C,A ; temporarily save in the C register AND #1F ; extract guardian's current x-coordinate CP B ; has the guardian reached the extremity of its range in the current direction of travel? JR Z,turn_around ; if so, jump to reverse its direction of travel LD A,C ; retrieve guardian definition byte 2 ADD A,E ; adjust x-coordinate LD (IX+$02),A ; and save JR #91B6 ; proceed to Move the next guardian turn_around: LD A,(HL) ; we're not updating the x-coordinate after all, XOR #E0 ; instead we are switching to consider the other set of four animation-frames LD (HL),A ; [assuming it's an eight-frame bidirectional sprite; if not, then filtering out of unwanted frames is done at the 'Draw the guardians' stage] JR #91B6 ; proceed to Move the next guardian [#9166 to #917E is now free - that's four more bytes than with previous method] This effectively reverses the status of Bit 7 of the guardian definition Byte 0, so that Bit 7 cleared = Moving Right, Bit 7 set = Moving Left. ;right adding #20 #00, #20, #40, #60 The Overflow Flag is clear with each addition but not #60+#20 = #80 (which is minus #80 in two's complement);left adding #E0 (minus #20) #E0 (minus #20), #C0 (minus #40), #A0 (minus #60), #80 (minus #80) Overflow clear with each addition but not #80+#E0 = #60 N.B. You would now need to adjust all the horizontal guardians' data as follows: - Transpose all the half-pages of the eight-frame bidirectional horizontal sprite (e.g. put right-facing Monk at #B400-#B47F, and left-facing Monk at #B480-#B4FF), so that their sprite-frames are arranged within the data in the same way as Willy's - if you don't do this, then they'll all walk backwards!; - Toggle Bit 7 of Byte 0 for all the horizontal guardian classes (i.e. all the relevant entries in pages #A0-#A3), in order to preserve the initial direction of travel upon Willy's entry to each room (e.g. for the green rolly thing in The Bathroom, change the value of #A1D8 from #01 to #81). All of the above is probably not worth the bother just to save another four bytes in the 'Move the guardians' routine. (Although it will save a few more bytes in the 'Draw Willy' routine as well, because there's no longer a need to swap half-pages when using the Flying Pig as the playing sprite in The Nightmare Room.) It was more of an interesting academic exercise to me, and it allowed me to gain a better grasp of the functioning of the Overflow Flag. :) Edited June 4, 2019 by IRF Spider 1 Quote Link to comment Share on other sites More sharing options...
IRF Posted January 12, 2018 Report Share Posted January 12, 2018 (edited) Incidentally, the aforementioned Overflow Flag also doubles up as the Parity Flag. I have wondered for some time about a possible viable use for the Parity Flag. And I've now discovered one, which relates to a possible efficiency for one of Dr Andrew Broad's patches from his 'Advanced MM/JSW Trainer' project. From the accompanying TECHNICA.txt document for that project: ------------------- Chequered cell-grid (JSW48 & MM48 annexes) ------------------- The chequered cell-grid patch changes the colour-attributes of half the cells in the 16x32 playing-area: those whose row- and column-numbers are not both even and not both odd. If, and only if, a cell has black PAPER, then its PAPER is set to blue just before the secondary attributes-buffer (#5C00-5DFF) is copied to video-RAM, and also before any extra-life colour-cycling (which therefore overrides the chequered cell-grid). The following subroutine is called every time-frame, at the point when the game-engine is about to copy the secondary pixels-buffer (#6000-6FFF) to video-RAM (the copying of pixels is completely independent of the copying of colour-attributes; I chose this point because the code that gets overwritten by the subroutine-call - which has to be inserted into the subroutine just before it returns - is the same in both MM and JSW): #87A2: CALL ccg ; MM48 only #89F5: CALL ccg ; JSW48, JSW128, JSW64 ccg: LD HL,#5C00 ; secondary attributes-buffer LD BC,#200 ; going to process 511 bytes (i.e. 32*16 cells) loop: LD A,L AND %00100001 ; if cell-row and cell-column are both even JR Z,skip ; then skip CP %00100001 ; if cell-row and cell-column are both odd JR Z,skip ; then skip LD A,(HL) ; get colour-attribute of current cell AND %00111000 ; extract PAPER-colour JR NZ,skip ; if not black (PAPER 0) then skip SET 3,(HL) ; set current cell to PAPER 1 (blue) skip: INC HL ; next cell DEC BC ; decrement counter LD A,B ; going to check if B and C are both 0... OR C ; ...by bitwise-ORing them together JR NZ,loop ; if BC <> 0 then loop back to process next cell LD HL,#6000 ; the code that was overwritten by the subroutine-call RET The three commands in bold above (six bytes) can be replaced with a three byte jump JP PE,skip which responds to the conditionality of the Parity Flag (thus saving three bytes). N.B. In this circumstance (after the AND #21 gate), the Parity Flag is set if a cell's row and column numbers are both even, or if they are both odd. If the row number is even but the column number is odd, or vice versa, then the Parity Flag is cleared. Edited January 12, 2018 by IRF jetsetdanny and Spider 2 Quote Link to comment Share on other sites More sharing options...
IRF Posted January 12, 2018 Report Share Posted January 12, 2018 An arrow's y-coordinate can be determined on an individual arrow-instance basis, via its specification byte 1 (which is copied to definition byte 2 in the current room's guardian buffer). However, Bit 0 of that specification byte is effectively unused - it must be left clear, or else the arrow when drawn will corrupt the game file at run-time (because erroneous addresses are looked up from the table at page #82 of the code - that's what caused the infamous Attic Bug). In the arrow-drawing code, the following command picks up Byte 2 of the arrow definition as follows: LD E,(IX+$02) If that were to be replaced with: LD A,(IX+$02) AND #FE LD E,A then this would prevent any accidental occurrences of 'Attic Bug' style problems caused by an odd value being assigned for an arrow's y-coordinate. Furthermore, Bit 1 of the arrow's y-coordinate specification byte could then be used for other purposes. (There are plenty of other unused entries in an arrow's definition, but those are all set on an arrow class basis, so they would hold the same values for all left-moving or all right-moving arrows in the original game.) As an example, you could introduce a check, just before making the arrow warning sound when the arrow is about to enter the current room - if Bit 0 of the arrow's definition Byte 2 is set, then bypass the code which generates the firing noise. So in some rooms, Willy gets an audible warning of an impending arrow, but in other rooms he does not! Spider 1 Quote Link to comment Share on other sites More sharing options...
Norman Sword Posted January 12, 2018 Report Share Posted January 12, 2018 Re arrows:- The arrows, my first play with them introduced a second arrow into the same guardian slot. Mentioning wasted bits I decided to implement something I had thought about concerning the arrows. This file shows what the wasted bits can do. Only demonstrated in the bathroom. This arrow demo, is tagged onto a file that keeps on being added to. (it needs deleting) mega volly.tap.tap Spider and IRF 2 Quote Link to comment Share on other sites More sharing options...
IRF Posted January 12, 2018 Report Share Posted January 12, 2018 Cool! (And nasty for Willy!) How many of the room's eight guardian slots does that take up? Quote Link to comment Share on other sites More sharing options...
IRF Posted January 12, 2018 Report Share Posted January 12, 2018 I also noticed that there are apparently random changes to the layouts of the first few rooms! (Oh, and by the way there's a typo in the end-of-game message: "Stike a light, what happened?") Spider 1 Quote Link to comment Share on other sites More sharing options...
Norman Sword Posted January 12, 2018 Report Share Posted January 12, 2018 (edited) The seven empty slots. Which because of the code that double up arrows, gives fourteen arrows in that room. Of note it only uses ONE guardian definition, the others are defined by the position. E.g. the code below is all it takes in the room set up. But first a quick run down of my thoughts... bit 0 gives the arrow bug .but just taking the first 16 values and removing that bug leaves values 00,02,04,06,08,10,12,14 . we also have a feature/bug that stops the code working on the extremes of chars, so values of 00 or 14, should also be avoided.leaving 02,04,06,08,10,12 = 6 values from the first 16. or for the full screen playing area 16*6 values. 96 values from 256 in total. . I fail to see why this is used. If the arrow had been confined to a fixed position within the char. Then only four bits are needed to define an arrow.The other four bits could be used for any multitude of applications. . At present an arrow is defined by a fixed guardian. If a JSW2 style volley is wanted then each arrow would need its own guardian slot/definition. . By juggling those four bits a shift can/could be introduced into the fixed timing phase of the arrow. (done at room set up)This then permits one guardian to be defined as having up to 16 sub classes, just by allowing a phase change on just the one guardian definition. . patched into the room set up, after testing for an arrow type guardian. With no attempt at reducing the code size. ld a,(iy+arrow_y)ld b,aand 15add a,aadd a,a add a,(iy+arrow_x)ld (iy+arrow_x),ald a,band $f0add a,8 ;middle of charld (iy+arrow_y),a Edited January 12, 2018 by Norman Sword Spider and IRF 2 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.