'//// SKATE ENGINE 1.0 \\\\' '//// AUTHOR: JAMES KOHER \\\\' '//// NOVEMBER 2022 \\\\' '*DESCRIPTION*' '// SCROLLING ENGINE WITH FULL-SQUARE HARD BLOCKS, HARD RAMPS OF VARIOUS SLOPES, SNAP-CORRECTING VERTICAL PARTIAL HARD RAMP BLOCKS, AND SOFT-BLOCKS WITH ONE-WAY HARD TOPS '// IMPLEMENTABLE PHYSICS: CUSTOMIZABLE SLOPE-NORMALIZED GRAVITY, COLLSION-IMPULSE, INPUT, AND FRICTION '// SLOPE-NORMALIZTION OCCURS BOTH ON LANDING (ENVIRONMENTAL COLLISION CORRECTION) '// AND EVERYTIME THE GROUND-SLOPE IS NON-ZERO (VY_UPDATE) '// VELOCITY LIMIT FUNCTION IMPLEMENTATION IS CUSTOMIZABLE; CURRENTLY THE MAX_V AND MAX_FALL_V ARE THE SAME WHILE THE MAXV_INPUT IS HALF THE VALUE OF THE OTHERS '// MOTION AND INPUT NORMALIZTION ARE HANDLED BY PROPORTIONALLY SCALING ACCELERATION AND VELOCITY TO THE GROUND_SLOPE,VIA SIN AND COS FUNCTIONS. '// INPUT ACCELERATION IS LIMITED WHEN THE MAX-DRIVEN-VELOCITY (MAXV_INPUT) IN ANY DIRECTION IS REACHED. '// A CUSTOMIZABLE TURN-ACCELERATION HAS BEEN IMPLEMENTED '// AS WELL AS THE OBLIGATORY COYOTE-TIME '// COLLSION CORRECTION: '// FULL-SQUARE HARD BLOCK: '// CHECKS WHICH CORNER POINTS HAVE PENETRATED HARD BLOCKS TO DETERMINE THE NATURE OF THE COLLISION '// IF TWO OPPOSITE CORNERS HAVE PENETRATED THEN IT IS IN AN INSIDE-CORNER CASE, AND CORRECTS TO THE APPROPRIATE CORNER, LIMITNG BOTH VX & VY TO '0' AND UPDATES THE OBJECT STATES (I.E. GROUNDED,SLOPE_GROUND,J_IND,ETC.) '// IF TWO ADJACENT CORNERS HAVE PENETRATED THEN IT IS CORRECTED TO THE OPPOSITE SIDE OF THE TILE(S) FROM THE DIRECTION OF THE INCOMING VELOCITY AND CORRECTS THE VELOCITY AND OBJECT STATES ACCORDINGLY '// IF ONLY ONE HAS PENETRATED THEN THE VELOCITIES AND 'VELOCITY-BASED IN-TILE PENETRATION POSTIONS' ARE COMPARED IN EACH DIRECTION TO DETERMINE '// WHICH SIDE WAS CROSSED BY THE OFFENDING POINT, AND ONE-OFF MOD-CORRECTS TO THAT 'EDGE' AND CORRECTS THE VELOCITY AND OBJECT STATES ACCORDINGLY '// RAMPS: '// MAY BE MADE OF MULTIPLE TILES/CHARS. EACH RAMP TILE HAS A ONE-WAY HARD TOP '// EACH RAMP CHAR# WILL BE ASSOCIATED WITH A SLOPE AND LEFT-SIDE, Y-INTERCEPT VALUE (TI_Y, MAY BE OFF-TILE), GLOBAL POSITION (T_X,T_Y) WILL BE DETERMINED VIA POSITION-MODULO DURING IN-TILE COLLISION '// IN-RAMP-COLLISION IS DETERMINED BY CHECKING IF OBJECT'S BOTTOM-MIDDLE PIXEL-POSTION IS BELOW SLOPE FOR SLOPES WITH AN ABSOLUTE VALUE UP TO 45* AND THE SLOPE-APPROPRIATE SIDE-CENTER PIXEL WHEN THE ABSOLUTE VALUE OF SLOPE IS OVER PI/4 '// IN-RAMP-CORRECTION: CORRECTS VERTICALLY FOR SLOPES THROUGH PI/4, ELSE POSITION IS CORRECTED HORIZONTALLY '// A NORMALIZED IMPULSE-CORRECTION IS USED TO DETERMINE THE RESULTANT VELOCITIES '// ONE-WAY BLOCKS: '// THE 'HARD TOP' MAY ONLY BE PASSED WHEN THE VELOCITY IS NEGATIVE (UPWARD) '// ONLY THE BOTTOM_CENTER PIXEL POSITION IS CHECKED (FOR COMPATIBILITY WITH RAMP INTERFACES) '// OTHERWISE, PASSING THE LID TRIGGERS A CORRECTION/GROUNDED-STATE AND SETS PS_Y TO THE TOP EDGE'S POSITION, KEEPS THE CURRENT PS_X AND NIXES THE Y-VELOCITY GAMEPAD 1 '// CONTROL ARRAY FOR SPRITE ANIMATIONS, DIM GLOBAL SKTR_ANIM(11,6) '// 0=SPRITE # , 1=SPRITE INDICATOR FLAG , 2=ANIMATION TILE # , 3=SPRITE X-VALUE , 4=SPRITE Y-VALUE , 5=HOR. FLIP-VALUE , 6=VERT. FLIP_VALUE '// SPRITE NUMBERS (0) EMPTY FOR AN OVER-BUFFER INB, (1-2) AUX HEAD SPRITES (3) MAIN PLAYER SPRITE, (4) PUSH-FOOT SPRITE , (5-8) BOARD SPRITES, (9-10) WHEEL SPRITES, AND (11) IS AN EXTRA UNDER-BUFFER GLOBAL PX,PY,PS_X,PS_Y,P_X,P_Y,D_X,D_Y,PX_,PY_ GLOBAL SCRL_X,SCRL_Y,L_SCRL_MARGIN,R_SCRL_MARGIN GLOBAL VX,VY,MAX_V,MAXV_INPUT,MAX_FALL_V GLOBAL D_INPUT,IS_DEC,IS_TURN,F_ACC,FT_ACC,F_FRICTION,F_GRAVITY,D_GRAVITY GLOBAL T_CHAR,T_X,T_Y,TI_Y,RAMP_SLOPE,ON_RAMP,SIGN_V_PAR,SIGN_VX_PAR,SIGN_VY_PAR GLOBAL SLOPE_GROUND,SLOPE_GROUND_C,SLOPE_VEL,SLOPE_VEL_REF,Q_SLOPE_VEL,Q_SLOPE_GROUND,SLOPE_GROUND_REF,SLOPE_IMP_REF GLOBAL VALID_COLL,GROUNDED,COYOTETIME GLOBAL J_ENABLE,J_IND,MAX_JUMP_V,J_COUNT,MAX_J_COUNT GLOBAL TL,TR,BL,BR,BC,LC,RC,UNDER_BC,ABOVE_TL,ABOVE_TR,UNDER_BL,UNDER_BR,OUT_TL,OUT_TR,OUT_BL,OUT_BR,OUT_LC,OUT_RC GLOBAL ANIM_TICK,FRAMETICK CELL SIZE 1,1 '// INITIALIZE SPRITES FOR I=0 TO 11 SKTR_ANIM(I,0)=I IF I=3 THEN SPRITE I SIZE 1 IF I=4 OR I=7 OR I=8 OR I=11 THEN SKTR_ANIM(I,1)=0 ELSE SKTR_ANIM(I,1)=1 SPRITE I PAL 0 PRIO 1 NEXT I '// SET STATIC ANIMATION TILES SKTR_ANIM(4,2)=41 '// HORIZONTAL SCROLL MARGINS: L_SCRL_MARGIN=64 R_SCRL_MARGIN=79.99 '// MAX VELOCIES: NOTE THAT MAX_V IS A MAXIMUM TOTAL VELOCITY (VECTOR OF X+Y) FOR 'GROUNDED' STATES ONLY AND THE MAXIMUM FALL VELOCITY IN JUST THE 'Y' WHEN NOT 'GROUNDED' MAX_V=3 MAX_FALL_V=MAX_V MAXV_INPUT=1.5 F_GRAVITY=0.1 D_GRAVITY=0.025 F_ACC=0.15 FT_ACC=0.2 F_FRICTION=-0.01 MAX_JUMP_V=-1.75 MAX_J_COUNT=22 PX=16.1 PY=0 SCRL_X=0 PS_X=PX+SCRL_X PS_Y=PY '// PRINT INITIAL SCREEN BG 1 IF SCRL_X>15 THEN BG COPY ((SCRL_X/16)-1),0,12,8 TO ((SCRL_X/16)-1),0 ELSE BG COPY (SCRL_X/16),0,12,8 TO (SCRL_X/16),0 SCROLL 1,SCRL_X,0 '// TEST SPRITE 'SPRITE 0 SIZE 1 'SPRITE 0,PX,PY,2 '// MAIN GAME LOOP DO '//// PLAYER CONTROL AND MOVEMENT \\\\' '//LEFT/RIGHT ACTIVE INPUT SAVED AS D_INPUT, ELSE IT TAKES ON DIRECTION OF PASSIVE HORIZONTAL MOTION\\' IF LEFT(0) THEN IF D_INPUT<>-1 THEN ANIM_TICK=0 D_INPUT=-1 ELSE IF RIGHT(0) THEN IF D_INPUT<>1 THEN ANIM_TICK=0 D_INPUT=1 END IF '// IF NO DIRECTION GIVEN THEN DECELERATE IF RIGHT(0)=0 AND LEFT(0)=0 THEN IS_TURN=0 D_INPUT=0 IF GROUNDED=1 AND ABS(VX)>=0.01 THEN IS_DEC=1 ELSE IS_DEC=0 ELSE IS_DEC=0 END IF '//IF ACTIVELY CHANGING DIRETION WHILE IN MOTION, THEN USE TURN ACC.\\' IF D_INPUT<>0 AND ABS(VX)>=0.2 AND SGN(VX)<>SGN(D_INPUT) THEN IS_TURN=1 IS_DEC=0 ELSE IF D_INPUT=0 OR SGN(VX)=SGN(D_INPUT) THEN IS_TURN=0 END IF '//TESTS FOR CANCELLING AND REINSTATING JUMP\\' IF BUTTON(0,0)=0 THEN IF J_IND=1 THEN J_IND=0 J_COUNT=0 END IF IF GROUNDED=1 OR (GROUNDED=0 AND SGN(VY)>0) THEN J_ENABLE=1 END IF '//TEST FOR JUMP BUTTON PRESS WHEN ON GROUND\\' IF BUTTON(0,0) AND J_ENABLE=1 AND (GROUNDED=1 OR COYOTETIME<10) THEN J_IND=1 J_ENABLE=0 J_COUNT=0 GROUNDED=0 ON_RAMP=0 COYOTETIME=10 IF ABS(SLOPE_GROUND)=PI/2 THEN IF SLOPE_GROUND>0 THEN SKTR_ANIM(3,5)=0 ELSE SKTR_ANIM(3,5)=1 SKTR_ANIM(3,6)=0 END IF SLOPE_GROUND=0 ANIM_TICK=0 END IF '// UPDATE VELOCITY AND POSITION THEN CHECK FOR COLLISIONS AND CORRECT, THEN UPDATE ANIMATIONS CALL UPD_VELOCITY CALL UPD_PX CALL UPD_PY CALL ENV_COLL_CHECK CALL UPDATE_ANIM '// TEST SPRITE 'SPRITE 0,PX,PY,2 '// OPTIONAL DEBUG PRINTOUT 'CALL DEBUG_PO '// UPDATE FRAMETICK INC FRAMETICK WAIT 1 LOOP SUB UPDATE_ANIM '// ANIMATION CANCELS IF ANIM_TICK=0 OR SLOPE_GROUND<>0 THEN SKTR_ANIM(4,1)=0 IF ABS(SLOPE_GROUND)<0.78 OR ABS(SLOPE_GROUND)>0.79 THEN SKTR_ANIM(1,1)=0 SKTR_ANIM(2,1)=0 END IF '// GROUND ANIMATIONS IF GROUNDED=1 THEN IF SLOPE_GROUND=0 THEN SKTR_ANIM(3,3)=PX SKTR_ANIM(3,4)=PY-3 SKTR_ANIM(3,6)=0 SKTR_ANIM(5,2)=55 SKTR_ANIM(6,2)=56 SKTR_ANIM(5,3)=PX SKTR_ANIM(5,4)=PY+8 SKTR_ANIM(6,3)=PX+8 SKTR_ANIM(6,4)=PY+8 SKTR_ANIM(5,5)=0 SKTR_ANIM(5,6)=0 SKTR_ANIM(6,5)=0 SKTR_ANIM(6,6)=0 IF D_INPUT=0 THEN SKTR_ANIM(4,1)=0 SKTR_ANIM(3,2)=2 IF VX>0 THEN SKTR_ANIM(3,5)=0 ELSE IF VX<0 THEN SKTR_ANIM(3,5)=1 END IF ELSE IF D_INPUT>0 THEN SKTR_ANIM(3,5)=0 IF ANIM_TICK MOD 30=0 THEN SKTR_ANIM(3,2)=6 ELSE IF ANIM_TICK MOD 30=8 THEN SKTR_ANIM(3,2)=8 SKTR_ANIM(4,1)=1 ELSE IF ANIM_TICK MOD 30=12 OR ANIM_TICK MOD 30=24 THEN SKTR_ANIM(3,2)=10 ELSE IF ANIM_TICK MOD 30=16 THEN SKTR_ANIM(4,1)=0 SKTR_ANIM(3,2)=12 END IF ELSE SKTR_ANIM(3,5)=1 IF ANIM_TICK MOD 30=0 THEN SKTR_ANIM(3,2)=6 ELSE IF ANIM_TICK MOD 30=8 THEN '// TURN ON PUSH-LEG SPRITE SKTR_ANIM(4,1)=1 SKTR_ANIM(3,2)=8 ELSE IF ANIM_TICK MOD 30=12 OR ANIM_TICK MOD 30=24 THEN SKTR_ANIM(3,2)=10 ELSE IF ANIM_TICK MOD 30=16 THEN '// TURN OFF PUSH-LEG SPRITE SKTR_ANIM(4,1)=0 SKTR_ANIM(3,2)=12 END IF END IF '// PUSH-FOOT CONTROL IF SKTR_ANIM(4,1)=1 THEN IF SKTR_ANIM(3,5)=0 THEN SKTR_ANIM(4,5)=0 IF ANIM_TICK MOD 30<12 THEN SKTR_ANIM(4,3)=PX+8 ELSE SKTR_ANIM(4,3)=PX+4 ELSE SKTR_ANIM(4,5)=1 IF ANIM_TICK MOD 30<12 THEN SKTR_ANIM(4,3)=PX ELSE SKTR_ANIM(4,3)=PX+4 END IF SKTR_ANIM(4,4)=PY+14 END IF ELSE IF SLOPE_GROUND<0 THEN SKTR_ANIM(3,5)=0 SKTR_ANIM(5,5)=0 SKTR_ANIM(6,5)=0 '// CONTROL FOR -1/2 (M) SLOPE IF SLOPE_GROUND<-0.45 AND SLOPE_GROUND>-0.47 THEN IF VY<=0 THEN SKTR_ANIM(3,2)=14 ELSE SKTR_ANIM(3,2)=71 SKTR_ANIM(3,3)=PX-2 SKTR_ANIM(3,4)=PY-1 SKTR_ANIM(3,6)=0 SKTR_ANIM(5,2)=39 SKTR_ANIM(6,2)=40 SKTR_ANIM(5,3)=PX SKTR_ANIM(5,4)=PY+8 SKTR_ANIM(6,3)=PX+8 SKTR_ANIM(6,4)=PY+8 '// CONTROL FOR -1 (M) SLOPE ELSE IF SLOPE_GROUND<-0.77 AND SLOPE_GROUND>-0.79 THEN '// HEAD ANIMATION SKTR_ANIM(2,1)=1 SKTR_ANIM(1,1)=1 IF VY<=0 THEN SKTR_ANIM(1,2)=45 SKTR_ANIM(2,2)=61 SKTR_ANIM(1,5)=0 SKTR_ANIM(2,5)=0 SKTR_ANIM(1,3)=PX-1 SKTR_ANIM(1,4)=PY SKTR_ANIM(2,3)=PX-9 SKTR_ANIM(2,4)=PY ELSE SKTR_ANIM(1,2)=61 SKTR_ANIM(2,2)=45 SKTR_ANIM(1,5)=1 SKTR_ANIM(2,5)=1 SKTR_ANIM(1,3)=PX-3 SKTR_ANIM(1,4)=PY SKTR_ANIM(2,3)=PX-11 SKTR_ANIM(2,4)=PY END IF '// BODY ANIMATION SKTR_ANIM(3,2)=46 SKTR_ANIM(3,3)=PX-5 SKTR_ANIM(3,4)=PY+2 SKTR_ANIM(3,6)=0 '// BOARD ANIMATION SKTR_ANIM(5,2)=57 SKTR_ANIM(6,2)=42 SKTR_ANIM(5,3)=PX-2 SKTR_ANIM(5,4)=PY+14 SKTR_ANIM(6,3)=PX+6 SKTR_ANIM(6,4)=PY+6 '// CONTROL FOR -2 (M) SLOPE ELSE IF SLOPE_GROUND<-1 AND SLOPE_GROUND>-1.2 THEN IF VY<=0 THEN SKTR_ANIM(3,2)=43 ELSE SKTR_ANIM(3,2)=69 SKTR_ANIM(3,3)=PX-3 SKTR_ANIM(3,4)=PY+2 SKTR_ANIM(3,6)=0 SKTR_ANIM(5,2)=54 SKTR_ANIM(6,2)=38 SKTR_ANIM(5,3)=PX+5 SKTR_ANIM(5,4)=PY+10 SKTR_ANIM(6,3)=PX+5 SKTR_ANIM(6,4)=PY+2 '// CONTROL FOR -PI/2 (R) ELSE IF SLOPE_GROUND<-1.4 AND SLOPE_GROUND>-1.6 THEN SKTR_ANIM(3,2)=36 IF VY<=0 THEN SKTR_ANIM(3,6)=0 ELSE SKTR_ANIM(3,6)=1 SKTR_ANIM(3,3)=PX-3 SKTR_ANIM(3,4)=PY SKTR_ANIM(3,5)=0 SKTR_ANIM(5,2)=33 SKTR_ANIM(6,2)=49 SKTR_ANIM(5,3)=PX+8 SKTR_ANIM(5,4)=PY SKTR_ANIM(6,3)=PX+8 SKTR_ANIM(6,4)=PY+8 END IF ELSE SKTR_ANIM(3,5)=1 SKTR_ANIM(5,5)=1 SKTR_ANIM(6,5)=1 IF SLOPE_GROUND>0.45 AND SLOPE_GROUND<0.47 THEN IF VY<=0 THEN SKTR_ANIM(3,2)=14 ELSE SKTR_ANIM(3,2)=71 SKTR_ANIM(3,3)=PX+2 SKTR_ANIM(3,4)=PY-1 SKTR_ANIM(3,6)=0 SKTR_ANIM(5,2)=40 SKTR_ANIM(6,2)=39 SKTR_ANIM(5,3)=PX SKTR_ANIM(5,4)=PY+8 SKTR_ANIM(6,3)=PX+8 SKTR_ANIM(6,4)=PY+8 ELSE IF SLOPE_GROUND>0.77 AND SLOPE_GROUND<0.79 THEN '// HEAD ANIMATION SKTR_ANIM(2,1)=1 SKTR_ANIM(1,1)=1 IF VY<=0 THEN SKTR_ANIM(1,2)=61 SKTR_ANIM(2,2)=45 SKTR_ANIM(1,5)=1 SKTR_ANIM(2,5)=1 SKTR_ANIM(1,3)=PX+17 SKTR_ANIM(1,4)=PY SKTR_ANIM(2,3)=PX+9 SKTR_ANIM(2,4)=PY ELSE SKTR_ANIM(1,2)=45 SKTR_ANIM(2,2)=61 SKTR_ANIM(1,5)=0 SKTR_ANIM(2,5)=0 SKTR_ANIM(1,3)=PX+19 SKTR_ANIM(1,4)=PY SKTR_ANIM(2,3)=PX+11 SKTR_ANIM(2,4)=PY END IF '// BODY ANIMATION SKTR_ANIM(3,2)=46 SKTR_ANIM(3,3)=PX+5 SKTR_ANIM(3,4)=PY+2 SKTR_ANIM(3,6)=0 '// BOARD ANIMATION SKTR_ANIM(5,2)=42 SKTR_ANIM(6,2)=57 SKTR_ANIM(5,3)=PX+2 SKTR_ANIM(5,4)=PY+6 SKTR_ANIM(6,3)=PX+10 SKTR_ANIM(6,4)=PY+14 ELSE IF SLOPE_GROUND>1 AND SLOPE_GROUND<1.2 THEN IF VY<=0 THEN SKTR_ANIM(3,2)=43 ELSE SKTR_ANIM(3,2)=69 SKTR_ANIM(3,3)=PX+3 SKTR_ANIM(3,4)=PY+2 SKTR_ANIM(3,6)=0 SKTR_ANIM(5,2)=54 SKTR_ANIM(6,2)=38 SKTR_ANIM(5,3)=PX+3 SKTR_ANIM(5,4)=PY+10 SKTR_ANIM(6,3)=PX+3 SKTR_ANIM(6,4)=PY+2 ELSE IF SLOPE_GROUND>1.4 AND SLOPE_GROUND<1.6 THEN SKTR_ANIM(3,2)=36 IF VY<=0 THEN SKTR_ANIM(3,6)=0 ELSE SKTR_ANIM(3,6)=1 SKTR_ANIM(3,3)=PX+3 SKTR_ANIM(3,4)=PY SKTR_ANIM(5,2)=33 SKTR_ANIM(6,2)=49 SKTR_ANIM(5,3)=PX SKTR_ANIM(5,4)=PY SKTR_ANIM(6,3)=PX SKTR_ANIM(6,4)=PY+8 END IF END IF END IF ELSE SKTR_ANIM(1,1)=0 SKTR_ANIM(2,1)=0 '// UNGROUNDED ANIMATION CONTROL IF ABS(SLOPE_GROUND)<>PI/2 THEN IF D_INPUT>0 THEN SKTR_ANIM(3,5)=0 ELSE IF D_INPUT<0 THEN SKTR_ANIM(3,5)=1 ELSE IF VX>0.01 THEN SKTR_ANIM(3,5)=0 ELSE IF VX<-0.01 THEN SKTR_ANIM(3,5)=1 END IF END IF SKTR_ANIM(5,2)=55 SKTR_ANIM(6,2)=56 SKTR_ANIM(5,3)=PX SKTR_ANIM(5,4)=PY+8 SKTR_ANIM(6,3)=PX+8 SKTR_ANIM(6,4)=PY+8 IF J_IND=0 THEN SKTR_ANIM(5,5)=0 SKTR_ANIM(6,5)=0 END IF IF J_IND=1 AND COYOTETIME<25 THEN SKTR_ANIM(3,2)=14 IF SKTR_ANIM(3,5)=0 THEN SKTR_ANIM(3,3)=PX-1 SKTR_ANIM(3,4)=PY-2 SKTR_ANIM(5,2)=39 SKTR_ANIM(6,2)=40 SKTR_ANIM(5,5)=0 SKTR_ANIM(6,5)=0 ELSE SKTR_ANIM(3,3)=PX+1 SKTR_ANIM(3,4)=PY-2 SKTR_ANIM(5,2)=40 SKTR_ANIM(6,2)=39 SKTR_ANIM(5,5)=1 SKTR_ANIM(6,5)=1 END IF ELSE IF VY<0.75 THEN SKTR_ANIM(3,2)=4 SKTR_ANIM(3,3)=PX SKTR_ANIM(3,4)=PY-3 SKTR_ANIM(5,2)=55 SKTR_ANIM(6,2)=56 SKTR_ANIM(5,5)=0 SKTR_ANIM(6,5)=0 ELSE SKTR_ANIM(3,2)=2 SKTR_ANIM(3,3)=PX SKTR_ANIM(3,4)=PY-3 END IF ELSE IF SLOPE_GROUND<0 THEN SKTR_ANIM(3,2)=36 IF VY<=0 THEN SKTR_ANIM(3,6)=0 ELSE SKTR_ANIM(3,6)=1 SKTR_ANIM(3,3)=PX-3 SKTR_ANIM(3,4)=PY SKTR_ANIM(3,5)=0 SKTR_ANIM(5,2)=33 SKTR_ANIM(6,2)=49 SKTR_ANIM(5,3)=PX+8 SKTR_ANIM(5,4)=PY SKTR_ANIM(6,3)=PX+8 SKTR_ANIM(6,4)=PY+8 ELSE SKTR_ANIM(3,2)=36 IF VY<=0 THEN SKTR_ANIM(3,6)=0 ELSE SKTR_ANIM(3,6)=1 SKTR_ANIM(3,3)=PX+3 SKTR_ANIM(3,4)=PY SKTR_ANIM(5,2)=33 SKTR_ANIM(6,2)=49 SKTR_ANIM(5,3)=PX SKTR_ANIM(5,4)=PY SKTR_ANIM(6,3)=PX SKTR_ANIM(6,4)=PY+8 END IF END IF END IF '// FLIP PLAYER SPRITES AND PRINT INDICATED ANIMATIONS TO THEIR DETERMINED LOCATIONS FOR I=1 TO 10 IF I<7 AND SKTR_ANIM(I,1)=1 THEN IF SKTR_ANIM(I,5)=0 THEN IF SKTR_ANIM(I,6)=0 THEN SPRITE I FLIP 0,0 ELSE SPRITE I FLIP 0,1 ELSE IF SKTR_ANIM(I,6)=0 THEN SPRITE I FLIP 1,0 ELSE SPRITE I FLIP 1,1 END IF END IF IF SKTR_ANIM(I,1)=1 THEN SPRITE I,SKTR_ANIM(I,3),SKTR_ANIM(I,4),SKTR_ANIM(I,2) ELSE SPRITE OFF I NEXT I INC ANIM_TICK END SUB SUB SIDE_CELLCHECK(X,Y) OUT_TL=MCELL.C(((X-1)/16),(Y/16)) OUT_TR=MCELL.C(((X+16)/16),(Y/16)) OUT_BL=MCELL.C(((X-1)/16),((Y+15)/16)) OUT_BR=MCELL.C(((X+16)/16),((Y+15)/16)) END SUB SUB BOX_CELLCHECK(X,Y) '//INSIDE CORNERS OF SPRITE TL=MCELL.C((X/16),(Y/16)) TR=MCELL.C(((X+15)/16),(Y/16)) BL=MCELL.C((X/16),((Y+15)/16)) BR=MCELL.C(((X+15)/16),((Y+15)/16)) END SUB SUB CENTER_CELLCHECK(X,Y) '// BOTTOM, LEFT AND MIDDLE PIXEL POSITIONS AND THEIR 'OUTSIDE' COUNTERTPARTS BC=MCELL.C(((X+7.5)/16),((Y+15)/16)) UNDER_BC=MCELL.C(((X+7.5)/16),((Y+16)/16)) LC=MCELL.C((X/16),((Y+7.5)/16)) OUT_LC=MCELL.C(((X-1)/16),((Y+7.5)/16)) RC=MCELL.C(((X+15)/16),((Y+7.5)/16)) OUT_RC=MCELL.C(((X+16)/16),((Y+7.5)/16)) END SUB SUB UNDER_CELLCHECK(X,Y) '// THE 'UNDER' POSITIONS BELOW THE LEFT-MOST AND RIGHT-MOST CORNERS OF THE SQUARE UNDER_BL=MCELL.C((X/16),((Y+16)/16)) UNDER_BR=MCELL.C(((X+15)/16),((Y+16)/16)) END SUB SUB UPD_VELOCITY '//DETERMINE JUMP/FALL/RAMP STATE AND APPLY GRAVITY ACCORDINGLY CALL GROUND_CHECK CALL DIR_CHECK IF J_IND=1 THEN CALL JUMP ELSE IF GROUNDED=0 THEN CALL FALL_GRAVITY(F_GRAVITY) ELSE IF ON_RAMP=1 THEN IF (SGN(SLOPE_GROUND)=D_INPUT OR D_INPUT=0) THEN CALL FALL_GRAVITY(F_GRAVITY) ELSE CALL FALL_GRAVITY(D_GRAVITY) CALL GROUND_IMPULSE(VX,VY) END IF IF GROUNDED=1 THEN '//DETERMINE HORIZONTAL ACC. TYPE TO BE USED AND UPDATE VX IF IS_DEC+IS_TURN=0 THEN IF SLOPE_GROUND=0 THEN IF ABS(VX)MAXV_INPUT THEN VX=SGN(VX)*MAXV_INPUT END IF ELSE IF VX*VX+VY*VY<=MAXV_INPUT*MAXV_INPUT THEN VX=VX+D_INPUT*F_ACC*COS(SLOPE_GROUND) VY=VY+D_INPUT*F_ACC*SIN(SLOPE_GROUND) CALL VEL_LIMIT(MAXV_INPUT) ELSE CALL VEL_LIMIT(MAX_V) END IF END IF ELSE IF IS_TURN=1 THEN IF SLOPE_GROUND=0 THEN VX=VX+D_INPUT*FT_ACC IF ABS(VX)<0.2 THEN IS_TURN=0 ELSE VX=VX+D_INPUT*FT_ACC*COS(SLOPE_GROUND) VY=VY+D_INPUT*FT_ACC*SIN(SLOPE_GROUND) IF ABS(VX)+ABS(VY)<=0.2 THEN IS_TURN=0 END IF ELSE IF IS_DEC=1 THEN IF SLOPE_GROUND=0 THEN VX=VX+SGN(VX)*F_FRICTION IF ABS(VX)<0.01 THEN VX=0 D_INPUT=0 IS_DEC=0 END IF ELSE CALL VEL_LIMIT(MAX_V) END IF END IF ELSE IF IS_DEC+IS_TURN=0 THEN IF ABS(VX)MAXV_INPUT THEN VX=SGN(VX)*MAXV_INPUT END IF ELSE IF IS_TURN=1 THEN VX=VX+D_INPUT*FT_ACC IF ABS(VX)<0.2 THEN IS_TURN=0 ELSE IF IS_DEC=1 THEN VX=VX+SGN(VX)*F_FRICTION IF ABS(VX)<0.01 THEN VX=0 D_INPUT=0 IS_DEC=0 END IF END IF END IF END SUB SUB GROUND_CHECK '// CHECK FOR CHANGE IN GROUND STATE AND UPDATE COYOTETIME CALL UNDER_CELLCHECK(PS_X,PS_Y) CALL CENTER_CELLCHECK(PS_X,PS_Y) CALL SIDE_CELLCHECK(PS_X,PS_Y) IF ON_RAMP=0 AND (UNDER_BL<164 AND UNDER_BR<164 AND UNDER_BC<128) THEN IF GROUNDED=1 THEN ANIM_TICK=0 GROUNDED=0 IF ABS(SLOPE_GROUND)<>PI/2 THEN SLOPE_GROUND=0 ELSE IF ON_RAMP=1 AND OUT_TL<160 AND OUT_BL<160 AND OUT_TR<160 AND OUT_BR<160 AND BC<76 AND LC<76 AND RC<76 THEN GROUNDED=0 ON_RAMP=0 IF ABS(SLOPE_GROUND)<>PI/2 THEN SLOPE_GROUND=0 ANIM_TICK=0 END IF IF GROUNDED=1 THEN COYOTETIME=0 ELSE INC COYOTETIME END SUB SUB DIR_CHECK IF VX>0 OR D_INPUT=1 THEN IF OUT_BR>163 OR OUT_TR>163 THEN CALL CANCEL_INPUT ELSE IF VX<0 OR D_INPUT=-1 THEN IF OUT_BL>163 OR OUT_TL>163 THEN CALL CANCEL_INPUT END IF END SUB SUB CANCEL_INPUT IF ON_RAMP=0 THEN D_INPUT=0 IS_DEC=0 IS_TURN=0 ANIM_TICK=0 END IF END SUB SUB VEL_LIMIT(L) IF VX*VX+VY*VY>L*L THEN VX=SGN(VX)*L*ABS(COS(SLOPE_GROUND)) VY=SGN(VY)*L*ABS(SIN(SLOPE_GROUND)) END IF END SUB SUB UPD_PX '// UPDATE LOCAL ON-SCREEN POSITION PX=PX+VX '// CORRECTS SCRL_X AND PX IF OUT OF MARGIN IF SCRL_X>0 AND PXR_SCRL_MARGIN THEN SCRL_X=SCRL_X+(PX-R_SCRL_MARGIN) PX=R_SCRL_MARGIN END IF '// UPDATE GLOBAL POSITION PS_X=PX+SCRL_X CALL UPD_SCRL END SUB SUB UPD_PY PY=PY+VY PS_Y=PY+INT(SCRL_Y) END SUB SUB FALL_GRAVITY(G) IF VYMAX_FALL_V THEN VY=MAX_FALL_V END SUB SUB JUMP IF VY>MAX_JUMP_V THEN VY=VY-0.25 IF J_COUNT=MAX_J_COUNT THEN J_IND=0 INC J_COUNT END SUB SUB ENV_COLL_CHECK BG 1 '// CHECK FOR COLLISION WITH ENVIRONMENT TILES WITH '// HIT DETECTION FOR EACH TYPE OF BLOCK INTERACTION '// FOUR-SIDED HARD BLOCKS (INCLUDES THE SPECIAL VERTICAL PARTIAL RAMP BLOCKS): CALL BOX_CELLCHECK(PS_X,PS_Y) IF TL>159 OR TR>159 OR BL>159 OR BR>159 THEN CALL BOX_COLL '// MAIN RAMPS: CALL CENTER_CELLCHECK(PS_X,PS_Y) IF (BC>75 AND BC<111) OR (LC>75 AND LC<111) OR (RC>75 AND RC<111) THEN CALL RAMP_COLL_CHECK '// PASS-THRU, ONE-WAY CIELING 'SOFTBOXES' (WILL ALSO INCLUDE RAILS AND LEDGES): IF BC=128 THEN CALL HARDTOP_COLL END SUB SUB HARDTOP_COLL P_Y=PS_Y+15 T_Y=16*INT(P_Y/16) PS_Y=T_Y-15.1 PY=PS_Y IF ON_RAMP=1 THEN V=SQR(VX*VX+VY*VY) VX=SGN(VX)*V END IF GROUNDED=1 ON_RAMP=0 SLOPE_GROUND=0 ANIM_TICK=0 VY=0 END SUB SUB BOX_COLL IF TL=164 OR TR=164 OR BL=164 OR BR=164 THEN CALL FULL_BLOCK_COLL ELSE IF TL=160 OR TR=160 OR BL=160 OR BR=160 THEN CALL CENTER_CELLCHECK(PS_X,PS_Y) CALL HALFSNAP_R_COLL ELSE IF TL=162 OR TR=162 OR BL=162 OR BR=162 THEN CALL CENTER_CELLCHECK(PS_X,PS_Y) CALL HALFSNAP_L_COLL END IF END SUB SUB HALFSNAP_R_COLL '// CHECK SUBSEQUENT DETECTION POINTS FOR IN-SOLID COLLISION IF RC=160 THEN P_X=PS_X+15 P_Y=PS_Y+7.5 ELSE IF TR=160 THEN P_X=PS_X+15 P_Y=PS_Y '// CHECK THE BOTTOM-RIGHT CORNER FOR A SNAP CONDITION IF NOT GROUNDED ELSE IF BR=160 THEN P_X=PS_X+15 P_Y=PS_Y+15 IF GROUNDED=0 AND J_IND=0 THEN CALL FIND_T(P_X,P_Y) IF P_X-(T_X+2)>0 AND P_X-(T_X+14)<0 THEN IF VY>ABS(VX) THEN ON_RAMP=1 GROUNDED=1 CALL PART_CORR_R ELSE PS_Y=T_Y-15.1 PY=PS_Y CALL VERT_STOP END IF P_X=0 END IF END IF ELSE IF BC=160 THEN P_X=PS_X+7.5 P_Y=PS_Y+15 ELSE IF BL=160 THEN P_X=PS_X P_Y=PS_Y+15 END IF '// DETERMINE THE GLOBAL ORIGIN OF IMPEDING TILE FROM TEST POSITION CALL FIND_T(P_X,P_Y) '// CHECK FOR IN-SOLID COLLISION STATE AND CORRECT MOTION,GROUND AND SLOPE VARIABLES ACCORDINGLY IF P_X-(T_X+8)>0 THEN CALL FIND_D(P_X,P_Y,8) IF VX=0 THEN IF VY>0 THEN PS_Y=T_Y-15.1 CALL VERT_STOP END IF ELSE IF VY=0 THEN CALL PART_CORR_R ELSE IF ABS(D_X/VX)0 THEN PS_Y=T_Y-15.1 CALL VERT_STOP ELSE CALL PART_CORR_R END IF END IF PY=PS_Y END IF END SUB SUB PART_CORR_R '// CORRECTS OBJECT TO THE LEFT OF THE PARTIAL 'RIGHT-SIDE-SOLID BLOCK', UPDATES THE SLOPE IF SNAPPED TO RAMP PS_X=T_X-7.1 IF (SCRL_X>0 AND PS_X-SCRL_X<=L_SCRL_MARGIN) OR PS_X-SCRL_X>=R_SCRL_MARGIN THEN PX_=PS_X-SCRL_X ELSE PX_=PS_X-INT(SCRL_X) CALL HOR_STOP CALL CORR_SCROLL(PX_) IF ON_RAMP=1 THEN SLOPE_GROUND=-PI/2 END SUB SUB HALFSNAP_L_COLL '// DETERMINE THE GLOBAL POSITION OF PENETRATING POINT IF LC=162 THEN P_X=PS_X P_Y=PS_Y+7.5 ELSE IF TL=162 THEN P_X=PS_X P_Y=PS_Y '// CHECK BOTTOM-LEFT CORNER FOR A SNAP CONDITION IF NOT GROUNDED ELSE IF BL=162 THEN P_X=PS_X P_Y=PS_Y+15 IF GROUNDED=0 AND J_IND=0 THEN CALL FIND_T(P_X,P_Y) IF P_X-(T_X+2)>0 AND P_X-(T_X+14)<0 THEN IF VY>ABS(VX) THEN ON_RAMP=1 GROUNDED=1 CALL PART_CORR_L ELSE PS_Y=T_Y-15.1 PY=PS_Y CALL VERT_STOP END IF P_X=15 END IF END IF ELSE IF BC=162 THEN P_X=PS_X+7.5 P_Y=PS_Y+15 ELSE IF BR=162 THEN P_X=PS_X+15 P_Y=PS_Y+15 END IF '// DETERMINE THE GLOBAL ORIGIN OF TILE FROM THE TEST POINT CALL FIND_T(P_X,P_Y) '// TEST POSITION FOR BEING IN THE SOLID AREA OF TILE, AND CORRECT APPROPRIATELY IF NEEDED IF P_X0 THEN PS_Y=T_Y-15.1 CALL VERT_STOP END IF ELSE IF VY=0 THEN CALL PART_CORR_L ELSE IF ABS(D_X/VX)0 THEN PS_Y=T_Y-15.1 CALL VERT_STOP ELSE CALL PART_CORR_L END IF END IF PY=PS_Y END IF END SUB SUB PART_CORR_L '// PS_X=T_X+8.1 IF (SCRL_X>0 AND PS_X-SCRL_X<=L_SCRL_MARGIN) OR PS_X-SCRL_X>=R_SCRL_MARGIN THEN PX_=PS_X-SCRL_X ELSE PX_=PS_X-INT(SCRL_X) CALL HOR_STOP CALL CORR_SCROLL(PX_) IF ON_RAMP=1 THEN SLOPE_GROUND=PI/2 END SUB SUB FULL_BLOCK_COLL '// CORRECT, UPDATE MCELL VALUES AND PARENT VALUES CALL BLOCK_COLL_COR CALL BOX_CELLCHECK(PS_X,PS_Y) END SUB SUB BLOCK_COLL_COR '// DETERMINE IF ANY PAIR OF OPPOSITE CORNERS IS IN A SOLID BLOCK INDICATING AN INSIDE-CORNER CASE IF TL=164 AND BR=164 THEN P_X=PS_X+15 P_Y=PS_Y CALL FIND_T(P_X,P_Y) IF VX>0 AND VY<0 THEN PS_X=T_X-15.1 PS_Y=T_Y+16.1 ELSE IF VX<0 AND VY>0 THEN PS_X=T_X+0.1 PS_Y=T_Y+0.9 END IF CALL HOR_STOP CALL VERT_STOP ELSE IF TR=164 AND BL=164 THEN P_X=PS_X+15 P_Y=PS_Y+15 CALL FIND_T(P_X,P_Y) IF VX>0 AND VY>0 THEN PS_X=T_X-15.1 PS_Y=T_Y-15.1 ELSE IF VX<0 AND VY<0 THEN PS_X=T_X+0.1 PS_Y=T_Y+0.1 END IF CALL HOR_STOP CALL VERT_STOP '// TEST EACH SIDE-PAIR OF DETECTION POINTS DETERMINING IF A FULL, SIMPLE COLLISION HAS OCCURED ELSE IF TR=164 AND BR=164 THEN P_X=PS_X+15 P_Y=PS_Y CALL FIND_T(P_X,P_Y) PS_X=T_X-15.1 CALL HOR_STOP ELSE IF BR=164 AND BL=164 THEN P_X=PS_X P_Y=PS_Y+15 CALL FIND_T(P_X,P_Y) PS_Y=T_Y-15.1 CALL VERT_STOP ELSE IF BL=164 AND TL=164 THEN P_X=PS_X P_Y=PS_Y+15 CALL FIND_T(P_X,P_Y) PS_X=T_X+16.1 CALL HOR_STOP ELSE IF TL=164 AND TR=164 THEN P_X=PS_X P_Y=PS_Y CALL FIND_T(P_X,P_Y) PS_Y=T_Y+16.1 CALL VERT_STOP ELSE '// LASTLY, TEST INDIVIDUAL POINTS FOR GLANCING COLLISIONS THAT REQUIRE FURTHER INVESTIGATION TO DETERMINE CORRECTION STATES CALL FIND_P(PS_X,PS_Y,164) CALL FIND_T(P_X,P_Y) CALL FIND_D(P_X,P_Y,0) IF VX=0 THEN IF VY>0 THEN PS_Y=T_Y-15.1 ELSE PS_Y=T_Y+16.1 CALL VERT_STOP ELSE IF VY=0 THEN IF VX>0 THEN PS_X=T_X-15.1 ELSE PS_X=T_X+16.1 CALL HOR_STOP ELSE IF ABS(D_Y/VY)0 THEN PS_Y=T_Y-15.1 ELSE PS_Y=T_Y+16.1 CALL VERT_STOP ELSE IF VX>0 THEN PS_X=T_X-15.1 ELSE PS_X=T_X+16.1 CALL HOR_STOP END IF END IF IF (SCRL_X>0 AND PS_X-SCRL_X<=L_SCRL_MARGIN) OR PS_X-SCRL_X>=R_SCRL_MARGIN THEN PX_=PS_X-SCRL_X ELSE PX_=PS_X-INT(SCRL_X) CALL CORR_SCROLL(PX_) PY=PS_Y END SUB SUB FIND_P(X,Y,C) IF TL=C THEN P_X=X P_Y=Y ELSE IF TR=C THEN P_X=X+15 P_Y=Y ELSE IF BL=C THEN P_X=X P_Y=Y+15 ELSE IF BR=C THEN P_X=X+15 P_Y=Y+15 END IF END SUB SUB FIND_T(X,Y) '// DETERMINE THE GLOBAL POSITION OF THE TILE CHAR'S ORIGIN IN PIXELS T_X=16*INT(X/16) T_Y=16*INT(Y/16) END SUB SUB FIND_D(X,Y,O) '// DETERMINE THE IN-SOLID INGRESS IN EACH DIRECTION IF VX>0 THEN D_X=X-(T_X+O) ELSE IF VX<0 THEN D_X=16-(X-(T_X+O)) ELSE IF VX=0 THEN D_X=0 END IF IF VY>0 THEN D_Y=Y-T_Y ELSE IF VY<0 THEN D_Y=16-(Y-T_Y) ELSE IF VY=0 THEN D_Y=0 END IF END SUB SUB HOR_STOP IF ON_RAMP=1 THEN V=SQR(VX*VX+VY*VY) VY=SGN(VY)*V IF VX>0 THEN SLOPE_GROUND=-PI/2 ELSE SLOPE_GROUND=PI/2 ELSE D_INPUT=0 IS_DEC=0 IS_TURN=0 ANIM_TICK=0 END IF VX=0 END SUB SUB VERT_STOP IF ON_RAMP=1 THEN V=SQR(VX*VX+VY*VY) VX=SGN(VX)*V END IF IF VY>=0 THEN GROUNDED=1 ON_RAMP=0 ANIM_TICK=0 ELSE J_IND=0 END IF VY=0 SLOPE_GROUND=0 END SUB SUB CORR_SCROLL(X) IF SCRL_X>0 AND X<=L_SCRL_MARGIN THEN PX=L_SCRL_MARGIN SCRL_X=PS_X-PX ELSE IF X>=R_SCRL_MARGIN THEN PX=R_SCRL_MARGIN SCRL_X=PS_X-PX ELSE IF (SCRL_X>0 AND PX=L_SCRL_MARGIN) OR PX=R_SCRL_MARGIN THEN SCRL_X=PS_X-PX ELSE PX=X SCRL_X=INT(SCRL_X) END IF END IF IF SCRL_X<0 THEN SCRL_X=0 PS_X=PX+SCRL_X CALL UPD_SCRL END SUB SUB RAMP_COLL_CHECK FOR T=76 TO 110 STEP 2 IF BC=T OR LC=T OR RC=T THEN CALL SET_RAMP_VARS(T) '// CONDITION CHECKS IF POINT (D_X,D_Y) IS BELOW THE RAMP SLOPE FOR THE GIVEN TILE CHAR# (T) AND THAT THE COLLISION POINTS FROM THE LOOP ARE VALID IF VALID_COLL=1 AND D_Y>=(TI_Y-0.1)+D_X*RAMP_SLOPE THEN SLOPE_GROUND=SLOPE_GROUND_C '// VERTICALLY CORRECT POSITION IF ABSOLUTE VALUE OF SLOPE IS PI/4 OR LESS IF ABS(SLOPE_GROUND)<=PI/4 THEN IF BC=T THEN PS_Y=T_Y+TI_Y-15.1+D_X*RAMP_SLOPE ELSE PS_Y=T_Y+TI_Y-7.6+D_X*RAMP_SLOPE END IF ELSE '// HORIZONTALLY CORRECT POSITION IF ABSOLUTE VALUE OF SLOPE IS MORE THAN PI/4 IF SLOPE_GROUND>0 AND LC=T THEN PS_X=(T_X+0.1)+(D_Y-TI_Y)/RAMP_SLOPE ELSE IF SLOPE_GROUND<0 AND RC=T THEN PS_X=(T_X-15.1)+(D_Y-TI_Y)/RAMP_SLOPE ELSE IF BC=T THEN IF SLOPE_GROUND<0 THEN PS_X=(T_X-11.35)+(D_Y-TI_Y)/RAMP_SLOPE ELSE PS_X=(T_X-3.65)+(D_Y-TI_Y)/RAMP_SLOPE END IF IF (SCRL_X>0 AND PS_X-SCRL_X<=L_SCRL_MARGIN) OR PS_X-SCRL_X>=R_SCRL_MARGIN THEN PX_=PS_X-SCRL_X ELSE PX_=PS_X-INT(SCRL_X) CALL CORR_SCROLL(PX_) END IF PY=PS_Y IF GROUNDED=0 AND ON_RAMP=0 THEN CALL GROUND_IMPULSE(VX,VY) ELSE V=SQR(VX*VX+VY*VY) IF VX<>0 THEN VX=SGN(VX)*V*ABS(COS(SLOPE_GROUND)) ELSE VX=SGN(VY*SLOPE_GROUND)*V*ABS(COS(SLOPE_GROUND)) END IF IF VY<>0 THEN VY=SGN(VY)*V*ABS(SIN(SLOPE_GROUND)) ELSE VY=SGN(VX*SLOPE_GROUND)*V*ABS(SIN(SLOPE_GROUND)) END IF END IF GROUNDED=1 ON_RAMP=1 ANIM_TICK=0 END IF END IF IF T=78 THEN T=94 NEXT T END SUB SUB SET_RAMP_VARS(T) '// DETERMINE RAMP SLOPE, AND LEFT-HAND Y-INTERCEPT FROM TILE CHAR# AND T_CHAR=T IF T=76 THEN TI_Y=32 RAMP_SLOPE=-2 ELSE IF T=78 THEN TI_Y=0 RAMP_SLOPE=2 ELSE IF T=96 THEN TI_Y=16 RAMP_SLOPE=-0.5 ELSE IF T=98 THEN TI_Y=8 RAMP_SLOPE=-0.5 ELSE IF T=100 THEN TI_Y=0 RAMP_SLOPE=0.5 ELSE IF T=102 THEN TI_Y=8 RAMP_SLOPE=0.5 ELSE IF T=104 THEN TI_Y=16 RAMP_SLOPE=-1 ELSE IF T=106 THEN TI_Y=0 RAMP_SLOPE=1 ELSE IF T=108 THEN TI_Y=16 RAMP_SLOPE=-2 ELSE IF T=110 THEN TI_Y=-16 RAMP_SLOPE=2 END IF '// DETERMINE THE GROUND SLOPE REFERENCE ANGLE IN RADIANS SLOPE_GROUND_C=ATAN(RAMP_SLOPE) '// DETERMINE GLOBAL X/Y VALUES (POSITION) OF CURRENT BM_BOARD DETECTION POINT DEPENDING ON SLOPE_GROUND AND THE VALIDITY OF THE COLLISION BEING TESTED IF ABS(SLOPE_GROUND_C)>PI/4 THEN IF SLOPE_GROUND_C>0 THEN IF LC=T THEN P_X=PS_X P_Y=PS_Y+7.5 VALID_COLL=1 ELSE IF BC=T THEN P_X=PS_X+7.5 P_Y=PS_Y+15 VALID_COLL=1 ELSE VALID_COLL=0 END IF ELSE IF SLOPE_GROUND_C<0 THEN IF RC=T THEN P_X=PS_X+15 P_Y=PS_Y+7.5 VALID_COLL=1 ELSE IF BC=T THEN P_X=PS_X+7.5 P_Y=PS_Y+15 VALID_COLL=1 ELSE VALID_COLL=0 END IF ELSE VALID_COLL=0 END IF ELSE IF BC=T THEN P_X=PS_X+7.5 P_Y=PS_Y+15 VALID_COLL=1 ELSE IF SLOPE_GROUND_C>0 AND LC=T THEN P_X=PS_X P_Y=PS_Y+7.5 VALID_COLL=1 ELSE IF SLOPE_GROUND_C<0 AND RC=T THEN P_X=PS_X+15 P_Y=PS_Y+7.5 VALID_COLL=1 ELSE VALID_COLL=0 END IF END IF '// DETERMINE THE GLOBAL POSITION OF THE TILE CHAR'S ORIGIN T_X=16*INT(P_X/16) T_Y=16*INT(P_Y/16) '//DETERMINE THE LOCAL, IN-TILE POSITION OF BOTTOM-CENTER DETECTION POINT D_X=P_X-T_X D_Y=P_Y-T_Y END SUB SUB GROUND_IMPULSE(VX_,VY_) CALL FIND_VEL_SLOPE(VX_,VY_) CALL FIND_SIGN_VPAR CALL FIND_IMPULSE_ANGLE CALL IMPULSE_CORRECT(VX_,VY_) END SUB SUB FIND_VEL_SLOPE(VX_,VY_) '//SUB FOR FINDING THE TRUE SLOPE, AND ITS REFERENCE SLOPE, OF A VELOCITY VECTOR WITH COMPONENTS VX AND VY '//AND FOR FINDING THE QUADRANT OF VECTOR'S SLOPE IF VX_<>0 AND VY_<>0 THEN SLOPE_VEL_REF=ABS(ATAN(VY_/VX_)) ELSE IF VX_=0 THEN IF VY_=0 THEN SLOPE_VEL=0 SLOPE_VEL_REF=0 ELSE IF VY_>0 THEN SLOPE_VEL=PI/2 SLOPE_VEL_REF=SLOPE_VEL ELSE IF VY_<0 THEN SLOPE_VEL=3*(PI/2) SLOPE_VEL_REF=PI/2 END IF ELSE IF VY_=0 THEN IF VX_>0 THEN SLOPE_VEL=0 SLOPE_VEL_REF=SLOPE_VEL ELSE IF VX_<0 THEN SLOPE_VEL=PI SLOPE_VEL_REF=PI END IF END IF IF VX_>0 AND VY_>=0 THEN SLOPE_VEL=SLOPE_VEL_REF Q_SLOPE_VEL=1 ELSE IF VX_<=0 AND VY_>0 THEN SLOPE_VEL=PI-SLOPE_VEL_REF Q_SLOPE_VEL=2 ELSE IF VX_<0 AND VY_<=0 THEN SLOPE_VEL=PI+SLOPE_VEL_REF Q_SLOPE_VEL=3 ELSE IF VX_>=0 AND VY_<0 THEN SLOPE_VEL=(2*PI)-SLOPE_VEL_REF Q_SLOPE_VEL=4 END IF END SUB SUB FIND_SIGN_VPAR '//SUB FOR DETERMINING THE 'SIGN' (I CHOSE '+' FOR WHEN THE RESULTANT VELOCITY MOVES TOWARD CENTER '// AND '-' WHEN IT MOVES AWAY FROM CENTER). '//QUADRANT OF GROUND SLOPE IS ALSO DETERMINED TO BE LATER COMPARED WITH THE VELOCITY SLOPE QUADRANT IF SLOPE_GROUND<0 THEN SLOPE_GROUND_=SLOPE_GROUND+PI ELSE SLOPE_GROUND_=SLOPE_GROUND IF SLOPE_GROUND_-(PI/2)<=0 THEN IF Q_SLOPE_VEL>2 THEN SLOPE_GROUND_P=SLOPE_GROUND_+(2*PI) ELSE SLOPE_GROUND_P=SLOPE_GROUND_ SLOPE_GROUND_REF=SLOPE_GROUND_ Q_SLOPE_GROUND=1 ELSE SLOPE_GROUND_P=SLOPE_GROUND_ SLOPE_GROUND_REF=PI-SLOPE_GROUND_ Q_SLOPE_GROUND=2 END IF IF ABS(SLOPE_GROUND_+(PI/2)-SLOPE_VEL)<0.0001 THEN SIGN_V_PAR=0 ELSE IF ABS(SLOPE_GROUND_P-(PI/2)-SLOPE_VEL)<0.0001 THEN SIGN_V_PAR=0 ELSE IF (SLOPE_GROUND_+(PI/2)>SLOPE_VEL) AND (SLOPE_GROUND_P-(PI/2)=0 AND SLOPE_GROUND_=PI/2 AND SLOPE_GROUND_=0 AND SLOPE_GROUND_=PI/2 AND SLOPE_GROUND_<=PI THEN SIGN_VX_PAR=-1 SIGN_VY_PAR=1 END IF ELSE IF SIGN_V_PAR=0 THEN SIGN_VX_PAR=0 SIGN_VY_PAR=0 END IF END SUB SUB FIND_IMPULSE_ANGLE '//FUNCTION FOR DETERMINING THE PROPER REFERENCE ANGLE '//TO USE TO DETERMINE THE COMPONENT OF VELOCITY THAT IS PARALLEL TO THE GROUND SLOPE IF Q_SLOPE_VEL=Q_SLOPE_GROUND OR Q_SLOPE_VEL=Q_SLOPE_GROUND+2 THEN SLOPE_IMP_REF=ABS(SLOPE_VEL_REF-SLOPE_GROUND_REF) ELSE SLOPE_IMP_REF=SLOPE_VEL_REF+SLOPE_GROUND_REF END IF END SUB SUB IMPULSE_CORRECT(VX_,VY_) '//CORRECT VX AND VY DURING GROUND COLLISION/SLOPE CHANGE VX=SQR((VX_^2)+(VY_^2))*ABS(COS(SLOPE_GROUND_REF)*COS(SLOPE_IMP_REF))*SIGN_VX_PAR VY=SQR((VX_^2)+(VY_^2))*ABS(SIN(SLOPE_GROUND_REF)*COS(SLOPE_IMP_REF))*SIGN_VY_PAR END SUB SUB UPD_SCRL IF PX<=L_SCRL_MARGIN OR PX>=R_SCRL_MARGIN THEN '// THESE TOLERANCE VALUES ARE GOOD FOR A HORIZONTAL VELOCITY UP TO 4 PIXELS PER FRAME IF (SCRL_X/16)-INT(SCRL_X/16)<=0.125 OR (SCRL_X/16)-INT(SCRL_X/16)>=0.875 THEN IF PX=R_SCRL_MARGIN AND VX>=0 THEN BG COPY (((SCRL_X)/16)+10),0,2,16 TO (((SCRL_X)/16)+10),0 ELSE IF PX=L_SCRL_MARGIN AND VX<=0 THEN IF (SCRL_X)>16 THEN BG COPY (((SCRL_X)/16)-2),0,2,16 TO (((SCRL_X)/16)-2),0 END IF END IF SCROLL 1,SCRL_X,0 END IF END SUB SUB DEBUG_PO BG 0 PAL 7 '//LEFT-SIDE DEBUG PRINT-OUT TEXT 0,0,"VX:" NUMBER 6,0,VX*100,4 TEXT 0,1,"VY:" NUMBER 6,1,VY*100,4 'TEXT 0,2,"VX_C:" 'NUMBER 6,2,VX_C*100,4 'TEXT 0,3,"VY_C:" 'NUMBER 6,3,VY_C*100,4 TEXT 0,4,"SLP:" NUMBER 6,4,RAMP_SLOPE*100,4 TEXT 0,5,"DIR:" NUMBER 6,5,D_INPUT,4 TEXT 0,6,"T_X" NUMBER 6,6,T_X,4 TEXT 0,7,"T_Y" NUMBER 6,7,T_Y,4 TEXT 0,8,"TI_Y:" NUMBER 6,8,TI_Y*10,4 TEXT 0,9,"TCHR:" NUMBER 6,9,T_CHAR,4 TEXT 0,10,"GRND:" NUMBER 6,10,GROUNDED,1 TEXT 0,11,"RAMP:" NUMBER 6,11,ON_RAMP,1 TEXT 0,12,"J_CNT:" NUMBER 6,12,J_COUNT,4 TEXT 0,13,"ATIK:" NUMBER 5,13,ANIM_TICK,5 TEXT 0,14,"CTM:" NUMBER 6,14,COYOTETIME,4 TEXT 0,15,"SCRL:" NUMBER 5,15,SCRL_X*10,5 '//RIGHT-SIDE DEBUG PRINT_OUT TEXT 10,0,"D_X:" NUMBER 15,0,D_X*100,5 TEXT 10,1,"D_Y:" NUMBER 15,1,D_Y*100,5 TEXT 10,2,"SLPR:" NUMBER 16,2,SLOPE_GROUND*100,4 TEXT 10,3,"PS_X:" NUMBER 15,3,PS_X*100,5 TEXT 10,4,"PS_Y:" NUMBER 15,4,PS_Y*100,5 TEXT 10,5,"P_X:" NUMBER 15,5,P_X*100,5 TEXT 10,6,"P_Y:" NUMBER 15,6,P_Y*100,5 TEXT 10,7,"LC:" NUMBER 16,7,LC,4 TEXT 10,8,"BC:" NUMBER 16,8,BC,4 TEXT 10,9,"RC:" NUMBER 16,9,RC,4 TEXT 10,10,"TL:" NUMBER 16,10,TL,4 TEXT 10,11,"TR:" NUMBER 16,11,TR,4 TEXT 10,12,"BL:" NUMBER 15,12,BL,5 TEXT 10,13,"BR:" NUMBER 15,13,BR,5 TEXT 10,14,"PX:" NUMBER 15,14,PX*100,5 TEXT 10,15,"PY:" NUMBER 15,15,PY*100,5 BG 1 END SUB #1:MAIN PALETTES 07353F0000390D02002E190400153C00 070B320C000E0A0500082410003F2A15 #2:MAIN CHARACTERS 00000000000000000000000000000000 00000000000000000000000000000000 000000070F0F1860000303070E0C1B1F 000000E0F0E0000600C0F8200000C0F8 00000000072F1F0000000303072E1C03 00000000E0F0E0000000C0F8200000C0 0000070F0F0C28600303070E0E0F1F1F 0000E0F0E0000040C0F8200000C0C0C0 0000000F1F1F18100007070E1C1C1F1F 000000C0E0C000000080F04000008080 000000070F0F1C00000303070E0E1F03 000000E0F0E0004000C0F8200000C0C0 0000010B070C00000101010B070C0101 0000F0F8F0000000E0FC900000E0E0F0 000000070F0F0808000303070E0C0B1F 000000E0F0E0000000C0F8200000C0F8 00000000000000000000000000000000 00000000000000000000000000000000 2100070F1F3E3C001F03070F1F3E3C78 8400E0F0F87C3C00F8C0E0F0F87C3C1E 602001000F1F1E001F1F03030F1F1E3C 06048000F0F87800F8F8C0C0F0F8783C 00030707070707000707070707070707 00FCFCFC00000000C2FEFEFE00000080 00181F0F070F0E000F07070F070F0E0F 8000C0E0F0783C1E8080C0E0F0783C1E 00000303030303000303020203030303 0000C0C0C0C0C000C0C04040C0C0C0E0 00000F3F3C00000001030F7F7C400000 000CECE0E0E0E000F8F0E0E0E0E0E0F0 0100674F1E3C38003F73070F1E3C3838 8072FE8000000000FCFCF8B800000000 00000000000000000000000000000000 180C040404040404180C040404040404 00010100081C1C1C0000002121316363 0000860E1E3E3CB80001078F9FBEFCF8 00000000040E0E0E0000001010183131 0080C0060E0E0E2C000001C7CFCFFEFC 00000101010102020000010101010202 00000000010618E000000000010618E0 00081860800000000008186080000000 1E000000000000001E1F000000000000 00000808102040800000080810204080 0000000010383839000001434363C7C7 0060400C1C3C78700080808E1E3EF8F0 0000C0E0C000000080F0400000808000 000000000000020500000F1F3E7F7F7F 000030200078FCF80000C0C000F8FCFE 00000000000010080000000000001818 0404040404040C180404040404040C18 1C1C180808090100737B190909080000 B83C3E1E0E860000F8FCBE9F8F070100 0E0E0E0602040000393D0E0602040000 2C0E0E0E06C08000FCFECFCFC7010000 04040808101020C004040808101020C0 00000000C07F000000000000C07F0000 0000000003FE00000000000003FE0000 01020408300000000102040830000000 00000000000000000000000000000000 3938381E00000000E7F73B1F03010100 6060C0C0C04040C0E0E0C0E0E0E08000 00000F0F0F08080007070E0C0C0F0F07 03070E6E4F0E04006F6F6E0E0F0F0706 90000000000000009C18000000800000 00092492240900000000000000000000 003F7FFFFF7F3F0000003F7F7F3F0000 00FCFEFFFFFEFC000000FCFEFEFC0000 00007FFFFF7F00000000007F7F000000 0000FEFFFFFE0000000000FEFE000000 00000000001E383800000001031F3BF7 0000604C1C3C78700000808E9E3E78F0 0000000F1F0F000000073F090000073F 000000E0E0E0202000C0C0E0E060A0F8 00000000000000000000000000000000 AA55AA55AA55AA55FFFFFFFFFFFFFFFF AA55AA55AA55AA55FFFFFFFFFFFFFFFF 00000000000000000000000000000000 0101020306050A0D0000010103030707 808040C060A050B000008080C0C0E0E0 00000000000000000000000000000000 001249A4491200000000000000000000 003F77EFF76F370000003F7F7F3F080C 00FCDEBFDFBEDC000000FCFEFEFC2030 00006FF7EF7F00000018107F7F000000 0000EEF7EFFE0000001810FEFE000000 3939383810000000E7C7C76343430100 6060C0C0C04040C0E0E0C0E0E0E08000 0300C78F1E3C38007FE7070F1E3C3838 0074FC8000000000FCF8F0B800000000 00001C1C18140C1C00081C18140C1C1C AA55AA55AA55AA55FFFFFFFFFFFFFFFF AA55AA55AA55AA55FFFFFFFFFFFFFFFF 00000000000000000000000000000000 1A152A356A55AAD50F0F1F1F3F3F7F7F 58A854AC56AA55ABF0F0F8F8FCFCFEFE 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000030E35EA0000000000030F3F 030E35EA55AA55AA00030F3FFFFFFFFF C070AC57AA55AA5500C0F0FCFFFFFFFF 00000000C070AC570000000000C0F0FC 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 0103060D1A356AD5000103070F1F3F7F 80C060B058AC56AB0080C0E0F0F8FCFE 00000000000000000000000000000000 0101020306050A0D0000010103030707 AA55AA55AA55AA55FFFFFFFFFFFFFFFF 55AA55AA55AA55AAFFFFFFFFFFFFFFFF 808040C060A050B000008080C0C0E0E0 00000000030E35EA0000000000030F3F 030E35EA55AA55AA00030F3FFFFFFFFF 55AA55AA55AA55AAFFFFFFFFFFFFFFFF 55AA55AA55AA55AAFFFFFFFFFFFFFFFF AA55AA55AA55AA55FFFFFFFFFFFFFFFF AA55AA55AA55AA55FFFFFFFFFFFFFFFF C070AC57AA55AA5500C0F0FCFFFFFFFF 00000000C070AC570000000000C0F0FC 0103060D1A356AD5000103070F1F3F7F AA55AA55AA55AA55FFFFFFFFFFFFFFFF 55AA55AA55AA55AAFFFFFFFFFFFFFFFF 80C060B058AC56AB0080C0E0F0F8FCFE 1A152A356A55AAD50F0F1F1F3F3F7F7F AA55AA55AA55AA55FFFFFFFFFFFFFFFF 55AA55AA55AA55AAFFFFFFFFFFFFFFFF 58A854AC56AA55ABF0F0F8F8FCFCFEFE FF55AA55AA55AA5500FFFFFFFFFFFFFF FF55AA55AA55AA5500FFFFFFFFFFFFFF 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 AA55AA55AA55AA55FFFFFFFFFFFFFFFF AA55AA55AA55AA55FFFFFFFFFFFFFFFF 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 FFD5AAD5AAD5AAD5007F7F7F7F7F7F7F FFAB55AB55AB55AB00FEFEFEFEFEFEFE 00000000000000000000000000000000 FFD5AAD5AAD5AAD5007F7F7F7F7F7F7F FF55AB55AB55AB5500FEFEFEFEFEFEFE 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 AAD5AAD5AAD5AAD57F7F7F7F7F7F7F7F 55AB55AB55AB55ABFEFEFEFEFEFEFEFE 00000000000000000000000000000000 AAD5AAD5AAD5AAFF7F7F7F7F7F7F7F00 AB55AB55AB55ABFFFEFEFEFEFEFEFE00 #3:MAIN BG 00018008A40600000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 0000A406A40600000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 0000A406A40600000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 0000A406A4064E060000000000000000 0000000000000000000000004C068006 4E060000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000600662068006 800680068006A2060000000000000000 00000000000000000000A00680068006 64066606000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 0000A406A4066E060000000000000000 0000000000000000000000006C064A06 6E060000000000000000000000060006 00060006000600000000000000000000 00000000000000000000000000000000 000000000000600662064A064A064A06 4A064A064A066E060000000000000000 000000000000000000006C064A064A06 4A064A06640666060000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 0000A406A4064A066A06000000000000 0000000000000000000068064A064A06 4A066A06000000000000000600060000 0000000068066A060000000000000000 00000000000000000000000000000000 0000600662064A064A064A064A064A06 4A064A064A064A066A06000000000000 000000000000000068064A064A064A06 4A064A064A064A066406660600000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 0000A406A4064A064A06640666060000 000000000000600662064A064A064A06 4A064A06640666060000000000000000 600662064A064A066406660600006006 62066406660600000000000000006006 62064A064A064A064A064A064A064A06 4A064A064A064A064A06640666060000 00000000600662064A064A064A064A06 4A064A064A064A064A064A0664066606 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 0000A406800680068006800680068006 80068006800680068006800680068006 80068006800680068006800680068006 80068006800680068006800680068006 80068006800680068006800680068006 80068006800680068006800680068006 80068006800680068006800680068006 80068006800680068006800680068006 80068006800680068006800680068006 80068006800680068006800680068006 80068006800680068006800680068006 80068006800680068006800680068006 80068006800680068006800680068006 80068006800680068006800680068006 80068006800680068006800680068006 80068006800680068006800680068006 80068006