Welcome, Guest |
You have to register before you can post on our site.
|
|
|
_OpenFile Dialog in same folder as exe |
Posted by: bplus - 12-04-2022, 08:28 PM - Forum: Utilities
- Replies (16)
|
|
I want the DefaultPathAndFile$ where my exe is.
_StartDir$ sure didn't get it, that's my QB64 exe folder
_Cwd$ works if I have been in folder for awhile but sometimes seems to be wrong when just starting cold.
So I am trying this:
Code: (Select All) Function ExePath$
Dim As Long t1, t2
t1 = _InStrRev(Command$(0), "\")
t2 = _InStrRev(Command$(0), "/")
If t1 > t2 Then ExePath$ = Left$(Command$(0), t1 - 1) Else ExePath$ = Left$(Command$(0), t2 - 1)
End Function
Look alright? I add forward slash in case of Linux, Windows doesn't care. It seems to be working for all the tests I gave trying to get out of _CWD$
|
|
|
Day 024: LCASE$ |
Posted by: Pete - 12-04-2022, 05:17 AM - Forum: Keyword of the Day!
- Replies (12)
|
|
Not much to say here. LCASE$ just converts any uppercase characters in a string to lowercase. LCASE$(mystring$)
The most obvious use for LCASE$ is an input routine...
Code: (Select All) PRINT "Was this information helpful? Y/N"; ans$
DO
_LIMIT 30
mykey$ = INKEY$
IF LCASE$(mykey$) = "y" THEN PRINT "You darn tootin' it waz ya mangy polecat!"
LOOP
The code above allows the user to type either "y" or "Y" to get a printed response."
Anyway, not much ELSE to see here; besides, it's Sunday, and God takes this day off. Me, I take a 1/2 day!
Pete
|
|
|
mini-weapon mixer |
Posted by: James D Jarvis - 12-03-2022, 11:20 PM - Forum: Programs
- Replies (2)
|
|
A cousin to the mini-monster-mixer and robot mixer. Generates 80 weapon sprites for a rpg/rougelike.
here's a sample run:
Code: (Select All) 'Mini-Weapon-Mixer v0.1
'By James D. Jarvis December 2022
'This program uses BASIMAGE coded by Dav for QB64GL 1.4, MAY/2020
'
'generate a sprite sheet of weapons for use in a roguelike/RPG
'each is 64 by 64 pixels but code here can be modified to change that
'
'press c or s to save a sprite sheet to the clipboard so you can paste it into a paint program
'and save is whatever format you desire
'pres <esc> to quit
'
'License: Share sprite sheets as long as they include generated credit bar in image
'any programs using original code or graphics from source or generated by program
' please include the following (or equivalent) line somwhere in comments and documentation:
'Includes Art and/or Code from Mini-Weapon-Mixer v0.1 created by James D. Jarvis
'
Randomize Timer
Dim Shared ms&
ms& = _NewImage(512, 360, 32)
Screen ms&
_Title "Mini-Weapon-Mixer V0.1"
Dim Shared part&
Dim Shared kk1 As _Unsigned Long
Dim Shared kk2 As _Unsigned Long
Dim Shared kk3 As _Unsigned Long
Dim Shared kk4 As _Unsigned Long
Dim Shared kk5 As _Unsigned Long
Dim Shared kk6 As _Unsigned Long
Dim Shared clr~&
part& = BASIMAGE1&
Type weapon_type
style As Integer
pole As Integer
rhead As Integer
chead As Integer
lhead As Integer
blade As Integer
handle As Integer
fgard As Integer
k1 As _Unsigned Long
k2 As _Unsigned Long
k3 As _Unsigned Long
k4 As _Unsigned Long
End Type
Dim Shared weapon_limit
weapon_limit = 80
Dim klrset(12, 3) As Integer
Dim Shared wlook(weapon_limit) As weapon_type
_Source part&
'read the colors from the color reference bar whichever color is in the top left corner will be transparent
clr~& = Point(0, 0) 'find background color of image
kk1 = Point(0, 1): kk2 = Point(0, 2): kk3 = Point(0, 3): kk4 = Point(0, 4)
_Dest part&
Line (0, 0)-(0, 8), clr~& 'erase the color reference bar from the bit map
_ClearColor clr~&, ms& 'set background color as transparent
_ClearColor clr~&, part&
_Source ms&
_Dest ms&
Do
Cls
mmx = 0: mmy = 0
For m = 1 To weapon_limit
'create a new set of weapon sprites
wlook(m).style = Int(1 + Rnd * 20)
'1- pole only
'2 - pole and chead
'3 - pole chead,rhead
'4 - pole chead,rhead and lhead
'5- pole rhead and lhead
'6- pole and rhead
'7- sword and handle
'8- sword , handle, and foregarde
'9- sword and pole
'10- sword, pole and foregarde
'11- sword, pole and lhead
'12- sword,pole lhead and rhead
Select Case wlook(m).style
Case 1
wlook(m).pole = Int(1 + Rnd * 20)
wlook(m).rhead = 0
wlook(m).chead = 0
wlook(m).lhead = 0
wlook(m).blade = 0
wlook(m).handle = 0
wlook(m).fgard = 0
Case 2, 18
wlook(m).pole = Int(1 + Rnd * 20)
wlook(m).rhead = 0
wlook(m).chead = Int(1 + Rnd * 20)
wlook(m).lhead = 0
wlook(m).blade = 0
wlook(m).handle = 0
wlook(m).fgard = 0
wlook(m).style = 2
Case 3, 13, 19
wlook(m).pole = Int(1 + Rnd * 20)
wlook(m).rhead = Int(1 + Rnd * 20)
wlook(m).chead = Int(1 + Rnd * 20)
wlook(m).lhead = 0
wlook(m).blade = 0
wlook(m).handle = 0
wlook(m).fgard = 0
wlook(m).style = 3
Case 4
wlook(m).pole = Int(1 + Rnd * 20)
wlook(m).rhead = Int(1 + Rnd * 20)
wlook(m).chead = Int(1 + Rnd * 20)
wlook(m).lhead = Int(1 + Rnd * 20)
wlook(m).blade = 0
wlook(m).handle = 0
wlook(m).fgard = 0
Case 5, 20
wlook(m).pole = Int(1 + Rnd * 20)
wlook(m).rhead = Int(1 + Rnd * 20)
wlook(m).chead = 0
wlook(m).lhead = Int(1 + Rnd * 20)
wlook(m).handle = 0
wlook(m).fgard = 0
wlook(m).style = 5
Case 6, 14
wlook(m).pole = Int(1 + Rnd * 20)
wlook(m).rhead = Int(1 + Rnd * 20)
wlook(m).chead = 0
wlook(m).lhead = 0
wlook(m).blade = 0
wlook(m).handle = 0
wlook(m).fgard = 0
wlook(m).style = 6
Case 7, 15, 16
wlook(m).pole = 0
wlook(m).rhead = 0
wlook(m).chead = 0
wlook(m).lhead = 0
wlook(m).blade = Int(1 + Rnd * 20)
wlook(m).handle = Int(1 + Rnd * 10)
wlook(m).fgard = 0
wlook(m).style = 7
Case 8
wlook(m).pole = 0
wlook(m).rhead = 0
wlook(m).chead = 0
wlook(m).lhead = 0
wlook(m).blade = Int(1 + Rnd * 20)
wlook(m).handle = Int(1 + Rnd * 10)
wlook(m).fgard = Int(1 + Rnd * 10)
Case 9, 17
wlook(m).pole = Int(1 + Rnd * 20)
wlook(m).rhead = 0
wlook(m).chead = 0
wlook(m).lhead = 0
wlook(m).blade = Int(1 + Rnd * 20)
wlook(m).handle = 0
wlook(m).fgard = 0
wlook(m).style = 9
Case 10
wlook(m).pole = Int(1 + Rnd * 20)
wlook(m).rhead = 0
wlook(m).chead = 0
wlook(m).lhead = 0
wlook(m).blade = Int(3 + Rnd * 18)
wlook(m).handle = 0
wlook(m).fgard = Int(1 + Rnd * 10)
Case 11
wlook(m).pole = Int(1 + Rnd * 20)
wlook(m).rhead = 0
wlook(m).chead = 0
wlook(m).lhead = Int(1 + Rnd * 15)
wlook(m).blade = Int(1 + Rnd * 20)
wlook(m).handle = 0
wlook(m).fgard = Int(1 + Rnd * 10)
Case 12
wlook(m).pole = Int(1 + Rnd * 20)
wlook(m).rhead = Int(1 + Rnd * 15)
wlook(m).chead = 0
wlook(m).lhead = Int(1 + Rnd * 15)
wlook(m).blade = Int(1 + Rnd * 20)
wlook(m).handle = 0
wlook(m).fgard = Int(1 + Rnd * 10)
End Select
wlook(m).k1 = _RGB32(Int(80 + Rnd * 150), Int(80 + Rnd * 150), Int(80 + Rnd * 150))
If Rnd * 6 < 2 Then wlook(m).k1 = _RGB32(Int(80 + Rnd * 150), Int(80 + Rnd * 120), Int(80 + Rnd * 50))
kk = Int(155 + Rnd * 100)
vk1 = kk: vk2 = kk: vk3 = kk
Select Case Int(Rnd * 10)
Case 1
vk1 = Int(vk1 * .8)
vk2 = Int(vk2 * .9)
Case 2
vk3 = Int(vk3 * .8)
vk2 = Int(vk2 * .9)
Case 3
vk1 = Int(vk1 * .8)
vk3 = Int(vk3 * .9)
End Select
wlook(m).k2 = _RGB32(vk1, vk2, vk3)
wlook(m).k3 = _RGB32(Int(vk1 * 0.7), vk2 * (0.7), Int(vk3 * 0.7))
kk = Int(150 + Rnd * 100)
wlook(m).k4 = _RGB32(kk, kk, Int(kk / Int(1 + Rnd * 10)))
draw_weapon mmx, mmy, m, 1
mmx = mmx + 32
If mmx >= _Width Then
mmx = 0
mmy = mmy + 64
End If
Next m
md$ = "Weapon Sprite Sheet generated " + Date$ + " at " + Time$
md2$ = "Mini-Weapon-Mixer V0.1 by James D. Jarvis"
_PrintString (0, 321), md$
_PrintString (0, 337), md2$
Do
_Limit 60
kk$ = InKey$
Loop Until kk$ <> ""
If kk$ = "C" Or kk$ = "c" Or kk$ = "S" Or kk$ = "s" Then
_ClipboardImage = ms&
_Delay 0.3
Locate 1, 1: Print "Sprite Sheet Saved to Clipboard"
Sleep 3
End If
Loop Until kk$ = Chr$(27)
_FreeImage part&
System
Sub draw_weapon (Mx, my, mid, scale)
'generate a monster image from source sprite sheet part& and render to the programs main screen ms&
tempi& = _NewImage(32, 64, 32)
'tempi& creates a temporary one sprite image for rendering
_ClearColor clr~&, tempi&
_Dest tempi&
Cls
'Locate 1, 1: Print wlook(mid).style
Select Case wlook(mid).style
Case 1 To 6
_PutImage (0, 32)-(31, 63), part&, tempi&, ((wlook(mid).pole - 1) * 32, 64)-((wlook(mid).pole - 1) * 32 + 31, 64 + 31)
If wlook(mid).rhead > 0 Then _PutImage (0, 0 + 16)-(31, 31 + 16), part&, tempi&, ((wlook(mid).rhead - 1) * 32, 32)-((wlook(mid).rhead - 1) * 32 + 31, 32 + 31)
If wlook(mid).lhead > 0 Then _PutImage (0, 0 + 16)-(31, 31 + 16), part&, tempi&, ((wlook(mid).lhead - 1) * 32, 96)-((wlook(mid).lhead - 1) * 32 + 31, 96 + 31)
If wlook(mid).chead > 0 Then _PutImage (0, 0 + 16)-(31, 31 + 16), part&, tempi&, ((wlook(mid).chead - 1) * 32, 0)-((wlook(mid).chead - 1) * 32 + 31, 0 + 31)
Case 7, 8
_PutImage (0, 0 + 24)-(31, 31 + 24), part&, tempi&, ((wlook(mid).blade - 1) * 32, 128)-((wlook(mid).blade - 1) * 32 + 31, 128 + 31)
If wlook(mid).handle > 0 Then _PutImage (0, 0 + 24)-(31, 31 + 24), part&, tempi&, ((wlook(mid).handle - 1) * 32, 160)-((wlook(mid).handle - 1) * 32 + 31, 160 + 31)
If wlook(mid).fgard > 0 Then _PutImage (0, 0 + 24)-(31, 31 + 24), part&, tempi&, ((wlook(mid).fgard + 9) * 32, 160)-((wlook(mid).fgard + 9) * 32 + 31, 160 + 31)
Case 9 To 12
_PutImage (0, 32)-(31, 63), part&, tempi&, ((wlook(mid).pole - 1) * 32, 64)-((wlook(mid).pole - 1) * 32 + 31, 64 + 31)
If wlook(mid).rhead > 0 Then _PutImage (0, 0 + 16)-(31, 31 + 16), part&, tempi&, ((wlook(mid).rhead - 1) * 32, 32)-((wlook(mid).rhead - 1) * 32 + 31, 32 + 31)
If wlook(mid).lhead > 0 Then _PutImage (0, 0 + 16)-(31, 31 + 16), part&, tempi&, ((wlook(mid).lhead - 1) * 32, 96)-((wlook(mid).lhead - 1) * 32 + 31, 96 + 31)
_PutImage (0, 0 + 13)-(31, 31 + 13), part&, tempi&, ((wlook(mid).blade - 1) * 32, 128)-((wlook(mid).blade - 1) * 32 + 31, 128 + 31)
If wlook(mid).fgard > 0 Then _PutImage (0, 0 + 13)-(31, 31 + 13), part&, tempi&, ((wlook(mid).fgard + 9) * 32, 160)-((wlook(mid).fgard + 9) * 32 + 31, 160 + 31)
End Select
_Source tempi&
'repaint source image with generate color values for new monster sprite
For y = 0 To 63
For x = 0 To 31
Select Case Point(x, y)
Case kk1
PSet (x, y), wlook(mid).k1
Case kk2
PSet (x, y), wlook(mid).k2
Case kk3
PSet (x, y), wlook(mid).k3
Case kk4
PSet (x, y), wlook(mid).k4
End Select
Next x
Next y
'generated image in tempi& is rendered to ms& as a 32 by 64 sprite
_PutImage (Mx, my)-(Mx + 31, my + 63), tempi&, ms&
_Source ms&
_Dest ms&
_FreeImage tempi&
End Sub
'================================
'PNG file saved using BASIMAGE1&
'================================
Function BASIMAGE1& 'weapon_pieces.png
v& = _NewImage(640, 192, 32)
Dim m As _MEM: m = _MemImage(v&)
A$ = ""
A$ = A$ + "haIkM_ULLLT\504KB\9aV4SeD:=F<Ie?dH\RC`>l?LkBaiJjTIT?ZX[6TjS?"
A$ = A$ + "nhk?000VS?o:oH00h5mmgO6O<0o]ci8nKUm^cfTGo_=gC?oCVoGO=keOh?QK"
A$ = A$ + "WSB?6PoOhnoIKb[oMYo?m0>?km<DI?4g;[Z63Yco?Mmof9hZ6g_KLgCfJOjW"
A$ = A$ + "o#nm0Y73Y\jm9I=8mI`>D3VVKelcjoXRnOfcIoGGeHhIoj:73EWMWTnLOjlW"
A$ = A$ + "\d?kY3[obO^?koH_?YZ17cG?PiZmEG_k#oO[OmnoL5SQWm[OG[oMBjkMFSQd"
A$ = A$ + "eQYjF]?mgoCjeoYWOjeodgiV^gW>d3J7639Vc;E>_gkijIonGeHh\<ClmoFM"
A$ = A$ + "oOgK^FM=X3BOgg=CinV>:MoOYOVCjl?>6BUOjk0BOOK7VoMHOHjj#RikN?PE"
A$ = A$ + "WoSnW[:kD_o]TiW^ng5Mh<o4[k7U^gSdmo=il_Y3iWlNPdWoCO7hTko;mn^M"
A$ = A$ + "EWoSnW[:KmoEOfMAjknVJMo8moU9oenndW1jBnYN78Yoi^Y;eoY=6Bmm_N_a"
A$ = A$ + "#Z\goeEUmcne_ci__fWn>XDBm^__gNQY9mmnjoCoO[cO9oiPGoOcZo_mnnB>"
A$ = A$ + "oC]g;Io7WUMUSQdiOfh8aNPddoGFC^o[d[o[ilanOB>oCWORa#7^oEoOeG3f"
A$ = A$ + "OVo4koCnb_3B?oCVOjkMCgoEjlC_n;olWoj`n_9ekE7bo\NoB]?HbWoTOnlC"
A$ = A$ + ";mON_BnnOBoM?TniOYc?ij_lcVO7nngComOT>oeH8m?kMYoI`;mkO>Efb?oJ"
A$ = A$ + "odn\OM8okmcNbdnn_T_lCn\gdOn[9GoU_lUOnlWHoGYco\O^CBg7jTZobGnM"
A$ = A$ + "iWm[YFoU_lU_lWHnWmcORnoT_l[=Kmo9Oi;Oi;oZcEoObGnjoKZeOi;OiW?o"
A$ = A$ + "dOocC=oSIgQa`dZobGnbGnbGnC=Obbj?0000000000000000000000000000"
A$ = A$ + "0000000000000000000000000000lgU_onchS1POUcU0`Ej[_nWWehi=#O<m"
A$ = A$ + "cS9VoC_V3<;7kocmO#?<mcSYjoKbeLPIiFoO;^k3jQYg;BZiod[k0canko[C"
A$ = A$ + "gm]gKJW6KDW9^fgacSCI=OZeLPIYSmHML<eYa5e_78eW=9mn]^doGbN`l>01"
A$ = A$ + "hjdagoWNoV]cjo_ja#jmMMhlHjg1GjnoL_3<7ClW1^TmoM<kmWi[g_gOgK=n"
A$ = A$ + "\m0GaNQ7mWmY:fkm:iOUS1iOnj\nonej#ja1DUYe3Hb_W]WeoGjg1dEKj?Wi"
A$ = A$ + "EGo_ZJdjOgEW[lkOnMiLIRaAWZ1MH<#>[mREWgDfc]GOkDoOELooSbm:cN_O"
A$ = A$ + "k^]O[jgoEbno>>6>KmYRiOjgoedc_j\_GnEnIOOUl[^nWNnGY7MoGeig]iO5"
A$ = A$ + "eRGYoSZ[oE^?XC[okonEd3hmZoEdKfnl[CWoGSWD?omNmRoWN\Xo?igUnoNf"
A$ = A$ + "Wo9AnEFokfl_C[oC=o[\fO_l[hIoM\nOeejkUoIcaZ>;nOYo_[XgSEF?J]?m"
A$ = A$ + "WoiZkonEGo_ji_noVMnEWmNnM[oW[>KcoO?omkR>>^BFoCWOZmOENnoh_GEm"
A$ = A$ + "0W^o_GIlMUm0n:eo[J_`nlZbemcVo?Zg_4k?ZHLl\n_[Zo3ig_l[^o_SoN9j"
A$ = A$ + "oi\lCdoMjioISS:Wo;We7HUiGQG9oZjoL?_:Z9o=DoOWm:goLEeWcj_Y3com"
A$ = A$ + "J#7fKLU[1Mim?UNm_KcoYlnoNfcg^baamb_ZcoMMnOfNTdco[X?XZOO3o=TO"
A$ = A$ + "U?c[Sco9iN_gQ:oloMMmO2k;fGc?noFe[o9Ze_bl_ZWoW>oZc^kVnk6HO?Bb"
A$ = A$ + "a`Eeo7onJmdg_3hIOYk1Z;iWNM89??\?eQ[jk060nEY__?]dmoT>o^<6BKjc"
A$ = A$ + "o>E7j`H00N_U^gWdigUa0mPm10`4TniMYcohhX;S500h:U^WWdigea200000"
A$ = A$ + "000000000000000000000000l0One?58o_njWVhl?MnZoc^n;Oi;Oi;oIVod"
A$ = A$ + "OnGjiObl_EcGogF`HogH`1GoG[1[eQ8co?bVOjcobOfiOKOObmoYc?MmGnc^"
A$ = A$ + "oWY?oCgog^9=ok#nY_oOUojGGMnY?o;oIWOjcOYWobOfiWniOCOnW>OeOmo]"
A$ = A$ + "f7DeHHoM>GmkQFnIcoXdgoTllgN=?I?X9WkkkoZN<L<o4eQXOo?3^oSdOoWC"
A$ = A$ + "?oO#oOaonO?n>0[bI_ki:_7#nIco\aAUi^TnlGjioJ<TZf?mn_BWOjWoU^o_"
A$ = A$ + "^Lgg4co7doGlnoFk5BUkTonGVDnW]7oAiGaIRYonoVdn?iOR1goWiOnlCGoC"
A$ = A$ + "WOjno>nI`CTOjmOb_^l?kmlLFnE^WLBeo7=6BUM7joNb_oad?o;mkoKbOo[Y"
A$ = A$ + "co7doG\mok?7nMom?Tnm?U>odeoE>_b?oQE^W8icnSOok7c]o?ioAlWoU^o_"
A$ = A$ + "9om_V>oOHhmoMlIREWm:cejnkNoOWeWamjoh:NoCYcoD5_oo\kL^Wg]mObGn"
A$ = A$ + "M;o^ll?co<codiW^nW>odOn_diWlim9jo8MnoV#koS?_oGYOgKYcO]FTL^Ol"
A$ = A$ + "co<YlGS1_o_IfoaIO^o9UOjjO7b?nio?bocNdTol?Yc?mnodiW^nW>oeH8Ef"
A$ = A$ + "Y_oKji?mcOYkocgok\OnCjcoY?o9oiNoG7b?mkO;MnYgo9oIOnOjcOi?klCg"
A$ = A$ + "oGjiOjcoYc?MmOjiWNm?Mn[a#Z\WNn^ogm_bO^iWl?o_MHnWnlOjlCGoWNnY"
A$ = A$ + "OoKYcoV9goEjleoWkOUoLcO]ggio0cm6TOjjodc?mj_lUoT_oIjcOi?klmio"
A$ = A$ + "LokTgoW>od_o]diOcTOoKYcgmo^oEnc=OWoeogTgoW>od[oYcO=6BUmdcgmo"
A$ = A$ + "^oEnc=OWo7ncO7nnodiWnm_U>odkoUo\_oIjcOi?kleoWkOWlnodiWNm?Mn["
A$ = A$ + "a#Z\WNn^ogm_bO^kolWogQolgQOn;MnYOoKYcoV9goEjleoWkOUOfmOMhkOa"
A$ = A$ + "io0cm6TOjjodc?mj_lUoT_oIjcOiWOoGj?o_noLokD?oU>od_o]diWNo_loi"
A$ = A$ + "c0BTOjcOY[oYWobOfkodoGnkOMocLc?mj_lU_noLo[lmnoVJm?mm_^oI^iWn"
A$ = A$ + "lGjmObOfiWnlgdWoC?od[ojocj_kOVKna?oma\oco`dcgkocm_C=oS[mYf3T"
A$ = A$ + "NoWoloZo_YNn_3i[o?i[o_iNoOjioTc_;moimo=gcoYc?MmOji7olg7c^o7i"
A$ = A$ + "7>oQOoOjioTcGoOoLN[o_0cm6TOjjodcGoObOdi?lkoC?oWNnYGoWNnFoWMm"
A$ = A$ + "OjiWNmGnb?jm?#Hfk30000000000000000000d39okN=HBLF30BKmgkfnko7"
A$ = A$ + "X6C_o_^<okbh0PZ]jmCoO#=BnOWSjR><o]>0<I[nnlgmm#=VNO7MHngQa00Y"
A$ = A$ + "LlMoME_o_SokF?VcTWenkeR9G?j`l?Mn0TDEmVMF>j3L6>kcHdUen4m0T^o_"
A$ = A$ + "dmmTNnOL<T\>0#BElnofcBoOcDgjo?E?0Yko9M_?MIn[o?HfVnOV7Z\o_Si]"
A$ = A$ + "g7`RkUOoL_gognN]ZGogcjHnGiHhNI8onTO5koBhMOn1_:mnmJ?Gn?I]nIVl"
A$ = A$ + "mC_c_GRWegOe[o?JlDEo7?[>T:odcoTiOUIgQcf9oI`X3cObY3OW?;MkW3YD"
A$ = A$ + "ePmgoaEGCBOgoaa`S67YF;ZlmOTHne]nolnoToIiOEinXkJZZggDigQioSDM"
A$ = A$ + "nMkmODAnMhnodmO<emo?km<FEnkmoUZnO_mNE]6Deco>[VWHmoNSYcb?Mo7b"
A$ = A$ + "O>moeUgmi4Vo?[6l^goCjlOfhXbcnW]?H:eok=f^Zl_gI^kEKZHM?AoO_jjo"
A$ = A$ + "E^6dYko[JmoAeRcFoCgoQleoGRaPioeUoa<fg[GInC_ocD?okNePSon_SmoM"
A$ = A$ + "F?7E?gNdJNZjoSjmkZko[b?okmb]jm0?K?IU?3jEN>DZlC?oCVORnOFo_WJ^"
A$ = A$ + "GEnMHnoXW1MUiOFOOEVooUahEgoIZl?j\W3m^GokNnE\VoXg1EbiO5mo]Z1g"
A$ = A$ + "k>`[Lng]mEWEWgG3B_7Xbi^l[YoW7m_k:nla?kloEVOjioJ^GMn_jW]8ik7I"
A$ = A$ + "Ri__OHJco^UOENUgobkLmoAOng9\n__?X;ePZf3nXnOTokmnoSgmUN\D]dW["
A$ = A$ + "kdWoUoaD?;0CGgNWTE?_C=gkBnYG7B=gWhckB>_ek70mcD_G>M?#Yb?ml>]Y"
A$ = A$ + ">gC_G?ml70hVdm1Yo?ZNM?mH00X3Bo<aZcG_O00<MYk5:AoOY[i000000000"
A$ = A$ + "000000000000000000000`4Tj_OhGogUXYVObJ?00iO>LjN#VJ?HM9oD[md3"
A$ = A$ + "Cml?iOf3TN?H7^o;M?0C<oSI?mlC\fCNYg3T>oeH8mj`DWkYcWlB_78mM?Om"
A$ = A$ + "eLoN#Gcmdmo<al?>6BT=I]FkWlm?[a#jeRY>gC_fCFY?ogQWoWZ7Xmn?BD3>"
A$ = A$ + ">gWfl?MnkSQZcVlBNoc:oY_o?MfM8Ogo<CYGok`M?joKVmOU>omaAR\9_d_o"
A$ = A$ + "_^doIZjOj\k#nY77CFjeo^LoCR\Cgog:kDePTmoealC?6Z>kDBo<WdiOLLLK"
A$ = A$ + "m?Mn9ko;icOFSQTIW<o9NgCgTNoWnodoG7jmY3iWN<DMfkZ\>T^7\^TOG^o="
A$ = A$ + "eH8MoWCM^O<o4ICnmOMjnWDeNmoeSNOj#nY73EWmBZJ#GVg9c?mjoTc?mcOk"
A$ = A$ + "B]?AfTOoWnodoGGjmY3iWN<DMfg\?oCdoG7Vk9bohjOZiOjmOjo;On9bNEoC"
A$ = A$ + "UM7<in_BW_nojGoGYc?mHXj\CfkGjiN7bOMf?AfMX6<ikog[m9c_jLgG3BUo"
A$ = A$ + "J<T<kYfoEjlCOnGoOm;odSQZc^CmoU^fWhlOW^oEoOcJogal[>gmePDi_639"
A$ = A$ + "c^;WoWFnY?o[o_nUOja#eIWLNgaeo4eod_3bdkoVjmoken9goGbn?BWoDko:"
A$ = A$ + "MnY?o[o?i_?6BUMRiM7ZoYc?mJ#jnOfG3ZLNOfmoYOogYb?ajnnj`Dc_;WoW"
A$ = A$ + "Fnjo;ocoVNnkSQDIWHNgQjOjlGWmCEog[1C9Omom[iWHMOOM8EnC]oWYW_no"
A$ = A$ + "bol_YWonH8Ef9VgMXnWnkn\Cgo>Ymojo;G]oN[3Yb_;WoTOmIgQnoFBol_YW"
A$ = A$ + "OeIgQa#jiodGoWJoGW=oCTMjj_mojoCnc=oSmoU:oYn\W>Toaa`4WoMiiOYF"
A$ = A$ + "kC?6BOogdcOjWodoWlCOn;MoGb?OnCNoGGNnCblCTMGFoWLn[a#jeoTiWnco"
A$ = A$ + "200000000000000000000000000000000000000000000000000000000000"
A$ = A$ + "00000000000000000000000000ekk_olod_?0lWcWohffOEUioeGo^DckTe1"
A$ = A$ + "HJdo70IU^WWZkmkNcMmm1eAoO0TEjNOBfoG7VoDojmObook_]lGokn\mlENF"
A$ = A$ + "#oO0TEjnOVNoO[LWBngkM^FekRMjiOfhh\oi[f:]Wmk10GSdmodQno^UMbn_"
A$ = A$ + "Z\n_WeIiOemol:cogelC_ngYl?f_WNo0NWmZgeVhM0<YolO\G3BeoGbjoIIW"
A$ = A$ + "H?`TkoAnolkk=F_OOne?=\lCOfOO<<]ioDcoA?k9EO?C:O0hSAgoG[b?mjOC"
A$ = A$ + "bgWoFn0#1BoloeHHZiW^ng\lSd7`Tgo9O0VYd?oO=6VJnY[o=;Omo9O0X0YO"
A$ = A$ + "noJ<<elCGoKFnjoCn0#1BoloeHHZiW^ng\leoWl1P2Tnio[a`Dc?Mm_Ai7k?"
A$ = A$ + "30CNoWl10XHncoI`nNU?004AbnOBgoMjl10P9:I_OWmo50000000P?nnoaJo"
A$ = A$ + "%%h1"
btemp$ = ""
For i& = 1 To Len(A$) Step 4: B$ = Mid$(A$, i&, 4)
If InStr(1, B$, "%") Then
For C% = 1 To Len(B$): F$ = Mid$(B$, C%, 1)
If F$ <> "%" Then C$ = C$ + F$
Next: B$ = C$: End If: For j = 1 To Len(B$)
If Mid$(B$, j, 1) = "#" Then
Mid$(B$, j) = "@": End If: Next
For t% = Len(B$) To 1 Step -1
B& = B& * 64 + Asc(Mid$(B$, t%)) - 48
Next: X$ = "": For t% = 1 To Len(B$) - 1
X$ = X$ + Chr$(B& And 255): B& = B& \ 256
Next: btemp$ = btemp$ + X$: Next
btemp$ = _Inflate$(btemp$)
_MemPut m, m.OFFSET, btemp$: _MemFree m
BASIMAGE1& = _CopyImage(v&): _FreeImage v&
End Function
|
|
|
Tough to ID key sequences... |
Posted by: Pete - 12-03-2022, 08:38 PM - Forum: General Discussion
- Replies (4)
|
|
One ID key sequence toggle tough to identify is Ctrl + Ctrl -. It is often used in browser to enlarge or decrease text size.
I love INKEY$ but it is worthless for this one. When Ctrl is held using a PEEK routine to identify it, the + and - keys simply do not get picked up by INKEY$. Now with Windows API we can accomplish this with...
Code: (Select All) CONST VK_CONTROL = &H11
CONST VK_OEM_PLUS = &HBB
CONST VK_OEM_MINUS = &HBD
CONST VK_ESCAPE = &H1B
DECLARE DYNAMIC LIBRARY "User32"
FUNCTION GetAsyncKeyState% (BYVAL vkey AS LONG)
END DECLARE
DO
_LIMIT 30
IF GetAsyncKeyState%(VK_CONTROL) AND GetAsyncKeyState%(VK_OEM_PLUS) THEN
PRINT "Ctrl +"
END IF
IF GetAsyncKeyState%(VK_CONTROL) AND GetAsyncKeyState%(VK_OEM_MINUS) THEN
PRINT "Ctrl -"
END IF
LOOP UNTIL GetAsyncKeyState%(VK_ESCAPE)
But what about x-platform methods?
Well, here is my shout out to _KEYHIT using Ctrl+ and Ctrl- to change font sizes...
Code: (Select All) SCREEN 0
fontsize% = 16
style$ = "monospace"
fontpath$ = ENVIRON$("SYSTEMROOT") + "\fonts\lucon.ttf"
DIM font(8 TO 32) AS LONG
FOR i = 8 TO 32 STEP 2
font(i) = _LOADFONT(fontpath$, i, style$)
NEXT
_FONT font(fontsize%)
ww = 600: wh = 350
WIDTH ww \ _FONTWIDTH, wh \ _FONTHEIGHT
PALETTE 7, 63: COLOR 0, 7: CLS
_FONT font(fontsize%)
_SCREENMOVE 0, 0
PRINT "Press ctrl + to increase font size or ctrl - to decrease."
DO
_LIMIT 30
c = _KEYHIT
IF c THEN
SELECT CASE c
CASE -189
IF fontsize% > 9 THEN fontsize% = fontsize% - 2: resizeit fontsize%, ww, wh, font()
CASE -187
IF fontsize% < 31 THEN fontsize% = fontsize% + 2: resizeit fontsize%, ww, wh, font()
END SELECT
END IF
LOOP
SUB resizeit (fontsize%, ww, wh, font() AS LONG)
_FONT font(fontsize%)
fw% = 0: fh% = 0
DO
fw% = _FONTWIDTH: fh% = _FONTHEIGHT
IF fw% <> 0 AND fh% <> 0 THEN EXIT DO
_DELAY .1
LOOP
WIDTH ww / fw%, wh / fh%
PALETTE 7, 63: COLOR 0, 7: CLS
_FONT font(fontsize%)
DO: LOOP UNTIL _SCREENEXISTS: _SCREENMOVE 0, 0
PRINT "Font size changed to:"; fontsize%: PRINT: PRINT "Window width:"; _WIDTH
_KEYCLEAR
END SUB
Pete
|
|
|
Day 023: INKEY$ |
Posted by: Pete - 12-03-2022, 07:18 PM - Forum: Keyword of the Day!
- Replies (1)
|
|
INKEY$ is one of several methods to communicate with the keyboard. Others are _KEYHIT, _KEYDOWN, INP(), PEEK and POKE, and for Windows users, the function GetAsyncKeyState%.
So why is INKEY$ so much better than those other choices, why because I code with it, of course!
Well, my comedy bit aside, INKEY$ is comfortable for me because it has easily recognized key associations, by string representation of ASCII values.
Terminate loop with the Esc key example...
Code: (Select All) DO
_LIMIT 30
LOOP UNTIL INKEY$ = CHR$(27) ' The string character for ASCII code 27.
Since INKEY$ functions as a string, unlike the other alternatives, we need recognize a string is true or false by being either filled or null.
Terminate loop with press almost any key...
Code: (Select All) DO
_LIMIT 30
LOOP UNTIL LEN(INKEY$) ' Loop exits when INKEY$ is no longer null, (e.g. INKEY$ = "").
I find the best way to set up a keyboard poll routine is by assigning a variable to INKEY$...
Code: (Select All) DO
_LIMIT 30
mykey$ = INKEY$
IF LEN(mykey$) THEN
SELECT CASE mykey$
CASE CHR$(27)
PRINT " INKEY$ CODE: CHR$(27)"
EXIT DO ' Escape loop to end program snippet.
CASE ELSE
show_Values (mykey$)
END SELECT
END IF
LOOP
SUB show_Values (mykey$)
SELECT CASE LEN(mykey$)
CASE 1
b = ASC(mykey$) ' ASC() converts a string character to a numeric value.
a$ = ""
CASE 2
b = ASC(MID$(mykey$, 2, 1))
a$ = "CHR$(0)" ' This is the nul character INKEY$ reports for 2 byte length key representation like the F1 - F12 keys.
END SELECT
b$ = LTRIM$(STR$(b)) ' This is how you convert a numeric variable to a string variable.
PRINT " INKEY$ CODE: ";
IF LEN(a$) THEN PRINT a$; " + ";
PRINT "CHR$("; b$; ") "; "AKA: " + CHR$(34) + CHR$(b) + CHR$(34) + " ";
END SUB
"...press almost any key." WTH is that???
Well, INKEY$ does not register for certain keys like...
Shift
Ctrl
Alt
Fn
Windows key
PrtScr
NumLock
Capslock
These keys need to be referenced in some other either supportive method or via a different key recognition keyword like _KEYDOWN.
An "old school" method I love, and successfully lobbied for 15+ years ago, is the supportive method of using PEEK addresses.
This routine identifies if Alt, Ctrl, or Shift keys are held down while other keys are pressed...
Code: (Select All) _CONTROLCHR OFF ' Allows us to key input combinations that would otherwise adversely affect screen output.
DO
_LIMIT 30
DEF SEG = 0
IF PEEK(1047) MOD 16 = 1 OR PEEK(1047) MOD 16 = 2 THEN
KeyCombos = 1 ' Shift
ELSEIF PEEK(1047) MOD 16 = 3 OR PEEK(1047) MOD 16 = 4 THEN
KeyCombos = 2 ' Ctrl
ELSEIF PEEK(1047) MOD 16 = 5 OR PEEK(1047) MOD 16 = 6 THEN
KeyCombos = 3 ' Ctrl+Shift
ELSEIF PEEK(1047) MOD 16 = 7 OR PEEK(1047) MOD 16 = 8 THEN
KeyCombos = 4 ' Alt
ELSEIF PEEK(1047) MOD 16 = 9 OR PEEK(1047) MOD 16 = 10 THEN
KeyCombos = 5 ' Shift+Alt
ELSEIF PEEK(1047) MOD 16 = 12 THEN
KeyCombos = 6 ' Ctrl+Alt
ELSEIF PEEK(1047) MOD 16 = 14 THEN
KeyCombos = 7 ' Shift+Ctrl+Alt
ELSE
KeyCombos = 0
END IF
DEF SEG
mykey$ = INKEY$
IF LEN(mykey$) OR KeyCombos THEN
SELECT CASE mykey$
CASE CHR$(27)
PRINT " INKEY$ CODE: CHR$(27)"
EXIT DO ' Escape loop to end program snippet.
END SELECT
show_Values mykey$, KeyCombos
END IF
LOOP
SUB show_Values (mykey$, KeyCombos)
STATIC OldKeyCombos
IF KeyCombos = OldKeyCombos AND LEN(mykey$) = 0 THEN EXIT SUB ' Neat trick to only print once to screen while PEEK discovered keys are held down.
DO ' Falx loop to avoid printing INKEY printing if only a non-INKEY$ is held down.
SELECT CASE LEN(mykey$)
CASE 0
EXIT DO
CASE 1
b = ASC(mykey$) ' ASC() converts a string character to a numeric value.
a$ = ""
CASE 2
b = ASC(MID$(mykey$, 2, 1))
a$ = "CHR$(0)" ' This is the nul character INKEY$ reports for 2 byte length key representation like the F1 - F12 keys.
END SELECT
b$ = LTRIM$(STR$(b)) ' This is how you convert a numeric variable to a string variable.
PRINT " INKEY$ CODE: ";
IF LEN(a$) THEN PRINT a$; " + ";
PRINT "CHR$("; b$; ") "; "AKA: " + CHR$(34) + CHR$(b) + CHR$(34) + " ";
EXIT DO
LOOP
IF KeyCombos THEN
SELECT CASE KeyCombos
CASE 1
PRINT " Shift Down";
CASE 2
PRINT " Crtl Down";
CASE 3
PRINT " Shift + Ctrl Down";
CASE 4
PRINT " Alt Down";
CASE 5
PRINT " Shift + Alt Down";
CASE 6
PRINT " Ctrl + Alt Down";
CASE 7
PRINT " Shift + Ctrl + Alt Down";
END SELECT
OldKeyCombos = KeyCombos
END IF
PRINT
END SUB
Cool, right? Well, not so fast there Sparky, there is a drawback. We can only read 3 key inputs at a time. Hold Shift + Ctrl + Alt then press "A" and just like I stated, the 4th input, "A" won't get printed. INP() won't help here either, and interestingly enough, although _KEYHIT and _KEYDOWN can handle most 3 key combinations, I noted some arrow combos and others were not registered when trying to get that technique to work. WinAPI can recognize some but not all 4+ multiple key presses. Fool around with some keys in this example if you have a Windows System. Hold Shift+Ctrl+Alt and try some arrow keys etc to see which ones show up for INKEY$. Some will, some won't, but those are all 4 key press events with this INKEY$ helper.
The only key I set to register in the alphabet is "A" so try Shift+Ctrl+Alt+A to see them all register. Oh, if you fooled with the code to try and get A+B+C+D to register, it would only register A+B+C.
Code: (Select All) CONST VK_SHIFT = &H10 'SHIFT key
CONST VK_CONTROL = &H11 'CTRL key
CONST VK_MENU = &H12 'ALT key
DECLARE DYNAMIC LIBRARY "User32"
FUNCTION GetAsyncKeyState% (BYVAL vkey AS LONG)
END DECLARE
DO
_LIMIT 30
a% = GetAsyncKeyState%(VK_SHIFT)
b% = GetAsyncKeyState%(VK_CONTROL)
c% = GetAsyncKeyState%(VK_MENU)
d% = GetAsyncKeyState%(&H41)
SELECT CASE a%
CASE 0
CASE ELSE
PRINT a%
END SELECT
PRINT a%, b%, c%, d%, INKEY$
LOOP
So what else can we say about INKEY$? Well, it can be used in combination with other keyboard keywords. Maybe not good practice, but just saying it's workable.
INKEY$ stores key presses in a buffer. You can use _KEYCLEAR to clear that buffer. Some programs need this to stop users who press keys during a program pause from being used in the routine. SLEEP is actually a very simple example...
Code: (Select All) SLEEP
IF LEN(INKEY$) THEN BEEP ' Will Beep
SLEEP
_KEYCLEAR
IF LEN(INKEY$) THEN BEEP ' Won't beep.
A bit more involved example of the buffer uses a delay to slow the typing output to the screen. With the buffer, Demo 1, the output catches up after you are done fast typing. In demo 2, _KEYCLEAR clears the buffer and the utput stops the moment the user stops fast typing.
Code: (Select All) PRINT "Demo 1: Buffer will catch up to your typing. Press Es when ready for demo 2..": PRINT
LOCATE , , 1 ' Let's show the cursor for these typing demos...
' That third LOCATE parameter of 1 gives us the underline stype cursor.
' See the LOCATE Keyword of the Day for other cursor appearance options).
DO
_LIMIT 30
mykey$ = INKEY$
IF LEN(mykey$) OR KeyCombos THEN
SELECT CASE mykey$
CASE CHR$(27)
EXIT DO
CASE ELSE
IF LEN(mykey$) = 1 THEN
PRINT mykey$;
_DELAY .25
END IF
END SELECT
END IF
LOOP
PRINT: PRINT: PRINT "Okay, demo two. The printing to the screen stops the moment you stop typing.": PRINT
DO
_LIMIT 30
mykey$ = INKEY$
IF LEN(mykey$) OR KeyCombos THEN
SELECT CASE mykey$
CASE CHR$(27)
EXIT DO
CASE ELSE
IF LEN(mykey$) = 1 THEN
PRINT mykey$;
_KEYCLEAR
_DELAY .25
END IF
END SELECT
END IF
LOOP
On a final note, my beloved INKEY$, as stated previously, can't do everything. For instance say you want to use Ctrl + and Ctrl - to resize text, just like browsers. Well, we can't do that with INKEY$, but we can use _KEYHIT or Win32 API. An example of each is provided here: https://qb64phoenix.com/forum/showthread.php?tid=1230
Pete
|
|
|
Remainder(n, d) Better than MOD, same as capping wrapping? |
Posted by: bplus - 12-03-2022, 05:22 PM - Forum: Utilities
- Replies (13)
|
|
Break this?
For ideal modulus, I imagine it should be between 0 and the divisor = modulus whether divisor is pos or negative.
I read johannhowitzer Wrapping, capping and other... and it all fell in place what we are trying to reach, keeping numbers between 0 and the divisor whether integer or float like Pi, we just want a proper remainder.
Code: (Select All) _Title "Remainder test" ' b+ for a modulus that always returns a number between 0 and divisor
' if divisor is negative then return a rational between 0 and some rational d < 0
' if divisor is positive then return a rational between 0 and some rational d > 0
' if divisor is 0 ? can't divide by 0
' Do we need to round? Doesn't look like it but I just ran a couple quick tests. Folks here can find fault with anything! ;-))
' NOTE: when testing don't leave space between , and d eg, do 5,3 not 5, 3
$Console:Only
Do
Input "0's quit, please enter n, d to find remainder n/d between 0 and d "; n, d
If (n = 0) Or (d = 0) Then End
Print Remainder##(n, d)
Print
Loop
' modeled on MODn
'ref Pete https://qb64phoenix.com/forum/showthread.php?tid=1195&pid=10983#pid10983
Function Remainder## (n##, d##)
If d## = 0 Then Exit Function
Remainder## = n## - (d##) * Int(n## / (d##))
End Function
BTW best toggle I've seen and used often from Chia Pet:
toggle = 1 - toggle
|
|
|
Wrapping, capping, toggling, and slicing, oh my! |
Posted by: johannhowitzer - 12-03-2022, 11:24 AM - Forum: One Hit Wonders
- Replies (4)
|
|
Who knows, maybe everyone out there is already using these things in some form,
but I use them EVERYWHERE and maybe someone will enjoy them! They're just simple
and common ways to manipulate values, but they will replace multiple lines of code
and make said code much easier to understand at a glance.
Code: (Select All) function wrap(n, l1, h1) ' n is adjusted back within lower(l) and upper(h) bounds similar to mod operator
l = l1: h = h1 ' make sure h is never less than l, this also prevents division by zero
if h1 < l1 then
l = h1: h = l1
end if
x = (l - n) / ((h - l) + 1)
if x <> int(x) then x = x + 1
wrap = n + (int(x) * ((h - l) + 1))
end function
This first function wraps a value between two values. You pass n, and if it's beyond one
of the bounds, it wraps back around. So say you have five menu options, and the user moves
the cursor to position 6, this will wrap it back around to 1. Going to 0 will also wrap around
to 5. It doesn't matter how far outside you go, and negatives are treated properly, so -256
in this example will get wrapped correctly to 4.
The bounds can be in any order, and n is usually going to be a simple addition or subtraction.
So in the case of the above menu example, [wrap(cursor + 1, 1, 5)] will move the cursor, with
the check to wrap around. And in most menu navigation scenarios, wrapping is super nice for
the user. So you can write the following:
if [input] = [up arrow] then cursor = wrap(cursor - 1, 1, [max])
if [input] = [down arrow] then cursor = wrap(cursor + 1, 1, [max])
You could also use this to wrap coordinates, so the player can leave the right side of your
stage and emerge on the left, like the Pac-Man tunnel, or create a seemingly infinitely scrolling
stage, like Asteroids, which really just repeats on itself. For the latter example, you would
wrap the coordinates of objects whenever they travel beyond the stage, and also wrap the
coordinates to within a range around the player's position, when using them to draw the screen.
The result will appear seamless, and it won't matter how fast things travel each frame.
Code: (Select All) function wrap_a(a) ' angle a is adjusted back within 0 and 2pi, noninclusive of 2pi
x = -a / atn1(8)
if x <> int(x) then x = x + 1
wrap_a = a + (int(x) * atn1(8))
end function
function atn1(n)
atn1 = n * atn(1)
end function
This does exactly the same thing, but for angles. Put any angle value in this function,
and it will simplify it to a positive angle less than a full circle. Very useful when
angle values can get adjusted over and over. Just put the function around any angle changes.
(Note that the little atn1() function is just a shorthand thing, I got tired of typing
n * atn(1) in a ton of places. It generates an angle in radians, where the value passed in
is an eighth of a circle or 45 degrees, so atn1(8) = 2 * pi radians, or 360 degrees.)
Code: (Select All) function plus_limit(n, p, l) ' p is added to n, but can't go past l in the direction of travel
q = n + p
if sgn(q - l) = sgn(p) then q = l
plus_limit = q
end function
This saves a lot of space capping values, and is direction-dependent. If p is positive,
n can't go past l upward; if p is negative, n can't go past l downward. I use this for many
things, like decaying values without going below zero, capping healing at maximum health,
trapping position coordinates at the edges of the screen, the uses are endless. The syntax
is very clean, all packed up in one line, it replaces stuff like this:
health = health + 100
if health > max_health then health = max_health
with this:
health = plus_limit(health, 100, max_health)
The directional dependency of this is more useful than you might think at first glance,
and is a feature that simple floor and ceiling functions don't have. For example,
you can use sgn() comparison to move something toward a goal value, and stop it if it
reaches the goal, but not snap to the goal if moving away from it.
Then you might use something like this:
x = plus_limit(x, sgn(goal - x) * speed, goal)
This can be very useful in having one value that changes instantly, and another that
constantly follows it. In my current game project, one way I use this is to give visual
feedback about damage that was just taken. If the player gets hit, the health is instantly
lowered, so the green health bar gets shorter. But there's a hidden second red bar behind
it, and that red bar's value follows the health value. If you gain health, this does
nothing, since the red bar will be shorter, but when you LOSE health, the player will see
part of the health bar become red, and instantly start shrinking, until all that's left
is the green part.
Do note that because of the dependency, if for example you are subtracting, this function
won't catch a value that was already higher than it should be. So be careful.
Code: (Select All) function toggle(v, p, q)
toggle = v
if v = p then toggle = q
if v = q then toggle = p
end function
This one just toggles between the given values. However, it will not do anything
if the variable passed is not one of these two values. Use like v = toggle(v, value1, value2).
Replaces the messier [if v = value1 then v = value2 else v = value1]. And since it's a function,
you can use it very compactly and dynamically, rather than directly manipulating variables.
Let's say you have a 1v1 RPG combat scenario, and one of the characters decided to attack.
You've calculated the damage already. So instead of:
if turn = char1 then target = char2 else target = char1
call damage_char(target, damage)
You can write:
call damage_char(toggle(turn, char1, char2), damage)
Think of it like the binary NOT operator, except this works between any two values you want.
Code: (Select All) function before$(t$, c$)
p = instr(t$, c$)
if p = false then p = len(t$) + 1
before$ = left$(t$, p - 1)
end function
function after$(t$, c$)
after$ = right$(t$, len(t$) - instr(t$, c$) - (len(c$) - 1))
end function
function between$(t$, c1$, c2$)
between$ = before$(after$(t$, c1$), c2$)
end function
These functions are used for slicing strings, which has been useful in developing my own scripting,
among other things. before$ will return everything in t$ before the first instance it finds of c$,
while after$ will return everything after it. If c$ is not found, it will simply return t$ unchanged.
An interesting application of this is to return more than one value from a function. For example,
if you want a function to return both x and y coordinates, you can make the function's return data type
a string, pack the two values up with a comma between like "100, 50", then use before and after
functions with val() to pull the values apart outside the function. You can also easily do this
for three-dimensional coordinates. And it need not be limited to coordinates, you could also use
a separator character to return multiple strings packed into one string, like "Alice|Timothy|Eric".
between$, of course, just cleans up the syntax when using before$ and after$ together, which often
happens in my code. This:
result$ = before$(after$(t$, "["), "]")
Becomes this:
result$ = between$(t$, "[", "]")
|
|
|
Data setting tutorial video! |
Posted by: johannhowitzer - 12-03-2022, 11:18 AM - Forum: Learning Resources and Archives
- Replies (6)
|
|
Is your code filled with blocks of variable setting or DATA statements? Is code you wrote years ago now indecipherable to you as a result? Suffer no longer! Table routines and abstraction are here to save the day.
This tutorial video isn't really QB64 specific, but hopefully people will get some mileage out of it, and find ways to make their code clearer and less bulky.
|
|
|
|