QB Express

Issue #8  ~  March 17, 2005

"A magazine by the QB community, for the QB community!"

In This Issue



From The Editor's Desk

Written by Pete

Absolutely incredible. I didn't think we could do it, but we've managed to top last month's mammoth issue (with no less than 11 tutorials) and put together THE BIGGEST QB EXPRESS ISSUE EVER. This issue is simply gigantic. It's got the most articles ever printed in this magazine (TEN tutorials, plus SEVEN articles, plus NINE "regular columns") -- that's TWENTY-SIX separate articles this month. Not to mention that the News Briefs section is also the largest we've ever published. This issue is not only the largest issue of QB Express to date, but the largest issue of any QB magazine ever created. Period.

But it's not only big, it's also has some of the best, most high-quality content we've ever published. The caliber of the articles and tutorials this month is simply impeccable. The contributors to this magazine do truly stupendous work. I can't rave about it enough.

Anyhow, I'm not going to bother doing a summary of what's in store for you this issue like I do normally, partly because it's already been delayed, but mostly because it's so darn big that it would take me too long to type it all up. I'll just tell you this much: you're gonna like it.

Enjoy!

Submit To QB Express

You all know the drill. This magazine can't exist without people SUBMITTING articles, editorials, tutorials, reviews, news and feedback. This is not just a solo effort by me... it's a group effort by people throughout the QB community. If you have anything to submit, or have time to write something, DO IT!

If you want to write about something, but can't think of a topic, or need inspiration, email me! I'm good at thinking of stuff to write about, and I know quite a bit about the QB community and about QB programming. If you're interested in getting your own monthly column or just want to write an article or two, by all means, do it! Anything that is submitted will be included!

I also want feedback and letters to the editor regarding this magazine. I want suggestions and critiques. What do you like? What don't you like? What could be done better? Let me know!

All submissions and feedback can be sent to pberg1@gmail.com. You can also PM me on the Pete's QB Site or QBasic News message forums, or send feedback through this form. If QB Express is going to continue to be so good, YOU need to contribute!

-Pete



Letters

Letter From King Krayz

Hi, how are u doing? My name is Harry but all my friends call me King Krayz. Im 28 and im a US Marine who before joining owned my own (very small) programming company. I ve recently tried to start programming again sort of as a hobby but was horrified at the prices for some of these languages; moreover, they all seemed to be depended of Windows platforms.

Not that I have a problem with windows long live bill gates, I guess it's somewhat the American way. Steal an idea and make it better then sell it for more. So I figured I will rebel. Go back to my beginnings. Old basic. Hmmm. Well at least qbasic anyway.

Overall I guess I am an intermediate qbasic programmer with a lot of advance ideas. But do to my limitations as a programmer in qbasic and the language s limitation I ve fled to the web for help. I've never found more broken links in my life.

Finally after many hours of searching I found my answer for one of my silly projects in the form of ASM programming. But to me it felt like an easy way out. I think if you have to result to another programming language to get a task done, not necessarily because it would be easier but because there is no other way then you ve out grown your language. But how could this be, I'm just an intermediate programmer. Did qbasic already let me down? Or did Microsoft let Qbasic down?

During that same search I came across and article about designing your own compiler for qbasic or other type languages but did not bothered reading it because again just an intermediate programmer. However it came to me what is wrong, qbasic is well overdue for an evolution (of cause I m sure programmers who have been programming in qbasic has come to this but this is about my awakening or felt vb is the answer).

So here I am, making my own compiler. Taking Qbasic where I feel it should be. Then it hit me, first who am I who just started up in the language to be the one to give it a face lift. After all, I'm sure there are thousands of qbasic programmers who like me had to find ways around the language to get a task done who would have great and better ideas. Rather war stories about their programming battles and how the language could be better, then a sad realization hit me. Lol I think I would be the only one to ever use my new compiler.

Anyway I m still going to stick with it after all it is my hobby and I believe in the project so I figured I would send this email to some of the great basic sites and to some programmers whose code impressed me.

Any help in the project would be greatly appreciated and full created given. I am broke and even if this project is a success I don't see any money value from it. It would be more for the programmers.

Starting this email I did not know what I would say but reading back I guess I had plenty to say after all; so, I will not bore you any more. If you are interested please read on else thank you for your time and have a great day.


If you have decided to help or at least read on then I thank you in advance. The way I've started to go with the project is like this, I'm trying to turn qbasic into a true text bass object oriented programming language but keeping the emphasis on basic. Hmmm. Believe it or not, that's the easy part.

Some of the other things I m trying to do is although I m designing a whole lot of new keywords I realize that sooner or later I will have to use ASM as a user of my compiler. So I m trying to implement in-line assembly as well as better graphic functions and some Internet functions.

Going through the Internet I found a lot of cool small subs and functions that improved or speed up or made programming in qbasic easier and I thought to my self they should ve been included. And the one s that are free domain I will use again keeping the emphasis on basic.

Anyway that is my project to create a, hopefully better, new qbasic using c++, asm and nifty qbasic programming.


The major problems I m having so far are these:

  1. Errors at the compiler level since I would have to generate these errors on the users syntax and on every thing else the user inputs this is way beyond my scope of programming. Realistically this is at the heart of a good compiler.
  2. Help files this really sucks, most of the info is already written but implementing them into my compilers gui
  3. Implementing in line assembly in my world I don t see what the problem is , I see no problem for in-lining ASM or c++ however asm for qbasic is a new concept for me and I don t know enough about it, and how it relates to qbasic or on my own generating the proper code to utilize in my own cold thank god for cut and paste .
  4. IM leaning towards leaving behind qlb for dll files as well as keywords: goto, screen or at least most of them and about three others. I just don't know what a seasoned qbasic programmer would feel about it.

Well I guess that's it for now again thank you for reading this any help would be appreciated.

----King Krayz

Sounds like a very ambitious project! I wish you luck.

But...Your project sounds very similar to V1ctor's FreeBasic, which has been taking the QB world by storm for the last few months. If you haven't heard of FreeBasic, you should really check it out. It's a Windows32 compiler that is compatible with QB-format code, and it gets rid of many of the limitations of QB such as memory and screen mode issues. It's basically exactly what you're trying to make, from the sounds of it.

I suggest instead of going commando and trying to build your own compiler from the ground up, you join forces with V1ctor and other FB contributors like lillo and DrV to help make the FreeBasic compiler even better.

But if you still want to create your own compiler, I don't want to discourage you. In fact, I wish you luck!

-Pete

-Pete

Letter From Lurah

Hi and once againg, thanks for another exellent issue you made. And also a big thanks for other contributors. Many so great articles and stuff.

Is QB dying conversation keeps going. Is DOS dying seems to be another subject that is "hot".

QB lives as long DOS lives. DOS lives as long ASCII and low level graphic programs lives. ASCII and low level programs lives as long DOS lives...endles loop? =)

In last issue you said;

"People who have been raised with modern computer systems have a whole lot less tolerance for the simplistic graphics and gameplay characteristic of QBasic. There's no way you're going to change that. That's the way it is."

Thats true. Man (or woman) who buys computer to play NFSU2, HALO2 etc. games probably arent curious about what happens on DOS and QB scene. Well, mostly they dont even know what those "wierd" things are. Well, NFSU2 and HALO2 are great games to play and watch. =) Do i want to use Gb´s of HDD space for them or is there good story line etc, is matter of opinion.

Any way, one of my friend collects a stamps. Gee, collects a stamps? I just dont get it. Why it´s so great to collect stamps? He has a 9 huge books full of stamps and he wants more. I just dont get it.

Well, he doesn't understand why I still code ascii game with QBasic, so I guess we're "even". =)

QBasic ain't dying. Lots of peoples will forget it and probably at year 200?, there are only a few hundred QBers. So what?

It´s still alive, and those few hundred QBers still loves and enjoys to work with it.

So maybe we all should be shut up, what comes at subject "is QB dying"? Well, I'm goin to do so for now on :)

So what happens for most QBers? Many seems to move on FreeBasic. Maybe some ones starts to work with CoolBasic or with other (variable)Basic´s.

But even then, arent we still one big "basic family"? =)

That´s all for now.

R.lurah

Käyhän piipahtamassa---> www.lemmikkini.net

I'll guarantee you one thing: BASIC will never die. Every few months, new and improved dialects of Basic (such as FreeBasic) are released, and they each gain a large community of users, both people who have moved on from previous versions of BASIC and brand new users. Right now, FreeBasic is ensuring that the QB syntax will stay alive for many more years to come.

Now as for if QBasic is dying, I still have to stick with my original view on this issue: yes it is. Like you said in your email, the number of QB users is dropping from thousands and thousands to only a few hundred. The number of new QB releases these days has slowed down so much that it's almost reached a standstill. The number of new QB sites that appear is just a handful, compared to in 1998 or 1999 when dozens of them would spring up every year. So to me, that constitutes "dying".

Maybe we're just confusing words and meanings here. You said it yourself that there would only be a few hundred QBers. To me, if there are just a few hundred users, that seems more like beating a dead horse than being an active, thriving programming language. There will always be people that use QB, but it's not like they will be doing much of anything significant with it.

I hate to take the pessimist's viewpoint, but I just have to admit it: the QB part of the QB scene is in serious decline. I'm one of the biggest QB advocates I know of, but I'm just facing the facts. And if Microsoft continues its disregard for DOS legacy support in its next few operating systems, which I'm sure will happen, it will cut down the number of users even more.

Luckily, the "QB community" is nowhere near dying. In fact, it's having one of the biggest booms ever because of FreeBasic. So don't worry about the Qmunity disappearing off the face of the earth. I'm pretty damn sure that there will be the Qmunity in some form for damn near forever. :)

-Pete

Letter From Stéphane Richard (MystikShadows)

Hi Pete,

Well the title says alot here ;-). (Ed: the subject of this email was "QB Express #7 - Absolutely Amazing".) Wish I could quickly find a picture of some award and paste it but I can't...but you sure do deserve it (along with all contributers). Like you said, sad to say but QBasic is dying, I agree with Nate's letter in that DOS will live on, for the reasons he mentions and for the ones you mention and let's not forget that FreeBasic is now DOS 32 bits capable (big plus for THIS DOS lover).

This letter is basically to comment on the letter from Lachie, and comment on your comment to the letter from lachie ;-). I have to say I like your way of seeing it and I approve. Like you said this is a volunteer based magazine. And I think anyone who volunteers should be valored at least a bit for daring to submit their writing skills to the likes of people like Lachie (no offense Lachie) but it is, like you said, critics like this one that makes or breaks the authors. I guess it depends on the point of view, but I found Nathan's article absolutely crystal clear and easy to follow Maybe you should start splitting your magazine into different levels of submissions or something or perhaps a glossary of terms to allow to quickly lookup terms we've never seen before might be a good idea :-). But I think categorizing things a bit might help especially if each upcoming issues keeps on growing like they do. It's good to see though, and I'm not complaining at all about having more to read each issue :-) and I never will.

I also noticed that you talked about my upcoming IDE :-) I know I announced it before, I had to put that project on the back burner a bit (to complete a few other things) but as you've seen by that post that you provided, I've went back to developing the ide and things are moving well. I added a few things to the TODO list before I release it. But one by one I'm getting things solved and read for beta release (which should be in weeks to come, maybe I'll sync myself to your next issue for the big announcement :-). we'll see how much time I have I'll keep you posted about that.

Again, one issue outdoes the past issues and I for one have nothing bad to say about it except maybe that I want EVEN BIGGER issues to read, I just can't get enough of it. (I'm about to replace my coffee with articles from QB Express here for crying out load LOLOL)....Nah don't think that will ever happen but it should tell you how much I appreciate the contents of each issue, the things I've learned from each of them and the things that are left to be written (God knows there so much to write about).

I must say that seeing so much activity on the FB side is a very refreshingly good surprise (well not much of a surprise really, since we know the impact FB has) but very refreshing to see.

Keep up the good work, I think I know what I'll do for my 3 part on file manipulation, not what we talked about but I think a good logical next step to Random Access Files, expect that in for the next Issue :-).

MystikShadows
Stéphane Richard

Thanks for all the positive comments!

As for Lachie's letter about excluding "crappy" content, you guys all know where I stand on that issue. (If not, check the letters section of Issue #7.) This is an "open" magazine written by volunteers, for a community, and I'll take anything that has any value whatsoever.

BUT: I'll be the first to admit that some of the content we publish in QB Express is of less quality than other stuff. Nathan1993's tutorial is a perfect example of that. It seemed rush, was unclear in parts, and didn't cover an area of QB programming that a lot of people are itching to learn (or don't already know). It was far lower quality than, say, Na_th_an's IF tutorials -- I'm not going to argue that point. And I guess you disagree with me, because you said Nathan's tutorial was "absolutely crystal clear and easy to follow". :)

Anyway, there's no arguing that the articles in this magazine are uneven in quality. But I think taking out anything would be a detriment to the mag. Bottom line: if you don't like an article, don't read it. Nobody's forcing you.

-Pete

Letter From MagnaUnum

Great issue Pete. It's good to see the whole range of articles and skill levels. Granted, it's about Freebasic, but a comprehensive article on Data Structures is something I don't think I've ever seen in a qb zine before. Congrats are in order to Na_th_an for that. Good to see some old names still floating around too. Everytime I read one of these (always at work, haha) I get closer to finally sitting down and starting up a career in freebasic myself. If only there were more time in the day. Good luck everyone!

MagnaUnum

You're right, tt's great to hear from "old names" from the Qmunity of old -- like yourself! Long time, no see, man. I'm glad you're contemplating coding in FreeBasic yourself. Now if only all the rest of the talented old QB programmers (I'm looking at you, NeoBasic) would give FreeBasic a shot, we'd see a whole lot amazing stuff coming out on the FB scene.

-Pete

Letter From Robin de Graaf

However corny this might sound, I want to thank and encourage you in your recent undertakings. I only recently found out you'd started updating your website again, and the magazine was quite the welcome surprise. I've been away from the 'Qmunity' since, well, ages. I doubt many of the people still remaining even remember me (well, nodt probably does, the bugger) but even that couldn't stop me from reading all the issues in a row and smiling at all the memories and good times I had back then.

I've never been a big help to the community - as my QB skills are below sub-zero. But I've managed to get decent at a number of other things, amongst which are PHP, webdesign and database design. What I want to mention, well, more, offer.. Is the following.

Zext.net was supposed to close down, but it didn't. Not entirely, anyway. The thing I'm willing and more than able to offer to those interested is hosting. I am offering free webhosting under a subdomain, with email, php, mysql, cgi, and almost anything else they'd want (amongst which is tomcat), without any form of advertising (thus no banners) or any kind of forced linkage.

No expectations from my side other than the future hostees being good netizens and not abusing my offer by uploading, say, quake 3 or any other form of illegal files.

For inquiries about hosting, interested parties can simply drop me an email at voh@hostvoh.net, at which I'm always available.

And to show that I do have links with the QB community, I've been hosting wafn and wolverian since around 2000, have worked with nodt on a couple of sites, have inspired him to do a game based on an off idea I had, and I've got FreeBasic installed as we speak :)

Vohaul aka NightHawk aka Robin de Graaf

Webdeveloper/Hoster of hostvoh.net, danwa.net, in business since 2000.

Free independent hosting rocks. I can't even count how many QB sites have been lost because they were hosted on a crappy, money-grubbing free host like Xoom.com, Tripod, FortuneCities, Hypermart, FreeYellow, etc. Plus the hosting is filled with ads and sub-par to begin with. So providing quality free hosting to the Qmunity is definitely one of the best things you can do for it. Now that Marcade's Zext.net is gone, I'm glad you've stepped up to the task!

Webmasters: If you're interested in taking advantage of Robin's free hosting, check out this article the News Briefs section for more details.

-Pete

Letter From BazookaSquirrel

Hey Pete,

At first I have to say that you do a really good job by making such a fantastic E-zine. About a year ago I stopped completely with programming in QBasic because I had no longer a version of DOS or WINDOWS 9X on my computer. Moving on to Windows XP was to me a complete stop on programming. Fortunately I discoverd a week ago FreeBasic AND YOUR E-ZINE. These two discoveries started me programming again. So again thank you!

If I can do something for your e-zine, drop me an e-mail. I look forward to hear from you,

Vincent Peters aka the BazookaSquirrel

English is not my primary language, so forgive me if I make a mistake sometimes...

Great! QB Express is doing exactly what it's supposed to accomplish: help revitalize the QB community.

I'm glad to hear you want to write for QB Express. As you may or may not know, this is an OPEN zine, meaning that anyone that wants to submit content can, and anything that's submitted will be published without censorship (as long as it's slightly relevant to QB / FB). So any kind of article you want to write -- tutorials, reviews, editorials, commentary, rants, raves, comics...just about anything you're interested in writing, we're interested in publishing. If you need help thinking of an article or something, let me know and I can help you out.

-Pete


Have a letter for the editor? Send all your rants, raves, ideas, comments and questions to pberg1@gmail.com.



Express Poll

Every issue, QB Express holds a poll to see what QBers are thinking. The poll is located on the front page of Pete's QBasic Site, so that's where you go to vote. Make sure your voice is heard!

What is the best QB shooter?

GameVotesPercentGraph
Monospace1430%
MoonCrap12%
Dynamic: Colonization of Jupiter12%
Rocket Fuel Mayhem12%
Shell Shock24%
Star Wrek37%
Space Warp37%
Frantic Journey1430%
Missing In Space24%
Other511%
46 Total Votes

Space shooters are by far one of the most popular genres among QB programmers because of their fast pace, frenetic action, and most of all, because they're pretty easy to make. Over the years, there have been a TON of space shooters released in the Qmunity, the best of which you'll find in the list above.



Monospace by Milo Sedlacek

Frantic Journey by Adigun A. Polack

This poll, as you can see, ended up being a dead-heat between the late Milo Sedlacek's classic Monospace shooter, in all its monochromatic glory, and Adigun A. Polack's flashy new Frantic Journey, which is chock-full of amazing visual effects that are truly mindblowing. Both of these games are some of the best work the QB community has ever seen, and if you've ever played either of these games, it's easy to see why they are the front-runners.

Surprisingly, every game in the poll got at least one vote, proving that there is no truly dominant game in the QB space shooter field. Every variation on the space shooter theme seems to have its fanbase in this community -- which is good news for prospective shooter programmers.


Next month: How did you first learn QBasic?
Vote in next month's poll! Just click here.


News Briefs

Written by Pete

News from all around the QB / FB community, about the latest games, site updates, program releases and more!

Site News

Plasma Launches New Phat Code Site!

On March 5th, Plasma launched his new Phat Code site, and at its launch, and I have to say, it is already one of the best QB / FB sites on the Internet. It's well-designed and entirely automated by PHP, and has a great collection of high-quality QB games, complete with thorough descriptions and screenshots. This is definitely the best organized files section I've seen around the Qmunity. There are also tutorials, info on Phat Code projects, articles and more. Plus there's the great "Scene News" section which syndicates news streams from all the top QB / FB news sites (QBasic News, QBNZ, Pete's QB Site, Rpg-Dev.net, FreeBasic.net, FreeBasic.tk, V Planet! and SIA-Tech). This site is great, and it's getting its fair share of praise.

QB Accelerator Issue #4 Finally Released

QB Express officially isn't the only QB / FB zine on the scene anymore: we have competition! After over a year of silence, QBXL editor SJ Zero put together a new issue of his edgy magazine, which is the biggest one yet. You can read it at this address. Not only does this issue feature SIX different reviews (of Collecter Guy, Nietzsche SE, Ball Blazing Fantasy, Immortal Kombat II, Arganoid and of FreeBasic itself), it also features a collection of tutorials on subjects such as Vectors, Calculus, an introduction to FreeBasic, "Advanced FreeBasic", a 3D coding tutorial by Xerol, Ray casting, music, and also editorial columns "The Edge" and "The Desk" by SJ Zero and Alien Jack Nicholson, respectively. There's a lot of great stuff in this issue, and it maintains the biting whiticism and no-holds-barred speak-your-mind style of the previous issues. Any fan of QB Express will enjoy this magazine for sure. So go read it while it's hot!

Los Monos del Obús Site Launches

Na_th_an and aetherfox have launched Los Monos del Obús, a blog-style site dedicated to their mutual projects. Already they have released a quirky, humorouse I.F. game (Interactive Fiction -- i.e. text adventure) called "The Quest For Opa Opa". And it sounds like more is on its way. On the latest blog post, this dynamic duo announced that:

"Apart from the sequels to our first release, we will be producing some cool stuff in between. Our next game, called Backdoor Explosion, will be a graphic adventure in the fashion of the good ol’ Sierra or Lucasfilms games (think about The Secret Of Monkey Island or Space Quest). It will feature the same acid humour that Opa Opa has, plus a tight point’n'click interface in the fashion of Scumm games, nice hand-drawn graphics and a stunning soundtrack. All we can reveal by the moment is that this game will be Sci-Fi themed and will feature aliens, cute chicks, a completely stupid main character and… er… anal plugs?
The Basic Network Throws In The Towel

Now when you visit The Basic Network, you're met with this ominous one-line notice: "The Basic Network has closed its doors forever. This domain will be available for sale shortly." That's right. Nekrophidius has officially shut down TBN, once a popular BASIC web community. Following a devastating crash a few months ago where much of the old message forum content was permanently lost, the site suffered long periods of downtime. When it was finally resurrected as just a brand new blank forum -- with none of the old content -- it was too late. TBN's visitors abandoned the site and the message forum was essentially a ghost town. Nek decided that it was better to just shut down the site than to leave a dead forum online, so he pulled the plug on TBN a few weeks ago. It will be missed.

ASCII-WORLD Breaks Onto the Scene

MystikShadows and Lurah teamed up this month to launch ASCII-WORLD, a site dedicated to text-based games. According to MystikShadows, this site is "A new place where any one that likes to create Text and ASCII graphics games or applications can come and talk about their projects, post articles about the art of Text development and meet other people who share their passion for Text and ASCII Development."

This site sports a neat DOS-IDE-style layout, similar to the famous QBasic IDE that we all know and love. It's full of articles, tutorials, reviews, code snippets and games, and has had very frequent (almost daily) updates since work began on the site on February 18th. I highly recommend that all fans of ASCII games check out this site.

JacobPalm.dk Becomes "Largest QBasic GUI Review Site in the World"

JacobPalm.dk has had several updates over the past month, including the addition of several new GUIs to its collection. Currently there are 23 reviewed QB GUIs available. The site recently ran a poll among visitors about which QB GUI was the best ever, and with 33.3% of the vote, Rush by Rush Soft took the top prize. This site's new design and regular updates makes it a worthy visit for any QBer.

What's The Deal With V Planet?

Over a month ago, popular QB reviews site V Planet! began to get a new makeover, switching from its old red and white color scheme to a cooler blue, gray and white layout (you can see the new logo to the left). The site also now sports sections for FreeBasic game reviews and news, though no FB content has been posted yet. Actually, the site is pretty much blank. It appears that V Planet! editor Nekrophidius got part way through a massive redesign and then never finished it -- leaving the site basically in shambles. The message board is broken. Almost all the reviews and news archives are inaccessible. There are broken links all over the place. It's a real shame that this popular and useful QB mecca is in such an unusable state. A note to webmasters: if you're going to redesign your site, finish the entire thing before uploading it. "Under Construction" websites blow...especially if it makes the content inaccessible. And Nek: hurry up and finish!

FreeBasic.tk Keeps Chugging Along

FreeBasic.tk, an increasingly-popular FB programming site, has seen several updates this month. The FB Tutorials Section was opened up by Zap a few weeks ago, archives of all the content from FBTK's predecessor Qbasic.tk have been uploaded for anyone interested, and the FB Frequently Asked Questions section has seen quite a few additions. Meanwhile, the number of users posting on the message forum has been steadily rising. Keep up the good work, FBTK!

Pete's QB Site Overhauls "QB Zines" Section

Yep, I did an update to my site too this month. :) Pete's QBasic Site is home to the largest collection of past QB magazines available anywhere, and after the latest updates, it's even closer to being complete. On March 8th, I added two more "lost" QB magazines to the library: The QFiles by Secret Weapon Software, and QBasic Gamer Magazine. All the issues of both magazines are now available. Also, by request, I have added downloadable zip archives of every magazine in the collection, so now you're able to read the mags online or download them to your harddrive for later reading. So go ahead and visit the QB Zines section.

Programmer's Haven Opens Up FreeBasic Section
Urger announced a while back that "Programmer's Haven, the excellent forum for Roy Scott's Basically Programming and Basicusers.net sites has just opened a section for FreeBASIC programming." Looks like FB is getting some mainstream attention. You can check out these links for details: Basically Programming, Basicusers.net, Programmer's Haven or the FreeBASIC section of Programmer's Haven.

The ABC Packets Are Back -- Abd Better Than Ever

After William Yu's famous "All Basic Code" website went down in mid-2004, the BASIC community has been missing a crucial, necessary resource. The sheer quantity and range of useful code snippets in the ABC packets was unbelievable, and all areas of BASIC programming were covered. But unfortunately, allbasiccode.com went down, and with it, this vast resource.


Luckily, though, Na_th_an has come to the rescue. This month, he launched The BASIC Source Repository, which contains the full collection of the ABC packets in a much more streamlined and accessible layout than ever before. Rather than offering downloadable zip archives of huge yearly packets (often upwards of 4MB) to find a ten-line code snippet, Na_th_an has extracted the snippets and categorized them so that you can view them in your browser. Additionally, he's incorporated a great formatting / highlighting script so that all of the snippets have nice, attractive, color-coded, easy-to-follow code. This is an incredibly useful resource for the Qmunity and for BASIC programmers in general, and should be at the top of everyone's bookmarks list.

MS BASIC Repository Back Online

Na_th_an's OTHER repository, another great resource for the BASIC community, has recovered from several months of downtime. The GWBasic/QuickBasic/QBasic/Visual Basic Repository has copies of just about every version of MS BASIC ever released, from the original GW BASIC up to Visual Basic 4.0. I'm glad to see that this site is back online, because now when those annoying newbies ask me "ware cann i get qb4.5???!!!!1", I know exactly what to tell them. :)

FreeBasic Documentation Project

Andrew Shelkovenko has begun a fairly comprehensive project to collect documents and information about FreeBasic, and he's done a pretty good job so far. He's collected all kinds of FB tutorials, FAQs, links, examples, documentation and more at his FreeBasic Documentation Project website.

Plantasy Studios Website By Z!re, Rune (Zap) and Kitten

Z!re, Rune and Kitten have teamed up to launch Plantasy Studios, a site devoted to their projects. This site will be will be the official home of Z!re's MOoRPG, among other things that the group makes. The site's still small and in its early stages, but there's some stuff up there, such as MooRPG screenshots and concept art.

Project News

FreeBasic Compiler v0.12b Released!

V1ctor released the newest version of FreeBasic in early March: v0.12b. This latest version features a host of additions. Here's an excerpt from the Changelog, with a list of all the new features ADDED in this release:

  • [added] resource files support on Windows, just add the .rc's or .res' to the list, they will be automatically compiled -- the Windows C headers were also added, so complex scripts (ie: dialogs and menus) can be used too (DrV)
  • [added] XPM icon resource files support on Linux. As with Windows resource, just pass the .xpm file to the commandline and the executable will sport a fb_program_icon symbol holding the XPM data. If using gfxlib, this is automatically used to set the window icon.
  • [added] built-in multiplatform threading functions (lillo)
  • [added] "operator =" shorthand, as in "a += b * c" (v1ctor)
  • [added] SELECT CASE AS CONST statement, only integer constants are allowed and a jump table is generated making the it much faster than an ordinary SELECT when more than 4 CASE's have to be checked (v1c)
  • [added] #DEFINE's with arguments (macros) as in "#DEFINE foo(a,b) ((a)*(b))" (v1c)
  • [added] "CONS:" and "ERR:" special file names, to open the console for i/o access and the std error for output (v1c)

Any new release of FreeBasic is a reason to celebrate. It just keeps getting better and better. As always, you can find the newest release at: www.freebasic.net

Inspiration Speeds Up and Gets Smarter

Wallace Software's upcoming FPS has seen a lot of progress in the past month. Since the game's switch from QB to FB, the raycasting engine has gotten a whole lot faster (up to 4x) thanks to FB's multithread support. Also, Wallace has begun rewriting the AI for all creatures, both human and alien. Now they're a whole lot smarter, and humans and aliens now have their own different fighting styles. Also, the engine now supports up to 512 sprites, which will allow for much bigger and more intense battle scenes. Visit Wallace's often-updated website for the latest info on Inspiration!

SonicX Version 10 On The Horizon

The tenth release of JO's Sonic the Hedgehog Clone, SonicX, is due out sometime in the near future, according to the March 11th update of QBasic Central. This game has probably had the longest development cycle of any QB game in history, clocking in at nearly seven years -- 1998 to 2005 -- and it's still going strong. Version 10 of SonicX will sport a new scripting engine that controls aspects of the game such as the bubbles in the underwater scene you see to the left. Underwater worlds are another new addition to Sonicx, which are created through a new layer which will support levels like in the Labryinth Zone of Sonic 1. Keep checking back at QBasic Central for the latest on SonicX.

SpaceMerc Demo Released

Mitth'raw'nuruodo, a very active newcomer to the QB scene (only been around since January but he's already posted over 650 messages on the Pete's QB Site forum), released a demo of his new spaceshooter SpaceMerc a few weeks ago. So far, it's in very early stages, but it sports mouse control and an impressive array of multi-colored bullet fire. (You fire A LOT of bullets in this game.) It's a good start -- hopefully it actually gets finished.

You can download the demo at this link.

The Latest Scoop on ADDGUIQB

Kurt Kuzba, the developer of the QB GUI library ADDGUIQB sent me a whole lot of news on the lib's latest release. But rather than paraphrase everything he said to me, I'll just let the man speak for himself:

Hi Pete;

I just finished updating and posting the ADDGUIQB library.

http://home.centurytel.net/kkuzba/links/addguiqb.html

The only visible changes, aside from the improvements in character display speed, are in the radio buttons, which now allow you to hi-lite a selection without clicking the associated button. A second click on a selected button clicks the button. A click on a selected button activates it. This differs from the original version where you needed to click on OK to activate a selected radio button. You also now have improved keyboard interaction with the radio buttons. Here's the general spiel:

ADDGUIQB is a C library for mouse and control object usage in mode 12h, or SCREEN 12, with QB45. It supports dropdown menus and radio buttons. Mouse cusrsors are user definable. User definable graphical control objects are supported, as well as onboard text buttons, using a built-in 8x12 character set.

Characters are not limited to standard text grid positions and may be placed at any location on the screen. Text characters may also have solid or transparent backgrounds.

Graphics primitives are part of the library, including line, circle, oval, disc, block, square, and rectangle.

Graphic data blocks may be blitted to the screen using bitblit or transparent bitblit, allowing display of sprite data or non-rectangular graphic objects within a rectangular area.

All source and compiled code is available as public domain and freeware on the ADDGUIQB web page.

Version 2.0 was released on March 6, 2005.

]<urt
   kkuzba@centurytel.net
   http://home.centurytel.net/kkuzba

Adigun Unleashes FreeBASIC 8-Bit Palette Machine

Adigun Azikiwe Polack has been making the rounds recently, announcing the release of his new FreeBasic palette library with well over 100 different palette routines. Here's the press release, straight from the source:

If you ever wanted to manipulate and adjust your 256-color palettes in your FreeBASIC programs like never before and then some, then this original library entitled “The New FreeBASIC 8-Bit Palette Machine” is just your big-time ticket over here!! ^_-=b !

In this lib, it has such *amazing* features as:

  • Palette Fading In/Out
  • Palette Rotation
  • Fade/Switch to Negative Palettes
  • Fade/Switch to Greyscale Palettes
  • Crossfading between TWO palettes
  • FULL support for both 768-byte palettes *and* PP256 palettes
  • FULLY 100% COMPATIBLE with Angelo Mottola’s GFXlib 2 for FB
  • .....and LOADS more!!! :)

For more information and a download of the *very* latest version of this library for FB, please visit this web address:

http://dhost.hopto.org/aapproj/fbpal/index.html

Thanks so much, and be seeing you there!!! ^-^

Other Interesting Program Releases This Month

The FB scene has been absolutely a-buzz in the past four weeks. There have been tons of releases -- many more than I can possibly keep track of. Here are some of the releases that have sprung up:


A few screenshots from these programs:

Dr_Davenstein's OpenGL Demo

Lin's Legacy II

(Click for larger view)

BattlePong

(Click for larger view)

Tales From Argania
OHRRPGCE Source Code Released By Hamster Republic

Quirky QB programming group Hamster Republic has released the QB45 source code to the Official Hamster Republic RPG Construction Engine. You can find it on their website, HamsterRepublic.com. I've also heard that an FB port is coming, though it's still uncomfirmed.

Phat Kids Returning

Late-Breaking Update: Nekrophidius sent me an email a few minutes before press time with the following tidbit: "Phat Kids Games is coming back! Big Nose, one of the original Phat Kids, has made it known that the popular game dev group is coming back and bringing with them a new version of their classic RPG, Kids Of Karendow. Although they no longer develop in QB, this is still a tribute to arguably one of the greatest QBRPGs of all times. More updates as they become available."

Competition News

QBXL Spring Beacons Contest

After the success of January's Frost Remembers FB coding compo at QBXL.net, SJ Zero decided to host another FB weekend marathon coding contest. This time, the contest was originally sheduled to run over last weekend for 48 hours, but after only "2.75" results were submitted by the deadline, the contest was extended until this Friday, March 18th.

So far, SJ Zero has entered "Rambo vs. Kitty Cat", a great platform shooting game with scribble-style graphics like you see in the logo to the right; DrV has entered "Pi Pong", a pong game; and Joakim and Xteraco also submitted an unfinished entry. Check out the QBXL forums to see the status of the competition.

Rattrapmax6's Circle Challenge

Rattrapmax6's simple challenge to create a circle using PSET in the smallest amount of lines resulted in some interesting results the other day over at QBasic News. Check out this thread for more info. Just proves that a challenge doesn't have to be complicated to be cool.

Misc. News

Free QB/FB Webhosting, Courtesy of Hostvoh.net!

As mentioned in the Letters to The Editor, Robin de Graaf is offering free QB / FB / programming site hosting on his server at hostvoh.net. Here's further info on the free hosting:

With a whopping 8 gigs of space free on my server and over 70 gigs of bandwidth just lying around, I thought I'd do something back for the community that started me on the painful path of learning your way around the web.

I've gotten to know some people that I still regard as friends, even though I might not talk to them a lot, and the QB community will always hold a special place in my heart.

But instead of coding, for which I sadly lack the time, motivation and skill (I'm much more at home in dabbling with PHP), I thought I'd give out free hosting with no strings attached (other than no illegal stuff Razz)

I am offering, to those who want it, hosting with the following features:

  • Hosting under subdomain
  • PHP/MySQL/Perl/C script ability
  • 20 megs of space, which is manually monitored, so if you go overboard, but not by much, it's fine by me
  • whatever bandwidth you require
  • NO advertising whatsoever, and there will NEVER be any of that shit on my server

It's free, it's good, it's reliable, and I'm offering it to you guys. I can set up accounts as soon as you want them, so let me know and I'll get you all set up.

And if you're wondering what my street cred is, well, I've been running danwa.net for over 5 years now, and from the start I've been hosting it from my own pocket.

The subdomains would be located under hostvoh.net until I decide I can spare the cash to purchase a more QB-ish domain name.

Ta!

If you're interested, contact Robin de Graaf and he'll hook you up. GeoCities and AOL Hometown no more!

Something Awful: Diary of a QBasic Gorilla

The absolutely awesome satire site Something Awful has poked fun at QBasic in one of its recent articles entitled Diary of a QBasic Gorilla. Inspired by the QB classic that came packaged with QBasic v1.1, Microsoft Gorilla, this article takes a look at the inner thoughts of one of the distressed gorillas that eventually went on to destroy countless skyscrapers with exploding banana bombs. Here's the opening paragraph of the article:

The following are selected entries from the journals of QBasic Gorilla. The journals were mailed to astronaut Neil Armstrong on the first day of 1991, and then subsequently turned over to the FBI. These writings helped investigators understand the distorted mindset that enabled QBasic Gorilla to carry out the grisly 1991 banana attack that killed thousands and left much of Manhattan in ruins.

To this day, many victims suffer post-traumatic stress disorder as a result of the harrowing banana rampage of QBasic Gorilla.

New QB Graphics Modes, Brought To You By A.A.P.

"New and never-before-seen QB graphics modes discovered!" announced Adigun A. Polack at the QBasic News forums recently. What are these new, never-before-seen graphics modes, you might ask? How about 512x133, 512x100 or 512x80 resolution with 16 colors? Sure they might be kinda useless, but I guess they can be fun to tinker with. Adigun apparently plans to write a tutorial on this subject for QB Express at some point. You can see a screen capture from one of Adigun's new screen modes below. Check out the thread for more details.

Z!re Leaves The Scene, Admits She's A Girl!

Z!re, easily one of the most active and respected members of the QB/FB community posted a few surprising messages a few weeks ago. Check them out here and here. Not only did Z!re announce "I've decided to leave the forum, well, all forums for a while.. probably a rather long while.." and take an extended break from the Qmunity, but on the way out, Z!re also admitted that she is...a she! That's right, folks: Z!re was a girl all along, but kept her true identity hidden and let us all naively assume that she was a male. Usually it's a forgone conclusion that almost everyone that programs QB or FB is a male, especially someone with as morbid sense of humor as Z!re (with the twisted bloody smiley face avatars and such). I guess we QBers should rethink our gender stereotypes, eh?

Although Z!re has opted to take an extended vacation from the various QB forums that she used to frequent, she hasn't stopped checking up on the Qmunity. In fact, she continus to post at FreeBasic.tk, and is still working on MooRPG and helping submit stuff to QB Express. So don't worry, we haven't lost Z!re -- she's just taking a break.

Below you can find a comic, the latest in Z!re's strip, "The Qmunity" that explains the whole situation from her point of view:


(Click for full size)


Robot Robbery Review

Written by Lachie Dazdarian

Review of Robot Robbery v.0.99 by KeiProductions(Keith Koshman)

This platform game arrived in 2003. after a couple of years of on and off development and despite it didn't featured many levels, spectacular graphic or anything new in any perspective it was well received. If you want to find out why, keep reading.

Graphics

Keith did a very nice and even job with the graphics. Despite the EGA look of it all tiles and sprites blend and fit nicely with one another. Game graphic could use more colors and shades but there is nothing bad I can say about the look of the game beside that. The main menu screen and story intro jump slightly above the quality of level graphic. Jeff(our hero) is animated satisfactory, with a cool "eye-blinking" effect but a better animation of Jeff's death would be nice. We can say the same for the enemy sprites, but the lack of more than two types of enemy inside the game ruins my impression a bit.

3 / 5

Sound/Music

Keith wrote in readme file that he implemented PC Speaker sound effects but since my computer doesn't feature ones I was not able to hear anything. Sorry, but I doubt I would give anything more that 1 in this category even if I've heard those "sound effects".

0 / 5

Gameplay

Robot Robbery is a standard platform game. Jeff doesn't carry any kind of weapon so you kill enemies by jumping on them(like in Super Mario). Despite the tile by tile scrolling playing Robot Robbery is quite enjoyable. The physics are very simple so jumping on small platforms is not frustrating. What can be frustrating is that you die by single touch of the enemy after which Jeff(you) returns to the BEGINING of the level. Anyway, the shortness of the game limits the gameplay quite a lot. It's hard to know how much this kind of concept and game engine would work in a larger game.

3 / 5

Story

Perhaps Robot Robbery deserves straight 5 in story section but since it hasn't got a proper ending and the plot is a joke itself I can't give it more than 4. Story features Jeff, our hero, whose computer get's stolen by evil robots. Short ones, though. We follow him in his computer search quest. Doesn't sound like something special, right? Why do I give it 4 is the humor. Keith really has a great sense of humor. Everything, from introducing story, story episodes between levels, even the credits and readme file are filled with excellent humor. The peak of this game.

4 / 5

Replay Value

Robot Robbery features only 3 levels. So it's very easy to remember everything inside the game. Once you finish it, I doubt you'll ever want to repeat it. There is nothing you'll want to see or experience again. Also, the fact you can continue from the level you are in infinite times, after you lose all your lives, doesn't help a lot. It allows everyone to finish the game from the first try, if they are enough patient.

1 / 5

Challenge

Good. Levels are well designed. You will definetly lose all your lives playing this game. There are enough tricky parts and traps to make you try harder. Not too frustraing and not too easy. If only the game was longer. Then we could really talk on this topic.

3 / 5

Fun Factor

Only 2?!? Yes. This was a promising game but due the fact it contains so little I can't be very generous here. It's fun, but for short. I can't blame the developer much for this, since this game was coded in QBasic 1.1(great acomplishment, by the way). What is done is done.
2 / 5

Total

16 / 35
Good: Great humor. Enjoyable graphics.
Bad: Game is too short. Tile by tile scrolling. No proper sound/music.

Download Robot Robbery, or visit Lachie's site, Kentauri.


What QBasic Means To Me

Written by Michael J. Wyldman

Back in 1993 I bought my 1st computer. It was an Atari IBM compatible with 640 meg memory, 32 MB hard disk with a cga monitor and DOS 3.3 . I mainly bought it because where I worked was going computerized and we were informened that we had a choice in this , of LEARNING or LEAVING. Not wanting to lose my job I decided to learn on my own time . In the factory where I worked were a lot of people with only basic schooling and they really struggled to understand this new work computer. They looked to me to help them and I was able to explain many simple things to them that made THE difference between leaving and staying in work. At this time I saw a program in the local tandy store called DR PROGRAMMER which intorduced me to GWBASIC. At work one fellow was quite adept at GW and he semi tutored me with firstly a manual and subsequent programs. My work mates were fascinated in how I could make there name fill the work computer screens! To them I was a master of computers. At home I learn DOS inside out and could do almost anything in DOS that you could imagine.

In my work mates eyes I was computer genius that could make a computer do anything. That’s how they saw me . However I saw myself as someone that was privy to knowledge that they didn’t understand and decided to try to "See it from there point " so id be able to help them more. I soon realized that I took certain knowledge for granted. Why ?. Simple because I had learnt it and I then incorporated it into my actions and realisations. What my workmates lacked was understanding. And more important understanding of the underlying concepts of computing. They saw this machine as being smarter that they were and a THREAT to their future wellbeing.

This is simply an example of ignorance formed by practice. My best results with "NEWB" users were discussion where I pointed out how much smarter they were than a computer. What a computer "EXPECTED" from the user and what results when a computer failure happens. Simply here I taught them the underlying principles and vanquished there ignorance and helped them to dispel there fears. I even demonstrate catastrophe by yanking out the power cord to dispel there fears of "breaking" the computer.

Now with this history I decided to introduce my 5 year old daughter to computing in the hope of increasing her opportunities in later life as I knew now how education could make for a much better life. She responded well and soon had her favourite programs that she knew intimately. It was during this phase that I wrote simple teaching programs in GWBASIC that helped to teach her.

My very 1st program was a simple math test of addition, subtraction, multiplication and division through a menu system. My 2nd program was a simple ASCII letter dropping from the top of the screen that was erased by pressing the corresponding key of the keyboard. As I had no mentor (he had moved on to New Zealand) I was on my own with increasing my knowledge of programming. It wasn’t until 1999 when I got on the internet and did my first search for QBasic that I found there was a community that helped, fostered and taught basic.

Now I had many questions (related to errors in my programs ((redo from start?))) and future knowledge that I wanted to learn. My first site logged to was QBasic.com where I posted the 1st of my questions. Days later I relogged anxious to read the reply and solve some of my inadequacies of understanding. Imagine my horror to discover that I was criticized for not "explaining" my problem in a "method" that these "experts" could understand!. It seemed that these experts expected posted questions in a form where they could immediately identify the answer so they could reply. This disillusioned me as I thought that these people wanted to help and would enter dialogue to reveal the programming truths to me. Some of my questions were answered with good explanations and references but most were not. At this time I noticed that there was an "authority" system in the way the experts answered. They seemed to be worried that they would make fools of themselves and instead posted reply to each others reply bolstering their initial assumptions.

Why am I revealing all of THIS?!?!. Simply to point out that knowledge frees us from ignorance but attitude traps us into assumption. How does this relate to QBASIC. Simply that people had a way to pass on this knowledge and the way THEY chose was not the best way for the user. To relate to the new user we must remember how we felt and what it was that puzzled us about programming and then we are in a better frame of mind to answer a user question that will foster there knowledge . Do we wish to be worshipped as an authority on the subject or instead respected for our ability to explain something to a person that needs that extra bit of time and care?.

And so onward in time to Pete’s web site and his QB Express series of magazines , where I read with great interest the letter from Brad Milison. Now I understand his point . You would think that with such a great community and with such great experts that we would have a simple and concise QBASIC for dummies idea as a tutorial. Brad has some concept of the information but he can’t relate to it. Is that his fault or can we foster something that he wants to capture and incorporate into himself. Imagine that we did have this magic tutorial and 99% of people after reading it are hooked on the idea of programming for THEIR reasons of what they can do with it for their lives. Now that’s a GIFT worthy of passing onward!

And so I come to the "challenge" part of my letter. Let the experts compose a simple tutorial that initiates the newb into the idea of WANTING to program. Let’s also assume that the only qualified judges are the NEWBs that we are trying to reach out to. Let’s try to make things accessible to all in our community.

The nutshell of my message is that DUMB people get it, where SMART people don’t! If you can’t define this point then you’re not dumb enough! Personally I tend to worship the experts from afar and marvel at their knowledge and hope one day I could be in there league.

Today I’d describe myself as an intermediate programmer still learning slowly and wanting to pass my ideas on to the community. I continually program small projects meaningful to me that serve small purposes in my life and desire of understanding this tool called computing and it children called programming. I still take more from this community than I put back and wish to thank very humbly the experts for there time and effort as my determination has let them help me and others. Who are these EXPERTs? Well that’s all of us and our mythology of which are new reincarnation of new generations of NEWBs. Instead of criticism, let’s get on with increasing our knowledge base that expands our community as a humanity.

Lately I have been involved with teaching homeless men computing including programming. For them it’s a chance to be part of a world they never expected to open for them. Once on the internet these people revel in new information and ideas. Programming is just another way they can expand themselves and relate to things that are important to them. I think FreeBasic is an invaluable source for our future, however it will be quiet some time before I will get around to using it as I wish to fully master my 1st love first.

Teach a man to fish and he feeds himself for life.
But a professional net fisherman is only as good as his net.

PS: the QB scene is dying as most the experts (leaders) are moving onto libraries and other dialects of basic (FreeBasic), perhaps our future experts will be there newbs. The danger of some directions is that the splinter can not return and be incorporated into the form of the stock. QB is the stock that is worthy of immortalizing for future newbs. Please remember that most people find QBasic MUCH easier to learn than the C language and from BASIC can move onward to other languages. I think Pete has done a tremendous job with this magazine and with the content of his web page. The amount of varied information available allows anyone to want to join his community and prosper. And so onward into our future we go with Pete as an ally.


I’m 48 years old , live in Wagga Wagga , Australia and am called MickJW.
QB to me is one of the languages of LIFE.


Writing A Game

Written by Jonathan Wallace

Let's face it; the days of going through a map, killing all of the enemies, and finding the exit are history. Now people want a little bit more to the story of a game. There are still some games out there in which you do a bunch of miscellaneous missions; most of them flop. Crimson Skies and Wolfenstien for Xbox for example.

All game companies now have professional writers on the staff, making sure that each element of the game goes along with a set story line, with references to allusions. Halo is a perfect example of a great story line, as it has one big mission, which changes due to seemingly uncontrollable circumstances. Realistically it was just a set of various missions, but they all fit seamlessly into a story line.

If Super Mario Brothers was released today, it would probably flop due only to the fact that the story is kind dumb. Sending a plumber to save a princess from a giant turtle is funny, but really dumb. Before you become a game coder, we should all try to be a game writer. Sit down at your computer, open up a Word document and start writing a story. Then take the story that you have written and write the code for it. This is how Contact was made. I had a written storyline long before I even had a ray casting (well actually, originally it was going to be an overhead shooter like the second level of Contra), but before I started to write a tile engine I had already set out a story.

You will find as you try to write your game that you may have had too much stuff in your game, this was the case with me, I had another mission originally where the Holding Chamber door was locked and you had to find the key, but that sounds a little reminiscent of having to find the blue key to open a door in DOOM or having to shut down the security system of The Silent Cartographer.

I am positive that almost anything that you can imagine in Word can be made into a .bas file. Even if it seems impossible to do as a whole break it down into smaller and smaller bits like a top down design tree. It will simplify itself out. If two parts of your game are not connected, say you have an indoor engine and an outdoors engine; write two different programs. Contact came with three different .exe programs. Contact 2 will have five or six.

Make your stories detailed and interesting and the Qbasic gaming community will experience a rebirth like never before.


Visit Wallace Software, home of Wallace's Inspiration and Contact FPS games.


Gallery

Written by Pete

Every issue QB Express features a preview and exciting new screenshots from an upcoming QB game. If you would like your game featured, send in some screenshots!

Simple Shot

Nobody really submitted anything for The Gallery this month, so I apologize for. The closest thing I got was this response by marzecTM on the QBasic News forum:

uhm i can only offer fbirc, sshot and the raknet wrapper. maybe you want to write something bout that


http://ratatoskr.dragonhill.cc/fbirc/fbirc0.03.rar

http://ratatoskr.dragonhill.cc/fbirc/sshot.rar

http://ratatoskr.dragonhill.cc/fbirc/fbraknet.rar

Normally, I would decline this offer, since two of these programs don't have graphics, and the third, his space shooter Simple Shot, is very simplistic and doesn't lend itself well to a Gallery article. (Nothing against MarzecTM or anything... it would just be difficult to write a good Gallery article on this stuff.)

But since I didn't get anything else, I figured I might as well use SShot. I don't know anything about this game other than what I can tell by actually playing it.


So here goes: It's a side-scrolling space shooter, where you control a blue triangle ship and shoot down green triangle enemy ships, who fly toward you and shoot bullets. When you destroy an enemy ship, you get points. When an enemy ship hits you, you lose life. Pretty standard stuff. And as far as I can tell, that's it. The graphics and gameplay are very old-school. SShot would feel right at home on an Atari 2600. If some more features were added, like a story, other enemies, power-ups, levels or bosses -- or at least some other objective besides "get the high score" -- this game would be a whole lot more fun. Right now, it looks like an example program for beginner FB programmers.

FreeBasic source code and an executable are included in the RAR archive above. The other two files are FBIRC and MarzecTM's Raknet Wrapper, which are pretty interesting releases. They are the first real networking routines that I've seen done in FB, and if I were a betting man, I'd bet that MarzecTM has network support in mind for this game in a future release (if there actually is one). Games with simple gameplay like this lend themselves quite well to network play, and the routines to do it are well on their way. I wouldn't be at all surprised if one of MarzecTM's future releases is FreeBasic's first networked game.


Contact MarzecTM at the QBasic News Forums.


Block Game Review

Written by Rattrapmax6

Info:

Diroga's first game. It goes by the name “Block Game 5.1” and according to his website it's still in development.

The over-all object of the game is to use blocks to climb over obstacles and make your way to the door. Its setup reminds me of GameBoy Color’s Monster Rancher minus the monsters.

There are only four levels that gives you a message on completing them. Also, there's no readme for all I saw, which left me banging on the keyboard for the controls.

Gameplay:

The controls are: arrow keys, up is climb (on object your facing). SpaceBar picks up blocks, D drops blocks, and B makes a new Block.

Direction management is set up to test your over-all strategy, even if it wasn’t intended, improves its rating when it comes to strategy. (i.e. You need three spaces to move if you plan to set a block on the opposite of your player from where you picked it up.). It takes time to get used to the controls, but it's worth it since it leaves you pulling your hair at times. All controls are case insensitive.

7/10
Posses a challenge when it comes to defeating levels.

Graphics:

The graphics are made up of what seems to be 10x10 inline DATA bitmaps. The levels are 16x10 in 320x200 so the map displayed comes out rather small.

The Brick effects for 10x10 are good, but they are random which throws off their shape. Doors and blocks are minimal in build, very flat and monotone in color (Black/Brown “Door” | White/Gray “Blocks”), even with 10x10 it can be improved to stand out with shadows and simple shading.

The man is pretty good, moves back and forth and reacts to picking up blocks well.

3/10
Can be overall improved in many places.

Conclusion:

It was a great first attempt at making a game. It seems to be built on a very well made engine that gives it that strategic edge. Graphics function for it, but they lack in quality and can be improved. I’ll defiantly look into any of the new developments and hope for better graphics over all.

50%
Fun, strategic, but lacks in graphics.

Download Block Game at Diroga's QBasic Corner.


Monthly Awards

Written by Z!re and Pete

A few people requested that we bring back the old Qmunity practice of handing out monthly awards to recognize programmers and QB/FB sites that have done exceptional work in the previous month. I was hesitant at first, because in the past these things have sometimes denigrated to mere ego-patters for a select few *1337* coders, but then after further consideration, I realized that people in the Qmunity are doing some pretty amazing stuff these days and they deserve more recognition than what they're getting. So now I present to you: the monthly awards.

These awards are given out to recognize QB or FB coders and websites that have done great work in the last month. They are not awarded for work done in the past, only for work that has been released since the last issue of the magazine. Z!re and I have teamed up to bring you these awards on a monthly basis to help give credit where credit is due.

Site of the Month

Phat Code
http://www.phatcode.net/

Webmaster: Plasma

The new Phat Code site just launched this month, but it's already become one of the most useful QB sites around. It features a slick design and is entirely automated and dynamic thanks to PHP scripts. Already Plasma has put together a large collection of useful downloads, all with a thorough description and often several screenshots. You can also find out about Phat Code's projects, or tutorials on many different aspects of programming. Phat Code also has a great section called "Scene News" which aggregates news postings from around the Qmunity into one convenient location for easy viewing. This should be your first stop if you want an overview of what's going on in the QB scene.



Programmer of the Month

RelSoft
http://rel.betterwebber.com/

RelSoft is a regular around the QB scene, especially at the QBasic News forums where he often wows us all with his beautifully crafted QB and FB graphics demos. But Rel also doesn't mind revealing his secrets to other coders; he's constantly writing tutorials, posting code snippets, and answering questions -- truly giving back to the community.

This month, RelSoft amazed us with his FreeBasic Terrain Blender Engine, which you can see in the screenshots to the right. The amazing part about all of this is that he managed to craft much of this incredible code on an old 486 computer -- which is quite a technical achievement, and really shows the efficiency and quality of his programming. Also, RelSoft managed to harness the power of the popular free graphics library OpenGL this month, and wrote a gigantic four-part series of tutorials on using it in FreeBasic. Those tutorials can be found printed in this issue, so I suggest everyone go take a look!







"Remake Space Invaders" Competition

Organized by Nekrophidius

Here's a great competition that Nekrophidius asked me to feature in this issue of QB Express. It's a cool compo with an actual prize, open for QB and FB programmers. And since this compo is officially sponsored by QB Express, all entries will be featured in the next issue of this magazine. So in addition to Nek's prize, you'll also get a shiny new "QB Express" award!

-Pete

Remake Space Invaders!

You can use either QB or FB for this challenge. Bonus for sound and gamepad control. The compo begins now and ends on April 17th, 2005 at midnight AST. Team entrants are allowed. I don't care if you rip graphics and sound effects, this is not the Boy Scouts. :)

The Prizes!

Aside from the typical "Winner" bitmapped plaque, the winner will receive a free domain name of their choice and free hosting for a year at DBS (total value: $93.59US). The runner-up will also get a bitmapped plaque. If either the winner or runner-up fulfill the bonus requirements, I'll throw something extra in as well. :)


To enter this competition, visit the official thread over at QBasic News. You can post your entries there!



Dialogue and Character Creation

Written by Levi

I know what you’re thinking, “Odd title.” Well let’s face it, we may have created a good plot line in the last tutorial but what good is it if the characters talk like robots? I’ve witnessed this thing many times in Qbasic RPGs.

“I want to cross the bridge”

“You can’t cross”

“Then we’ll fight”

“Okay.”

I mean who talks like that? Seriously. But can you truly just make the characters talk without developing them? Sure, it’s possible, take the following example.

Soldier: This was once the ancient Kingdom of Heir. Now these ruins are all that remain.
Levi: Then why are you here?
Soldier: It was our duty in life to protect this kingdom. We have not yet been relieved of our duties. (Soldier vanishes)

Did you see what I did there? I created a soldier character and without previous development gave him a personality, a past, and a purpose. And though this is all well and good I prefer making each and every character personally in order to bring out the greatest dialogue possible. If you remember from our last tutorial there are four major types of characters besides the obvious main characters.

1. Disposable Characters

Now one of the most asked questions is, “Why bother developing a Disposable Character?” Very good question with a very simple answer. You don’t. It’s true that disposable characters can be talked to. And do need good dialogue to really bring out the game, but how do you do this? Well I’m not going to go giving these guys a past or develop their relationships to others. I am however going to give them a personality.

Picture this, a woman walking down the street carrying a bucket with which she intends to pick up some water. Here is the first step to successfully creating a Disposable Character. The Now.


Some disposable characters from RPGMaker. Litter them throughout your game!

The Now is an odd thing, but easy enough to learn and understand. Basically, it’s what the character is doing now. Not what they are going to do, or what they did do. But what they are doing. In this case, she’s going to the well for water. Simple, do you have to talk to her to find relevant info? No. But we have given her a personality we can use already. She’s a water fetcher, from that alone the user can imagine her as a house wife, or maid. But what if she does talk? What if the user decides to talk to her? Well that’s the next part. The Who.

The Who may sound like it contradicts what I said earlier about not developing the character, or not giving them anything to truly identify them. Well, we can give her a name. Let’s call her Rose. Rose we can say is a gossip. So when you talk to her. She’ll give you juicy tid-bits. And Walla you have a Disposable Character. Rose, house wife, and gossip. Speak to her to learn something about the state of the world

2. Anomalous Characters

Here is the definition I gave for these Random characters.

I made this up basically but in a game these do exist. They are much like regular Secondary Characters except that their parts are far under developed and a stupid move by them causes the whole game to go out of wack. These characters are ones who if you don’t beat to a certain area you’ll never finish your objective, these are minor enemies and bosses who are there only for the purpose of stopping you and making the game more fun and time consuming.

Ever played The Legend of Zelda: Ocarina of Time? Do you remember getting into a horse race with a man called Ingo. Well believe it or not you need to race him to get Epona, the horse. And this horse makes things easier, and I can almost guarantee that she is needed to finish the game. Well Ingo is an Anomalous Character, his position on the Ranch is a hired helper. He is of no real importance. He is later consumed with evil and takes over the Ranch but by stealing the horse he goes back to normal. His Character is very undeveloped, but he has a past, he a position in the now, and he has a personality. So he does have some development under him. And he serves one major purpose, to make the game that much more difficult to win and offer a bit more fun.

So let’s go over what we need for these characters. We need a past, we need a purpose, we need a now, we need a personality. Even one of the weakest bosses has a past to him. Let’s say you’re playing in Arabia, the sub-boss here is an old snake charmer. We have a now. His first line is, “You’ll never get past me.” His purpose is to keep you away. But that leaves us wanting two things. One a past, and two a personality.

Let’s look at that line, “You’ll never get past me.” Dull, cliché, over done. Isn’t there something we can do to liven it up? Sure, “Kantaba will reward me for your death. Unless you’re afraid, I might be willing to let you go.” See? In those few short phrases we emphasized the now. We gave him a purpose on a more detailed scale, we gave him a personality. He’s greedy, looking for a reward, and willing to kill. We also gave him a slight past. Kantaba, is his leader and promised him something for your capture or death. It’s not an extreme past but knowing he’s a snake charmer gives you some idea of what he’s been doing with his life. It also gives you something to work on for the fights.

You’ll also notice small characters like Ingo always muttering under their breaths. Making deals, complaining and bragging. Knowing your characters, what role they play in your game. And what pasts they have, really brings out the ability to make stunning dialogue.

3. Secondary Characters

These characters are the extra characters who give depth to all of your main characters. Levi’s parents, Jessie’s friend Allegra, people who exist for the sole purpose of being helpful but unnecessary. Who accentuate and give a realness feeling to your characters without having any say in how the game turns out.

Now if you notice or remember Secondary characters, unlike Anomalous Characters, don’t determine any part of the game. They are more for story events, or to whine, or give purpose to the main characters. Let’s take for example, that one guy in that one game. Yeah you know the one I’m talking about, or better yet you don’t. These characters are notorious for talking to you, crying out loud, telling you where to go, and then vanishing from sight until later in the game. Now don’t get me wrong when I tell you that they don’t determine how the game turns out, they do move the game forward. I mean if that strange guy who turns out to be your father doesn’t save you in the beginning, you won’t live long enough to find out he’s your father. However, him saving you is built into the game. You don’t have to convince him to save you by doing a whole bunch of side games, he just does once you reach a certain portion. So he won’t determine how the game turns out, but he will move it forward.

But notice, I made him your father. I made it a secret, which means his past is secret but enough is known, he’s your father, to give him a past. His personality gets to be developed right away or later in the game depending on how fast you present the character. If you’re talking to a friend the past, purpose, and so on are determined right away. However if you talk to someone who turns out to be someone from your past later on, a lot of them is hidden for later.

Basically Anomalous Characters and Secondary Characters are the same in their need for development. But how they are seen and used is different. That’s all. Dialogue will however tend to be far more developed for them since they move the game on that much more. I mean a Father who challenges you to a side game for a special object you need, will talk less than a Father who gives you words of wisdom. So keep in mind what type of character each is and develop them accordingly.

4. Main Secondary Characters

These are the extra characters who have just as much say and purpose in the story as the main characters, just not as large a part. In an RPG these would be the followers or group members of your party. In games like Zelda these are the main characters whom you always have to visit, meet, help, receive help from. And so on.

You’ll notice that Main Secondary Characters in regular games are almost exactly like Anomalous and Secondary Characters. The difference? Again, they make the story move forward and offer more than simple words. You can play games with them, you work with them to save someone, or save them. They are important to the game in how you interact with them. So their personalities, their pasts, their purposes, are tied with the main characters. Making them that much harder to produce effective dialogue for.

The other characters if you’ll notice have preset things to say, will say no more and no less than what they are programmed to say and change as events happen. This is the same with all non-Main characters obviously. But though Main Secondary Characters also have preset things to say, they can change depending on your reactions to them. To move the story forward, or to move to a side game. To save and give helpful info and objects to, or to work with to save such a person. A common Dialogue between the main and Main Secondary Characters could be like Navi and Link in Zelda. Where Navi points out things you should check out, tells you what it’s found and enemies weaknesses. As well as giving good dialogue during story sequences to explain things and move the story along. Their personalities and their relationship with the Main characters develop during the story and so what they say and do is more like a roller coaster than a flat road. Keep these things in mind when developing these characters.

5. Main Characters

Now wait a minute. Didn’t we already develop these characters in the first tutorial? The answer, yes. Or at least you were suppose to. We gave them a past, we gave them personalities. We gave them looks, and attitudes, and purpose, where they are now and where they were before. Everything we ever needed to give them. So why talk about them? Well again, we may have those but those are the building blocks to good dialogue.

Imagine I have a character who is a hot head. If someone swears at him and tells him to get lost, will he get lost? Will he just shrug his shoulders and leave? NO! He’ll yell at the guy, start a fight, swear back if he has to. He’ll probably be short on words in fact. Often stuttering as he’s trying to control his anger only to burst out with a loud war cry. There of course is the chance he’d just leave only to take out his anger in another way but you have to plan for these things. How is your character most likely to react to each of these types of characters? How do his past, purpose, relationships, and current hardships affect who he is and how he acts? These are important questions to consider. But the biggest question is what happened just before the character’s introduction.

Let’s face it, in all games something has happened to the character, his village, his family, he was off traveling, he was doing chores, he was playing games, sleeping, something. He was doing something before the game started and before he entered. How does that affect his personality at that moment? A person angry at having to do chores is less likely to be whistling than someone coming home after a long journey and daydreaming.

Let’s look at Levi from my previous story example. Here’s how I introduced him.

War, there isn’t a single generation that has been spared its wrath. Not a single child alive nor still born has escaped it’s looming presence. That death like grip that holds all men in fear for their lives. Now war is not simply over there being fought by a few. It’s here, it’s now, its being fought by all.

Levi walked down the streets of his once lovely town, now crumbling with decay and destruction. As he watched the once proud building tumble and corrode slowly he realized that with greed came such destruction, and that in this world of death that so many suffered, death itself was the only escape this devastation offered.

If he didn’t have the love of his family, of his friends, Levi might just wish for such an end himself.

Now if you’ll notice how I introduced the setting. Setting again is important to the beginning, The Now of the character, and his personality. I said that a once proud city had fallen in war. I described the world and the destruction that plagued it. The horrible living conditions, how most just wanted to die. And how much Levi relied on his family. My oh my what might happen if one went missing? I introduced The Now, I brought a bit of his personality to life. I’ve given him relationships. And I’ve done a bit of foreshadowing. I’ll explain foreshadowing in depth in another tutorial.

That short piece introduced so much and gives you a slight idea of what to expect when we meet Levi himself and he begins a dialogue with his friends and family.

I hope this has given you much to think about. That dialogue is determined by your characters, their positions, their personalities and likely reactions to the settings and other characters. And how these can make or break a plot line. Good luck and happy gaming.


You can contact Levi at this address.


Snakes!!!

Written by Rattrapmax6

Okay, Pete passed around a clever little story involving a QBasic Gorilla. Sir Newton passed around that for every action that there is a equal and opposite reaction. The opposite reaction is me writing something similar for Pete and his one of a kind QB Express,... As follows:

Behind that blue and gray IDE there lies vast green, grassy fields. In these vast fields, there are mutable apple trees, and every where on the ground you can find apples. The occupants, as you can imagine, love apples. They loved eating them so much they made a game out of it.


QBasic Nibbles. Ahhhhh, the good old days!

These games ranked in levels, for the beginner snakes only had to collect apples from a maze with no time limit. Proceeding on to the next level, the snakes had to see which one could eat all the apples in the maze the fastest. Then there was the finial two. The ones where two snakes raced against the clock. The First level of this the snakes took on one maze, but in the highly awarded last level, the snakes raced several mazes eating spell cast apples that made them grow in length every time they ate one.

There was that one little snake that dreamed of greatness. He went out and practiced ever day. His chance came that summer in those distant QBasic hills. He took the challenge of the first level with ease. Nibbles was determined to win. He battle, and raced until a nightmare struck him.

“Now entering the ring! Nibbles along with Balrogna!” Balrogna was a fowl snake that would do any thing to win. And it was this that ruined Nibbles dream that summer. Around a corner out of the judges site, Balrogna tapped Nibbles. Then coming right into plain sight Nibbles tapped back and Balrogna acted out a desperate crash! The judges banned Nibbles for the rest of the summer.

All he could do was watch as Balrogna took gold at the end of the season. Nibbles didn’t deheart, he went back to training hard every day out in the fields. He also practiced not to pay any heed to Balrogna’s attempts to get him to cheat. But Balrogna still was up to no good. He waited up top a tree one day when Nibbles was out practicing. When Nibbles passed under the tree, Balrogna dropped a coconut on him. Nibbles was badly hurt and doomed from running the games that summer.

He didn’t give up though. One week left and he practiced in the field even though it hurt him so bad. The day came and he struggled to pull off the first level. As he went, it got better until the next to last level where he met back up with Balrogna. He stayed off him till the last apple. Nibbles dashed for it and took it but Balrogna clipped him directly in the side redamaging Nibbles.

Nibbles was in deep pain during the last stage, every growth apple flared every nerve in his body. It was getting close, Balrogna had no problem dashing through the maze. It seamed that Nibbles dream was over once more. But, a pretty girl snake in deep excitement stood up and shouted: “GO BALROGNA!!”, He looked up and at the same time “WHACK!”. He had slammed into the wall knocking him out. Nibbles took his chance and won the competition.

On releasing QBasic, Microsoft honored Nibbles by writing a QBasic game as a demo. The objectives were changed around, but the meaning stood. Nibbles bravely over came the odds against him and took gold that summer. Now Nibbles is happily married and plans to raise a family in FreeBasic, were maybe one day, his son Nibbles the Second will win his title as greatest apple eater....

Finis (Latin for The End)

-Kevin (x.t.r.GRAPHICS) (aka: Rattrapmax6)


Contact Kevin or visit x.t.r. Graphics.


ASCII Ain't Goin' Anywhere And It Will Live Forever

Written by Lurah

I give all honor for modern games. They include 3D effects that has never been seen before and best part of these games is that they advance all the time.

Specs that modern day computers offers game developers are awesome. And as line earlyer, specs advance all the time.

No doubt that some day I'll have a 10 000Ghz pc with 100Gb RAM right here on my desk.

Lol, can't wait to see what kind of graphics game developers offer then. Probably we need some special glasses on our head because those games takes graphic out of human eye limits...who knows. But no doubt that day is coming, the real question might be "when" not "if".

Graphical presentations have advanced at speed that human couldn't predict it would.

There's only few years passed since first real 3d games hit the markets. Now 3D is "must" what comes for "big public" games. Who knows, maybe some genius finds a way to make 4d...

So hooray for 3D and modern technology computers.

But from topic to another...have you ever read a book?

I mean those old things that were printed on paper. And if it was a long book, usually it was allmost heavy to keep in your hands.

If you have read books, you probably understand why peoples keeps saying "good movie, but the book was way better".

I have read alot of books. Lord of the Rings a few times, The Hitch Hiker's Guide to the Galaxy series and Shogun at least twice + dozens of other great books.

All glory to Peter Jackson, Lord of the Rings movies are absolutely great but i bet he never can't beat my imagination with any special effects.

If you feel that you just dropped out of this article, it's ok. Let me explain =)

When I was reading L.O.T.R., I could allmost say that I was there. I saw Middle-Earth, Helm's Deep, Aragorn, Eowyn, Sam, Legolas...Right next to me, they were all there.

It has gone more than a 10 years now, since i read L.O.T.R. for the first time in my life and still i don't have to open that book to remember what Helm's Deep looked like. Yeah, it wasn't like in the movie but surprisingly near. The book did give me so big effect that it's still here. I guess, it won't ever stop affecting me.

I watched those movies and I enjoyed to see them, but hard to remember mutch of em. Yeah, nice effects but I guess that's all for me.

Can't remember more of movies...but hey, nice special effects =)

Maybe game developers should try to give peoples imaginations more space with games they play?

Should we get worried about situations? If peoples get all imagination that is needed on the screen already, is it just ok?

ASCII games and books aren't the same thing, not at all. But the purpose of em is.

#############
#...@.......#
#.###########
#.#.X#..o...#
#....#.....##
#.##.########
#...........#
#############
>

Do you see just some boring thing up there?

I see more, way more than that.

There is dungeon and I'm in it. It's not an X that stands there, it's an stairway to next level and o is some monster i got to get rid of, # is an old brick wall...bricks are old and cracked...smell ain't good and floors are full of water...and i can hear water splashing under that monster's step...
...and it's getting closer...man, I'm in really bad situation here...no arrows and my axe is broken....

Make a movie about that game. I was there, your movie is just something that I watch and forget. Maybe I'll remember that it has some great special effect or stuff.

But what comes to experience with that game? I probably email to its maker and say that he has done a great game. =)

So ASCII games wont die until their developers die. But with imagination that ASCII game developers has...i bet we are here pretty long time.

Can you imagine just how long? Hehe, I bet you got it. ;)

Happy coding for all.
Lurah
lurah@luukku.com


Visit ASCII-World, a new ASCII site co-founded by Lurah and Stéphane Richard.


Comics

By Rattrapmax6

Rattrapmax6 returns this month another "QBasic Horse Humor" comic!





QBasic Horse Humor Comic




IF Tutorial, Chapter #3

By Na_th_an

The Exceptions engine

I'm, for one, a horrid planner. I completely forgot about this very important part of the IF engine: the exceptions engine. In fact, I didn't quite forgot about it, I just changed my strategies. Let me explain this.

As we discussed in earlier chapters, "exceptions" are those things that are performed in the game that are out of the normal rule. The "normal rule" is the default objects behaviour within the engine, i.e. when the player enters "turn torch on" the engine will recognize it and will turn the torch on. We explained that in the previous chapter: the objects manager performs the normal actions. If you turn a torch on, the torch is supposed to become "on". It's a matter of changing a flag and a couple of checks that are always the same. We have designed our engine to take care of this "common stuff" automaticly. Exceptions are things "out of the blue". Those things are what build the puzzles, i.e. the game: combine two objects to get another one, use keys, enter a teleporter, trigger a trap... Let's see this with a simple example: opening a locked door.

With our pristine engine, you can't have open or closed doors. Only container objects can be opened or closed, so we are in front of a problem. Let's say we want a door that's locked with a key. How we make the engine act correctly? How do we code this door into the engine?

Easy: using a exception. The door will be "openable" and "closeable", but not as a container. We have to code explicitly this special case in the game.

There are two ways of coding exceptions for the game: the easy, straightforward way which consists on hard coding a bunch of IFs in certain parts of our code, or the clever, flexible and reusable way of coding a nice scripts interpreter which can be called from several points using different scripts.

This is the change of strategy I talked about above: I've thought that spending this third chapter explaining how to code a scripts parser for our engine will be very useful, 'cause the techniques explained here may apply to many kinds of games and engines, not only IF.

The Main Loop Structure

Before we start, let's begin putting this into shape. As every other game, IF games run inside a loop. We have to show current description, prompt the player, and act accordingly.

We'll have two nested loops. The outter one loops endlessly until the game ends. The inner one repeats until the player moves, prompting for action and acting accordingly. When the player moves, the inner loop ends and a new location is loaded, displayed, and then the inner loop starts again.

Basicly, our code structure looks this way:

DO <read current location "lid%" from file> <perform pre-description exceptions> <show description and exits> DO <perform pre-input exceptions> <prompt player> [<attempt to move player> |<preform post-input exceptions> |<perform common actions>] LOOP UNTIL <player moves> LOOP

Note that we are checking for exceptions in three different places: before giving the location description, before asking the player for input, and after having player's input. That means that we'll have three different sets of checks. Why these three different sets? Let's describe them:

1. Pre-description exceptions.

Those are checks that must be done "before entering" a location, i.e. just after the player moves and before the new location is described on screen. Why is this useful? I can think of many examples: for example, if you want that a room is dark so you can't see anything if you don't carry a light source that's turned on, you have to place an exception in this set, some kind of (pseudocode):

If lid% = 10 then ' In room 10 If player doesn't have torch Or If player has it but it's off then desc$ = "You can't see anything!"

Look at the main loop structure: normally, room 10 is read from the file. The variable desc$ is filled with the description found in the file. Right afterwards, pre-description exceptions are ran and if you don't have the torch or you have it but it is off the desc$ variable is changed with a new description which tells the player that you can't see anything. The next step is showing the description. See how it works?

Another situation where we could need a pre-description exception would be to add or remove an obvious exit from a location. For example, if the player wears sunglasses he could distinguish an extra location in a very sunny and shiny exterior place. Again in pseudocode, this would be something like:

If lid% = 27 then If player wears the sunglasses Add "north" to the exits list

2. Pre-input exceptions

Those are very similar to pre-description exceptions. If you look at the main loop structure, you'll notice how this set is placed just at the beginning of the inner loop. This set of exceptions may be used for the same kind of stuff that pre-description exceptions are used for, but don't need the player to enter a new location.

For example, with the dark room problem mentioned above: what if, once in the dark room, the player turns the torch on? Do we have to force the engine to exit the room, re-read the location from file, etcetera? No. We just add a couple of checks to this set of exceptions:

If lid% = 10 then If player doesn't have torch Or If player has it but it's off then desc$ = "You can't see anything!" If lid% = 10 then If player has the torch And If the torch is on then desc$ = "You are in a blah blah blah (full description)"

That way the player can turn on or off the torch as many times he or she wants, and the game will respond accordingly.

3. Post-Input exceptions

Those exceptions are very important. They will perform stuff according to the player's input. You want a funny reply in your game to several stupid possible player actions, you do it here. You need that a normal command acts differently (for example: open pandora's box causes a big explosion of evil!), you do it here. You allow the player to do specific stuff in a specific location, you do it here.

For example, in The Quest for Opa Opa #1, released this month by aetherFox and me ( http://www.apeshell.net ), there's a location where you can swim a lake. Only in this location you can get naked and swim (I'm giving you a very important hint for this game!). Both actions are hold by two post-input exceptions, in this fashion (again, pseudocode):

If lid% = lake then if verb$ = "unwearall" then if player is clothed then print "Hoping nobody's looking, you get naked." all player clothes go to the inventory If lid% = lake then if verb$ = "unwearall" then if player is naked then print "You are already naked" ... If lid% = lake then if verb$ = "swim" then if player is clothed then print "You won't swim all clothed." If lid% = lake then if verb$ = "swim" then if player is naked then ...( spoiler here ;) )

As you see, exceptions are just three different bunches of simple checks. As mentioned, we could hard-code them in the engine, but that's not nice. Look at the Opa Opa sources and you'll get a headache. Hard-coding the exceptions was a bad move, it made the code unbearable, and the engine non reusable. Avoid that. You can hard-code your exceptions if you are a beginner, but I'd suggest you to keep reading and learn how to do things properly.

Planning our scripting engine

When I have to write a scripting engine, I sit down for a while and think about what we need. You can write all sorts of scripting engines, more simple or more complex, but I've found that studying the requisites we can end coding a very, very simple scripting engine that works fast and is easy to implement.

In this case, basicly we need to design a language that allows us to check the game variables (player's location, objects, etcetera) and perform actions over them. This is everything we'll be doing: check, then act, check, then act... ad infinitum. We also need a set of flags (numbered, nothing very fancy) which contain integer values. We have to be able to check those flags and write to them.

As our scripts will be just a collection of checks, we'll be coding a clausal interpreter. "Clausal" may sound bold, but's it's a very easy concept. It comes from Boole's Algebra theories. To explain it shortly, we just check that a bunch of conditions (clausules) are true, if so we execute a set of commands. Our scripts will be populated by a number of constructions that have this structure:

IF <clausules> THEN <commands> END IF

For example, something like this:

IF EQF 1 3 AT 7 THEN SETF 1 4 MSG "You hear a horrid sound which comes from nowhere!" END

The interpreter will check for each clausule (one per line, so easy to parse!). When it finds one that's false, it just breaks to the next set of clausules (i.e. it skips to the next END, then keeps executing). If every clausule was true it reaches the THEN line and begins executing, in order, all the commands util it finds the END line.

This cryptic language is extremely easy to code and fast to interpret. We do it with a very simple FSM (Finite State Machine) which has three states: waiting for IF, waiting for THEN, waiting for END:

Now we have described how it works, let's see an example of these kind of languages. I call it Ñe for no special reason. It's yet another language designed by yours truly.

The Ñe language reference

Let's summarize all we have said: Basicly you have a bunch of conditions. Each condition has this structure:

IF <clausules> THEN <commands> END

Clausules are evaluated and joined with "AND". Commands are executed sequentially. Example:

IF EQF 1 3 AT 7 THEN SETF 1 4 MSG "You hear a horrid sound which comes from nowhere!" END

The above example means "If flag #1 equals 3 and player is at 7, then make flag #1 equal 4 and display the message".

IF has lazy evaluation. That means that as soon as a clausule is false, the parser will stop evaluating and junp to the next IF.

Clausules:

You can use ! for "NOT", that way "!EQF x y" is the same as "NEF x y" and "!ISOPEN x" will return true if object x is closed.

Commands:

Some details

1. EXITEVAL

By default, the parser runs the whole script from top to bottom. That might not be desirable, depending on the situation. The command EXITEVAL will cause an inmediate exit from the interpreter, ignoring the rest of the file.

Using it or not using it is up to you. Most times, the only reflected effect will be saving some milliseconds, which is always nice. Other times, it will be absolutely needed: if we change the value of a flag some IF blocks might be triggered - that's what we call a "side effect" which can be avoided whether reordering your checks or making smart use of EXITEVAL.

2. ORs

You may be missing ORs. They are there, but not explicitly. To get an Or, you just place another IF and don't use EXITEVAL. For example, to perform something if you flag 2 equals 3 OR 5 OR 7, you have to place three IFs:

IF EQF 2 3 THEN MSG "You are cool!" END IF EQF 2 5 THEN MSG "You are cool!" END IF EQF 2 7 THEN MSG "You are cool!" END

For OR conditions with different clausules (non-excluding ones - in the above example the three cases were mutually excluding), we smartly use EXITEVAL:

IF HAS 5 THEN MSG "You feel good." EXITEVAL END IF EQF 6 1 THEN MSG "You feel good." EXITEVAL END

The message "You feel good." will be displayed if player has object number 5 'OR' if flag #6 equals 1. Here the EXITEVAL is used so the message isn't displayed twice.

3. Making the scripts efficient

It's nothing out of the blue, just common sense: place the checks that will be executed more often at the top of your scripts.

On the next chapter...

CODE! YES! AT LAST! In the next chapter we'll revisit every single part of the engine explaining how *I* code them. Of course that's just my way and you can do it better if you work on it.

Meanwhile, try to understand the concepts explained in this chapter. Some may sound puzzling, but fear not! Once we're down to code this you'll understand everything completely.

Have a nice month!


Visit Los Monos del Obús or contact Na_th_an.


Downloaded FreeBasic, Double-clicked fbc.exe and Nothing Happened!!

Written by: Antoni Gual

The standard answer: "It's a command line app, just key in fbc your_source.bas" And it will not work unless you cd to the freebasic folder and have your bas file in it. If you try it and you end up with an .exe with the same name as your source, you did it! End or the article.

...ok, Pete, I'll write some more!

Windows has succeeded in making most of us some computer iliterates, so this tutorial will try to help Windows users to get started with FB. Linux and DOS users know better their command lines, so I won't adress them.

Fbc.exe is a console app: all the compilers you know work like this, only they come wrapped in a user-friendly IDE that hides the details from you. Freebasic was born 5 months ago,and their main developers concentrate in making the compiler faster, more stable and powerful.No official IDE exists yet, so you will have to live with some command line.

.

Starting with FreeBasic

First of all download the program at the official site http://www.freebasic.net. Make sure you grab the Windows version.

Create a folder c:\freebasic and unzip the distribution in it. It will create the bin, inc,lib and examples subfolders.

The trick of cd'ing to the freebasic folder and put the bas file on it is good for a test but you probably want to have your sources in their own folders, so you must modify your PATH to get everything working.

Setting the path

The PATH is the list of folders where a file is searched when no path is appended to the file name. The files are first searched in the work folder, then in the folders in the list.

A way to modify the PATH permanently is to modify your AUTOEXEC.BAT(W9x) or AUTOEXEC.NT(XP-2000) file, but if you (or program installers) do it for every app you will end having broken PATHS that don't fit in the environment and don't work correctly.

The solution is to use a wrapper batch file to modify the path, run the required app and set back the path to the original state. Moreover, it will allow us to drag-and-drop the source into it, and make all the dirty work.

Here are two batch files, one for W9x and another for XP-2000, as their commands are slightly different.

Batch for Windows 9x.

:: cfb.bat, wrapper for Freebasic Compiler set oldpath=%path% :: :: modify this line to suit your fb path :: set fbp=c:\freebasic path=%path%;%fbp%;%fbp%\bin;%fbp%\inc;%fbp%\lib %1 cd %1 fbc %1 if %errorcode%==1 pause path=%oldpath% set oldpath= set fbp=

Batch for Windows XP-2000.

:: cfb.bat, wrapper for Freebasic Compiler setlocal :: :: modify this line to suit your fb path :: set fbp=c:\freebasic path=%path%;%fbp%;%fbp%\bin;%fbp%\inc;%fbp%\lib cd /d %~dp1 fbc %~nx1 if %errorcode%=1 pause endlocal

Put the appropiate .bat file in your desktop and you will be able to drag and drop .bas files into it.

Testing the compiler

At last some action!!

Open Notepad and key in this first program. It has a deliberate error!

PRINT "Hello,World" DATE$ SLEEP

Save it as hello.bas, be sure of having cfb.bat the near it and drag-'n-drop the dource file to the bat.You will get:

C:\Program files\freeBASIC\examples\ dummies.bas dummies.bas(1) : error 3: Expected End-of-Line, found: 'date' Press any key to continue . . .

The second line is the important one. It says FB found an error in the line 1, someting is wrong before DATE$. If you know QB, you have already detected the problem. Put a semicolon before DATE$ and re-compile

This time the console window closes inmediately. This is because FB did'nt give any error mesage. In fact the compiler only created a hello.exe in the source folder. You can run it:

Hello World! It's 02-24-2005

Congratulations! you did it!

Testing the samples

You can compile and test the samples in the FB distribution.You should not have any problem with the compiler.

When running the samples some of them will trigger an error message about one dll file missing. This is normal,those programs use third party dll's that don't come with the distribution. The readme.txt file has the links to the sites distributing those libraries. You must download the proper .dll file and put it in your windows folder. The program should work fine then.

Compiling a QB program

Now you will likely want to recompile some of your QB code. It will not work correctly unless you do some changes .FB tries to avoid some of the weirdnesses of QB but it adds it's own, so you WILL have some errors. Don't try with a 2000 lines source!

The errors FB gives in simple programs come mainly from:

Difference
Workaround
The default variable type in FB is INTEGER while in QB is SINGLE. Add a DEFSNG A-Z to the top of your program.
FB does'nt allow two variables with the same name and a different suffix: A% can coexist with A$ in QB but not in FB. Also a variable can't have the same name as a keyword with a suffix added. FOR& is a valid name in QB, not in FB. You must rename all the offending variables.
To support ON ERROR and RESUME NEXT, the compiler must be called with fbc -xe yourcode.bas. Make a copy of the batch file and add -xe just after the call to fbc
CALL ABSOLUTE and CALL INTERRUPT are not supported. Avoid programs using them as they need adding substitute FB or 32 bit assembler routines.
The alignment and field sizes in a TYPE are different than QB Avoid programs using TYPE (UDT) variables to GET data from files, or learn how to modify TYPES.
Sound, printer and comm port are not implemented yet Avoid programs using them or check third party libraries
ON PLAY, ON KEY, ON COMM and writing/reading to hardware ports is not and will not be implemented Avoid programs using them or use Windows API workarounds
Slave Windows interface programs as DS4QB++ or DSOCK are not needed and will not work. Check third party libraries or the Windows API
QB libraries don't work The only usable libraries are those programmed in QB,not in assembler, provided you can have the source and re-compile them in FB.

An example of what can happen when re-compiling QB programs.

The code works correctly in QB and draws a Mandelbrot set

SCREEN 12 CONST module = 640& * 480 DO x& = (x& + 103) MOD module im = 0: re = 0 FOR iter% = 1 TO 255 im2 = im * im im = 2 * re * im + (CSNG(x& \ 640) / 200 - 1.2) re = re * re - im2 + (CSNG(x& MOD 640) / 240 - 1.9) IF (re * re + im * im) > 4 THEN EXIT FOR NEXT PSET (x& MOD 640, x& \ 640), iter% LOOP UNTIL x& = 0 DO: LOOP UNTIL LEN(INKEY$)

If you compile it with FB you will have no errors. Running it will give you the result on the left side. A weird Mandelbrot set.... Adding DEFSNG A-Z at the top will solve the problem: the result is the one in the right side

Where to go From here:

If you reached this point it means you patiented with my broken english, you liked FB and you want more..

Documentation: The FB documentation is a work in progress. The only correctly documented part is the graphics library made by Angelo Mottola, check gfxlib.txt in the distribution. For the rest, program as if you were using QB, and check the file keywords.txt if it don't works. If not, ask in QBasicNews, the developement forum. The sample code provided is a good source of information.

Get an IDE. VonGodric FBIDE made one specifically for FB. It will serve you until you start modularizing programs, as VonG's IDE is for a single document. There are general use IDEs you can adapt, and there are several FB-specific Ide's in developement, that will be available soon.

If you want to use SDL, FMOD, LUA, you should get the documentation for the third party libraries, at the same places where you got the dll's.

.

Get Docs for Libraries For doing a GUI application with menus, dialogs and toolboxes, you are alone with the Windows API. Some people is trying to port wxWidgets, it's a portable GUI library that works both in Windows and Linux.

Explore the Windows API jungle You will need a good documentation: The main reference youi can check online is the Microsoft Platform SDK. If you run Windows XP-2000 and you can make a 350 Mb download you can install it in your computer. You can too use the older (10 years) and smaller (8Mb) win32.zip Borland distributes with it's compilers. You can find it at ftp://ftp.borland.com/pub/delphi/techpubs/delphi2/win32.zip

Have Fun!


Click here to download this tutorial.
Check out Antoni Gual's Page for all kinds of great QB / FB stuff!


FREEBASIC - MOUSE TUTORIAL

Written by Stéphane Richard (Mystikshadows)

INTRODUCTION:

After doing some searches, I quickly noticed that there simply wasn't an official tutorial or technique for manipulating the mouse in a windows console application in FreeBasic. Therefore, I decided to write this technique in order to give such an example to the FreeBasic Community. As you know A Windows Console is already mouse aware by ways of the fact that it is a windows console, which means it's created with the use of the Windows API, which means that the mouse can be accessed from the Console Window. So There's no need to turn the mouse on or off in your code. All you need to do is Get or Set the X and Y coordinates and get the states of the mouse buttons. We will be covering the following subjects in this tutorial.

As with most tutorials, this one too can be better explained with the use of an example program. We will be creating a very simple program that acts upon the user's interaction with the mouse and certain areas of the screen. It should provide the bases of code needed to efficiently operate and control the mouse in your own programming projects.

IMPORTANT: It is mandatory that you set yourself in a graphic mode in order to use the mouse. the mouse commands will always return -1 for a value if the graphic mode is not set.

THE SAMPLE PROGRAM DESCRIPTION:

For the sake of a demonstration program, things will be quite simple and as straightforward as it possibly can. THe program will show 3 items at the top of the screen and depending on which one you click a different message will be displayed on the screen. This should give you enough information to know how to work with the mouse in FreeBasic.

In FreeBasic, there's basically 2 commands that you need to worry about when trying to handle the mouse in your projects. Here they are with their syntax explained as per the documentation.

-------------------------------------------------------------------------------- Syntax: GETMOUSE x,y[,wheel,[buttons]] Argument: Description: x,y Mouse position in screen coordinates is stored in these variables on function termination. If mouse is not present or out of the program window, x and y will hold -1. wheel Mouse wheel counter. Rotating the wheel away from you makes the count to increase, rotating towards you makes it to decrease. If mouse is not present or out of the program window, wheel will hold -1. buttons On function termination, this will return a bitmask holding buttons status. Bit 0 is set if left mouse button is down; bit 1 is set if right mouse button is down; bit 2 is set if middle mouse button is down. Insights: Use this function to get mouse info while in gfx mode. Pay attention: GETMOUSE does NOT work if a gfx mode is not set. Pass x, y, wheel and buttons variables by reference, so this function will store result values in them. If mouse is not present or out of the program window, all returned values will be -1. -------------------------------------------------------------------------------- Syntax: SETMOUSE [x][,[y][,cursor]] Argument: Description: x,y Screen coordinates of the new mouse cursor position. cursor Pass 0 to hide the cursor, or 1 to show it. Insights: This statement is useful to set the current system mouse cursor position, and to hide or show it. The cursor is shown by default when you call SCREEN. --------------------------------------------------------------------------------

THE CODING BEGINS:

Here are a set of constants that I declare at the beginning of the module. This is simply to gain a bit of clarity of code in the rest of the programming example.

CONST LEFTBUTTON = 1 CONST MIDDLEBUTTON = 2 CONST RIGHTBUTTON = 4 CONST SHOWMOUSE = 0 CONST HIDEMOUSE = 1

As a first step in this example, we will be declaring variables that we will be using throughout the example program. Of course you don't have to declare your variables, but me I like to do so because when you do so you know exactly why you're declaring your variables. To me that's good practice.

DIM CurrentX AS INTEGER DIM CurrentY AS INTEGER DIM MouseButtons AS INTEGER DIM CanExit AS INTEGER

The idea here is to do everything within a loop so that we can also control how the program exits. So we'll create a loop that will exit when the "CanExit" variable is equal to 0. In the loop we'll Interrogate the mouse and print some basic values. (this part is extracted from the example provided in the GETMOUSE syntax explanation in the gfxlib.txt file). Don't forget to set your graphics mode as it is a must to get valid return values from the mouse commands. We'll use Screen 12 for our example.

SCREEN 12 CanExit = 1 DO WHILE CanExit <> 0 GETMOUSE CurrentX, CurrentY, , MouseButtons IF CurrentX < 0 THEN PRINT "Mouse is out of context." ELSE PRINT USING "Mouse position: ###:### Buttons: "; CurrentX; CurrentY; IF MouseButtons AND LEFTBUTTON THEN PRINT "L"; IF MouseButtons AND MIDDLEBUTTON THEN PRINT "R"; IF MouseButtons AND RIGHTBUTTON THEN PRINT "M"; END IF LOOP

This sample will basically continuously display information about Where the mouse is, if it's on the program window and which mouse button is pressed if any. the GETMOUSE statement basically puts the current X and Y coordinates in our CurrentX and CurrentY variables and the status of the mouse buttons in our MouseButtons variable. The Three If Statements will print L if the left button was pressed, M if the middle button (or the wheel) was pressed and R if the Right button was pressed.

For the next step, since we want to control a bit what's happening with the mouse, will display a few extra things at the beginning of the program and control what happens with them afterwards, in the loop. This is regular text being displayed, this could be replaced by a series of line commands or something to draw a button for the different options. But that is outside the scope of this tutorial. So far, by getting rid of the unwanted print statements from the code above, the loop should now look like this:

SCREEN 12 SETMOUSE 1, 1, 1 CanExit = 1 LOCATE 1,1 PRINT " | FIRST | SECOND | THIRD | EXIT | " DO WHILE CanExit <> 0 LOCATE 1,1 GETMOUSE CurrentX, CurrentY, , MouseButtons LOOP

Basically we print the line that has " | FIRST | SECOND | THIRD | EXIT | " at the top of the screen. And we go into the loop that interrogates the mouse. Of course, right now nothing will happen if you press a button because there is no code for it. In our example, we'll add code that simple prints which option was selected. If the user selects the EXIT option, we'll print the Option and we'll exit the loop. We'll also add a print statement outside the loop with a sleep to tell the use that we are truely outside the loop and therefore the program is ended. With all this, the code should now look like this. I am putting the whole source file here so you can cut and paste it easily.

CONST LEFTBUTTON = 1 CONST MIDDLEBUTTON = 2 ' UNUSED IN THIS DEMO CONST RIGHTBUTTON = 4 ' UNUSED IN THIS DEMO CONST SHOWMOUSE = 0 CONST HIDEMOUSE = 1 DIM CurrentX AS INTEGER DIM CurrentY AS INTEGER DIM MouseButtons AS INTEGER SCREEN 12 SETMOUSE 1, 1, SHOWMOUSE CanExit = 1 LOCATE 1,1 PRINT " | FIRST | SECOND | THIRD | EXIT | " DO GETMOUSE CurrentX, CurrentY, , MouseButtons IF MouseButtons AND LEFTBUTTON THEN IF CurrentY <= 12 THEN IF CurrentX >= 0 AND CurrentX <=75 THEN LOCATE 12, 1 PRINT "First Option Selected "; ELSEIF CurrentX >= 76 AND CurrentX <= 147 THEN LOCATE 12, 1 PRINT "Second Option Selected"; ELSEIF CurrentX >= 148 AND CurrentX <=212 THEN LOCATE 12, 1 PRINT "Third Option Selected "; ELSEIF CurrentX >= 213 AND CurrentX <=268 THEN LOCATE 12, 1 PRINT "Last Option Selected "; EXIT DO ENd IF END IF END IF LOOP WHILE INKEY$ = "" SETMOUSE 1, 1, HIDEMOUSE PRINT PRINT "AND NOW WE'RE OUT OF THE LOOP" SLEEP

You can see the many IF statements in this last piece of code. The numbers that are there have been measured as per SCREEN 12 returned coordinates. They should work in all graphics mode however because a pixel is a pixel in a Console Graphics Window. Each if represents where the different options are written on the screen. If you would have used a graphics button routine you could simply use the same width and height as you did to draw the button in these if statements to know which button was clicked.

IN CONCLUSION:

As you can see, using the mouse has been made very simple in FreeBasic. You can use simple statement like the print command to draw your screens or you can use graphics command like LINE to draw your screens graphically. No matter which way you choose to draw your screens with, the SETMOUSE and GETMOUSE statement will work the same way and return the very same values. All you have to do is get that information and make your programs do what you want them to do if they press a button, select an option, or even in the case of a game, you could easily make the main character move towards the location where you clicked on the screen as well. The choice is up to you.

As always, if you have any questions regarding this tutorial or any other I've written, feel free to email me and we'll see what we can do about solving your particular problem.


MystikShadows
Stéphane Richard
srichard@adaworld.com


Download a copy of this tutorial, or contact MystikShadows.


Music Composition Part 2

Written by Matt2Jones

Dun - DeDunDun

Part III - The Score

Okay, after the RAVING SUCCESS of the first installment (Ie. No-one told me I fucked up) I return with the more practical and vocational section of Leaving Cert Music: Composition - Writing music.

First, to recap on last month, we learned that there are 11 notes, repeated on and on towards, but never reaching, infinity. We learned that the first note of a song is called the Key, and it dictates the notes that can follow pleasantly afterwards. We learned the how to find the notes in the Key of Any note you choose by means of the 'stencil' analogy (remember, skip one, skip one, etc... ?). And finally we learned how to find notes that will sound pleasing to the ear when played at the same time via Chords. At least that was the important stuff. What you didn't learn was how to do ANYTHING AT ALL with the knowlage. That's what this installment is to redress.

The conventional method for writting music oft referred to as Scores, Sheet Music, 'The Stave', and undoubtably many other blandular words, but it has been perfected over the years so it's realy quite effective for writing music so that's what I'm going to teach you to use (tongue having been bionicaly implanted into cheek many years previously...).

You will notice that the Nature of the Stave eliminates the need to worry, or indeed know about, the fiddly technical 'low level' bits I explained previously, like how many semi tones between each note in a key, or Chord, so it should agree with the more vocational, practical, and the the guys who like OOP and continuously jabber 'Classes are great because you don't need to know Anything...' Sorry, its my problem, I'll deal with it....

For our 'intensive' purposes this is the medium inwhich your music shall be written:


The curly thing on the left is called the 'Clef', this particular one being the 'Treble Clef'. When you see this symbol it tells you the following:

That is what you are to think every time you see the treble clef.

From the First (AKA Bottom) line, to the Fifth (AKA Top) Line the Notes are:

E, G, B, D, F

There are many helpful acronyms to help you remember these. Every Good Boy Deserves Fruit, Every Great Bum Dies Fucked, Every Gay Bum Dies Fucked, they aren't hard to invent, but thanks to my own personal, ingenious, observations, you won't need to resort to this primitive level.

You see the spaces between the lines also represent notes, and those notes are (from the first space (aka the space above the bottom line)) to the fourth space (aka the space below the top line):

F, A, C, E

For some reason there are no helpful rhymes to aid commiting this sequence to memory.



But, in steps the mightly M2J, there is an easier way to remember them! And it is as follows:

Combine the two sequences in order, from botom line, to the adjacent space, the who way up, and you get:

E, F, G, A, B, C, D, E, F

Look familiar?



Now here is where you are to appreciate the wonders and ease of use of 'The Score System':

As you should be able to tell, all the above notes are notes in the Key of C. So if you are writing music in the Key of C, you could, hypotheticly, write a note on any one of those lines or spaces and it would sound okay. You wouldn't even have to think, just drop your pen on the five lines and where-ever it landed everything would be cool.

Now, let's examine the Key of G for a while.

The key of G consists of:

G, A, B, C, D, E, F#

(Remember the method last month to work that out)



Now, this is mostly the same as the Key of C, so if we were writing sheet music in the Key of G via a falling pen, the music would sound okay, as long as it didn't hit the fifth line, which represents F, which is not in the key of G.

Lets examine the difference between the two Keys of C and G again. Aside from them both starting on different notes, there is only ONE difference, and that is there is an F, and an F# in the key of G. Now, we have a system that can cater for the key of C quite well, and if there's only one note, only one semitone for christsakes, keeping us from using it for the key of G aswel, so what do we do.

Well, I think the obvious solution would be to put a mark on the Line that represents F, to indicate that whenever this note is played, you play F# instead instead of F. And thats exactly what you do. The "Key Signature" for the Key of G is:


In a Concise....Wrong Nutshell they Key Signature is the combination of Sharps (#'s) and Flats (b's) that follow the Clef, which 'configures' the five lines to be in a certain key. You follow? If not, email me :-P

There will be a list of Keys and Key signatures at the end of the Chapter.

Okay, so we've covered the Cleft, what it is, and the Key Signatures, but whats up with the 4/4 in between them? Well, this describes the rhythm the song will be written in. The Top number is the amount of Beats-in-the-Bar, which is hard to explain unless you already know what I'm talking about, suffice it is to say, leaving it at four will do fine for now. The bottom number is even more technical, it describes which of the musical Symbols will be used for one 'beat'. So 4/4 means there will be four one quater beats per bar.

We will be fucking around with time signatures (the 4/4 thing) later, but for the moment this brings us nicely into the next section...

Part IV - Rhythm


Let's examine this peice of music here. What can we tell about it?

Well first up, the lack of any #'s or b's mean this is written in the Key of C. Second, we can tell by the Trebel Clef that the notes, from bottom line to top line, are E, F, G, A, B, C, D, E, F. From this we can deduce that the first note of the Peice is a C (Which makes sense since this is in the Key of C...).

Now, we know that this is in 4/4 time, but what does that actually tell us?

To Understand this fully we're going to need to know the values of the Notes Rhythmically (?spell anyone?).

The Crotchet:

In x/4 time this is the note that represents one 'beat' of the bar, because a Crotchet is a Quater (1/4) note. The Rule is if the Bottom number of the time signature is a 4, then a Crotchet = 1 Beat.

The Quaver:

Quavers are one eighth of a note (1/8), and so any note written as a quaver should last half as long as a note written as a Crotchet. In 4/4 time Quavers are paired together with a line joining the stems, one pair of which = 1 Beat.

The Minum:

Any note written as a Minum lasts twice as long as a note written as a Crotchet, and in 4/4 time one minum = 2 beats.

Don't worry if you don't get what the fuck I'm on about, I'm now going to go through it all in Patronising Detail:


Okay, the first note is a Crotchet, and it is written on the third space, which is C, so the peice will begin with the Note C being played for one 'beat' (an undefined yet constant length of time, say, half a second?), and then followed by the Note E, which is a Quaver, so played for half the time the Crotchet was played for (which would be a quater of a second in this case), then Followed by the Note F, again a quaver, so played for the same length of time for the previous note.

Now, this is 4/4 time, which has four beats in a bar, and we said a Crotchet counts for 1 beat, and a quaver counts for a half (a pair counting for 1) beat, so that means we are 2 beats into the first bar, with a total of 4 beats to go through, so we should be half way. Making sense?

Next is another Quaver, on the note of A, so again, we play it for one half beat, and next another quaver, on G, another half beat, and finaly, at the end of the Bar, a Crotchedt on E, to be played for one beat.

So lets tally up the scores:

4 	.... beats in the bar
4	.... 1/4 note = 1 beat   ....  4 x 1/4 = one bar

From the start:
	1/4 + 1/8+1/8 + 1/8+1/8 + 1/4 = 1 = 4 x 1/4 = one bar

Yay! We have one bar played.

Do you have a better grasp on it now?

Okay, now take a look at the last note in the peice, 'The Minum'. This lasts for 2 beats, as you can see from above, and, as a rule of thumb, heralds the end of a 'Phrase'. A Phrase is like a musical sentence (I hate analogies like that but its all I can think of), its a peice of music with a beginning, middle and end, made of up a certain number of bars. The music peice is made up of a load of Phrases, each with, generaly speaking, the same number of bars per Phrase.

So in this case we have a four bar Phrase, with four beats to the bar (ie. 4/4 time), which is all very symetrical and divisable and binary.

Right, I was going to start talking on actually writing music at this point, but today is the submition deadline, and, looking back, I'm still on the schedual I'd planned, so we'll call it a day (/month...) and next month, I SWEAR I'll teach you how to write music.

M2j


Download this tutorial (1.237MB!), or contact Matt2Jones.


VisualBASIC for DOS - Creating Custom Controls

Written by Stéphane Richard (Mystikshadows)

INTRODUCTION:

Welcome to this tutorial on creating custom controls for VB-DOS Professional. We will learn how to create custom controls for VB-DOS Professional Edition (this is the only one that allows us to create custom controls). When you design a dialog in VB-DOS, you have a form (on the right) and a toolbox (on the left) where all the controls that you can insert on the form are. in VB-DOS Professional, there's a way to add controls that aren't on that toolbox by default. These are what's known as a custom control.

In this technique we'll create a custom control and see how to use it in a typical application's form design. In the next section I'll explain what you will need to create the custom controls and the steps involved in creating the control.


WHAT YOU WILL NEED:

In order to create custom controls there's a couple things you'll need to make sure you have. If you don't have everything, don't worry, you can still learn how things work, but to create your own custom controls you'll need to see if you can find what's listed here.

GETTING STARTED:

Let's get right to it. I'm not going to invent a control because that would make this technique so long to read that even I couldn't stay up long enough to write it. So, we'll be using a control that's been created already, it comes with your Visual Basic for DOS installation, in the INCLUDE directory. it's has 4 files total that are called SPIN.BAS, SPINREG.ASM, SPINDEMO.FRM and SPINDEMO.MAK respectively.


ABOUT THE CUSTOM CONTROL GENERATOR:

CUSTGEN.EXE is a utility that you use when you want to create custom controls. When you double click on it, or execute it. you can see the main screen which looks like this:


You need to specify a Control Name and select the properties you'll want your control to have and the methods you'll want your control to manage. You can also select which language to generate the control template that you will be modifying. Finally, you can also specify if the control will be a container control. A container control is a container which can hold other controls within itself. For example a form is a container control because it can hold other types of controls in itself.

The list of Possible Events on the left can be changed, there are more events than those you can see on that list. To add to these events just click the Events button on the right, it will bring you to a this following dialog.


The list on the left is the list of events that are already available, as you can see by the fact that the list on the right is empty (by default) all events are available, if you don't want to see some of those events you can take them out of any list by clicking on the event or events you don't want and clickin the -> button, you'll see them get deleted from the list on the left and added to the list on the right. when you're done, just click the OK button to go back to CUSTGEN's main screen.

As you might have noticed when designing forms in VB-DOS, when you insert a control on a form, they each have their properties that you can set. For example, you can change the caption property of a label control to change what is displayed on the screen for that given label control. Just like the events, you can select what properties you want your control to allow to change. On the main screen, click the Properties button on the right and you'll see this screen:


Just like the list of events, all you need to do is take away the properties you don't want shown for your control. This is done by selecting the properties from the list and hitting the -> button to add them to the list of "not available" properties.

Once you have everything entered, properties and events selected and you are ready to create the custom control you just hit the Generate button, this will bring you to this screen:


Just enter a name for the Assembler Registration IsHandler (SPINREG.ASM was used for this purpose in the SPIN control) and the control name (which will be a .BAS file if you selected BASIC from the languages on the main screen, SPIN.BAS in our sample control). Once that's done, hit the OK button and CUSTGEN will create the control template for you. Then all you need is to edit the .bas file to implement the methods/events that you wanted to implement by adding the code you want executed for each of these events.


FINAL STEP, COMPILING AND LINKING:

Indeed, at this point, everything is generated, you've properly inserted the code in the different event methods you wanted to and you are now ready to create the control itself. In VB-DOS a custom control is quite simple a library / Quick Library set of files. I'm assuming here that you have MASM and VB-DOS installed and that your PATH variable is setup to have the MASM an VB-DOS paths added and ready. In order to get that set of files, here are the steps required:

SPECIAL NOTE:

As you know, the I.D.E. allows the loading of only one Quick Library (.QLB) file per session. You can of course combine multiple controls into one bigger Quick Library so that all controls can be used at once. To do so, just follow these 3 steps:

IN CONCLUSION:

If all went well, at this point you should now have a SPIN.LIB library, it's Quick library equivalent SPIN.QLB and a VBDOSQLB.LIB that has the regular VB-DOS default controls as well as your custom control ready to be used in your projects that is if you have Visual Basic for DOS version 1.0 Professional and MASM handy on your hard drive.

As always I hope this technique proves useful to at least one of you. Most of this was created from memory (and with testing of the spin control itself) so if I've omitted something you feel might be important to add, drop in an email at the email listed below and I'll see about correcting things as soon as possible.


MystikShadows
Stéphane Richard
srichard@adaworld.com


Download a copy of this tutorial.


FreeBASIC Allegro Tutorial 1

Written by Gustav

Someone recently told me about FreeBASIC and I've been a C++ programmer for awhile now so I decided to port a basic Allegro application from C++ to freeBASIC and write a tutorial about it.

The first thing you must always do when creating a freeBASIC allegro application is declear the library like this;

freeBASIC C++ '$include "allegro.bi" #include

The next thing I'll be doing is declearing some constant variables. This is done by using the define statement. This is then followed by a variable and then its parameter like in the following syntax;

freeBASIC C++ #define SCREEN_WIDTH 640 #define SCREEN_WIDTH 640 #define SCREEN_HEIGHT 480 #define SCREEN_HEIGHT 480

This is particularly useful because if your program becomes very large and you want to change one of the variables you only change it in the define statement. As opposed to changing it at every statement in the program that uses the variable.

Next, we need to create our procedures/subs. I'll be creating one procedure that initiates allegro, one for the main loop and one that exits the program. The first procedure will contain a statement that initiates allegro, the next will install they keyboard and the third will set the graphics mode.

freeBASIC C++ sub rs_init_allegro() void rs_init_allegro(void) { allegro_init allegro_init(); install_keyboard() install_keyboard(); set_gfx_mode(GFX_AUTODETECT, SCREEN_WIDTH, set_gfx_mode(GFX_AUTODETECT, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0) SCREEN_HEIGHT, 0, 0) end sub }

GFX_AUTODETECT is the mode in which the application will be displayed, also known as the screen- mode. This particulair screen-mode sets the application at full-screen but if the resolution is not allowed it detects that, and sets the mode to windowed. There are also many other screen- modes such as the following;

The next procedure we'll be creating is the main procedure that will handle the main loop. It will also detect whether you have pressed the ESC key and if so, it will then exit the loop. It should look something like this;

freeBASIC C++ sub rc_main_loop() void rc_main_loop(void) do while (!key[KEY_ESC) if (*(@al_key+KEY_ESC) <> 0) then { exit do end if } loop } end sub

The last procedure necessary to write a basic allegro program is the procedure that exits the program. It should close any bitmaps that were loaded or created. It is quite simple and should look like this;

freeBASIC C++ sub rc_exit() void rc_exit(void) { allegro_exit() allegro_exit(); end sub }

The allegro_exit() function is not necessary to exit the application but it is always good to include it. Next on our list is the main body of code. In this section of code we simply call all the procedures we've created and then end the program.

freeBASIC C++ rs_init_allegro() int main(int argc, char *argv) { rs_main_loop() rs_init_allegro(); rs_exit() rs_main_loop(); end 0 rs_exit(); } END_OF_MAIN();

Now that you've finished writing your code it should look something like this;

'' Simple Alegro Window Programmed by Gustav '' Declear Libraries '$include: "allegro.bi" '' Definitions #define SCREEN_WIDTH 640 #define SCREEN_HEIGHT 480 '' Procedures sub rs_init_allegro() allegro_init '' Install allegro install_keyboard() '' Install keyboard set_gfx_mode(GFX_AUTODETECT, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0) '' Set graphics mode end sub sub rs_main_loop() do if (*(@al_key+KEY_ESC) <> 0) then '' Determin is ESC is pressed exit do '' Exit loop end if loop end sub sub rs_exit() allegro_exit() '' Exits allegro end sub '' Main Procedure rs_init_allegro() '' Install allegro & set graphics rs_main_loop() '' Begin main loop rs_exit() '' Exit application end 0

Download a copy of this tutorial.
You can contact Gustav at UbeltaterSchatten@Hotmail.com.


Animation Part 2:
Motive Power of Animation

Written by Rattrapmax6

Introduction:

Well in the last tutorial I carried on about the basic parts of animation. I never did tell you how to move them for several reasons. One well, I’m submitting these to Pete’s magazine and left it for something else to submit. Two, moving them is a whole another lesson. And three, I left you to practice with what a taught you to better under stand what I’m about to drop you into... let's carry on now...

Moving the Animation:

Yes, just like last time, we need frames.. I’ll carry the two we did for the first lesson:

SCREEN 13 DATA 23,23,23,23,00,00,00,00,00,00,00,00,00,00,00,00,23,23,23,23 DATA 22,22,22,22,00,00,00,00,00,00,00,00,00,00,00,00,22,22,22,22 DATA 21,21,21,21,00,53,53,53,53,53,53,53,53,53,53,00,21,21,21,21 DATA 22,22,22,22,28,55,55,55,55,55,55,55,55,55,55,28,22,22,22,22 DATA 21,21,21,21,00,55,55,55,55,55,55,55,55,55,55,00,21,21,21,21 DATA 22,22,22,22,00,55,55,55,55,55,55,55,55,55,55,00,22,22,22,22 DATA 21,21,21,21,00,55,55,55,55,55,55,55,55,55,55,00,21,21,21,21 DATA 22,22,22,22,00,55,55,55,55,55,55,55,55,55,55,00,22,22,22,22 DATA 21,21,21,21,00,55,55,55,55,55,55,55,55,55,55,00,21,21,21,21 DATA 22,22,22,22,00,55,55,55,55,55,55,55,55,55,55,00,22,22,22,22 DATA 21,21,21,21,00,55,55,55,55,55,55,55,55,55,55,00,21,21,21,21 DATA 22,22,22,22,00,55,55,55,55,55,55,55,55,55,55,00,22,22,22,22 DATA 21,21,21,21,00,55,55,55,55,55,55,55,55,55,55,00,21,21,21,21 DATA 22,22,22,22,00,55,55,55,55,55,55,55,55,55,55,00,22,22,22,22 DATA 21,21,21,21,00,55,55,55,55,55,55,55,55,55,55,00,21,21,21,21 DATA 22,22,22,22,00,55,55,55,55,55,55,55,55,55,55,00,22,22,22,22 DATA 21,21,21,21,28,55,55,55,55,55,55,55,55,55,55,28,21,21,21,21 DATA 22,22,22,22,00,01,01,01,01,01,01,01,01,01,01,00,22,22,22,22 DATA 21,21,21,21,00,00,00,00,00,00,00,00,00,00,00,00,21,21,21,21 DATA 20,20,20,20,00,00,00,00,00,00,00,00,00,00,00,00,20,20,20,20 FOR y = 1 TO 20 FOR x = 1 TO 20 READ z PSET (x, y), z NEXT NEXT DIM sprt1(20 * 20): GET (1, 1)-(20, 20), sprt1 CLS DATA 23,23,23,23,00,00,00,00,00,00,00,00,00,00,00,00,23,23,23,23 DATA 21,21,21,21,00,00,00,00,00,00,00,00,00,00,00,00,21,21,21,21 DATA 22,22,22,22,00,53,53,53,53,53,53,53,53,53,53,00,22,22,22,22 DATA 21,21,21,21,28,55,55,55,55,55,55,55,55,55,55,28,21,21,21,21 DATA 22,22,22,22,00,55,55,55,55,55,55,55,55,55,55,00,22,22,22,22 DATA 21,21,21,21,00,55,55,55,55,55,55,55,55,55,55,00,21,21,21,21 DATA 22,22,22,22,00,55,55,55,55,55,55,55,55,55,55,00,22,22,22,22 DATA 21,21,21,21,00,55,55,55,55,55,55,55,55,55,55,00,21,21,21,21 DATA 22,22,22,22,00,55,55,55,55,55,55,55,55,55,55,00,22,22,22,22 DATA 21,21,21,21,00,55,55,55,55,55,55,55,55,55,55,00,21,21,21,21 DATA 22,22,22,22,00,55,55,55,55,55,55,55,55,55,55,00,22,22,22,22 DATA 21,21,21,21,00,55,55,55,55,55,55,55,55,55,55,00,21,21,21,21 DATA 22,22,22,22,00,55,55,55,55,55,55,55,55,55,55,00,22,22,22,22 DATA 21,21,21,21,00,55,55,55,55,55,55,55,55,55,55,00,21,21,21,21 DATA 22,22,22,22,00,55,55,55,55,55,55,55,55,55,55,00,22,22,22,22 DATA 21,21,21,21,00,55,55,55,55,55,55,55,55,55,55,00,21,21,21,21 DATA 22,22,22,22,28,55,55,55,55,55,55,55,55,55,55,28,22,22,22,22 DATA 21,21,21,21,00,01,01,01,01,01,01,01,01,01,01,00,21,21,21,21 DATA 22,22,22,22,00,00,00,00,00,00,00,00,00,00,00,00,22,22,22,22 DATA 20,20,20,20,00,00,00,00,00,00,00,00,00,00,00,00,20,20,20,20 FOR y = 1 TO 20 FOR x = 1 TO 20 READ z PSET (x, y), z NEXT NEXT DIM sprt2(20 * 20): GET (1, 1)-(20, 20), sprt2

Okay, we got the two robots again. Last time I covered just the animation, now I'll cover moving it. First we need to set up some arrays and variables...

CLS DIM mask(20 * 20): GET (1, 1)-(20, 20), mask y = 100: x = 160 ox = x: oy = y PUT (x, y), sprt1, PSET

CLS, you can guess what that does.. DIM mask(20 * 20): GET (1,1)-(20, 20), mask, this will be a black tile set just before moving the robot, it will prevent smearing.. y = 100: x = 160, Where we want to start the robot at.. ox = x: oy = y, this is the old positions of the robot, we update these in the code just before adding the X, Y. The ox & oy is where the mask is set.. PUT (x, y), sprt1, PSET, this will set the sprite on the screen so we see it from the get go.. Now lets take a look at the main control structure..

DO ' Master LOOP FOR i = 1 TO 10 'Control LOOP press$ = INKEY$ ox = x: oy = y {Sub control code here} WAIT &H3DA, 8 'Keeps it clean.. IF press$ = CHR$(27) THEN END 'Ends LOOP on Keypress .. FOR a = 1 TO 1000: NEXT 'Controls speed.. NEXT LOOP

All the same except for a few new things: press$ = INKEY$, this will prompt the keyboard.. ox = x: oy = y, this will update the ox & oy so we can place the mask and clear the part of the screen the robot was setting.. WAIT &H3DA, 8 is moved to the bottom, this just shows you can place it here also. (Can be before you draw or after, effects are the same, stop and think why.) IF press$ = CHR$(27) THEN END, last time I had it on the LOOP UNTIL, but this time its much nicer to have it inside the FOR.. NEXT loop. This way your not waiting for 10 loops to exit.. Now, the code that moves the animation..

IF press$ = CHR$(0) + CHR$(72) THEN ' Up Arrow Key y = y - 1: PUT (ox, oy), mask, PSET ' Prevents smearing IF i <= 5 THEN PUT (x, y), sprt1, PSET 'First frame on LOOP 1 - 5 IF i > 5 THEN PUT (x, y), sprt2, PSET 'Second frame on LOOP 6 - 10 ELSEIF press$ = CHR$(0) + CHR$(80) THEN ' Down Arrow Key y = y + 1: PUT (ox, oy), mask, PSET ' Prevents smearing IF i <= 5 THEN PUT (x, y), sprt1, PSET 'First frame on LOOP 1 - 5 IF i > 5 THEN PUT (x, y), sprt2, PSET 'Second frame on LOOP 6 - 10 END IF

Look hard enough yet?? Its not really, lets break this down. IF press$ = CHR$(0) + CHR$(72) THEN, runs a block of code on keypress Up Arrow. It can be wrote like this also: "IF press$ = CHR$(0) + "H" THEN".

The Up Arrow block of code goes like this: y = y - 1, this will move the robot up the screen.. PUT (ox, oy), mask, PSET, this will clear the last spot where the robot was setting... And if you learned any thing from the last tutorial, the next two lines places the animation according to the loop number..

ELSEIF press$ = CHR$(0) + CHR$(80) THEN, else if?? You use this in a IF.. THEN block so when you end it you only need one END IF... other wise you would place a END IF for how many IF THEN blocks used. The only thing different about the Down Arrow block is y = y + 1, this moves the robot down the screen. The rest of the code is the same as the above block. END IF closes the IF.. THEN block.. Here is the whole control code:

DO ' Master LOOP FOR i = 1 TO 10 'Control LOOP press$ = INKEY$ ox = x: oy = y IF press$ = CHR$(0) + CHR$(72) THEN ' Up Arrow Key y = y - 1: PUT (ox, oy), mask, PSET ' Prevents smearing IF i <= 5 THEN PUT (x, y), sprt1, PSET 'First frame on LOOP 1 - 5 IF i > 5 THEN PUT (x, y), sprt2, PSET 'Second frame on LOOP 6 - 10 ELSEIF press$ = CHR$(0) + CHR$(80) THEN ' Down Arrow Key y = y + 1: PUT (ox, oy), mask, PSET ' Prevents smearing IF i <= 5 THEN PUT (x, y), sprt1, PSET 'First frame on LOOP 1 - 5 IF i > 5 THEN PUT (x, y), sprt2, PSET 'Second frame on LOOP 6 - 10 END IF WAIT &H3DA, 8 'Keeps it clean.. IF press$ = CHR$(27) THEN END 'Ends LOOP on Keypress .. FOR a = 1 TO 1000: NEXT 'Controls speed.. NEXT LOOP

Wow, I hope all this helps in creating animations in your QBasic programs. I'll see about doing a animation tutorial with more than two frames. I'll leave you with the complete code of what we did above:

SCREEN 13 DATA 23,23,23,23,00,00,00,00,00,00,00,00,00,00,00,00,23,23,23,23 DATA 22,22,22,22,00,00,00,00,00,00,00,00,00,00,00,00,22,22,22,22 DATA 21,21,21,21,00,53,53,53,53,53,53,53,53,53,53,00,21,21,21,21 DATA 22,22,22,22,28,55,55,55,55,55,55,55,55,55,55,28,22,22,22,22 DATA 21,21,21,21,00,55,55,55,55,55,55,55,55,55,55,00,21,21,21,21 DATA 22,22,22,22,00,55,55,55,55,55,55,55,55,55,55,00,22,22,22,22 DATA 21,21,21,21,00,55,55,55,55,55,55,55,55,55,55,00,21,21,21,21 DATA 22,22,22,22,00,55,55,55,55,55,55,55,55,55,55,00,22,22,22,22 DATA 21,21,21,21,00,55,55,55,55,55,55,55,55,55,55,00,21,21,21,21 DATA 22,22,22,22,00,55,55,55,55,55,55,55,55,55,55,00,22,22,22,22 DATA 21,21,21,21,00,55,55,55,55,55,55,55,55,55,55,00,21,21,21,21 DATA 22,22,22,22,00,55,55,55,55,55,55,55,55,55,55,00,22,22,22,22 DATA 21,21,21,21,00,55,55,55,55,55,55,55,55,55,55,00,21,21,21,21 DATA 22,22,22,22,00,55,55,55,55,55,55,55,55,55,55,00,22,22,22,22 DATA 21,21,21,21,00,55,55,55,55,55,55,55,55,55,55,00,21,21,21,21 DATA 22,22,22,22,00,55,55,55,55,55,55,55,55,55,55,00,22,22,22,22 DATA 21,21,21,21,28,55,55,55,55,55,55,55,55,55,55,28,21,21,21,21 DATA 22,22,22,22,00,01,01,01,01,01,01,01,01,01,01,00,22,22,22,22 DATA 21,21,21,21,00,00,00,00,00,00,00,00,00,00,00,00,21,21,21,21 DATA 20,20,20,20,00,00,00,00,00,00,00,00,00,00,00,00,20,20,20,20 FOR y = 1 TO 20 FOR x = 1 TO 20 READ z PSET (x, y), z NEXT NEXT DIM sprt1(20 * 20): GET (1, 1)-(20, 20), sprt1 CLS DATA 23,23,23,23,00,00,00,00,00,00,00,00,00,00,00,00,23,23,23,23 DATA 21,21,21,21,00,00,00,00,00,00,00,00,00,00,00,00,21,21,21,21 DATA 22,22,22,22,00,53,53,53,53,53,53,53,53,53,53,00,22,22,22,22 DATA 21,21,21,21,28,55,55,55,55,55,55,55,55,55,55,28,21,21,21,21 DATA 22,22,22,22,00,55,55,55,55,55,55,55,55,55,55,00,22,22,22,22 DATA 21,21,21,21,00,55,55,55,55,55,55,55,55,55,55,00,21,21,21,21 DATA 22,22,22,22,00,55,55,55,55,55,55,55,55,55,55,00,22,22,22,22 DATA 21,21,21,21,00,55,55,55,55,55,55,55,55,55,55,00,21,21,21,21 DATA 22,22,22,22,00,55,55,55,55,55,55,55,55,55,55,00,22,22,22,22 DATA 21,21,21,21,00,55,55,55,55,55,55,55,55,55,55,00,21,21,21,21 DATA 22,22,22,22,00,55,55,55,55,55,55,55,55,55,55,00,22,22,22,22 DATA 21,21,21,21,00,55,55,55,55,55,55,55,55,55,55,00,21,21,21,21 DATA 22,22,22,22,00,55,55,55,55,55,55,55,55,55,55,00,22,22,22,22 DATA 21,21,21,21,00,55,55,55,55,55,55,55,55,55,55,00,21,21,21,21 DATA 22,22,22,22,00,55,55,55,55,55,55,55,55,55,55,00,22,22,22,22 DATA 21,21,21,21,00,55,55,55,55,55,55,55,55,55,55,00,21,21,21,21 DATA 22,22,22,22,28,55,55,55,55,55,55,55,55,55,55,28,22,22,22,22 DATA 21,21,21,21,00,01,01,01,01,01,01,01,01,01,01,00,21,21,21,21 DATA 22,22,22,22,00,00,00,00,00,00,00,00,00,00,00,00,22,22,22,22 DATA 20,20,20,20,00,00,00,00,00,00,00,00,00,00,00,00,20,20,20,20 FOR y = 1 TO 20 FOR x = 1 TO 20 READ z PSET (x, y), z NEXT NEXT DIM sprt2(20 * 20): GET (1, 1)-(20, 20), sprt2 CLS DIM mask(20 * 20): GET (1, 1)-(20, 20), mask y = 100: x = 160 ox = x: oy = y PUT (x, y), sprt1, PSET DO ' Master LOOP FOR i = 1 TO 10 'Control LOOP press$ = INKEY$ ox = x: oy = y IF press$ = CHR$(0) + CHR$(72) THEN ' Up Arrow Key y = y - 1: PUT (ox, oy), mask, PSET ' Prevents smearing IF i <= 5 THEN PUT (x, y), sprt1, PSET 'First frame on LOOP 1 - 5 IF i > 5 THEN PUT (x, y), sprt2, PSET 'Second frame on LOOP 6 - 10 ELSEIF press$ = CHR$(0) + CHR$(80) THEN ' Down Arrow Key y = y + 1: PUT (ox, oy), mask, PSET ' Prevents smearing IF i <= 5 THEN PUT (x, y), sprt1, PSET 'First frame on LOOP 1 - 5 IF i > 5 THEN PUT (x, y), sprt2, PSET 'Second frame on LOOP 6 - 10 END IF WAIT &H3DA, 8 'Keeps it clean.. IF press$ = CHR$(27) THEN END 'Ends LOOP on Keypress .. FOR a = 1 TO 1000: NEXT 'Controls speed.. NEXT LOOP

Until next time! Happy animating! :D

-Kevin (x.t.r.GRAPHICS)


Download a copy of this tutorial.
Visit x.t.r. GRAPHICS or email Kevin at Rattrapmax6@aol.com.


Useless Useful Information: Parsers

Written by Nathan1993

Welcome!

This could be the first of my tutorials. A series? Nah... I'll just write some more about text.

Well... This will be about some text animation. I gotta go mess around with QB for a few mins...

Hmm... this might take longer than I though! Well, end first segment time: 6:12 eatern atlantic time, Febuary 22!

Nevermind... so a parser tutor it is.

Current time: 6:42 Eastern time. March 8! LoLoLz...

OK.. now to find my parser code! (LaLaLaLaLALALAlalalaLALALA)

Heres the code:

FUNCTION CheckSpace (Var AS STRING) FOR i = 1 TO LEN(Var) IF MID$(Var, i, i - 1) = " " THEN CheckSpace = True NEXT i END FUNCTION SUB Parse (Answer$, Word1$, Word2$) Parse: Answer$ = LTRIM$(RTRIM$(Answer$)) IF Answer$ = "" OR Answer$ = " " THEN Word$ = Answer$ Index = 0 DO Index = Index + 1 IF MID$(Answer$, Index, 1) = " " THEN EXIT DO LOOP Word1$ = LEFT$(Answer$, Index - 1) num = LEN(Answer$) 'You had this so close, you Answer$ = RIGHT$(Answer$, num - Index) 'did it backwards. RIGHT$ 'reads from the right, so 'you have to subtract Index IF CheckSpace(Answer$) THEN 'from the total number of GOTO Parse 'characters... that gives ELSE 'you the right calculation. Word2$ = LTRIM$(RTRIM$(Answer$)) EXIT SUB END IF END SUB

OK, copy those subs to your program. Then just call like this

Parse TwoWordStringToParse$, TheFirstReturnedWord$, TheSecondReturnedWord$.

Now, I am a good person (well, no I'm not)but I feel that I commented the code, so it will be easyer.

OK... now, basicly what it does it check for spaces. When it finds the spaces, it cuts the word with the mid function. The checkspace thing just returns the place of the space.

Hey that rhymes, and you know it rhymes. Admit it! You wanted me to crawl, but this man dosn't crawl he stands tall! I BEET CITY HALL! </quotefromsimpsons>

Anyway... Then, if it is any spaces left, then you trim them off. I have to go, guys. Well, this is the end of my parser tutor!

OK, so its not the end. I'll do a little more on explaining some functions in a sec. Or later... 3:31, March 8th; getting ready to go to tae-kwon-do. OK... just got home on the 10th. OK... about the functions!

I know some of you guys don't like GOTOs...

_ _ _
B|_| | 1 d0n| (_@r3!!!

Thats all! Feel free to use as needed.

DONT COPY MY CODE! That is why this is a TUTOR; not a freebie or code snippet.

Don't credit me (fine if you do) becuase you will probably forget.

It is now 3:17 PM March 15 and I am PMing this to pete as we... er, I am sending this message.


Contact Nathan1993 at this address, or download this article.


File Manipulation In QBasic #3: Binary Files

Written by Stéphane Richard (Mystikshadows)

INTRODUCTION:

Welcome to the 3rd of this file manipulation series, you guessed it by the title already, we'll be covering the concept of binary file access. What are those? The answer comes in more than one flavor. you could say that any file that you can't open in a text editor and read is either a random access file or a binary file. Here are a few examples of such files:

All this to say that there are many reasons binary files are used hence more than one structure behind them as well. The important thing to know is that if you are provided with the right information, you will be able to open any and all of these binary files.

ADVANTAGES OF USING BINARY FILES:

Since all these companies use binary files for their storage system (be it documents, databases, spreadsheets, graphics, vector graphics and everything else), there must be a reason why these companies chose binary over the other formats. There's more than one reason actually. Here are the main advantages:

WORKING WITH BINARY FILES:

To work with binary files I do have to say you need to plan things ahead atleast a bit. if you think of what I just said for the advantages, you can imagine why we might need to plan ahead. Don't forget that the variables you choose to read from or write to a binary file represents the actual amount of bytes that will be read. Planing ahead (a little) will help you stay ahead of the situation especially when changes to what is being read or written occurs.

Now, just like Random Access File, you'll be using the OPEN and CLOSE statements and the GET and PUT statements to GET (read) from the file and PUT (write) to the file. Here is a first small example to set the command syntax straight. The example will open a file in binary mode, put 2 values in the file and then read them back in and finally it will close the file.

' --------------------------------- ' Work variables for this example ' --------------------------------- DIM FileHandle AS INTEGER DIM FirstField AS INTEGER ' TO READ/WRITE 2 BYTES (4 BYTES IN FREEBASIC) DIM SecondField AS LONG ' TO READ/WRITE 4 BYTES (4 BYTES IN FREEBASIC) ' ------------------------ ' First we open the file ' ------------------------ FileHandle = FREEFILE OPEN "TEST.BIN" FOR BINARY AS #FileHandle ' ------------------------ ' Next we write 2 values ' ------------------------ FirstField = 4 SecondField = 13040392 PUT #FileHandle, , FirstField PUT #FileHandle, , SecondField ' ------------------------------------------------------ ' We clear the variables to test the reading of values ' ------------------------------------------------------ FirstField = 0 SecondField = 0 ' --------------------------------------------------- ' We position ourselves on the first byte (to read) ' --------------------------------------------------- SEEK #FileHandle, 1 GET #FileHandle, , FirstField GET #FileHandle, , SecondField ' ------------------------------------------ ' We print the variables we have just read ' if it worked, 4 and 13040392 should show ' ------------------------------------------ PRINT FirstField, SecondField ' ------------------------------ ' We close the file, of course ' ------------------------------ CLOSE #FileHandle

I believe this little example is pretty much self explanatory so I'm not going to comment on it too much. Basically notice the change in the OPEN statement which now says OPEN "FileName.Ext" FOR BINARY AS #FileHandle. I use the FREEFILE here as well because it's good practice in binary files just like any other file types. Naturally, at the end of the program I close the file.

A MORE PRACTICAL USE OF BINARY FILES:

What you saw in the first sample program above probably has you wondering what the real use of binary files is. It's important to know that to read or write binary files you can use any data type, including User Defined Types that you create. You can also mix and match data types as well. For example you could easily have a TYPE / END TYPE structure for the header part of the file and a list of LONG values for the rest of the file. It really depends on what the needs are. That's the beauty of binary files, the way you can mix and match types of data and as long as you know what you did you will always be able to read the data the way it's supposed to be read.

In this section we'll be creating a little example that you'll be able to use as a template for your own creations. Most binary files created by software manufacturers are generally composed of 2 parts. The header and the rest of the file (which can be one big remander of the file (in the case of graphic file formats) or more of a repetetive nature (much like the now well known DBase File Format (the DBF file). Some might have 3 or more parts as well. Our example will user TYPE Definitions to create a generic database structure somewhat similar to DBASE's DBF file format. Note that for this example we won't be creating Indexes or relationship, we'll simple create a format to store the data we need. The complete code is available here.

DATABASE FORMAT DEFINITION:

When create a file format that can change, you have to ask yourself how to go about it. What you will need to know in order to have control over the rest of the file. In other words, you'll want to know what will go in the header part of the database file. Here's a User Defined Type that typically would be adequate for our needs.

' ------------------------------------------------------ ' This Structure holds the database header information ' ------------------------------------------------------ TYPE HeaderInformation DatabaseName AS STRING * 30 DatabaseVersion AS LONG Created AS STRING * 10 ' STRING representing a date Modified AS STRING * 10 ' STRING representing a date FieldCount AS INTEGER RecordCount AS LONG HeaderLength AS INTEGER ' Length of this header structure RecordLength AS LONG ' Length of the Values taken by a record RecordOffset AS LONG ' Position of the start of the 1st Record END TYPE

Next we'll need a structure to hold each field definition. We'll need to know the field name, it's type, the length it will occupy and it's value. Because of the variety of data types that can be in value, we'll use a String to hold the value. The structure will look like this:

' ------------------------------------------------- ' This Structure holds Field Specific Information ' ------------------------------------------------- TYPE FieldInformation FieldNumber AS LONG FieldName AS STRING * 32 FieldType AS STRING * 1 ' T=Text, I=Integer, L=Long, D=Double FieldLength AS INTEGER END TYPE

Of course, when you have written data to the database file, you can use a user defined type, like in this example, to load and save the information. You could use a series of variables of the desired types as well depending on the needs. Here we are making a database example, so, a user defined type becomes most appropriate for this type of binary file usage.

' ------------------------------------------------------------------------ ' This Structure holds Employee Information read from the database file ' ----------------------------------------------------------------------- TYPE EmployeeInformation EmployeeNumber AS LONG EmployeeName AS STRING * 40 Address1 AS STRING * 50 Address2 AS STRING * 30 City AS STRING * 20 State AS STRING * 30 ZipCode AS LONG Telephone AS STRING * 14 Fax AS STRING * 14 HourlyRate AS DOUBLE END TYPE

We will now need variables to hold everything in order to create the database file itself. We will need a variable for the File Handle, one for the Header and an array to hold the field definitions. In this example we will use a fixed array but we could use a dynamic array if we'd need the number of fields to change.

' ---------------------------------------------- ' Needed Variable Declarations for this module ' ---------------------------------------------- DIM DBHeader AS HeaderInformation DIM DBFields(1 TO 10) AS FieldInformation ' 10 fields for this example DIM CurrentEmployee AS EmployeeInformation DIM DatabaseHandle AS INTEGER DIM Counter AS INTEGER DIM WorkLength AS INTEGER DIM TotalRecordLength AS INTEGER

Now that we have all this defined, we will go about defining the structure and saving that definition as the beginning of the binary file. To do so, we'll need to make sure that all the fields we plan on defining are indeed defined and that the fields in the header section are filled prior to writing it to the binary file.

First we'll create a subroutine that will serve to assign values to our field definition array. This step will save us many lines of repetitive coding when we go about actually adding the field information for the database.

SUB AddField(TheNumber AS LONG, TheName AS STRING, TheType AS STRING, Length AS INTEGER) DBFields(Number).FieldNumber = Number DBFields(Number).FieldName = Name DBFields(Number).FieldType = TheType DBFields(Number).FieldLength = Length END SUB

Next comes the actual Assignment of the different Fields that define the structure of our database. In this example we know the number of fields already. However, we could be dealing with a structure created by another user perhaps and we'd need to determine everything by reading the header, then the field definition and finally going about reading records in the database area. For now, let's just create the fields we'll be using here.

' ------------------------------------------ ' Add the definitions to the DBField Array ' ------------------------------------------ CALL AddField( 1, "EmployeeNumber", "I", 2 ) ' Would be 4 in FreeBasic CALL AddField( 2, "EmployeeName", "T", 40 ) CALL AddField( 3, "Address1", "T", 50 ) CALL AddField( 4, "Address2", "T", 30 ) CALL AddField( 5, "City", "T", 20 ) CALL AddField( 6, "State", "T", 30 ) CALL AddField( 7, "ZipCode", "I", 2 ) ' Would be 4 in FreeBasic CALL AddField( 8, "Telephone", "T", 14 ) CALL AddField( 9, "Fax", "I", 14 ) CALL AddField(10, "HourlyRate", "D", 8 )

Now that our field definition is complete we have everything we need to fill up our database Header with the needed information.

' ------------------------------------------------- ' Evaluate a few values before assigning DBHeader ' ------------------------------------------------- WorkLength = LEN(DBHeader) FOR Counter = 1 TO UBOUND(DBFields) TotalRecordLength = TotalRecordLength + DBFields(Counter).FieldLength NEXT Counter ' -------------------------------------------------------------- ' Populate the DBHeader structure with appropriate information ' -------------------------------------------------------------- DBHeader.DatabaseName = "Employee" DBHeader.DatabaseVersion = 1 DBHeader.Created = DATE$ DBHeader.Modified = DATE$ DBHeader.FieldCount = 9 DBHeader.RecordCount = 0 DBHeader.HeaderLength = WorkLength DBHeader.RecordLength = TotalLength DBHeader.RecordOffset = WorkLength + TotalLength + 1

At this point, all the structures are filled with the information we need and are ready to be saved to the database file. this is done quite simply in this example. If you prepare yourself properly in your own binary file projects, it could very well be this easy to write any file format you could invent. Here's the code to do the actual writing of the file format and field definition.

' ---------------------------------------------------------------- ' Write The contents of the file definition to the database file ' ---------------------------------------------------------------- DatabaseHandle = FREEFILE OPEN RTRIM$(DBHeader.DatabaseName) + ".df" FOR BINARY AS #DatabaseHandle PUT #DatabaseHandle, , DBHeader FOR Counter = 1 TO UBOUND(DBFields) PUT #DatabaseHandle, , DBFields(Counter) NEXT Counter

It doesn't get much shorter than this does it? When your data structures are prepared, it really is that simple. Next we'll add a few records In there for the sake of having data to work with. Once again, I'll use a user defined type to create a structure to represent the data I'll be reading. In this example I know the structure so I can do that, but in a more complete database application, you'd have to code yourself a dynamic mean to read and accomodate any data type (Perhaps an array of strings in which you convert the data read into the data type it should be treated as). We'll create 2 records in this example.

' ---------------------------------------------------------------------- ' Assign values to the First Employee to be Saved to the database file ' ---------------------------------------------------------------------- CurrentEmployee.EmployeeNumber = 1 CurrentEmployee.EmployeeName = "Stephane Richard" CurrentEmployee.Address1 = "I don't know" CurrentEmployee.Address2 = "And I never will" CurrentEmployee.City = "Somewhere" CurrentEmployee.State = "Out There" CurrentEmployee.ZipCode = 12345 CurrentEmployee.Telephone = "(000) 000-0000" CurrentEmployee.Fax = "(000) 000-0000" CurrentEmployee.HourlyRate = 37.5 ' --------------------------------------------- ' Write this information to the database file ' --------------------------------------------- PUT #DatabaseHandle, DBHeader.RecordOffset, CurrentEmployee ' ---------------------------------------------------------------------- ' Assign values to the First Employee to be Saved to the database file ' ---------------------------------------------------------------------- CurrentEmployee.EmployeeNumber = 2 CurrentEmployee.EmployeeName = "Kristian Virtaken" CurrentEmployee.Address1 = "Ain't got a clue" CurrentEmployee.Address2 = "blueberry hill" CurrentEmployee.City = "South of North" CurrentEmployee.State = "down here" CurrentEmployee.ZipCode = 12121 CurrentEmployee.Telephone = "(111) 111-1111" CurrentEmployee.Fax = "(111) 111-1111" CurrentEmployee.HourlyRate = 38.5 ' more than fair on salaries. ' --------------------------------------------- ' Write this information to the database file ' --------------------------------------------- PUT #DatabaseHandle, , CurrentEmployee ' -------------------------------------------------------------------- ' Let's not forget to update the Record Count in the database header ' -------------------------------------------------------------------- DBHeader.RecordCount = 2 PUT #DatabaseHandle, 1, DBHeader ' Save the whole header structure

At this point The database file should have everything it needs to manage itself saved in it's contents. What do we want to do next? How about reading the information back to make sure it got saved ok? To do that in this example, we'll position ourselves on the RecordOffset value from the DBHeader structure and loop RecordCount number of times reading the record and displaying it. We'll use CurrrentEmployee to read each record and display them. Again everything is prepared with the user defined types we created, when you can do that prior to handling the file, you can definitaly shorten code and coding time as well. Here is the code to do the positioning and reading of the records.

' -------------------------------------------------------------- ' Position our file pointer and loop 2 times to read and print ' -------------------------------------------------------------- SEEK #DatabaseHandle, DBHeader.RecordOffset FOR Counter = 1 to DBHeader.RecordCount GET #DatabaseHandle, , CurrentEmployee PRINT "EMPLOYEE NUMBER: " + LTRIM$(STR$(CurrentEmployee.EmployeeNumber)) PRINT "EMPLOYEE NAME..: " + CurrentEmployee.EmployeeName PRINT "HOURLY RATE....: "; PRINT USING "##.##"; CurrentEmployee.HourlyRate NEXT Counter ' ------------------------------ ' And we close the file handle ' ------------------------------ CLOSE #DatabaseHandle

Faily simple isn't it? Although I'm not the worst at writing tutorials, I can't claim to be 100% clear at everything I explain. you can email me any comments/questions/request for new tutorials even and I'll see what I can do. Hope you enjoyed this long but I hope good tutorial. I've certainly enjoyed writing it.

Stéphane Richard
srichard@adaworld.com


Download this tutorial for easier viewing.


OpenGL Tutorials for FreeBasic
Parts 1 - 4

Written by RelSoft

Part One

Introduction

Hi peeps. Due to insistent public demand, I'm back again with a string of OpenGL tutorials for use with the coolest BASIC compiler around. That is, FreeBASIC . As I was the one who ported the GL and GLU headers from the C implementation, I felt that it's my duty to write tutorials on how to use OpenGL in FB. You might not know this but OpenGL does not have a windowing system of it's own so any OpenGL program would need a windowing function to run on Windows, Linux etc. The reason why SGI( OpenGL implementors ) did not add windowing functions to it's implementations is that they want OpenGL to be Cross-Platform. Meaning it would run on any machine that supports OpenGL. With that in mind, I myself would not delve deep into the windows API for windowing but use SDL for all Windowing, Audio, and input functions. All the Graphics will be done by OpenGL itself. Note: Since FB 0.12 OpenGL is implemented in the GFX module but I hate rewriting code and have written this tute in FB 0.11. Converting all the windowing funks would prolly take you 10 mins max so I'd stick with SDL for a while. A word of warning, I'm not an OpenGL expert myself nor I'm an expert in SDL. What I know may be very minimal but I got some request from the community to make a series of tutes on OpenGL. It's also notable that I would not discuss matrix operations, vector operations and most of 3d math here because I've already written 5 chapters that explains it all for you in a very BASIC way. So you might want to read those tutorials before delving into OpenGL beacuse it would make OpenGL easy for you. You can download the 1st 4 chapters of those tutes in my site (Rel.betterwebber.com) and the fifth chapter in a previous issue of this mag. You might wan't to read chapter 3(Vectors, except the triangle rasterizers) and 4(Matrices) because they explain very well what openGL does with your points. So wihout further ado...

Setting Up

As I've said we will use SDL(Simple Direct Media Layer developed by Sam Lantiga) for windowing and input as SDL is pretty much the standard for windowing in OpenGL, add to that the fact that SDL, like OpenGL, is cross-platform makes our code portable. First thing we need is to download SDL.DLL at the SDL site and put that DLL in your \windows\system folder for win9x or \windows\system32 for WinXP. Chances are you don't need to download openGL.DLL since your video card should provide its own. Lets start with the declarations:

The following constants would define what type of window we will have. With the following consts we would have a 640 * 480 screen in 32 bit color.

const SCR_WIDTH = 640 'Width of the screen const SCR_HEIGHT = 480 'height of the screen const BITSPP = 32 '32 bits per pixel format

The next section would include the necessary headers(BI files) that enables us to call SDL(sdl.bi), OpenGL(gl.bi) and GLU(glu.bi). GLU stands for the OpenGL Utility Library which is a standard lib that works on top of OpenGL. We would need to provide an *Option Explicit* statement so that errors are minimized and the interface between SDL/OpenGL/GLU and FB would be as seamlessly a possible.

option explicit 'Force declaration '$include: "\sdl\sdl.bi" 'sdl function and constants declaration '$include: "\gl\gl.bi" 'OpenGL funks and consts '$include: "\gl\glu.bi" 'GL standard utility lib

WE also have to declare the functions and subs that we made before using them in our code because that's what FB require. We have 3 funks so...

'Declarations DECLARE SUB Init_GL_SDL(SDLscreen as SDL_Surface ptr) Declare Sub SDL_GetEvents(EscapeVal as Integer) Declare Sub draw_scene()

I would explain to you what each sub does and why we need them. First we should make function that intitializes SDL and OpenGL. We will call it Init_GL_SDL. It needs an SDL surface pointer as an argument.

SUB Init_GL_SDL(SDLscreen as SDL_Surface ptr) dim Result as unsigned integer 'checker value for SDL initialization dim SDL_flags as integer 'Flags for SDL screen 'OpenGL params for gluPerspective dim FOVy as double 'Feild of view angle in Y dim Aspect as double 'Aspect of screen dim znear as double 'z-near clip distance dim zfar as double 'z-far clip distance 'Let's set up our sdl flags variable SDL_flags = SDL_HWSURFACE 'use Hardware surface SDL_flags = SDL_flags or SDL_DOUBLEBUF 'doublebuffer to prevent flicker SDL_flags = SDL_flags or SDL_OPENGL 'activate OpenGL 'SDL_flags = SDL_flags or SDL_FULLSCREEN 'FullScreen(REM for windowed) 'Init everything for SDL(video,audio, key, joy, etc) result = SDL_Init(SDL_INIT_EVERYTHING) if result <> 0 then 'error? end 1 'then quit end if 'Set 640*480*32 'SCR_WIDTH/HEIGHT/BITSPP are CONSTANTS declared at the main module SDLscreen = SDL_SetVideoMode(SCR_WIDTH, SCR_HEIGHT, BITSPP, SDL_flags) if SDLscreen = 0 then SDL_Quit end 1 end if SDL_WM_SetCaption "Sdl Template", "" 'Make caption if windowed 'Set OpenGL ViewPort to screen dimensions glViewport 0, 0, SCR_WIDTH, SCR_HEIGHT 'Set current Mode to projection(ie: 3d) glMatrixMode GL_PROJECTION 'Load identity matrix to projection matrix glLoadIdentity 'Set gluPerspective params FOVy = 80/2 '45 deg fovy Aspect = SCR_WIDTH / SCR_HEIGHT 'aspect = x/y znear = 1 'Near clip zfar = 200 'far clip 'use glu Perspective to set our 3d frustum dimension up gluPerspective FOVy, aspect, znear, zfar 'Modelview mode 'ie. Matrix that does things to anything we draw 'as in lines, points, tris, etc. glMatrixMode GL_MODELVIEW 'load identity(clean) matrix to modelview glLoadIdentity glShadeModel GL_SMOOTH 'set shading to smooth(try GL_FLAT) glClearColor 0.0, 0.0, 0.0, 0.0 'set Clear color to BLACK glClearDepth 1.0 'Set Depth buffer to 1(z-Buffer) glEnable GL_DEPTH_TEST 'Enable Depth Testing so that our z-buffer works 'compare each incoming pixel z value with the z value present in the depth buffer 'LEQUAL means than pixel is drawn if the incoming z value is less than 'or equal to the stored z value glDepthFunc GL_LEQUAL 'have one or more material parameters track the current color 'Material is your 3d model glEnable GL_COLOR_MATERIAL 'Tell openGL that we want the best possible perspective transform glHint GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST END SUB

Let me explain to you what each code fragment does. Basically we dim all variables that we want to use because of Option Explicit.

dim Result as unsigned integer 'checker value for SDL initialization dim SDL_flags as integer 'Flags for SDL screen 'OpenGL params for gluPerspective dim FOVy as double 'Feild of view angle in Y dim Aspect as double 'Aspect of screen dim znear as double 'z-near clip distance dim zfar as double 'z-far clip distance SDL_flags = SDL_HWSURFACE 'use Hardware surface SDL_flags = SDL_flags or SDL_DOUBLEBUF 'doublebuffer to prevent flicker SDL_flags = SDL_flags or SDL_OPENGL 'activate OpenGL 'SDL_flags = SDL_flags or SDL_FULLSCREEN 'FullScreen(REM for windowed) 'Init everything for SDL(video,audio, key, joy, etc) result = SDL_Init(SDL_INIT_EVERYTHING) if result <> 0 then 'error? end 1 'then quit end if

Result is a value that will be returned by SDL_INIT if it's 0 then SDL_Init is successful and 1 or -1 otherwise. SDL_flags is a value that sets up our SDL Screen. The follwing declarations would be needed by GLUPERSPECTIVE to set up out Projection matrix. You can forget about those values for now as I'll be explaining it to you as we go on.

Then initialize SDL_flags by OR-ing the parameters and loading them into SDL_flags. SDL_HWSURFACE makes use of HARDWARE surfaces. Try SDL_SWSURFACE for sofware. SDL_DOUBLEBUF means double buffer. Basically reduces flicker like in QB. SDL_OPENGL is a flag that would let us use OpenGL drawing primitives on our SDL surface. SDL_FULLSCREEN is REMmed for development purposes as it's easier to close an application in windowed mode as opposed to full screen. We should UNREM it later when we are sure that our OpenGL program is bug free since Full screen is faster that windowed mode. If all goes well, Result would be 0 and we could continue.

Passing SDL_INIT_EVERYTHING into SDL_init would initialize our OpenGL screen, audio capabilities, keyboard funks, joystick, etc. Basically every stuff SDL supports are initialized. If you want just video, you should pass SDL_VIDEO.

Okay, next sub...

Sub SDL_GetEvents(EscapeVal as Integer) 'SDL event is type in the SDL inc directory dim event as SDL_Event 'poll events while( SDL_PollEvent ( @event ) ) select case event.type case SDL_KEYDOWN: 'if a key is pressed quit proggie EscapeVal = -1 case SDL_MOUSEBUTTONDOWN: end select wend End Sub

The above sub is just a way to get events from SDL so that we could handle the mouse, keyboard, etc. For now it would return -1 when we press any key.

Last sub....

Sub draw_scene() 'clear the screen 'GL_COLOR_BUFFER_BIT = to black(remember glClearColor?) 'GL_DEPTH_BUFFER_BIT set depth buffer to 1 (remember glClearDepth?) glClear GL_COLOR_BUFFER_BIT OR GL_DEPTH_BUFFER_BIT 'Draw our geometry 'Nothing yet. Just a black screen 'Force completion of drawing glFlush end sub

In this sub we would draw everything we want. For now, we only clear the screen and the depth-buffer(z-buffer). glflush just forces completion of drawing before we flip the page.

The main code....

dim vpage as SDL_Surface ptr 'The screen we want to draw to dim Finished as integer 'Quit or not? Init_GL_SDL vpage 'init GL SDL stuff Finished = 0 'set finished to false do SDL_GetEvents(Finished) 'handle events draw_scene 'Draw something SDL_GL_SwapBuffers 'Flip to screen SDL_PumpEvents 'force an event queue update(input, etc) loop until Finished SDL_Quit 'quit SDL end

Now that the subs are all done for, we can make our module level code. Vpage is a Pointer to screen surface or the screen that would would be displayed. Note: We can't use the word "screen" because it's a reserved FB keyword since FB 0.11. Finished is a variable that we will use to check if we wan't to close the application. Before doing any SDL/GL stuff we should call our init sub:

Finished is set to zero(0) so that we could loop around.

Init_GL_SDL vpage 'init GL SDL stuff Finished = 0 'set finished to false

The main loop:

do SDL_GetEvents(Finished) 'handle events draw_scene 'Draw something SDL_GL_SwapBuffers 'Flip to screen SDL_PumpEvents 'force an event queue update(input, etc) loop until Finished

The do::Loop construct allows our application to run indefinitely until we press a key. Before drawing, we call SDL_GetEvents and pass "Finished" as an argument. When a key is pressed, finished would return -1 and we exit the loop. Then we call draw_scene for screen drawing(nothing for now). SDL_GL_SwapBuffers is like flipping pages and showing the completed drawing to screen. SDL_PumpEvents forces events completion on the SDL side of things. After we exit the loop, we call SDL_Quit so that our SDL screen would close and END so that FB would end.

Well that's it for now. Not much, just giving you a "feel" of OpenGL in SDL. Next time we will draw an OpenGL primitive so that we could see the power of OpenGL. Here's the source to what we discussed on this article. Until next time.

gl_tute_template.bas | gl_tute_template.exe

Part Two

Introduction

This time, we would draw a smooth shaded triangle on our OpenGL application. I would introduce you to some new GL commands and how to modify those commands and play with it. I believe the best way to learn OpenGL is to play with it. You may experience some crashes but it would make you understand GL better.

OpenGL overview

OpenGL is a sofware interface to GFX hardware. What it means is that GL is an API that lets you call your hardware graphics functions via OpenGL commands. It's a device independent interface, meaning OpenGL would work on any GFX card that supports it. Open GL is also a "STATE MACHINE". You can picture out OpenGL as a console with switches on it. And once a switch is turned ON, the effect of that switch stays until you turn it off. Like a light switch, the light stays off until you turn it on and it would go on until you switch it off. More on this later...

OpenGL syntax

Before we try to draw something, let me introduce you to a little OpenGL program. Warning, do not compile this. I took this from the GL redbook. I've numbered it to make it more readable.

'Init window here 1 glClearColor 0.0, 0.0, 0.0, 0.0 2 glClear GL_COLOR_BUFFER_BIT 3 glColor3f 1.0, 1.0, 1.0 4 glOrtho -1.0, 1.0, -1.0, 1.0, -1.0, 1.0 5 glBegin GL_POLYGON 6 glVertex2f -0.5, -0.5 7 glVertex2f -0.5, 0.5 8 glVertex2f 0.5, 0.5 9 glVertex2f 0.5, -0.5 10 glEnd 11 glFlush

Here's a little table that summarizes the OpenGL suffixes. ie. "2f" in glVertex2f.

Suffix Data Type Typical FreeBASIC DataType OpenGL Type Definition b 8-bit integer byte GLbyte s 16-bit integer short GLshort i 32-bit integer integer/long GLint, GLsizei f 32-bit floating-point single GLfloat, GLclampf d 64-bit floating-point double GLdouble, GLclampd ub 8-bit unsigned integer unsigned byte GLubyte, GLboolean us 16-bit unsigned integer unsigned short GLushort ui 32-bit unsigned integer unsigned intger/long GLuint, GLenum, GLbitfield

Examples are:

I would rather use the "OpenGL Type Definition" when coding in FB since I've converted the C #defines to FB #defines. So when declaring and angle:

You could:

Dim angle as GLfloat

Instead of:

dim angle as single

Now that you know the basic OpenGL syntax, let's draw something to that boring screen! There wouldn't be much addition to our last articles code. In fact I've already explained almost all the stuff I added to our template to make it draw something. ;*)

Our Init funk:

SUB Init_GL_SDL(SDLscreen as SDL_Surface ptr) dim Result as unsigned integer 'checker value for SDL initialization dim SDL_flags as integer 'Flags for SDL screen 'OpenGL params for gluPerspective dim FOVy as double 'Feild of view angle in Y dim Aspect as double 'Aspect of screen dim znear as double 'z-near clip distance dim zfar as double 'z-far clip distance 'Let's set up our sdl flags variable SDL_flags = SDL_HWSURFACE 'use Hardware surface SDL_flags = SDL_flags or SDL_DOUBLEBUF 'doublebuffer to prevent flicker SDL_flags = SDL_flags or SDL_OPENGL 'activate OpenGL 'SDL_flags = SDL_flags or SDL_FULLSCREEN 'FullScreen(REM for windowed) 'Init everything for SDL(video,audio, key, joy, etc) result = SDL_Init(SDL_INIT_EVERYTHING) if result <> 0 then 'error? end 1 'then quit end if 'Set 640*480*32 'SCR_WIDTH/HEIGHT/BITSPP are CONSTANTS declared at the main module SDLscreen = SDL_SetVideoMode(SCR_WIDTH, SCR_HEIGHT, BITSPP, SDL_flags) if SDLscreen = 0 then SDL_Quit end 1 end if SDL_WM_SetCaption "Sdl Triangles", "" 'Make caption if windowed 'Set OpenGL ViewPort to screen dimensions glViewport 0, 0, SCR_WIDTH, SCR_HEIGHT 'Set current Mode to projection(ie: 3d) glMatrixMode GL_PROJECTION 'Load identity matrix to projection matrix glLoadIdentity 'Set gluPerspective params FOVy = 80/2 '45 deg fovy Aspect = SCR_WIDTH / SCR_HEIGHT 'aspect = x/y znear = 1 'Near clip zfar = 200 'far clip 'use glu Perspective to set our 3d frustum dimension up gluPerspective FOVy, aspect, znear, zfar 'Modelview mode 'ie. Matrix that does things to anything we draw 'as in lines, points, tris, etc. glMatrixMode GL_MODELVIEW 'load identity(clean) matrix to modelview glLoadIdentity glShadeModel GL_SMOOTH 'set shading to smooth(try GL_FLAT) glClearColor 0.0, 0.0, 0.0, 0.0 'set Clear color to BLACK glClearDepth 1.0 'Set Depth buffer to 1(z-Buffer) glEnable GL_DEPTH_TEST 'Enable Depth Testing so that our z-buffer works 'compare each incoming pixel z value with the z value present in the depth buffer 'LEQUAL means than pixel is drawn if the incoming z value is less than 'or equal to the stored z value glDepthFunc GL_LEQUAL 'have one or more material parameters track the current color 'Material is your 3d model glEnable GL_COLOR_MATERIAL 'Tell openGL that we want the best possible perspective transform glHint GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST END SUB

I added some code to our init sub the first ones are these:

1 glViewport 0, 0, SCR_WIDTH, SCR_HEIGHT 2 glMatrixMode GL_PROJECTION 3 glLoadIdentity 4 FOVy = 80/2 '45 deg fovy 5 Aspect = SCR_WIDTH / SCR_HEIGHT 'aspect = x/y 6 znear = 1 'Near clip 7 zfar = 200 'far clip 8 gluPerspective FOVy, aspect, znear, zfar

The above gluPerspective parameters are somewhat the standard so you will almost always use the above values.

The next code fragment does something to our modelview matrix.

9 glMatrixMode GL_MODELVIEW 10 glLoadIdentity 11 glShadeModel GL_SMOOTH 'set shading to smooth(try GL_FLAT) 12 glClearColor 0.0, 0.0, 0.0, 0.0 'set Clear color to BLACK 13 glClearDepth 1.0 'Set Depth buffer to 1(z-Buffer) 14 glEnable GL_DEPTH_TEST 'Enable Depth Testing 15 glDepthFunc GL_LEQUAL 16 glEnable GL_COLOR_MATERIAL 17 glHint GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST

Another sub we changed is the draw_scene sub. Here's the whole sub:

Sub draw_scene() 1 glClear GL_COLOR_BUFFER_BIT OR GL_DEPTH_BUFFER_BIT 2 glPushMatrix 3 glLoadIdentity 4 glTranslatef 0.0, 0.0, -10.0 5 glBegin GL_TRIANGLES 6 glColor3f 1.0, 0.0, 0.0 '1st color 7 glVertex3f 0.0, -1.0, 0.0 '1st vertex 8 glColor3f 0.0, 1.0, 0.0 '2nd color 9 glVertex3f -1.0, 0.0, 0.0 '2nd vertex 10 glColor3f 0.0, 0.0, 1.0 11 glVertex3f 1.0, 0.0, 0.0 12 glEnd 13 glPopMatrix 14 glFlush End sub

Those are the only things that we changed in our last tute. Try to change some values in glColor3f, glVertex3f and glTranslate to see how they change the triangle's view. The source could be downloaded here (gl_tute_triangles.bas or gl_tute_triangles.exe). Try to play with it and see some changes. BTW, the new added lines are labeled with "NEW!!!"

Okay, now that you know how to draw a triangle, why not try to draw some GL_QUADS and pass 4 vertices or GL_LINES and pass 2 verts. So long and until next time.

Part Three

Introduction

Rel back again for another short FreeBASIC OpenGL tutorial. This time we would try to do some standard 3d transforms like rotation and scaling. Here are some of the new glCommands.

1. glScalef

Produces a general scaling along the x, y, and z axes. The three arguments indicate the desired scale factors along each of the three axes. The resulting matrix is like the scaling matrix in my matrix article in my QB 3d series.

The current matrix mode (likely to be MODELVIEW) is multiplied by the scale matrix with the product replacing the current matrix. ie. M = M * S

Example:
     glScalef 2.0, 1.5, 1

Would scale the current matrix 2x in the x-axis, 1.5x in the y-axis and does not scale in the z-axis.

2. glRotatef

Specifies the angle of rotation, in degrees. Computes a matrix that performs a counterclockwise rotation of angle (in degrees) about the vector from the origin through the point (x, y, z).

Example:
     glRotatef 270, 1, 0, 0

Rotates the current matrix 270 degrees on the x-axis.

     glRotatef 30, 0.1, 0.4, 0.6

Rotates the current matrix 30 degrees about the vector (0.1, 0.4, 0.6)

Now for the code...
Sub draw_scene() static theta as integer 'NEW!!!Rotation degrees dim xtrans as single 'NEW!!!xtanslation dim ytrans as single 'NEW!!!ytanslation dim ztrans as single 'NEW!!!ztanslation dim scalefactor as single 'NEW!!!Scaling factor 'clear the screen 'GL_COLOR_BUFFER_BIT = to black(remember glClearColor?) 'GL_DEPTH_BUFFER_BIT set depth buffer to 1 (remember glClearDepth?) glClear GL_COLOR_BUFFER_BIT OR GL_DEPTH_BUFFER_BIT 'Push matrix to the matrix stack so that we start fresh glPushMatrix 'Reset the matrix to identity glLoadIdentity ''NEW!!! Our translation factor 'Try to change these arguments xtrans = -0.9 ytrans = -1.5 ztrans = -10 glTranslatef xtrans, ytrans, ztrans ''NEW!!! Our scale factor Scalefactor = 2.5 'NEW!!! 'glScalef scalefactor, scalefactor, scalefactor 'Scales our modelview matrix 3x in the x, y, z axes 'try to change its arguments to different values glScalef scalefactor, scalefactor, scalefactor 'NEW!!! 'glRotatef angle, x, y, z rotates your model 'angle = Specifies the angle of rotation, in degrees 'x, y, z = Specify the x, y, and z coordinates of a vector 'So to rotate your 3d object theta degrees in the x axis you would write: 'we will meke use of some other values for x,y ans z coords in later tutes glRotatef theta, 1, 0, 0 'angle, x axis = 1, all other axis are zero glRotatef theta, 0, 1, 0 'rotate in the y axis glRotatef theta, 0, 0, 1 'rotate in the z axis 'Draw our geometry glBegin GL_TRIANGLES '1st vert glColor3f 1.0, 0.0, 0.0 glVertex3f 0.0, -1.0, 0.0 '2nd vert glColor3f 0.0, 1.0, 0.0 glVertex3f -1.0, 0.0, 0.0 '3rd vert 'NEW!!! changed the y coord to so that tri is centered in rotation glColor3f 0.0, 0.0, 1.0 glVertex3f 1.0, 1.0, 0.0 glEnd glPopMatrix Theta = theta + 1 'Force completion of drawing glFlush end sub

Here are the explanations code by code...

Define some variables at the top of our draw_scene sub

1 static theta as integer 2 dim xtrans as single 3 dim ytrans as single 4 dim ztrans as single 5 dim scalefactor as single
6 xtrans = -0.9 7 ytrans = -1.5 8 ztrans = -10 9 glTranslatef xtrans, ytrans, ztrans 10 Scalefactor = 2.5 11 glScalef scalefactor, scalefactor, scalefactor
12 glRotatef theta, 1, 0, 0 'angle, x axis = 1, all other axis are zero 13 glRotatef theta, 0, 1, 0 'rotate in the y axis 14 glRotatef theta, 0, 0, 1 'rotate in the z axis

Then we still draw our old triangle after that. The increment our angle by calling this:

Theta = theta + 1

Theta should retain it's value in between calls because we declared it as static.

That's all for now. Try to play with the parameters in glScalef and glRotatef to familiarize yourself of their effects to your triangle. Here's the source: gl_tute_rotation.bas and gl_tute_rotation.exe

Ciao!!!

Part Four

Introduction

Last time we explored scaling and rotation on our triangle. But a single triangle looks boring after a while. Today we would try to rotate a cube instead of a triangle. I could have used a more algorithmic way to define a cube but I used the model used my Nehe as I believe it's much easier to understand for someone new to OpenGL. After we finish the first program which load the cube using multiple glVertex calls we would progress to using Data Arrays to manage our models easier.

Let's begin by the newest sub called the Draw_cube sub. This sub basically just draws a cube in the center of the current GL cursor. I took this from Nehe's tutorial. I numbered some of it for purposes of explaning.

Sub Draw_Cube() 1 glBegin GL_QUADS ' Front Face 2 glColor3f 1.0, 0.0, 0.0 'Color of first quad = RED 3 glVertex3f -1.0, -1.0, 1.0 'the following 4 vertices would make 4 glVertex3f 1.0, -1.0, 1.0 'a quad(4 sided polygon) 5 glVertex3f 1.0, 1.0, 1.0 ' 6 glVertex3f -1.0, 1.0, 1.0 ' 'Back Face glColor3f 0.7, 0.0, 0.5 glVertex3f -1.0, -1.0, -1.0 glVertex3f -1.0, 1.0, -1.0 glVertex3f 1.0, 1.0, -1.0 glVertex3f 1.0, -1.0, -1.0 'Top Face glColor3f 0.0, 1.0, 0.7 glVertex3f -1.0, 1.0, -1.0 glVertex3f -1.0, 1.0, 1.0 glVertex3f 1.0, 1.0, 1.0 glVertex3f 1.0, 1.0, -1.0 'Bottom Face glColor3f 0.0, 0.0, 1.0 glVertex3f -1.0, -1.0, -1.0 glVertex3f 1.0, -1.0, -1.0 glVertex3f 1.0, -1.0, 1.0 glVertex3f -1.0, -1.0, 1.0 'Right face glColor3f 0.0, 1.0, 0.0 glVertex3f 1.0, -1.0, -1.0 glVertex3f 1.0, 1.0, -1.0 glVertex3f 1.0, 1.0, 1.0 glVertex3f 1.0, -1.0, 1.0 'Left Face glColor3f 0.9, 1.0, 1.0 glVertex3f -1.0, -1.0, -1.0 glVertex3f -1.0, -1.0, 1.0 glVertex3f -1.0, 1.0, 1.0 glVertex3f -1.0, 1.0, -1.0 7 glEnd End Sub

Note: You can draw multiple GL_QUADS in between a single glBegin-glEnd bracket as long as the vertices are arranged in 4's. ie: The first 4 vertices would draw the first quad, the next 4 would draw quad number 2 and so on. I'm setting a different color for each face so that you'll see each face.

Then in the draw_scene sub, we call draw_cube instead of the triangle. Wahla! a rotating cube.

Here's the source: gl_tute_cube.bas and gl_tute_cube.exe

Making it better

With the above draw_cube sub's multiple glVertex calls one might say: "Do I have to write glVertex3f for each vertex I want?". Fortunately, the answer is NO. We could store our vertices and color values in an array and use a FOR_NEXT loop to draw the cube. But where do we store the data before loading to the array? You could store it in a file or you could store it in DATA statements like this:

I only put here the values for the first face to save article space.

' x y z DATA -1.0, -1.0, 1.0 DATA 1.0, -1.0, 1.0 DATA 1.0, 1.0, 1.0 DATA -1.0, 1.0, 1.0

Then we would change our draw_cube sub drastically like so:

Sub Draw_Cube() 1 dim i as integer, j as integer 2 static color_init 3 if color_init = 0 then 'is it initialized already? 4 static colors(23, 2) as GLfloat 5 static cube(23, 2) as GLfloat 'put values to each elements by looping 6 for i = 0 to 23 7 for j = 0 to 2 8 colors(i, j) = rnd 'Color range are from 0 to 1 9 read cube(i,j) 'read cubes coords from data statements 10 next i 11 next j 12 color_init = -1 13 end if 14 glBegin GL_QUADS 'Draw the cube 15 for i = 0 to 23 'Draw the cube with smooth colors 16 glColor3f colors(i,0), colors(i,1), colors(i,2) 17 glVertex3f cube(i,0), cube(i,1), cube(i,2) 18 next i 19 glEnd End Sub

Here's the source and exe: gl_tute_cube_smooth.bas and gl_tute_cube_smooth.exe

Special thanks to Nehe for the Cube model.

Well, I hope this and the previous articles helped you get yourself acquainted to OpenGL, Try to play with it and you'll be surprised how easy it is compared to using QB to make 3d stuff. I would suggest you read my QB 3d articles because it would be easier to use OpenGL once you master the 3d series. Next time I'll teach you how to use the *vector* implementation of some GL commands to speed up your rendering, TextureMapping, Blending, Landcapes, bitmaps, FPS and 3rd persom Cameras, lighting, fogs, billboarding, etc and I'll probably use the FBGFX windowing system instead of SDL so that we won't need SDL.DLL for our programs. So until next time...

-RelSoft


Sites that teaches a lot of GL stuff:


Download FBGLtutes.zip for all four of these tutorials and all the source code too.
Visit Rel's website, Genso's Junkyard, or contact him.


Final Word

Well that about wraps it up for this mega-issue of QB Express. This magazine is really hitting a stride. We're gaining more and more readers (and therefore more and more contributors) by the month. And meanwhile, the quantity and quality of the content that's submitted is second to none. QB Express just gets better and better.

Most QB magazines peak after two or three issues, and then gradually decline over time, but QB Express has done just the opposite. And I have YOU to thank for that. (Plus V1ctor and FreeBasic, which has brought this Qmunity back to life.) There's just so much going on these days that we need a huge magazine every month to cover it.

BUT: as the magazine grows, it's getting tougher and tougher to put it together myself. I'm only one man, and I can't do it alone. I'm looking for talented writers to help take a bit of the workload off of my shoulders, especially for the News Briefs section, which is by far the most time consuming part of this magazine to put together. I spent nearly five hours in the past two days on just that section alone, searching websites for news stories, capturing and formatting images/screenshots, writing up the articles... It's a lot of work, and I'm looking for people who want to be News Reporters for this magazine. Contact me (pberg1@gmail.com) if you're interested.

And as always, I need more of the great tutorials and articles that are the backbone of this magazine. If you're at all interested in writing, by all means, do it! We're an OPEN magazine, and we want to hear from YOU!

QBasic: The Magazine, the largest and most popular QB magazine ever, died after 12 issues. We're at eight right now, and there are no signs of slowing down. As far as I can tell, there's nowhere for us to go but up!

Until next time...END.

-Pete


Copyright © Pete Berg and contributors, 2005. All rights reserverd.
This design is based loosely on St.ndard Bea.er by Altherac.