This is the "SaveImage" routine from the Wiki, changed by me to try to make it faster, but it seems to be a failure with big pictures. For stuff larger than 1920x1080 might have to set even greater string buffers for "d$" and "r$". It was quite fast on my old Toshiba laptop purchased in December 2006 with 1024x768 resolution.
The "DIM" declarations are to ensure it works in "OPTION _EXPLICIT" mode.
!Needs testing!
Code: (Select All)
''from QB64 wiki
''modifications by mnrvovrfc
''this uses MID$() in replacement up to greatly speed up
'' the reading of the screen,
'' it avoids concatenation of strings as much as possible
'' which is notoriously slow when millions of bytes are involved
Sub SaveImage (image As Long, filename As String)
Dim ld As Long, lr As Long, lx As Long
Dim bytesperpixel&, bpp&, lastsource&, px&, py&, cv&, c&, f&, x&, y&, b$, d$, r$, padder$, rrr$, filename2$
bytesperpixel& = _PixelSize(image&)
If bytesperpixel& = 0 Then Print "Text modes unsupported!": End
If bytesperpixel& = 1 Then bpp& = 8 Else bpp& = 24
x& = _Width(image&)
y& = _Height(image&)
b$ = "BM????QB64????" + MKL$(40) + MKL$(x&) + MKL$(y&) + MKI$(1) + MKI$(bpp&) + MKL$(0) + "????" + String$(16, 0) 'partial BMP header info(???? to be filled later)
If bytesperpixel& = 1 Then
For c& = 0 To 255 ' read BGR color settings from JPG image + 1 byte spacer(CHR$(0))
cv& = _PaletteColor(c&, image&) ' color attribute to read.
b$ = b$ + Chr$(_Blue32(cv&)) + Chr$(_Green32(cv&)) + Chr$(_Red32(cv&)) + Chr$(0) 'spacer byte
Next
End If
Mid$(b$, 11, 4) = MKL$(Len(b$)) ' image pixel data offset(BMP header)
d$ = Space$(50000000)
ld = 1
lastsource& = _Source
_Source image&
If ((x& * 3) Mod 4) Then padder$ = String$(4 - ((x& * 3) Mod 4), 0)
For py& = y& - 1 To 0 Step -1 ' read JPG image pixel color data
r$ = Space$(10000000)
lr = 1
For px& = 0 To x& - 1
c& = Point(px&, py&) 'POINT 32 bit values are large LONG values
If bytesperpixel& = 1 Then
rrr$ = Chr$(c&)
Else
rrr$ = Left$(MKL$(c&), 3)
End If
lx = Len(rrr$)
Mid$(r$, lr, lx) = rrr$
lr = lr + lx
Next px&
r$ = Left$(r$, lr - 1)
rrr$ = r$ + padder$
lx = Len(rrr$)
Mid$(d$, ld, lx) = rrr$
ld = ld + lx
Next py&
_Source lastsource&
d$ = Left$(d$, ld - 1)
Mid$(b$, 35, 4) = MKL$(Len(d$)) ' image size(BMP header)
Mid$(b$, 3, 4) = MKL$(Len(b$) + Len(d$)) ' size of data file(BMP header)
filename2$ = filename$
If LCase$(Right$(filename$, 4)) <> ".bmp" Then filename2$ = filename$ + ".bmp"
f& = FreeFile
Open filename2$ For Output As #f&: Close #f& ' erases an existing file
Open filename2$ For Binary As #f&
Put #f&, , b$
Put #f&, , d$
Close #f&
End Sub
I ain't got nothin' but KEYWORDS, eight days a week...
So let's talk _SCREENPRINT, the little bro to the bigger and better Win32 SENDKEYS function.
SYNTAX: _SCREENPRINT text$
Note: This keyword is not supported in Linux and Mac Operating Systems.
So what does it do?
_SCREENPRINT is acts as a virtual keypress and text transmitter. It is limited in the key combos available, which can be seen in the table, below...
Code: (Select All)
CTRL + A = CHR$(1) ☺ StartHeader (SOH) CTRL + B = CHR$(2) ☻ StartText (STX)
CTRL + C = CHR$(3) ♥ EndText (ETX) CTRL + D = CHR$(4) ♦ EndOfTransmit (EOT)
CTRL + E = CHR$(5) ♣ Enquiry (ENQ) CTRL + F = CHR$(6) ♠ Acknowledge (ACK)
CTRL + G = CHR$(7) • BEEP (BEL) CTRL + H = CHR$(8) ◘ [Backspace] (BS)
CTRL + I = CHR$(9) ○ Horiz.Tab [Tab] CTRL + J = CHR$(10) ◙ LineFeed(printer) (LF)
CTRL + K = CHR$(11) ♂ Vert. Tab (VT) CTRL + L = CHR$(12) ♀ FormFeed(printer) (FF)
CTRL + M = CHR$(13) ♪ [Enter] (CR) CTRL + N = CHR$(14) ♫ ShiftOut (SO)
CTRL + O = CHR$(15) ☼ ShiftIn (SI) CTRL + P = CHR$(16) ► DataLinkEscape (DLE)
CTRL + Q = CHR$(17) ◄ DevControl1 (DC1) CTRL + R = CHR$(18) ↕ DeviceControl2 (DC2)
CTRL + S = CHR$(19) ‼ DevControl3 (DC3) CTRL + T = CHR$(20) ¶ DeviceControl4 (DC4)
CTRL + U = CHR$(21) § NegativeACK (NAK) CTRL + V = CHR$(22) ▬ Synchronous Idle (SYN)
CTRL + W = CHR$(23) ↨ EndTXBlock (ETB) CTRL + X = CHR$(24) ↑ Cancel (CAN)
CTRL + Y = CHR$(25) ↓ EndMedium (EM) CTRL + Z = CHR$(26) → End Of File(SUB) (EOF)
So let's take a look at the first entry, Ctrl+A. This is the key combo we use to highlight text in other apps.
_SCREENPRINT CHR$(1) will therefore highlight all the text on another open and active app.
Wait for it to compile and start. When you see the window open, click back on this browser window...
Code: (Select All)
_DELAY 5 ' Give yourself some time to click another app, like this browser.
_SCREENPRINT CHR$(1)
Cool, right? Well now _SCREENPRINT also works progressively, so if we wanted to copy that text to our clipboard, we would just code...
Code: (Select All)
_DELAY 5 ' Give yourself some time to click another app, like this browser.
_SCREENPRINT CHR$(1)
_SCREENPRINT CHR$(3) ' See the chart. This is Ctrl+C, COPY.
' Now let's see if it worked by reading the clipboard...
PRINT _CLIPBOARD$
If you wanted to paste, it's _SCREENPRINT CHR$(22), btw.
So speaking of pasting, lets try a select all, copy/paste from the QB64 IDE into Notepad...
Windows only example.
Code: (Select All)
_CLIPBOARD$ = ""
_DELAY 1
_SCREENHIDE
DO
_LIMIT 5
LOOP UNTIL LEN(_CLIPBOARD$)
SHELL _HIDE "start Notepad.exe" ' Open Windows Notepad.
_DELAY 1
_SCREENPRINT _CLIPBOARD$
_DELAY 3
_SCREENSHOW
PRINT: PRINT " Cool, right?"
So with _SCREENPRINT we can do things like fill out web forms (Note: _SCREENPRINT CHR$(9) is Tab to change form fields), gather text from other apps, execute commands with _SCREENPRINT CHR$(13) the Enter key, etc.
For some routines like ALT + F to open the QB64 IDE File Menu, you need something more robust like Win32 API SENDKEYS.
DECLARE DYNAMIC LIBRARY "user32"
SUB SENDKEYS ALIAS keybd_event (BYVAL bVk AS LONG, BYVAL bScan AS LONG, BYVAL dwFlags AS LONG, BYVAL dwExtraInfo AS LONG)
END DECLARE
PRINT "Click the QB64 IDE window after I hide!"
_DELAY 5
_SCREENHIDE ' Get the app window the hell out of our way...
_DELAY 5
SENDKEYS VK_ALT, 0, 0, 0 ' Alt
SENDKEYS &H46, 0, 0, 0 ' F open IDE file menu.
_DELAY .1
SENDKEYS &H45, 0, KEYEVENTF_KEYUP, 0 ' Release F key.
SENDKEYS VK_ALT, 0, KEYEVENTF_KEYUP, 0 ' ' Release Alt key.
_DELAY 5
_SCREENSHOW
This is a TCP/IP routine. Windows users will need to Okay it, on the first run, with Windows Defender.
I posted two versions. The first minimizes and restores the chat window to activate it. The second uses QB64 _SCREENCLICK. auto-activation allows us to continuously send messages back and forth without clicking the window each rotation.
Sorry Linux and mac users, I tried, but to return focus to each active chat window requires one Win32 API command to restore the window, and mn pointed out that _SCREENCLICK isn't supported in these operating systems. If anyone can figure out a QB64 way to force a minimized window back to the desktop, please let me know.
So to gives this a try, you need to copy and run both the "host" and client" programs. Since the host starts the client, you will need to name the client as messenger_client.bas and save it as messenger_client.exe before you run the host program.
Min/Restore Version
Host
Code: (Select All)
DECLARE DYNAMIC LIBRARY "user32"
FUNCTION ShowWindow& (BYVAL hWnd AS LONG, BYVAL nCmdShow AS LONG) 'maximize process
END DECLARE
_SCREENMOVE 0, 0 ' Set up this host window to the left of your desktop.
WIDTH 60, 25
PALETTE 0, 8
COLOR 7, 0
CLS
IF NOT _FILEEXISTS("messenger_client.exe") THEN PRINT "Cannot find file: messenger_client.exe. Ending...": END
DIM host_msg AS STRING, client_msg AS STRING
DO
IF initiate = 0 THEN ' This only needs to be performed once, to open the client window.
DO UNTIL x ' Stay in loop until window determines if it is the host or client window.
x = _OPENCLIENT("TCP/IP:1234:localhost") ' Used to establish a TCP/IP routine.
IF x = 0 THEN
x = _OPENHOST("TCP/IP:1234") ' Note the host and clinet must have the same 1234 I.D. number.
a$ = "Opening as host." ' x channel is now open and this window becomes the host.
ELSE
a$ = "Opening as client." ' Should not go here for this demo.
END IF
PRINT a$
LOOP
SHELL _HIDE _DONTWAIT "START messenger_client.exe" ' Open the client window.
initiate = -1 ' Switches this block statement off for all subsequent loops.
END IF
IF z = 0 THEN ' Initiates an open channel number when zero.
DO
z = _OPENCONNECTION(x) ' Checks if host is available to transfer data.
LOOP UNTIL z
PRINT "Connection established."
_DELAY 1
LOCATE 2: PRINT SPACE$(_WIDTH * 2) ' Remove previous text.
LOCATE 3, 1
GOSUB focus
END IF
' Okay, time to input something on the host that will be communicated to the client.
COLOR 7: LINE INPUT "Message to client: "; host_msg: PRINT
PUT #z, , host_msg ' Input is now entered into TCP/IP routine.
IF host_msg = "" THEN SYSTEM
DO
GET #z, , client_msg
LOOP UNTIL LEN(client_msg) ' Exits loop when a return msg is received.
COLOR 6: PRINT "Message from client: "; client_msg: PRINT
host_msg = "": PUT #z, , host_msg$ ' Now put our client value back into the routine. Failure to do so would result in the client not waiting in the GET #x DO/LOOP.
_KEYCLEAR ' Prevents typing before ready.
DIM host_msg AS STRING, client_msg AS STRING
_SCREENMOVE 600, 0 ' Set up this client window next to your host window.
WIDTH 50, 25
PALETTE 0, 8
COLOR 7, 0
CLS
x = _OPENCLIENT("TCP/IP:1234:localhost") ' Used to establish a TCP/IP routine.
PRINT "Opened as client.": PRINT
DO UNTIL x = 0 ' Prevents running if this app is opened without using host.
DO
_LIMIT 30
GET #x, , host_msg ' Waits until it receives message sent from the host.
LOOP UNTIL LEN(host_msg)
COLOR 6: PRINT "Message from host: "; host_msg
PRINT
_KEYCLEAR ' Prevents typing before ready.
GOSUB focus
COLOR 7: LINE INPUT "Message to host: "; client_msg: PRINT
IF client_msg = "" THEN SYSTEM
That one used all Win32 API to find, minimize and restore the window. If you are interested in seeing the extra API stuff, check it out. Also, I play loose and fast with the API type variables. So far I've only been stung once by changing an _OFFSET to a LONG. Most of the time you can get away from convention.
Oh, why bother minimizing and restoring? Well, so far none of us can figure out a way to get a window not just in focus, but active and in focus after another window is made active. Spriggsy and I both came up with the min/restore trick at the same time, which was pretty funny.
Okay, for Linus and Mac fans... (And yes, I made _SCREENCLICK 'smart' so you can move the windows around).
_SCREENCLICK Version: Same App, but uses _SCREENCLICK instead of Win32 API to activate each window.
_SCREENMOVE 0, 0 ' Set up this host window to the left of your desktop.
WIDTH 60, 25
PALETTE 0, 8
COLOR 7, 0
CLS
IF NOT _FILEEXISTS("messenger_client.exe") THEN PRINT "Cannot find file: messenger_client.exe. Ending...": END
DIM host_msg AS STRING, client_msg AS STRING
DO
IF initiate = 0 THEN ' This only needs to be performed once, to open the client window.
DO UNTIL x ' Stay in loop until window determines if it is the host or client window.
x = _OPENCLIENT("TCP/IP:1234:localhost") ' Used to establish a TCP/IP routine.
IF x = 0 THEN
x = _OPENHOST("TCP/IP:1234") ' Note the host and clinet must have the same 1234 I.D. number.
a$ = "Opening as host." ' x channel is now open and this window becomes the host.
ELSE
a$ = "Opening as client." ' Should not go here for this demo.
END IF
PRINT a$
LOOP
SHELL _HIDE _DONTWAIT "START messenger_client.exe" ' Open the client window.
initiate = -1 ' Switches this block statement off for all subsequent loops.
END IF
IF z = 0 THEN ' Initiates an open channel number when zero.
DO
z = _OPENCONNECTION(x) ' Checks if host is available to transfer data.
LOOP UNTIL z
PRINT "Connection established."
_DELAY 1
LOCATE 2: PRINT SPACE$(_WIDTH * 2) ' Remove previous text.
LOCATE 3, 1
GOSUB focus
END IF
' Okay, time to input something on the host that will be communicated to the client.
COLOR 7: LINE INPUT "Message to client: "; host_msg: PRINT
PUT #z, , host_msg ' Input is now entered into TCP/IP routine.
IF host_msg = "" THEN SYSTEM
DO
GET #z, , client_msg
LOOP UNTIL LEN(client_msg) ' Exits loop when a return msg is received.
COLOR 6: PRINT "Message from client: "; client_msg: PRINT
host_msg = "": PUT #z, , host_msg$ ' Now put our client value back into the routine. Failure to do so would result in the client not waiting in the GET #x DO/LOOP.
_KEYCLEAR ' Prevents typing before ready.
DIM host_msg AS STRING, client_msg AS STRING
_SCREENMOVE 600, 0 ' Set up this client window next to your host window.
WIDTH 50, 25
PALETTE 0, 8
COLOR 7, 0
CLS
x = _OPENCLIENT("TCP/IP:1234:localhost") ' Used to establish a TCP/IP routine.
PRINT "Opened as client.": PRINT
DO UNTIL x = 0 ' Prevents running if this app is opened without using host.
DO
_LIMIT 30
GET #x, , host_msg ' Waits until it receives message sent from the host.
LOOP UNTIL LEN(host_msg)
COLOR 6: PRINT "Message from host: "; host_msg
PRINT
_KEYCLEAR ' Prevents typing before ready.
GOSUB focus
COLOR 7: LINE INPUT "Message to host: "; client_msg: PRINT
IF client_msg = "" THEN SYSTEM
_DELAY 2
_SCREENHIDE
_DELAY 5
' Error 5 after delay at line below...
IF _SCREENICON THEN BEEP ' Should beep with value -1 when minimized by _SCREENHIDE.
_SCREENSHOW
So I have done Win32 API min/restore with focus, but now I was looking for an all QB64 method. Since _SCREENHIDE is supposed minimize the program, it seems odd _SCREENICON should throw an error. It should return -1 when the window is minimized. If you REM out the SCREENHIDE and manually minimize, it works just fine, but apparently not when _SCREENHIDE minimizes the window for you.
Dim As Long connection: connection = OpenClient("HTTP:https://api.kanye.rest/")
If connection <> 0 And StatusCode(connection) = 200 Then
Dim As String buf, outbuf
While Not EOF(connection)
Get connection, , buf
outbuf = outbuf + buf
Wend
outbuf = Mid$(outbuf, 11)
outbuf = Mid$(outbuf, 1, Len(outbuf) - 2)
Print outbuf
Print: Print "-Kanye West"
End If
For folks who want to see how much QB64 has evolved and grown over the last year, I present my little Christmas Program that I was working on and stalled out on last year.
(IF the forum download is too slow, which seems to be a problem for some of our Linux folks, you can also try to get it directly from my OneDrive: https://1drv.ms/u/s!AknUrv8RXVYMm_Uh2wya...A?e=XIKRX8 It may work better for you. )
Last year, I ran into an issue that I simply couldn't work around at all -- it was taking FOREVER and EVER to load my list of holiday music into QB64. No matter how sneakily I tried to sort out a workaround to get past the issue, it still introduced unacceptable levels of lag into the program and made user responses delay by several seconds. Either that, or else I just introduced a nice 10 minute pause at program startup, so that all the sounds could be loaded at first, before actually playing around with the program.
NEITHER of which were actual workable solutions for the program!!
So... come along this year, QB64-PE gets a complete overhaul of the audio system. What took 10 minutes to load, we now load in perhaps 3 seconds! I can once again resume work on my Christmas Project one more time!!
If anyone wants to see the difference in performance for themselves, just download the file above and extract it. It's in its own little XMas folder, so it's easy to clean up and remove the clutter from your drive after extracting, if anyone's worried about something like that.
Compile and run... At the very start, you'll see a series of numbers that pop up and count down the screen -- that's the program loading our music files for us, for the first time. Regardless of if it's incredibly slow or fast for you, once it's finished (or you terminate the process), go into the QB64-PE IDE and navigate to "Options >> Compiler Options" and then toggle the option at the bottom of the list: "use old audio backend".
Compile and run a second time.
The difference here should be as plain as night and day. THAT'S how much QB64-PE has changed under the hood in the last year!!
And if that doesn't put you in a Merry Christmas spirit, then BAH HUMBUG TO YOU, MISTER PETE! Errr... MISTER SCROOGE!!
Space, the final frontier, and when you're sick of space on both sides of your string, use _TRIM$.
_TRIM$ simply removes any leading and/or trailing spaces from any string.
SYNTAX: _TRIM$(mytext$) and can also be used as: _TRIM$(" my text ")
_TRIM$ is the QB64 answer to, "What do you get when you put LTRIM$ + RTRIM$ together?" Well, until _TRIM$ came along it was LTRIM$(RTRM$(mystring$)). Note: LTRIM$ removes leading spaces, spaces to the "left" and RTRIM$ removes trailing space, spaces to the right, and _TRIM$ removes both.
If there are no spaces, _TRIM$ simply does nothing.
_TRIM$ can be combined with STR$(), which converts a number to a string and removes the trailing space. So why do we need _TRIM? The answer is to get rid of the leading space the system uses to reserve space for a possible negative sign in front of a number even after STR$() is used to convert it to a string.
So while PRINT STR$(-1) is "-1", PRINT STR$(1) would be " 1". To get rid of that leading space we can code either: PRINT LTRIM$(STR$(1)) or PRINT _TRIM$(STR$(1)). Of course most of the time a number will be represented by a variable, so we usually code: MyNumber = 1: MyNumber$ = _TRIM$(STR$(a)).
Code: (Select All)
a = -1
PRINT "|"; a; "|" ' Has one trailing space.
PRINT "|"; STR$(a); "|" ' Chops the trailing space when converting to a string.
PRINT "|"; _TRIM$(STR$(a)); "|" ' Actually not needed here because of the negative number value.
PRINT
a = 1
PRINT "|"; a; "|" ' Has one leading space and one trailing space.
PRINT "|"; STR$(a); "|" ' Chops the trailing space when converting to a string.
PRINT "|"; _TRIM$(STR$(a)); "|" ' Chops the remaining leading space.
Another use is when a DIM statement if made to produce a "fixed" string. A fixed string defines the string length and creates trailing spaces if the string is smaller the dim size created.
Example:
Steve's Spreadsheet
Code: (Select All)
DIM a as STRING * 10 ' All strings named a will be 10 bytes long.
FOR i = 1 TO 3 ' (Not 2 B confused with 1, 2, 3.) :D
READ a
PRINT "|";a;"|", LEN(a)
PRINT "|";_TRIM$(a);"|", LEN(_TRIM$(a)) ' Here we combine _TRIM$ with LEN() to output the length of our trimmed string.
NEXT
' Steve's sheet spreaders...
DATA Horse,Pig,Mule
_TRIM$ is often used in parsing routines to compare strings as apples to apples, instead of apples to apples with leading and trailing spaces.
So how about some more use examples? Feel free to post yours...
The Dungeon contains assembly to trap ctrl-break and can be removed from the source by deleting Call Setint/Call Restint.
This program and source are completely 16-bit and won't load in QB64 because it contains arrays in UDTs..
For Dungeon_v12_QB64.zip it contains no assembly.
Attached is:
Dngeon12.zip for VB10.
Dungeon_v12_QB64.zip for QB64.
The readme.txt is:
Code: (Select All)
Program:
Welcome to The Dungeon Adventure Game v12.0 r3.0. These files, documents,
and programs are public domain. Anyone may use, rewrite, or distribute
them without any fee, charge for use, or packaging requirements.
Files:
Separate the .zip file with the PKWare utility into the directory:
c:
cd \
md dngeon12
cd \dngeon12
copy \temp\dngeon12.zip \dngeon12
with the command
pkunzip dngeon12.zip
The .zip file contains the files:
ansi.bas -- opening screen source
ansi.exe -- opening screen program
compile.bat -- compiling batch program
compile.txt -- compile instructions
desc.sdi -- program description
dungeon.bas -- main dungeon source
dungeon.doc -- short documentation
dungeon.exe -- main dungeon program
edit.bas -- edit utility source
edit.exe -- edit utility program
file_id.diz -- program description
features.txt -- list of features
go.bat -- startup batch file
help.bas -- help menu source
help.exe -- help menu program
keytrap.asm -- assembly utility source
list.bat -- lists source to printer
mapedit.bas -- map edit utility source
mapedit.exe -- map edit utility program
page.com -- display utility
print.bat -- prints documentation
program.txt -- description of program
readme.bat -- displays readme file
readme.txt -- readme text file
swapbas.asm -- assembly utility source
util.bas -- display utility
util.exe -- display utility source
Dungeon creates the files:
datafile.00x -- player data file
players.dat -- player data file
ranklist.dat -- ranking list bulletin
Requirements:
The Dungeon is designed to operate on any standard PC, XT, or AT with
minimum of 256K memory, a floppy or fixed disk, and any color graphics
adapter.
The DUNGEON v12.0 r3.0 Documentation Page i
Starting the game:
Enter one of the following commands at the DOS prompt:
go -- read documentation and start the program
print -- print the documentation
readme -- display the readme text file
Instructions:
Playing is done by entry on the numeric keypad. Keys 0, 1, .., 9, and
other symbols like -, +, and = are used for commands. Be sure you have
turned on numlock before game play. The Dungeon also recognizes cursor
keys for moving in the game without numlock.
Program compiling:
This disk contains the compile batch files, BASIC source, and additional
utility for the dungeon v12.0. These files, documents, and programs are
public domain. Anyone may use, rewrite, or distribute them without any
fee, charge for use, or packaging requirements.
Compiling requirements:
The compile program is designed to operate on any standard PC, XT, or AT
with 512K, fixed disk, and any monitor.
Starting the compiler:
Enter one of the following commands at the DOS prompt:
compile -- start the compiling process
list -- print the source
Compiling instructions:
Compiling is done by entering the subprogram name to create with the
compile.bat program. You should have the required compiler and library
listed in the compile.txt file. Example to start: compile dungeon. Also,
the dungeon comes with a makefile containing instructions for nmake.exe
to compile the dungeon programs by date of .exe files.
Maintenance release v12.0 r2.0 Fixed/added:
Alt-Tab to add the globe of power to player inventory.
Clearing monster array between changing dungeon levels.
Dungeon level replenish to avoid placing items in rooms.
Overflow error in info screen for levels greater than 50.
More than eight monsters attacking player at once.
Distance to monsters for evade/approach fixed.
Count loops inside searching for empty dungeon cell.
Timer beyond midnight pause loop corrected.
Bulletin report utility display cleaned.
Added F11/F12 display/clear dungeon symbols.
Fixed page length in util display.
Eat keystrokes in second timer pause routine.
Remove monsters beyond player from attack array.
Update some counting variables during player movement.
Trapped interrupt service error during program shells.
Error with trapped control-break being returned as two-byte null.
Problem restoring current directory during shells.
ERASE probably should be renamed ARRase, because all it erases is the values stored in a specified array.
ERRASE makes the strings assigned to an array null or makes the numeric values assigned to a numeric array zero.
ERASE ArrayName [, others...]
Example:
Code: (Select All)
DIM Pete(10) AS STRING, var(100) AS INTEGER, cnt(20) AS LONG
ERASE Pete, var, cnt
ERASE can be used with STATIC or DYNAMIC arrays, but there is an important difference. Try running the two following code snippets.
Code: (Select All)
DIM Pete(1 TO 20) AS INTEGER ' DIM makes Pete a STATIC array.
FOR i = 1 TO 20
Pete(i) = -i
NEXT
FOR i = 1 TO UBOUND(Pete)
PRINT Pete(i)
NEXT
SLEEP
ERASE Pete
' All zeros will now be output.
CLS
FOR i = 1 TO 20
PRINT Pete(i)
NEXT
PRINT " ubound(Pete) is still ="; UBOUND(Pete)
Pete(15) = 101
PRINT: PRINT " Pete(15) ="; Pete(15)
Note: This routine will error out unless we Re-initialize the Pete array.
Code: (Select All)
REDIM Pete(1 TO 20) AS INTEGER ' REDIM makes Pete a DYNAMIC array.
FOR i = 1 TO 20
Pete(i) = -i
NEXT
FOR i = 1 TO UBOUND(Pete)
PRINT Pete(i)
NEXT
SLEEP
ERASE Pete
' This will error out unless we do a REDIM Pete(1 TO 20) here.
CLS
FOR i = 1 TO 20
PRINT Pete(i)
NEXT
PRINT " ubound(Pete) is still ="; UBOUND(Pete)
Pete(15) = 101
PRINT: PRINT " Pete(15) ="; Pete(15)
So ERASE appears to have more value and versatility when used with STATIC arrays, if you consider not de-initialing your array as a benefit.
And what makes an array either static or dynamic? Well...
DIM makes the array static.
REDIM makes the array dynamic
And this important note...
REM $DYNAMIC makes ALL arrays dynamic. So even...
Code: (Select All)
REM $DYNAMIC
DIM Pete(1 to 20)
ERASE Pete
REDIM Pete(1 to 20)
...makes the otherwise static DIM array, of Pete, dynamic. So if you use REM $DYNAMIC at the top of your code, use REDIM because a DIM statement after an ERASE statement won't work with REM DYNAMIC in your code.
REM $STATIC makes ALL arrays static. but...
Code: (Select All)
REM $STATIC
REDIM Pete(1 to 20) ' Change to DIM to get this to work.
ERASE Pete
PRINT Pete(15) ' Errors out because even though we used REM $STATIC REDIM messed it up.
So we've kicked the tires quite a bit here. Anyone want to add anything more?