Welcome, Guest
You have to register before you can post on our site.

Username/Email:
  

Password
  





Search Forums

(Advanced Search)

Forum Statistics
» Members: 501
» Latest member: BryanCheat
» Forum threads: 2,856
» Forum posts: 26,766

Full Statistics

Latest Threads
Trojan infection !
Forum: Help Me!
Last Post: PhilOfPerth
1 hour ago
» Replies: 4
» Views: 80
Qix line monster
Forum: Programs
Last Post: Abazek
3 hours ago
» Replies: 0
» Views: 14
Tenary operator in QB64 w...
Forum: Utilities
Last Post: eoredson
5 hours ago
» Replies: 8
» Views: 301
_IIF limits two question...
Forum: General Discussion
Last Post: NakedApe
9 hours ago
» Replies: 10
» Views: 425
Curious if I am thinking ...
Forum: Help Me!
Last Post: bplus
9 hours ago
» Replies: 28
» Views: 395
Aloha from Maui guys.
Forum: General Discussion
Last Post: SMcNeill
Yesterday, 10:38 PM
» Replies: 17
» Views: 491
Glow Bug
Forum: Programs
Last Post: SierraKen
Yesterday, 06:33 PM
» Replies: 7
» Views: 129
ADPCM compression
Forum: Petr
Last Post: Petr
Yesterday, 03:13 PM
» Replies: 0
» Views: 41
Who wants to PLAY?
Forum: QBJS, BAM, and Other BASICs
Last Post: dbox
Yesterday, 02:47 PM
» Replies: 15
» Views: 243
BAM Sample Programs
Forum: QBJS, BAM, and Other BASICs
Last Post: CharlieJV
Yesterday, 02:50 AM
» Replies: 36
» Views: 2,003

 
  _Round () issue
Posted by: dcromley - 05-11-2022, 04:08 AM - Forum: Help Me! - Replies (17)

I know this is a 'nit -- a very minor thing, but it probably should be fixed in the future.

It is that _Round(5/10) should be 1, but it is 0.  And there is a pattern: 25, 45, 65, etc. 
But maybe that is an alternative rule that I don't know about.  It is a 'nit.

Code: (Select All)
[ deleted 5/13 - incorrect ]

Print this item

  Phoenix Edition Repo Info
Posted by: SMcNeill - 05-11-2022, 01:59 AM - Forum: SMcNeill - Replies (5)

(Say that title ten times fast!  That's a great tongue twister!)

Code: (Select All)
Screen _NewImage(1024, 720, 32)
com$ = "curl -H " + Chr$(34) + "Accept: application/vnd.github.v3+json" + Chr$(34)
com$ = com$ + " https://api.github.com/repos/QB64-Phoenix-Edition/QB64pe/releases"
com$ = com$ + " >temp.txt"

Shell _Hide com$
_Delay 1 'give the os time to download and create the file
Open "temp.txt" For Binary As #1
Do Until EOF(1)
    Line Input #1, temp$
    If InStr(temp$, "download_count") Then Print Mid$(temp$, 27);
    If InStr(temp$, "browser_download_url") Then Print Mid$(temp$, 33)
Loop

For anyone who wants to take a look at the number of downloads the Phoenix Edition has for each release, you can use the little app above to do so.

If you're really curious about a lot more junk than just the download count, you can open the "temp.txt" and get a whole status report on the repo and the releases and such.  I'm not certain if anyone else would be interested in this type of thing, but I thought I'd share just in case.  Wink

Print this item

  Remember SBMIDI?
Posted by: davidshq - 05-10-2022, 10:35 PM - Forum: Help Me! - Replies (1)

Hi All,

One of the games I'm working with comes bundled with SBMIDI, it appears to be a sound driver of sorts for Soundblaster back in the day. See for example:
https://github.com/creationix/basic-game...I.DOC#L147

I'm trying to figure out what if anything I need to do to have the sound continue to work in QB64. The SBMIDI files aren't Windows compatible and I don't have the source code.

Any suggestions?

Thanks!
Dave

Print this item

  Spiro - A Simulation
Posted by: TarotRedhand - 05-10-2022, 07:02 AM - Forum: Programs - Replies (13)

Another adaptation of an old QB4.5 program of mine. This is a simulation of a Spirograph. To be precise it simulates the result of a wheel that runs around inside a larger wheel and the patterns that can be created with different diameters of the small wheel and offsets from its centre. It is easy to use and is something of a rabbit hole that you may well disappear down into. While instructions are included in the comments, here is the relevant text -

Quote:To experiment with the patterns that this program can produce it is only necessary to alter the values held in two constants.  These constants are SmallDiameter# and Offset#.  Changing the value in SmallDiameter# will alter the overall shape of the pattern while altering Offset# will change the "pointyness" of the peaks.  To see what I am talking about, simply play around with these constants.  Note that it is not necessary to change both values every time that you wish to change the pattern.


If you find values for one or the other of those constants feel free to post them in here. To start you off try a value of 100 for SmallDiameter#. One little warning - it is possible to get the drawing to run off the screen although this doesn't crash the program.

SPIRO.BAS
Code: (Select All)
'===========================================================================
' Subject: SIMULATION OF A SPIROGRAPH        Date: 02-23-99 (21:53)
'  Author: TarotRedhand                      Code: QB, QBasic, PDS
'===========================================================================
'SPIRO.BAS - A simulation of the most used part of the toy called a
'            spirograph.  Public domain.  Use entirely at own risk.  The
'            author accepts no liability whatsoever.  In the case that I have
'            used a registered trademark, I apologise.  I do not at this time
'            own any trademarks.
'
' There is a toy called a spirograph that is used to make curved patterns.
' This toy consists of a number of pieces that are made from transparent
' plastic and a number of ball-point pens with different coloured inks in them.
' Each piece has gear-teeth along their outside edges.  The gear-teeth are
' all of the same size, independent of the piece that they are on.  In
' addition each piece has a number of holes in them, which are designed to
' accept a pen point.
'
' This program works in VGA mode 12 graphics and is a simulation of the most
' often used part of that toy.  It simulates the use of 2 of the plastic pieces
' to produce a circular pattern.  As this program uses double-precision
' numbers and maths, it is comparatively slow.  One thing that I have done to
' speed this up is to have 2 identical SUBs with STATIC variables in them.
' This works by ensuring that the built-in functions SIN and COS are only
' called once for each of the 2 angles that are used.
'
' RULES
'
' In order to use this program there are a few rules that you should be aware
' of.  DO NOT alter the value of the constant LargeDiameter#.  DO NOT place a
' value in the constant SmallDiameter# that is less than or equal to zero or
' greater than or equal to the value in LargeDiameter#.  DO NOT place a value
' greater than one or less than or equal to zero in the constant Offset.
' Violation of any of these rules will result in at best, the program
' attempting to draw off of the screen.
'
' Using this program.
'
' To experiment with the patterns that this program can produce it is only
' necessary to alter the values held in two constants.  These constants are
' SmallDiameter# and Offset#.  Changing the value in SmallDiameter# will alter
' the overall shape of the pattern while altering Offset# will change the
' "pointyness" of the peaks.  To see what I am talking about, simply play
' around with these constants.  Note that it is not necessary to change both
' values every time that you wish to change the pattern.
'
' Anyway, have fun.
'
' TarotRedhand - 11/1998
'
Const PI# = 3.141592653589793#
Const LargeDiameter# = 478
Const SmallDiameter# = 333
Const CenterX# = 320, CenterY# = 240
Const Offset# = .725
Const Angle1# = 1
Const StartColour = 1
Const EndColour = 13
Const FALSE% = 0
Const TRUE% = Not FALSE%

LC# = (PI# * LargeDiameter#) / 360
A2# = 360 / ((PI# * SmallDiameter#) / LC#)
SmallRadius# = SmallDiameter# / 2
SmallCenterY# = 1 + SmallRadius#
SmallCenterX# = CenterX#
StartX# = CenterX#
StartY# = 1 + SmallRadius# - (SmallRadius# * Offset#)
MyX# = StartX#
MyY# = StartY#
Orbit1 SmallCenterX#, SmallCenterY#, CenterX#, CenterY#, Angle1#, TRUE%
Orbit1 MyX#, MyY#, CenterX#, CenterY#, Angle1#, FALSE%
Orbit2 MyX#, MyY#, SmallCenterX#, SmallCenterY#, -A2#, TRUE%
Screen 12
_FullScreen _SquarePixels
Line (1, 1)-(640, 480), 15, BF
Colour = StartColour
Line (StartX#, StartY#)-(MyX#, MyY#), Colour
Do
    For Index% = 1 To 360
        Orbit1 SmallCenterX#, SmallCenterY#, CenterX#, CenterY#, Angle1#, FALSE%
        Orbit1 MyX#, MyY#, CenterX#, CenterY#, Angle1#, FALSE%
        Orbit2 MyX#, MyY#, SmallCenterX#, SmallCenterY#, -A2#, FALSE%
        Line -(MyX#, MyY#), Colour
        _Delay 0.002
        If InKey$ <> "" Then
            Exit Do
        End If
    Next Index%
    Colour = Colour + 1
    If Colour > EndColour Then Colour = StartColour
Loop
End

Sub Orbit1 (PointX#, PointY#, OrbitX#, OrbitY#, Angle#, FirstTime%)
    Static C#, S#
    If FirstTime% Then
        C# = Cos(Angle# * (PI# / 180#))
        S# = Sin(Angle# * (PI# / 180#))
    End If
    OldX# = PointX# - OrbitX#
    OldY# = PointY# - OrbitY#
    PointX# = (OldX# * C# - OldY# * S#) + OrbitX#
    PointY# = (OldX# * S# + OldY# * C#) + OrbitY#
End Sub

Sub Orbit2 (PointX#, PointY#, OrbitX#, OrbitY#, Angle#, FirstTime%)
    Static C#, S#
    If FirstTime% Then
        C# = Cos(Angle# * (PI# / 180#))
        S# = Sin(Angle# * (PI# / 180#))
    End If
    OldX# = PointX# - OrbitX#
    OldY# = PointY# - OrbitY#
    PointX# = (OldX# * C# - OldY# * S#) + OrbitX#
    PointY# = (OldX# * S# + OldY# * C#) + OrbitY#
End Sub

TR

Print this item

  My masterpiece - 13,500+ lines - WIM-Tools, Windows Image Management Tools
Posted by: hanness - 05-09-2022, 09:58 PM - Forum: Programs - No Replies

I'm not a professional programmer, just a hobbyist, but I'm proud of what I was able to accomplish with QB64.

This is a program that will be of interest to a limited audience. It's for those who want to be able to manage, update, manipulate, and deploy Windows 10 and 11 images and media.

I've spent years learning how to perform all these tasks, and more importantly, how to do them the RIGHT way. I've poured all that knowledge into this program.

If this sounds like something that you might be at all interested in check it out on my GitHub page. It was simply too large to post here.

hsehestedt (github.com)

Print this item

  Optimized bash script compilation of QB64 for Linux
Posted by: Coolman - 05-09-2022, 03:54 PM - Forum: General Discussion - Replies (1)

This script was located in this post : why the qb64 editor is slow under linux

to simplify the updates, I created this dedicated post.


after reading some information about gcc, i decided to use the -O3 compiler option. it's a good compromise between security and speed.

if this is your first installation of qb64, it is advised to run the script setup_lnx.sh to install the package dependencies necessary for qb64...

this script allows to insert the -O3 compiler option of gcc g++ to optimize qb64. the original files are saved. i removed some useless sections of the original script setup_lnx.sh. download the source code of qb64, unzip, put the script in the directory where is setup_lnx.sh, make it executable and run it. the processing is automatic. if the compilation was successful, the qb64 executable will be created:

compile_qb64.sh

Code: (Select All)
#!/bin/bash
# QB64 Installer
# Argument 1: If not blank, qb64 will not be started after compilation

dont_run="$1"

#This checks the currently installed packages for the one's QB64 needs
#And runs the package manager to install them if that is the case
# *** SECTION ENLEVE ***


#Make sure we're not running as root
if [ $EUID == "0" ]; then
  echo "You are trying to run this script as root. This is highly unrecommended."
  echo "This script will prompt you for your sudo password if needed to install packages."
  exit 1
fi

GET_WGET=
#Path to Icon
#Relative Path to icon -- Don't include beginning or trailing '/'
QB64_ICON_PATH="internal/source"

#Name of the Icon picture
QB64_ICON_NAME="qb64icon32.png"

DISTRO=

lsb_command=`which lsb_release 2> /dev/null`
if [ -z "$lsb_command" ]; then
  lsb_command=`which lsb_release 2> /dev/null`
fi

#Outputs from lsb_command:

#Arch Linux  = arch
#Debian      = debian
#Fedora      = Fedora
#KUbuntu     = ubuntu
#LUbuntu     = ubuntu
#Linux Mint  = linuxmint
#Ubuntu      = ubuntu
#Slackware   = slackware
#VoidLinux   = voidlinux
#XUbuntu     = ubuntu
#Zorin       = Zorin
if [ -n "$lsb_command" ]; then
  DISTRO=`$lsb_command -si | tr '[:upper:]' '[:lower:]'`
elif [ -e /etc/arch-release ]; then
  DISTRO=arch
elif [ -e /etc/debian_version ] || [ -e /etc/debian_release ]; then
  DISTRO=debian
elif [ -e /etc/fedora-release ]; then
  DISTRO=fedora
elif [ -e /etc/redhat-release ]; then
  DISTRO=redhat
elif [ -e /etc/centos-release ]; then
  DISTRO=centos
fi

#Find and install packages
# *** SECTION ENLEVE ***

echo "Compiling and installing QB64..."

### Build process
find . -name "*.sh" -exec chmod +x {} \;
find internal/c/parts -type f -iname "*.a" -exec rm -f {} \;
find internal/c/parts -type f -iname "*.o" -exec rm -f {} \;
find internal/c/libqb -type f -iname "*.o" -exec rm -f {} \;
rm ./internal/temp/*

echo "Modification 'makeline*'"
cp ./internal/c/makeline_lnx.txt ./internal/c/makeline_lnx_ORG.txt
find ./internal/c -type f -name "makeline_lnx.txt" -print0 | xargs -0 sed -i 's/g++ -no-pie -w qbx.cpp/g++ -O3 -no-pie -w qbx.cpp/g'
cp ./internal/c/makeline_lnx_nogui.txt ./internal/c/makeline_lnx_nogui_ORG.txt
find ./internal/c -type f -name "makeline_lnx_nogui.txt" -print0 | xargs -0 sed -i 's/g++ -no-pie -w qbx.cpp/g++ -O3 -no-pie -w qbx.cpp/g'

echo "Building library 'LibQB'"
pushd internal/c/libqb/os/lnx >/dev/null
rm -f libqb_setup.o
cp setup_build.sh setup_build_ORG.sh
cp build_test.sh build_test_ORG.sh
find . -type f -name "*.sh" -print0 | xargs -0 sed -i 's/g++ -c -w -Wall/g++ -O3 -c -w -Wall/g'
./setup_build.sh
popd >/dev/null

echo "Building library 'FreeType'"
pushd internal/c/parts/video/font/ttf/os/lnx >/dev/null
rm -f src.o
cp setup_build.sh setup_build_ORG.sh
cp build.sh build.sh_ORG.sh
find . -type f -name "*.sh" -print0 | xargs -0 sed -i 's/g++ -s -c -w -Wall/g++ -s -O3 -c -w -Wall/g'
./setup_build.sh
popd >/dev/null

echo "Building library 'Core:FreeGLUT'"
pushd internal/c/parts/core/os/lnx >/dev/null
rm -f src.a
cp setup_build.sh setup_build_ORG.sh
cp build.sh build.sh_ORG.sh
find . -type f -name "*.sh" -print0 | xargs -0 sed -i 's/gcc -s -O2 -c/gcc -s -O3 -c/g'
./setup_build.sh
popd >/dev/null

echo "Building 'QB64'"
tar -czvf ./internal/source/main.tar.gz ./internal/source/main.txt
find ./internal/source -type f -name "main.txt" -print0 | xargs -0 sed -i 's/g++ -c -s -w -Wall libqb.cpp -D FREEGLUT_STATIC/g++ -O3 -c -s -w -Wall libqb.cpp -D FREEGLUT_STATIC/g'
cp -r ./internal/source/* ./internal/temp/
pushd internal/c >/dev/null
g++ -O3 -no-pie -w qbx.cpp libqb/os/lnx/libqb_setup.o parts/video/font/ttf/os/lnx/src.o parts/core/os/lnx/src.a -lGL -lGLU -lX11 -lpthread -ldl -lrt -D FREEGLUT_STATIC -o ../../qb64
popd

if [ -e "./qb64" ]; then
  echo "DISTRO: $DISTRO"
  echo "Done compiling!!"
  echo
  echo "QB64 is located in this folder:"
  echo "`pwd`"
else
  ### QB64 didn't compile
  echo "It appears that the qb64 executable file was not created, this is usually an indication of a compile failure (You probably saw lots of error messages pop up on the screen)"
  echo "Usually these are due to missing packages needed for compilation. If you're not running a distro supported by this compiler, please note you will need to install the packages listed above."
  echo "If you need help, please feel free to post on the QB64 Forums detailing what happened and what distro you are using."
  echo "Also, please tell them the exact contents of this next line:"
  echo "DISTRO: $DISTRO"
fi
echo
echo "Thank you for using the QB64 installer."

Print this item

  Find the ball - classic shell game
Posted by: Dav - 05-09-2022, 01:00 PM - Forum: Programs - Replies (20)

I put this together last night for a younger relative to play.  It's the classic cups and ball, or shell game.  The ball hides under a cup, cups are shuffled around, you click on the cup you think the ball is under.  There's no score keeping, it just keeps looping over with a new game.  Mildly entertaining to play for a while I suppose.  The fun for me was making it.  This uses the power of RotoZoom3 to animate/shuffle the cups. 

- Dav

Code: (Select All)
'============
'FINDBALL.BAS
'============
'Classic Cups & Ball game (shell game)
'Coded by Dav, MAY/2022

'Cups will shuffle.  Click the cup with the ball.
'If selected correctly, screen flashes green.  If not,
'screen will flash red.  This could be turned into a
'game easy, with score keeping and speed changes.
'For now it just loops over and over.

RANDOMIZE TIMER

SCREEN _NEWIMAGE(1000, 600, 32)

cup& = BASIMAGE1& 'decode cup image to use
ball& = BASIMAGE2& 'decode ball image to use

'=== draw background
CLS , _RGB(232, 232, 255)
LINE (0, 350)-(_WIDTH, _HEIGHT), _RGB(128, 255, 128), BF

'=== grab background image
back& = _COPYIMAGE(_DISPLAY)

speed = 75 'speed for _LIMIT
moves = 15 'how many shuffle moves to do


DO

    cupball = INT(RND * 3) + 1 'make random cupball number (1,2,or 3)

    GOSUB ShowBall 'show where ball is first

    'shuffle the cups
    FOR m = 1 TO moves
        SELECT CASE INT(RND * 6) + 1 'random move
            CASE 1: GOSUB move1to2
            CASE 2: GOSUB move1to3
            CASE 3: GOSUB move2to1
            CASE 4: GOSUB move2to3
            CASE 5: GOSUB move3to1
            CASE 6: GOSUB move3to2
        END SELECT
    NEXT

    GOSUB PlaceCups 'make sure they are placed right

    selected = 0 'not selected yet

    DO
        WHILE _MOUSEINPUT: WEND
        IF _MOUSEBUTTON(1) THEN
            mx = _MOUSEX: my = _MOUSEY
            'clicked cup 1
            IF mx > 114 AND mx < 316 AND my > 146 AND my < 439 THEN
                IF cupball = 1 THEN selected = 1
                EXIT DO
            END IF
            'clicked cup 2
            IF mx > 378 AND mx < 600 AND my > 146 AND my < 439 THEN
                IF cupball = 2 THEN selected = 1
                EXIT DO
            END IF
            'clicked cup 3
            IF mx > 694 AND mx < 911 AND my > 146 AND my < 439 THEN
                IF cupball = 3 THEN selected = 1
                EXIT DO
            END IF
        END IF
    LOOP

    'make sure mouse button up to continue
    DO UNTIL _MOUSEBUTTON(1) = 0: m = _MOUSEINPUT: LOOP

    'flash screen based on selection
    IF selected = 0 THEN
        'flash red - wrong one
        LINE (0, 0)-(_WIDTH, _HEIGHT), _RGBA(255, 0, 0, 100), BF
        _DISPLAY
        _DELAY .25
    ELSE
        'flash green - selected right
        LINE (0, 0)-(_WIDTH, _HEIGHT), _RGBA(0, 255, 0, 100), BF
        _DISPLAY
        _DELAY .25
    END IF

    GOSUB ShowBall 'show where ball is

LOOP

END

'===================================================================
PlaceCups: 'shows all cups in place
'=========
'Place all cups first
_PUTIMAGE (0, 0), back&
RotoZoom3 200, 300, cup&, 1, 1, 0
RotoZoom3 500, 300, cup&, 1, 1, 0
RotoZoom3 800, 300, cup&, 1, 1, 0
_DISPLAY
RETURN
'=====

'===================================================================
ShowBall: 'Raises cup to show ball
'=======

'make sure showing all cups first
GOSUB PlaceCups

_DISPLAY: _DELAY 1

'raise a cup based on cupball number
SELECT CASE cupball
    CASE IS = 1 'raise cup 1
        _PUTIMAGE (0, 0), back&
        FOR y = 300 TO 175 STEP -7
            _PUTIMAGE (0, 0), back&
            RotoZoom3 500, 300, cup&, 1, 1, 0
            RotoZoom3 800, 300, cup&, 1, 1, 0
            RotoZoom3 210, 400, ball&, 1, 1, 0 'ball first
            RotoZoom3 200, y, cup&, 1, 1, 0 'cup over
            _DISPLAY
            _LIMIT 50
        NEXT
    CASE IS = 2 'raise cup 2
        _PUTIMAGE (0, 0), back&
        FOR y = 300 TO 175 STEP -7
            _PUTIMAGE (0, 0), back&
            RotoZoom3 200, 300, cup&, 1, 1, 0
            RotoZoom3 800, 300, cup&, 1, 1, 0
            RotoZoom3 510, 400, ball&, 1, 1, 0 'ball first
            RotoZoom3 500, y, cup&, 1, 1, 0 'cup over
            _DISPLAY
            _LIMIT 50
        NEXT
    CASE IS = 3 'raise cup 3
        _PUTIMAGE (0, 0), back&
        FOR y = 300 TO 175 STEP -7
            _PUTIMAGE (0, 0), back&
            RotoZoom3 200, 300, cup&, 1, 1, 0
            RotoZoom3 500, 300, cup&, 1, 1, 0
            RotoZoom3 810, 400, ball&, 1, 1, 0 'ball first
            RotoZoom3 800, y, cup&, 1, 1, 0 'cup over
            _DISPLAY
            _LIMIT 50
        NEXT
END SELECT

_DELAY 1 'pause to see ball

'now lower the same a cup
SELECT CASE cupball
    CASE IS = 1 'lower cup 1
        _PUTIMAGE (0, 0), back&
        FOR y = 175 TO 300 STEP 7
            _PUTIMAGE (0, 0), back&
            RotoZoom3 500, 300, cup&, 1, 1, 0
            RotoZoom3 800, 300, cup&, 1, 1, 0
            RotoZoom3 210, 400, ball&, 1, 1, 0 'ball first
            RotoZoom3 200, y, cup&, 1, 1, 0 'cup over
            _DISPLAY
            _LIMIT 50
        NEXT
    CASE IS = 2 'lower cup 2
        _PUTIMAGE (0, 0), back&
        FOR y = 175 TO 300 STEP 7
            _PUTIMAGE (0, 0), back&
            RotoZoom3 200, 300, cup&, 1, 1, 0
            RotoZoom3 800, 300, cup&, 1, 1, 0
            RotoZoom3 510, 400, ball&, 1, 1, 0 'ball first
            RotoZoom3 500, y, cup&, 1, 1, 0 'cup over
            _DISPLAY
            _LIMIT 50
        NEXT
    CASE IS = 3 'lower cup 3
        _PUTIMAGE (0, 0), back&
        FOR y = 175 TO 300 STEP 7
            _PUTIMAGE (0, 0), back&
            RotoZoom3 200, 300, cup&, 1, 1, 0
            RotoZoom3 500, 300, cup&, 1, 1, 0
            RotoZoom3 810, 400, ball&, 1, 1, 0 'ball first
            RotoZoom3 800, y, cup&, 1, 1, 0 'cup over
            _DISPLAY
            _LIMIT 50
        NEXT
END SELECT

RETURN
'=====


'===================================================================
move1to2: 'moves cup 1 over to cup 2
'=======
cup1z = 1: cup2z = 1: cup3z = 1
FOR move = 1 TO 300 STEP 15
    _PUTIMAGE (0, 0), back& 'redraw background
    'cup 3 stays in place
    RotoZoom3 800, 300, cup&, cup3z, cup3z, 0
    'cup 2 shrinks, going under cup 1, moving left
    RotoZoom3 500 - move, 300 - cup2z, cup&, cup2z, cup2z, 0
    IF move > 150 THEN cup2z = cup2z + .03 ELSE cup2z = cup2z - .03
    'cup 1 enlarges, going over cup 2, moving right
    RotoZoom3 200 + move, 300 * cup1z, cup&, cup1z, cup1z, 0
    IF move > 150 THEN cup1z = cup1z - .03 ELSE cup1z = cup1z + .03
    _DISPLAY
    _LIMIT speed
NEXT
'swap ball placement
SELECT CASE cupball
    CASE 1: cupball = 2
    CASE 2: cupball = 1
END SELECT

RETURN
'=====


'===================================================================
move1to3: 'move cup 1 over to cup 3
'=======
cup1z = 1: cup2z = 1: cup3z = 1
FOR move = 1 TO 300 STEP 8
    _PUTIMAGE (0, 0), back&
    'cup 3 shrinks, moves left two places
    RotoZoom3 800 - (move * 2), 300 - cup3z, cup&, cup3z, cup3z, 0
    IF move > 150 THEN cup3z = cup3z + .02 ELSE cup3z = cup3z - .02
    'cup 2 stays in place
    RotoZoom3 500, 300, cup&, cup2z, cup2z, 0
    'cup 1 enlarges, moving right two places
    RotoZoom3 200 + (move * 2), 300 * cup1z, cup&, cup1z, cup1z, 0
    IF move > 150 THEN cup1z = cup1z - .02 ELSE cup1z = cup1z + .02
    _DISPLAY
    _LIMIT speed * 1.7
NEXT
SELECT CASE cupball
    CASE 1: cupball = 3
    CASE 3: cupball = 1
END SELECT

RETURN
'=====

'===================================================================
move2to1: 'move cup 2 over to cup 1
'=======
cup1z = 1: cup2z = 1: cup3z = 1
FOR move = 1 TO 300 STEP 15
    _PUTIMAGE (0, 0), back&
    '3rd cup stays in place
    RotoZoom3 800, 300, cup&, cup3z, cup3z, 0
    'cup 1 shrinks, moving right
    RotoZoom3 200 + move, 300 - cup1z, cup&, cup1z, cup1z, 0
    IF move > 150 THEN cup1z = cup1z + .03 ELSE cup1z = cup1z - .03
    'cup 2 enlarges, moving left
    RotoZoom3 500 - move, 300 * cup2z, cup&, cup2z, cup2z, 0
    IF move > 150 THEN cup2z = cup2z - .03 ELSE cup2z = cup2z + .03
    _DISPLAY
    _LIMIT speed
NEXT
SELECT CASE cupball
    CASE 1: cupball = 2
    CASE 2: cupball = 1
END SELECT

RETURN
'=====

'===================================================================
move2to3: 'move cup 2 over to cup 3
'=======
cup1z = 1: cup2z = 1: cup3z = 1
FOR move = 1 TO 300 STEP 15
    _PUTIMAGE (0, 0), back&
    'cup 1 stays in place
    RotoZoom3 200, 300, cup&, cup1z, cup1z, 0
    'cup 3 shrinks under, moves left 1 cup,
    RotoZoom3 800 - move, 300 - cup3z, cup&, cup3z, cup3z, 0
    IF move > 150 THEN cup3z = cup3z + .03 ELSE cup3z = cup3z - .03
    'cup 2 enlarges over, moves right 1 cup
    RotoZoom3 500 + move, 300 * cup2z, cup&, cup2z, cup2z, 0
    IF move > 150 THEN cup2z = cup2z - .03 ELSE cup2z = cup2z + .03
    _DISPLAY
    _LIMIT speed
NEXT
SELECT CASE cupball
    CASE 2: cupball = 3
    CASE 3: cupball = 2
END SELECT

RETURN

'===================================================================
move3to1: 'move cup 3 over to cup 1
'=======
cup1z = 1: cup2z = 1: cup3z = 1
FOR move = 1 TO 300 STEP 8
    _PUTIMAGE (0, 0), back&
    'cup 1 shrinks under, moving right two cup places,
    RotoZoom3 200 + (move * 2), 300 - cup1z, cup&, cup1z, cup1z, 0
    IF move > 150 THEN cup1z = cup1z + .02 ELSE cup1z = cup1z - .02
    'cup2 stays in place
    RotoZoom3 500, 300, cup&, cup2z, cup2z, 0
    'cup 3 enlarges over, moving left two cup places,
    RotoZoom3 800 - (move * 2), 300 * cup3z, cup&, cup3z, cup3z, 0
    IF move > 150 THEN cup3z = cup3z - .02 ELSE cup3z = cup3z + .02
    _DISPLAY
    _LIMIT speed * 1.7
NEXT
SELECT CASE cupball
    CASE 3: cupball = 1
    CASE 1: cupball = 3
END SELECT

RETURN
'=====

'===================================================================
move3to2: 'move cup 3 over to cup2
'=======
cup1z = 1: cup2z = 1: cup3z = 1
FOR move = 1 TO 300 STEP 15
    _PUTIMAGE (0, 0), back&
    'cup1 stays in place
    RotoZoom3 200, 300, cup&, cup1z, cup1z, 0
    'cup 2 shrinks under, moves right 1 cup
    RotoZoom3 500 + move, 300 - cup2z, cup&, cup2z, cup2z, 0
    IF move > 150 THEN cup2z = cup2z + .03 ELSE cup2z = cup2z - .03
    'cup 3 enlarges over, moves left 1 cup,
    RotoZoom3 800 - move, 300 * cup3z, cup&, cup3z, cup3z, 0
    IF move > 150 THEN cup3z = cup3z - .03 ELSE cup3z = cup3z + .03
    _DISPLAY
    _LIMIT speed
NEXT
SELECT CASE cupball
    CASE 3: cupball = 2
    CASE 2: cupball = 3
END SELECT

RETURN


SUB RotoZoom3 (X AS LONG, Y AS LONG, Image AS LONG, xScale AS SINGLE, yScale AS SINGLE, radianRotation AS SINGLE)
    ' This assumes you have set your drawing location with _DEST or default to screen.
    ' X, Y - is where you want to put the middle of the image
    ' Image - is the handle assigned with _LOADIMAGE
    ' xScale, yScale - are shrinkage < 1 or magnification > 1 on the given axis, 1 just uses image size.
    ' These are multipliers so .5 will create image .5 size on given axis and 2 for twice image size.
    ' radianRotation is the Angle in Radian units to rotate the image
    ' note: Radian units for rotation because it matches angle units of other Basic Trig functions
    '       and saves a little time converting from degree.
    '       Use the _D2R() function if you prefer to work in degree units for angles.

    DIM px(3) AS SINGLE: DIM py(3) AS SINGLE ' simple arrays for x, y to hold the 4 corners of image
    DIM W&, H&, sinr!, cosr!, i&, x2&, y2& '   variables for image manipulation
    W& = _WIDTH(Image&): H& = _HEIGHT(Image&)
    px(0) = -W& / 2: py(0) = -H& / 2 'left top corner
    px(1) = -W& / 2: py(1) = H& / 2 ' left bottom corner
    px(2) = W& / 2: py(2) = H& / 2 '  right bottom
    px(3) = W& / 2: py(3) = -H& / 2 ' right top
    sinr! = SIN(-radianRotation): cosr! = COS(-radianRotation) ' rotation helpers
    FOR i& = 0 TO 3 ' calc new point locations with rotation and zoom
        x2& = xScale * (px(i&) * cosr! + sinr! * py(i&)) + X: y2& = yScale * (py(i&) * cosr! - px(i&) * sinr!) + Y
        px(i&) = x2&: py(i&) = y2&
    NEXT
    _MAPTRIANGLE _SEAMLESS(0, 0)-(0, H& - 1)-(W& - 1, H& - 1), Image TO(px(0), py(0))-(px(1), py(1))-(px(2), py(2))
    _MAPTRIANGLE _SEAMLESS(0, 0)-(W& - 1, 0)-(W& - 1, H& - 1), Image TO(px(0), py(0))-(px(3), py(3))-(px(2), py(2))
END SUB

FUNCTION BASIMAGE1& 'cup.png
    v& = _NEWIMAGE(235, 336, 32)
    DIM m AS _MEM: m = _MEMIMAGE(v&)
    A$ = ""
    A$ = A$ + "haIkM^Z\ULK50=O66UZ<`h1KZ=gP;dLGYlg`DVIP13l0SQikHh14H0Q5BZ:h"
    A$ = A$ + "4JZ9gn<GecFZgjEgB]N]0[JNN?W^E_GmFB]d^odWndOhC000L9nOoWomW<lO"
    A$ = A$ + "oWoeRbojS?^d?_lH[e]C0DKTaknla=Wj<l?n;o9_lgocoX:nno7jk1G661RU"
    A$ = A$ + "c;G?JgKNlR5o]?lMQignf3lago^RSegQhkOoHeagce_acQBRVOjjQ6OK;>f4"
    A$ = A$ + "WokodgHa_nSOmdQllCee=N]`YCaUaI1G2iPblQblObLKbhBO^i_l3oaZA[Me"
    A$ = A$ + "#^[?7f=?M>iXaUG;TnYd9=i4U^fV?lcOoGU5ed=kI?EbI>?dlLY[od[OeWaK"
    A$ = A$ + "W7BY?[?cEZdWEILF^>:^jiLE]c9ON\9_\<?\_l^h`m;^i;gmagj[J\nUfcNi"
    A$ = A$ + "8iYUfOmM>kVkeTgeh_Tg]?`=gYjllhhXYjU]boVE7]Fn^Vk:ck:ciRgf67Ej"
    A$ = A$ + "VKNY_aI:mbFkHhVg;76W[`MaI[WKjjWVnfjVcLDcER[FFLKkTmCfeIaK;SSJ"
    A$ = A$ + "=^CWlWb[;mlh:aIKW[jfnY=fFcmoaG_VSn\?^:i?G5o4W]\>[i_?DNfF7o?2"
    A$ = A$ + "4J<XVfmEa7?S_R7W?BOe<oah[nAV7mYSnKOkd?6dBk\alHh8Vf:[i>6O=ZSj"
    A$ = A$ + ">GAaLDLedLH8^[Zi[dOHM?eMlXmnJ#HdXe>aXPKoQgR=K]WdJliYKaES`j5J"
    A$ = A$ + "DYe^#_Sel3oJL9c=lGV3Y[hYhZh[e`EUkoW]aU]b^jfinEjg;^:^J]`Moj]j"
    A$ = A$ + "^jF>eWkm<ajdM;6Zgg?;c2]f7jEdfS][\[J6WjfhfUk1][hZcZcFjHALe`]9"
    A$ = A$ + "J^jFLjZ>G`bWQJYMeIbKe^WOY8D<k8B9SILmEcL1_RiFMG_3VfT]hUBjZSZ_"
    A$ = A$ + "6ZoIedE7EO]da<K]3ba\^b?WE;GED[R^bl;MG>K9n>JMOG;aaaMd>Mg>ZaCU"
    A$ = A$ + "[72ijj7Ge^fIFCO=gHVJM?QBi7gmWAZ^J_L]h\NjQJZ:^ZU[^GC0cH=0G;W]"
    A$ = A$ + "VnOYbcNGLgikJQSJ^68mDI=Z4Gm;^jQJG]ccai^^VECOLdLfJM>fj[MJG7?D"
    A$ = A$ + "WeLZSjhZnMEI>fLZg3m\OfJg[7miFN]dT7eJLYNR3aE?f7HIMLFn^RXde1dJ"
    A$ = A$ + "hY]dI>clmf;^lMO=DjXk[?OUH>j3LV^ZX]c]ff[Ekc^K7m>M_LMdcncg:_]f"
    A$ = A$ + "^YEmAc=?ZBl6^JR^ZFKXkkU2AoS;]cfC>J[HDMFO>ZUOj9^bgkl;LeS?cVLl"
    A$ = A$ + "E]L]YlNTY7mdFkUg]cNEOemJQkalQgG>nbQVPWR[VQ[V1aN?#icIKiHAK];f"
    A$ = A$ + "bL\ij]QjG[d;;J\4^JELeH>K<^khDLEo]1IoNQ]Fa#hZEeE3RWgYgV[?YdOj"
    A$ = A$ + "FjYSlgKXS1O_WFC]?[U6Le>fECHL;aN_QgjlOm4Nco5jmRn5^>Q[>Q^JTH2i"
    A$ = A$ + "kWgHhK^Y?;nRece?>[CMfnPj[?YbfgCe^NS^9^j0hZ>>kIME[[abl7GdOSVO"
    A$ = A$ + "bC^:OoOZnaRWWEnEKGaEk0G]2c;#?A:nC87B]m9cn1hmiM5Y_0Q>NkVkaFk["
    A$ = A$ + "K\oEG6GmP_V2alQ2hZN_?BV7[]^]5G]^\G33kYn03P0]n0_Re`5=G]eGK69T"
    A$ = A$ + "]IYVkSfi;d>S[niJ>:a#W:ni:djcQA1CkUimlh:kZTGmla?hZgGKm:WG=imI"
    A$ = A$ + "34=>27]n]a[jL;9kokcfS0k9O0J9kc3lSGFbn1_o^ah3OGeFge0D2T?;[]ol"
    A$ = A$ + ":UKeTCehYbebVFMY2PFR97R<nLEb]J6WZaC=ki2b[2i`MllXT[52inoI5b]:"
    A$ = A$ + "7Wjfi]LO6CoPQD8Wi#[Tc[V\_O[`hFU?W6CNEcnnWa]2Y#9N>Ei6O]moG>F]"
    A$ = A$ + "]o^EbEMOGHX]>eaIQFR\?`bm9hfofF^eI^O`K^jncYA<gBKnZjNkPWE8L38O"
    A$ = A$ + "^<FoMRaZ:SA=[SYIfE=?[6IKAfk3;UmTE[_F3c3JcWdQWGa2iZZi9C`=mjdT"
    A$ = A$ + "_5^0^aQAgKm;Z[j[m:emRMdJS0^;88DNRD[;=[R[VjnE=TgVMM51gMj9ii3>"
    A$ = A$ + "ch9_a#_67_4^JRSe\h]g9Fc3JML7DVHR[F[Ylfg_gZC4C_[nhUTMeT_NUCOH"
    A$ = A$ + "BLnZ`Sk#O<Sa7MF7E^fOmNLmfon:iZ1_VUH=\cgea;=obW`UKMlm8bIbAV[c"
    A$ = A$ + "UZ;kN]=hal2jZU>6o\m;:WHScT;NUMjBUSl\>J>gc=icU9gEgGcBEdE;am]C"
    A$ = A$ + "mnhU>_lXjj9MLGPLT9gnGafAGGMFGWQ]`E;I\eIMeRf?l6h`Ga5;QSVKKa]4"
    A$ = A$ + "k\P^J[c9TE\i9m[RWG^2iZ;Y7FdkOeQm_H5Lemj[DWkZIk`96CGEG]RL;7gM"
    A$ = A$ + "V?VS[>SSIMdMe;iaE:odMjXWfE[dH7aE_9GM0_6M;nL7ilUL^LJMKO=^>>[^"
    A$ = A$ + "jFOjefS=]^MOdXY>lRhRYN=HkgKFC`cdHF?DSAG`[agAlC=YeWSm2^^j\=oB"
    A$ = A$ + "hZ`\`\kZVaZR[2S>J^j<=VENOH0c4ka`Chk=3LEHVHfMEjo;<;X=G`]fa`EQ"
    A$ = A$ + "NTF7o<k^jNoOW\e\4\NH57?Ie72LEHVHjMe7_H]6HJMk=0W5ij4Kk?S[2#Ob"
    A$ = A$ + "<kZbggZhZ`XSaE=ej`]hkFkHhZ0L4LE063`E1H<HFMEcN\1G5V5dLeIH_fP["
    A$ = A$ + "2c6hZ0<6<[^ZI?fHEWA`EQ16gHiIH_fHZcBF^:[MOH`aZ6G9LeA>g:^:<S\B"
    A$ = A$ + "^J[K[1hZ<[^jfNl3G5V9Tacc#]7EFo2aEQI2GGMdW;HLEHFIfLEI]6Uj2=<C"
    A$ = A$ + "8SWWQJ?:^:<[<[^Z\FSR[2c0FacC#]7M_n5R[2C6^^jXG?3eZeXhZ`<PKll<"
    A$ = A$ + "jZ]^=6PBa\iZKm?`ml2PI0[Hj1_fSJEGPaEQ93ga\>l^ZkiD7d63#9`=^6G5"
    A$ = A$ + "PnTIbEOn\EOl2k5>H:A^ghfncSL=BSm]:<cX]?FK]cE:G]e]]0DJ`E1H<H6L"
    A$ = A$ + "EIm;Tn03c8Jm1N4gGLF^:N:<Y8S_aE1XOI6LE[JR6n:<Qh6K?Zk;>[JR6^:<"
    A$ = A$ + "Qh6K?R[Oo3e_#lDHBAcE7Yn1C]K1F56mJiRV[fjfD0Z5hZ0<6<3^ZL_[fjfC"
    A$ = A$ + "0Z5SL=B3G5F96MGe]n5fjfC0Z5SLm<dZVXajf7VLTkQeAcE=momii1^:<i8M"
    A$ = A$ + "ECoPK]3VU[n`No2ejfC0Z5^aihZ0dW<j^jna?^:<ih6[S[2#Ob`kZ_NLoago"
    A$ = A$ + ">LEHjahZVhmAcEg>^aEQE0Y[^1^:0m9SZ[JZM;hZ`ZPV[>2kQELEHeHDMEcj"
    A$ = A$ + "f7G5F5dLeAHM6JF;`k^:N:\0\5WKRi7Qe4\EMFb<7fhZ`2PaEgRk7Qj^T[[B"
    A$ = A$ + "oOQE1ijQ0G5Pn5LE0636=GMkh3G5FAdLeNNnU\ZOQhZ`2Q[[fk?g6LEHE1G5"
    A$ = A$ + "PaPAeEUe_#LEH5`:NO0ZmXJeJDLEH5`eEkme^4^:\Z<\^ZkaN7dF2#=a=N_g"
    A$ = A$ + "ME[j2<^:\#L8N_c[C`Jc[4^:\2L8VO4LE]Sk>X]4PJRF<oXiZ]^=4Pk2LE06"
    A$ = A$ + "36=GUno2[:^anhZ0dW<:^ZYn5R[2[:J^J?^7FaEQEWAbEO^oJ`EQ55gHo=OX"
    A$ = A$ + "7Memj11^:\XXiZmhj<DcEKMK70g=m^[JECd`EQ56=G]Wj7\?G5O5F9le7hNc"
    A$ = A$ + "Eg[M;hY`2S[[fKc5\EMF2G5FHdLeNJ<[DWU0hcX]_hjFGm]JG8^:\R\kZ_j1"
    A$ = A$ + "hZ0d_<2^jNMFRJ2<\h\kZ?j_j^TINUNNLR[2;>^^J?]OK`E1h;dk^jNm;4G5"
    A$ = A$ + "FLT^J_ESd\NN=hZ`RSU7dA^ZI=;9?6KMK50]6I>[NI];I]7cOkmTE[KW0Xe8"
    A$ = A$ + "O?9R[2#oB_jZF__EaE1`b7jUj3QdEohkO7^:0?Nab7jFGUi06PWN#_iZVeGh"
    A$ = A$ + "fa5^:0O6S[^A_\>3aE1h8hZ0<6P[2`H#_iZFe4=acCZe]C0dJT[gPNX6YQ[2"
    A$ = A$ + "P>hZ0<6dK^ZEm;4G5PMLMeFG;G>DWU`E1h9F[?n>X^;Q[2P>hZ0<6de^:e`K"
    A$ = A$ + "0fYgZYghZ0XC?jZke_#LE0fae7JmJGbZFSR[2`>J^J[ZAJbgSSJ7K0\bhcEK"
    A$ = A$ + "ajQH_n5JZ;`hZ0\c1Oh]a\fJGUgUi0Hc1WX7LE]S[>X]2PFRVCdK^J[KS0XG"
    A$ = A$ + "XWLEVG90lSfl;eBGUno2P>^^1^:0m9mR[^_7caE1#5=G]5[M9=G]e]=0dKdE"
    A$ = A$ + "^jKk3>LE0>b^[:ZU;]`EgggZhZ0XRdEgl5LE0jCJ][JZOQhZ046=Gm>W;H[e"
    A$ = A$ + "2<^:0NaeE_ke^dQj\4^:0ZXiZgIoPgMe7_P[2#0\Le7_P[2#WB?jZ]^=1PNU"
    A$ = A$ + "FjZFe^5LE02RdE_kj^4^:0YC[Le3e4=LE02RV[N7?g6LE0bSFkZke4=LE02R"
    A$ = A$ + "UWLS[72LE0bSFiZ7N_HlF^M00o8cYMGk=>[mH^iMFG7dF0#?SlMN:^:0m;MQ"
    A$ = A$ + "[bHE18:BOi>MEN?V3#NHe?dKJ?WS[2#nd<GmaWkom7Ook`E181flTWnbKc_c"
    A$ = A$ + "MjZKO_hZ0T66GMS]olMkZd7H0B3COP_;GejM37SG5PTamILFke^4^:0W3LE0"
    A$ = A$ + "63^KGm#]K1G5PT#cE[iHFaE1hLP[2`H`MjZVg;6hZ0T?nLeJ<VEEGUj2<09Q"
    A$ = A$ + "_j4l]hZl>B6PTaeGZ][JECd`E18ILmUJFSdT^Zlk5G5Phhj<hZ0dWLW^ZI\Z"
    A$ = A$ + "hZ0T?nLeJlLK\NW[R[2#FL`IZhkRe3eJDLE0B6=WYFeM9O^J[K30HD0G5PaP"
    A$ = A$ + "kdEI\Z0LNd6cJEMEaJ;4G5PdabE[Hm<DFo2aE18O>hZ?ZCMGbZVXQ[2#f8mV"
    A$ = A$ + "JFSd`E1hJLG^ZIoe8MeFO^3`XQ[[^iEebEIO[2`iAKO\FB?m#m;4G5PCQV[F"
    A$ = A$ + "be_?^:0UQJkZDkF0X<h[F^DJGM_n>Q[2`Y#jZKoJ9MEIMF2G5P[Q?G]4m3fh"
    A$ = A$ + "ZkkaLLE0>=^^ZImkG2Gm#mP0G5PCSV[FZn1S[2#i0G5PaPk`EggkZhZ0LJLM"
    A$ = A$ + "eBFgU`E1XLDKGeZf]`kK:0^4^NDYZU;F^:_Kh0hb\kZ_]fU:][BoO1X<hkI\"
    A$ = A$ + "F2GUaZ2#i#K<[U`E]N7>R[2`UiP[nX<kSE]gSihZ0LN\Le2^Wc=[IoWe^5LE"
    A$ = A$ + "0^<BGeDCT:V[Jn<aE1hbL`EOmGaE1XoX6^ZYf]\miI0G5P[Q\F6JhZeb5LE0"
    A$ = A$ + ":?hZ0<6DJGMkWceEIlZ0LML7_ZdE?S_:[cBhZ0D>liZW]F^HECdHNP1XHhKN"
    A$ = A$ + "PaE1X_XF^jcmH3^:053=Gm:ec`]O>LE0:?QLec\OK\Z9JhZ0D<liZW]F^hjZ"
    A$ = A$ + "\?K0X<h^?K`E1X?YF^jcJ21^:053=Gm:ec#LE0Z3e`EOFo2U^Zik0G5PCSdS"
    A$ = A$ + "T^jI[AJnZeXhY0LMdZS;WaE=[Iom?CbY2#Ai#^EA=B;ee3QjkKEbY2#ai`hF"
    A$ = A$ + "o#N_?FgWCY77kk;^:0U3ea]nhUTVS9IOOef7LhZ0D>LMESc]m_5Z_`J[EOgJ"
    A$ = A$ + "1Q;]nL5PA3O^TU_5I]l;ONZbO>LE0:7YhZ?c]6hi]j^>maE1XlTZ[JVW9gJA"
    A$ = A$ + "ZILZbOVOoWn6LE0:<YjZn6gjf_OcQUNZQ#^:n:0YC8?BcE=SKEjZViD:V[Zm"
    A$ = A$ + "mejcO065dLW#^j6bebTLnO?S[R_2#Lli=YTGe<O`J^ZdGaE1hjTS[jKM<9gC"
    A$ = A$ + "iJ^j6QjW=^:0a9V3M`EOk_G^7dmmLEoeOl[ObCGeI];Q[2#N4dEMGkAbeO_h"
    A$ = A$ + "i\6cEg#K]6R[2#jTZWJe7HWmP^?GM;OZdE3i[]^M0PNWchY^^jnjeGI]5^i["
    A$ = A$ + "ob?l7SVK]e]30dk4J<ZbeMT_lZVWaZ_e\_9gjV_^?W`h[0T5abY6bEM[E4BG"
    A$ = A$ + "ePlciWon_JgGINV08=bI<ZYjZbe3\V_Jb]^A\iI2W5FMbI>O3>NeGoo[]?Fg"
    A$ = A$ + "[_X2OeML[YdGHlEHU9TSV[WJ6[JXJgRfWSGO=an4So2c6nRa?USjTcMkccgn"
    A$ = A$ + "Ge]VXiji^c;\eNV;QWmZV[Rk2S4Ja_NMeLLDWn7_mkSESddZgBk[7HQ_:GCC"
    A$ = A$ + "Yj[idoHb13]RLR??KNd#NZ<WJ\JIXEM<<#nE=OEkHh\]EhZ#;8Wh_LWgXDbW"
    A$ = A$ + "^miVck:3gj>ZkgQkcNEeI_P_AOUQkTLRg:J^d?lMFoKKOnin>]A^oKf?nn]_"
    A$ = A$ + "=Z_j[Oaid>4[]YeGGQiQHaFAS7MF?PihXFmIe9OJZeMOOef#gk18ocBW=VgN"
    A$ = A$ + "Un6OU[7Gic0j;l=G8WmcjDOgW]o^>o\?on_`k8>Oc?lcSEWkUX=6FScVbL6G"
    A$ = A$ + "j[MnV;;b;?n4L>M^`LINZ_OWeOP\f<h>>#OiRgn<ciMRAfm9fImBhn\Qdba:"
    A$ = A$ + "?Gl^f7c\=Eno=e[QhZS=iLMfgemLSaliWJNJ`e9TWei#9mD]n47:7[_kg8ck"
    A$ = A$ + "jj_WaK3Uo<deeF7_1egES5GTegCRnI\nljV;]4mi=UL\knZ97[km=lh[^^Jb"
    A$ = A$ + "iLCHm<R[>oDR[oA9`l45:FegcRa:gcK_?TcimfHYba:ccjNN6;7[[kj;WKXl"
    A$ = A$ + "^aLALeiRLj[KbnJ2i=SiX7b[hTSa]V9MG>Z_aa^g_h0]1Ydgh#NKXkSMf[_]"
    A$ = A$ + ">nKeidiobhJIXlValbH>J\iNAjYgI^dH>[Vg6kl;FOT3i_U`IKM\jZC=MD[?"
    A$ = A$ + "O5o<DOibaA]Nn;>nI_hXI=NfCT_eGNgHS[G;6#N][eaW#HG=eO^HGCeRgBI^"
    A$ = A$ + ">C>7ZkaMS6?jEAVWmPkVhcA>dmibY?;7bknjaQYMERi_o996GEkn_e;nc]NN"
    A$ = A$ + ";^>hmJTcaZKLS_WKH:aFYjYBg\eS7]TN[ilAmic6hinLEWFK\4^a4YjZ]8F^"
    A$ = A$ + "dnM[?VCjHGaEEMd4F;>nF_j9?fC?cGTiiSN7?kUk6gadjV_ednWBkF>]iiBb"
    A$ = A$ + "?SX;NlLfkAYMlM9O=bm<_jmAE?OSdV6jNbYL?j[>^cmSi?lUnQ9cO>2S5]6i"
    A$ = A$ + "KeFO5Q^>7jJOXl7Qb5WT;UHldMAZ[KT#NIY>FZQWh>VBgLU^[kLOcMQil>Fk"
    A$ = A$ + "XfOoFkG?llFj52U_eZo?:cEPJoJC8F]dNC^gO?7R=7UYj1elHl\WGQVSOge;"
    A$ = A$ + "CB?oMUhP#^ZKNC3[Lnc[h`FmE>R_Jm[1j_EBmA<QnS5;><ghD=dbW4:7C^ol"
    A$ = A$ + "iL\TjcD;Wc[DOFj1c;ZLm:DOgUgOgM^Q`9_V_VENg#g7=B>Hg?3OmG<eL6Ge"
    A$ = A$ + "C;Q_F;G]4NZFoHU^ZI>L>#\lU:ckO\lVhYeeSEcmJ^FjLMdmjGBNMTafEbnn"
    A$ = A$ + "MeHMghmDLfkfASegmHcmZln\n^nI6WYfcCa4cdjHgEVHiNCjIVNaWED[6GH?"
    A$ = A$ + "<VjBN<kKl;aNn>abIfjHD8<VkSjKn[>hcAjKE?BdW5b=m\^:jiSWn_jN]Cfg"
    A$ = A$ + "EbI>O4J<`n67\aQ?eJ=X#?ObTleCl<;;bm8llmWJkU<7Y_aEbH;1Y3k3I<R?"
    A$ = A$ + "7?enM?BinbNnd3dODO>WF^AGJM\1<fTS3k^VFeh\^]jLX5ImTLFg;4ihT]nJ"
    A$ = A$ + "70BB9o\?O_Gagi0i110P_`o7c`W^%%%0"
    btemp$ = ""
    FOR i& = 1 TO LEN(A$) STEP 4: B$ = MID$(A$, i&, 4)
        IF INSTR(1, B$, "%") THEN
            FOR C% = 1 TO LEN(B$): F$ = MID$(B$, C%, 1)
                IF F$ <> "%" THEN C$ = C$ + F$
            NEXT: B$ = C$: END IF: FOR j = 1 TO LEN(B$)
            IF MID$(B$, j, 1) = "#" THEN
        MID$(B$, j) = "@": END IF: NEXT
        FOR t% = LEN(B$) TO 1 STEP -1
            B& = B& * 64 + ASC(MID$(B$, t%)) - 48
            NEXT: X$ = "": FOR t% = 1 TO LEN(B$) - 1
            X$ = X$ + CHR$(B& AND 255): B& = B& \ 256
    NEXT: btemp$ = btemp$ + X$: NEXT
    btemp$ = _INFLATE$(btemp$,m.SIZE)
    _MEMPUT m, m.OFFSET, btemp$: _MEMFREE m
    BASIMAGE1& = _COPYIMAGE(v&): _FREEIMAGE v&
END FUNCTION

FUNCTION BASIMAGE2& 'ball.png
    v& = _NEWIMAGE(100, 99, 32)
    DIM m AS _MEM: m = _MEMIMAGE(v&)
    A$ = ""
    A$ = A$ + "haIkM^SSULL45EK5jB#j#j#K^1X?g3L=X=S\4Xf3bAN22#0bAK1jC718d2i8"
    A$ = A$ + "L8>jP8cZNmlYkIdHTXNeWg_hVghNS8[ne?mdCo^Wn8Jl[ojonY7mj^kcicS7"
    A$ = A$ + "37niOnGNjWnYoiCOkgnGNjkn^ojCOogogNj7oaoaK6[Sch7nQonK6L>6[Woj"
    A$ = A$ + "eiGnUoeKfnILjnanePhmJ;ajenP7L\eiiJhjIo5^hWkjh[S]N=Fk3flBoMne"
    A$ = A$ + "fPHBSIlHfB\MM^_iKncoF\gL2oLlSGl3S]`ghinILioR34?Fah6G1CFaNNlj"
    A$ = A$ + "LLm[S_h:6o<Wal4b[ak1SbSFSoO0Khk8iS#3PHZWccSGKoj_n?mK7O]e77L0"
    A$ = A$ + "\TLIFSYhDaTV?cL8`V?Ua77g0;J>V_j[nS_I0^\Rm>?5KiiKL4L[ijHdg;[3"
    A$ = A$ + "EO0\oWJhajk3cWGOoH>oJ[c]\fWcicclOOLh5`7<N`ila<6DMWV_bL6kQkC1"
    A$ = A$ + "LQio<?VHIe\]NPSUFOQ[5>bjJIh[Qg_6kW`2^^VcZibFjo<nH5GPC`lJ`Sef"
    A$ = A$ + "_l;o3o?j1Mn]SINn^7P9h3^NcjnljHLfh>hajc4HE[YiS9=O[IcgEVo1>HMF"
    A$ = A$ + "66Chk^a:N<n[hh53Lle_g4OMLfl8S?L=>nk]`AFWOEob;M<o:lXnR<W`NT#["
    A$ = A$ + "`i_LlKYWcccaGWCSg7k9XNPkFc]Vh7UghSaaMN\efGjhn^QW;_RWV?\3?jS;"
    A$ = A$ + "6Jl`ajeS9FiJ8Jm:E?gL1beE<QGGV3<EkB[KiU>fGN1cG17:oPib;M3Vkcn["
    A$ = A$ + "]niQ^`jHe?\WWRnTc_\N^[hSeE\6d47Qc3NJl`nPkk??VJmO=XYPGFW_`iR\"
    A$ = A$ + "gDcAje0NDM2b7I^1WOM>fjjnJn?S9^F3cOZ?\ZW=i?cjkXYlBS9N^b:V^V_c"
    A$ = A$ + "LNc1ji:7aOGao5N`\7Gh46;L]KT7cNQiHegKk;cTWRbGVZ]deX\`UG:NQ[;f"
    A$ = A$ + "iK86kloCnEij<naSA3bJ?>>^>VcQKM5S[CnMM]ifCUmT]c;\emme1N\^n?de"
    A$ = A$ + "X#o`]_DV_kh[i5P;LN?0;9>ae3G`ccWVW2FD_34OmjVh1H2_^Xghn]H?FmmU"
    A$ = A$ + "i2UO`[k72L0]k>oN:7ediikD?GcAINW[Qca:[oC>:RYXEhHF[C1<\LGN^]Nm"
    A$ = A$ + "jMXc9<?1\im9?1]Kc5\F\e8^3nhLCLMPcNOdGLLScI\ShWkkEm2kLB`KlaL^"
    A$ = A$ + ">[a<M=Ci]\NRGGbg7h1a]El1N]cg<EC1h5HXW[GM3O=P1]F2l137S_oT?[nJ"
    A$ = A$ + "MmfnJ\nSk=Yi3Pa6;]oH[1IlP_OPg_?jIo2WGOf8>eikkh7nlClSRa^>Ub3J"
    A$ = A$ + "ODLmUPG]WTMnKi34[K_RWZmXi]LLg7W??_?l1K=3g3SV7JbK[c[17bJ?niHn"
    A$ = A$ + "6aIZ7T_O^ol`SJOiiL=7Ue6\VMmmB>8g3IS5>?f4oYH6Hek:O`P5NN\kAKi1"
    A$ = A$ + "TOZJ3NOO<SaCh2ji6?LmO4C\gFc=L=l>GFkSYS]6?VZiPSgJJ#cXjj_;efa?"
    A$ = A$ + "X[YXLRF_AgWL863m[UgjN]hGofWBfB\cm6YJbV;dLknh>>jNhkJB0G;_Y[[8"
    A$ = A$ + "_7P_LM_]LS9O#]7DCa`6gGO7nR_hg?VcRSGOIF[`NKkajlI^^FOX_?Q0K[n="
    A$ = A$ + "eb<M?MiNTdj5mLQbChinf`AH=<H>Xk_Ti8lmRhjTVM7[[cl2Z3O5;\O1oJCL"
    A$ = A$ + "_lYV;bHVi7fSUaTCjd=fglFFKcNOkmdRgOMm?7oFN]<#K]iS:_ahAmJI^ROM"
    A$ = A$ + "<WYL3cA\nQeI\7;?GaJg>7_WokJk9Nfm;_`7OjNO`jk5C`[ecAKO]fGFgce1"
    A$ = A$ + "F=4??gjkFKOGmP>6Jn`dLL`4?_dcEF7gehhJ48nHN1JSlhNO<<iEfnfZGHSm"
    A$ = A$ + "mn8RmG_O?7lXaT9OCEcM:WD[=_ihhj]_:Z3H:gUO\i0lIbHg^J4LOZJMe>ob"
    A$ = A$ + "^Jm:gYNb<G\m\Q]?bm6^[]bi=8>K_>CiVFG3i^J^]jCKb_\a57WI>Q_oi`C;"
    A$ = A$ + "iI\6m^jUGGSi0f[TciH_JWdBlj<feVWgCS7`G^;g0Mcj_MZWjWh6\MB7W7kn"
    A$ = A$ + "oB]6`1H[mRaaMnYFWNS;fkZa1N>63J>^^FiMM2]6R[i_HYeUNTeh5Ml67WlK"
    A$ = A$ + "JmK7k=NhAe>\7PbA8V?E3Ze<J=RnnmRH#7XohLCP;PAfCTSQMoNOcIO^VSJ<"
    A$ = A$ + "5]mkLoY#<Qi]4;[o5VSklH>?e4F`cah8io[?FkOXn]#GQlZlLZfQmCanPONm"
    A$ = A$ + ":ZoDjE7iijlJkcZiiVlkJN67WgS[dAXWQ5CfYKK?[>7d>^1c]]>Ni2nhTCZn"
    A$ = A$ + "j#W_N;Z?Wfk9RAT_kT6Na:[QDoC>VkgO`=SU<FGcMbEe_S^nPFgPa6S3E3_i"
    A$ = A$ + "NVRm]>4k3NZ70f?3jl]7F6;JM7=fajnfn4bfYJgM]7]o8<gHB3RS][f`ngRA"
    A$ = A$ + "[=PhBcgH=3`Sj_]i\VdULlgLYRW^n2S9]OiN[cOG]SF;Q_?M9W5m6Xi\:7ae"
    A$ = A$ + "WG=WjgV?CWZ5aeefJ;LLNZ^^CNZZ^OaVR3<O`H2iiVZGTL?NhN\he`]aD?_W"
    A$ = A$ + "jWK?1I=aWdfieXN\=6<i9cO6fU[Zc3kjMdHoT>Bef[>dT_=O==7W?>n`;VdN"
    A$ = A$ + "WS^=l0FCaYNP`lId:\647SccXiTLN#_F:EGYikhLCi[lkAScCNHW`Vb30?kc"
    A$ = A$ + "amj]l3jYH7CmX1_7CHR[W0]UYid6;lJNgijklSI<^i7giAfhgJkT_GdkVR1C"
    A$ = A$ + "ik;fd7?QUV3ihkjHF?X_gX7cSYnJ[kKn\WoiLF4cZ_FR=`9hhCmC\nFKO6M="
    A$ = A$ + "oXUK\OjeI:WEe^mlmYhnD<_hada>U_ceH2?Uh??Vjm<F\nnhG3lcjih4[0O\"
    A$ = A$ + "WFhF`=VbAI]4WgJWOFS7W`eMJ85;HnfD\KBo^HDm2<EoMeThjJOR[>6a?R7\"
    A$ = A$ + "n9N=XjmHGkiT[ScaG7o[f#aRYHMa7kg]mGaioZ6bT?c9L`aZCeSGn#iCCJD^"
    A$ = A$ + "nS^N8lHjY1KiiiiJPM^GF^>mMnT<NhJcMl]L3[7ILZeWLE=;UOdoNFMlgcCg"
    A$ = A$ + "YY_;WfEiYVl=dN;F_g>g:GgTVZeh[gO[KPfIeVMl_lXZEG=jZ]DNAW3dOcEl"
    A$ = A$ + "mHVSYf_IcYM:f_;of4^HMn9<Rgkf3;^6h4MMX<7QScl[YN;eloCcgW6f[PGO"
    A$ = A$ + "4ZAehe4NDnab_5i8LOXJ^nMnYVdD^3_HGo`f]F_X5cn>7T[K`miemNWJc]fC"
    A$ = A$ + "a3h0=7h9\`[cB[=deA^[g`^6Mn]cQGg9>`ELRChd^lJnjFOGVhR5GHNVcQiJ"
    A$ = A$ + "dmn^_DN0NI?^FGfmKdj4f3l^NkF?0=Wf4V`SK]P`g[VaEH`^LEChDaEl]Bm7"
    A$ = A$ + "CNl\f5O>]N_mNI\HZWRM=YVjUUkGKaP9]W9lYHbM`3[OPomYk7QMnJ?YQgmi"
    A$ = A$ + "eag7Y6gJMSN=A0gJ^:gW=OOGH\`[52eNH>C[93mTfCFGkA[UKROdjj_:OeJD"
    A$ = A$ + "lPiX>G`DLNW6nMh>ne`g;kU;jkW1`WN<c7LoBXgRnNN`J<CmZ]e8<]n9=6Fn"
    A$ = A$ + "a^QcQ]cSejL>O5n][?ZMj0Mnm9OEk`Dc=\>2_oCanZognNRn7?o^N]L=FKWW"
    A$ = A$ + "CWcGNcDl_i[V`7SmklF=Q7^?RCha>_BCLQMJ?^Fm9mofC`nnEo_nm0ojd;G`"
    A$ = A$ + "5G?a>mNO]Fk`e\?5cgQ7Ga5JmU5?FSeW1jk`^ii=?oSZc_S;IlJmnG_FM\[g"
    A$ = A$ + "l<_Wmm_S34Wih>?V[Aam4_m:L:VOWLFneZ[?b^nUh_GWl4M7oCGQ3khHMn#k"
    A$ = A$ + "EBmeJo1>Vje]ZeT<U_ae`ihV_?_#gN2G>UCbeW<igjDoBVFkY9>a9Na9?0dO"
    A$ = A$ + "BkgZigLlOGmifOUel]_:[=P_17o\FcTW7RaLM^O8]^V[l?=QIEKZ[=hdgARI"
    A$ = A$ + "kd3jlmkTkj4?aiS:FP^=L2VojW7OnWhB>NRf^[=dSf?hYj:?YG\cWeT7]Yj1"
    A$ = A$ + "MoMM>[YNafN:NEM9nLljjlCClRZIEoFnNJLJm[LmOU;`iLn0l1H]V9nd9=4c"
    A$ = A$ + "=Z7gN]5oW^W6FO?X^#VGMU^jEiX>]n9CHLaTR=]O:^?m`MljWkLGV?hn2ihN"
    A$ = A$ + "koD[5gcYkLoYadjmfJcYF`ZW_>Oio4;gMoB_C;ac]?Yi?eGGkWXNJgMOJQ70"
    A$ = A$ + "VoklE<ggHBgWhWo]C[j0Ge?ZCiY>mJ]>o^koZ^NMG=_NG>[9<M]UeSMgLn[N"
    A$ = A$ + "?mJP`nhWbJ7nJL]<^>NkkbeRSnn^eEdahCe6^kjVdkgMon<ekRYNR_SG\3;Z"
    A$ = A$ + "7]9lSLj`KfmgaC_?7lehLAnnU`eNHM4h2>_2LZYNW_[FlMhb>OGNoCgCengS"
    A$ = A$ + "5RGkF3ZYl?Wd#Vb?aa?E3:i_jW3goTnlMmQ\_[U`mC1>2j\DWQaQnk;`9oEC"
    A$ = A$ + "[ga4NLRKDO_liMBGm4OH7WaL\nl\_YeW_MiYhcE[?RmKoNjejeRfmAdeoeN8"
    A$ = A$ + "FOEWFSYR7WbAI_gW`SePL0ecc^hn4?IjlWZoHW^nJ;N<jJd>E3YcA]R1]OE`"
    A$ = A$ + "CFa2>6cCkmjhD]l6;fUGJG=9Cn1X^SCo=7PgAgkd9]f[h9mJfYI?QgP1ncAi"
    A$ = A$ + "I4KK=k>V^>6aNbOimmm7TeDjnUgdjgiLklF1nD<i>o=4b_emkddWl3]S[L2C"
    A$ = A$ + "L_WVjKBe4:oXO^Xf9nnKMJd88ninIe[gecio^0[G;>NoMJhD=R]nS[`2cAfU"
    A$ = A$ + "3OBGO27:>E?CgQWHmh9mJ[=`ekJ^K=SP5eg[a3d^]n^i4lJhJh;FDmTF32_f"
    A$ = A$ + "g5?H^VeJWbK_37:FLjJ?i]ZL3dfL_XaW<WWcQnAm0gn>Jo`Nn^kaKc=A]SU?"
    A$ = A$ + "hlBCJ<>OeSlkc0go?Cl46m_9]MNIgUoJJ>o9>9HQe\I;aLN<HR[WgeThk78S"
    A$ = A$ + "?mN?iD?5_ZG96K:oHmJMG\PaZ7GCOo?UcJga>Ec^SKnlnmU7glGLL_^96Clm"
    A$ = A$ + "5Q_ON1oLmFL<RO>GVebkJI=QGClQW;g`3gOK[WOE?>fi9k46iib=6?U_dKml"
    A$ = A$ + "OgG:N<eMklE]fkMeNH_0Wh1WZo[jh?GlPkC_VoHZ__]?RGY_L:?5[ij4W`J_"
    A$ = A$ + "]O]L>_68DgW_o]\f=HU[Ygj6kZ=\SYjEVFCZgVOCbhnjm^i\JoZNTad_mR4G"
    A$ = A$ + "m[;mkc[OQiB^f?bk0FhNQhNX#\bhl4VLEoBVjWnSF?nMeAlJfEOFG]>7EgOJ"
    A$ = A$ + "=7_Rc0g0^YkOUmo26dkEGgk:kgU[Uh=iVV`RMieVjQeD_ZNGmKJ9cMJ>[CLT"
    A$ = A$ + "N\MheSR;=o5mS2^1l1[U0ND__eOeTnb9naDOfGSYkcdgUoNF^f>e_X7M<ekg"
    A$ = A$ + "VcZgCYkd_M>=WoghBe5PkhNTHoA^W_CNMWh9]NLkAci[NGP55GJ=fWF;g7E_"
    A$ = A$ + "h>LVMn[ZWFSKeSUe80?PchLFfck>LXm>am:fJj__nmY6o9kRICnP_;VE=YF;"
    A$ = A$ + "Ji>E;caNfgL7gO4g;AWcbl8S=eOl^OKA=VlXm4ii<Fe]OEOh;NLG>a9nQa:l"
    A$ = A$ + "6i1jKESWSeOW\ZFQSo5[fE3Xa2G;^kWnkSlDCSk\fjk`TCHDm\i[clUE\XeT"
    A$ = A$ + "KlXl4cGL_D:g`iWfYG0nP_k9?_L]O8`26>VMelnCmRgHaTfT?6aoNoGiof7Q"
    A$ = A$ + "7dj2WZS\[32aiMm\jT7;GCnjeh3mogRH]MW`RWSo[YJJ>MM=GUa<Zecjgf?E"
    A$ = A$ + "eBLN9?__gOLk`3[K\^^Gbo7B=e[fkP;CmhjAmEQ6?i^lJKB\dh1LPZOKlZ[]"
    A$ = A$ + "adm8Wi:eSk;mo?_N4mTkb=fQY^WVClUjUbkG]4ogSSoo2BSc5;Ln\ZOlJ0;H"
    A$ = A$ + "<M_^m^HH_]^fRfgUZQkHOkCRmG1gXo__Ym:LGM7nnBhedH=g0lhdjH]S3<e?"
    A$ = A$ + "aFSQeamlMOO?HmlbEjS]nQ[5Qh]m3_KlBmog^k>FOnfMOdMUf\i4ChSO=K_A"
    A$ = A$ + "le<U_Zm#YeKHmMk[eeJknd^>n[moO2K^bEiN^SfOe>lPed`l3n]<YeKDNAm="
    A$ = A$ + "a_g<U_d17o>ggD_67k^O3_S7<j5eD_AZnMa]YjnJ=PP=C[IKcGiJDnHQC<aA"
    A$ = A$ + ">aEN>N`8oTi0ESOWg:hCCnJWjI5l4gG`?FaRMhcMmOeenKJ^_eb=6ioWC#<e"
    A$ = A$ + "eUglBFGIJ]VN=jMjM5N`h^hBej]V^cI]fgiE<6eofKVZi^m]RJ?nHCOhiR;\"
    A$ = A$ + "Uee[LSM[;UmmBlfJ==7Ui9FSgnJ13Ho?Ei3?:_I57Vh=E3_LUjSMbS[[kfL4"
    A$ = A$ + "NmH=Sno1n`EHAOlJk:OadmgK__kWlIinG=]N8XWlJ[o6O<<\V3[=Ia9b]=eG"
    A$ = A$ + "4^VeSGNSl[g;mg]?U7Cl\??nlh]MlOPD%%L2"
    btemp$ = ""
    FOR i& = 1 TO LEN(A$) STEP 4: B$ = MID$(A$, i&, 4)
        IF INSTR(1, B$, "%") THEN
            FOR C% = 1 TO LEN(B$): F$ = MID$(B$, C%, 1)
                IF F$ <> "%" THEN C$ = C$ + F$
            NEXT: B$ = C$: END IF: FOR j = 1 TO LEN(B$)
            IF MID$(B$, j, 1) = "#" THEN
        MID$(B$, j) = "@": END IF: NEXT
        FOR t% = LEN(B$) TO 1 STEP -1
            B& = B& * 64 + ASC(MID$(B$, t%)) - 48
            NEXT: X$ = "": FOR t% = 1 TO LEN(B$) - 1
            X$ = X$ + CHR$(B& AND 255): B& = B& \ 256
    NEXT: btemp$ = btemp$ + X$: NEXT
    btemp$ = _INFLATE$(btemp$,m.SIZE)
    _MEMPUT m, m.OFFSET, btemp$: _MEMFREE m
    BASIMAGE2& = _COPYIMAGE(v&): _FREEIMAGE v&
END FUNCTION



Attached Files Thumbnail(s)
   
Print this item

  HELP!!!
Posted by: PhilOfPerth - 05-09-2022, 01:24 AM - Forum: General Discussion - Replies (4)

Help!!!
I've found this morning that I can't produce ANY new QB64 programs. When I write one, as simple as SCREEN 12 : PRINT "OK": STOP, I get an error "C++ compilation failed".
I can re-compile and run all my previous progs, even after making changes to them, but no new ones  . What the...?  Huh
(I know this is headed as HELP, and should possibly be in the Help Me post, but it seems more related to QB64 questions, to me).

Print this item

  Optimizing for Speed
Posted by: TarotRedhand - 05-08-2022, 06:14 PM - Forum: Learning Resources and Archives - Replies (2)

Constructed from a series of letters that I posted in the QB ECHO of FIDONET quite a long time ago. Note that this tutorial was all about speeding things up which may not be quite the problem it was back then. Anyway, here is the original tutorial. In addition to the line drawing routine that is used to illustrate this tutorial on optimisation, I have included a couple of other graphics primitives routines. Fill is a seed fill routine and doros is an integer circle drawing routine.  Doros is based on an algorithm discovered by a professor Doros and is a variation of the standard bresenham routine.  The only drawback to it is that in order for it to produce circular circles it needs square pixels (i.e. SCREEN 12).

As there doesn't seem to be a lot of code floating around at present and we have quite a few newbies here I thought I would give an example of the way I have developed stuff in the past.  Now as most people who are new to programming are interested in graphics I thought I'd use an example based in this area.  Below is a small program that illustrates a different method of drawing a line on the screen than the one that is built into QB.  The actual algorithm used is called a digital difference engine and while it is small it does have some drawbacks <g>.

Try it now and see if you can spot what they are.  When you have done that go to the end of this message for an explanation of what they are and how the algorithm works.

Code: (Select All)
CONST FromX = 10
CONST FromY = 10
CONST ToX = 310
CONST ToY = 190
SCREEN 13
_FullScreen _SquarePixels
FOR index = 1 TO 5
    LINE (FromX, FromY)-(ToX, ToY), 15
    Sleep
    DigitalDifferenceEngine FromX, FromY, ToX, ToY, 12
    Sleep
NEXT index
SLEEP
END

SUB DigitalDifferenceEngine (X1, Y1, X2, Y2, C)
    XS = 1
    YS = 1
    XI = 1
    YI = 1
    DX = X2 - X1
    DY = Y2 - Y1
    IF DX < 0 THEN XS = -1
    IF DY < 0 THEN YS = -1
    NX = ABS(DX)
    NY = ABS(DY)
    IF NX >= NY THEN
        NP = NX
        YI = NY / NX
    ELSE
        NP = NY
        XI = NX / NY
    END IF
    FOR Q = 0 TO NP
        X = X1 + XS * INT(Q * XI + .5)
        Y = Y1 + YS * INT(Q * YI + .5)
        PSET (X, Y), C
    NEXT Q
END SUB

O.K. So first lets mention what is good about this routine.  First the layout is almost perfect and second flow of control is good i.e. no spaghetti.  Thirdly it does what it is supposed to do.  So what's bad about it.  Well the majority of the variable names are either one or two letters long which makes it a lot harder to understand than necessary.  Apart from this it is *slow*.  Its slow because it uses floating point routines instead of integer and it is not optimised at all.  However, before we can optimise it we have to understand how it works.  The first step to understanding how it works is too change the variable names to something more meaningful.
Code: (Select All)
CONST FromX = 10
CONST FromY = 10
CONST ToX = 310
CONST ToY = 190
SCREEN 13
_FullScreen _SquarePixels
FOR index = 1 TO 5
    LINE (FromX, FromY)-(ToX, ToY), 15
    Sleep
    DigitalDifferenceEngine FromX, FromY, ToX, ToY, 12
    Sleep
NEXT index
SLEEP
END

SUB DigitalDifferenceEngine (X1, Y1, X2, Y2, Colour)
    DirectionX = 1
    DirectionY = 1
    XIncrement = 1
    YIncrement = 1
    DistanceX = X2 - X1
    DistanceY = Y2 - Y1
    IF DistanceX < 0 THEN DirectionX = -1
    IF DistanceY < 0 THEN DirectionY = -1
    NewDistanceX = ABS(DistanceX)
    NewDistanceY = ABS(DistanceY)
    IF NewDistanceX >= NewDistanceY THEN
        NumberOfPoints = NewDistanceX
        YIncrement = NewDistanceY / NewDistanceX
    ELSE
        NumberOfPoints = NewDistanceY
        XIncrement = NewDistanceX / NewDistanceY
    END IF
    FOR PointNumber = 0 TO NumberOfPoints
        X = X1 + DirectionX * INT(PointNumber * XIncrement + .5)
        Y = Y1 + DirectionY * INT(PointNumber * YIncrement + .5)
        PSET (X, Y), Colour
    NEXT PointNumber
END SUB

So how does this work?  First we set the variables that determine the direction that the line will be drawn in (i.e. up and to the right etc.) to one each.  We also set the variables that determine the rate of change in both the X and Y directions, to one each.  After this we determine the distance between the start and end points for both the X and Y directions.  Having got a value for the distances we then test for these values being negative and if they are we correct the relevant direction variables to reflect this.  We then make sure that we have positive values for both distance variables.  We are now ready to determine how many points need to be set for our line.  We do this by testing to see which of the two distance variables is the larger. Once we have determined this we set the number of points to be equal to the larger value.  We also reduce the value held in the variable that determines the rate of change for the other direction.  So if the distance between the 2 X coordinates is larger than that between the 2 Y coordinates we change the YIncrement variable.  The new value that is assigned to this variable is less than one and is determined by dividing the smaller distance by the longer.  We are now, finally, ready to draw our line.  See if you can work out how the X and Y coordinates are finally determined in the body of the for-next loop.

OK so how do we go about optimising this?  Well first we need to analyse it in a little more depth.  Looking at it a bit more closely it becomes apparent that *both* the longest and shortest distances are important.  We have already established that the longest distance is the number of pixels (-1) that we need to turn on for our line.  The shortest distance is the number of times we need to alter our other coordinate.  For example if the longest distance is in the X direction then we will need to change our Y coordinate DistanceY times.  We can use this fact a little later to enable us to optimise our routine.

Now as our major concern is to speed this routine up, the most obvious change would be to convert it from floating point to integer because floating point operations are *slow* by comparison.  This is easy enough until we get to the point where fractions are used.  However there is a way around this.  In order to illustrate this I will assume that the distance between the two X coordinates is the longest. Looking at our routine we can see that in this case our DistanceX corresponds to an IncrementX of precisely 1.  What this does is to ensure that for every pass through our for-next loop, a new pixel is set in the X direction.  We also see that our IncrementY is a fraction of 1.  This means that it takes a more than 1 pass (except in one special case mentioned later) through our for-next loop before we change the Y coordinate of the pixels that we are setting.  We can simulate this by use of a variable that holds an intermediate value. What we do is to assign a value of zero to this variable before we enter the for-next loop.  Then on every pass through the loop we add the DistanceY to this variable and compare the result with our DistanceX.  When the value in our variable equals or exceeds that of DistanceX we alter the Y coordinate and subtract the value of DistanceX from it.

We are now almost there.  We can now (if we so desire) convert our line drawing routine from being floating point to integer.  However there is still some optimisation we can do to our routine.  Again the 2 distance variables are central to this.  This is because there are some cases where we do not need to do any comparisons within the for-next loop.  Remember, every time that we need to make a comparison we are using processor time.  Fortunately these cases are easy enough to detect by examining the values of the 2 distance variables.

The first special case is detected when both distance variables hold the value zero.  When this is the case it means that we are dealing with a single pixel that needs to set and not a line to be drawn so we can use PSET and return from our SUB.

The second case is where the DistanceX variable holds zero and DistanceY does not.  This means that we need to draw a vertical line.

In the third case it is DistanceY that holds zero and DistanceX does not.  In this case we need to draw a horizontal line.

The final special case is where neither distance variable holds zero but both contain the same value.  This is where we need to draw a diagonal line at 45 degrees (at least in modes with square pixels). This means that for each new pixel there is a new X and Y coordinate pair.

This leaves the 2 cases that will be used most often.  Where the DistanceX is greater than the DistanceY and where the DistanceY is greater than the DistanceX.  As we have separated out the other 4 cases in the interests of speed optimisation it makes sense to do the same for this last pair of cases.

The final design decision that I have taken is to implement the whole thing as a number of SUBs.  This makes it easier to test and also, I hope, easier to understand.

Code: (Select All)
CONST FromX = 10
CONST FromY = 10
CONST ToX = 310
CONST ToY = 190
SCREEN 13
_FullScreen _SquarePixels
FOR Index = 1 TO 5
    LINE (FromX, FromY)-(ToX, ToY), 15
    Sleep
    DDE2 FromX, FromY, ToX, ToY, 12
    Sleep
NEXT Index
SLEEP
END

SUB DDE2 (X1%, Y1%, X2%, Y2%, Colour%)
    XLength% = X2% - X1%
    XIncrement% = SGN(XLength%)
    XLength% = XLength% * XIncrement%
    YLength% = Y2% - Y1%
    YIncrement% = SGN(YLength%)
    YLength% = YLength% * YIncrement%
    IF XLength% = 0 AND YLength% = 0 THEN
        PSET (X1%, Y1%), Colour%
    ELSEIF XLength% = YLength% THEN
        Do45Degrees X1%, Y1%, XIncrement%, YIncrement%, XLength%, Colour%
    ELSEIF XLength% = 0 THEN
        DoVertical X1%, Y1%, Y2%, YIncrement%, Colour%
    ELSEIF YLength% = 0 THEN
        DoHorizontal X1%, X2%, Y1%, XIncrement%, Colour%
    ELSEIF XLength% > YLength% THEN
        XGreater X1%, Y1%, XLength%, YLength%, XIncrement%, YIncrement%, Colour%
    ELSE
        YGreater X1%, Y1%, XLength%, YLength%, XIncrement%, YIncrement%, Colour%
    END IF
END SUB

SUB Do45Degrees (XStart%, YStart%, XIncrement%, YIncrement%, Length%, Colour%)
    X% = XStart%
    Y% = YStart%
    PSET (X%, Y%), Colour%
    FOR Index% = 1 TO Length%
        X% = X% + XIncrement%
        Y% = Y% + YIncrement%
        PSET (X%, Y%), Colour%
    NEXT Index%
END SUB

SUB DoHorizontal (X1%, X2%, Y%, XIncrement%, Colour%)
    FOR X% = X1% TO X2% STEP XIncrement%
        PSET (X%, Y%), Colour%
    NEXT X%
END SUB

SUB DoVertical (X%, Y1%, Y2%, YIncrement%, Colour%)
    FOR Y% = Y1% TO Y2% STEP YIncrement%
        PSET (X%, Y%), Colour%
    NEXT Y%
END SUB

SUB XGreater (XStart%, YStart%, XLength%, YLength%, XIncrement%,  YIncrement%, Colour%)
    X% = XStart%
    Y% = YStart%
    ChangeY% = 0
    PSET (X%, Y%), Colour%
    FOR Index% = 1 TO XLength%
        X% = X% + XIncrement%
        ChangeY% = ChangeY% + YLength%
        IF ChangeY% >= XLength% THEN
            Y% = Y% + YIncrement%
            ChangeY% = ChangeY% - XLength%
        END IF
        PSET (X%, Y%), Colour%
    NEXT Index%
END SUB

SUB YGreater (XStart%, YStart%, XLength%, YLength%, XIncrement%,  YIncrement%, Colour%)
    X% = XStart%
    Y% = YStart%
    ChangeX% = 0
    PSET (X%, Y%), Colour%
    FOR Index% = 1 TO YLength%
        Y% = Y% + YIncrement%
        ChangeX% = ChangeX% + XLength%
        IF ChangeX% >= YLength% THEN
            X% = X% + XIncrement%
            ChangeX% = ChangeX% - YLength%
        END IF
        PSET (X%, Y%), Colour%
    NEXT Index%
END SUB

Finally a few notes.

IMPORTANT - There is absolutely *no* error detection in either routine!  So be careful and add them in yourself.  This was done for clarity.

At this point you may be saying 'But QB already has a LINE command, why do we need another one?  Not only that, but this new line does less than the built in one!'  True, but the built-in commands won't work with any of the varieties of modex.  And what happens if for some reason you need to write a line drawing routine in some other language say assembly?  Well now you've got an algorithm that you can use.

Once you've run these routines you may be saying 'Well it appears to work but it doesn't draw exactly the same line as the built-in routine.' True again <g>.  This just shows that there are a number of different algorithms that can be used to achieve the same end.  I strongly suspect that the built-in routine is a variety of the more commonly used Bresenham algorithm.  Because the Bresenham algorithm has error-correction built-in it draws a more accurate line, but this can slow the drawing down.  Even though the Bresenham algorithm is more accurate both algorithms start and end at exactly the same point, so the choice is yours <g>.

Fill and Doros follow in next 2 posts.

TR

Print this item

  Poker hand evaluator
Posted by: Pete - 05-08-2022, 06:11 PM - Forum: Programs - No Replies

I built a game called Pecos Pete Poker around a couple of decades ago. I recently updated it to play on QB64, and I also got together with TheBOB who offered his graphics playing cards if I wanted to make a graphics version. I've been working on that, and since I love reinventing the wheel, I came up with a completely new poker hand evaluator to go with it. This hand evaluation model is written in SCREEN 0 but can be converted to evaluate graphics hands, which I'll work on next week.

You need jacks or better to display a "Pair" with a payout. Other lesser pairs are marked in grey. Press Enter or any non-number key to draw the next hand. Since it takes awhile to get hands like 4 of a kind, and especially a royal flush, I put number buttons in a menu. Press 1 to wait on a royal flush, 2 for a straight flush, 3 for 4 of a kind, 4 for a full house, etc. Press esc if you get tired of waiting, it will go back to one at a time display.

Code: (Select All)
' Jacks or better poker evaluator demo.
' Use keys 1 - 9 to search for particular hands, Royal Flush, Full HOuse, etc.
sw% = 55
sh% = 17
WIDTH sw%, sh%
PALETTE 7, 63
COLOR 0, 7: CLS
fontpath$ = ENVIRON$("SYSTEMROOT") + "\fonts\lucon.ttf"
font& = _LOADFONT(fontpath$, 40, "monospace")
_FONT font&
_DELAY .25
_SCREENMOVE 0, 0
msg$ = "Poker Hand Evaluator"
LOCATE 1, (sw% / 2) - (LEN(msg$) / 2): PRINT msg$;
msg$ = "Any Key or 1=RF 2=SF 3=4K 4=FH 5=F 6=S 7=3K 8=2P 9=P"
LOCATE sh%, (sw% / 2) - (LEN(msg$) / 2): PRINT msg$;
VIEW PRINT 3 TO sh% - 2: LOCATE 4, 1

h = 1 ' Number of hands.
noc = 5 ' Number of card.

DO
    REDIM cardID$(1, 5)
    REDIM taken(5)
    taken(3) = 13: taken(4) = 26: taken(5) = 39
    FOR i = 1 TO noc
        DO
            card = INT(RND * 52) + 1
            FOR j = 1 TO i
                IF taken(j) = card THEN flag = -1: EXIT FOR
            NEXT
            IF flag = 0 THEN taken(i) = card: EXIT DO ELSE flag = 0
        LOOP
        cardID$(h, i) = LTRIM$(STR$(y)) + "|" + LTRIM$(STR$(scol + (i - 1) * 120 + x)) + "#" + LTRIM$(STR$(card))
    NEXT

    IF POS(0) > 3 OR CSRLIN > 4 THEN PRINT: PRINT: PRINT: LOCATE CSRLIN - 1

    LOCATE , 3

    FOR j = 1 TO 5
        a = VAL(MID$(cardID$(h, j), INSTR(cardID$(h, j), "#") + 1))
        a1 = (a - 1) MOD 13 + 1
        x$ = LTRIM$(STR$(a1))
        b = (a + 12) \ 13
        suite$ = CHR$(2 + b)
        REM PRINT x$; suite$; "  ";
        IF suite$ = CHR$(3) OR suite$ = CHR$(4) THEN COLOR 4 ELSE COLOR 0
        SELECT CASE VAL(x$)
            CASE 1: PRINT "A"; suite$; "   ";
            CASE 13: PRINT "K"; suite$; "   ";
            CASE 12: PRINT "Q"; suite$; "   ";
            CASE 11: PRINT "J"; suite$; "   ";
            CASE 10: PRINT "10"; suite$; "  ";
            CASE ELSE: PRINT LTRIM$(STR$(VAL(x$))); suite$; "   ";
        END SELECT
    NEXT

    GOSUB eval

    COLOR 1
    LOCATE , 28
    IF hand$ = "Pair" THEN
        IF highkind >= 11 THEN COLOR 1: PRINT hand$; " (Pay Out)"; ELSE COLOR 8: PRINT hand$;
    ELSE
        PRINT hand$;
    END IF
    COLOR 1

    IF search$ = "" THEN GOSUB getkey ELSE IF INKEY$ = CHR$(27) THEN search$ = ""

    IF LEN(search$) THEN
        IF hand$ = search$ THEN SLEEP: search$ = ""
    END IF

LOOP
END

eval:
hand$ = ""
DO
    ' Look for flush, same suit.
    samesuit = 0
    FOR j = 1 TO noc
        a = VAL(MID$(cardID$(h, j), INSTR(cardID$(h, j), "#") + 1))
        b = (a + 12) \ 13
        IF j > 1 AND b <> samesuit THEN flag = -1: EXIT FOR
        samesuit = b
    NEXT
    IF flag = 0 THEN
        ' Flush or better.
        hand$ = "Flush"
    ELSE
        flag = 0
    END IF

    ' Look for staright, sequential order.
    high = 0: low = 0: match$ = ""
    FOR j = 1 TO noc
        a = VAL(MID$(cardID$(h, j), INSTR(cardID$(h, j), "#") + 1))
        a1 = (a - 1) MOD 13 + 1
        match$ = match$ + CHR$(a1 + 64)
    NEXT
    IF INSTR(match$, CHR$(1 + 64)) THEN
        IF INSTR(match$, CHR$(13 + 64)) THEN high = 14 ' Ace high straight possible.
    END IF

    FOR j = 1 TO noc
        a = VAL(MID$(cardID$(h, j), INSTR(cardID$(h, j), "#") + 1))
        a1 = (a - 1) MOD 13 + 1
        IF j > 1 AND INSTR(match$, CHR$(a1 + 64)) <> j THEN match$ = "": EXIT FOR
        IF low = 0 OR low > a1 THEN
            IF a1 = 1 AND high = 14 THEN ELSE low = a1
        END IF
        IF high = 0 OR high < a1 THEN high = a1
    NEXT

    IF LEN(match$) AND high - low = noc - 1 THEN
        IF hand$ = "Flush" THEN
            IF high = 14 THEN
                hand$ = "Royal Flush"
            ELSE
                hand$ = "Straight Flush": EXIT DO
            END IF
        ELSE
            hand$ = "Straight": EXIT DO
        END IF
    END IF

    ' Look for number of kinds.
    kinds = 1: highkind = -1
    FOR j = 1 TO noc
        kindcnt = 0
        a = VAL(MID$(cardID$(h, j), INSTR(cardID$(h, j), "#") + 1))
        a1 = (a - 1) MOD 13 + 1
        IF a1 = 1 THEN ' Convert ace high.
            a1 = 14
            '' cardID$(h, j) = MID$(cardID$(h, j), 1, INSTR(cardID$(h, j), "#")) + "14"
        END IF
        FOR k = 1 TO noc
            IF j <> k THEN
                IF a1 = (VAL(MID$(cardID$(h, k), INSTR(cardID$(h, k), "#") + 1)) - 1) MOD 13 + 1 OR a1 = 14 AND (VAL(MID$(cardID$(h, k), INSTR(cardID$(h, k), "#") + 1)) - 1) MOD 13 + 1 = 1 THEN
                    kindcnt = kindcnt + 1: IF highkind < a1 OR highkind = 0 THEN highkind = a1
                END IF
            END IF
            IF kinds <= kindcnt THEN kinds = kindcnt + 1
        NEXT k
    NEXT j

    IF kinds = 4 THEN hand$ = "Four of a Kind": EXIT DO

    IF kinds = 3 THEN ' Look for full house.
        kinds = 0
        FOR j = 1 TO noc
            kindcnt = 0
            a = VAL(MID$(cardID$(h, j), INSTR(cardID$(h, j), "#") + 1))
            a1 = (a - 1) MOD 13 + 1
            FOR k = 1 TO noc
                IF j <> k AND a1 <> highkind THEN
                    IF a1 = (VAL(MID$(cardID$(h, k), INSTR(cardID$(h, k), "#") + 1)) - 1) MOD 13 + 1 THEN
                        kindcnt = kindcnt + 1
                    END IF
                END IF
            NEXT k
            IF kinds < kindcnt THEN kinds = kindcnt + 1
        NEXT j
        IF kinds = 2 THEN
            hand$ = "Full House": EXIT DO
        ELSE
            hand$ = "Three of a Kind": EXIT DO
        END IF
    END IF

    IF kinds = 2 THEN
        ' Look for two pair.
        kinds = 0
        FOR j = 1 TO noc
            kindcnt = 0
            a = VAL(MID$(cardID$(h, j), INSTR(cardID$(h, j), "#") + 1))
            a1 = (a - 1) MOD 13 + 1
            FOR k = 1 TO noc
                IF j <> k AND a1 <> highkind THEN
                    IF a1 = 1 AND highkind = 14 THEN
                        ' Checks for ace as 1 here after previous highkind converion to 14.
                    ELSE
                        IF a1 = (VAL(MID$(cardID$(h, k), INSTR(cardID$(h, k), "#") + 1)) - 1) MOD 13 + 1 THEN
                            kindcnt = kindcnt + 1
                        END IF
                    END IF
                END IF
            NEXT k
            IF kinds < kindcnt THEN kinds = kindcnt + 1
        NEXT j
        IF kinds = 2 THEN
            hand$ = "Two Pair": EXIT DO
        ELSE
            hand$ = "Pair": EXIT DO
        END IF
    END IF
    EXIT DO
LOOP
RETURN

getkey:
DO
    _LIMIT 30
    b$ = INKEY$
    IF LEN(b$) THEN
        IF b$ = CHR$(27) THEN SYSTEM
        IF b$ >= "1" AND b$ <= "9" THEN
            SELECT CASE VAL(b$)
                CASE 1: search$ = "Royal Flush"
                CASE 2: search$ = "Straight Flush"
                CASE 3: search$ = "Four of a Kind"
                CASE 4: search$ = "Full House"
                CASE 5: search$ = "Flush"
                CASE 6: search$ = "Straight"
                CASE 7: search$ = "Three of a Kind"
                CASE 8: search$ = "Two Pair"
                CASE 9: search$ = "Pair"
            END SELECT
            EXIT DO
        END IF
        EXIT DO
    END IF
LOOP
RETURN


$IF  THEN
    ---------Hearts
    1=A
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11=J
    12=Q
    13=K
    ---------Diamonds
    14=A
    15=2
    16=3
    17=4
    18=5
    19=6
    20=7
    21=8
    22=9
    23=10
    24=J
    25=Q
    26=K
    ---------Clubs
    27=A
    28=2
    29=3
    30=4
    31=5
    32=6
    33=7
    34=8
    35=9
    36=10
    37=J
    38=Q
    39=K
    ---------Spades
    40=A
    41=2
    42=3
    43=4
    44=5
    45=6
    46=7
    47=8
    48=9
    49=10
    50=J
    51=Q
    52=K
    --------------------Test
    card = 13: i = 3: cardID$(h, i) = LTRIM$(STR$(y)) + "|" + LTRIM$(STR$(scol + (i - 1) * 120 + x)) + "#" + LTRIM$(STR$(card))
    card = 26: i = 4: cardID$(h, i) = LTRIM$(STR$(y)) + "|" + LTRIM$(STR$(scol + (i - 1) * 120 + x)) + "#" + LTRIM$(STR$(card))
    card = 39: i = 5: cardID$(h, i) = LTRIM$(STR$(y)) + "|" + LTRIM$(STR$(scol + (i - 1) * 120 + x)) + "#" + LTRIM$(STR$(card))
    card = 1: i = 1: cardID$(h, i) = LTRIM$(STR$(y)) + "|" + LTRIM$(STR$(scol + (i - 1) * 120 + x)) + "#" + LTRIM$(STR$(card))
    card = 14: i = 2: cardID$(h, i) = LTRIM$(STR$(y)) + "|" + LTRIM$(STR$(scol + (i - 1) * 120 + x)) + "#" + LTRIM$(STR$(card))
$END IF


Pete

Print this item