IRF Posted March 1, 2018 Report Share Posted March 1, 2018 (edited) I have managed to amend the code which moves vertical guardians, and also the guardian-drawing and sprite-drawing routines, in such a way that a guardian may safely wrap around past the top/bottom of the screen without crashing into its own 'trail of havoc' (i.e. errant pixels left on the primary screen buffer.Please see the attached. The starting room is 'On Top of the House'. There are now two flag guardians in that room, which have identical definition bytes to each other except that, for one of the flags, the upper and lower bounds have been transposed (causing it to wander up off the top of the screen and back again).I thought it was appropriate to use the flag guardians to illustrate this behaviour, as I managed to achieve this technical novelty by careful use of the F Register flags (the Zero, Carry and Parity Flags were all instrumental).I'll type up the source code when I find the time. But note that the same routine handles both guardians. Vertical Wraparound Guardians.z80 Edited March 3, 2018 by IRF Metalmickey and Spider 2 Quote Link to comment Share on other sites More sharing options...
jetsetdanny Posted March 1, 2018 Report Share Posted March 1, 2018 Interesting stuff, Ian! Congratulations on this novelty :). IRF and Spider 2 Quote Link to comment Share on other sites More sharing options...
Spider Posted March 2, 2018 Report Share Posted March 2, 2018 Excellent. :) IRF 1 Quote Link to comment Share on other sites More sharing options...
IRF Posted March 3, 2018 Author Report Share Posted March 3, 2018 (edited) Horizontal and Vertical Guardians can now wrap around both the vertical and horizontal edges of the screen - see the attached. Note that the horizontal guardians do not change Base Sprite as they wrap around (which they do in the original JSW game engine). Getting both the graphic bytes and attributes to fully behave was quite a challenge. But I got there in the end. :) P.S. In the test file (startup room = Back Door), don't be surprised if the two guardians eventually collide with each other! Horizontal and Vertical Wraparound Guardians.z80 Edited March 3, 2018 by IRF jetsetdanny, Spider and Metalmickey 3 Quote Link to comment Share on other sites More sharing options...
Spider Posted March 3, 2018 Report Share Posted March 3, 2018 That's brilliant. :) It does slightly remind me in a way of how some guardians in T.Ted can behave (this is a positive comment) too. It certainly is an interesting twist on things. :thumbsup: jetsetdanny and IRF 2 Quote Link to comment Share on other sites More sharing options...
jetsetdanny Posted March 3, 2018 Report Share Posted March 3, 2018 Congratulations again, Ian! :) IRF and Spider 2 Quote Link to comment Share on other sites More sharing options...
IRF Posted March 8, 2018 Author Report Share Posted March 8, 2018 (edited) Several things needed to be done to achieve these wraparound guardians. - In the 'Draw a sprite' routine (#9456), I added a command after the code at #9482-85 [original addresses] which moves HL down from one vertical screen-third to the next. The command RES 4, H ensures that the guardian doesn't extend from the secondary pixel-buffer into the primary pixel-buffer, but wraps back round to the top of the former. i.e. a value #70xx is adjusted to #60xx. - Also in 'Draw a sprite', after the INC L command at #9462 [original address], I made a check to see if the right-hand half of the sprite is wrapping round to the left-hand side of the screen: LD A,L AND #1F If that sets the Zero Flag, then subtract #20 and load back to L, draw the graphic byte under consideration and then add #20 again before moving down to draw the next pair of graphic bytes on the next pixel-row. - The 'Draw a guardian' routine also needs to be adjusted, in a similar manner to the above, to keep the guardian's colour attributes within the same character row when it is wrapping round past the right-hand edge of the screen, and also to prevent its colour attribute being written permanently onto the primary attribute buffer when it is wrapping past the bottom of the screen. In the latter case, a RES 1, H command is used to adjust a value for the attribute coordinates of #5Exx to #5Cxx, which is back within the valid range. - In the 'Move the guardians' routine, a simple adjustment has been made for horizontal guardians at #9151 and #9174 [original addresses], in order to prevent the guardians from changing sprite (which previously occurred because the DEC (IX+$02) / INC (IX+$02) commands meant that the adjustment of the x-coordinate in Bits 0-4 was spilling over into the Base Sprite setting in Bits 5-7). Preventing this was achieved by loading the guardian byte definition byte 02 into both the Accumulator and the C register, then adjusting A accordingly for the appropriate direction of movement (e.g. applying a DEC A or an INC A, although in the test file uploaded above I have implemented the shared left/right movement code for guardians), and then doing the following sequence: XOR C AND #1F XOR C before reloading the result in A back to IX+$02. That adjusts the x-coordinate from #00 to #1F or vice versa, whilst leaving the Base Sprite setting unaltered. - The changes to the vertical guardians part of the 'Move the guardians' routine are the 'piece de resistance'! After the code which updates the animation frame for vertical guardians (or not, depending on the animation speed), I have devised the following [starts at #9193 in the original code], which was built upon an earlier draft of this part of the routine provided by Norman Sword: (Note that HL is pointing at guardian definition byte 00 going into this, after a pair of commands PUSH IX / POP HL.) INC HL INC HL INC HL ;HL points at guardian definition byte 03 (pixel y-coordinate) LD A, (HL) INC HL ;HL now points at guardian definition byte 04 (vertical speed) ADD A, (HL) LD B, A ;A and B now both hold the updated y-coordinate LD C, #00 ;C will be used to keep track of various flags LD D, (IX+$06) ;upper bound of guardian in D LD E, (IX+$07) ;lower bound of guardian in E CP D ;has the guardian moved past its upper bound? RR C ;rotate a raised flag into C if so CP E ;has the guardian moved past its lower bound? RR C ;rotate a lowered flag into C if so [or if it is exactly at its upper bound, but that situation is dealt with separately below] LD A, E ;load the guardian's lower bound into A CP D ;if this is a normal vertical guardian, then E>D; if it is a wraparound, then D>E RR C ;rotate a flag into C (raised only for a wraparound vertical guardian) BIT 7, (HL) ;is the guardian currently moving downwards? JR Z, down ;if so, skip the next command LD A, D ;otherwise, load the guardian's upper bound into A (the guardian is currently moving upwards) down: CP B ;has the guardian exactly reached the extent of its permitted range for the current direction of travel? JR Z, change_direction ;if so, then jump to toggle the direction of travel RRC C ;this command doesn't change the value in C, it merely test the status of the Parity Flag JP PO, y_update ;If Parity is odd, then jump to update y-coordinate with the value stored in B (the guardian is within its permitted range) LD B, A ;otherwise, if Parity is even, then the guardian has exceeded its permitted range, so load up B with the extent of its permitted range for the current direction of travel change_direction: LD A, (HL) ;load vertical speed into A NEG ;toggle it to reverse the guardian's direction of travel LD (HL), A ;and load back into guardian byte 04 y_update: DEC HL ;HL points at guardian definition byte 03 again (pixel y-coordinate) LD (HL), B ;update the guardian's y-coordinate with the value stored in B That is then directly followed by (or a jump is made to) the existing command LD DE, #0008 at #91B6. I'll add some commentary about the use of the Parity Flag when I get more time. Edited March 8, 2018 by IRF jetsetdanny and Spider 2 Quote Link to comment Share on other sites More sharing options...
IRF Posted March 8, 2018 Author Report Share Posted March 8, 2018 More analysis on the use of the Parity Flag in the above, for handling wraparound vertical guardians: C starts off holding 00000000 (Parity Even) Normal vertical guardian - three scenarios (other than a guardian located exactly on one of its bounds, which is dealt with by a separate check): TOP OF SCREEN GUARDIAN POSITION UPPER BOUND IN D LOWER BOUND IN E BOTTOM OF SCREEN C=01100000; Parity Even, guardian is out of bounds TOP OF SCREEN UPPER BOUND IN D GUARDIAN POSITION LOWER BOUND IN E BOTTOM OF SCREEN C=00100000; Parity Odd, guardian is within its permitted bounds TOP OF SCREEN UPPER BOUND IN D LOWER BOUND IN E GUARDIAN POSITION BOTTOM OF SCREEN C=00000000; Parity Even, guardian is out of bounds Wraparound vertical guardian - three scenarios (other than a guardian located exactly on one of its bounds, which is dealt with by a separate check): TOP OF SCREEN GUARDIAN POSITION LOWER BOUND IN E UPPER BOUND IN D BOTTOM OF SCREEN C=11100000; Parity Odd, guardian is within its permitted bounds TOP OF SCREEN LOWER BOUND IN E GUARDIAN POSITION UPPER BOUND IN D BOTTOM OF SCREEN C=10100000; Parity Even, guardian is out of bounds TOP OF SCREEN LOWER BOUND IN E UPPER BOUND IN D GUARDIAN POSITION BOTTOM OF SCREEN C=10000000; Parity Odd, guardian is within its permitted bounds Spider and jetsetdanny 2 Quote Link to comment Share on other sites More sharing options...
IRF Posted March 9, 2018 Author Report Share Posted March 9, 2018 RRC C ;this command doesn't change the value in C, it merely tests the status of the Parity Flag Just to clarify, the above isn't strictly true - the eight bits of C are rotated rightwards once by the operation. What I meant to say is that the RRC C command doesn't alter the balance of the number of set/reset bits in C, and so the balance of parity isn't changed by the operation; rather it tests what that balance is (i.e. whether an odd or an even number of bits are set), and then the conditionality of the subsequent jump is determined on that basis. Whereas the three preceding RR C commands did determine the balance of parity in C (because RR is a nine-bit rotation, bringing the Carry Flag into Bit 7 of the register), the RRC is an eight-bit 'internal' rotation of C (it also copies Bit 0 of C into the Carry Flag, but that is of no consequence here). N.B. It's easy to get mixed up between "RR C" and "RRC" - perhaps I should have swapped the roles of the B and C registers to reduce the prospect for confusion!? Spider and jetsetdanny 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.