'*************************************** '3D ISOMETRIC GAME ENGINE 'BY JEAN-MILOST REYMOND '*************************************** GLOBAL ITEMCOUNT, RADIUS, PLAYERDIR, PLAYERVELOCITY, ROOMCHANGING, NEXTPOSX, NEXTPOSY, NEXTDIR, FADERVALUE, FADEROFFSET, MSGX, INFOMSG$ 'ISOMETRIC COORDINATE SYSTEM AXIS: ' Z Y ' | / ' | /\/ ' |/\/\/ ' \/\/\ ' \/\ ' \ ' X DIM GLOBAL ORIGIN(2) 'SPRITES ARE ORGANIZED AS FOLLOW: '0 TO 3 - USED FOR USER INTERFACE '4 TO 17 - USED FOR FRONT DOORS 'SINCE 18 - SCENE ITEMS 'BOUNDING BOX COLLECTION, IN RELATIVE COORDINATES, ORGANIZED AS FOLLOW: '0 - 1X2 CELLS BOUNDING BOX, I.E 8X8X16 PIXELS ON XYZ AXIS 'ITEMS ARE ORGANIZED AS FOLLOW: '0 - MIN EDGE, X POSITION '1 - MIN EDGE, Y POSITION '2 - MIN EDGE, Z POSITION '3 - MAX EDGE, X POSITION '4 - MAX EDGE, Y POSITION '5 - MAX EDGE, Z POSITION DIM GLOBAL BBOX(1, 6) 'SPRITE COLLECTION, ITEMS ARE: '0 - PLAYER LEFT DIR, FRAME 1 '1 - PLAYER LEFT DIR, FRAME 2 '2 - PLAYER BOTTOM DIR, FRAME 1 '3 - PLAYER BOTTOM DIR, FRAME 2 '4 - ROBOT LEFT DIR, FRAME 1 '5 - ROBOT LEFT DIR, FRAME 2 '6 - ROBOT BOTTOM DIR, FRAME 1 '7 - ROBOT BOTTOM DIR, FRAME 2 '8 - GREEN PLANT 'EACH SPRITE ITEM IS ORGANIZED AS FOLLOW: '0 - TOP CHAR INDEX '1 - MASK CHAR INDEX '2 - BOTTOM CHAR INDEX '3 - TOP CHAR PALETTE INDEX '4 - MASK CHAR PALETTE INDEX '5 - BOTTOM CHAR PALETTE INDEX '6 - Y DELTA BETWEEN TOP AND BOTTOM CHARS '7 - BOUNDING BOX ITEM (IN BOUNDING BOX COLLECTION) DIM GLOBAL COLLECTION(9, 8) 'PLAYER CHARACTER DATA, INDEX ARE: '0 - X POSITION '1 - Y POSITION '2 - Z POSITION '3 - WALKING ANIMATION FRAME DIM GLOBAL CHARDATA(4) 'DOORS, ORGANIZED AS FOLLOW: '0 - TOP DOOR '1 - RIGHT DOOR '2 - BOTTOM DOOR '3 - LEFT DOOR 'EACH DOOR CONTAINS ASSOCIATED DATA, WHICH ARE DEFINED AS FOLLOW: '0 - IF 1, DOOR IS VISIBLE, OTHERWISE HIDDEN '1 - MIN TRIGGER ZONE EDGE, X POSITION '2 - MIN TRIGGER ZONE EDGE, Y POSITION '3 - MIN TRIGGER ZONE EDGE, Z POSITION '4 - MAX TRIGGER ZONE EDGE, X POSITION '5 - MAX TRIGGER ZONE EDGE, Y POSITION '6 - MAX TRIGGER ZONE EDGE, Z POSITION DIM GLOBAL DOORS(4, 7) 'SCENE ITEMS, MAX 15 PER SCENE 'INDEX ARE: '0 - X POSITION '1 - Y POSITION '2 - Z POSITION '3 - SPRITE INDEX IN THE COLLECTION '4 - IF 1, SPRITE SHOULD BE MIRRORED '5 - IF 1, THE ITEM IS VISIBLE IN THE SCREEN DIM GLOBAL SCENEITEMS(15, 6) 'SORTED ITEMS TO DRAW IN THE FINAL SCENE, ORGANIZED AS FOLLOW: '0 - X POSITION '1 - Y POSITION '2 - TOP CHAR INDEX '3 - BOTTOM CHAR INDEX '4 - TOP MASK CHAR INDEX '5 - BOTTOM MASK CHAR INDEX '6 - TOP SPRITE PALETTE '7 - BOTTOM SPRITE PALETTE '8 - TOP MASK SPRITE PALETTE '9 - BOTTOM MASK SPRITE PALETTE 'DIM GLOBAL DRAWITEM(25, 6) 'PALETTES ARRAY FOR BLENDING DIM GLOBAL PALETTES(8, 4) 'GLOBAL VALUES INIT ITEMCOUNT = 15 PLAYERVELOCITY = 0.75 FADEROFFSET = 0.05 GAMEPAD 1 'SET THE SCENE ORIGIN AND RADIUS FROM ORIGIN TO LIMITS ON EACH AXIS ORIGIN(0) = 25.25 ORIGIN(1) = 105.25 RADIUS = 30.5 'LOAD THE BOUNDING BOX COLLECTION CALL LOADBBOX 'LOAD THE SPRITE COLLECTION CALL LOADSPRITES 'LOAD THE PLAYER DATA CALL LOADPLAYER 'LOAD THE DOOR DATA CALL LOADDOORS 'LOAD THE LEVEL CALL LOADLEVEL 'SAVE THE PALETTES STATE CALL SAVEPALETTES 'CONFIGURE THE DOORS FOR THE CURRENT ROOM DOORS(0, 0) = 1 DOORS(1, 0) = 1 DOORS(2, 0) = 1 DOORS(3, 0) = 1 'DRAW THE SCENE PART WHICH WILL NOT CHANGE DURING THE SCENE LIFETIME CALL DRAWSTATICSCENE ON RASTER CALL RASTERFUNC 'MAIN LOOP DO 'USED FOR DEBUGGING 'LOCATE 0, 0 'PRINT CHARDATA(0) 'LOCATE 8, 0 'PRINT CHARDATA(1) 'IS PLAYER ENTERING NEXT ROOM? IF ROOMCHANGING THEN FADERVALUE = FADERVALUE + FADEROFFSET 'CHECK FADER VALUE LIMITS IF FADERVALUE >= 1.0 THEN 'MAX FADE VALUE REACHED, CONFIGURE PLAYER POS AND NEXT ROOM FADEROFFSET = -FADEROFFSET FADERVALUE = 1.0 CHARDATA(0) = NEXTPOSX CHARDATA(1) = NEXTPOSY PLAYERDIR = NEXTDIR ELSE IF FADERVALUE <= 0.0 THEN 'MIN FADE VALUE REACHED, STOP THE TRANSITION FADEROFFSET = -FADEROFFSET FADERVALUE = 0.0 ROOMCHANGING = 0 END IF 'FADE THE WHOLE SCENE IN OR OUT CALL FADEPALETTES(0, FADERVALUE, 6) END IF CALL MOVEPLAYER CALL DRAWSCENE CALL SHOWMSG WAIT VBL LOOP '*************************************** 'LOAD THE BOUNDING BOX COLLECTION '*************************************** SUB LOADBBOX RESTORE BBOXDATA FOR I = 0 TO UBOUND(BBOX) - 1 FOR J = 0 TO UBOUND(BBOX, 2) - 1 READ BBOX(I, J) NEXT J NEXT I END SUB '*************************************** 'LOAD THE SPRITE COLLECTION '*************************************** SUB LOADSPRITES RESTORE COLLECTIONDATA FOR I = 0 TO UBOUND(COLLECTION) - 1 FOR J = 0 TO UBOUND(COLLECTION, 2) - 1 READ COLLECTION(I, J) NEXT J NEXT I END SUB '*************************************** 'LOAD THE PLAYER CHARACTER DATA '*************************************** SUB LOADPLAYER 'SET THE PLAYER ON THE CENTER OF THE ROOM CHARDATA(0) = ORIGIN(0) CHARDATA(1) = ORIGIN(1) CHARDATA(2) = 0.0 RESTORE PLAYERDATA FOR I = 3 TO UBOUND(CHARDATA) - 1 READ CHARDATA(I) NEXT I END SUB '*************************************** 'LOAD THE DOORS DATA '*************************************** SUB LOADDOORS RESTORE DOORDATA FOR I = 0 TO UBOUND(DOORS) - 1 FOR J = 1 TO UBOUND(DOORS, 2) - 1 READ DOORS(I, J) NEXT J NEXT I END SUB '*************************************** 'LOAD A LEVEL '*************************************** SUB LOADLEVEL COUNT = 4 'TODO FIXME DONT'T HARDCODE, USE A PARAMETER INSTEAD RESTORE ENTRANCE FOR I = 1 TO COUNT FOR J = 0 TO UBOUND(SCENEITEMS, 2) - 2 READ SCENEITEMS(I, J) NEXT J SCENEITEMS(I, UBOUND(SCENEITEMS, 2) - 1) = 1 NEXT I END SUB '*************************************** 'SAVE THE PALETTES '*************************************** SUB SAVEPALETTES FOR I = 0 TO UBOUND(PALETTES, 1) - 1 FOR J = 0 TO UBOUND(PALETTES, 2) - 1 PALETTES(I, J) = COLOR(I, J) NEXT J NEXT I END SUB '*************************************** 'FADE THE WHOLE PALETTE WITH A TARGET COLOR 'TARGETCOL - TARGET COLOR TO REACH 'VALUE - BLENDING VALUE BETWEEN 0.0 AND 1.0 'LIMIT - PALETTE UNTIL WHICH THE VALUE SHOULD BE APPLIED '*************************************** SUB FADEPALETTES(TARGETCOL, VALUE, LIMIT) DIM C(4) MAXPAL = UBOUND(PALETTES, 1) - 1 IF LIMIT < MAXPAL THEN MAXPAL = LIMIT END IF 'BLEND EACH PALETTE COLORS WITH TARGET COLOR FOR I = 0 TO MAXPAL CALL BLENDCOLORS(PALETTES(I, 0), TARGETCOL, VALUE, C(0)) CALL BLENDCOLORS(PALETTES(I, 1), TARGETCOL, VALUE, C(1)) CALL BLENDCOLORS(PALETTES(I, 2), TARGETCOL, VALUE, C(2)) CALL BLENDCOLORS(PALETTES(I, 3), TARGETCOL, VALUE, C(3)) PALETTE I, C(0), C(1), C(2), C(3) NEXT I END SUB '*************************************** 'BLEND COLORS TOGETHER 'STARTCOL - START COLOR TO BLEND 'ENDCOL - END COLOR TO BLEND WITH 'VALUE - BLENDING VALUE BETWEEN 0.0 AND 1.0 'RESULT[OUT] - BLENDED COLOR '*************************************** SUB BLENDCOLORS(STARTCOL, ENDCOL, VALUE, RESULT) 'GET THE START COLOR RGB COMPONENTS STARTR = INT(STARTCOL / 16) STARTG = INT(STARTCOL / 4) MOD 4 STARTB = STARTCOL MOD 4 'GET THE END COLOR RGB COMPONENTS ENDR = INT(ENDCOL / 16) ENDG = INT(ENDCOL / 4) MOD 4 ENDB = ENDCOL MOD 4 'BLEND COLOR RGB COMPONENTS TOGETHER RESULTR = INT(STARTR + ((ENDR - STARTR) * VALUE)) RESULTG = INT(STARTG + ((ENDG - STARTG) * VALUE)) RESULTB = INT(STARTB + ((ENDB - STARTB) * VALUE)) 'BUILD THE RESULTING BLENDED COLOR RESULT = RESULTR * 16 + RESULTG * 4 + RESULTB END SUB '*************************************** 'ADD AN INFO MESSAGE TO SHOW 'MSG$ - MESSAGE TO ADD '*************************************** SUB ADDMSG(MSG$) IF LEN(INFOMSG$) THEN INFOMSG$ = INFOMSG$ + " - " END IF INFOMSG$ = INFOMSG$ + MSG$ END SUB '*************************************** 'SHOW THE SCROLLING MESSAGE ON BOTTOM '*************************************** SUB SHOWMSG INC MSGX IF MSGX >= 256 THEN MSGX = 0 END IF 'DO DRAW THE NEXT CHAR? IF (MSGX MOD 8) = 0 THEN BG 0 'CALCULATE THE NEXT POS ON THE RIGHT, OUT OF THE SCREEN TX = 20 + (MSGX \ 8) TY = 14 L = LEN(INFOMSG$) C$ = " " 'ALL THE TEXT WAS DRAWN? IF L THEN 'GET THE NEXT CHAR TO DRAW C$ = MID$(INFOMSG$, 1, 1) 'REMOVE LAST DRAWN CHAR FROM STRING INFOMSG$ = RIGHT$(INFOMSG$, L - 1) END IF 'DRAW THE NEXT CHAR TEXT TX, TY, C$ END IF END SUB '*************************************** 'MOVE THE PLAYER AND CHECK HIS POSITION '*************************************** SUB MOVEPLAYER ISWALKING = 0 PREVPOSX = CHARDATA(0) PREVPOSY = CHARDATA(1) PREVPOSZ = CHARDATA(2) 'HANDLE THE USER INPUT IF ROOMCHANGING = 0 THEN IF LEFT(0) THEN ADD CHARDATA(0), PLAYERVELOCITY PLAYERDIR = 0 ISWALKING = 1 ELSE IF DOWN(0) THEN ADD CHARDATA(1), PLAYERVELOCITY PLAYERDIR = 2 ISWALKING = 1 ELSE IF RIGHT(0) THEN ADD CHARDATA(0), -PLAYERVELOCITY PLAYERDIR = 1 ISWALKING = 1 ELSE IF UP(0) THEN ADD CHARDATA(1), -PLAYERVELOCITY PLAYERDIR = 3 ISWALKING = 1 END IF END IF VALID = 0 'CHECK IF NEXT PLAYER POSITION IS VALID CALL CHECKPOSVALID(CHARDATA(0), CHARDATA(1), CHARDATA(2), VALID) IF VALID = 0 THEN CHARDATA(0) = PREVPOSX CHARDATA(1) = PREVPOSY CHARDATA(2) = PREVPOSZ ISWALKING = 0 END IF DOOR = 0 PDIR = PLAYERDIR 'CHECK IF PLAYER IS FACING A DOOR CALL CHECKDOOR(CHARDATA(0), CHARDATA(1), CHARDATA(2), PDIR, DOOR) 'A DOOR WAS REACHED? IF DOOR <> 0 THEN CALL ONPLAYERREACHEDDOOR(DOOR) END IF FRAME = 0 IF ISWALKING THEN FRAME = CHARDATA(3) \ 5 IF CHARDATA(3) = 0 THEN TRACK 0, 3 END IF END IF INDEX = 0 'ADD THE PLAYER SPRITE TO THE SCENE SCENEITEMS(INDEX, 0) = CHARDATA(0) SCENEITEMS(INDEX, 1) = CHARDATA(1) SCENEITEMS(INDEX, 2) = CHARDATA(2) SCENEITEMS(INDEX, 3) = ((PLAYERDIR MOD 2) * 2) + FRAME SCENEITEMS(INDEX, 4) = PLAYERDIR > 1 SCENEITEMS(INDEX, 5) = 1 CHARDATA(3) = (CHARDATA(3) + 1) MOD 10 END SUB '*************************************** 'CHECK IF PLAYER IS FACING A DOOR 'X - CHARACTER X POSITION 'Y - CHARACTER Y POSITION 'Z - CHARACTER Z POSITION 'PDIR - PLAYER DIRECTION 'R[OUT] - RESULT, WHERE: ' 0 - NO DOOR ' 1 - TOP DOOR ' 2 - RIGHT DOOR ' 3 - BOTTOM DOOR ' 4 - LEFT DOOR '*************************************** SUB CHECKDOOR(X, Y, Z, PDIR, R) R = 0 RESULT = 0 'CHECK THE TOP DOOR IF VISIBLE AND PLAYER IS WALKING AGAINST IT IF DOORS(0, 0) = 1 AND PDIR = 3 THEN 'IS PLAYER INSIDE DOOR TRIGGER? CALL CHECKDOORTRIGGER(X, Y, Z, 0, RESULT) IF RESULT = 1 THEN R = 1 EXIT SUB END IF END IF 'CHECK THE RIGHT DOOR IF VISIBLE AND PLAYER IS WALKING AGAINST IT IF DOORS(1, 0) = 1 AND PDIR = 1 THEN 'IS PLAYER INSIDE DOOR TRIGGER? CALL CHECKDOORTRIGGER(X, Y, Z, 1, RESULT) IF RESULT = 1 THEN R = 2 EXIT SUB END IF END IF 'CHECK THE BOTTOM DOOR IF VISIBLE AND PLAYER IS WALKING AGAINST IT IF DOORS(2, 0) = 1 AND PDIR = 2 THEN 'IS PLAYER INSIDE DOOR TRIGGER? CALL CHECKDOORTRIGGER(X, Y, Z, 2, RESULT) IF RESULT = 1 THEN R = 3 EXIT SUB END IF END IF 'CHECK THE LEFT DOOR IF VISIBLE AND PLAYER IS WALKING AGAINST IT IF DOORS(3, 0) = 1 AND PDIR = 0 THEN 'IS PLAYER INSIDE DOOR TRIGGER? CALL CHECKDOORTRIGGER(X, Y, Z, 3, RESULT) IF RESULT = 1 THEN R = 4 EXIT SUB END IF END IF END SUB '*************************************** 'CHECK IF CHARACTER POSITION IS VALID 'X - CHARACTER X POSITION 'Y - CHARACTER Y POSITION 'Z - CHARACTER Z POSITION 'R[OUT] - RESULT, IF 1 POS IS VALID, OTHERWISE 0 '*************************************** SUB CHECKPOSVALID(X, Y, Z, R) R = 0 'IS PLAYER OUT OF PLAYFIELD ON X AXIS? IF X <= ORIGIN(0) - RADIUS OR X >= ORIGIN(0) + RADIUS THEN EXIT SUB END IF 'IS PLAYER OUT OF PLAYFIELD ON Y AXIS? IF Y <= ORIGIN(1) - RADIUS OR Y >= ORIGIN(1) + RADIUS THEN EXIT SUB END IF 'TEST COLLISIONS WITH EACH SCENE OBJECTS FOR I = 1 TO UBOUND(SCENEITEMS) - 1 'IS OBJECT VISIBLE? IF SCENEITEMS(I, 5) = 1 THEN SPRIDX = SCENEITEMS(I, 3) BBIDX = COLLECTION(SPRIDX, 7) MIX = SCENEITEMS(I, 0) + BBOX(BBIDX, 0) MIY = SCENEITEMS(I, 1) + BBOX(BBIDX, 1) MIZ = SCENEITEMS(I, 2) + BBOX(BBIDX, 2) MAXX = SCENEITEMS(I, 0) + BBOX(BBIDX, 3) MAY = SCENEITEMS(I, 1) + BBOX(BBIDX, 4) MAZ = SCENEITEMS(I, 2) + BBOX(BBIDX, 5) RES = 0 'TEST COLLISION BETWEEN OBJECT AND PLAYER CALL INSIDEBOX(X, Y, Z, MIX, MIY, MIZ, MAXX, MAY, MAZ, RES) 'FOUND A COLLISION? IF RES = 1 THEN EXIT SUB END IF END IF NEXT I R = 1 END SUB '*************************************** 'CHECK IF POSITION IS INSIDE A DOOR TRIGGER ZONE 'X - X POSITION 'Y - Y POSITION 'Z - Z POSITION 'INDEX - DOOR INDEX ROR WHICH TRIGGER ZONE SHOULD BE TESTED 'R[OUT] - RESULT, 1 IF POS IS INSIDE TRIGGER, OTHERWISE 0 '*************************************** SUB CHECKDOORTRIGGER(X, Y, Z, INDEX, R) MINX = DOORS(INDEX, 1) MINY = DOORS(INDEX, 2) MINZ = DOORS(INDEX, 3) MAXX = DOORS(INDEX, 4) MAXY = DOORS(INDEX, 5) MAXZ = DOORS(INDEX, 6) CALL INSIDEBOX(X, Y, Z, MINX, MINY, MINZ, MAXX, MAXY, MAXZ, R) END SUB '*************************************** 'CHECK IF POSITION IS INSIDE A BOX 'X - X POSITION 'Y - Y POSITION 'Z - Z POSITION 'MINX - MIN BOX X POSITION 'MINY - MIN BOX Y POSITION 'MINZ - MIN BOX Z POSITION 'MAXX - MAX BOX X POSITION 'MAXY - MAX BOX Y POSITION 'MAXZ - MAX BOX Z POSITION 'R[OUT] - RESULT, 1 IF POS IS INSIDE THE BOX, OTHERWISE 0 '*************************************** SUB INSIDEBOX(X, Y, Z, MINX, MINY, MINZ, MAXX, MAXY, MAXZ, R) IF X >= MINX AND Y >= MINY AND Z >= MINZ THEN IF X <= MAXX AND Y <= MAXY AND Z <= MAXZ THEN R = 1 EXIT SUB END IF END IF R = 0 END SUB '*************************************** 'CALLED WHEN A DOOR IS REACHED 'DOOR - THE REACHED DOOR, WHERE: ' 1 - TOP DOOR ' 2 - RIGHT DOOR ' 3 - BOTTOM DOOR ' 4 - LEFT DOOR '*************************************** SUB ONPLAYERREACHEDDOOR(DOOR) IF ROOMCHANGING THEN EXIT SUB END IF ROOMCHANGING = 1 PAL 7 LOCATE 0, 0 IF DOOR = 1 THEN CALL ADDMSG("DOOR 1") NEXTPOSX = 25.25 NEXTPOSY = 135.25 NEXTDIR = 3 ELSE IF DOOR = 2 THEN CALL ADDMSG("DOOR 2") NEXTPOSX = 55.25 NEXTPOSY = 105.25 NEXTDIR = 1 ELSE IF DOOR = 3 THEN CALL ADDMSG("DOOR 3") NEXTPOSX = 25.25 NEXTPOSY = 75.25 NEXTDIR = 2 ELSE IF DOOR = 4 THEN CALL ADDMSG("DOOR 4") NEXTPOSX = -4.75 NEXTPOSY = 105.25 NEXTDIR = 0 END IF END SUB '*************************************** 'DRAW THE SCENE PART WHICH WILL NEVER 'CHANGE DURING THE SCENE LIFETIME '*************************************** SUB DRAWSTATICSCENE BG 0 PAL 0 'DRAW THE SCENE (FROM BACKGROUND DESIGNER) BG COPY 0, 0, 20, 16 TO 0, 0 'DRAW THE DOORS CALL DRAWLEFTDOOR CALL DRAWTOPDOOR CALL DRAWRIGHTDOOR CALL DRAWBOTTOMDOOR END SUB '*************************************** 'DRAW THE SCENE PART WHICH WILL CHANGE 'DYNAMICALLY '*************************************** SUB DRAWSCENE DIM DRAWITEMS(ITEMCOUNT, 5) ENTITYCOUNT = 0 'RASTERIZE THE SCENE ITEMS TO DRAW FOR I = 0 TO UBOUND(SCENEITEMS) - 1 IF SCENEITEMS(I, 5) = 1 THEN X = SCENEITEMS(I, 0) Y = SCENEITEMS(I, 1) Z = SCENEITEMS(I, 2) CALL PROJECTISO(X, Y, Z, DRAWITEMS(I, 0), DRAWITEMS(I, 1)) DRAWITEMS(I, 2) = SCENEITEMS(I, 4) DRAWITEMS(I, 3) = SCENEITEMS(I, 3) INC ENTITYCOUNT END IF NEXT I DIM SORTEDITEMS(ITEMCOUNT) 'SORT THE ITEMS BY Z ORDER CALL SORT(DRAWITEMS(), SORTEDITEMS()) SLOT = 18 'DRAW THE ITEMS IN THE SCENE FOR I = 0 TO ENTITYCOUNT - 1 X = DRAWITEMS(SORTEDITEMS(I), 0) Y = DRAWITEMS(SORTEDITEMS(I), 1) MIRROR = DRAWITEMS(SORTEDITEMS(I), 2) INDEX = DRAWITEMS(SORTEDITEMS(I), 3) CALL DRAWSPRITE(X, Y, MIRROR, INDEX, SLOT) NEXT I END SUB '*************************************** 'SORT THE ITEMS TO DRAW BY Z ORDER 'ENTITIES - SCENE ITEM ENTITIES TO SORT 'RESULT[OUT] - SORTED ITEMS '*************************************** SUB SORT(ENTITIES(), RESULT()) DIM BUCKETS(62, ITEMCOUNT + 1) 'ITERATE THROUGH SCENE ITEMS FOR I = 0 TO UBOUND(SCENEITEMS) - 1 'IS ITEM VISIBLE IN SCENE? IF SCENEITEMS(I, 5) = 1 THEN 'CALCULATE THE DISTANCE FROM CAMERA DISTANCE = INT(ENTITIES(I, 1)) - 35 'IS DISTANCE OUT OF BOUNDS? IF DISTANCE < 62 THEN 'SET ITEM IN BUCKET ARRAY INC BUCKETS(DISTANCE, 0) BUCKETS(DISTANCE, BUCKETS(DISTANCE, 0)) = I END IF END IF NEXT I POS = 0 'ITERATE THROUGH BUCKETS AND SORT THEM BY DISTANCE IN RESULT FOR I = UBOUND(BUCKETS) - 1 TO 0 STEP -1 FOR J = 0 TO BUCKETS(I, 0) - 1 RESULT(POS) = BUCKETS(I, J + 1) INC POS NEXT J NEXT I END SUB '*************************************** 'DRAW A SPRITE FROM THE COLLECTION 'X - SPRITE X POSITION IN PIXELS 'Y - SPRITE Y POSITION IN PIXELS 'MIRROR - IF 1, THE SPRITE WILL BE MIRRORED ON X AXIS 'INDEX - THE SPRITE INDEX TO DRAW IN THE COLLECTION 'SLOT[IN, OUT] - THE NEXT AVAILABLE SPRITE SLOT (I.E SPRITE INDEX) 'NOTE THE POSITION IS BASED ON THE X CENTER AND Y BOTTOM '*************************************** SUB DRAWSPRITE(X, Y, MIRROR, INDEX, SLOT) 'CALCULATE THE CENTER X AND TOP Y POSITION CX = X - 4 TY = Y - COLLECTION(INDEX, 6) 'DRAW THE TOP SPRITE IF COLLECTION(INDEX, 0) <> 0 THEN SPRITE SLOT PAL COLLECTION(INDEX, 3) FLIP MIRROR, 0 SPRITE SLOT, CX, TY, COLLECTION(INDEX, 0) INC SLOT END IF 'DRAW THE MASK SPRITE IF COLLECTION(INDEX, 1) <> 0 THEN SPRITE SLOT PAL COLLECTION(INDEX, 4) FLIP MIRROR, 0 SPRITE SLOT, CX, TY, COLLECTION(INDEX, 1) INC SLOT END IF 'DRAW THE BOTTOM SPRITE IF COLLECTION(INDEX, 2) <> 0 THEN SPRITE SLOT PAL COLLECTION(INDEX, 5) FLIP MIRROR, 0 SPRITE SLOT, CX, Y, COLLECTION(INDEX, 2) INC SLOT END IF END SUB '*************************************** 'DRAW THE TOP DOOR '*************************************** SUB DRAWTOPDOOR IF DOORS(0, 0) = 0 THEN EXIT SUB END IF DIM DOORITEMS(7, 3) CALL FILLDOORITEM(5, 7, 17, DOORITEMS(), 0) CALL FILLDOORITEM(5, 6, 18, DOORITEMS(), 1) CALL FILLDOORITEM(5, 5, 19, DOORITEMS(), 2) CALL FILLDOORITEM(5, 4, 20, DOORITEMS(), 3) CALL FILLDOORITEM(6, 4, 21, DOORITEMS(), 4) CALL FILLDOORITEM(6, 5, 22, DOORITEMS(), 5) CALL FILLDOORITEM(6, 6, 23, DOORITEMS(), 6) CALL DRAWBACKDOOR(DOORITEMS()) END SUB '*************************************** 'DRAW THE RIGHT DOOR '*************************************** SUB DRAWRIGHTDOOR IF DOORS(1, 0) = 0 THEN EXIT SUB END IF DIM DOORITEMS(7, 3) CALL FILLDOORITEM(13, 6, 24, DOORITEMS(), 0) CALL FILLDOORITEM(13, 5, 25, DOORITEMS(), 1) CALL FILLDOORITEM(13, 4, 26, DOORITEMS(), 2) CALL FILLDOORITEM(14, 4, 27, DOORITEMS(), 3) CALL FILLDOORITEM(14, 5, 28, DOORITEMS(), 4) CALL FILLDOORITEM(14, 6, 29, DOORITEMS(), 5) CALL FILLDOORITEM(14, 7, 30, DOORITEMS(), 6) CALL DRAWBACKDOOR(DOORITEMS()) END SUB '*************************************** 'DRAW THE BOTTOM DOOR '*************************************** SUB DRAWBOTTOMDOOR IF DOORS(2, 0) = 0 THEN EXIT SUB END IF DIM DOORITEMS(7, 3) CALL FILLDOORITEM(13, 11, 17, DOORITEMS(), 0) CALL FILLDOORITEM(13, 10, 18, DOORITEMS(), 1) CALL FILLDOORITEM(13, 9, 19, DOORITEMS(), 2) CALL FILLDOORITEM(13, 8, 20, DOORITEMS(), 3) CALL FILLDOORITEM(14, 8, 21, DOORITEMS(), 4) CALL FILLDOORITEM(14, 9, 22, DOORITEMS(), 5) CALL FILLDOORITEM(14, 10, 23, DOORITEMS(), 6) CALL DRAWFRONTDOOR(4, DOORITEMS()) END SUB '*************************************** 'DRAW THE LEFT DOOR '*************************************** SUB DRAWLEFTDOOR IF DOORS(3, 0) = 0 THEN EXIT SUB END IF DIM DOORITEMS(7, 3) CALL FILLDOORITEM(5, 10, 24, DOORITEMS(), 0) CALL FILLDOORITEM(5, 9, 25, DOORITEMS(), 1) CALL FILLDOORITEM(5, 8, 26, DOORITEMS(), 2) CALL FILLDOORITEM(6, 8, 27, DOORITEMS(), 3) CALL FILLDOORITEM(6, 9, 28, DOORITEMS(), 4) CALL FILLDOORITEM(6, 10, 29, DOORITEMS(), 5) CALL FILLDOORITEM(6, 11, 30, DOORITEMS(), 6) CALL DRAWFRONTDOOR(11, DOORITEMS()) END SUB '*************************************** 'FILL A DOOR ITEM 'X - ITEM X POSITION 'Y - ITEM Y POSITION 'C - ITEM CHAR INDEX 'ITEMS() - ITEM LIST CONTAINING ITEM TO FILL 'INDEX - ITEM INDEX TO FILL '*************************************** SUB FILLDOORITEM(X, Y, C, ITEMS(), INDEX) ITEMS(INDEX, 0) = X ITEMS(INDEX, 1) = Y ITEMS(INDEX, 2) = C END SUB '*************************************** 'DRAW A BACK DOOR 'ITEMS() - LIST OF DOOR ITEMS TO DRAW '*************************************** SUB DRAWBACKDOOR(ITEMS()) BG 1 PAL 3 FOR I = 0 TO UBOUND(ITEMS) - 1 CELL ITEMS(I, 0), ITEMS(I, 1), ITEMS(I, 2) NEXT I END SUB '*************************************** 'DRAW A FRONT DOOR 'INDEX - FIRST SPRITE INDEX TO USE 'ITEMS() - LIST OF DOOR ITEMS TO DRAW '*************************************** SUB DRAWFRONTDOOR(INDEX, ITEMS()) FOR I = 0 TO UBOUND(ITEMS) - 1 SPRITE I + INDEX PAL 3 SPRITE I + INDEX, ITEMS(I, 0) * 8, ITEMS(I, 1) * 8, ITEMS(I, 2) NEXT I END SUB '*************************************** 'CALCULATE THE NEARNESS OBJECT VALUE 'INDEX - OBJECT INDEX TO CALCULATE 'VALUE[OUT] - NEARNESS VALUE '*************************************** SUB NEARNESS(INDEX, VALUE) VALUE = SCENEITEMS(INDEX, 0) ADD VALUE, SCENEITEMS(INDEX, 1) ADD VALUE, SCENEITEMS(INDEX, 2) END SUB '*************************************** 'CALCULATE WHICH OBJECT IS CLOSER THE POINT OR VIEW 'LEFTINDEX - LEFT OBJECT INDEX TO COMPARE 'RIGHTINDEX - RIGHT INDEX TO COMPARE WITH 'RESULT[OUT] - THE INDEX OF THE CLOSER OBJECT '*************************************** SUB CLOSER(LEFTINDEX, RIGHTINDEX, RESULT) IF NEARNESS(LEFTINDEX) > NEARNESS(RIGHTINDEX) THEN RESULT = LEFTINDEX ELSE RESULT = RIGHTINDEX END IF END SUB '*************************************** 'PROJECT 3D ISO COORDS TO 2D COORDS 'X - 3D ISO X POSITION 'Y - 3D ISO Y POSITION 'Z - 3D ISO Z POSITION 'XP[OUT] - PROJECTED 2D X POSITION 'YP[OUT] - PROJECTED 2D Y POSITION '*************************************** SUB PROJECTISO(X, Y, Z, XP, YP) XP = Y - X YP = (X * 0.5) + (Y * 0.5) - Z END SUB '*************************************** 'RASTER FUNCTION '*************************************** SUB RASTERFUNC 'SCROLL THE MESSAGE AREA IF RASTER >= 112 AND RASTER < 120 THEN SCROLL 0, MSGX, 0 ELSE SCROLL 0, 0, 0 END IF END SUB BBOXDATA: DATA -4.0, -4.0, -16.0, 4.0, 4.0, 0.0 COLLECTIONDATA: DATA 64, 65, 66, 1, 2, 2, 8, 0, 64, 65, 67, 1, 2, 2, 8, 0 DATA 68, 69, 70, 1, 2, 2, 8, 0, 68, 69, 71, 1, 2, 2, 8, 0 DATA 72, 0, 73, 4, 0, 4, 8, 0, 72, 0, 74, 4, 0, 4, 8, 0 DATA 75, 0, 76, 4, 0, 4, 8, 0, 75, 0, 77, 4, 0, 4, 8, 0 DATA 129, 0, 128, 6, 0, 5, 5, 0 PLAYERDATA: DATA 0.0, 0 DOORDATA: DATA 17.75, 75.25, -24.0, 32.75, 76.25, 0.0 DATA -4.75, 97.25, -24.0, -3.75, 112.75, 0.0 DATA 17.75, 134.25, -24.0, 33.55, 135.25, 0.0 DATA 54.25, 97.75, -24.0, 55.25, 114.25, 0.0 ENTRANCE: DATA 6.5, 86.5, 0.0, 8, 0, 46.5, 86.5, 0.0, 8, 0 DATA 6.5, 125.5, 0.0, 8, 0, 46.5, 125.5, 0.0, 8, 0 #1:MAIN PALETTES 002A1500003906240039061A003F2A15 002B273100392410000E0904003F2A15 #2:MAIN CHARACTERS 00000000000000000000000000000000 00000000030C30C000000000030F3FFF 00000000C0300C0300000000C0F0FCFF 00000000030C30C000000000030F3FFF 030C30C0C0300C03030F3FFFFFFFFFFF C0300C030F3CF0C0C0F0FCFFF3CF3FFF 00000000C0300C0300000000C0F0FCFF 030C30C0C0300C03030F3FFFFF3F0F03 C0300C030F3CF0C0C0F0FCFFF3CC30C0 C0300C0300000000FF3F0F0300000000 0F3CF0C0C0300C03F3CF3FFFFF3F0F03 C0300C030F3CF0C0FFFFFFFFF3CC30C0 0F3CF0C000000000F3CC30C000000000 C0300C0300000000FF3F0F0300000000 0F3CF0C000000000F3CC30C000000000 C0300C030F3CF0C0FFFFFFFFF3CF3FFF 0F3CF0C0C0300C03F3CF3FFFFFFFFFFF A0A0808000000000C0C0C08000000000 A0A0A0A0A0A0A0A0C0C0C0C0C0C0C0C0 20A0A0A0A0A0A0A040C0C0C0C0C0C0C0 0000000000030D34000000000000030C 00030D3DD54505050000020E36C60606 05050505050505050606060606060606 05050505040000000606060604000000 A0A0A0A0200000006060606020000000 A0A0A0A0A0A0A0A06060606060606060 00C0B0BCABA2A0A0000040706C636060 0000000000C0B02C000000000000C030 04050505050505050203030303030303 05050505050505050303030303030303 05050101000000000303030100000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 1C3E7E5B3E1C00001C26426500623C18 00000000000042E700000000000042E7 E7FFFF7F6E6CCC18FFFF7E7C6E0C0000 E7FFFEFE66666CC0FFFFFC7866600000 1C3E7E7F3E3F18001C3E7E7F3E7F3E18 00000000000040E600000000000040E6 FFFFFF7F6E7C6E0CFFFF7E7C6E6C0C00 FFFFFEFE66677660FFFFFC7866666000 00183C7E7C38C07E000000002A041880 7F7EBE3C35160200988199010120640C 7F7E7E3D363210009881590100042C60 00183C7E7C38C07E0000000002041880 7F7EBE3C35360600A499810101083106 7F7E7E3D34363000A499410100010E30 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 0000060E0E0E0C000018667E7E7E3C00 00101020223214080004040808080800 #3:MAIN BG 00001410000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000003000400 05000600000000000000000000000000 00000000000000000000000000000000 030004000F0010000F00100005000600 00000000000000000000002000000000 00000000030004000F0010000F001000 0F0010000F0010000500060000000000 0000002000000000030004000F001000 0F0010000F0010000F0010000F001000 0F001000050006000000002000000000 09000A000F0010000F0010000F001000 0F0010000F0010000F0010000B000C00 00000020000000000000000009000A00 0F0010000F0010000F0010000F001000 0B000C00000000000000000000000000 000000000000000009000A000F001000 0F0010000B000C000000000000000000 00000000000000000000000000000000 0000000009000A000B000C0000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000 #15:MAIN SOUND 2800303A000000001800846C003A0000 08006060000000002800303019FE0000 38002020000000003800505000000000 0800000F000000000800000F00000000 0800000F000000000800000F00000000 0800000F000000000800000F00000000 0800000F000000000800000F00000000 0800000F000000007F0A200008FFCC00 40404040404040404040404040404040 40404040404040404040404040404040 40404040404040404040404040404040 40404040404040404040404040404040 40404040404040404040404040404040 40404040404040404040404040404040 40404040404040404040404040404040 40404040404040404040404040404040 40404040404040404040404040404040 40404040404040404040404040404040 40404040404040404040404040404040 40404040404040404040404040404040 40404040404040404040404040404040 40404040404040404040404040404040 40404040404040404040404040404040 40404040404040404040404040404040 2BFF00FF000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000