GAME.BAS

This is a QBASIC program, which I wrote when I was eighteen - before I started studying programming formally at university. It's a sort of platform game, only there's nobody to shoot at except the wall and powerups for your gun are totally useless (except the first one). Still, it shows what my programming was like when I was eighteen, which is its historical interest.

Assuming you have a QBASIC interpreter in the first place, don't try running this straight under Windows on a modern computer. Use a DOS emulator such as DOSBOX from http://dosbox.sourceforge.net/ instead, and set the number of CPU cycles per second to something like 5376. Set it too high (or without using an emulator) and your man will only be able to jump straight up and down (i.e. no jumping over things) which will make the very first room impossible. Set it too low, and the whole thing will be in slow motion. You'll want to set it just right, and on my computer it's optimised for 5376 cycles per second. YMMV.


REM Display Instructions

    CLEAR : SCREEN 12: CLS : RANDOMIZE TIMER
    FOR x = 1 TO 7
    COLOR x: PRINT "INSTRUCTIONS"
    NEXT x
    PRINT ""
    PRINT "*** KEYS ***"
    PRINT "*    Arrow keys (except down) to move, space to fire, q to quit."
    PRINT ""
    PRINT "*** PLEASE DON'T ***"
    PRINT "*    Do not hold down more than one key at a time.  If you do, your actions may"
    PRINT "     be misinterpreted."
    PRINT ""
    PRINT "*** GAME ELEMENTS ***"
    PRINT "*    Just walk over objects to pick them up."
    PRINT "*    Watch for messages in the top left corner."
    PRINT "*    Shoot wall switches and stand on platform switches.  Switches can be"
    PRINT "     recognised by their colour."
    PRINT ""

REM Prompt To Continue

    PRINT "Continue?"
    COLOR 0: INPUT cont$
    CLS

REM Define keys

    up$ = CHR$(0) + CHR$(72)
    lft$ = CHR$(0) + CHR$(75)
    rght$ = CHR$(0) + CHR$(77)
    fire$ = " ": quit$ = "q"

REM Define constants

    CONST hmov = 10
    CONST bspacing = 10
    CONST mesgstay = 100
    CONST mesgclr = 6
    CONST roomclr = 7:     CONST manclr = 6
    CONST objclr = 4:      CONST bulletclr = 10
    CONST switchwclr = 5:  CONST switchpclr = 3

REM Define Initial Environment Variables

    room = 1
    hposback = 50
    movedirback = hmov
    vmovinit = 20

REM Define Environment Dimensions

    pit = 481:      cheatpit = 1000
    leftside = 10:  rightside = 590
    rooms = 4:      plats = 6

REM Define Other Variables

    gravity = 2.3:   accelgainfreq = 3
    manfreq = 3:     gunfreq = 1
    manheight = 20:  gunheight = 10

REM Define arrays

    DIM wall(rooms, plats)
    DIM platr(rooms, plats):        DIM platg(rooms, plats)
    DIM switchr(rooms, plats - 1):  DIM switchg(rooms, plats - 1)
    DIM onr(rooms, plats - 1):      DIM ong(rooms, plats - 1)

REM Define room 1 platforms

    platr(1, 1) = 200:  platg(1, 1) = 400
    platr(1, 2) = 150:  platg(1, 2) = 350
    platr(1, 3) = 200:  platg(1, 3) = 300
    platr(1, 4) = 180:  platg(1, 4) = 375
    platr(1, 5) = 150:  platg(1, 5) = 481
    platr(1, 6) = 320:  platg(1, 6) = 330
    wall(1, 1) = 75:   wall(1, 2) = 175:  wall(1, 3) = 305
    wall(1, 4) = 355:  wall(1, 5) = 455:  wall(1, 6) = rightside + 10

REM Define room 2 platforms

    platr(2, 1) = 225:  platg(2, 1) = 330
    platr(2, 2) = 170:  platg(2, 2) = 300
    platr(2, 3) = 120:  platg(2, 3) = 481
    platr(2, 4) = 201:  platg(2, 4) = 260
    platr(2, 5) = 201:  platg(2, 5) = 481
    platr(2, 6) = 201:  platg(2, 6) = 300
    wall(2, 1) = 105:   wall(2, 2) = 205:  wall(2, 3) = 305
    wall(2, 4) = 405:  wall(2, 5) = 505:  wall(2, 6) = rightside + 10

REM Define room 3 platforms

    platr(3, 1) = 200:  platg(3, 1) = 300
    platr(3, 2) = 200:  platg(3, 2) = 300
    platr(3, 3) = 250:  platg(3, 3) = 260
    platr(3, 4) = 250:  platg(3, 4) = 260
    platr(3, 5) = 150:  platg(3, 5) = 260
    platr(3, 6) = 50:   platg(3, 6) = 180
    wall(3, 1) = 105:  wall(3, 2) = 205:  wall(3, 3) = 305
    wall(3, 4) = 455:  wall(3, 5) = 555:  wall(3, 6) = rightside + 10

REM Define room 4 platforms

    platr(4, 1) = 50:  platg(4, 1) = 180
    platr(4, 2) = 75:  platg(4, 2) = 200
    platr(4, 3) = 75:  platg(4, 3) = 200
    platr(4, 4) = 75:  platg(4, 4) = 200
    platr(4, 5) = 75:  platg(4, 5) = 200
    platr(4, 6) = 75:  platg(4, 6) = 200
    wall(4, 1) = 105:  wall(4, 2) = 205:  wall(4, 3) = 305
    wall(4, 4) = 405:  wall(4, 5) = 505:  wall(4, 6) = rightside + 10

REM Define visible switches

    switchr(1, 3) = 1:                      switchp(1, 6) = 1
    switchr(2, 2) = 1:  switchg(2, 1) = 1
    switchr(3, 2) = 1:  switchg(3, 2) = 1:  switchp(3, 5) = 1
    switchr(4, 1) = 1:  switchg(4, 1) = 1

REM Define Guns

    DIM gun(rooms, plats)
    gun(1, 3) = 1
    gun(2, 4) = 1
    gun(3, 2) = 1
    gun(3, 6) = 1

REM Define variables reset on death

5   hpos = hposback: GOSUB 10
    vpos = ground
    vmov = vmovinit
    movedir = movedirback

REM Start Main cycle

    DO UNTIL action$ = quit$

REM [Main cycle] Record cycle number as measure of time

        time = time + 1
        IF time = 1000000 THEN
            time = 0
            lostcount = 1
        END IF

REM [Main cycle] Print number lives lost

        LOCATE 1, 1
        COLOR mesgclr
        PRINT "LIVES LOST ="; deaths

REM [Main cycle] Display Messages

        IF mesgtime > 0 THEN LOCATE 2, 1
        PRINT message$
        IF (time - mesgtime) MOD 1000000 = mesgstay THEN
            mesgtime = 0
            CLS
        END IF

REM [Main cycle] Draw platforms

        IF platmov = 1 THEN CLS
        platmov = 0
        FOR x = 1 TO plats
            IF switchp(room, x) = 1 THEN
                    COLOR switchpclr
            ELSE
                    COLOR roomclr
            END IF
            LINE (wall(room, x - 1), platg(room, x))-(wall(room, x), platg(room, x))
            LINE (wall(room, x - 1), platr(room, x))-(wall(room, x), platr(room, x))
        NEXT x

REM [Main cycle] Draw walls

        FOR x = 1 TO plats - 1
            IF switchg(room, x) = 1 THEN
                COLOR switchwclr
            ELSE
                COLOR roomclr
            END IF
            LINE (wall(room, x), platg(room, x))-(wall(room, x), platg(room, x + 1))
            IF switchr(room, x) = 1 THEN
                COLOR switchwclr
            ELSE
                COLOR roomclr
            END IF
            LINE (wall(room, x), platr(room, x))-(wall(room, x), platr(room, x + 1))
        NEXT x

REM [Main cycle] Detect keypress

        action$ = INKEY$

REM [Main cycle] Horizontal movement and room entry

        IF time / manfreq = INT(time / manfreq) THEN
            IF action$ = lft$ THEN
                hpos = hpos - hmov: movedir = -hmov
            ELSEIF action$ = rght$ THEN
                hpos = hpos + hmov: movedir = hmov
            ELSEIF action$ = "" THEN
                IF prevaction$ = lft$ THEN
                    hpos = hpos - hmov: movedir = -hmov
                ELSEIF prevaction$ = rght$ THEN
                    hpos = hpos + hmov: movedir = hmov
                END IF
            END IF
        END IF
        IF hpos < leftside THEN
            room = room - 1
            hpos = rightside
            platmov = 1
        ELSEIF hpos > rightside THEN
            room = room + 1
            hpos = leftside
            platmov = 1
        END IF
        IF room = 0 THEN
            room = 1
            hpos = leftside
            platmov = 0
        ELSEIF room = rooms + 1 THEN
            COLOR mesgclr
            IF lostcount = 1 THEN
                PRINT "You made it to the end, but I lost count of how long you took.  Hit Enter."
            ELSEIF lostcount = 0 THEN
                PRINT "You have got all the way to the end in"; time; "program cycles.  Hit Enter!"
                INPUT cont$
                END
            END IF
        END IF
        GOSUB 10

REM [Main cycle] Narrow passage detection

        IF ground - roof <= gravity + ABS(vmov) THEN
            IF vpos <= ground AND vpos + gravity - vmov >= ground THEN
                vpos = ground
            ELSEIF vpos >= roof AND vpos + gravity + vmov <= roof THEN
                vpos = ground
            END IF
        END IF

REM [Main cycle] Prevent walking through walls
        IF (prevground > ground AND vpos > ground) OR (prevroof < roof AND vpos - manheight < roof) THEN
            hpos = hpos - movedir
            GOSUB 10
        END IF

REM [Main cycle] Check Platform Switches

        onp(room, plat) = 1
        IF vpos = ground THEN
            IF onp(3, 5) = 1 THEN
                IF manheight < 20 THEN
                    manheight = manheight + .5
                    CLS
                END IF
                IF gunheight < 10 THEN
                    gunheight = gunheight + .25
                END IF
            END IF
            IF onp(1, 6) = 1 THEN
                IF wall(1, 5) <> 405 THEN
                    wall(1, 5) = 405
                    wall(1, 4) = 305
                    wall(1, 3) = 205
                    platmov = 1
                    mesgtime = time
                    message$ = "Just to show I can move walls, too..."
                END IF
            END IF
        END IF
        onp(room, plat) = 0

REM [Main cycle] Jumping

        IF action$ = up$ THEN
            jumpseq = 1
        END IF
        IF jumpseq = 1 AND prevjumpseq = 0 THEN
            vpos = vpos - vmov
        END IF

REM [Main cycle] Falling

        IF vpos < ground AND prevvpos = prevground THEN
            IF jumpseq = 0 THEN
                vmov = 0
            END IF
        END IF
        IF time / accelgainfreq = INT(time / accelgainfreq) THEN
            IF vpos < ground THEN
                vmov = vmov - gravity
                vpos = vpos - vmov
            END IF
        END IF

REM [Main cycle] Prevent passing through platforms

        IF vpos - manheight < roof THEN
            vmov = -ABS(vmov)
            vpos = roof + manheight
        ELSEIF vpos > ground THEN
            vpos = ground
        END IF
        IF vpos = ground THEN
            jumpseq = 0
            vmov = vmovinit
        END IF

REM [Main cycle] Death from falling in pit

        IF ground >= pit AND vpos >= ground THEN
            deaths = deaths + 1
            mesgtime = time
            message$ = "You fell and died..."
            GOTO 5
        END IF

REM [Main cycle] Erase man (body, leg, leg, arms, face, head)

        COLOR 0
        LINE (prevhpos, prevvpos - gunheight)-(prevhpos, prevvpos - manheight)
        LINE (prevhpos, prevvpos - gunheight)-(prevhpos - 5, prevvpos)
        LINE (prevhpos, prevvpos - gunheight)-(prevhpos + 5, prevvpos)
        LINE (prevhpos - 5, prevvpos - gunheight)-(prevhpos + 5, prevvpos - gunheight)
        LINE (prevhpos + 5 * SGN(prevmovedir), prevvpos - manheight)-(prevhpos, prevvpos - gunheight)
        LINE (prevhpos + 5 * SGN(prevmovedir), prevvpos - manheight)-(prevhpos, prevvpos - manheight)
  
REM [Main cycle] Draw man (body, leg, leg, arms, face, head)

        COLOR manclr
        LINE (hpos, vpos - gunheight)-(hpos, vpos - manheight)
        LINE (hpos, vpos - gunheight)-(hpos - 5, vpos)
        LINE (hpos, vpos - gunheight)-(hpos + 5, vpos)
        LINE (hpos - 5, vpos - gunheight)-(hpos + 5, vpos - gunheight)
        LINE (hpos + 5 * SGN(movedir), vpos - manheight)-(hpos, vpos - gunheight)
        LINE (hpos + 5 * SGN(movedir), vpos - manheight)-(hpos, vpos - manheight)

REM [Main cycle] Draw Objects

        FOR x = 1 TO plats
            IF gun(room, x) = 1 THEN
                COLOR objclr
                objhpos = (wall(room, x) - wall(room, x - 1)) / 2 + wall(room, x - 1)
                objvpos = platg(room, x)
                LINE (objhpos - 5, objvpos - 10)-(objhpos + 5, objvpos - 10)
                LINE (objhpos - 5, objvpos - 10)-(objhpos - 5, objvpos - 5)
            END IF
        NEXT x

REM [Main cycle] Pick Up Objects

        IF gun(room, plat) = 1 AND vpos = ground THEN
            objhpos = (wall(room, plat) - wall(room, plat - 1)) / 2 + wall(room, plat - 1)
            IF ABS(hpos - objhpos) < 10 THEN
                gun(room, plat) = 0
                radius = radius + 1
                mesgtime = time
                message$ = "MORE GUN POWER!!"
                CLS
            END IF
        END IF

REM [Main cycle] Initiate shooting

        IF action$ = fire$ AND prevshootseq = 0 AND radius > 0 THEN
            shootseq = 1
            shootdir = movedir
            bvpos = vpos - gunheight
            firehpos = hpos
        END IF
        IF shootseq = 1 THEN

REM [Main cycle] [Shooting] Begin moving bullet

            IF time / gunfreq = INT(time / gunfreq) THEN
                fire = fire + 1
                bhpos = firehpos + SGN(shootdir) * fire * bspacing + 10
        
REM [Main cycle] [Shooting] [Moving bullet] Find ground and roof where bullet is

                FOR x = 1 TO plats
                    IF bhpos > wall(room, x - 1) AND bhpos < wall(room, x) THEN
                        bplat = x
                        bground = platg(room, bplat)
                        broof = platr(room, bplat)
                    END IF
                NEXT x

REM [Main cycle] [Shooting] [Moving bullet] Detect Bullet Hitting Lower Wall (and activate switch)

                IF bvpos > bground THEN
                    shootseq = 0
                    IF shootdir > 0 THEN
                        ong(room, bplat - 1) = 1
                    ELSEIF shootdir < 0 THEN
                        ong(room, bplat) = 1
                    END IF
                    IF ABS(hpos - 300) <> 290 THEN
                       IF ong(2, 1) = 1 THEN
                           platr(2, 6) = 200: platr(3, 1) = 200
                           mesgtime = time: message$ = "Something moved..."
                       END IF
                       IF ong(3, 2) = 1 THEN
                           platr(2, 6) = 260: platr(3, 1) = 260
                           mesgtime = time: message$ = "The roof lowered..."
                       END IF
                       IF ong(4, 1) = 1 THEN
                           FOR x = 3 TO 6
                               platg(4, x) = RND * 750
                               IF platg(4, x) < platr(4, x) THEN x = x - 1
                           NEXT x
                           mesgtime = time: message$ = "Watch this!"
                       END IF
                    END IF
                    IF shootdir > 0 THEN ong(room, bplat - 1) = 0
                    IF shootdir < 0 THEN ong(room, bplat) = 0
                    platmov = 1
                END IF

REM [Main cycle] [Shooting] [Moving bullet] Detect Bullet Hitting Upper Wall (and activate switch)

                IF bvpos < broof THEN
                    shootseq = 0
                    IF shootdir > 0 THEN onr(room, bplat - 1) = 1
                    IF shootdir < 0 THEN onr(room, bplat) = 1
                    IF ABS(hpos - 300) <> 290 THEN
                        IF onr(1, 3) = 1 THEN
                            platr(1, 6) = 225
                            mesgtime = time: message$ = "The door opened..."
                        END IF
                        IF onr(2, 2) = 1 THEN
                            platr(2, 5) = 130
                            platr(2, 6) = 290: platr(3, 1) = 290
                            mesgtime = time: message$ = "You probably thought this would let you through..."
                        END IF
                        IF onr(3, 2) = 1 THEN
                            mesgtime = time: message$ = "YOU HAVE BEEN TRANSFORMED INTO A RAT!"
                            manheight = 2: gunheight = 1
                        END IF
                        IF onr(4, 1) = 1 THEN
                            FOR x = 3 TO 6
                                platr(4, x) = RND * 450
                                IF platr(4, x) > platg(4, x) THEN x = x - 1
                                mesgtime = time: message$ = "Watch this!"
                            NEXT x
                        END IF
                    END IF
                    IF shootdir > 0 THEN onr(room, bplat - 1) = 0
                    IF shootdir < 0 THEN onr(room, bplat) = 0
                    platmov = 1
               END IF
           
REM [Main cycle] [Shooting] [Moving bullet] Check bullet still moving

                IF bhpos < 0 THEN shootseq = 0
                IF bhpos > 600 THEN shootseq = 0
                IF prevroom <> room THEN shootseq = 0
                IF shootseq = 0 THEN fire = 0

REM [Main cycle] [Shooting] [Moving bullet] Draw bullet

                FOR x = 1 TO radius
                    CIRCLE (prevbhpos, bvpos), x, 0
                NEXT x
                IF shootseq = 1 THEN
                    FOR x = 1 TO radius
                        CIRCLE (bhpos, bvpos), x, bulletclr
                    NEXT x
                END IF

REM [Main cycle] Finish moving bullet and shooting

            END IF
        END IF

REM [Main cycle] Store variables redefined each cycle

        prevhpos = hpos: prevvpos = vpos
        prevground = ground: prevroof = roof
        prevshootseq = shootseq: prevjumpseq = jumpseq
        prevmovedir = movedir
        prevbhpos = bhpos
        prevroom = room
        IF action$ <> "" THEN prevaction$ = action$
        IF time / manfreq = INT(time / manfreq) THEN prevaction$ = ""
        IF vpos = ground THEN IF ground < pit THEN hposback = hpos: movedirback = movedir

REM Finish Main Cycle

    LOOP
    END

10 REM Find current platform - GOSUB WHEN horizontal position redefined

    FOR x = 1 TO plats
    IF hpos > wall(room, x - 1) THEN
        IF hpos < wall(room, x) THEN
            ground = platg(room, x): roof = platr(room, x)
            plat = x
            END IF
        END IF
    NEXT x
    RETURN