'===========================================================================
' Subject: CATHEDRAL SCREEN-TEASER            Date: 01-15-98 (23:30)       
'  Author: David A. Wicker                    Code: QB, QBasic, PDS        
'  Origin: pyramax@fastlane.net             Packet: EGAVGA.ABC
'===========================================================================
DEFINT A-Z
'$DYNAMIC
' Cathedral Stained-Glass Window Screen-Teaser >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
' Written by David A. Wicker
' pyramax@fastlane.net
' http://www.fastlane.net/~pyramax
' ---------------------------------------------------------------------------
' As always, if you borrow anything from any source code for your
' shareware projects, please give credit to the original author!
' ---------------------------------------------------------------------------

' DEFINT A-Z and '$DYNAMIC as the first two lines of every QBasic program
' ensure maximum speed and maximum memory capability.
' They are chiseled in every single program I write.

DECLARE SUB Center (A, A$)
DECLARE SUB TR (T$)
' QBasic is a curious creature.  It will insert these declarations
' automatically.  If you are not using the percent keystroke % anywhere
' in your source code, use:
' ALT-S C % ALT-C   to erase all occurances of % in your source code,
' then use shift arrow keystrokes to highlight the DEFINT A-Z and
' '$DYNAMIC to scoot it up to the top with Cut and Paste.  Do you use the
' mouse ?  I never do.  Use SHIFT-DEL and SHIFT-INS to both cut and paste.

  DEF FNC$ (A$, A) = MID$(A$, A, 1)
' QBasic never came with a really big set of commands for string handling,
' so I developed most of my own with the easy-to-use DEFine FuNction command.
' In this case, it plucks out a single character from A$ at position A.
' Saves me keystrokes, yep, I'm lazy at times.  :)

A$(0) = "Cathedral v0.3 ù (C) 1998+ David A. Wicker"
' You can insert special keystrokes like that raised dot above there.
' Hold down the ALT key and without releasing it, tap ONLY on the
' numbered keypad, 2 5 4 .  You will create a little square.
' Refer to your ASCII character codes available in QBasic help for a full
' listing.  This can be dangerous for source code if misused, CTRL-P and
' any keystroke will insert that keystroke direct in your sourcecode,
' anything from backspace to hidden characters.  Always save your
' sourcecode in ASCII.  QBasic 4.5 does have a nasty habit of inserting
' something indigestible in your sourcecode through too many INP or OUTs
' and you will lose your source code if it is saved in the fast LOAD/SAVE
' format.  It also makes printing it out later impossible.
'
' Saving in ASCII ensures that for whatever reason, if your sourcecode
' cannot be read in QBasic, you can bring it up under a text editor and
' manually take out the part that is causing it trouble.

A$(1) = "You like ?  Please send a postcard to let me know !"
A$(2) = "3436 Clayton Road East ù Fort Worth, Texas ù 76116"
' Please!  A postcard would be nice, or even an Email message letting me know you
' learned a little something from this source.  :)

FOR I = 0 TO 2
  FOR J = 1 TO LEN(A$(I))
    A = A + ASC(FNC$(A$(I), J))
  NEXT
NEXT

WHILE A <> 11954: WEND
' I originally used this as a checksum to ensure no-one tampered with my
' .EXE when I released it years ago.  I'm still pretty paranoid but not at
' the level I used to be.  :)

  Splice = 9
' Change this value to get some interesting effects:
' I.E.: 1, 2, 9, or 100

  RANDOMIZE TIMER
' Any calls to RND or RND(1) will always have the same "random" values
' everytime you run your code unless you include this.  You can "seed" random
' values too.  Can anyone think of how to make a good encryptor with this?
' I used to protect files this way with the seed # being long integer.

  DEF FNR (A) = INT(RND * A)
' Use DEFine FuNctions like this one to create your own shortcuts to
' computations!  For all the years I've used this, since all my variables are
' defined as integers from the DEFINT A-Z, I have always insisted on using:
' INT(RND*A)    instead of:
' RND*A
' The results are the same, but it doesn't feel right in my head.  :)

Again:
 
  SCREEN 9
  ' Resolution 640x350x16, the pixels are really flat and nice looking.
  ' Does =ANYBODY= use screen 2 today ?  Eyyech!

  LINE (0, 0)-(639, 349), 0, BF
  K$ = ""

  X& = FNR(640) * 100&
  Y& = FNR(350) * 100&
' Math time!  If you are =EVER= going to use a long integer that you know
' will get bigger than 32767, you have probably hit the dreaded:
' OVERFLOW error.  Just like Pascal programming, you need to ensure all the
' variables inside know what type they are.  I.E.:

' A=32767
' B&=A+1000

' OVERFLOW will rear its ugly head in this case.  Convert it to:
' B&=A+1000&

' And then it will work fine.
' If there are no constant numbers, make the last item in the entry
' +0& for long integer, +0# for real, etc.
' You could go to the top and say: DEFLNG A-Z or DEFSNG A-Z, (which is
' actually the default, but then your program speed will be cut in half or
' worse.  Stick with 16 bit integer.  It's worth it in the long run.

' Using FNR we've just gotten random values!
' What other FuNctions can you think of making with this ?

  N = 1000
  Z = 0

  TT! = TIMER
' Timer is a REAL variable, you can check for it up to 100ths of a second
' If you put DEFINT A-Z in front of all your source codes,
' they will run considerably faster, and if you need non small integer
' numbers, use ! for Real, & for Long Integer, and $ for strings,
' but you knew that.  :)

  DO
    K$ = UCASE$(INKEY$)
' Use UCASE$ to turn any string of any kind all uppercase, you should
' =NEVER= have to use OUT and POKE to force someone's CAP-LOCK or NUM-LOCK
' on.  It's not only rude, it can get stuck backwards with it being lit and
' it acts like it's off.

    IF K$ = "E" OR TIMER - TT! > 30 OR TIMER < TT! THEN GOTO Again
' After 30 seconds, or if "E" is pressed, clear the screen and start a new
' picture.  Lowercase "e" acceptable too, via our UCASE$ from above.

    IF Z MOD 10 = 0 THEN WHILE TIMER - TT2! < .01: WEND: TT2! = TIMER
' Every 10 cycles, a hundredth of a second will pause

    IF K$ = "P" THEN NotActive = 1 - NotActive: K$ = ""
' Pause if we really want to

    Z = Z + 1
    IF Z = 32767 THEN Z = 0
    IF Z MOD N > N \ 2 THEN C = (C + 1) MOD 16
    COLOR C
    IF NotActive = 0 THEN
      X = X& \ 100
      Y = Y& \ 100
' the forward / is to receive decimal divison, the backward slash is for
' integer division, it is considerably faster and since we know our results
' will be integer, we use the backslash every time.

      PSET (X, Y)
      PSET (640 - X, Y)
      PSET (X, 350 - Y)
      PSET (640 - X, 350 - Y)
    END IF

    X& = (63900 + FNR(1000) - X&) - ABS(Y& - 100) / Splice * 3
    Y& = (34900 + FNR(1000) - Y&) - ABS(X& - 100) / Splice
' Swing our pixels around like a tornado in a paintbucket!
' Notice these values are *100.  Integer math will always be faster than
' floating point math.  They have the accuracy of up to two decimal places
' because I divide by 100 when I plot them.
' If they were only 639 and 349, the stained-glass window would not look as
' pretty.

    IF X& < 0 THEN X& = X& + 64000
    IF Y& < 0 THEN Y& = Y& + 48000
    IF X& > 63900 THEN X& = X& - 64000
    IF Y& > 34900 THEN Y& = Y& - 35000
' Flip our plotter to opposite end of screen if it goes too far.
' Always try to monkey-proof your software.  Just because you are asking
' someone who runs your software for a particular input, file, or event,
' doesn't necessarily mean they will follow the rules.  I never do.  :)

  LOOP UNTIL K$ > ""

SCREEN 0, 1, 0, 0
WIDTH 80
COLOR 7, 0
CLS
PRINT STRING$(80, " ");
' Some strange versions of Win95 put a blue bar at the top of a text screen
' when you leave graphics.  Mine doesn't, but yours may.  I only included it
' here because I originally wrote this on a Win95 platform computer that
' had it.  It is also the platform I lost the source code to my
' Internet Backdrop generator.  I still have the .EXE but the source is gone.
' My boss wiped it accidentally.  :/

LOCATE 10
' Many commands can use abbreviated arguments in QBasic.
' LOCATE 10 will put the cursor at the VERTICAL 10th position.
' LOCATE,10 will put the cursor at the HORIZONTAL 10th position.
' In both cases, for vertical, the horizontal is unaffected, and vice-versa.
' This abbreviation also applies to the SCREEN command.  Tap F1 on the
' word SCREEN to see available options.  Why do I use QBasic above all other
' languages ?  It's built-in help is the best I've seen, period.
' Also I'm a stick-in-the-mud for running my program every 5 minutes to see
' what little changes I've done affected it.  :)
' Tap CTRL-F1 to bring up the last help you were looking at.

Center 1, A$(0)
Center 5, A$(1)
Center 4, A$(2)
' Example of calling a SUBPROGRAM, parentheses and CALL are not needed for
' the arguments.  Naturally, if you are calling a single SUBPROGRAM with
' no arguments and you use the ":" to separate it from another command on the
' same line, QBasic will get confused and think it is a marker label for
' GOTO and GOSUB.  Try to avoid the ":" as much as possible.  It's a bad
' habit.
' Save your keystrokes.  :)

COLOR 7
LOCATE 23

TT! = TIMER: WHILE TIMER - TT! < 1 AND TIMER >= TT!: WEND
' I learned about using TIMER to delay or pause execution from the WormHole
' QB demo.  I gave credit for them in Treasure Hunter in the credits listing.
' :)
' Always use TIMER for loops, and yes, you can pause for tenths of a second
' too.  if you use FOR I= to / NEXT loops, just because your computer runs
' at a good speed by "fudging" the numbers, there is no way it can run the
' exact same speed on anyone else's computer.
' I am forever inserting the TIMER routine into some of the very good games
' that have been received into William Yu's ABC packets by others in QBasic
' but the programmer did not foresee a pentium attempting to run them.
' By the time I blink the game is over.  :)

DO: LOOP UNTIL INKEY$ = ""
DO: LOOP UNTIL INKEY$ > ""
' There is no way that a keystroke can be less than nothing, so you do not
' need <>, save yourself a keystroke, I always do.  :)

' Tap F2 at this point to see the subprograms.  If you've never used
' Subprograms before, you really should learn them!  They make managing code
' a lot easier and are much more powerful than GOSUB or GOTO.

REM $STATIC
SUB Center (A, A$) : SHARED ColFlip
' using SHARED inside a SUB makes it global to your entire program and it
' will not get erased once you exit the subprogram, all variables are
' initialized to zero (0) when you first run a program, so I use that as a
' starting point for my variable flags before they are set to another value.
 
  LOCATE , 40 - LEN(A$) \ 2
  ColFlip = A
  TR A$
  PRINT
  PRINT
END SUB

SUB RGB (N, R, G, B)
' Original Author: Unknown!  I "earned" learning this over the internet
' chatting with someone.  I traded it for the source code to a QBasic fill
' any graphic region routine that used PSET only.  If there is a need for
' this today, I'll release that source too.  Huzzah!  =NEVER= use PALETTE!
' Although PALETTE may run fine and well on your computer, on others, it
' takes better than 4 seconds to only change 256 colors!
' Pentium computer notwithstanding!

  OUT &H3C8, N
  OUT &H3C9, R
  OUT &H3C9, G
  OUT &H3C9, B
END SUB

SUB TR (T$) : SHARED ColFlip
' TR to me means TRANSMIT.  It is a carry-over when I wrote BBSs years ago.
' Ever consider writing your own fancy PRINT routines ?  As long as they are
' strings, you can make your own this exact same way!  Be creative and set it
' so special unusual characters like @ or ^ do curious things to the string
' being sent through, not just for color, but for typeface, appearance,
' location, speed of display, audio, etc.

' Back on the Apple ][+ when I wrote Orbs of Ankhar, I used CTRL-E for a
' click sound, CTRL-F for a fighting sound (clash), and CTRL-G for a quick
' warble up.  Richard Garriot used a CTRL-G TSR when he wrote Ultima I years
' ago on the Apple ][+, and yes, I had a chance to talk to him over the phone
' years ago when he was starting out.  :)

  FOR I = 1 TO LEN(T$)

    C$ = FNC$(T$, I)
' Remember, this is our nifty little nick out a single character function
' defined in the beginning of the source.

    IF C$ = "`" THEN C$ = CHR$(34)
' This was not used in this program, but as you know, or should, you cannot
' insert a quote key inside a print statement.  I.E.:
' Print"She said, "Hello There!" --> Will not work.
' You'll get back.
' She said,   0   0
' So, since we're using a fancy text-displayer, whenever it sees the seldom
' used "`" key, it converts it to print out CHR$(34).
' DATA statements balk at using the comma "," as part of a string unless you
' have an opening quote first:
' DATA "Bread,Milk,Eggs","Cedar,Redwood,Birch"

    IF C$ < "A" OR I = 1 THEN COLOR ColFlip + 8
' Another example of an abbreviated argument:
' COLOR,5 would change only the background to 5 leaving the foreground
' untouched.

    PRINT C$;
    IF C$ <> " " THEN COLOR ColFlip
  NEXT

' Before I close, I would like to emphasize the overuse of line numbers that
' are still apparent in today's QBasic source codes.  People, they are not
' needed!  It is far easier to write code like this than to break it all down
' to line #'s.  Force yourself to learn it because GWBASIC is as old as the
' Pet Rock and just as useful.  :)  Usage of the colon ":" in codes to pack
' more than one statement to a line should really be a big no no as well,
' especially if it forces the single line to span greater than 80 characters
' across so the source code has to be shifted all to the right to read it.
' Use IF THEN {insert the body of what occurs} and ENDIF on multiple lines,
' please.

' One Final Thing, if you turn off the TAB setting under (O)ptions,
' (D)isplay, you can hit spacebar twice to indent clean code and not have it
' jump 8 characters to the right.  Better to have a small indentation than
' one that forces programming lines greater than 80 characters across.
'
' Also, please EMail me if you know the POKE or OUT command to convert the
' FLASHING state in regular 80x25 text to be the high-bit color background,
' like the Quickbasic editor does when you select (O)ptions and (D)isplay.
' Notice how you can set the background to greater than color #7 and it
' displays it like it should.  No-one I know uses the flash in text anymore,
' so I don't want to have the flash in my text-handling library.

' pyramax@fastlane.net

END SUB
