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

Username/Email:
  

Password
  





Search Forums

(Advanced Search)

Forum Statistics
» Members: 326
» Latest member: hafsahomar
» Forum threads: 1,758
» Forum posts: 17,919

Full Statistics

Latest Threads
MBA Assignment Help in Du...
Forum: General Discussion
Last Post: hafsahomar
06-11-2025, 07:05 AM
» Replies: 0
» Views: 12
лучшие песни медляки слуш...
Forum: Petr
Last Post: WillieTop
06-08-2025, 02:21 AM
» Replies: 0
» Views: 25
пинк слушать онлайн беспл...
Forum: SMcNeill
Last Post: WillieTop
06-08-2025, 02:20 AM
» Replies: 0
» Views: 22
скачать музыку российскую...
Forum: madscijr
Last Post: WillieTop
06-08-2025, 02:18 AM
» Replies: 0
» Views: 23
нежная музыка mp3 скачать
Forum: Keybone
Last Post: WillieTop
06-08-2025, 02:17 AM
» Replies: 0
» Views: 22
лучшая песня слушать онла...
Forum: bplus
Last Post: WillieTop
06-08-2025, 02:16 AM
» Replies: 0
» Views: 25
пикник слушать онлайн луч...
Forum: Spriggsy
Last Post: WillieTop
06-08-2025, 02:15 AM
» Replies: 0
» Views: 22
какая сейчас популярная м...
Forum: RhoSigma
Last Post: WillieTop
06-08-2025, 02:14 AM
» Replies: 0
» Views: 18
хит лета 2019 музыка на т...
Forum: Christmas Code
Last Post: WillieTop
06-08-2025, 02:12 AM
» Replies: 0
» Views: 26
бесплатная музыка mp3 рег...
Forum: Works in Progress
Last Post: WillieTop
06-08-2025, 02:11 AM
» Replies: 0
» Views: 18

 
  Announcing QB64 Phoenix Edition v0.5 Release!
Posted by: admin - 04-28-2022, 03:45 AM - Forum: Announcements - Replies (7)

Release v0.5.0 · QB64-Phoenix-Edition/QB64pe (github.com)

Another step forward in making our first version "1.0" as the new team working on QB64. This release (version 0.5) now:

  • Has swapped out the mingw compilers to updated versions for Windows users.
  • Reduced the size of the repo considerably for those who wish to download direct and setup QB64 manually, for whatever reason.
  • Prepacked Linux and max versions of QB64, which come in at less than 10MB each now.
  • We've swapped out all the references to the now defunct .net and .org sites that we could find, and replaced them to proper, working links which now connect to our new wiki, forum, and all at qb64phoenix.com.
  • $Color:0 and $Color:32 has now been tweaked to work with $NoPrefix. Color names will remain the same in all cases, if $Color is used without $NoPrefix. When $Color is used in conjunction with $NoPrefix, the colors of Red, Green, and Blue which would normally conflict with the now underscoreless commands of _Red, _Green, _Blue, have been altered to have NP_appended to them (for No Prefix). Example: Color NP_Red, Orange for a red on orange color.


Click on the big title above to go directly to the release page and grab yourself a copy of the latest version for all your QB64 needs!

Print this item

  LSTYLES.BAS
Posted by: TarotRedhand - 04-28-2022, 12:09 AM - Forum: Programs - Replies (5)

Here's a little something I wrote and posted on FidoNet back in 1997. It's just an illustration of some of the styles of line that you can have when you use the LINE command. If nothing else grab one or more of the included constants at the top of the code. When run you will get a small window that shows the linestyles (maybe too small for anything larger than full HD).


Code: (Select All)
'===========================================================================
' Subject: DIFFERENT LINE STYLES              Date: 12-22-97 (12:06)
'  Author: TarotRedhand                      Code: QB
'===========================================================================
'Just for a change I am posting a small program that illustrates what
'is probably an underused parameter of a well known command, LINE.  If
'you check out either the manual or the help system, you will see that
'the final (optional) parameter that can be passed to the LINE
'statement is one called linestyle.  In order to show what this
'parameter can produce when properly used here are 13 (12a? <g>)
'constants, for you to use, that are part of the following small
'program.

CONST DenseDotted% = &HAAAA            '| "- - - - - - - - "
CONST MediumDotted% = &H8888          '| "-  -  -  -  "
CONST SparseDotted% = &H8080          '| "-      -      "
CONST OneDot% = &H80                  '| "        -      "
CONST LongDash% = &HFFFC              '| "--------------  "
CONST MediumDash% = &HFCFC            '| "------  ------  "
CONST ShortDash% = &HDDDD              '| "--- --- --- --- "
CONST WideGapped% = &HF0F0            '| "----    ----    "
CONST SparseDash% = &HCCCC            '| "--  --  --  --  "
CONST LongShort% = &HFDBF              '| "------ -- ------"
CONST DashDot% = &HFAFA                '| "----- - ----- - "
CONST DotDashDot% = &H9FE4            '| "-  --------  -  "
CONST SixThreeOne% = &HFCE4            '| "------  ---  -  "

SCREEN 1
COLOR 8, 1
MyY% = 7
Gap% = 14
MyColour% = 3
X1% = 15
X2% = 302
LINE (X1%, MyY%)-(X2%, MyY%), MyColour%
MyY% = MyY% + Gap%
LINE (X1%, MyY%)-(X2%, MyY%), MyColour%, , DenseDotted%
MyY% = MyY% + Gap%
LINE (X1%, MyY%)-(X2%, MyY%), MyColour%, , MediumDotted%
MyY% = MyY% + Gap%
LINE (X1%, MyY%)-(X2%, MyY%), MyColour%, , SparseDotted%
MyY% = MyY% + Gap%
LINE (X1%, MyY%)-(X2%, MyY%), MyColour%, , OneDot%
MyY% = MyY% + Gap%
LINE (X1%, MyY%)-(X2%, MyY%), MyColour%, , LongDash%
MyY% = MyY% + Gap%
LINE (X1%, MyY%)-(X2%, MyY%), MyColour%, , MediumDash%
MyY% = MyY% + Gap%
LINE (X1%, MyY%)-(X2%, MyY%), MyColour%, , ShortDash%
MyY% = MyY% + Gap%
LINE (X1%, MyY%)-(X2%, MyY%), MyColour%, , WideGapped%
MyY% = MyY% + Gap%
LINE (X1%, MyY%)-(X2%, MyY%), MyColour%, , SparseDash%
MyY% = MyY% + Gap%
LINE (X1%, MyY%)-(X2%, MyY%), MyColour%, , LongShort%
MyY% = MyY% + Gap%
LINE (X1%, MyY%)-(X2%, MyY%), MyColour%, , DashDot%
MyY% = MyY% + Gap%
LINE (X1%, MyY%)-(X2%, MyY%), MyColour%, , DotDashDot%
MyY% = MyY% + Gap%
LINE (X1%, MyY%)-(X2%, MyY%), MyColour%, , SixThreeOne%
Q$ = INPUT$(1)
END

Enjoy.

TR

Print this item

  Air Hockey
Posted by: bplus - 04-27-2022, 11:53 PM - Forum: bplus - Replies (18)

Back by popular demand! Smile 

Air Hockey, choose between light and dark versions. I think I like dark more let's see:

[Image: AH-Light.png]    




Zip contains 2 bas source file, 2 Windows exe's and an Arial font file for those that don't have it.



Attached Files
.zip   Air Hockey Light and Dark.zip (Size: 2.63 MB / Downloads: 82)
Print this item

  I was bored so I made this.
Posted by: Keybone - 04-27-2022, 10:14 PM - Forum: Works in Progress - No Replies

This is a dynamic array that resizes itself as you add to or remove from it.
each entry has 2 properties: whichType and Content.
whichType tells what kind of variable is stored, and Content is what the variable contains.
whichType is a _byte and content is always a string. variables are converted to/from strings by the subs/functions.
here is the code, maybe it might be useful:

Code: (Select All)
Option _Explicit

Type Limits
    Minimum As _Byte
    Maximum As _Unsigned _Integer64
    Current As _Unsigned _Integer64
End Type

Type Entry 'global array
    whichType As _Byte
    Content As String
End Type

Dim Shared theLimit As Limits
ReDim Shared theBase(theLimit.Minimum) As Entry
'
theLimit.Minimum = 0
theLimit.Maximum = 0 - 1
'
theLimit.Current = theLimit.Minimum

' End Declarations

Dim test1%%
Dim test2&&
Dim test3~&&
Dim test4##
Dim test5$

add_byte 54
test1%% = get_byte(theLimit.Current)
Print test1%%

add_int 1444443893487
test2&& = get_int(theLimit.Current)
Print test2&&

add_uint 45989379879387398734987
test3~&& = get_uint(theLimit.Current)
Print test3~&&

add_float 80982.39802
test4## = get_float(theLimit.Current)
Print test4##

add_str "boom!"
test5$ = get_str(theLimit.Current)
Print test5$


' Begin modules

Function trim$ (theInput As String)
    trim = LTrim$(RTrim$(theInput))
End Function

Sub add_byte (theInput As _Byte)
    add_Item
    theBase(theLimit.Current).Content = trim$(Chr$(theInput))
    theBase(theLimit.Current).whichType = 1
End Sub

Sub add_int (theInput As _Integer64)
    add_Item
    theBase(theLimit.Current).Content = trim$(_MK$(_Integer64, theInput))
    theBase(theLimit.Current).whichType = 2
End Sub

Sub add_uint (theInput As _Unsigned _Integer64)
    add_Item
    theBase(theLimit.Current).Content = trim$(_MK$(_Unsigned _Integer64, theInput))
    theBase(theLimit.Current).whichType = 3
End Sub

Sub add_float (theInput As _Float)
    add_Item
    theBase(theLimit.Current).Content = trim$(_MK$(_Float, theInput))
    theBase(theLimit.Current).whichType = 5
End Sub

Sub add_str (theInput As String)
    add_Item
    theBase(theLimit.Current).Content = trim$(theInput)
    theBase(theLimit.Current).whichType = 7
End Sub

Sub add_Item
    theLimit.Current = theLimit.Current + 1
    ReDim _Preserve theBase(theLimit.Current) As Entry
End Sub

Function get_byte%% (Selector As _Unsigned _Integer64)
    get_byte = Asc(theBase(Selector).Content)
End Function

Function get_int&& (Selector As _Unsigned _Integer64)
    get_int = _CV(_Integer64, theBase(Selector).Content)
End Function

Function get_uint~&& (Selector As _Unsigned _Integer64)
    get_uint = _CV(_Unsigned _Integer64, theBase(Selector).Content)
End Function

Function get_float## (Selector As _Unsigned _Integer64)
    get_float = _CV(_Float, theBase(Selector).Content)
End Function

Function get_str$ (Selector As _Unsigned _Integer64)
    get_str = trim$(theBase(Selector).Content)
End Function

Sub rm_byte (Selector As _Unsigned _Integer64)
    theBase(Selector).whichType = 0
    theBase(Selector).Content = ""
    Dim rm_global_B_inc
    For rm_global_B_inc = Selector To theLimit.Current - 1
        theBase(rm_global_B_inc).whichType = theBase(rm_global_B_inc + 1).whichType
        theBase(rm_global_B_inc).Content = theBase(rm_global_B_inc + 1).Content
    Next rm_global_B_inc
    rm_Item
End Sub

Sub rm_int (Selector As _Unsigned _Integer64)
    theBase(Selector).whichType = 0
    theBase(Selector).Content = ""
    Dim rm_global_I_inc
    For rm_global_I_inc = Selector To theLimit.Current - 1
        theBase(rm_global_I_inc).whichType = theBase(rm_global_I_inc + 1).whichType
        theBase(rm_global_I_inc).Content = theBase(rm_global_I_inc + 1).Content
    Next rm_global_I_inc
    rm_Item
End Sub

Sub rm_uint (Selector As _Unsigned _Integer64)
    theBase(Selector).whichType = 0
    theBase(Selector).Content = ""
    Dim rm_global_UI_inc
    For rm_global_UI_inc = Selector To theLimit.Current - 1
        theBase(rm_global_UI_inc).whichType = theBase(rm_global_UI_inc + 1).whichType
        theBase(rm_global_UI_inc).Content = theBase(rm_global_UI_inc + 1).Content
    Next rm_global_UI_inc
    rm_Item
End Sub

Sub rm_float (Selector As _Unsigned _Integer64)
    theBase(Selector).whichType = 0
    theBase(Selector).Content = ""
    Dim rm_global_F_inc
    For rm_global_F_inc = Selector To theLimit.Current - 1
        theBase(rm_global_F_inc).whichType = theBase(rm_global_F_inc + 1).whichType
        theBase(rm_global_F_inc).Content = theBase(rm_global_F_inc + 1).Content
    Next rm_global_F_inc
    rm_Item
End Sub

Sub rm_str (Selector As _Unsigned _Integer64)
    theBase(Selector).whichType = 0
    theBase(Selector).Content = ""
    Dim rm_global_S_inc
    For rm_global_S_inc = Selector To theLimit.Current - 1
        theBase(rm_global_S_inc).whichType = theBase(rm_global_S_inc + 1).whichType
        theBase(rm_global_S_inc).Content = theBase(rm_global_S_inc + 1).Content
    Next rm_global_S_inc
    rm_Item
End Sub

Sub rm_Item
    theLimit.Current = theLimit.Current - 1
    ReDim _Preserve theBase(theLimit.Current) As Entry
End Sub

Print this item

  Steve's Ole Dice Roller
Posted by: SMcNeill - 04-27-2022, 09:14 PM - Forum: SMcNeill - No Replies

Code: (Select All)
SCREEN _NEWIMAGE(1024, 720, 32)
_SCREENMOVE _MIDDLE

CONST DiagRollEm = -1

'The next lines are only needed for manual testing
DIM DiceToRoll AS DiceRoller_Type
DIM SHARED Brief AS LONG

'Feel free to change options as wanted for your program
'DiceToRoll.NumberOfDice = 2
'DiceToRoll.DiceSides = 10
'DiceToRoll.DiceReroll = "=1"
'DiceToRoll.DiceOpenRoll = "=10"
'DiceToRoll.DiceMod = 2
'DiceToRoll.DiceKeepHigh = 1
'DiceToRoll.DiceKeepLow = 1

'DiceToRoll.Set = 10
'DiceToRoll.SetMod = 1
'DiceToRoll.SetReRoll = "<6"
'DiceToRoll.SetOpenRoll = ">10"
'DiceToRoll.TotalMod = 27

'DiceToRoll.SetKeepHigh = 9


PRINT RollEm$("10skh9r2;2d10o20;t2;b2")

PRINT
PRINT "PRESS <ANY KEY> TO CONTINUE"
SLEEP
PRINT

ClearDice
DiceToRoll.Set = 6
DiceToRoll.NumberOfDice = 4
DiceToRoll.DiceSides = 6
DiceToRoll.DiceKeepHigh = 3


Brief = 0
PRINT "NON-BRIEF OUTPUT:"
PRINT "'6s; 4d6 kh3' -- Roll 6 sets of 4 six-sided dice, keep the three highest"
PRINT DiceRoll$
PRINT
PRINT "PRESS <ANY KEY> TO CONTINUE"
SLEEP
PRINT

Brief = 1
PRINT "SEMI-BRIEF OUTPUT:"
PRINT "'6s; 4d6 kh3' -- Roll 6 sets of 4 six-sided dice, keep the three highest"
PRINT DiceRoll$
PRINT
PRINT "PRESS <ANY KEY> TO CONTINUE"
SLEEP
PRINT

Brief = 2
PRINT "MOST BRIEF OUTPUT:"
PRINT "'6s; 4d6 kh3' -- Roll 6 sets of 4 six-sided dice, keep the three highest"
PRINT DiceRoll$
PRINT
PRINT "PRESS <ANY KEY> TO CONTINUE"
SLEEP
PRINT







TYPE DiceRoller_Type
    Set AS LONG
    SetMod AS LONG
    SetReRoll AS STRING * 100
    SetOpenRoll AS STRING * 100
    SetKeepHigh AS LONG
    SetKeepLow AS LONG
    SetDiscardHigh AS LONG
    SetDiscardLow AS LONG

    NumberOfDice AS LONG
    DiceSides AS LONG
    DiceMod AS LONG
    DiceReroll AS STRING * 100
    DiceOpenRoll AS STRING * 100
    DiceKeepHigh AS LONG
    DiceKeepLow AS LONG
    DiceDiscardHigh AS LONG
    DiceDiscardLow AS LONG

    TotalMod AS LONG
END TYPE

SUB StripNumber (m$)
    v = VAL(m$)
    DO UNTIL v = 0
        'PRINT "Stripping number"; m$
        m$ = MID$(m$, 2)
        v = VAL(m$)
    LOOP
    DO UNTIL LEFT$(m$, 1) <> "0" 'strip any zeros
        m$ = MID$(m$, 2)
    LOOP
END SUB


SUB ClearDice
    SHARED DiceToRoll AS DiceRoller_Type
    DiceToRoll.Set = 0
    DiceToRoll.SetMod = 0
    DiceToRoll.SetReRoll = ""
    DiceToRoll.NumberOfDice = 0
    DiceToRoll.DiceSides = 0
    DiceToRoll.DiceMod = 0
    DiceToRoll.DiceReroll = ""
    DiceToRoll.DiceOpenRoll = ""
    DiceToRoll.DiceKeepHigh = 0
    DiceToRoll.DiceKeepLow = 0
    DiceToRoll.DiceDiscardHigh = 0
    DiceToRoll.DiceDiscardLow = 0
    DiceToRoll.TotalMod = 0
END SUB

FUNCTION DiceRoll$
    SHARED Brief AS LONG
    SHARED DiceToRoll AS DiceRoller_Type
    IF DiceToRoll.DiceKeepHigh OR DiceToRoll.DiceKeepLow THEN
        IF DiceToRoll.DiceDiscardHigh OR DiceToRoll.DiceDiscardLow THEN DiceRoll$ = "Error - Can not keep and discard at the same time.": EXIT FUNCTION
    END IF
    IF DiceToRoll.NumberOfDice < 1 THEN DiceRoll$ = "Error - No dice to roll!": EXIT FUNCTION


    RANDOMIZE TIMER
    SHARED DiceToRoll AS DiceRoller_Type
    REDIM rolls(0) AS LONG
    REDIM SetRolls(0) AS LONG
    SetCount = 0
    IF Brief = 2 THEN out$ = "("
    FOR j = 1 TO DiceToRoll.Set
        ReRollSet:
        SetTotal = 0
        IF Brief = 0 THEN
            out$ = out$ + "RAW: ("
        ELSEIF Brief = 1 THEN
            out$ = out$ + "("
        END IF

        rollcount = -1
        FOR i = 1 TO DiceToRoll.NumberOfDice
            ReRollDice:
            roll = INT(RND(1) * DiceToRoll.DiceSides) + 1

            IF ParseDiceOption(roll, DiceToRoll.DiceReroll) THEN
                DiceOK = 0
                IF Brief = 0 THEN out$ = out$ + "r" + _TRIM$(STR$(roll)) + ", "
                GOTO ReRollDice
            END IF
            IF ParseDiceOption(roll, DiceToRoll.DiceOpenRoll) THEN
                DiceOK = 0
                DiceTotal = DiceTotal + roll + DiceToRoll.DiceMod
                IF Brief = 0 THEN
                    out$ = out$ + _TRIM$(STR$(roll)) + "o"
                    IF DiceToRoll.DiceMod THEN out$ = out$ + " + " + _TRIM$(STR$(DiceToRoll.DiceMod))
                    out$ = out$ + ","
                END IF
                rollcount = rollcount + 1
                REDIM _PRESERVE rolls(rollcount) AS LONG 'make certain we dont get out of bound errors for crazy reroll scenarios
                rolls(rollcount) = roll + DiceToRoll.DiceMod
                GOTO ReRollDice
            END IF

            rollcount = rollcount + 1
            REDIM _PRESERVE rolls(rollcount) AS LONG 'make certain we dont get out of bound errors for crazy reroll scenarios
            rolls(rollcount) = roll + DiceToRoll.DiceMod
            DiceTotal = DiceTotal + roll + DiceToRoll.DiceMod
            IF Brief = 0 THEN
                out$ = out$ + _TRIM$(STR$(roll))
                IF DiceToRoll.DiceMod THEN out$ = out$ + " + " + _TRIM$(STR$(DiceToRoll.DiceMod))
                IF i < DiceToRoll.NumberOfDice THEN 'more dice to roll in this set
                    out$ = out$ + ", "
                ELSE 'we're finished
                    out$ = out$ + ")"
                END IF
            END IF
        NEXT

        IF rollcount > 0 THEN Sort rolls() 'No need to try and sort only 1 dice.

        IF Brief = 0 THEN
            out$ = out$ + "; SORTED: ("
            FOR i = 0 TO rollcount
                out$ = out$ + _TRIM$(STR$(rolls(i)))
                IF i < rollcount THEN out$ = out$ + ", " ELSE out$ = out$ + ")"
            NEXT
        END IF

        REDIM keep(rollcount) AS LONG
        IF DiceToRoll.DiceKeepHigh OR DiceToRoll.DiceKeepLow THEN
            IF DiceToRoll.DiceKeepHigh THEN
                FOR i = DiceToRoll.DiceKeepHigh - 1 TO 0 STEP -1
                    IF i < rollcount THEN keep(rollcount - i) = -1
                NEXT
            END IF
            IF DiceToRoll.DiceKeepLow THEN
                FOR i = 0 TO DiceToRoll.DiceKeepLow - 1
                    IF i < rollcount THEN keep(i) = -1
                NEXT
            END IF
        ELSEIF DiceToRoll.DiceDiscardHigh OR DiceToRoll.DiceDiscardLow THEN
            FOR i = 0 TO rollcount
                keep(i) = -1
            NEXT
            IF DiceToRoll.DiceDiscardHigh THEN
                FOR i = DiceToRoll.DiceDiscardHigh - 1 TO 0 STEP -1
                    IF i < rollcount THEN keep(rollcount - i) = 0
                NEXT
            END IF
            IF DiceToRoll.DiceDiscardLow THEN
                FOR i = 0 TO DiceToRoll.DiceDiscardLow - 1
                    IF i < rollcount THEN keep(i) = 0
                NEXT
            END IF
        ELSE
            FOR i = 0 TO rollcount
                keep(i) = -1
            NEXT
        END IF

        IF Brief = 0 THEN out$ = out$ + "; KEEP: ("
        KeepTotal = 0
        kept = 0
        FOR i = 0 TO rollcount
            IF keep(i) THEN
                kept = kept + 1
                IF Brief < 2 THEN
                    IF kept > 1 THEN out$ = out$ + ", "
                    out$ = out$ + _TRIM$(STR$(rolls(i)))
                END IF
                KeepTotal = KeepTotal + rolls(i)
            END IF
        NEXT
        IF Brief < 2 THEN out$ = out$ + ") = " + _TRIM$(STR$(KeepTotal))

        IF ParseDiceOption(KeepTotal, DiceToRoll.SetReRoll) THEN
            IF Brief < 2 THEN out$ = out$ + "r" + CHR$(13)
            GOTO ReRollSet
        END IF

        IF ParseDiceOption(KeepTotal, DiceToRoll.SetOpenRoll) THEN
            SetTotal = SetTotal + KeepTotal + DiceToRoll.SetMod
            SetCount = SetCount + 1
            REDIM _PRESERVE SetRolls(SetCount) AS LONG
            SetRolls(SetCount) = SetTotal
            GrandTotal = GrandTotal + SetTotal
            IF Brief = 2 THEN out$ = out$ + _TRIM$(STR$(SetTotal))
            out$ = out$ + "o"
            IF Brief < 2 THEN
                IF DiceToRoll.SetMod THEN out$ = out$ + " + " + _TRIM$(STR$(DiceToRoll.SetMod))
                out$ = out$ + " = " + _TRIM$(STR$(SetTotal))
                out$ = out$ + CHR$(13)
            ELSE
                out$ = out$ + ", "
            END IF

            GOTO ReRollSet
        END IF

        SetTotal = SetTotal + KeepTotal + DiceToRoll.SetMod
        SetCount = SetCount + 1
        REDIM _PRESERVE SetRolls(SetCount) AS LONG
        SetRolls(SetCount) = SetTotal
        GrandTotal = GrandTotal + SetTotal

        IF Brief < 2 THEN
            IF DiceToRoll.SetMod THEN
                out$ = out$ + " + " + _TRIM$(STR$(DiceToRoll.SetMod))
                out$ = out$ + " = " + _TRIM$(STR$(SetTotal))
            END IF
            out$ = out$ + CHR$(13)
        ELSE
            out$ = out$ + _TRIM$(STR$(SetTotal))
            IF j < DiceToRoll.Set THEN out$ = out$ + ", " ELSE out$ = out$ + ")"
        END IF


    NEXT
    IF Brief < 2 THEN out$ = out$ + CHR$(13) + "GRAND TOTAL:"

    IF DiceToRoll.TotalMod THEN
        IF Brief < 2 THEN out$ = out$ + STR$(GrandTotal) + " +" + STR$(DiceToRoll.TotalMod)
    END IF

    GrandTotal = GrandTotal + DiceToRoll.TotalMod
    out$ = out$ + " =" + STR$(GrandTotal)

    Sort SetRolls()
    IF Brief = 0 THEN
        out$ = out$ + CHR$(13) + CHR$(13) + "Sorted Set: ("
        FOR i = 1 TO SetCount
            out$ = out$ + _TRIM$(STR$(SetRolls(i)))
            IF i < SetCount THEN out$ = out$ + ", " ELSE out$ = out$ + ")"
        NEXT
    END IF

    REDIM keep(SetCount) AS LONG
    IF DiceToRoll.SetKeepHigh OR DiceToRoll.SetKeepLow THEN
        IF DiceToRoll.SetKeepHigh THEN
            FOR i = DiceToRoll.SetKeepHigh - 1 TO 0 STEP -1
                IF i < SetCount THEN keep(SetCount - i) = -1
            NEXT
        END IF
        IF DiceToRoll.SetKeepLow THEN
            FOR i = 0 TO DiceToRoll.SetKeepLow - 1
                IF i < SetCount THEN keep(i) = -1
            NEXT
        END IF
    ELSEIF DiceToRoll.SetDiscardHigh OR DiceToRoll.SetDiscardLow THEN
        FOR i = 0 TO SetCount
            keep(i) = -1
        NEXT
        IF DiceToRoll.SetDiscardHigh THEN
            FOR i = DiceToRoll.SetDiscardHigh - 1 TO 0 STEP -1
                IF i < SetCount THEN keep(SetCount - i) = 0
            NEXT
        END IF
        IF DiceToRoll.SetDiscardLow THEN
            FOR i = 0 TO DiceToRoll.SetDiscardLow - 1
                IF i < SetCount THEN keep(i) = 0
            NEXT
        END IF
    ELSE
        FOR i = 0 TO SetCount
            keep(i) = -1
        NEXT
    END IF




    out$ = out$ + CHR$(13) + "Set Kept: ("
    IF Brief = 2 THEN out$ = "("
    KeepTotal = 0
    keep = 0
    FOR i = 1 TO SetCount
        IF keep(i) THEN
            keep = keep + 1
            IF keep > 1 THEN out$ = out$ + ", "
            out$ = out$ + _TRIM$(STR$(SetRolls(i)))
            KeepTotal = KeepTotal + SetRolls(i)
        END IF
    NEXT
    KeepTotal = KeepTotal + DiceToRoll.TotalMod
    out$ = out$ + ") = " + _TRIM$(STR$(KeepTotal))
    DiceRoll$ = out$
END FUNCTION


FUNCTION ParseDiceOption (num, t_temp$)
    SHARED DiceToRoll AS DiceRoller_Type
    temp$ = _TRIM$(t_temp$)
    IF temp$ = "" THEN EXIT FUNCTION
    IF RIGHT$(temp$, 1) <> "," THEN temp$ = temp$ + ","
    DO
        f = INSTR(temp$, ",")
        IF f THEN
            o$ = LEFT$(temp$, f - 1)
            temp$ = MID$(temp$, f + 1)
            o = VAL(MID$(o$, 2))
            o$ = LEFT$(o$, 1)
            SELECT CASE o$
                CASE "=": IF num = o THEN ParseDiceOption = -1: EXIT FUNCTION
                CASE "<": IF num < o THEN ParseDiceOption = -1: EXIT FUNCTION
                CASE ">": IF num > o THEN ParseDiceOption = -1: EXIT FUNCTION
            END SELECT
        END IF
    LOOP UNTIL f = 0 OR temp$ = ""
END FUNCTION

SUB Sort (Array() AS LONG)
    'The dice sorting routine, optimized to use _MEM and a comb sort algorithm.
    'It's more than fast enough for our needs here I think.  ;)
    DIM m AS _MEM
    DIM o AS _OFFSET, o1 AS _OFFSET
    DIM t AS LONG, t1 AS LONG
    m = _MEM(Array())
    $CHECKING:OFF
    gap = rollcount

    DO
        gap = 10 * gap \ 13
        IF gap < 1 THEN gap = 1
        i = 0
        swapped = 0
        DO
            o = m.OFFSET + i * 4
            o1 = m.OFFSET + (i + gap) * 4
            IF _MEMGET(m, o, LONG) > _MEMGET(m, o1, LONG) THEN
                _MEMGET m, o1, t1
                _MEMGET m, o, t
                _MEMPUT m, o1, t
                _MEMPUT m, o, t1
                swapped = -1
            END IF
            i = i + 1
        LOOP UNTIL i + gap > UBOUND(Array)
    LOOP UNTIL swapped = 0 AND gap = 1
    $CHECKING:ON
    _MEMFREE m
END SUB


FUNCTION RollEm$ (temp$)
    SHARED DiceToRoll AS DiceRoller_Type
    text1$ = UCASE$(temp$)
    FOR i = 1 TO LEN(text1$) 'check for invalid characters
        m$ = MID$(text1$, i, 1)
        SELECT CASE m$
            CASE "0" TO "9", "+", "-", "D", "K", "H", "L", "S", "T", ";", "=", "<", ">", ",", "R", "O", "B"
                text$ = text$ + m$ 'add valid characters to make text$
            CASE " " 'do nothing to a space
            CASE ELSE
                'invalid
        END SELECT
    NEXT
    'IF DiagRollEM THEN PRINT "Verified: "; text$

    IF text$ = "" THEN EXIT SUB 'can't do nothing with an empty string
    ClearDice
    DO
        semicolon = INSTR(text$, ";")
        IF semicolon THEN
            l$ = LEFT$(text$, semicolon - 1)
            text$ = MID$(text$, semicolon + 1)
        ELSE
            l$ = text$
        END IF

        'IF DiagRollEM THEN PRINT "PROCESSING: "; l$

        found = 0
        s = INSTR(l$, "S"): IF s THEN found = found + 1
        d = INSTR(l$, "D"): IF d THEN found = found + 1
        t = INSTR(l$, "T"): IF t THEN found = found + 1
        b = INSTR(l$, "B"): IF b THEN found = found + 1
        IF found <> 1 THEN EXIT SUB 'we should only find ONE element each pass, and there should always be one.  IF not, somebody screwed up.

        IF s THEN
            DiceToRoll.Set = VAL(LEFT$(l$, s - 1))
            IF DiagRollEm THEN PRINT "Number of Sets = "; DiceToRoll.Set
            m$ = MID$(l$, s + 1)

            pass = 0
            DO UNTIL m$ = ""
                pass = pass + 1
                'IF DiagRollEM THEN PRINT "SUBPROC "; m$
                n$ = LEFT$(m$, 1)
                IF n$ = "K" OR n$ = "D" THEN n$ = LEFT$(m$, 2)
                m$ = MID$(m$, LEN(n$) + 1)
                v = VAL(m$)
                SELECT CASE n$
                    CASE "+" '+ set mod
                        IF v > 0 THEN DiceToRoll.SetMod = v
                        IF DiagRollEm THEN PRINT "Set Mod"; v
                    CASE "-" ' - set mod
                        IF v > 0 THEN DiceToRoll.SetMod = -v
                        IF DiagRollEm THEN PRINT "Set Mod"; v
                    CASE "KH" 'keep high
                        IF v > 0 THEN DiceToRoll.SetKeepHigh = v
                        IF DiagRollEm THEN PRINT "Keep the Highest"; v; " Sets"
                    CASE "KL"
                        IF v > 0 THEN DiceToRoll.SetKeepLow = v
                        IF DiagRollEm THEN PRINT "Keep the Lowest"; v; " Sets"
                    CASE "DH"
                        IF v > 0 THEN DiceToRoll.SetDiscardHigh = v
                        IF DiagRollEm THEN PRINT "Discard the Highest"; v; " Sets"
                    CASE "DL"
                        IF v > 0 THEN DiceToRoll.SetDiscardLow = v
                        IF DiagRollEm THEN PRINT "Discard the Lowest"; v; " Sets"
                    CASE "R", "O" 'reroll or open roll
                        finished = 0: t$ = "": innerpass = 0
                        DO UNTIL finished
                            innerpass = innerpass + 1
                            v = VAL(m$)
                            IF v <> 0 THEN 'it's an o/r followed by a number
                                t$ = t$ + "=" + _TRIM$(STR$(v)) + ","
                            ELSE
                                n1$ = LEFT$(m$, 1)
                                SELECT CASE n1$
                                    CASE "="
                                        m$ = MID$(m$, 2)
                                        v = VAL(m$)
                                        t$ = t$ + "=" + _TRIM$(STR$(v)) + ","
                                    CASE "<"
                                        m$ = MID$(m$, 2)
                                        v = VAL(m$)
                                        t$ = t$ + "<" + _TRIM$(STR$(v)) + ","
                                    CASE ">"
                                        m$ = MID$(m$, 2)
                                        v = VAL(m$)
                                        t$ = t$ + ">" + _TRIM$(STR$(v)) + ","
                                    CASE ","
                                        m$ = MID$(m$, 2)
                                    CASE ELSE 'a character not a number, or =<>,
                                        finished = -1
                                END SELECT
                            END IF
                            StripNumber m$
                            IF n$ = "R" THEN
                                DiceToRoll.SetReRoll = t$
                                IF DiagRollEm THEN PRINT "Reroll Sets "; DiceToRoll.SetReRoll
                            ELSE
                                DiceToRoll.SetOpenRoll = t$
                                IF DiagRollEm THEN PRINT "Openroll Sets "; DiceToRoll.SetOpenRoll
                            END IF
                            IF m$ = "" THEN finished = -1
                            IF innerpass > 255 THEN IF DiagRollEm THEN PRINT "Error -- Too many loops processing Set ReRoll or OpenRoll": EXIT FUNCTION
                        LOOP
                END SELECT
                StripNumber m$
                n$ = LEFT$(m$, 1)
                SELECT CASE n$
                    CASE "K", "D", "R", "O", "+", "-" 'see if it's another command without a comma
                    CASE ELSE
                        comma = INSTR(m$, ",")
                        IF comma THEN m$ = MID$(m$, comma + 1)
                END SELECT
                IF pass > 100 THEN IF DiagRollEm THEN PRINT "Error - endless processing loop deciphering SET information": EXIT FUNCTION
            LOOP
        END IF


        IF d THEN
            v = VAL(LEFT$(l$, d))
            IF v < 1 THEN DiceToRoll.NumberOfDice = 1 ELSE DiceToRoll.NumberOfDice = v
            IF DiagRollEm THEN PRINT "Number of Dice To Roll = "; DiceToRoll.NumberOfDice
            m$ = MID$(l$, d + 1)

            v = VAL(m$)
            IF v > 0 THEN DiceToRoll.DiceSides = v
            StripNumber m$
            IF DiagRollEm THEN PRINT "Dice Sides = "; DiceToRoll.DiceSides
            pass = 0
            DO UNTIL m$ = ""
                pass = pass + 1
                'IF DiagRollEM THEN PRINT "SUBPROC "; m$
                n$ = LEFT$(m$, 1)
                IF n$ = "K" OR n$ = "D" THEN n$ = LEFT$(m$, 2)
                m$ = MID$(m$, LEN(n$) + 1)
                v = VAL(m$)
                SELECT CASE n$
                    CASE "+" '+ set mod
                        IF v > 0 THEN DiceToRoll.DiceMod = v
                        IF DiagRollEm THEN PRINT "DM"; v
                    CASE "-" ' - set mod
                        IF v > 0 THEN DiceToRoll.DiceMod = -v
                        IF DiagRollEm THEN PRINT "DM"; v
                    CASE "KH" 'keep high
                        IF v > 0 THEN DiceToRoll.DiceKeepHigh = v
                        IF DiagRollEm THEN PRINT "DKH"; v
                    CASE "KL"
                        IF v > 0 THEN DiceToRoll.DiceKeepLow = v
                        IF DiagRollEm THEN PRINT "DKL"; v
                    CASE "DH"
                        IF v > 0 THEN DiceToRollDiceDiscardHigh = v
                        IF DiagRollEm THEN PRINT "DDH"; v
                    CASE "DL"
                        IF v > 0 THEN DiceToRoll.DiceDiscardLow = v
                        IF DiagRollEm THEN PRINT "DDL"; v
                    CASE "R", "O" 'reroll or open roll
                        finished = 0: t$ = "": innerpass = 0
                        DO UNTIL finished
                            innerpass = innerpass + 1
                            v = VAL(m$)
                            IF v <> 0 THEN 'it's an o/r followed by a number
                                t$ = t$ + "=" + _TRIM$(STR$(v)) + ","
                            ELSE
                                n1$ = LEFT$(m$, 1)
                                SELECT CASE n1$
                                    CASE "="
                                        m$ = MID$(m$, 2)
                                        v = VAL(m$)
                                        t$ = t$ + "=" + _TRIM$(STR$(v)) + ","
                                    CASE "<"
                                        m$ = MID$(m$, 2)
                                        v = VAL(m$)
                                        t$ = t$ + "<" + _TRIM$(STR$(v)) + ","
                                    CASE ">"
                                        m$ = MID$(m$, 2)
                                        v = VAL(m$)
                                        t$ = t$ + ">" + _TRIM$(STR$(v)) + ","
                                    CASE ","
                                        m$ = MID$(m$, 2)
                                    CASE ELSE 'a character not a number, or =<>,
                                        finished = -1
                                END SELECT
                            END IF
                            StripNumber m$
                            IF n$ = "R" THEN
                                DiceToRoll.DiceReroll = t$
                                IF DiagRollEm THEN PRINT "DR: "; DiceToRoll.DiceReroll
                            ELSE
                                DiceToRoll.DiceOpenRoll = t$
                                IF DiagRollEm THEN PRINT "DO: "; DiceToRoll.DiceOpenRoll
                            END IF
                            IF m$ = "" THEN finished = -1
                            IF innerpass > 255 THEN IF DiagRollEm THEN PRINT "Error -- Too many loops processing Dice ReRoll or OpenRoll": EXIT FUNCTION
                        LOOP
                END SELECT
                StripNumber m$
                n$ = LEFT$(m$, 1)
                SELECT CASE n$
                    CASE "K", "D", "R", "O", "+", "-" 'see if it's another command without a comma
                    CASE ELSE
                        comma = INSTR(m$, ",")
                        IF comma THEN m$ = MID$(m$, comma + 1)
                END SELECT
                IF pass > 100 THEN IF DiagRollEm THEN PRINT "Error - endless processing loop deciphering SET information": EXIT FUNCTION
            LOOP
        END IF


        IF t THEN
            DiceToRoll.TotalMod = VAL(MID$(l$, 2))
            IF DiagRollEm THEN PRINT "Dice Total Modifier = "; DiceToRoll.TotalMod
        END IF

        IF b THEN
            Brief = VAL(MID$(l$, 2))
            IF DiagRollEm THEN PRINT "Roll Information Displayed: ";
            SELECT CASE Brief
                CASE 0: IF DiagRollEm THEN PRINT "Full"
                CASE 1: IF DiagRollEm THEN PRINT "Reduced"
                CASE 2: IF DiagRollEm THEN PRINT "Final Results Only"
            END SELECT
        END IF

    LOOP UNTIL l$ = text$
    RollEm$ = DiceRoll$
END FUNCTION

If you want to make this a library for your own usage, just strip it out at line 70 or so, and save it as whatever library name you want.  "DiceRoller.BM" works for me, but make it whatever you'd like...

At that point, usage is rather simple:

'$INCLUDE:'whatever_you_named_your_library.BM" would go at the bottom of your code, and then you can simply use:

result$ = RollEm$(whatever_to_roll$)




This little library is able to do just about anything you'd need it to do, as far as dice rolling for RPGs go, as long as you follow the basic syntax and send it a proper string.

[b]First Concept of Library:[/b] Our "dice rolling formula" is broken down into segments seperated by a semicolon.

[b]Our 4 basic segments are:[/b]
Sets
Dice
Total mod
Brief output

[b]For Sets, the syntax is:[/b]
##S  -- the number of sets, followed by S

[b]For Dice, the syntax is:[/b]
##D##  -- the number of dice, followed by D, followed by the sides on the dice.  NOTE: the first set of numbers are optional, so you could simply use D6 to roll a single six sided dice.

[b]For Total modifed, the syntax is:[/b]
T##  -- T followed by the total to add or subtract to the total dice roll

[b]For Brief output, the syntax is:[/b]
##B  -- the number to represent how little output we want, followed by B
0 = full output
1 = reduced output
2 = minimal output (basically only the final results)

[b]Second Concept of Library:[/b] Our segments can be further limited by optional parameters

[b]+## (or -##)[/b] -- add (or subtract) number  to segment

[b]KH## [/b]-- Keep the Highest number of "segment"
[b]KL## [/b]-- Keep the Lowest number of "segment"
[b]DH## [/b]-- Discard the Highest number of "segment"
[b]DL## [/b]-- Discard the Lowest number of "segment"

[b]R + [i]stuff[/i][/b] -- Reroll according to [i]stuff[/i]
[b]O + [i]stuff[/i][/b]-- Openroll according [i]to stuff[/i]

[i]stuff[/i] -- A string composed of numbers, operators,  and commas, to represent what to reroll or openroll.  It sounds complex, but its not.

R1  -- Reroll all 1's
R=2,=3  -- Reroll all rolls that are equal to 2 and equal to 3
R<4 -- Reroll all rolls that are less than 4

O1<2>3 -- (a silly rule set, but hey, it's an example)... Openroll all 1's, all numbers less than two, and all numbers greater than 3

[b]Putting it all together:[/b]

In the end, what we end up with is formulas which look like the following:

3S;2D10 -- Roll 3 sets; of 2 10-sided dice.

6S;4D6KH3 -- Roll 6 sets; of 4 6-sided dice, keeping the 3 highest rolls

10SKH1KL1;2D10+2 -- Roll 10 sets of dice and only keep the highest set and the lowest set; of 2 10-sided dice, and add 2 to each dice.

Depending on what you want, you can generate some rather impressive formulas and take all the bite out of the dice rolling process completely for your games.

NOTE: Spaces are optional, so if they help you understand your "dice rolling formulas" better, feel free to use them:

4S; 3D10 KH2 O20 R2 ; T1; B2 -- Roll 4 sets of; 3 10-sided dice, keeping the 2 highest dice, and openrolling if the dice total to 20, and rerolling if the dice total to 2; then add 1 to the final total; and all we want to see are the final results...

Print this item

  Text to Speech Library (Windows only)
Posted by: SMcNeill - 04-27-2022, 09:06 PM - Forum: SMcNeill - Replies (11)

I turned the powershell stuff into a simple little library for people to make use of in their projects, and here it is:

Code: (Select All)
_Title "Steve's Powershell Speech Library"

Speech_IoR 'initialize or reset speech options
Speech_SaP "Hello World, This is a normal speed demo of David's voice" 'speak and print
_Delay 2
Speech_Speaker "Ziva"
Speech_Say "Hello again.  This is a normal speed demo of Ziva's voice." 'just speak this one
_Delay 2
Speech_Speaker "David"
Speech_Speed -10
Speech_SaP "And now I'm speaking as David, but I'm speaking veeery slow."
_Delay 2
Speech_Speaker "Ziva"
Speech_Speed 5
Speech_SaP "And now I'm a very hyper Ziva!"
_Delay 2
Speech_Speed 0
Speech_Volume 30
Speech_SaP "And now I'm whispering to you that I'm done with my demo!"


'$INCLUDE:'TextToSpeech.BM'

As you can see, all the commands are preceeded by "Speech_", to try and help keep the sub names unique, associative, and not interfere with any user variable names and such.

Routines in this little package are:

Speech_IoR -- Init or Reset.  Call this first to initialize the settings (and turn volume up to 100, or else you'll be speaking on a MUTE channel)

Speech_Speaker -- Change the default speaker.  Currently I only support "David" and "Ziva", but feel free to change or add to this if your system has other voices installed via language/voice packs.

Speech_Speed -- Set a value from -10 to 10 to adjust the speed of the speaker.  0 id default, -10 is sloooow, and 10 is faaaast.

Speech_Volume -- Set a value from 0 to 100 to adjust how loud you're going to be speaking with the voices.

Speech_OutTo -- Use this to change where you want the speech to go.  Only options now are your speakers or a file.  Since it's not currently in the demo, as I didn't want to randomly save junk to folks drives, an example looks like:

        Speech_OutTo "MyTextToFile.wav"
        Speech_OutTo "Speaker"
        Speech_OutTo "" 'defaults/resets to speaker

Speech_Say -- Just says the text you specify with the settings you gave it previously.

Speech_SaP -- Says and Prints the text you specify to the screen as a quick print and speak shortcut.  Uses previous settings.

Speech_ToWav -- Converts text to a wav file and saves it to the disk where you specify.  Since it's not in the short demo above, usage would be as:

       Speech_ToWav "Hello World.  This is the text I'm saving to a file!", "MyFile.wav"

speak -- This is the master command with all the options built into it.  You can skip everything else, if you want to use this as a stand alone command to do everything all at once.  Everything else ends up calling this command at the end of the day, so you can bypass some processes if you call this directly.




And that's basically it for now.  Windows Speech Synthesizer is quite a powerful little tool, with a ton of options which we can utilize with it, but I figure this is the basics of what someone would need to be able to do with it for a program.  It seems to handle what I need from it for now.

If you guys need it to do more, feel free to ask and I'll see about adding extra functionality as people need it.  Or, feel free to make the changes necessary yourself and then share them here with us so everybody else can enjoy any extra tweaks you guys add into the code.




To make use of this:

1) Download the library from the attachment below.
2) Move it to your QB64 folder.
3) '$INCLUDE:'TextToSpeech.BM' at the end of your program.
4) Speech_IoR inside your code to initialize everything
5) Call the other subs as you want to make use of them and alter the settings to your specific needs.

It's that simple!  ;D



Attached Files
.bm   TextToSpeech.BM (Size: 2.96 KB / Downloads: 99)
Print this item

  Abacus - Tired of Windows Calculator? Try This Instead!
Posted by: Pete - 04-27-2022, 08:51 PM - Forum: TheBOB - No Replies

Abacus.bas by Bob Seguin.
[Image: Screenshot-657.png]
Description: Ancient Japanese calculator. Use the mouse to move the beads.

Download: Download the zip file below. Unzip to either your QB64 folder, or for better organization, to a folder you create like "TheBOB-Abacus".

Install: Compile Abacus.bas with QB64 v1.3 or above, and make sure the compiler output is set to create the .exe file in the same folder. See the option in the QB64 IDE RUN menu and check the RUN option: "Output EXE to Source Folder".



Attached Files
.7z   TheBOB-Abacus.7z (Size: 11.08 KB / Downloads: 81)
Print this item

  Convert QB64 Program to Animated Avatar
Posted by: bplus - 04-27-2022, 08:51 PM - Forum: Help Me! - Replies (10)

Convert QB64 Program to Animated Avatar  How?

I would very much like to use this:
https://staging.qb64phoenix.com/showthread.php?tid=195

or another one with a similar changing image.

Print this item

  Steve's 3D Print
Posted by: SMcNeill - 04-27-2022, 08:51 PM - Forum: SMcNeill - Replies (1)

Inspired by Petr's 3D printing, I sat down and worked up a simple little routine to make pseudo-3d text of my own, and I wrapped it up into a single neat little SUB with 3 zillion parameters...



Code: (Select All)
SCREEN _NEWIMAGE(1024, 720, 32)
_SCREENMOVE _MIDDLE
OE20 = _LOADFONT("calibri.ttf", 72)
_FONT OE20

Print3D 100, 100, "Hello World", 10, 10, OE20, &HFFFFFF00, 1, 1, 1, 1
Print3D 100, 200, "Steve is Awesome!", 5, -10, OE20, &HFFFF0000, -1, 1, 1, 1.25
Print3D 100, 300, "So, what do you guys think?", 6, 0, OE20, &HFFFFFFFF, 1, .5, .5, .5

Print3D 100, 400, "No 3D, just *italic* style text.", 1, 20, OE20, &HFF00FF00, 0, 0, 1, 1


SUB Print3D (x AS INTEGER, y AS INTEGER, text$, thick AS INTEGER, tilt AS INTEGER,_
             f AS LONG, fg AS _UNSIGNED LONG, xchange as integer, ychange as integer,_
             scalex as _float, scaley as _float)
    DIM copy AS INTEGER
    DIM dx1 AS _FLOAT, dx2 AS _FLOAT, dy1 AS _FLOAT, dy2 AS _FLOAT

    d = _DEST: s = _SOURCE: font = _FONT
    copy = _NEWIMAGE(_WIDTH, _HEIGHT, 32)
    _DEST copy: _SOURCE copy
    _FONT f
    sx1 = 0: sy1 = 0
    sx2 = _PRINTWIDTH(text$, copy): sy2 = _FONTHEIGHT(f)

    dx1 = x: dy1 = y
    dx2 = x + sx2 * scalex: dy2 = y + sy2 * scaley

    FOR i = thick TO 0 STEP -1
        CLS , 0
        COLOR _RGBA32(_RED32(fg), _GREEN32(fg), _BLUE32(fg), 155 + 100 / i), 0
        PRINT text$
        _MAPTRIANGLE (sx1, sy1)-(sx2, sy1)-(sx1, sy2), copy TO(dx1 + tilt, dy1)-(dx2 + tilt, dy1)-(dx1, dy2), d
        _MAPTRIANGLE (sx1, sy2)-(sx2, sy1)-(sx2, sy2), copy TO(dx1, dy2)-(dx2 + tilt, dy1)-(dx2, dy2), d
        dx1 = dx1 + xchange: dx2 = dx2 + xchange: dy1 = dy1 + ychange: dy2 = dy2 + ychange
    NEXT
    _DEST d: _SOURCE s: _FONT font
    _FREEIMAGE copy
END SUB

Various thickness is supported. Different tilts are supported. Text can expand from any direction... We can use it to italicize our text if we want to... It scales text to different widths and heights...

It's not a true 3D text, as in we can't rotate it on the x/y/z axis, but it makes a nice imitation text which we can use to create a nice title screen, or such, for our programs.

Play around with it, see what you guys think of it, and I'll be happily awaiting to see how you guys who are much better than me in math will improve/alter this.

Many thanks go to Petr for providing the inspiration for me to sit down and play around with getting this up and going to the point where it is. I'm really quite happy with how it performs and what it can do for us, and I think this will end up going into my toolbox for regular use from now on. Wink

And a little demo of some of the various styles of 3d text which we can generate with the routine.  Watch and pay attention to which direction the text tilts and turns as the program goes along.


Code: (Select All)
SCREEN _NEWIMAGE(1024, 720, 32)
_SCREENMOVE _MIDDLE
OE20 = _LOADFONT("calibri.ttf", 72)
_FONT OE20

FOR x = -2 TO 2 STEP 0.1
    CLS , 0
    Print3D 100, 200, "Steve is Awesome!", 5, x * 20, OE20, &HFFFF0000, x, x, 1, 1.25
    _LIMIT 3
    _DISPLAY
NEXT
FOR x = -2 TO 2 STEP 0.1
    CLS , 0
    Print3D 100, 200, "Steve is Awesome!", 5, x * 20, OE20, &HFFFF0000, -x, -x, 1, 1.25
    _LIMIT 3
    _DISPLAY
NEXT
FOR x = -2 TO 2 STEP 0.1
    CLS , 0
    Print3D 100, 200, "Steve is Awesome!", 5, x * 20, OE20, &HFFFF0000, x, -x, 1, 1.25
    _LIMIT 3
    _DISPLAY
NEXT
FOR x = -2 TO 2 STEP 0.1
    CLS , 0
    Print3D 100, 200, "Steve is Awesome!", 5, x * 20, OE20, &HFFFF0000, -x, x, 1, 1.25
    _LIMIT 3
    _DISPLAY
NEXT





SUB Print3D (x AS INTEGER, y AS INTEGER, text$, thick AS INTEGER, tilt AS INTEGER,_
             f AS LONG, fg AS _UNSIGNED LONG, xchange as integer, ychange as integer,_
             scalex as _float, scaley as _float)
    DIM copy AS INTEGER
    DIM dx1 AS _FLOAT, dx2 AS _FLOAT, dy1 AS _FLOAT, dy2 AS _FLOAT

    d = _DEST: s = _SOURCE: font = _FONT
    copy = _NEWIMAGE(_WIDTH, _HEIGHT, 32)
    _DEST copy: _SOURCE copy
    _FONT f
    sx1 = 0: sy1 = 0
    sx2 = _PRINTWIDTH(text$, copy): sy2 = _FONTHEIGHT(f)

    dx1 = x: dy1 = y
    dx2 = x + sx2 * scalex: dy2 = y + sy2 * scaley

    FOR i = thick TO 0 STEP -1
        CLS , 0
        COLOR _RGBA32(_RED32(fg), _GREEN32(fg), _BLUE32(fg), 155 + 100 / i), 0
        PRINT text$
        _MAPTRIANGLE (sx1, sy1)-(sx2, sy1)-(sx1, sy2), copy TO(dx1 + tilt, dy1)-(dx2 + tilt, dy1)-(dx1, dy2), d
        _MAPTRIANGLE (sx1, sy2)-(sx2, sy1)-(sx2, sy2), copy TO(dx1, dy2)-(dx2 + tilt, dy1)-(dx2, dy2), d
        dx1 = dx1 + xchange: dx2 = dx2 + xchange: dy1 = dy1 + ychange: dy2 = dy2 + ychange
    NEXT
    _DEST d: _SOURCE s: _FONT font
    _FREEIMAGE copy
END SUB

Print this item

  Steve's Quick Lesson on Number TYPEs and Colors
Posted by: SMcNeill - 04-27-2022, 08:45 PM - Forum: Learning Resources and Archives - No Replies

Salvaged from the other boards, some of you may have seen this before:

Code: (Select All)
Screen _NewImage(640, 640, 32)
_Title "Number Types and Colors"
Print "Welcome to Steve's Qucik Lesson on Number Types and Colors."
Print
Print "The most important thing to keep in mind in this lesson is that we're going to be talking exclusively about 32-bit color values here.  For all other screen modes, this lesson holds much less importance."
Print
Print "Press <ANY KEY> to begin!"
Sleep
Cls , 0
Print "First, let's talk about how SINGLE variable types work (or DON'T work), in regards to 32-bit colors."
Print
Print "Let's choose a nice color and use it to draw a box on the screen."
Print "How about we choose a BLUE box?  _RGB32(0, 0, 255)"
Print
Line (50, 90)-(250, 250), _RGB32(0, 0, 255), BF
Locate 18, 1: Print "Looks like a nice BLUE box.  Right?"
Print "Press <ANY KEY> to continue!"
Sleep
Cls , 0
Print "Now, let's store that BLUE value inside a SINGLE tyoe variable."
Print "BLUE = _RGB32(0, 0, 255)"
Print ""
Print "Once we've did that, let's draw the exact same box on the screen again with the variable."
BLUE = _RGB32(0, 0, 256)
Line (50, 90)-(250, 250), BLUE, BF
Locate 18, 1: Print "Looks like a nice BLUE box.  Right?"
Print "Press <ANY KEY> to continue!"
Sleep
Cls , 0
Print "What do you guys mean, 'What box?'??"
Print "Do you mean to tell me you nice folks DIDN'T see a pretty BLUE box on the last screen??"
Print
Print
Print "Just what the hell happened to it?!!"
Print
Print
Print "For the answer to that, let's print out two values to the screen:"
Print "BLUE = "; BLUE
Print "_RGB32(0, 0, 255) = "; _RGB32(0, 0, 255)
Print
Print "At first glance, those APPEAR to be the same numbers, but let's expand the      scientific notation fully:"
Blue&& = BLUE
Print "BLUE = "; Blue&&
Print "_RGB32(0, 0, 255) = "; _RGB32(0, 0, 255)
Print
Print "Press <ANY KEY> to continue!"
Sleep
Cls , 0
Print "HOLY COW, BATMAN!!  Was those two numbers DIFFERENT?!!"
Print "BLUE = "; Blue&&; "vs"; _RGB32(0, 0, 255)
Print
Print "Well... They're only a LITTLE different...  Right?"
Print "I mean, how bad can one little number difference be?  Right??"
Print
Print "For the answer to that, let's look at the HEX values of those numbers:"
Print "BLUE = "; Hex$(Blue&&)
Print "_RGB32(0, 0, 255) - "; Hex$(_RGB32(0, 0, 255))
Print
Print "And to help understand what we're seeing in HEX, break those values down into   groups of 2 in your mind."
Print "(I'm too lazy to do it for you..)"
Print "The first two values are ALPHA, followed by RED, followed by GREEN, followed by BLUE."
Print
Print "So  BLUE = FF alpha, 00 red 01 green, 00 blue"
Print "_RGB32(0, 0, 0) = FF alpha, 00 red, 00 green, FF blue"
Print
Print "And keep in mine that FF is HEX for the decimal value of 255."
Print
Print "Press <ANY KEY> to continue!"
Sleep
Cls , 0
Print "Since SINGLE values lose precision after numbers get so large, our variable BLUE"
Print "has to round to the nearest scientific notation point and try for the closest"
Print "possible match."
Print
Print "And even though "; Blue&&; " is only one number off from "; _RGB32(0, 0, 255); ","
Print "that number still greatly changes the color value."
Print
Print "It changes it from FF 00 00 FF (255 alpha, 0 red, 0 green, 255 blue) to"
Print "FF 00 01 00 (255 alpha, 0 red, 1 green, 0 blue)."
Print
Print "Our BLUE has become a GREEN, simply by using a SINGLE variable type!!"
Print "(And, it's such a low shade green, my poor eyes can't make it out at all."
Print "To me, the damn 'green box' was just as black as my black screen."
Print "I didn't see it at all!)"
Print "Press <ANY KEY> to continue!"
Sleep
Cls , 0
Print "So, at this point, I think it should be obvious WHY we don't want to store"
Print "color values inside SINGLE variables."
Print
Print "But what about using a normal LONG to hold the values??"
Print
Print "Let's look and see!"
Print
Print "For this, let's draw our box again:"
Line (50, 150)-(250, 250), _RGB32(0, 0, 255), BF
Locate 18, 1: Print "Looks like a nice BLUE box.  Right?"
Print
Print "But let's get the POINT value from that box, and store it in a LONG variable."
BLUE& = Point(100, 200)
Print "BLUE& = "; BLUE&
p&& = Point(100, 200)
Print "POINT(100, 200) = "; Point(100, 200)
Print
Print
Print "Again, we're looking at two numbers that don't match!"
Print
Print "FOR THE LOVE OF GOD, WHYYYY??!!!!"
Print "Press <ANY KEY> to continue!"
Sleep
Cls , 0
Print BLUE&; "<>"; p&&
Print
Print "Why are those two numbers so different??"
Print
Print "For that answer, let's look at their HEX values again:"
Print "BLUE& = "; Hex$(BLUE&)
Print "POINT(100, 200) = "; Hex$(p&&)
Print
Print "."
Print "..."
Print "......"
Print
Print "WHAT THE HEX??  Those two values are EXACTLY the same??"
Print
Print "They are.  It's just that one of them is stored as a SIGNED LONG, while the     other is an UNSIGNED LONG."
Print
Print "HEX wise, they're the same value..."
Print
Print "BUT, can you see where the two numbers might not match if we use them in an IF  statement?"
Print
Print "IF "; BLUE&; "="; p&&; "THEN...."
Print
Print "Ummm...  That might not work as intended!"
Print
Print "Press <ANY KEY> to continue!"
Sleep
Cls , 0
Print "Even thought the HEX values for "; BLUE&; "and"; p&&;
Print "are EXACTLY the same, the values themselves are quite different."
Print
Print "A LONG will, indeed, hold the proper value for a 32-bit color, as it stores"
Print "all four HEX values properly for us."
Print
Print "As long as our program uses NOTHING but LONG values, you'll never have a"
Print "problem with using LONG as a variable type..."
Print
Print "BUT...."
Print
Print "The moment you start to compare LONG values directly against POINT values,"
Print "your program is going to run into serious issues!"
Print
Print "Because at the end of the day,"; BLUE&; "is not the same as "; p&&
Print
Print
Print "Press <ANY KEY> to continue!"
Sleep
Cls , 0
Print "So, with all those examples, and all that said, let's answer"
Print "the most important question:"
Print
Print "'What TYPE works best for 32-bit colors??"
Print
Print
Print "DOUBLE, _FLOAT, _UNSIGNED LONG, _INTEGER64, _UNSIGNED _INTEGER64"
Print
Print "Of all the types which QB64 offers, only the above are TRULY viable"
Print "to hold a 32-bit color value."
Print
Print "Any type not listed above is going to be problematic at one time or"
Print "another for us!"
Print
Print "And of those suitable types, I personally prefer to keep integer values"
Print "as integers, so I recommend: _UNSIGNED LONG or _INTEGER64."
Print
Print
Print "Press <ANY KEY> to continue!"
Sleep
Cls , 0
Print "And WHY _UNSIGNED LONG??"
Print
Print "Simply because it's only 4 bytes of memory (the minimal we can possibly use for"
Print "32-bit color values), and it's what QB64 uses internally with POINT and such."
Print
Print
Print "So, if _UNSIGNED LONG works so well, WHY would I *ever* use _INTEGER64??"
Print
Print "Becauses sometimes I like to code command values into my colors."
Print "(Such as: NoColor = -1)"
Print
Print "_UNSIGNED LONG *only* holds the values for the colors themselves."
Print "EVERY number from 0 to FFFFFFFF is accounted for as part of our color spectrum."
Print
Print "If I need *special* or unique values for my program, I usually just use _INTEGER64s"
Print "for my variable types and then I can assign negative numbers for those unique values."
Print
Print
Print "Press <ANY KEY> to continue!"
Sleep
Cls , 0
Print "At the end of the day though, when all is said and done, you're still the"
Print "one responsible for your own code!"
Print
Print "Use whichever type works for you, and works best for your needs."
Print
Print "Just keep in mind:  Various TYPEs come with various limitations on your code."
Print
Print "_BYTE, INTEGER, (both signed and unsigned) are insane to use..."
Print "SINLGE loses precision.  Expect to lose whole shades of blue...."
Print "LONG may cause issues with POINT, if compared directly...."
Print "_UNSIGNED LONG works fine, any ONLY stores 32-bit color values...."
Print "_INTEGER64 works fine, and can store extra values if necessary...."
Print "DOUBLE and _FLOAT both work, but are floating point values...."
Print
Print
Print "And with all that said and summed up, it's now up to YOU guys to decide what"
Print "works best in your own programs."
Print
Print
Print "As I said, I personally recommend _UNSIGNED LONG or _INTEGER64 in special cases."
Print "But the choice, and the debugging, is entirely up to YOU.   :D"


Copy.  Paste.  Compile.  I'll let the code speak for itself and hopefully it'll help folks learn a bit more about WHY certain variables are more suitable for use with 32-bit color values than others.  Wink

Print this item