QB Express

Issue #17  ~  January 9, 2006

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

In This Issue

From The Editor's Desk

Written by Pete


I know, I know, this issue is three weeks late... it was originally supposed to come out before Christmas. (For a laugh, check out Rattrapmax6's Horse Humor comic this month...how untimely, heheh.)

Anyway, what happened? Two things:

(1) Major computer problems on my end. (Everything just happened to fail at once... first it was a hard drive...then while trying to recover the data, my wireless network card went... Then I started getting rampant BSODs and discovered that my motherboard was bad, so I had to get a new one. Then I tried to recover the lost data on my crashed hard drive....so I copied as much as I could to a NEW external hard drive that I bought, and that failed a few days later! And then, to make matters worse, my 19" LCD monitor that I paid $540 for two years ago failed, and I had to buy a new display. ARRRRRRRGH.) But I'm not complaining.

(2) I MOVED ACROSS THE COUNTRY! I am now living in sunny Los Angeles, California. It's quite a change from snowy upstate New York...Let's just say that last night I was swimming and then sitting in a hot tub at 11:00PM. It's so warm here -- 75 degrees Fahrenheit during the day, sunny, and not a cloud in the sky! And I didn't know that palm trees could grow that tall...

Anyway, I'll be out here until May, interning somewhere in the entertainment industry (I'm working on finding a cool internship right now, preferably making documentaries or reality TV). This should be a fun and relatively relaxed semester, compared to the hell I went through in the past six months, so I'll have plenty of time to devote to QB Express these next few months.

Enough about me, though. Go ahead -- get to the magazine!

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, check out the "Official QB Express Article Requests" thread! There have been quite a few articles requested -- and even if none of them strikes your fancy, we can help you come up with something that you would like to write about. 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. If QB Express is going to continue to be so good, YOU need to contribute!



Letter From MystikShadows

Hi Pete,

Exactly like you said, a short time since the last issue and look at what we've been able to come up with. A pretty spectacular issue considering that shorter time between issues. :-). Great work to everybody.

Mennonite, I think he defined his point of view much better this time. I'm all for FreeBasic, everybody knows that :-). However, when I see someone flamed for wanting to use the QB and family of compilers, I do wonder what they hope to acheive by doing this. As far as I'm concerned, If the ask a general question about which language they should, sure i'll tend to suggest FreeBasic Otherwise, only if the ask how to do something that can't be done in QB and Family (pds or vb-dos) will I suggest to them to go to FreeBasic. I'm thinking if they googled for it (like they should, then they'll see the existence of FreeBasic and be able to decide for themselves or might have already decided to not go with FreeBasic for which ever reason (using a DOS emulator on an handheld, build something for a very old system and so on). On the plus side, FreeBasic how has a CHM file available which is a good starting point since most other compilers available do have their help available without having to go online somewhere. At the very least, before throwing them into FreeBasic we should ask them what they want to do and on what kind of hardware they want to do it in just to see if FreeBasic can answer that call better than any QB compiler could on the given hardware/OS configuration.

From his emails in this issue (and your replies). It seems to me a bit weird that there's was a dispute to begin. Basically I have to say I think memnonite (and you) are right about one thing. Any can decide to start a project, and anyone can decide which language he/she should be using for it. I'll use a BASIC dialect whenever I can, but sometimes, depending on the minding the project needs to be set it to really achieve it's goal (game or application alike) a different language is simply better suited either for the role of the project or for the reason why I'd be writing that project. For example, many compilers are written in C or Pascal, why? because if they want to use Lex/Yacc or Flex/Bison they spit out C code and mixing that with another language is almost pointless. If you don't want to use these compiler technologies, you could, technically write a compiler in any language you want. I did know that C extremist would be defending C, etc etc for the other languages. But between QB and FB it shouldn't be a question of which one is best, it should be a question of which one we want to use (regardless of whether or not it will run on modern hardware) we can make people aware that doing a game in QB might not work on XP and that there is an alternative, FB that will work on modern hardware/OS if they are willing to learn the new syntax, but moving to FB, today, is more than simply using a different compiler, there is a learning curve (obviously) learning the new FB syntax, learning FB IDE or whatever other editor they might choose to code in, if they want to push their game further they will have to learn The new graphics librariies (Allegro, OpenGL, etc). Really depends on the project they are doing. That was my two cents...basically what the two of you were exchanging in your emails, you're both right, it's, like memnonite said, your respective points of view on the impact FB is having on the QMunity. But you said it more than once before, the QMunity is not about the language, not about QB, PDS, VB-DOS or FreeBasic, it's about the people :-).

And now back on the subject matter :-) QB Express #16 itself. Let's start this off with the awards. Adigun's new updates on his website. You know, some people aren't bad at all graphics wise, some people really seem to know how to write what they want to communicate with the impact it needs to get transmitted. Adigun seems to have both of these qualities. It's like going to his website and reading about his projects and additions is almost a boost of energy in itself just with the dedication and passion he has for what he does and you can read that clearly when you visit his website. And well it's no secret that Adigun is on the top of my list as far as graphics go. As far as Programmer of the month goes, I've always seen post by Lithium about different things he's been working. But I think he really made his mark in the anals of QB history with his Raycasting Engine. Like you said he's been more active lately but the Raycasting engine really put him on the next level of programming. Excellent job on the raycasting engine. A more than well deserved award too Lithium.

Lachie's article on "Writing A Story For A Computer Game". One of the most insighful articles I've read on the subject. He's definitaly right about one thing if nothing else, a pac man clone really doesn't need a story. Many arcade like games don't need a story. Some could do with enough text to put the user into perspective for what he or she is about to see (some year in the future for example to tell the player that he's about to see things that don't exist today, nothing more really). But if you're going to write a game that does need a story, then you do need to spend time to write a good story. Best example of that, Quest for Opa Opa which needs no introduction today. Of course, Lachie's "Searching for the Unknown" is keeping up strongly with this month's submission. I always wonder what game he'll find next to put in this series and well he really picks them good and seems to have a knack for talking about them, describing them and letting us know all about them. Great work Lachie, and I can't wait to see what I'll be reading in your column next.

Rick Clark's article on Managing Complexity and on FreeBasic's UNION structure were very insightful. I think that anyone who has worked on any bigger project, or would like to, should read his article on managing complexity. This article becomes even more vital the bigger the project is because that is, after all, what programming is all about, managing complexity and if Managing Complexity is applied early in the development cycle and maintained throughout it can all help with not feeling overwhelmed by a given programming task. I also really liked the way he uses UNIONs in his DDD game too. Not many people, like he mentionned used unions but as they can see from his example it can prove to be one of the best means of organizing and managing your data. Now if FreeBasic had PCOPY in text mode (SCREEN 0) like QB, PDS and VB-DOS have, it would be grand considering FB is supposed to be an evolution from these languages to the next level :-) (sorry guys, I'm an ASCII developer, so I have to try to push this feature whenever I get the chance ;-) long live ASCII hehe.).

Agamemnus' "Programming Language Syntax Tenets" Showed me things about programing I've definitaly experienced first hand (now that I think of it) but never actually sat down and pondered upon, until now. Very informative article that really helps understand why different programming languages are the way they way the are. There is definately a ratio between flexibility and universiality. Like wise there is also a ratio between flexibility and simplicity that help categorize a programming language. For example, I've always wondered why languages such as Pascal, C and Ada did not support string variable and/or string literals in their version of the SELECT CASE statement. The main reason is for speed of execution of course, but when you think of how simple and easy to understand a select case using String literals can look when others are viewing your code, I say all languages should implement it (even if they would have to add a note that String based select cases might not be as fast as Numeric ones. So one thing I would like to see is a more detailed coverage of the subject matter. This version was good enough to grab my attention about the subject, now I'd definitaly like to know more, much more about it. But great work on opening my eyes Agamemnus :-).

Immortis' "How To Program A Simple Text Parser In FB/QB" I think presented an excellent way to parse a string. His article finished with "If I hear any requests, I might show some practical uses of this code or even something different (if I can think of anything...)" Well Imortis, consider this the first of those requests. I would definitaly like to see how to use this for practical use. Let's see what the second of this series will teach us next.

As a last Item on the list, I would like to address Na_th_an personally here, well not so personal in a letter to the editor, but oh well :-). Basically, I'm still very much wanting to read part 8 of his IF tutorial. I'm probably the biggest fan of that series and since part 8 should be closing the gap of the 7 previous parts of the series and making it all fit together, I can't wait to see and read all about it. So, if Na_th_an has a chance (and read this paragraph ;-) to make it happen, then I hope he can find the time to make that part 8 a reality :-).

A very awesome issue, that's the least I can say about QB Express's sweet #16 ;-). One of the best things about it, is to see how much mmore advanced projects the same QB people are tackling thanks to FreeBasic. Would you look at these projects happening lately? I'm amazed and most definitaly glad to see it all happen. And I'm sure there's plenty more projects in the making that are just waiting to be "developed enough to be worth showing to the world" too. Everything is moving forward and well I'm just glad to see that big wheel turning. Excellent work to everyone involved in QB Express, it's really fun to see where the QMunity, the projects and the the rest of the QMunity see where they are going and I can't wait to see what will pop up next. Until Next time.

Stephane Richard

Great feedback, as always! Every month, I look forward to reading your letter (as I'm sure all of our other readers are too)!

As for the whole mennonite situation, I think you hit the nail on the head....and now I'm gonna let the whole thing drop. Interestingly, even though mennonite decided to quit writing for QB Express, he began a new mini-magazine about The QBasic Forum ('apostrophe) and gave me and QB Express exclusive rights to republish it. Even when he vows to never write for QB Express again, he still manages to contribute to the magazine. So I thank him for that.

I look forward to hearing from you next month!


Letter From Lachie Dazdarian

I'm starting this letter on the 9th of November though I know I won't be able to send it for several weeks from today. I want to write this today while my impressions on issue #15 are still fresh. Also, there are few things I really want to say which are making me difficult to concentrate on other things, like preparing an exam. This current situation where I'm able to get online only so seldom is really irritating. It doesn't allow me to present my opinions about the community and the magazine when they are still current and in general, to be a very constructive member of the community(in the sense of being in the loop; I'm not talking about making contributions). I can assume that this also irritates people who email me questions since they have to wait for weeks to get a reply. When I finally get online it's a crazy situation where I need to check all the posts I know I should check and email all the people I need to email in couple of hours. Proper roaming through the community forums is just not an option. For example, I didn't have time to read issue #15 online so I missed the news about the new version of FBIDE and didn't download it. Now I have to wait for like a month to be able to download it. *sigh*

Other aspect of this situation relates to my college where I'm unable to work on my projects on an efficient way since that requires often consultations and similar. All this leaves unnecessary long gaps between exams and forces me to postpone my college projects which will probably make my end of study very frustrating. I also feel I should be doing some sort of part time job now but since I don't live in the capital that is not going to happen. Bus fare prices are very high now. Stupid oil crisis.

For some reason issue #15 left me with so many opinions and comments needed to be written down.

I really want to start with critics about the very editing. I've noticed that my letter in the issue #15 is not the version I have in my archive.

Check this paragraph(original version):

"I've read in the issue #12 your thanks to MystikShadows for pre-formatting his articles. First of all, I didn't know you could do it so easily and format it outside the entire magazine. Shows my lack of HTML knowledge(or is it some other lingo?)."

While this appears in the magazine:

"I read in issue #12 your thanks to MystikShadows for his pre-formatting of his articles. First of all, I didn't know you could do that. I didn't know you could do that one article at a time. Shows my lack of HTML knowledge."

Duh? Did I send you something so awfully incoherent like that? I was sure I sent you the latest version. I don't know. I just want to be sure what I sent you and that this "change" is not a result of proofreading. But this is probably my mistake.

Also, why the second half of my letter has (?) where (') should be? What's up with that? It made my letter look very sloppy.

Few news were entirely in bold like "Adigun Azikiwe Polack AFLIB2 Progress Report" while that shouldn't be(I assume).

I have to comment the way you played with the screenshots in my articles. I know you are the editor and have the right to choose how the articles will look in the magazine but I really think some of your action were unconstructive. Some of the image shiftings are probably the result of you working in 1024*768 or some higher resolution and I work in 800*600 resolution(the best if you ask me, others are just murder of a good eyesight). Still, I don't understand you shifting screenshots I've placed outside a paragraph into a paragraph. Why do you hate screenshots placed outside paragraphs so much? For example, screenshot of the MADMIX's main menu is on the end of introduction section for a reason because the entire introduction is about QBasic pacman games while the very end mentions MADMIX. Putting that screenshot in the middle of introduction where I jab about QBasic pacman games might be confusing for the readers. When I think about the next two articles I already sent you I fear what you might to with the screenshot in them since the placement of screenshots in those two articles is especially important.

Err...the next thing happened in few previous issues too. Some HUGE images mess up the placement of an article in the sense of prolonging its edge to the right. I don't know if that is a problem of IE. This happens in issue #15 in "Graphical User Interfaces - A Complete Study Part 1 - GUI Design" article. Each time you notice that some large image messes up an article you should try to reduce its size and make a link of it in case the reader wants to see that image in full size. That's what I did in Bozula Block Buster review. A similar mistake I noticed with larger images placed in a text box making the text beside the image unreadable(part of it being covered by the image). You should consider "taming" HUGE images in the next issues. That would be about the editing.

I wish to say few things about the current events(well, they were when I wrote this letter) in the community. I'm really sorry so many people(including you) approached with distrusts and some sort of jealousy(not you Pete) to the new management of QBasic.com. First about those "The QBasic Forum" bozos. I'm calling them bozos because they are asking for it. Above all, they should calm down. Mark Wilhelm PAID for the domain and he has all the right to remove the link to the old forum at Network 54 if he likes. If I was on his place I would do it. Why? Because I would want for MY site to feature MY own forum under MY control because I PAID for the domain. The old moderators from the Network 54 forum should ask Mark if he could make them the moderators in the new forum which is something they deserve(at this point) and which is something I think Mark would agree too. Any situation is better than what it was till now with QBasic.com. The only damage Mark can do is sabotage the community on purpose. Doing something like placing a picture of Tubgirl on the main page with a message under it "HOT ENOUGH!". Somehow I doubt this will happen. :P I just think he doesn't deserve such irrational suspicion. We should offer suggestions and help and stop being so paranoid. As for the debate about QBasic.com featuring FreeBASIC content I have to agree with V1ctor on this. I think it's enough to offer information about FreeBASIC and links to appropriate sites. Let's get real, QBasic is a different compiler and FreeBASIC is not the OFFICIAL update of QBasic. If any site has to remain true to QBasic then that site is QBasic.com. If you don't like that then don't visit the site. Anyone using FreeBASIC has absolutely no right to demand the userbase of some other compiler whatever his or her opinions about that compiler and its link with FreeBASIC are. So I'm personally against FreeBASIC content on QBasic.com except for information about FreeBASIC and links to FreeBASIC sites. That's more than enough. Anyway, QBasic.com was for years outside the real QBasic community(based around VPlanet, qb45.com and qbasicnews.com) so claiming that QBasic.com belongs to the community members who switched to FreeBASIC is wrong.

As for mennonite, I mostly disagree with him and find his dislike of FreeBASIC childish. I can assume that this attitude comes from his hate toward Windows which I find difficult to understand since his bellowed DOS is also a Microsoft product. I generally think that Windows are criticized way too often with very little real arguments. My PC(with Windows XP installed) serves me so well from coding in FreeBASIC, doing college projects to playing QBasic games. Some people forget that the majority of computer users are not interested in computers. They simply want to have an OS that serves their needs on the most efficient way. Anyway, the way mennonite behaved(through his posts to you Pete) makes all of us doubt his maturity. I hate using that word since it makes me sound condescending. But really, I can't escape the impression that he is a very inpatient person who reacts with rage on any obstacle and changes opinions on hourly basis. Definitely a troubled boy who should grow up. The only thing I didn't like in your response Pete is your opinion about rude behavior toward "annoying" newbies. I highly disagree with you in that. There is a very thin line between justified and unjustified rudeness and people go across that line more often than not. I've experienced similar rudeness without asking stupid questions or being annoying and that rudeness was almost always a result of that person's inability to help me. If you can't or don't want to help someone why in the world attack or trash that person? Really? I don't see any sense in that. Be kind and warn that person about his or her poorly constructed question. The only real reason to attack someone on the Internet with rude words and names is if that person constantly spams the forum or really has a poor character, where he or she keeps insulting everyone or is openly a racist, pedophile or whatever. I don't know. But stupid questions are not a reason for bashing. Period. Anyway, not all people have time to search for the right tutorial, including me. Their time on the Internet might be limited(you don't know) and pointing them out to the right tutorial is a blessing. Also, many tutorials do more damage than help. And believe me on this because I remember by beginnings very well. I also have some experience with newbies and know what kind of mistakes they do. Mistakes mostly caused by over-simplified and poorly constructed tutorials. That's one of the reasons why I'm planning to create a series of articles about game design oriented programming which will allow newbies to learn game design in few lessons and skip several annoying and unnecessary long stages in learning how to program games. I just know how indifference of moderators in forums toward bashing can be destructive and where it leads. Mark my words.

Phew, I'm not even near the end of this letter. I'm scared too. :P

I'm quite surprised with the poll results(What is your favorite finished FB game?) and very reserved to them. Looking at the number of votes "Other" got makes me wonder did the people who click on it understood the question. The question was about your favorite FINISHED FB game. I would really like to know on what game(s) these people were thinking and do they honestly think that this "secret" game is better than Red Jumpy Ball or The Quest For Opa Opa or ArKade or Battle Pong or Poxie or the brilliant The Griffon Legend. If you ask me, jealous losers voted for "Other". I apologize if I'm mistaken but I doubt. Like I said, show me this game and I'll apologize. I forgot to vote in this poll like in so many before. And the last time I was online I again forgot to vote. Crap.

In the news section you mentioned my articles site. If anyone is wondering I'm having problems logging on to my account(some stupid new college firewall) so I was unable to update the site on the 7th of November and I don't know if I'll be able to do it any time soon. But two updates are ready. To those few who actually visited the site I can only promise it will update. Somehow. :( It's not a site went dead, I assure you.

Also, MystikShadows described the preview of the MySQL QBasic games database I'm creating as a site. I don't want for people to get the wrong idea about this preview page. It is not a site nor it resembles to my idea of the QBasic Game Directory site. It only features some of the RAW content that will appear on the site. The only reason why I'm showing this preview is because I'm having problems running some of the QBasic games so in order to get help on that I need to show people that I'm actually doing something. I need to show them that this project just might be successful and their help won't be in vain. But for some reason nobody is offering help in testing these game. I barely got help regarding one of my games(Dark Quest) from Zap since I can't score and critically describe my games. I think the site will have to open with around 50 games on the pending list because the community simply dropped the ball on this. I think I'll have to find one person who has an access to several PCs with several Windows version to do the testing of those game since my requests are not bringing result. But at least any critique, when the real site opens, regarding so many games on the pending list won't be my fault.

It's nice to see Adigun's work on AFLIB2 going so well and I hope it will be GFXLib friendly or will have all that GFXLib has plus more. I'm having problems getting certain routines necessary to port LONG to FB(I will obviously have to cut out some of the game's features) from Eric including 8-bit translucency and sprite scaling and rotation. BTW, what's up with Eric? I didn't hear from him over a month. I'm stuck without him. Anyway, hopefully AFLIB2 will solve most of my "game design oriented programming needs". He-he.

I'm surprised to see someone still developing in FutureLib(I'm referring to Cadisman from the Gallery section). I hope that Brad Lanham is aware for how small userbase he is developing. Someone should suggest him to switch to FB.

I can't say I'm happy with the quantity of articles and tutorials in this issue though the decline, compared with the issue #14, is almost ignorable. But if you take out my and MystikShadows contribution you will have 5 articles and 3 tutorials. I'm not presuming the quality of my articles here, I'm just saying that without certain 3-4 contributors this magazine would look much smaller. I really hate when some tutorial series stop to be released like Rattrapmax6's "A Course In FreeBasic" or Na_th_an's "Coding A Parallax Scrolling Platformer" which is almost forgotten(issue #10, remember?). I would really like to see more people sticking with their series once they start them. All in all I feel a certain slowdown in the community which is, I admit, just my impression. What I can notice from the magazine and from the number of replies I get on some of my topics(an the quality of replies) in www.freebasic.net forum the community is not active as it was few months ago. I think too many people are concentrated on their projects or just concentrated on something other than the community at this point. Just look at the tutorials section in this issue. If we ignore Jonathan Wallace's tutorial about group A.I. others don't feature a single line of FreeBASIC code. Like I already said, I'm planning to do something about that by starting a concrete, "all around" game design oriented tutorial. Anyway, I'm sure the situation will get better. That is if you agree with me that it's not the best.

Both comics were very amusing in this issue and I applaud both Rattrapmax6 and Matt2Jones on their work though I still dislike the approach Rattrapmax6 has to drawing.

urger's article about writing was very useful and just what I needed. Remember all those questing I email you about grammar? Matt2Jones "Game Production" article was strangely insightful but I don't agree with him entirely especially with his statement that making a game faster makes it better. I think it would be better to say that unnecessary slow pace and delays in a game are a shameful rip-off of user's free time.

I think I should end this horridly long letter now. Like I always say, take my comments in good will as they were written in good will. If I'm wrong help me realize that. I so hope some of this dribble will relevant in a month.

Best Wishes, Lachie D.

P.S.(Oh, noooooo!)

This was written on December 8th before I got online. I had many plans for this month but all of that had to be postponed because I decided to participate in the Roguelike competition. I know, I know. I promised I won't start developing another game before finishing LONG. I got hooked on the idea of creating a Roguelike game with a turn-based battle system after reading the last issue of QB Express. For a long time I wanted to create a game with a turn-based battle system and this compo seemed like a nice opportunity. I just couldn't help it. Once the thought enter my mind I had to start to develop my entry or I wouldn?t be able to sleep(help me). I hope those 2-3 persons who are waiting for LONG will forgive me for being so weak. Since I was developing a brand new game for the last 30 days I did nothing for QB Express and very little on the QBasic Games Directory project though the work I planned to do was minimal. I'm hoping to get some useful PHP tips next time I get online and will attempt to create at least the skeleton of the site during the holydays. Where's my new game, you must be asking yourself(just work with me :P). Well, it's bloody not finished! Argh! I spent over 90 hours (I timed it this time), around 25 evenings and it still isn?t done. Ugh. I gave up a week before the 16th(the day I'm emailing this letter) since I realized I wouldn't be able to complete my entry(named Mini Space Rogue) properly and since I needed some time to decompress for the college obligations. I didn't want to finish it.....hmmm...I would say on Croatian "na vrat na nos" but I don't know how to translate that to English. All in all, I need more time. I want to be happy with the final version. Expect the release somewhere in the middle of the January 2006(stop rolling with your eyes) and don't expect anything grand. First of all, it's a Roguelike game. No dialogues or some complex plot. Just endless walking through dungeons. Well, in Mini Space Rogue it's through an abandoned space ship. Anyway, Roguelike theme was very convinient for creating something not very demanding in the graphics department(static graphics) and even less demanding in the story/plot department. And that's the main reason why I'm pissed for not being able to fininsh Mini Space Rogue before today. It won't be anything special. I've sent you Pete the crippled version. If you want to say few words on it be my guest. Just don't SHARE the archive or I'll think bad of you(how threatening).

Thanks for the great letter! I'll respond to a few parts (sorry if I skip something important -- it's a very long letter).

I'm sorry about your issues with the formatting and proofreading. It's pure negligence on my part. I make QB Express on a computer with a 19" monitor at 1280x1024 resolution, and it looks great at that resolution, and also at 1024x768. I know a lot of stuff in the layout gets screwed up at 800x600 resolution, and I apologize. If I had more time, I would gladly reformat the magazine for different screen resolutions, but I'm just too busy. I release the mag every month knowing that it will look wonky on anything less than 1024x768.

I guess I've just got to cut my losses. Since only 17% of my site's visitors use a resolution of 800x600 or lower, (and that number is dropping every single day), I figure that I should tailor to the majority of my visitors. The up side is that people like to look at big images, so using HUGE images means that at high resolutions, the magazine will look much better. I could easily fix the formatting and proofreading problems if I had another full day to spend on each issue...but I just don't have the time, unfortunately. If anyone wants to volunteer to help me with this, it would be great.

As for the discrepancies between the final version of your letter and the one that was published, I'm not sure how they came about. As you know, I do very little proofreading on my own since I don't have time. That particular letter might have been edited by urger when he did the proofreading (though I doubt he would have edited it like that to make it less intelligible). As for the ? marks instead of apostrophes ('), that happens when converting between raw ASCII text and ANSI text. Sorry I didn't catch it when I published the issue.


I also have noticed the slowdown in the Qmunity in the past few months, both in number of posts and submissions to QB Express. It seems that every issue since #12 or #13 has been a lot smaller than they were just a few months before. The total number of posts on some forums has dropped significantly -- The Basic Network barely gets any posts these days, QBNZ is almost dead, QB45 is down to just a few posts per week, and QBasic News and my site's forums have also slowed down. In fact, the only forum that's gotten more active recently is FreeBasic.net's. The number of new program releases has also slowed down.

Why? I think what it comes down to is that "FreeBasic Fever" has died down. FreeBasic is no longer a new thing, so people aren't as excited about it as they were at this time last year. There simply aren't as many finished releases being made right now. So in that respect, the Qmunity has slowed down. However, the Qmunity is still WAY more active than it was when I first started QB Express back in the summer of 2004 -- in the days BEFORE FreeBasic. Just look at the "Project News" briefs this month. There are so many HUGE projects in the works, including a lot of awesome games and libraries that will undoubtedly set new standards for the FB community. Sure, the number of releases my have decreased, but the quality of the releases these days is much higher than the before. (What would you rather see, Lynn's Legacy or two dozen graphics demos?)


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!

Should Pete remember to post polls from now on?

1 Total Vote
Whoops! It's been a very busy month, and I completely forgot to post a new poll. (The one vote in the poll above is from me, heheh...) Anyway, there WILL be one in the next issue, promise.

News Briefs

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

QB Site News

QB Top 50 Relaunches

After a hiatus of several years, AhmedF has relaunched QBTop50.com! This QB / FB top sites list couldn't have come at a better time, now that the last remaining QB top sites list (the QB RPG Top 50) went down a few months ago.

Unlike past top sites pages, the QBTop50 rates based on Unique Hits to registered web pages, so it is much more difficult for webmasters to cheat than in the past.

QB Top 50 - The best QBasic and QuickBasic Sites

The Pete's QB Site / QB Express voting image for the QB Top 50. Shameless self promotion, I know. So sue me.

If you've got a QB or FB website, I encourage you to register it with the QBTop50. It will help give you free publicity, and will almost certainly drive more traffic to your site.

News Brief by Pete

A Ton of QB GUI News

Todd Seuss and company have been keeping up to date on the QuickBasic GUI Blog launched back in November. In the past month and a half, there have been a few dozen news posts on various happenings around the QB GUI Community. In fact, there are far too many releases and news updates to mention here, so you should go and check out the blog for yourself!

News Brief by Pete

FBIde Official Site Launches

The new site design for VonGodric's popular FreeBasic IDE FBIde, has just launched. You can view it at either http://fbide.freebasic.net or http://fbide.sourceforge.net. The site now sports a brand new CMS created by VonGodric specifically for the site, and a snazzy new design. Sweet!

News Brief by Pete

The Code Post Makes A Comeback

Dav has resurrected The Code Post, a QB message board from a few years back where users were encouraged to post snippets of their code. Here's some info from Dav:

The once (kind of popular) Qbasic code post I ran a few years back is returning - this time adding FreeBasic to the list.

The code post is a forum driven site where programmers share their work with others. The main site is still being developed, but a temporary forum is up and running.

More languages will be added. Code packs will be assembled containing all contributing code posted and be available for download, if it gets that popular again...

For those new-comers that what to see what the code post was all about, you can download the last Qbasic source-code book right here...


It contains all the source code submitted before the site was closed - over 100 snippets in it.

The Code Post is hosted by Plasma (Phat Code), and base don Fling-master's Flingforum mesage board script. Go check it out...and post your code!

News Brief by Pete

Project News

Dark Knight Software Releases Dark Ages II: Engel

On December 11th, Dark Knight Software finally released the sequel to the well known Dark Ages I. It's called "Dark Ages II Engel". Here is the description of the game that you can read about and download from the website:

About Dark Ages II: Engel

Dark Ages II: Engel is a free computer role-playing game that follows the story of those three initiates of the Thieves' Guild. The plot is non-linear in the sense that key points in the plot will require a choice. That choice will lead to different quests without turning back. The world will change according to those choices. I hope to add replayability (is that a word?) by allowing the player to start the game over after they've won and play a whole series of new quests and still win the game. How it differs from most non-linear games is that it does not change how the game ends; merely all the content in the middle. A lot of games change the storyline to fit non-linear choices, but the quests and tasks are the same. In the case of DA2, some quests will never become available. You will just have to play again to try them out.

Here are a few screenshots to give you an idea of the type of game as well as all the hard work that has been put into this game's production.

The game is currently in its release candidate 4 (RC4) state which brings it very close to its official release. In fact, they state that the official release should be out by christmas. All of you readers are encouraged to download the game and give it a try see if you can spot a a final bug that can be corrected before the official release date.

News Brief by MystikShadows

Yagl - Yet Another Game Programming Library

Yagl is a high-performance 2D game programming library based on OpenGL and OpenAL, outperforming SDL and Allegro. Its purpose is to be a fast, easy-to-use general-purpose game development tool. It is completely object-oriented and supports fast graphic blitters, easy integration with OpenGL, 3D sound, keyboard and gamepad input, and networking capabilities, native support for loading oggs, wavs, aus, snds, bmps and pngs. Also, wrappers for C and FreeBASIC exist making it attractive for procedural languages too. you can get more information on yagl at http://goddess.selfip.com/yagl

News Brief by marzec

duke4e Creates an Arkanoid Clone

duke4e has been busy these past months with the creation of his Arkanoid Clone. As most of your know Arkanoids hardly needs an introduction. It is an evolutionary step to the classic breakout type game and features many addtions to the game to help make it more interesting to play. The game seems to respond well to user input and performs quite well even on lower end systems which broadens it's range of users.

Here are a few screenshots of the game in action. You'll see quickly here what this game is all about and what you can expect out of it.

You'll be happy to know that on December 9th duke4e has release the official version 1.0 of this game for all to download and play.

You can follow this game's development and user's comments right here on the Freebasic.net Project thread forum.

News Brief by MystikShadows

Mambazo Anounces Arena: To The Death

Just last week, mambazo announced an ambitious new FB fighting game entitled Arena: To The Death. It's still in its early stages, but mambazo has big plans for it. Here's the full report, copied from his Freebasic.net post:


A small project i've been tootling about with for the last few days. It's still in the very early stages of development.

This is inspired by the fighting system of the age old game Budokan. So button bashers beware! Its all about timing and precision ([i]note: you can beat the single player opponent in two well placed moves![/i]). There are 6 attacks, 4 tactical moves and 3 blocks. More attacks will be added at a later stage.

I hope to make at least 10 different fighters, with axes, maces, etc etc!

Plans in development:

The game is taking a more interesting turn! You will mainly play the part of an Owner. You'll be able to buy & sell fighters, enter different contests, win cash, and manage your fighters!


You receive coinage for each battle you win. Use your Wealth to purchase more fighters and maintain them. You can also spend your earnings in the Black Market to increase your chances of winning. If one of your fighters is no longer of use to you, you may sell him.


Before each fight, there is a chance a stranger will approach you with a request. You can choose to accept or reject the offer.

The higher your reputation the more likely you will be asked, and the more money you will be offered. As your reputation increases, the tasks will get harder. If you complete the task, you gain a reputation point. If you fail, you loose a point.

Depending on your reputation, you may or may not be eligible to enter certain arenas.

The Alley

This is where you will most likely start your career. In the grotty sidestreets, out of site. The winnings are low here, but the entry fee is most forgiving. You will not face any heros here, just clumsey unfit oafs, desperate for money.

The Battlegrounds

Whilst costly to enter, considerable winnings await you at the battlegrounds, provided you can hold your own. Pit your fighters against the commonfolks' lesser heros in public. Let your name spread through the city!

The Grand Arena

Only the most barbaric warriors remain standing after battle in The Grand Arena. Bleed your way to true fame and wealth while thousands of onlookers gasp and cheer! The entry fee is hefty and the winnings are glorious.

Fighter Stats

Health - The amount of damage he can take.

Stamina - Affects the amount of damage he can deal. During battle, he will tire with each swing of his blade.

Vitality - The rate at which his stamina regenerates.

Strength - Affects the amount of minimum damage he can deal.

Range - How far he can reach with his blade.

Experience - Gained after each battle. The more fights he wins, the more valuable he becomes.

Worth - For use in trading.

Wages - The amount this fighter costs you each week.

Black Market

The black market is where you can gain an devious edge over your opponent before entering the arena.

Doctor - Heal your wounded fighters.

Stab - Wound your opponent before the battle. Make him weak on his feet.

Blunt - Blunt your opponent's weapon such that he cannot wound you deeply.

Poison Blade - Poison your own blade. Make your opponent suffer.

Studded Boots - Suprise your opponent with a steel kick to the ribs.

The Devil's Drink - Drink this before battle for a more, stimulating, fight.

Undercoat - Feel indestructable with an extra layer of armour.

Gamble - Be sure of yourself and place a bet to win, at the Grand Arena.


The fighter manager part of the game has not been coded yet, as I wanted to make sure I could make a, somewhat fun, fighting engine first.

In the Single Player zip there is a file called [b]moves.txt[/b] showing you your keys (W A S D, G H), and all the moves currently available.

Comments & critisisms welcome,



Download Arena.zip
note: on the first seletion screen, press 2 to watch the PC fight itself.

Download Arena_Update_07_01_06.zip
Note: You need Arena.zip also to use this update. Just unzip into the Arena folder and let it overwrite the files.

News Brief by Pete / mambazo

Zero G Academy Splits Into 2 Games!

Syn9, being the prolific FB developer that he is, has decided to turn his upcoming racer into two different games:

I split Zero G Academy into 2 games. A gunship game that is currently untitled with gameplay like the Jungle Strike / Soviet Strike games. And Zero GTR, which is the sequel to Zero G.


Here's the logo from Zero GTR:

There are also several more screenshots from Syn9's upcoming projects available at his website, Syn9's Hideout. They include the Gunship game, as well as an upcoming 3D RPG made in QB and a Turn Based Strategy game. Incredible stuff, if I do say so myself!

News Brief by Pete

Turn-Based Strategy Game Making Progress

The engine for the game has progressed quite nicely thanks to syn9 and Eclipzer. The engine now sports randomly generated trees, lakes, rivers, and bridges. Line of sight has been implemented, as well as movement squares. Rattrapmax and xteraco have been busy making new models, such as a new mech (Rattrap), new buildings (xteraco), and more.

By next month, we expect to see animated and textured models. We also plan to have the main game loop done. Ryan is working hard on his network code, a big deal in turn-based strategy games. That's right, the game will have full multiplayer support. SSC has been working hard on the game rules, and the design document. Thank heaven for him, because we'd be lost without those rules. I, Torahteen, have little to do at this point in time, other then to look over the project to see that it gets done. Truthfully, I enjoy my job ;). Here are two more screen shots to show you all just how much work the team has been putting into this project.

More info next month. Until then...

News Brief by Torahteen

AFLIB2 Status Report

(As of December 19th, 2005)

As some of you may already know from his many update posts on the different forums, Adigun Azikiwe Polack has been relentlessly busy working on his AFLIB2 project. The forum threads are of course FreeBasic.net thread and the QBasicNews.com thread. I've been covering it's development for a few months already and it seems, every month, the new functionality just keeps on growing at a good and steady pace. Here is the rundown of the new functionality added in the course of the last month.

  • AFLIB2 Filters: Yup, AFLIB2 now has image filtering. the ability to filter colors out of a picture which is used to add some pretty impressive visual effects.
  • AFLIB2 PP256 Based Scoring: Specialized routine for managing and displaying scores first it displayed the scores, now it displayes the scores with translucency which according the screenshots on the forums, really gives a great effect.
  • AFLIB2 Horizontal Screen Flipping: I think this one pretty much speaks for itself. The ability to horizontally flip (often call a horizontal mirror) of any given pictures.
  • AFLIB2 Can now be compiled as a whole: Indeed Adigun has prepared all of the code so that it can be compiled as a whole library. As mentionned by adigun himself, the compiled library stands at around 7 megs which is a big size indeed. However, for the functionality it offers (and the work it saves the programmer) I don't believe that 7 megs (3.5 Megs minimum) isn't all that alarming.
  • First AFLIB Sample Program Available: On December 12th, Adigun offered us a first sample program available to be viewed. You can see from this example that it really seems like AFLIB2 is well underway to making the code you'll have to write as short as possible using this project. Here is that sample application.

It's important for you to know that these additions are available in all screen resolutions supported by the AFLIB2 project. Also, Adigun has started the tedious task of documenting AFLIB2. With all the functions, it might take him a while, then again, it might not. So be on the look out for upcoming (as soon as he possibly can) of a no doubt very detailed documentation for this very elaborate library project.

News Brief by MystikShadows

Black Satin!

Nekrophidius has announced a new FreeBasic fighting game he has in the works, entitled Black Satin. The game will use marzec's speedy YAGL library, and is sure to have a lot more twists than that. Here's the word, straight from Nekrophidius/Nodtvedit/sn0ball (apparently)...

Black Satin is a fighting game not unlike other 2D fighting games, with one exception: all the characters are female and they're all 3D rendered rather than hand-drawn. Anyways, here's an early shot of the game working...this is just the vs screen and it doesn't show the graphical effects I used here but anyways...

This shows Midarana (left) and Desiree (right) about to catfight. :)

The one thing I've noticed while testing yagl is its amazingly high speed...even on my crappy old TNT2 video card. Anyways, I'll get some screenies of the game "in action" soon, and perhaps put out a prototype build within a few days or so...

For the record: anyone from the MUGEN scene of old should remember this game...I, as "sn0ball", was developing Black Satin for MUGEN back in 2000-2001...my star character for the game was "Megan" and she was the only character to ever be released "into the wild". Once MUGEN "died", I dropped this project...

I'm sure it doesn't need to be said, but Black Satin sounds awesome...I for one can't wait!

News Brief by Pete

Lynn's Legacy Progress Update

Here's all the latest on Lynn's Legacy, courtesy of Josiah Tobin!


Maps are going great, thanks to Cha0s' custom-made map editor, 'Gmap', that has existed and gone through many different iterations since the start of the current development process. All the overworld maps are complete, and the dungeons are currently the main focus. Dungeons 1-3 are fully complete (though 2 and 3 are currently sans-boss), and dungeon 4 is about 1/4 done. There are eight dungeons in total, the first six of which play essentially like the dungeons in Zelda: A Link To The Past. The last two have a slightly different focus and purpose. (no spoilers, sorry :p) We were thinking about releasing a version of the game that is complete up to the end of the sixth dungeon, once we get to that point-- Basically a 'teaser' version of the game, with most of it there, giving us time to work on the somewhat ambitious final section. IF we do go through with this plan, the idea would be that we would have an earlier release date for most of the game, and while people play through that, we'd be working on finishing up the 'lost' segment-- Hopefully we'd finish it before most people beat the released version. Anyhow, that's all speculation; we're still not certain, and the idea was very vague when first mentioned anyway, so don't expect anything.

Note: All the dungeons were planned out beforehand on paper; they're all fully designed, barring the last two-- The plans are simply used as reference for the actual maps, and the smaller details of the individual rooms are all thought of and implemented during editing.


Graphics are all complete, for the most part, and have been for some time now. There are a few tiny exceptions, like certain little sprites I forgot to do, that are always taken care of whenever the need for them arises. For all intents and purposes, the graphics are 100% done.


Music is all 100% done. Sounds are being done along the way, as they're needed. Since they're so simple to do, this isn't really a problem.


The Lynn's Legacy script is fully complete, is roughly 40 pages long, and does not include descriptions of any of the dungeons, except for key story points that occur within them. For the most part it simply details the path of the game, and every line of dialogue within. I'm very proud of the script-- I honestly can't wait for the game to be finished so I can see the reaction to the final section of the story. On the topic of story, it's interesting to note that originally, the game wasn't intended to be too plot-heavy-- it was simply meant to be a somewhat basic action-rpg with only the essentials of a story to hold it together, instead focusing primarily on fun factor and how it played. When it started out in mid-2003 (I think it was 2003? Cha0s may be able to correct me here), the concept and story were COMPLETELY different, the only thing in common with its current iteration being the name, and the type of gameplay. Maybe I'll elaborate more on this in the future if anyone is interested, once the game is finished.


None. :p Not yet, at least. I know you've all heard it before coming from various projects, but it will be finished. Maybe we'll have a better estimate when we're closer to our goal. As mentioned before, the main focus for me is currently the dungeon maps. The amount of time it takes to complete a full dungeon varies-- The second dungeon took several weeks (more due to apathy than anything else) while the third was completed in about a day after working on it almost constantly. I'll also be working full time very soon, but you can be sure that I'll spend every second of free time I have slaving away on the maps. :p

News Brief by Josiah Tobin

Competition News

Rogue Compo Update

(As of December 19th, 2005.)

As is now tradition, and as you've come to expect, I am bringing you now an update on the ongoing Rogue like compo currently happening on the FreeBasic.tk forums.

First off I would like to announce that Lachie Dazarian has now joined this compo as you can read in this FreeBasic.tk forum thread. Indeed, on December 16th, Lachie announce his interest to join this compo with an already impressive entry as you can see from the screenshots he supplied on this thread.

Now for the update. From what I have read in reply to my monthly post, it seems some people have done alot, others have had less time to work at it this month. My thread on the monthly update can be read right here. Here is a rundown of what has happened this month.

Andrew Collins reported the most amount of changes this month. And what an impressive list of change it is. Here is his very own reply with all the details: (fasten your safety belts, there is a lot).

"These are the changes since the last build that I reported to you....

0.17e 12:30 AM 11/19/05
Monsters use spells now and fixed some bugs

0.17f 9:04 PM 11/19/05
Added some more spells and did some work on the parser.
Added some more monsters.
Monsters that can (and will) teleport, when you hit them.
You may now enchant(and disenchant) items.
Added a save game feature(exiting the game autosaves)
Lowered restrictions for special item generation so more will be generated.
0.18a 10:29 AM 11/20/05
Went bug hunting.
Found a bug in the spell parser and fixed it.
Found a bug in Inventory and fixed it. X2
Found a bug in Melee combat and fixed it.
Added the ability to drop multiples of the same item on one tile.
Found a bug in the Item Generator and fixed it.
Arrows must be equiped to use them with the bow.(Quiver)
Arrows stack when equipped in the quiver.
Inventory auto sorts by tval's(might color coded in the future)
Added more Items and Item specials.
Added more spells.
I've given Jocke his own spell! Look for it on a scroll.
Added more monsters.
Player can now die!

0.18b 6:40 PM 11/21/05
Fixed a game killing bug in the spells sub.

0.18c 7:35 PM 11/21/05
Fixed a small inventory bug.
Removed the numbering system from the spells.
Added more spells.
Gave Ryan and Myself a spell.(I'm not very flattering with spellname's)
I did reverse the names to protect the innocent.

0.18d 6:45 PM 11/22/05
Fixed another inventory bug.
Items now drop around you if you are dropping an item and one is at your feet.
You may eat food now with the Quaff command. Food heals damage for now.

10:45 PM 11/23/05

Removed the console window.
Starting to add mouse support.

0.18e 2:33 PM 11/25/05
Monsters now have enchantment immunities.(can't be hit by a +1 weapon and so on)
Monsters now can be invisible(see invisible for monsters isn't implemented).
Fixed a bug in the Monster Generator.
Monsters can now regenerate.

0.18f 4:50 PM 11/28/05
Monsters can now use breath weapons.(Dragons and Others)
Item overlays can now add and take away from players speed.(+ and - to speed items)
Items can have see invisible.
See Invisible spell.
Changed Display slightly
Added Spells +/- ToHit, ToAC, ToDamage
Added item Slay (Creature Type) X4 damage
Added item Hurt (Creature Type) X3 damage
Added item Harm (Creature Type) X2 damage
Added Item Harm/Hurt/Slay Evil, THIS STACKS with the other damage bonuses
So if you have a "Holy Avenger" dagger that SLAYS DEMON and SLAYS EVIL
and you attack an EVIL DEMON it will do (X4 damage) X4
so lets say you do 2 base damage.
SLAY DEMON Raises that to 8 damage(2 X4)
SLAY EVIL Raises that to 32 Damage(8 x4)
So while a "Holy Avenger" is bad for evil monsters, it's REALLY bad for evil demons.

0.18g 4:04 PM 12/1/05
Added a MiniMap (works off the ~(tilde) key)*----Graphics only
Fixed an Inventory drop bug.
Monsters will now drop items.
Fixed a rather nasty bug(Out of bounds) in the dungeon display code.
The X key in the Inventory/Equipment Menu's allows you to examine Items.
If you are looking at Inv you can Examine Inv.
If you are looking at Eq you can examine Eq.
Works well for comparing items.
Fixed a few minor bugs.
Added Resting to regain 1 hp per turn(X key or 5 on num pad.)

0.19a 12:03 PM 12/3/05
Added Resistance (+/-) to specials.
Fixed a breathweapon bug.
Fixed an item drop bug.
Fixed a monster casting bug.
Added resist viewing to the View Player(C) menu.
Monster attacks can now drain experience and can poison.
Monsters now use an ammo variable.
Monsters that can heal other monsters will now do so.
Animals and Insects can't open doors anymore.
Made dungeon larger and added more monsters,Items, and item overlays.
Items now need to be identified.
Equipping an item automatically Id's it.
Examining an item also id's it(For now!!!!!!)
Added randomresist to special.txt parser.
Started work on skills.

0.19b 8:20 PM 12/5/05
Added wands
Added rods
Added spell effects for other items(rings,amulets and such)
Items will now stack and unstack according to thier stats.
Fixed a Targeting Bug.
Tweaked the Message parser a little.
You now can scribe spells into a spell book.
You now need a Mana crystal in your inventory to cast a spell from a spell book.
Mana crystal charges stack in inventory.(When you pick up a mana crystal it's charges
are add to the master crystal.I.E. you never have more than 1 crystal.)
Items will now cast a spell on a hit.(Fireball arrows and swords and such.)
SPACE clears the message display.
Melee and ranged skills have been implemented.
Magic skills have been implemented.(Except General Affinity)
I haven't completely abandoned ASCII but it doesn't work well anymore(will work on it later).
Changed experience(it now takes twice as much to level.)
Message's will now auto clear after four turns.
Item Specials that raise a skill level will now stack on the same item IE....
If you have an item that rasies Fire Affinity twice you will get
a 20% bonus instead of the normal 10% bonus!
Examining items shows relavent information. IE...(E(X)amining a shield won't show it's damage anymore(unless it adds to damage!)

---As of this writing this is what I have done for the newest build
0.19c 2:09 PM 12/13/05
Increased melee and bow skill leveling.
Fixed.. an inv drop bug.
Fixed.. Eq and Inv text weren't aligning correctly
Fixed.. There was a delay in monster movements that would stack and slow the game down,the delay has been removed
Mana crystals now display the charges they have when you open your inventory.
Added an equipment slot for spell books.
You must unequip a spellbook to (S)cribe spells into it.
You may now use the (M) key from the main screen to cast a spell from an equiped spellbook.
RDC styse messages (the old system was rather ugly)

I'm hoping to go to beta around christmas.....


Needless to say Andrew has been very productive and busy since his last report. anothing I've noticed is that the projects are definitaly starting to evolve and mature. I'm assuming that soon, we'll all be busy giving atleast some of these games a try.

Barok, Ryan and Xerol essentially reported no progress this month. Of course that doesn't mean their project is dead, it is december after all, time for holiday planning and the rest of what we do during this month.

News Brief by MystikShadows

Have QB / FB news to report? Send an email to pberg1@gmail.com!


Written by Pete / Lachie Dazdarian

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!

Mini Space Rogue by Lachie Dazdarian

Lachie is at it again -- this time with a new FB roguelike called "Mini Space Rogue" -- and boy, is it great so far! I was given a special sneak preview version of the game this month, and MSR is already a very polished and very fun game. It has many elements of traditional roguelike games, but many cool innovations too (such as attacking separately with your left and right hands). It certainly gets my seal of approval.

I would write a full preview for this game, but Lachie has been so kind to write his own preview the entire game for you -- and what better person to get the inside scoop on a game than from the creator himself?


I've been developing a new game named Mini Space Rogue for the last 30 days which will be my entry for the Roguelike compo. The decision to work on a new project was quite sudden but once I started thinking about it I couldn't get it out of my head and had to start to develop it(I need help). Apologizes to people who are waiting for LONG to be released. My plan was to finish Mini Space Rogue before the December 16th(when I knew I'll be online) but I failed. I gave up a week before that date since I realized it couldn't be done. My concept simply turned out to be much tougher to code and the graphics more demanding to draw that I originally imaged it to be. I can't believe I convinced myself I could finish it before the 16th. But I must be honest, my work on the project was not very intensive with around 4 hours per day in average. I could only code during evenings since I was preparing an exam but a lot of time went into watching TV(my life is so exciting).

Anyway, Mini Space Rogue is a Roguelike game(what a shock) placed on an abandoned bio-research space ship and the movement is mock-tile by tile(characters slide from one position to another). Mini Space Rogue is also my first game done in 640*480 screen mode(weee!). NPCs and the main character are represented with a simple tile. No "walk" animations. A lot of time and effort went into creation of the game's interface which is both mouse and keyboard controlled(you pick). I think Mini Space Rogue will mostly be remembered because of it's interface. The battle system is turn-based(as well as the non-battle mode) and in the classic "you hit me, I hit you" concept I tried to introduce something new. You see, in Mini Space Rogue the main character can carry two weapons, one in the left hand and one in the right hand. During battle when you attack with one hand that hand stamina decreases and if it completely depletes your attacks with that hand will be less powerful. This concept is combined with the game featuring two types of weapons(hand and fire weapons) and with the main character being left or right handed(you pick). I was not quite successful there. The very system in not very beneficial for the gameplay but it doesn't damage it either. The game will feature 5 medium sized levels and one small(bridge). Being a Roguelike game it won't feature dialogues or some sort of plot development. It will be about exploring the ship, fighting monsters, leveling up and gathering useful items(a lot of items in the game). The in-game graphical design(map tiles) is not the game's strongest part but I managed to create a nice light/point of view effect. Sadly, this light concept created new problems since it requires 4 versions of each tile in the tileset to exist and the tilesets are being made with PP256. We all know about PP256 64 KB tileset limit.

Why it's called MINI Space Rogue? The original idea in my head included at least 5 huge space ships to explore featuring some neat way you find(track) abandoned space ships. If some game developer happens to really like Mini Space Rogue he or she(oh, yeah!) can try to expand it.

I need at least one more week to complete this game but great deal of it has been finished. The menus, instructions(it needs few more nitpicks), save/load game feature, entire interface, skeleton of the engine, 2.5 levels out of 6 and 90% of the graphics. All I need to do is design the remaining levels. It won't be easy but it will mostly be designing and very little coding. One more tileset probably needs to be created and there's the music. I think it won't be difficult to create nice music for this type of game. All I need is few Pads in Fruity Loops and viola! I have suspense-like atmosphere. Anyway, apologies to people who are waiting for my other projects to be finished(articles, QBasic Games Directory, LONG, ...). I just can't help myself(I'm sick).

I will be able to release the game somewhere in the middle of the January, 2006.

-Lachie Dazdarian

Visit Lachie's website, KENTAURI, to find his other games.

News From The QBasic Forum

Written by mennonite

new year edition, 2006

[issue 1]

= from the editor =

welcome to the first edition of 'apostrophe. this project began in response to a complaint made by pete berg, editor and host of qb express, the leading magazine on qbasic news: [yes, damnit, it's an excellent magazine. no, damnit, i'm not being patronizing -ed.]

As for 'The QBasic Forum," you complain that we don't include you in the Qmunity -- but it's for good reason, in my opinion: you keep to yourself and don't share anything with the rest of us.

'apostrophe is not intended to replace any feature of qbe, in fact it is designed as more of a supplement to qbe from our forum. there are at least three possible responses i expect and welcome from qbe and its readers:

  1. come here to read our news. it's certainly possible to do so, though it doesn't solve the "you never tell us" challenge.

  2. someone can pick up 'apostrophe and "transplant it" in whole or in part to qbe- i retain copyright as do the authors of things i quote and screenshot, etc... but i'm granting qbe the exclusive rights to copy/summarize/edit (please do not give us all the credit for your take on our articles) things from 'apostrophe for use at http://petesqbsite.com for the limited purpose of creating qbe articles, or for hosting copies of 'apostrophe at http://petesqbsite.com. be my guest, maybe i can even get someone i know to do this part for pete's sake.

  3. ignore us completely. when pete told me that we never update the rest of the community about what's happening here, i explained that for one, i don't think we're doing anything that anyone in the rest of the community really cares about. (imo.) we're not a development forum, we're mainly a help forum. some of us work on small projects of our own, but generally we're making demos and tutorials when others are making first person shooters in fb. etc. obviously, there are other help forums, too... and pete's is one. we tend to focus on it nearly to the absence of other topics, which we sort into... anyway, you've seen our forum.

there have been exceptions, of course. mac used to say the one exception was v'ger, a next-to-impossible ascii game whose code is so out of control that it may one day send cyborgs back in time to kill us.

lately there have been many other exceptions, and in the event that someone outside the forum is interested, i will attempt to tell you all you need or could want to know.

in regards to mark wilhelm's forum, while i consider our forum at network54 (the same forum that mallard put here for qbasic.com) to be "the qbasic forum", mark wilhelm decided he didn't like it, so he made... that. this is my own opinion, not shared by everyone on our forum, to be certain - but to me, we were and are the forum, not the "Classic Forum", and surely not the "old" forum. if someone wants to report on the news there, that is certainly their option. i don't as a habit go there, and i certainly don't post there. on the other hand, mark never comes here, either- but their news is "not my problem."

that said, i'll be doing my personal best to report our news (even news about myself) here with a professional "bias" or none at all. it certainly isn't possible for anyone to be bias-free, but then again - it is more than just possible to try. my opinions here will be announced as opinions, and hopefully the lesser of all features on the page.

'apostrophe will not be a monthly publication. it will be added to as often and inoften as i see fit. the latest news will appear at the top, with a dated heading- and older news, it would follow, (quite literally) that it be lower down on the page.

as you can see, i have made myself editor. i figured it was me, michael, or matthew - though there are other regulars that might care about this more than i do. both mentioned have websites of their own, and if one of them wants to take this project off my hands, i would be happy to link to them and step aside.

hopefully that takes care of any questions you have for now- we now return you to the news, which is already... in progress...

- mennonite

= kriegspiel referee =

trying his hand with an old development trick he worked at ibm, mac (yes, ibm-mac, har har) has led a handful of us into a chess project called "kriegspiel referee".

while we aren't interested at the moment in an ai that can play against the user, we are in the process of creating a computer chess game where two human players play chess against each other... without seeing his opponent.

because i enjoy the feeling of the wind in my hair, and because half of it goes right over my head, i will simply post a bit of what mac was trying to say about it, in his native danish tongue:

"For example in regular chess, assume that all opponent pieces are gone except for the King and you have a King and protected Pawn. If you are a good players, you know that if the opponent King is ahead of you, you can never promote (the opponent keeps moving to your side of the pawn). It is an agreed draw or else stalemate."

But in Kriegspiel, it is a win. You simply toss a coin and move to a random side. The opponent, sooner or later, moves to the wrong side and you advance!

On the other hand, in regular chess, if you are good players, you know that an end game of King-Knight-Bishop versus a King is a win. But in Kriegspiel, it is an obvious draw.

There is a third person involved: a Referee. This person keeps a third board with all pieces accurately placed. If it is White to move, White attempts to move and the Referee announces "not possible" until a legal move is made. Black hears this exchange and can sometimes guess what is going on. To avoid tricks, if White tries something like taking a White piece or moving a Pawn backwards, the Referee says "illegal move" so no bad data is transferred."

he then begins to outline our mission as coders, should we choose to accept it:

"The basic sequence is to identify a component of the system, such as LegalMove and develop a driver and simulation. Debug that first.

Then, in parallel without needing to communicate, the developer of LegalMove substitutes code for the simulation and the developer of the main display uses the simulation.

When both work perfectly, they are simply put in the same module and the program magically works.


But you can't modify the driver or the simulation. They MUST be used as-is or integration will fail."

when i needed clarification, pete wrote a qb program to help break the language barrier. below is a screenshot: (it reminds me a lot of the danish translator i made a while ago...)


i can't say i've kept up with the project as much as i should have, but i know the board works and the logic "driver" (if i have half an idea what it is) is being worked on extensively by some of our best and brightest. the last time i saw the board, it looked like this:


yes, that's a cursor on row 2. we have a thing about ascii. we do graphics too, but i love ascii as much as anyone.

i personally denied myself a handful of opportunities for a full belly and an empty bladder to work on the intro screen. i did the layout yesterday or the day before (i don't really think in terms of "days", more like "uptime"...) and today i wrote the overly-functional menu code to run on top of it:


anyway, i'm very pleased. i can't wait to see more of this project complete, even less to figure out wtf it is!

= computerghost's parents completely suck =

we won't be seeing much of computerghost for a while, his college grades are not completely up. mind you, cg is studying computers - good choice. his parents' answer to a round of bad grades?

show him what it's like now if he fails later.

instead of helping him in a more traditional fashion, cg's parents have decided the best course of action would be to do everything in their power to prevent his access to computers over the next year. obviously, he will need them in school to do his work, at home this simply won't be an option. this might not be so damning if cg lived at school- alas, he doesn't.

this might be the daftest thing i've heard in the course of my life, so to cg's parent's: a big "f-u" to the craziest effing morons i've ever heard of from the editor of 'apostrophe. you're both touched in the head.

i have hope- who knows? maybe they'll get brain transplants. we miss him terribly and hope to have him back soon.


= mennonite's pretty good intro to qbasic =

i've been talking about this forever, so instead of just talking, i finally put it online. the thing is, it's been almost done for months, and i decided to just finished my work on chapter 4 and get on with it.

each chapter is a qbasic program. to view the tutorial, you run the program for the chapter you want in either the qbasic interpreter, or the quickbasic compiler. the rest of the chapters, 5 through 21, are still in the plaintext (included.) this is what the website means when it refers to "finished" vs. "unfinished", despite the fact that all 21 chapters are already available in one form or the other.

this is a very large tutorial i designed to replace an actual high-school level intro to programming class, and the plaintext of the tutorial as a whole would be about 70kb, roughly 1/5 to 1/4 the size of a plaintext copy of "the great gatsby". the project has already received mixed opinions from those i've shown it to, but i'm certainly very proud of it all the same. i intend to use it to teach qbasic to anyone i know who is interested in learning, and personally recommend it to anyone who is starting out, whether i knew them or not.


the download page is located on this site, click here if you would like to know more.


= matthew's qbasic.com fundraiser =

by matthew

I have wanted to start fundraising to purchase QBasic.com from the first day Mark acquired it. I have finally gotten off my ass and done it. You can visit the fundraiser page here. I think I can do a better job at administering qbasic.com than mark can. The main features of the new site will be:

1) The Net54 forum will be the main forum(mark's forum at qbasic.plutokiss.com will remain linked to)

2) The site will be VERY open to suggestions

3) There will be a wiki installed somewhere so users can create/edit QB-related content in a section seperate from the main site

4) It won't look like dog diarrhea like the current site

5) I won't be mad with power when I acqure it :+)

I plan to make this a site for QB programmers, by QB programmers. This means I will not be greedy and not keep the site my own and only my own. The site will be very open to suggestions, and will include a wiki so people can create and edit content (in a seperate area of the main site) as they see fit. I will not leave FreeBASIC out of the site, although I won't focus on it either. I won't use a crappy content-management script (the only known non-commercial example of a good content-management-based site is Pete's QB site, so I don't want to take chances with making a shittier site than mark's.) The forum will be the net54 forum, like it used to be before mark threw it aside like it doesn't matter to anyone. I honestly think I can do a better job at it than mark could ever do.

If you are interested in donating, visit my fundraiser page, read it, and click the "paypal donate" button at the bottom.


= other announcements =

from the programs you are proud of subforum:

computerghost - simple ascii space game (version 1.1)

solitaire - happy new year - times square program

kewbie - simple "mark-up type" text formatter - tformat.bas

until the next edition, happy coding :)

[2006 jan 02 issue 1]

Visit mennonite's site or The QBasic Forum.

Cadisman Game Review

A review by Stéphane Richard (Mystikshadows)


ON January 9th, inded005 announce, in this post on the FreeBasic.net forum, that he converted an old QB game to FreeBasic. The game is called Cadisman and after taking a peek at it in the provided link, I decided this was most definitaly game review material. I downloaded the game and started playing it to get a feel of what the game is all about and well, let's just say this review was supposed to be done earlier than this. I got caught in that game just a bit longer than I planned.

As usual, I will begin this review by talking a bit about the game and finish with the gaem review itself. So then, let's get right to it shall we?


CAdisman is a graphical RPG game and as such offers all the features one would expect of this category of game. It has a very decent user interface an isn't all that hard to get into the game, even without instructions, and start finding your way around the many locations and levels. Just to give you a bit of a preview, here are some screenshots taken from the website.

As you can see from this first screenshot right here, this game features one of the most detailed player profile I've seen in a game. There's a lot of different characteristics of your player that changes as you gain experience, fight battles and the likes.

This second screenshot features the very convincing tile graphics that make up the game. I particularly like the many textures used in the game and the color selection is realistic.

This last screenshot is yet another example of the tile worksmanship. Even at this small size, inded005 really managed to bring some excellent artwork to the game.

There are more graphics in the game as well, I'll let you play this game yourself so you can see them all as you make your way through the game. And now, for the review. As always, I will review the game based on playability, overall entertainment, replay value and technical feature.

PLAYABILITY: Score (4/5)

As I've said before, when you start the game, everything is quite self explanatory, the game is essentially played with the mouse an the keyboard and as such, all the features of the game are readily available for you to use. A very intuitively designed icon menu on the right gives access to such things as the player's profile, inventory items and the likes in a very well presented fashion. As such I gave it a score of 4 out of 5.


AS far as entertainement is concerned The game is quite entertaining, it features atleast a minimal enemy A.I. system based on the classic turn based attack system. All in all, it brings the entertainement expected from this kind of game. I do wonder however if perhaps inded005, now that the game is ported to FB, wouldn't be able to work with new gaming A.I. systems that might bring Cadisman up yet another notch. All in all, it is a pretty good game so a 4 our 5 is very well warranted.

REPLAY VALUE: Score (3/5)

Again, Cadisman being an RPG, if you like RPG games you know the replay value of such a game. Since I haven't completed the game, I do not know if the game can have aternate endings (other than either you succeed or you die). But hey, even that's already 2 possible endings right there. I do believe however that the game has a good enough replay value to come back to it and finish it no matter how long it takes in my opinion. For that reason, I gave it a replay value of 3 out of 5.


By technical features I mean the amount of technology used to create the game. Although the game doesn't seem to have sound (I don't have a sound card at the moment but I haven't noticed any sound files) nor does it support Open GL or Direct-X you can tell that alot of efforts have been made to bring the best gaming experience to the player with the technology that were used. Aside perhaps the characters of the game being a bit bigger, the game doesn't suffer in playability regardless of the technology that was used to create it. For that reason, a 3 out of 5 is definitaly the score I give this category of review.

THE FINAL VERDICT: 14/20 (70%)

While playing the game for the little time I have played it, I found no big issue with it, everything seemed to be running quite smoothly and I came across no errors or complications. Just that is already a big thing in my book. It seems to be a very stable game and from the little i've seen, seems to be a very addictive RPG. I just can't imagine any RPG lover out there not liking Cadisman. And for that, the score of 70% is more than well deserved. I hope that inded005 can add many new adventures and twists to what seems to be an already complete adventure. A sequel would be a very good idea in my book as well.

For those of you who want to give Cadisman a try, you can get it right here, if you like RPG games, you won't regret downloading this one.

Stéphane Richard

NPC Bad Guys in the New Age

Written by Nekrophidius

In times past, roleplaying games have almost always had good character development (I use the word "good", not "excellent"). The main character has always been portrayed in the best possible way by the storyteller. However, the "enemy", or "villian", has not been. This article is all about making that bad guy of yours just as important as the hero in your roleplaying game's story.

Gone are the days of "anonymous evil wizard kidnaps princess". Nowadays, players want to completely immerse themselves in the personalities of all the characters of a game. And for the most part, designers are certainly fufilling the needs. But what about on the other side? Why is there less attention payed to the one element which fuels the storyline to begin with: the antagonist?

Okay, so maybe you're reading this and wondering "why should the bad guy have his name in lights?". Villians, by their nature, are designed to be expendable. However, a well-designed villian will keep its purpose for a long time. Like so many things in the rpg storyline, the villian is a valuable tool. It's the fault of the villian that the world is gone crazy, or that the next city from here is on fire. What's going on?

The most effective way to begin the creation of your villian is to actually identify him or her. And I don't just mean "he's an evil wizard hell bent on ruling the world!". Well, maybe he is. Why? Did he get picked on in high school, and now he wants revenge against his torturers? Maybe he got stood up for the prom or something. In any event, there must be a reason for his mission. After all, the "good guy" has a reason for HIS mission, why doesn't the bad guy?

Okay, let's assume your all-powerful evil wizard has a hatred for fluffy bunnies. Let's say the main character loves fluffy bunnies and wants to protect them all. So, now there's a purpose for the evil wizard's "madness". It may be silly, but it's more than 99% of the bad guys out there. Why does he hate fluffy bunnies? Hrm. Maybe he got bitten by one as a child and grew to hate them. Maybe he thinks fluffy ones are ugly, preferring the shaved ones (so maybe he's going around shaving all the fluffy bunnies). Maybe in his quest to rid the world of fluffy bunnies, he runs into something which likes the fluffy bunnies and tries to help them out. Now, the evil wizard guy has another enemy! So now he's going to hate whatever it is that helps the bunnies (maybe...two- tailed deer? Okay, works for me). So now, we've got an evil wizard who hates fluffy bunnies and two-tailed deer. Now we're getting somewhere, our bad guy has a purpose in life, which is to hunt down fluffy bunnies and two-tailed deer.

Is the evil wizard going to torch an entire town because of his hatred for fluffy bunnies? Probably not, unless it was populated by fluffy bunnies (or environmentalists, take your pick). As insane as people get, there are just certain things that do not make sense. The bad guy's actions should reflect his motivation. No action should be "just coz he's evil", that's dull. He should go around putting fluffy bunny's heads on pikes, kinda like shown in the ending of DOOM. Now that's true evil (and a fitting representation of his hatred for fluffy bunnies).

Now, how does the main character even find out about the bad guy's mission? Does he read it in the latest issue of "Villian Digest"? Probably not. Perhaps the hero had a bunny, and the evil wizard guy took his bunny away, so now the hero's pissed. Or maybe the hero's girlfriend has a bunny that was taken. Whatever the case is, the hero has to be informed of the bad guy's actions somehow. After all, this is what sets him out on his journey to begin with. Make it believable...and sensible!

So, we've established that the bad guy hates bunnies. Okay. So now, what does the bad guy LIKE? I hear dozens of groans right about now, with the same thing: "oh man, who cares? it's the bad guy, who gives a rat about what kind of person he is". Wrong! The player cares! Does the villian like music? What kind? How about flowers? Sure, it seems crazy for the bad guy to like flowers, doesn't it? But it isn't crazy. I mean after all, everyone has likes and dislikes. Maybe the bad guy likes this one flower which grows only by this one certain pond. Hell, maybe the bad guy likes spending time by the pond in the evening, watching the sun set in the presence of his favourite flower. I'll make a case in point here...if you've played "Lunar Silver Star Story" on the Playstation console, the main villian, Ghaleon, had a love for music, and even played a musical instrument.

Well then, another set of details come to mind here. Where does the bad guy live? Sure, you can be cliche and say "a big castle atop of a mountain with a skull carved into the side!". ****snore**** been there, done that, got the t-shirt. Okay, so maybe you really do want a castle for the bad guy. How'd he get it? Did he just magically make it appear out of nowhere? Wouldn't the locals get kinda pissed about that? Even in rpgs, there are laws! I'd have to say that making a castle just sit down anywhere has got to be against someone's laws. So, how did he get it? Maybe he inherited it. Maybe he paid for it himself. If so, how'd he get the money? What does he do for work? Is he only a bad guy during his time off from his job? If he doesn't work anymore, did he get fired for his obsession with bunnies? Maybe he missed too many days of work chasing down the critters, got fired, and now he's really mad. "Damn bunnies are ruining my life! They must PAY!" So now, he's in danger of losing his castle, since he has no income and can't pay the taxes or whatever. Okay, mad killing spree! Not. How is a mad killing spree going to help things? Think about it. Well, maybe if he finds enough fluffy bunnies, he can just sell their fur or something. Just to make some money to keep his pad, while at the same time, ridding the world of these "gruesome furry monsters". Although the thought of the bad guy just going postal is kinda cool, it's an overused cliche that should be avoided unless absolutely necessary.

I think by now you're beginning to understand the importance of the bad guy's character development. But there's just a few more things I'd like to cover before I call this a wrap. First of all, we've established that our bad guy is a big evil wizard. Now, how did he become a wizard anyways? Did he go to school for it? Who were his teachers? What do they think of him now that he's a big bad bunny slayer? Do they look at his yearbook picture and shake their head in disbelief? And what about his parents? Maybe his parents sent him to magic school as a punishment for his arsonistic obsessions. Yes, antagonists can have more than one obsession, in fact, the more the merrier. Well, now the evil wizard is all powerful, and comes back to punish his ungrateful parents for their "cruel treatment". And while he's at it...he eats their bunnies.

Second of all, eventually the bad guy and the good guy are going to cross paths, you can't avoid this. Let's say the good guy is travelling with a cute chick. The bad guy sees her and falls in love with her. He forgets his obsession with bunny murder and relentlessly pursues the good girl. Well, now we've reached a dilemna...is he still a bad guy? C'mon, bad guys are sposed to be BAD! They aren't supposed to have emotions! Right? Right? Wrong. It's no mystery that opposites attract. And what if the good girl suddenly develops a crush on the bad guy? What if the bad guy has no interest in her? hrm...imagine the problems that can arise in this situation. And right there, you've got a vehicle for creating a storyline within a storyline. Now, what happens if the bad guy and the good girl both fall in love with each other, and the good girl betrays the hero? Is the former good girl suddenly a menacing legion of doom? Maybe, maybe not, that's up to you to decide. BUT! It doesn't have to be that way. Most people just automatically assume that just because the good girl has gone astray that she's now evil too. Bad assumption. Downright evil, even.

The final consideration is the end of the villian. Does the villian die in the end? Usually. But does this have to happen? I mean after all, all we're trying to do is stop him from doing what he's doing. What if we were to convert him? Make him see the error of his ways? Let him know that his bunny murder is breaking the hearts of hot sexy women everywhere? Okay, maybe he repents. Now, the hero puts a knife in his head. HAHAHA! Now who's the bad guy, biatch! *cough* Anyways...consider the end of the story. If you deem that the antagonist must die, it must be for a very good reason. And again, don't fall back on "coz he's evil". After all, killing in itself is a necessary evil, and makes the hero no more a good guy than the bad guy. But once you balance the WHY, you'll know what you have to do to end the story. But consider this one final point. There is no better way to vanquish an enemy than to make him an ally. You'll avoid that one final killing and you'll accomplish your goal all at once. Of course, at the same time, nothing beats a good bloodbath of a final battle, good versus evil!

If you've absorbed even half of what I've outlayed here today, you're off to a good start at developing excellent villians. If you're one of those AD&D players (as many RPG developers are...or were), I recommend reading Kirk Botula's excellent "Complete Book Of Villians" (ISBN 1-56076-837-1), as it goes into much more detail of the concepts I've covered here. Just say NO! to cliche bad guys!

"Virtue untested is innocence." -Anonymous

Download a copy of this article: npc_bad_guys.txt

SmithcoSoft Map Editor Preview

Written by SmithcoSoft Creations 2002-2005


SmithcoSoft MapEd is being designed for the use of map creation for RPG games. Specifically it is being designed for a SmithcoSoft Creations upcoming RPG, which will not be announced at this time. The Editor has many useful features including many that most map editors do not have. The editor is being developed using SDL but can be used to make maps for any 2D engine, as the files saved are simple data. Though it is not yet complete it is nearing completion, and a demo or full versions should become available soon.


Standard Map Functions

Layer System

Graphics Loading


Character Editor (yet to be added)

Animation editor (Yet to be added)

Menu System



The following pictures will briefly show some of the features of the editor, just keep in mind these are placeholder graphics =)

This is the default load of the MapEd

This is the fill screen option before and after

This is showing the base layer with a small scene I created to show how it looks while creating the maps.

Same view as above with the mini map turned on

This is the object layer overlaid on the base layer (note the background of the tree is transparent)

This is the fringe layer overlaid on the object and fringe layers

This is the main menu

This is before and after of a saved map (note uses custom text handling for text input)

Here are just a few of the scripting menus

And finally here is how the triggers will appear on the map


There are other features I have not listed here today, but what I have listed is being developed now.

Also I am looking for a good artist for my upcoming game which uses a slightly altered version of the MapEd engine which gives a smooth pixelxpixel scroll using SDL, and the many other game effects I am and already have developed. I am willing to work with the artist on sizes and styles. The story for the game is more or less complete and the engine is almost ready to go, just as soon as the map editor is finished. If anyone is at all interested let me know, and i'll fill you in on the details. Questions are welcome as well.

Email me at smithcosoft@yahoo.com

AIM me at smithcosoft

or just PM me at http://forum.qbasicnews.com

Monthly Awards

Written by Pete

Every month, QB Express hands out two awards to recognize QB or FB coders and websites that have done exceptional 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. We will bring you these awards on a monthly basis to help give credit where credit is due.

Site of the Month

QB Top 50

Webmaster: AhmedF

Way back in Issue #5 of QB Express, I wrote up a Blast From The Past article on the history of QB Top Sites lists and their influence on the QB community. I trumpeted the importance of QB top sites lists, because back in the golden age of QB on the Internet (ie: 1998), they brought the Qmunity together. Here's a snippet from that Blast From The Past article:

Back in QB's earlier days on the web, there were literally hundreds of QB sites all over the place, and it was pretty much impossible to keep track of them all. The best method anybody found were the anarchic top sites pages where webmasters could automatically add and promote their sites (without going through a middleman webmaster). Top sites pages like the original QBasic / QuickBasic Top 50 were extremely important to the QB community for sharing and promoting sites that would have otherwise been hidden away in the dark corners of the world wide web, never to be visited.

When AhmedF re-launched the QB Top 50, I was very excited. It's been years since there was a legitimate QB top sites list (the QB RPG Top 50 was devoted to only RPG sites, easily spammable and full of broken links). And for the first time in history, AhmedF has set up a fair and difficult-to-cheat top sites script that rates based solely on unique hits to your website. Judging by its success in just the first few weeks of existence, the QB Top 50 will become another new central hub for the Qmunity.

For its great design and potential to bring the far corners of the Qmunity closer together, the QB Top 50 is the QB Express site of the month!

Programmer of the Month

(Mario Zechner)

Up in the News Briefs section, marzec announced his new library YAGL - Yet Another Game Library, but judging by its humble title and the humble way he pitched it, you would never guessed that this library is absolutely genius. In just a month, YAGL has repeatedly wowed the FB community with its "blazingly fast" speed and features. Several people have released demos taking advantage of YAGL, and they are extremely impressive. Z!re has released several graphics demos AND switched her sprawling RPG, Fieldview to YAGL. Nekrophidius has gotten behind YAGL big time, and is promoting it all over the place and developing in it himself. He even made this banner ad to help promote YAGL:

After you check out the YAGL Official Site, check out this Freebasic.net post where marzec originally announced the library and he posted his early dev log. And then -- most importantly -- check out this page which features several awesome projects created in YAGL. Here are a few of the cooler ones:

Three of these screenshots are from graphics demos by Z!re, and the fourth is from the mini game Asteroids 3D which was coded for a 48h challenge. You can check out all of these programs at the YAGL Projects page.

For making such an awesome graphics / game library, marzec is unquestionably the QB Express programmer of the month!

Have a suggestion for Programmer / Site of the Month? Email me!


By Rattrapmax6

Rattrapmax6 is back this month with another QBasic Horse Humor comic!

QBasic Horse Humor

Tree Tutorial, Parts 1 & 2

Written by Syn9


This tutorial is designed for someone with a small background in 3d matrix math and preferably with experience dealing with child-parent relationships within objects. A good example of this type of relationship would be skeletal systems.

There are 6 parts covering everything from setting up the software 3d development scene to displaying our final tree in an OpenGL scene. We'll be covering Parts 1 and 2 in this issue.

Part 1: 'Base Code'

In order to properly see all the branches we must setup a 3d scene that we can change our viewing angle of. We'll also be able to Zoom in & out of the scene to aid in viewing the entire tree.

The following code will establish a software 3d environment showing a pixel grid floor. This grid consists of points on the X and Z axis with a 0 y coordinate. We will be constructing our tree to stick out of this floor by moving + on the y axis.


DECLARE SUB getXY (x0!, y0!, z0!, sx%, sy%)
DECLARE SUB mRotate (an!, plane%)
DECLARE SUB mIdentity ()
declare sub mScale (factor!)

randomize timer

const xplane = 0, yplane = 1, zplane = 2

DIM SHARED apage, bpage, zback, rad as single
DIM SHARED matrix(8) AS SINGLE, tempmatrix(2, 8) AS SINGLE

screen 13,,2

apage = 0
bpage = 1
rad = 3.141592 / 180
zback = 30
matrixScale! = .8
xan! = -20
rotSpd! = .05
scaleSpd! = .001


    swap apage, bpage
    screenset apage, bpage

    mRotate yan!, yplane
    mRotate xan!, xplane
    mScale matrixScale!
    FOR x! = -10 TO 10 STEP 2
        FOR z! = -10 TO 10 STEP 2
            getXY x!, 0, z!, sx, sy
            PSET (sx, sy), 7

    if multikey(&h1) then exit do
    if multikey(&h48) then xan! = xan! + rotSpd!
    if multikey(&h50) then xan! = xan! - rotSpd!
    if multikey(&h4b) then yan! = yan! - rotSpd!
    if multikey(&h4d) then yan! = yan! + rotSpd!
    if multikey(&h4e) then matrixScale! = matrixScale! + scaleSpd!
    if multikey(&h4a) then matrixScale! = matrixScale! - scaleSpd!
    while inkey$ <> "": wend


SUB getXY (x0!, y0!, z0!, sx, sy)

  nx! = x0! * matrix(0) + y0! * matrix(3) + z0! * matrix(6)
  ny! = x0! * matrix(1) + y0! * matrix(4) + z0! * matrix(7)
  nz! = x0! * matrix(2) + y0! * matrix(5) + z0! * matrix(8) - zback

  IF nz! = 0 THEN nz! = -.1
  sx = 160 + nx! / nz! * 256
  sy = 150 + ny! / nz! * 256


SUB mIdentity

  for i = 0 to 8
    matrix(i) = 0

  matrix(0) = 1
  matrix(4) = 1
  matrix(8) = 1


SUB mMult
  FOR i = 0 TO 8
    tempmatrix(0, i) = matrix(i)

  FOR y = 0 TO 2
    FOR x = 0 TO 2
      v! = 0
      FOR a = 0 TO 2
        i1 = y * 3 + a
        i2 = a * 3 + x
        v! = v! + tempmatrix(0, i1) * tempmatrix(1, i2)
      i3 = y * 3 + x
      matrix(i3) = v!


SUB mRotate (an!, plane)

    CASE xplane
      tempmatrix(1, 0) = 1
      tempmatrix(1, 1) = 0
      tempmatrix(1, 2) = 0
      tempmatrix(1, 3) = 0
      tempmatrix(1, 4) = COS(rad * an!)
      tempmatrix(1, 5) = -SIN(rad * an!)
      tempmatrix(1, 6) = 0
      tempmatrix(1, 7) = SIN(rad * an!)
      tempmatrix(1, 8) = COS(rad * an!)
    CASE yplane
      tempmatrix(1, 0) = COS(rad * an!)
      tempmatrix(1, 1) = 0
      tempmatrix(1, 2) = SIN(rad * an!)
      tempmatrix(1, 3) = 0
      tempmatrix(1, 4) = 1
      tempmatrix(1, 5) = 0
      tempmatrix(1, 6) = -SIN(rad * an!)
      tempmatrix(1, 7) = 0
      tempmatrix(1, 8) = COS(rad * an!)
    CASE zplane
      tempmatrix(1, 0) = COS(rad * an!)
      tempmatrix(1, 1) = SIN(rad * an!)
      tempmatrix(1, 2) = 0
      tempmatrix(1, 3) = -SIN(rad * an!)
      tempmatrix(1, 4) = COS(rad * an!)
      tempmatrix(1, 5) = 0
      tempmatrix(1, 6) = 0
      tempmatrix(1, 7) = 0
      tempmatrix(1, 8) = 1


sub mScale (factor!)
    for i = 0 to 8
        matrix(i) = matrix(i) * factor!
end sub

I will only provide a simple explanation on the functions of this code that will directly affect our progress later

    mRotate yan!, yplane
    mRotate xan!, xplane
    mScale matrixScale!

These commands will setup our matrix to properly convert 3d coordinates to our rotated and scaled view

    getXY x!, 0, z!, sx, sy
    PSET (sx, sy), 7

getXY will multiply our 3d coordinate by our matrix and spit out a screen coordinate which Pset draws

    if multikey(&h1) then exit do
    if multikey(&h48) then xan! = xan! + rotSpd!
    if multikey(&h50) then xan! = xan! - rotSpd!
    if multikey(&h4b) then yan! = yan! - rotSpd!
    if multikey(&h4d) then yan! = yan! + rotSpd!
    if multikey(&h4e) then matrixScale! = matrixScale! + scaleSpd!
    if multikey(&h4a) then matrixScale! = matrixScale! - scaleSpd!

    while inkey$ <> "": wend

We will be using multikey extensively since it provides a much faster response time than inkey$. the last line clears the keyboard buffer so that on our next cycle we detect only new keys that were pressed for that cycle.

I wont be explaining how the 3d math functions work to save writing, but if at the current time you do not understand the theory behind 3d matrix math I highly recommend doing some research on the subject. Rel has written some awesome tutorials that you can find here http://rel.betterwebber.com/junk.php?id=21

Part 2: 'Planning'


The Idea is to have a branch made up of several segments. At any of the segments a new branch can be attached. The further you get away from the base of the branch the smaller the diameter of the branch and length of each segment become. Also, the base of a branch will start out at the diameter of the point that it is connected to. Lastly, since we don't want a really long branch to have a base at a point toward the end of a branch, we'll limit the number segments that a branch can have based on what segment its base is connected to


The leaves are made up of flat squares that are displayed over the branches. The center of each plane is positioned around a random joint on a random branch. The plane will be placed at a point that is > 1/2 along the branches to ensure that the leaves are in the upper part of the tree and not on the trunk. Next, the plane is rotated opposite the direction of the object and camera in order to make them constantly face forward. Then once the engine is displaying the tree in openGL, the leaves will be z-sorted and blended together.

I hope I didn't lose anyone. Just incase, here is a picture to hopefully give a good visual representation.

End Product:

For the final mesh, we will make a 'skin' around the branch skeleton by finding points that are perpendicular to each segment connection, then draw a cylinder connecting each segment. At the base, instead of a cylinder we'll have the 1st segment's cylinder come to a point to make a cone. These cones will be stuck into the parent branch segment base point. In order to make the polygons display properly in openGL we'll also generate UV coordinates and Normal vectors for each vertex.

Download a copy of this tutorial: treetutorialpt1-2.zip

Dynamic Arrays Inside a Type

Written by Deleter

Amazingly enough, I finally figured something out so that I can write something other than a rant! In this somewhat off color tutorial by one of the qmunities more random individuals, I explore a somewhat interesting and highly useful technique for making a dynamic sized array inside a type.

This requires more doing than a normal array since you cannot use redim on a type, it just doesn’t work.

For this tutorial, you are going to have to understand pointers, if you don’t you can still follow along, but it might not make sense.

To start us off, lets make our own user defined type. (UDT):

type MyType
	x as byte ptr
end type

Ok, now that we have a type, we have to declare a variable with it:

dim as MyType myVar

Now, we want to create an array for usage later on in the program. This introduces the callocate command. For those not familiar, callocate allocates a number of bytes and erases them (allocate simply allocates them). Creation is done as follows:

myVar.x = callocate(bytes)

Callocate creates an area of memory of size bytes and then hands the address over to our pointer. Now, to use this array, we can access it in the following way:


Ok, that’s all!

No? More you say? Alright, let's go!

The above example was great, assuming you only want an array declared once and wanted only byte elements, we can do a heck of a lot more than this, so lets do it.

Let's say we allocate the array, but then realize later on we need more space. This can easy be done with the reallocate command:

myVar.x = reallocate(myVar.x, newBytes)

In this, we remake the array so that it now contains an amount newBytes of, erm, new bytes. Luckily for us, v1ctor has made the command as easy as possible, so the old contents are not erased and your data is safe when resizing the array (that is assuming your new size is the same or bigger size).

Once we are done with the array, use the deallocate command to free up the memory. It is done automatically and the end of the program, but its better practice to do it manually so you don’t end up with memory leaks:


Now we can make, resize, and delete our array, but how do we make one whose elements are bigger than a byte? Lets do this with integers first. An integer in freebasic consists of four bytes put together. Therefore for each element of our array, we need four bytes instead of one. To start us off, we need to change our UDT so that it is an integer pointer instead:

type MyType
	x as integer ptr
end type

Now, when we create it, we have to replace the implied * 1 with a *4:

myVar.x = callocate(elements * 4)

Where elements is the amount of elements we want in our new array. Likewise, to resize our array, we have to also use a * 4:

myVar.x = reallocate( myVar.x, newElements * 4)

Where newElements is the amount of total elements we wish to have. To access it, luckily we do not have to worry about bytes thanks to the fact we are dealing with an integer pointer. This automatically splits the memory up for us for access. So, access to the first, second, and third array elements would be as follows:


Now that we have the basics of allocating and reallocating based on a known bytesize, its time to figure out how based on an unknown size. For this, the command sizeof( type ) is used. If you two haven’t met, sizeof, programmer; programmer, sizeof. Ok, here is the usage of sizeof:

print sizeof(integer)

As you will see if you run this program, you will get the number 4. That is because sizeof returns the number of bytes a type needs. To apply this to our earlier code, we can do the following:

myVar.x = callocate(elements * sizeof(type) )

Where elements is the amout of elements you want for your array type. As you may have caught on, guessed, or otherwise figured out, this can be extended to UDT’s for some really sweet applications. Example:

‘create a type for usage in another type
type MySubType 
	x as integer
	y as integer
end type

‘create a type for “owning” another type
type MyMasterType 
	mySub as MySubType ptr
end type

‘make a variable of the “owning” type
dim as MyMasterType myVar 

‘used to define number of elements, not necessary, used for clarity
dim as integer elements 

‘set for amount of elements you want in array
elements = 10 

’allocate the memory
myVar.mySub = callocate( elements * sizeof(MySubType) )
‘first array element
myVar.mySub[0].x = 21 
myVar.mySub[0].y = 2

‘... other elements can be referenced here...

‘last array element
myVar.mySub[9].x = 84 
myVar.mySub[9].y = 12

‘add one to number of elements
elements +=1 

‘resize array to include new element
myVar.mySub = reallocate( myVar.mySub, elements * sizeof( MySubType ) )

‘check and see that old values have not been erased
print myVar.mySub[0].x; myVar.mySub[0].y
print myVar.mySub[9].x; myVar.mySub[9].y

‘new array element
myVar.mySub[10].x = (42 or 7)
myVar.mySub[10].y = 3

‘show new array elements
print myVar.mySub[10].x; myVar.mySub[10].y

‘free up the memory, we are done with it


This example contains all the ideas presented in this tutorial, so if it seems overwhelming at first, go from the top and go step by step, I commented everything so that you can understand it better.

That is all for now. With this knowledge, go forth and use memory with confidence, it’s a powerful tool. Thanks for reading.


Download a copy of this tutorial: Dynamic_Arrays_Tutorial.doc

Music Tutorial Part 1

Written by The Awakened

I needed a break from C++ tutorials, so I figured I'd write about something I'm a little more proficient with: music. The method I'm going to teach you isn't exactly "standard", but it definately gets you on track as soon as possible. I know many people might want to use a tracker or sequencer, but don't know much about music theory and whatnot. Hopefully, I can help you out.

I highly recommend learning an instrument, and guitar and piano are among the more "all-encompassing" instruments, meaning that most of the stuff taught here can be applied to either of those instruments.

For the theory that I teach, I'm not exactly a conservatory student, although I know quite a bit. I'm not 100% on the staff and "official names" for certain things, but when it comes to scales and chords (which, in my opinion, is where it really counts), I'm fairly proficient. I've met people in my school who've been playing piano for a few years longer than I have at guitar (they've been taught by the Conservatory, and I'm pretty much self taught), and I ask something like "what's the relative mixolydian of G?", and they immediately go cry in a corner. Something that might take me 10 or 15 seconds to figure out, and they have no idea.

Anyway, enough of me speaking highly of myself. ;) Let's get going.

1. Notes

In western music, we have 12 notes. They are:

A, A#/Bb, B, C, C#/Db, D, D#/Eb, E, F, F#/Gb, G, G#/Ab. Then it repeats. A, A#/Bb...

# means "sharp", b means "flat". Notice the ones with flat and sharp signs. They're the same note, but you can refer to them in two different ways. A# and Bb are the same note. Also notice that some notes don't have flats and sharps. B doesn't have a sharp, and C doesn't have a flat. Same with E and F.

Now, most contemporary music doesn't use all these notes in one melody. Instead, we use patterns of notes called scales. The most common scale is the major scale. Starting with C, it looks like this:

C, D, E, F, G, A, B (and repeat)

Wow. That's cool. Compare it to the 12 notes above, and you'll see there's a pattern. It starts on C, then it goes up in different "intervals." When it jumps by two notes, (like say, A to B), it's called a "whole step." If it's only one note (for example, A to A#), then it's called a "half step." The intervals of the major scale are as follows:

Whole step, whole step, half step, whole step, whole step, whole step, half step.

The half steps are in between E and F, and B and C. That's why it's easiest to remember the C major scale, since the half steps and whole steps are already built into the western 12 note system.

2. Keys

When someone refers to the "key" of the music, they're referring to what the main note that the song uses and keeps "returning to", and what scale is being used. As we saw above, the most basic scale is the major scale, and the simplest key to have the major scale in is C (simply because there's no sharps or flats to deal with). But having many different songs in the same key gets boring. Let's look at the major scale in a few different keys. Remember, we use the whole-whole-half-etc pattern.

In E:

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

In A#:

A#, C, D, D#, F, G, A

Try figuring out a couple more for yourself.

Easy enough? Good.

3. Diatonic Scales

A diatonic scale is a seven note scale. The most common is the major scale. Scales are notated as follows. Let's take the C major scale:

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

1, 2, 3, 4, 5, 6, 7

1 is your root, 2 is the second, 3 is third, etc. So C is the root, D is the second, E is the third, and so on.

Now, the major scale is your all out, super happy, bouncy bubbly scale. But how about some other patterns of notes? How about some more scales?

If you're thinking "oh crap, he's gonna give me some more long patterns to memorize!!!", then calm down. Let's look at the C major scale again.

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

What if I kept that pattern, but I started on a different note of the seven note scale?

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

Ooh! Sounds interesting, kinda rockin'. How about another one?

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

Hmm... kind of mysterious... interesting, could make some pretty heavy riffs.

It doesn't have to be done on the C major scale (duh), you can do it to other keys as well.

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

can become

F#, G#, A, B, C#, D#, E (I just shifted up by one note of the original scale)

These are called the "modes" of the major scale. In C major, C is the "root mode". There are names for the other modes too:

1 - Ionian (Major)
2 - Dorian
3 - Phrygian
4 - Lydian
5 - Mixolydian
6 - Aeolean (Minor)
7 - Locrian

These are Greek names. I know it's a bit much to take in all at once, but let me try to explain the overall sound and feeling of each one:

So the one I did above with the C major scale was:

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

That's D dorian. If I started on E, it would be E phrygian. And this can be done in any key, as long as you know what notes are in the major scale. Easy enough? Sweet.

4. Intervals and Harmony

Playing up and down the scale can get boring, if you're only playing the notes in sequence. This is where intervals come in. An interval is the "distance" between two notes. I've put how many half steps away from the root the interval is.

0 - Root
1 - Minor Second
2 - Major Second
3 - Minor Third
4 - Major Third
5 - Perfect Fourth
6 - Augmented Fourth/Diminished Fifth
7 - Perfect Fifth
8 - Minor Sixth
9 - Major Sixth
10 - Minor Seventh
11 - Major Seventh
12 - Octave

Note that this isn't necessarily relative to the key you're playing in. It's relative to any note.

Two notes that are an octave apart are the same note, just one whole register higher.

Notice something. We've got something called a "perfect fifth", yet it's 7 half steps away. Why? Because in the diatonic scale, it's five steps away. See, every mode of the diatonic scale is made up of different sequences of these intervals. When you begin to compose your own stuff, you can hear how each interval sounds in a scale, and step outside the scale when you want to, and make it sound cool.

Harmony is two or more notes played at the same time. You can play these intervals at the same time, and depending on what intervals you play, they can sound pleasant, or gut-wrenching. :)

If you look at a scale, the harmony is "built in" for you. Just play two or more notes of a scale at the same time and you've got harmony. Sometimes it sounds good, sometimes it doesn't. How will you know when they sound good? Let's look at arpeggios.

5. Arpeggios and Chords

Arpeggios are simply a group of three or more notes that are spaced out a bit more than scales are, and played as individual notes (as opposed to chords, as we'll see in a bit here.) The most common and simple ones are 3 note ones (also known as triads), and out of the 3 note arpeggios, the most basic ones are Major, Minor, and Diminished.


Root, Major Third, Perfect Fifth


Root, Minor Third, Perfect Fifth


Root, Minor Third, Diminished Fifth

A C major arpeggio would look like:

C, E, G

Because E is a major third away from C, and G is a perfect fifth away from C.

An A minor arpeggio would look like:

A, C, E

Because C is a minor third away from A, and E is a perfect fifth away from A.

A B diminished arpeggio would look like:

B, D, F

Because D is a minor third away from B, and F is a diminished fifth away from B.

How does all of this fit together? Well, with the way the diatonic scale is set up, different notes have different arpeggios associated with them. Taking a look at the C major scale again:

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

If we started with C, and made a 3 note arpeggio by going up by two notes, we'd get:

C, E, G

Major arpeggio, just like the above. Do the same with D:

D, F, A

It's a minor arpeggio. E:

E, G, B

Another minor arpeggio. "Okay, is there a pattern?" Yup. Before I show you, see if you can figure out, by yourself, the order of what types of arpeggios are in the major scale.

And here's the pattern, with the C major scale as reference:

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

1, 2, 3, 4, 5, 6, 7

Major, Minor, Minor, Major, Major, Minor, Diminished

Hopefully, as you begin to compose stuff, you'll look at these patterns and use them to your advantage.

Chords are groups of three or more notes played simultaneously. Basically, they're like arpeggios, but the notes get played all at the same time. Chords tend to be the backbone of a lot of compositions. Only playing single notes gets really, really boring.

There are many different kinds of chords/arpeggios. We'll get to other kinds in a later tutorial.

6. Harmony Revisited

Probably the most commonly used and most pleasant harmony is created by playing a third above the note you're playing. So just like we did above, take whatever note you're on in the scale, and go two notes up. It's either a major or minor third. You can add the fifth on top of that too.

6. Chord/Key Notation

So far, we've learned three types of chords: major, minor, and diminished. If you want to write out a chord progression out on paper, or you want to write what key a song is in, there's some "notation".

The root note name by itself represents major. So if you came across:

C, F, G

You'd play C major, F major, and G major.

Minor chords are written as the root note name, but with a lower case "m" in front. Diminished chords are written as the root note name followed by "dim". It can also be followed with the "degree" symbol, but to my knowledge, ASCII doesn't have the degree symbol. ;) So here's a sample chord progression:

Am, C, Bdim, G

We'd play A minor, then C major, then B diminished, then G major.

You can also say "my composition is in the key of G" which means the key of the song is G major. Or "this song is in A minor" and it would be in the key of A minor. "But, what about the modes?!?" To be honest, I'm not too sure. I've never really heard a music teacher say "this is in the key of B dorian." For me though, I do say the name of the mode.

7. Timing

Most music we listen to is in "4/4" timing. Count out loud "ONE, two, three, four", each one equally spaced out, with an emphasis on the "ONE". The first 4 in "4/4" means that there are four notes of whatever note duration is in the second number. In this case, the second number is a 4, so that means it's a quarter note. So there are 4 quarter notes for every measure, or bar, in 4/4 timing.

In 4/4, a whole note is worth the whole measure. A half note is worth half the measure, quarter note is worth a quarter, eighth note worth an eighth, etc etc. Typically, we don't go beyond sixty-fourth note, since it's pretty impractical to write on a staff, and unless you have an extremely slow piece (like 40 beats per minute), you don't need anything faster than that. At an average speed (like 120 beats per minute), 128th notes are... superhuman, heh.

8. Simple Chord Progressions

The most common chord progression in western music is probably the "1-4-5". The numbers represent the scale degrees of the root note of each chord. In other words, if you were in C major:

C major would be 1
F major would be 4
G major would be 5

Review the scale degrees and all that other stuff if you're confused.

So if you did this over a 4 bar progression, it would be:

C major, F major, G major, C major (repeat)

Why does that sound good? It's the G major. The G is your 5th, and, for whatever reason, the human brain likes the tension it creates when you play the 5th and then the root. Simple as that.

Here a minor progression: 1, 7, 6, 7

In E minor, it looks like this:

Em, D, C, D

That's a common progression in many types of music.

Experiment, and come up with your own. Use the diminished chord sparingly.

9. Creating Melodies over Chord Progressions

Really, I can't tell you how to make up a melody. I can give you a few guidelines, though:

10. Summing Up

My God, I hope that made sense. If you have any questions, I'm on Pete's board.

Next time, we'll get into other chords, other scales, odd time signatures, other melody writing techniques, and the staff.

Good luck!

-The Awakened

Download a copy of this tutorial: music_pt1.txt

Coding Standards, Naming Conventions and Formatting Styles

Written by Stéphane Richard (Mystikshadows)


AS you've read from the title of this article, it is all about coding standards, naming conventions and style of your source code module. The mean reason I've created this article isn't to brainwash you into my way of doing things. This article is not the first to talk about such a subject. But what i have elaborated here have proven themselves worth my time on all my projects both professional and personal. There's more than one reason to do so as you'll read here and to the best of my knowledge, following these standards and conventions, that you created yourself, might take just a bit more time in the programming phase of your project, but it can easily save you alot of time in the debugging phase. Likewise, because these are your standards made to follow your coding methods, it doesn't really take any of the fun out of your programming project.

The main thing to remember in this article isn't the standard itself (although you're more than welcome use it if you like it) but rather to give you the reasons why coding standards exist, why they can bring benefits to your projects, even the smallest ones. It takes a little mental training to motivate yourself to create this standard, take the extra time to name your variables, subs and other elements with clear and relevant names. But you'll be the first to reap the rewards of implementing these practices into your own programming endeavors. Note that I am using the standards I've elaborated in the 3rd part of my Graphical User Interfaces - A Complete Study So the standards might look familiar as it is the standards I follow on any of my projects (big or small). I will however elaborate on them in more details here. So then, Let's get right to it.


This is always the bigger question isn't it? Of course, if you can't find a reason to create a standard, chances are it will be hard for you to actually create one and even more so actually follow the standard you set yourself. What I will do here is give you the reasons why I created my own standards, and what benefits they've given me so that you can see for yourself what standards and conventions are really all about.

I don't know about you, but by reading these advantages, I'm sure just those got you thinking all of a sudden. It's clear to see that good standards and naming conventions really helps make things more prepared for the unevitable future of programming, changing existing code, adding new code in and remembering what you did 5 years ago. If you could find a way to give you all these "easier things in a programmer's life", wouldn't you want to alteast give it a good try? It doesn't take a bachelor's degree to create a standard and you don't need rocket science to be able to stick to it. All you need is the time to create it. In my case it took about 2 good hours of thinking and writing. So it's not that much time. But the time it will save you in the long run can be alot more than you would think possible.

So then, with all this in mind, the next logical step is to simply go right ahead and elaborate these standards. It's very important for you to remember that these are the standards I created and like to work by. They might sound interesting to you and as such you can definitaly used them if you want. Some of your might feel that only part of this elaboration wight be usable in your case. Again, feel free to use this in whole or in parts. The real idea behind this whole article is to help you find a way to organize your code in a way that will help you work on projects without being overwhelmed by the code you have done or the code you are about to undertake. Simple organization prior to coding as well as some common sense is really all it takes. So het's talk about these standards.


The standard I'll be using is broken down into three workable standard groups. These are the "Source File Documentation", "Indentation and Spacing" and "Naming Conventions". As I mentionned, coding standards are there because when the code gets big, it's clarity will have better chances at staying as clear as possible across the thousands of lines of codes there will be. Let's take the time to review these standards right here.


In big projects, if you don't implement error management right from the start, it will be a major headache to add it later in the project or at the end after you're done coding everything else. For this reason alone I talk about error management as part of a convention because like the rest of your standards and conventions, they need to be implemented from the start so they don't quickly become quite an overwhelming task. However, doing it from the start like this, you can integrated it easily to your coding routine and almost not have to worry about it. At the end you'll end up with all your error management done and be ready to move on to the next step of your project right away.

Throughout all the modules, each sub and function, when implementing the error management code, you might want to think about the reasons why you are implementing error management. As far as I'm concerned One of the main reason I implement error management is because of the debugging phase and the other errors that might occur afterwards as users actually use my program. As such, I need a system that can point me as close as possible to the erroneous code. This way I don't have to spend too much time locating where the error is actually happening. For that to successfully occur, I need a certain list of information to help me in my quest. Whether the bug is reported on screen or logged to a file this information will still help locating bugs quickly. Here's that information: (note that this is also in my 3rd part of my GUI series).

Error Information Description
Engine Name
Module Name
Sub/Function Name
Parameter List
Error Number
Error Description
The Engine name is displayed
The Name of the .bas or .bi file
The Sub or Function Name
The values of the parameters passed
The error number as returned by ERR
A human readable description of what the error means

This essentially means that whenever an error is returned by the system, it will give me back these specific pieces of information. By knowing right from the start, the Engine where the error occured, the module name, the sub or function name, the values of the parameters that were passed to that sub or function (if any) and the error that occured, imagine how fast the debugging process will suddenly become for me, or anyone else correcting the error. Here is an example of a typical function and how I will provide the needed information. Let's assume that this function will be in a module called MouseControl.bas and that the project is called DrawingPad:

' ============================================= ' NAME: MouseOverControl() ' PARAMETERS: XPos AS INTEGER ' YPos AS INTEGER ' Width AS INTEGER ' Height AS INTEGER ' MouseX AS INTEGER ' MouseY AS INTEGER ' ASSUMES: Parameters are positive values ' RETURNS: True if mouse is on top of the ' control, False if it is not. ' CALLED FROM: EVRIL's main logic loop. ' --------------------------------------------- ' DESCRIPTION: This function will take the ' position and dimensions of a ' control, do the math to get ' the range of coordinates that ' the mouse need to be in to be ' considered to be on top of the ' control and compare the mouse ' coordinates to see if it falls ' within the control's range. If ' it does, True will be returned ' to the calling sub. If it's ' not on top of it, False will ' be returned instead. ' ============================================= FUNCTION MouseOverControl(XPos AS INTEGER, YPos AS INTEGER, _ Height AS INTEGER, Width AS INTEGER, _ MouseX AS INTEGER, MouseY AS INTEGER) AS INTEGER ' ------------------------------------------------ ' We create a variable to hold the error message ' ------------------------------------------------ DIM ErrorMessage AS STRING DIM BottomRightX AS INTEGER DIM BottomRightY AS INTEGER DIM WorkResult AS INTEGER ' -------------------------- ' Turn in Error management ' -------------------------- ON LOCAL ERROR GOTO ErrorManager ' --------------------------------------- ' Evaluate the bottom right coordinates ' --------------------------------------- BottomRightX = XPos + Width - 1 BottomRightX = YPos + Height - 1 ' ------------------------------------------------------------ ' Compare Mouse coordinates to control's area and return the ' proper value of the function based on if the mouse is over ' the control or not. ' ------------------------------------------------------------ IF (MouseX >= XPos AND MouseX <= BottomRightX) AND (MouseY >= YPos AND MouseY <= BottomRightY) THEN WorkResult = True ELSE WorkResult = False END IF ' ------------------------------------------------------------- ' Return the value and exit the function right here before ' execution of the error management section can take place ' if no error occured. ' ------------------------------------------------------------- MouseOverControl = WorkResult EXIT FUNCTION ' ------------------------------------------------------------------- ' This is where the error management message is created and printed ' ------------------------------------------------------------------- ErrorManager: ' ------------------------------------------------------- ' First step is to formulate the complete error message ' ------------------------------------------------------- ErrorMessage = "Engine: DrawingPad" + CHR$(13) + _ "Module: MouseControl.bas" + CHR$(13) + _ "Function: MouseOverControl" + CHR$(13) + _ "Parameters: (" + STR$(XPos) + ", " + _ STR$(YPos) + ", " + _ STR$(Height) + ", " + _ STR$(Width) + ")" + CHR$(13) + _ "Error: " + STR$(Err) + ":" + Err$ ' ------------------------------------------------------------- ' Next we either display the error or append it to a log file ' ------------------------------------------------------------- IF ErrorLogging = True THEN LogError(ErrorMessage) ELSE DisplayError(ErrorMessage) END IF ' --------------------------------------------------------------- ' In this case, we resume execution loging or showing the error ' --------------------------------------------------------------- RESUME NEXT END FUNCTION


And there you have it, the coding standard documents comes to an end. If you've paid attention, you can see that the major factor you need to remember when creating your coding standards is that they have to make sense to you now and in a year or 2 if you need to get back to that same code. If just that stays in your mind after reading this, I will be able to say mission accomplished. Too many times I've seen people code away for months, leave to work on another project and be baffled when they need to get back to that project. Too many times I've joined projects that didn't follow any standard imaginable. It's really amazing what a couple of hours (maybe a days work) defining a standard can do to the overall coding process. How much it can help during and after the programming phase. This is the major reason why I wrote this article. Is to make you think about it.

What's to say next? Are you going to create your standards or keep working the way you are now? That decision is up to you some might have the natural gift to code so clear that not understanding what's happening is simply not an option. Others could benefit from such a standard being in place. But that's just as far as code readability goes. For maintainability purposes however, I strongly believe that having a standard in place can only have benefits. Sure when deadlines are concerned people tend to think that standards just waste too much time, but that's usually because they didn't know what I've shared with you right here. When it comes to deadlines, there's one thing you need to think about. Do you want to spend a day creating a better standard or delay your release 3 or 4 weeks because you are lost in 1000s of lines code somewhere thinking (maybe I should have created a standard)? That answer is simple to me, isn't it to you? Until I write again, feel free to email me with comments or questions. Happy coding.

Stéphane Richard

Download this tutorial: codingstandard.html

How To Build a Shell For Qbinux, Part 1

Written by Seb McClouth

Shell, what's that?

You might know the SHELL-command in Qbasic/QB. And if you run it just as SHELL, you'll get a commandprompt. And that's the shell. If you don't have a shell... your OS simple won't work. The Shell communicates your commands to the kernel which will run it. In Qbinux, just like in Linux, Shell is the first program to be loaded when you log in, and keeps on running until you log out.

You have downloaded Qbinux and you think... Qbash is not really the thing I want... I want to create more sumfin of my own... It's possible...

What do you need?

The Qbinux core ofcourse... And some experience in programming. In order to get more comfortable with this, we first gonna build a basic shell... which is not capable of doing anything yet but it's a start. Along the way you can add things you'd like to see in your own shell.

And remember, if you have any questions... don't hesitate to e-mail me.

Create a new file call sh.qs0 or whatever-name-you-like.qs0 and place it into the map shell. Then edit the compile.bat file and change the qbash to your shell.

For a non-working-basic-shell you need the following code:

IF CVL(CurDrive) = 0 THEN cp$ = "root:"
DIM dm(2048) AS STRING
IF CurDir <> ocdir$ THEN
 ocdir$ = CurDir
 cp$ = ""
 t$ = CurDir
 IF t$ <> MKL$(0) THEN
   t$ = GetName(LEFT$(t$, 4), 1)
   cp$ = cp$ + RIGHT$(t$, LEN(t$) - 4), 1)
   LOOP UNTIL LEFT$(t$, 4) = MKL$(0)
   cl = 0
   FOR a = 1 TO LEN(cp$)
          t$ = MID$(cp$, a, 1)
          IF t$ <> "/" THEN
            g$ = g$ + t$
            dm(cl) = g$
            cl = cl + 1
            g$ = ""
          END IF
   cp$ = ""
   FOR a = cl -1 TO 0 STEP 01
          cp$ = cp$ + dm(a) + "/"
   IF CurDir <> MKL$(0) THEN
     t$ = GetName(CurDir, 1)
     cp$ = RIGHT$(t$, LEN(t$) - 4) + "/"
     cp$ = ""
IF pcom = "" THEN
 PRINT cp$;"#";
 LINE INPUT "", com$

That's it for now. Till next time.

Seb McClouth

http://mcclouth.tk or http://www.freewebs.com/qbinux


Download this tutorial: qbinux_shell_pt1.txt

A Course in FreeBasic: Chapter 2

Written by Rattrapmax6


Well, it's been some time since chapter one. And now we will continue on where I left off last time with Variables and Constants. In chapter one you got a little taste of these so you could see how the INPUT function worked. In this chapter, I will explain in pretty good detail the some of the many ways to use Variables and Constants, and a few of the codes that alter or render them.

Variables VS. Constants: In greater detail..

Variables are values in your program that will change over the course of its operation. Much like I said last time, things such as age, time, the position of something (That moves), or any number of things. Variables exsist in just about every program you run, and thus are a great way to control events in a game, or trigger errors when something goes wrong in your application, or game.

Constants are values in your program that do not change over the course of its operation. Things such as mathimatical constants (e.g., pi, g, etc.), a person's name, a creature's type (e.g. Horse, dog, cat, etc.) or many other things. Constants are very helpful when it comes to programs that use a lot of math constants so you only have to type the names insted of their long values.


Strings are variables/constants that store text values, and numbers stored as strings are considered text. Stings are noted to the compiler by a $ symbol at the end of their name, unless they are DIMed as an string. Here is an example of the two types:

'A normal string..
stringname$ = "Text value.."

'A DIMed string (Show as DIM AS STRING, but can be DIM stringname AS STRING like in QBasic)..
DIM AS STRING stringname
stringname = "Text value.."

Strings have severial functions that can use or alter them. Two of them you already know as PRINT and INPUT. PRINT will read the value from the string and display it to the screen, where as INPUT stores a user defined value to the string. There are several commands that involve strings, but those will be covered in their correct time.


Numbers are variable/constants that may be of severial types. These are bytes, shorts, integers, longs, singles, and doubles. Each have their own perpose for storing numbers, and some can be either signed or un-signed. Here is a list of the data types:

BYTE: Is a 8-bit signed whole-number that can hold a
       value between: -128 to 127.
UBYTE: Is a 8-bit unsigned whole-number that can hold
        a value between: 0 to 255.
SHORT: Is a 16-bit signed whole-number that can hold
        a value between: -32,768 to 32,767.
USHORT: Is a 16-bit unsigned whole-number that can
          hold a value between: 0 to 65,365.
INTEGER: Is a 32-bit signed whole-number that can hold
           a value between: -2,147,483,648 to 2,147,483,647.
UINTEGER: Is a 32-bit unsigned whole-number that can
            hold a value between: 0 to 4,294,967,295
LONG: (Same as Integer)

LONGINT: Is a 64-bit signed whole-number that can hold
           a value between: -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
ULONGINT: Is a 64-bit unsigned whole-number that can hold
            a value between: 0 to 18,446,744,073,709,551,615
SINGLE: Is a 32-bit floating point number that can hold 
          a value between: 1.1 E-38 to 3.43 E+38.
          Its precision is of 6 decimal digits.
DOUBLE: Is a 64 bit floating point number that can hold
          a value between: -2.2E-308 to +1.7E+308.
          Its precision is of 14 decimal digits.

Data types are assigned to a variable/constant by the use of DIM. A quick note on how DIM can be used before we continue: DIM can assign the same type to multible values by using DIM AS (Type), or it can assign values to each one to be DIMed. You also have CONST which sets a constant to be caried over the whole program. Examples:


'DIM all varibles AS BYTEs..
DIM AS BYTE variable1, variable2, variable3

'DIM each varible AS diferent types..
DIM variable1 AS BYTE, variable2 AS INTEGER 


CONST PI = 3.14


Now that you see the basics on how DIM works, I will continue with an example code on using a few of the types so you can get an idea of their uses.. :

'DIM an Integer and a Single...
DIM numint AS INTEGER, numsng AS SINGLE 

'Give both a value of 100.5...
numint = 100.5

numsng = 100.5

'Print both values and see what you get...
PRINT numint; " <-- Integer."
PRINT numsng; " <-- Single."


Basic ways to use Variables/Constants:

So, now that you know the different data types, you probaly want to have something to do with them. Here are some fun little sample programs that you can study and see a few ways to use these different types:


'Make a String and three Shorts
DIM AS STRING username
DIM AS SHORT syear, eyear, age

'Get user's name...
INPUT "Hello, who are you"; username
'Make a space so lines don't run together...
'Welcome user...
PRINT "Hi, "; username; "."
'Ask user for his/her birth year...
INPUT "What year were you born? (####): ", syear

'Ask user for the current year...
INPUT "What is the current year? (####): ", eyear

'Calculate user's age..
age = eyear - syear


'Tell the user how old the user will be on his birthday...
PRINT "On your birthday in"; eyear; ", you will be"; age; "."

'Tell the user good bye...
PRINT "Have a nice day, "; username; "."

'Pause long enough for user to see the last message...


'DIM are variables...

CONST PI = 3.14 'Set the constant..

ANG = 40 'Our angle to make a Radian..

RAD = ANG * PI / 180 'Make the angle a Radian..

PRINT "Original Angle:"; ANG

PRINT "The Radian value:"; RAD

The comments explain what the code does, and you should by now be able to understand the commands I used. Well, that wraps up this tutorial on using variables, so until next time, happy coding, and have fun!

PS: No debugging tips since the tips from the last chapter will work here if problems arise.

Contacting me:

EMail: Rattrapmax6 on AOL

Webpage: My Site...

Download a copy of this tutorial: fbc2.html

Programming the Multiprocessing Core for QB 4.5

Written by Nick Verlinden


Why in gods name do you want a multitasking core for qb someone once asked, I could use it for allot of things. For monitoring multiple subs at once. You never wanted to to display the time in a custom sized text box while playing a game? This is the reason I programmed this thing. The only criple thing in QB 4.5 was the lack of running mutiple subs at once (not to mention the speed, but hey..). I'm trying to make a librarie out of it, but first i'm going to introduce to you the first beta release. I kept the alpha releases silent because I didn't want to be overkilled by questions etc, and the alpha versions contained allot of bugs. May it be usefull or not, here it is anyway.

The reason I'm writing this article/tutorial is because it isn't that simple to program subs in QB 4.5 without knowing how to trap loops. This is a big adaptation. But I must say I'm stunned when I saw how it actually affected the running speed. It's faster than I thought it would be. A sub with a dry loop (meaning only doing variable math) can go as fast as 666 loops per second on a dos box in windows. So it might even come in handy. In this tutorial I hope to learn you how to do multiprocessing loops, a better understanding of the program. I will keep messing around with my core until it ultimatly becomes complete. But what is complete? That's why, if you have any suggestions and/or questions, you may contact me on my e-mail address listed at the end of this document. I'm going to explain the basics first, and then we go further into detail like all the variables. Right, let's get busy.

Chapter 1

The Core

It's probably not as spectacular as it sounds, but hey, I put my efforts in it and I'm proud of it. How does the core work you ask? Simple, I keep track of all kinds of stuf in variables. An example would be nice right? ok, here it is:

I want to add a task, let's display the clock. (In my demo, there is a sub called display.time) so what the shell (in my demo, it's the sub CMD) does is, it opens a new array with the process ID as holder, it sets all kind of variables. The most important varible is this: run.appshelf(ID%). The system goes into it's usual loop 'systemidle' and it checks all the registered arrays if there is a program to run, if the variable in array run.appshelf(ID%) = 1 then the system will execute the given script with a simple sub I made called script.appshelf(ID%). So basically, the source can be converted to any language possible. Now that you have a better understanding of how the core works, lets look at my built in shel CMD. One important thing is due to the limitations of QB 4.5 I only made a 255 array, meaning that there can be a maxx of 255 processes because the system is process 0.


CMD, a biult in sub I made for directing the system core. This is just a simple example and is probable not the most efficient way to use it. Lets look at the source. It reads in a command from the command line, and then adds the process to the systemcore by setting the variables in the sub add.process.

loopy.appshelf(ID%) = 0
screen.erase 1, 1, 1, 70
Sinput Inp$, "-->", 1, 1, 60, 7, 0, 0
IF LEFT$(UCASE$(Inp$), 4) = "KILL" THEN kill.appshelf(VAL(RIGHT$(Inp$, 1))) = 1: VAL(RIGHT$(Inp$, 1))
IF LEFT$(UCASE$(Inp$), 3) = "ADD" THEN a% = add.process("", RIGHT$(Inp$, 1), "USERPROC", 1)
IF LEFT$(UCASE$(Inp$), 3) = "VAR" THEN display.variables VAL(RIGHT$(Inp$, 1))
IF LEFT$(UCASE$(Inp$), 5) = "FLOOD" THEN flood.kernel VAL(RIGHT$(Inp$, 3)), "1"
IF LEFT$(UCASE$(Inp$), 7) = "TASKMON" THEN a% = add.process("", "6", "Display Process call", 1)
IF LEFT$(UCASE$(Inp$), 3) = "PRC" THEN display.process 10, 1 'ELSE LOCATE 3, 1: PRINT "Unknown command"
IF LEFT$(UCASE$(Inp$), 4) = "CALC" THEN a% = add.process("", "8", "Calc test", 1)
IF LEFT$(UCASE$(Inp$), 7) = "CHRONOS" THEN a% = add.process("", "7", "Chronos monitor", 1)
IF LEFT$(UCASE$(Inp$), 6) = "DOLOOP" THEN a% = add.process("", "9", "Do Loop test", 1)
IF LEFT$(UCASE$(Inp$), 4) = "LAST" THEN storeloc 0: LOCATE 23, 1: PRINT "LastID%: " + STR$(LastID%): restoreloc 0
IF LEFT$(UCASE$(Inp$), 7) = "DOMULTI" THEN a% = add.process("", "10", "Multiloop test", 1)
run.appshelf(ID%) = 1

As you might have noticed this is a command line, and it uses the sub Sinput instead of the usual INPUT function in QB 4.5. This is because the processes should still keep running even if you are typing in a command. The sub is not mine, I did not program it, I just modified it a little to work with my core. It's a good piece of code, too bad I don't have the name from who might have written it. Sorry fellow programmer, if you might read this article. The input is checked for a known command. lets look at the first line, it says KILL, if you couldn't figure out what it did, it kills processes running in the systemcore. then a 1 character variable (because I was too lazy to make a line that can read arguments) and takes it as the ID. I want to know the ID of a running process? ok, type in PRC or TASKMON, the prc command does only display the current running processes, taskmon updates constantly until killed. The add command is just written for my own debugging purposes. CALC does a random calculating job in 2300 loops. CHRONOS is the main trigger for refreshing applications sush as TASKMON, every second that passes it updates the status of the programmes on the screen. DOLOOP is a never ending loop, wich is just a process that i used for seeing if the system slows down. LAST prints the last ID that is used by the processes. What you might want to know is, that if a process is finished it's ID is recycled, so if there are 5 processes running, and you end the fourth process, then you add another, it uses the fourth ID. CLS clears the screen. DOMULTI does a multiloop sub, so a sub with more than one loop in it. It will finish after the two loops reach 1000. CMD itself is also a process. But if you kill it, there's no way to end the program, so be warned.

FUNCTION Add.process(ID%)

This sub sets the basic variables that the systemcore needs to know. What type of app is it, is it initialized (this variable is for the ID recycling), does it need to be activated, what is the name, the linescript, what kind of user is it, what file to execute... I made this a function so it can return an error if something wasn't right, but that's not implented yet.

FUNCTION add.process% (file$, script$, name$, user%)
'PRINT "Add a process trigger": SLEEP 'debugging
ID% = FreeID%
type.appshelf(ID%) = 0
init.appshelf(ID%) = 1
run.appshelf(ID%) = 1
name.appshelf(ID%) = name$
linescript.appshelf(ID%) = script$
user.appshelf(ID%) = user%
file.appshelf(ID%) = file$
loopy.appshelf(ID%) = 0

SUB script.appself(ID%)

The script sub just executes what is needed, for example if the linescript is "10" it runs the multiprocess sub. Lets look at the source.

SUB script.appshelf (ID%)
IF file.appshelf(ID%) = "" THEN GOTO linescriptz ELSE GOTO runfile

IF linescript.appshelf(ID%) = "1" THEN disp.time ID%, 1, 70
IF linescript.appshelf(ID%) = "2" THEN disp.time ID%, 1, 60
IF linescript.appshelf(ID%) = "3" THEN CMD ID%
IF linescript.appshelf(ID%) = "4" THEN disp.time ID%, 1, 50
IF linescript.appshelf(ID%) = "5" THEN calc.flood ID%
IF linescript.appshelf(ID%) = "6" THEN display.processu ID%, 10, 1
IF linescript.appshelf(ID%) = "7" THEN display.chronos ID%
IF linescript.appshelf(ID%) = "8" THEN calc.flood ID%
IF linescript.appshelf(ID%) = "9" THEN do.looptest ID%
IF linescript.appshelf(ID%) = "10" THEN do.multiloop ID%
GOTO endsubscr

filehandle.appshelf(ID%) = FREEFILE
OPEN file.appshelf(ID%) FOR BINARY AS filehandle.appshelf(ID%)
IF LOF(filehandle.appshelf(ID%)) = 0 THEN CLOSE filehandle.appshelf(ID%): KILL file.appshelf(ID%)
GET filehandle.appshelf(ID%), , tempvar
IF tempvar = 1 THEN disp.time ID%, 1, 1
CLOSE filehandle.appshelf(ID%)
GOTO endsubscr


What happens within here? It checks the process Script.appshelf(ID%) variable, it's a string. First we check the file.appshelf(ID%) variable wich holds the filename of a script to execute. If this varible is empty check the linescript.appshelf(ID%) variable. lets look at script 10. It's the DOMULTI sub!, so if the variable is "10" then he activates the do.multiloop sub.

What have we learned?

If you want to use my built in CMD, then you must first write a line of code in the sub wich tells the system what to do when that command is typed. Then type a line of code in the linescript sub what sub to launch. Later on I will try to teach how to program a shell for the core. We are almost writing our first MultiProC program. Read further about it in the next chapter.

Chapter 2

Program Design

Now that you have an idea of how the core works internally, let's build our own little application. What kind of application? Something simple off coarse for starters. We are going to make a date displaying SUB

What you need to know:
The program type we are making is a program that doesn't loop on it's own, meaning that the system keeps running the program as long as it isn't killed. I'm going to explain line per line to make it more clear.

SUB display.date (ID%,X%,Y%)

We take the x and y arguments to display the date on a specific location. And if you are programming a sub that wil not run within the core, then we must always give the process ID wich is given bij add.process.

loopy.appshelf(ID%) = 0

This line sets the systemvariable loopy to 0, so that the system knows it must be run every cycle, if you set it to 1 then the system will ignore that process because it loops on it's own. Else you get an error message out of stack space, because the sub keeps running deeper and deeper, it's a neverending loop opening the sub. In this case, this isn't actually needed, because the add.process sub already sets the value to 0.


We set the cursor location to X% and Y%, and print the date on this location.


End of the sub.

So maybe to see the sub in total:

SUB display.date (ID%,X%,Y%)
loopy.appshelf(ID%) = 0

Okay, we designed the sub. Now to add it in the command shell:

loopy.appshelf(ID%) = 0
screen.erase 1, 1, 1, 70
Sinput Inp$, "-->", 1, 1, 60, 7, 0, 0
IF LEFT$(UCASE$(Inp$), 4) = "KILL" THEN kill.appshelf(VAL(RIGHT$(Inp$, 1))) = 1: VAL(RIGHT$(Inp$, 1))
IF LEFT$(UCASE$(Inp$), 3) = "ADD" THEN a% = add.process("", RIGHT$(Inp$, 1), "USERPROC", 1)
IF LEFT$(UCASE$(Inp$), 3) = "VAR" THEN display.variables VAL(RIGHT$(Inp$, 1))
IF LEFT$(UCASE$(Inp$), 5) = "FLOOD" THEN flood.kernel VAL(RIGHT$(Inp$, 3)), "1"
IF LEFT$(UCASE$(Inp$), 7) = "TASKMON" THEN a% = add.process("", "6", "Display Process call", 1)
IF LEFT$(UCASE$(Inp$), 3) = "PRC" THEN display.process 10, 1 'ELSE LOCATE 3, 1: PRINT "Unknown command"
IF LEFT$(UCASE$(Inp$), 4) = "CALC" THEN a% = add.process("", "8", "Calc test", 1)
IF LEFT$(UCASE$(Inp$), 7) = "CHRONOS" THEN a% = add.process("", "7", "Chronos monitor", 1)
IF LEFT$(UCASE$(Inp$), 6) = "DOLOOP" THEN a% = add.process("", "9", "Do Loop test", 1)
IF LEFT$(UCASE$(Inp$), 4) = "LAST" THEN storeloc 0: LOCATE 23, 1: PRINT "LastID%: " + STR$(LastID%): restoreloc 0
IF LEFT$(UCASE$(Inp$), 7) = "DOMULTI" THEN a% = add.process("", "10", "Multiloop test", 1)
IF LEFT$(UCASE$(Inp$), 4) = "DATE" THEN a% = add.process("", "11", "System Date", 1)
run.appshelf(ID%) = 1

The line in bold is the line we added, now command knows if date is typed, he must add a process with the script "11". But as you know the next thing systemidle will be looking for is script.appshelf we also have to add what this script "11" actually does, so we will add it like this:

SUB script.appshelf (ID%)
IF file.appshelf(ID%) = "" THEN GOTO linescriptz ELSE GOTO runfile

IF linescript.appshelf(ID%) = "1" THEN disp.time ID%, 1, 70
IF linescript.appshelf(ID%) = "2" THEN disp.time ID%, 1, 60
IF linescript.appshelf(ID%) = "3" THEN CMD ID%
IF linescript.appshelf(ID%) = "4" THEN disp.time ID%, 1, 50
IF linescript.appshelf(ID%) = "5" THEN calc.flood ID%
IF linescript.appshelf(ID%) = "6" THEN display.processu ID%, 10, 1
IF linescript.appshelf(ID%) = "7" THEN display.chronos ID%
IF linescript.appshelf(ID%) = "8" THEN calc.flood ID%
IF linescript.appshelf(ID%) = "9" THEN do.looptest ID%
IF linescript.appshelf(ID%) = "10" THEN do.multiloop ID%
IF linescript.appshelf(ID%) = "11" THEN display.date ID%, 2, 30
GOTO endsubscr

filehandle.appshelf(ID%) = FREEFILE
OPEN file.appshelf(ID%) FOR BINARY AS filehandle.appshelf(ID%)
IF LOF(filehandle.appshelf(ID%)) = 0 THEN CLOSE filehandle.appshelf(ID%): KILL file.appshelf(ID%)
GET filehandle.appshelf(ID%), , tempvar
IF tempvar = 1 THEN disp.time ID%, 1, 1
CLOSE filehandle.appshelf(ID%)
GOTO endsubscr


The line of code in bold is the one we added and we are ready to test. So run the file and at the command line type "date", it doesn't matter what case you tpye, because the CMD sub will automaticly convert it to uppercase.

Now that we see it has worked, mess a bit around, try to run 6 processes at once, like:


and if you watched it closely, you must have noticed the speed of doloop and domulti has seriously slowed down, this is because we update the date constantly, i know you only have to display the date once every day, but if you do a cls, it will disappear. so therefore we are going to use the chronstat function, this function does the following thing, it updates the screen once every second. so we don't lose any valuable process time.

SUB display.date (ID%,X%,Y%)
loopy.appshelf(ID%) = 0
IF chrono.check(ID%, 0) = 1 THEN

The lines in bold where added. So what this means is: If chrono.check returns that I still have to refresh, then do the code.

Congratulations, you have made your first MPC application.

Loops, loops and more loops!!

Global variables!

Because we go out of the sub while it's still looping, we must use global variables. To make it easy, I created 2 global arrays global.integer(ID%,15) global.string(ID%,15). these are arrays which can hold 16 variables. If you wich you can always add more to them in the main program.

The hardest thing to figure out was how to do the loops. because if you do a loop just like you are used to do, it would stuck the system right?

I will demonstrate this with an existing sub called the doloop sub.

SUB do.looptest (ID%)
loopy.appshelf(ID%) = 0
IF type.appshelf(ID%) = 1 THEN GOTO loopingtheloop
PRINT "Starting loop"
global.integer(ID%, 1) = 0
a% = global.integer(ID%, 1)
IF a% > 1000 THEN a% = 0 ELSE a% = a% + 1
LOCATE 28, 30: PRINT "looptest: loop " + STR$(a%)
type.appshelf(ID%) = 1
global.integer(ID%, 1) = a%

If we have just one loop the following technique is used. The type of the appshelf type.appshelf(ID%) just holds a variable telling the sub that has already entered the loop. how do you ask? Almost at the end of the sub you see: type.appshelf(ID%) = 1, this is an indication that the sub was already in the loop, so if the sub is accessed again by the core, then it jumps to the loopingtheloop label.

This was easy, now something more difficult. multi loops. More than 1 loop in the sub. (shiver shiver)

SUB do.multiloop (ID%)
loopy.appshelf(ID%) = 0
IF type.appshelf(ID%) = 1 THEN
   SELECT CASE loopindex.appshelf(ID%, 1) 'in what loop where we
      CASE 1
        GOTO loop1
      CASE 2
        GOTO loop2
LOCATE 23, 1: PRINT "Starting multiloop " + TIME$
global.integer(ID%, 1) = 0
LOCATE 24, 1: PRINT "Start loop 1 at " + TIME$

loopindex.appshelf(ID%, 1) = 1   'say that you entered loop 1
loopindex.appshelf(ID%, 0) = 1   'say that the loop isn't done yet
a% = global.integer(ID%, 1)
IF a% > 999 THEN a% = -1 ELSE a% = a% + 1 'our goal, if a% is over 1000 then give the loop end instruction
LOCATE 25, 1: PRINT "looping 1: loop " + STR$(a%)
type.appshelf(ID%) = 1
global.integer(ID%, 1) = a%
IF global.integer(ID%, 1) = -1 THEN loopindex.appshelf(ID%, 0) = 0 'if our goal is achieved, then go out of loop1
IF loopindex.appshelf(ID%, 0) = 1 THEN GOTO domultiloopend
LOCATE 26, 1: PRINT "Start loop 2 at " + TIME$
global.integer(ID%, 0) = 0

loopindex.appshelf(ID%, 1) = 2
loopindex.appshelf(ID%, 0) = 1
a% = global.integer(ID%, 1)
IF a% > 999 THEN a% = -1 ELSE a% = a% + 1
LOCATE 27, 1: PRINT "looping 2: loop " + STR$(a%)
type.appshelf(ID%) = 1
global.integer(ID%, 1) = a%
IF global.integer(ID%, 1) = -1 THEN loopindex.appshelf(ID%, 0) = 0 'if our goal is achieved, then go out of loop2
IF loopindex.appshelf(ID%, 0) = 1 THEN GOTO domultiloopend
finish.appshelf(ID%) = 1
LOCATE 28, 1: PRINT "Loops done at " + TIME$


Thus, for every loop, you create a label, and at the end of the sub also a label. A little tip, if you use endsublabel or something and use it in every sub, QB will complain, because the label is also somewhere else, what I do is use the subname without special characters and add "end" to it, and thats my subend label.

We start by checking if the the code before the first loop is done by checking the variable type.appshelf(ID%). Then if this is the case we look at what it did last before going back to the systemcycle. we check the variables loopindex.appshelf(ID%, 1) and loopindex.appshelf(ID%, 0), if (ID%,1) = what loop where we in, (ID%,0) = where we done? To end the loop, we do the following,

IF global.integer(ID%, 1) = -1 THEN loopindex.appshelf(ID%, 0) = 0 'if our goal is achieved, then go out of loop1
IF loopindex.appshelf(ID%, 0) = 1 THEN GOTO domultiloopend

This means, if (in this case global integer (ID%, 1) = -1 ) our goal is achieved, set the loopindex variable to completed
(loopindex.appshelf(ID%,0) = 0).
after the las loop we say the process is finished, unless you don't want it to finish, then you leave that line of code out of the source and set variables loopindex.appshelf(ID%,0) & loopindex.appshelf(ID%,1) to 0.

What if i wanted to do a FOR loop?

I'm just gonna give you an example, the rest is like in the looping examples above.

SUB calc.flood (ID%)
loopy.appshelf(ID%) = 0
storeloc (ID%)
IF type.appshelf(ID%) = 1 THEN GOTO calcfloodloop
PRINT "Calc Flood start"
global.integer(ID%, 1) = 0

'FOR an% = 1 TO 32000
global.integer(ID%, 1) = global.integer(ID%, 1) + 1
add! = (RND * 255) * (RND * 255)
bdd! = (RND * 255) * (RND * 255)
LOCATE 21, 1: PRINT "Random calculating test: ", add!
LOCATE 22, 1: PRINT "Random calculating test: ", bdd!
LOCATE 23, 1: PRINT "Loop: ", global.integer(ID%, 1)
type.appshelf(ID%) = 1

IF global.integer(ID%, 1) <> 2300 THEN GOTO endsubcalcflood

finish.appshelf(ID%) = 1
restoreloc (ID%)


I marked the important things once more so you don't have to break your head looking for them.

Chapter 3

The interesting parts: Technical documentation

Functions & Subs

do.multiloop (ID%)	Multiple loop example
do.looptest (ID%)	Looping test
display.chronos (ID%)	Display the chronos trigger for refreshing
chrono.check% (ID%, m%)	Function that checks if an process may refresh
nano.chrono ()	The chrono sub for refrshing (originaly in nano seconds) 
storeloc (ID%)	Store the cursorlocation
restoreloc (ID%)	Restore the cursor location
screen.erase (x1%, y1%, x2%, y2%)	Erase text screen from X1 to Y2
display.processu (ID%, x%, y%)	Display the running processes (updated - TASKMON)
calc.flood (ID%)	Calculation test
flood.kernel (loops%, akk$)	Add process flooding (for testing only, isn't usefull)
display.variables (ID%)	Display the process variables
waitforkey ()	Waits for a key in a sub, while systemidle keeps running
display.process (x%, y%)	Display a list of current running processes (not updated)
RunningID% ()	Used by display process
LastID% ()	Returns the highest ID used
CMD (ID%)	Built in command shell
script.appshelf (ID%)	system scripting sub
erase.appshelf (ID%)	erase process variables
add.process% (file$, script$, name$, user%)	add a process to the system
check.appshelf% (ID%)	check the appshelf for kill, finish or add requests
graphgarbage (x%, y%, x2%, y2%, m%)	Draw some graphical garbage (used in earlier versions)
systemidle ()	The main sub wich handles everything
disp.time (ID%, x%, y%)	Display the time
Sinput (Inp$, Prompt$, Row%, Col%, Length%, Fore%, Back%, cursor%)	Input a string
FreeID% ()	Returns the first free ID


chronos AS INTEGER	Chronos variable (was used in earlier versions, removed)
curx(255) AS INTEGER	used for storing the cursor position
cury(255) AS INTEGER	same as curx
chrono.trigger AS INTEGER	refresh trigger variable
chronstat.appshelf(255) AS INTEGER	process refresh trigger
filehandle.appshelf(255) AS INTEGER	process filehandle for the script file
loopy.appshelf(255) AS INTEGER	process looping by itself? 1 = yes, 0 = let system loop it
run.appshelf(255) AS INTEGER	process does it need to be started
name.appshelf(255) AS STRING	process name
user.appshelf(255) AS INTEGER	process user type
active.appshelf(255) AS INTEGER	process is active? 1 = yes 0 = no
finish.appshelf(255) AS INTEGER	process is finished? 1 = yes 0 = no
task.appshelf(255) AS INTEGER	process need to do something? used by systemidle
init.appshelf(255) AS INTEGER	process confirms id register (used by FreeID)
file.appshelf(255) AS STRING	process script file
linescript.appshelf(255) AS STRING	process if no scriptfile do this codeline
kill.appshelf(255) AS INTEGER	process kill request
type.appshelf(255) AS INTEGER	process type (used for looping see chapter 2)
chronos.appshelf(255) AS INTEGER	process chronos variable
chronosstart AS INTEGER	used for nano.chrono
loopindex.appshelf(255, 1) AS INTEGER	process loop state (ID%, 0) = is loop done? (ID%, 1) = what loop
global.integer(255, 10) AS INTEGER	global integers (ID%, integern%)
global.string(255, 10) AS STRING	global stings (ID%, stringn%)

The main routine

active.appshelf(0) = 1 'systemcore
'ON ERROR GOTO errhandler
'OPEN "c:\boot.cfg" FOR INPUT AS 1
'IF LOF(1) = 0 THEN PRINT "boot.cfg is missing": CLOSE #1: KILL "boot.cfg": END
'LINE INPUT #1, Greetingmessage$
'PRINT Greetingmessage$
'LINE INPUT #1, shellname$
'PRINT "shell: ", shellname$
'SLEEP    'sleep for debugging purpouses
'xcuteshellx for afterworks
'we are going to use a normal sub for testing, the built in command
chronosstart% = VAL(RIGHT$(TIME$, 1))
shelname$ = "Built-in Command Shell"
a% = add.process("", "3", shellname$, 0)
'a% = add.process("", "2", "Clock 3", 1)
'LOCATE 25, 1: PRINT "Next free ID", FreeID% used for debugging in earlier versions
LOOP WHILE active.appshelf(0) = 1 'this will only work if you kill the process and exit CMD
PRINT "Error while booting"


This is my first beat release, and my first public release, the source is a little crappy, but I expect next version will be cleaned up, varialbes that aren't used removed etc,...

Hope this article/tutorial was any good, Have fun.

Nick Verlinden


A Test Tour in MPC

Start up MULTI.EXE

you see the commandline.
Type in prc

You get to see something like this:

Running Processes:
Processes: 1
Name: Built-In CMD Shell ID: 1 User: System

erase the screen by typing cls

now type doloop

type taskmon

you should see a screen like the prc screen, but it keeps updating
to test this kill the process doloop
so look at the process ID in taskmon and type:
kill (id number here)

did you see the task monitor updating? removing the doloop process?
this was probably a success.

type add 6

this is the internal clock, i didn't give it a command name for some reason.
if you read the programmers manual you could try to set a command name for the clock

look at taskmon the time process is also active

this was our little tour, i'l give you a short list of built-in commands:

add 	add a process with linescript ...
	1 = clock 1	only for testing
	2 = clock 2	only for testing
	3 = CMD	open another CMD shell
	4 = clock 3	only for testing
	5 = calc.flood	calculation flood for testing process slow down
	6 = taskmon
	7 = chronos monitor	display chronos variables updated
	8 = calc.flood	no difference with 5
	9 = doloop test	single loop
	10 = multiloop	multiple loop test
chronos <>

displays the chronos variables

prc <>

displays the current processes running (not updated)

taskmon <>

displays the processes running (constantly updated until kill)

var <ID>

displays the process variables for that ID

doloop <>

infinite loop

domulti <>

does 2 different loops

calc <>

does random calculating for ...allot of loops

flood <Number of processes>

adds as many processes as given

kill <ID>

kills the process with that ID

Tour END

Download Multiprocessing Core for QB 4.5 and these articles: Multi.zip

Modular Programming Versus Object Oriented Programming
(The Good, The Bad and the Ugly)

An Article Written by Stéphane Richard (Mystikshadows)


I'm sure some of your, by now, might be saying "what is that all about?". Allow me to begin this with a brief history of why I decided to write on this subject. You see, for decades already, when I hear talks about programming concepts and paradigms, It seems that Modular Programming techniques and object Oriented Programming have been under somekind of comparison by developers all around the world. A hidden feud between the two serving the soul purpose of boasting the advantages of one over the other. Also, It seems that with time, O.O.P. took on a very different role, one that radically changes the way newcomers to the world of development see and understand the concept. However, if you go on C forums, QB forums, and other languages too, and talk about O.O.P. you might be surprised at the answers you get from those communities.

Basically, these two items are what motivated me to write about the subject in question. NOte that the contents of this document represent my own point of view, my personal understanding of the concepts and my thoughts on what should be what. But i have seen the evolution of Modular Programming and Object Oriented Programming from their very beginning, I've also seen all the deviation that these programming methods took in the course of their evolution. I will be explaining these methods and share my views and insight on where each method can provide the best advantages on a project. This will give you the information you need to understand the rest of the document where I will be sharing what has been said about these methods and show you where the deviations that was bestowed upon the O.O.P. paradigm changed everything that O.O.P. is known as today.


Modular (or Procedural) programming is a coding method that entails the use of routines, sub routines and functions in order to organize and execute specific sets of instructions pertaining to a given task to be done. The main rule of thumb in this technique is that if a set of instructions, that perform a specific task or calculation, will be called several times, it should be moved to a subroutine (if it does not return a value) or a function (if it does return a value) and called from the needed other parts of the program.

Typically, to create a successful modular structured approach to solve a problem, you need to define the problem in terms of what actions or calculations the program needs to do in order to perform the task defined in the problem. You also need to see if there is any special connection between procedures and functions to establish an execution order for them. The other concept here is that if a subroutine or a function is quite big, it is probably due for a refactoring into two or more sub routines. This is essentially how modular programming manages the complexity of a program by breaking it down into smaller, simpler, more managable sections of code.

Over the years, structured programming has been given more than one coding style and as such gives a good foundation to adapt the programming method to fit one's minding. By that I mean that depending on a developer's background he or she might like to organize their modules, procedures and functions based on functional grouping (all string manipulation functions go in one module, all datatypes go in another module, all constants in yet another module, this is often the type of organization I like to follow as well. Others might prefer to organize their modular approach based on an entity structure (somewhat closer to O.O.P.). For example, all datatypes, procedures and functions that affect an employee's information goes in one module, all inventory datatypes and functionality goes in another module. This is one of the great advantages to the modular programming approach in that it allows to organize the code in a way that fits the developer's way of thinking. When you think about it, it can be a very strong point since everyone thinks in very different ways but everyone needs to be able to define their problem and bring solutions based on how they would solve them manually.


Object Oriented Programming is a coding method that entails the use of objects and their relationships in order to describe, programmatically, the problem to be solved. The classic definition of O.O.P. was based on three founding pillars which were Encapsulation, Inheritance and Polymorphism. Here is a brief explanation of these founding blocks.

In the classic definition of O.O.P. These founding blocks were created because of the birth of a need for code reusability without simply cut and pasting existing code into a new module. Hence you could create an object or a hierarchy of objects that pertained to a specific role. then give the compiled version of that object as a library to another person who could then create his own objects as being part of the originally defined hierarchy. Today, two new pillars have been added to the definition of O.O.P. They are Interface and Abstraction. Here are their definitions.

Essentially, O.O.P. is an evolving standard that adapts to new needed concepts as they are needed. This can be fun in some cases, but a real curse in most other cases. These last two pillars also created the concept of black box and white box programming techniques. The classic object was White box (which means that levels of the hierarchy needed to know what came at the parent level in order to be able to perform its task. In White Box development, a hierarchy defined levels of specializations of objects in a hierarchy where objects in a lower level had more refined programming compared to it's parent. In Black Box development, Each level of the hierarchy tends to define containment rather than refinement. For example: The white box would state that a dog is a specialized (or refined) type of Canidae. In Black box, a Canidae has a dog (and a wolf, and a fox as it's sub components. This can lead to some serious conflicts in my opinion, which i will share later in this document. For now, let's compare Modular Programming and Object Oriented Programming versus a typical problem scenario to get a glimpse of the real differences of both methods.


The Scenario:

The scenario I'll be using is the following. The boss comes to see you and asks you: "I would like a program that can save information on the employees to a file, I would like to be able to enter the Employee's ID, his name, address, city, state, zip code, telephone number, email and hourly rate and it should also be able to to retrieve that information based on one or more criteria that I would enter in different fields. I would like to print that information so I can put the employee information in a physical file. The employee should be able to to enter the time they arrive at, the time the leave and come back from lunch and the time they leave at the end of the day in a timesheet program. The program should be able to calculate how many hours they have worked that week, the gross pay they have gotten and the amount of overtime they worked (as well as what monetary value the overtime amounts to. Employees are paid 1 1/2 times their hourly rate for any hours over the regular 40 hours a week and they are paid twice their rate on any holiday. Everything should be saved and retrievable on a per employee basis. I also want weekly, monthly and yearly detailed and summary reports on all this information for all or one of the employees at a time."

The Modular Programming Approach:

In the modular programming approach, the verbs in the problem description are the ones considered first. Typically, these verbs represent the work to be done and therefore the likely subroutines that we would have to implement in order to solve the problem. The names in the description represent the information (variables and datatypes) that will will be acting on or producing at the end. Modular programming is based on three things, which are: 1. The information needed before the process can start, 2. The work to be done with that information and 3. The expected output of a procedure. We will here answer these questions as per our scenario above:

As you can see, the modular approach is closely related to the functionality needed in the problem description. You think in terms of what needs to be done and usually can pretty quickly devise a workable complete solution to a problem by consecutively answering these three questions (some of these answer may require that you breakdown the system into smaller answers to a subset of these three question depending on how complex the system gets. This breaking down into smaller more specific procedures and functions is how Modular Programming offers to manage the complexity of a program.

The Object Oriented Approach:

In Object Oriented Programming, the names, not the verbs, are the first to be considered because in O.O.P. the first task is to define entities, not actions. O.O.P. starts by defining the players (or actors if you will) of a given scene (the problem) and them proceeds to defining how the actors are described (the properties) and what the actors can do (the methods). Once all these are defined for all playing actors, then the scene (the main part of the program controls what each players has and what it does. Only when you are defining the methods of the object can you actually start answering the same three questions that the modular approach lets you define right from the start. Again, as we did in the modular approach, I will define the same problem description using the Object Oriented Programming Approach instead of the Modular Approach I used previously:

The Entities:

By reading the problem description. We can clearly indentify three entities. The Employees, the Timesheet and the reporting system. This is how O.O.P. problem solving begins. You need to identify these entities first and the define how you describe the object as well as define what the object can do. So let's take each entity and define them so you can see how things work:

As you can see, the Object Oriented Approach to problem solving is quite different from the Modular Approach. With all this information you now have on the two methods, you might be wondering if there are certain projects, or certain parts of a big project that could benefit from the Modular Approach and likewise for the Object Oriented Approach. Is there situations where you would be better off using one method over another. In this next section, I will discuss this subject, based on my own personal experiences with both methods.


If we take into consideration both methods used in the example above. We can see that both of them managed to define the problem, and possible organization adequately. In their own domain, we can say that they were both as successful as the other in doing what they are supposed to do. So where and when can and should you use one method over another? My experience has shown me that the best way to answer that question is to go by development domains they each have their own best way of describing their needs. Let's take a few examples industries to see how to select the best method.

This covers the industry and which method you're more likely to want to employ when developing (and presenting) a solution to the people that work in these respective industries. There is another factor that can be a very big player in your decision to use one method over another. That factor is one of the size of a project and hence it's complexity. There are many cases where even a program, for an entirely O.O.P. oriented industry like Multimedia and Entertainment, just doesn't need O.O.P. or would fail to take advantage of the O.O.P. approach to bring a solution to that particular problem. Likewise, O.O.P. could very well be the only viable solution to a problem brought forth by industries that have never needed O.O.P. before. It really all depends on the way they can explain these problems based on what they know of their industry. One last factor could be that the company you are developing for already have tools and do not wish to purchase tools to accomodate for the missing method. In other words, companies could very well impose their development methods and expect you to be able to arrive at a solution using their method whether it's suited for the task or not. In those case you just need to make the best of what you have.

These represent how I would deal with problems in these specific industries. I'll take the time to see how a concept can best be described to the users of the program I am making and if the description is based on objects, unless there is a restriction that stops me from doing so, I will use an O.O.P. approach especially when you are creating an entirely new project. When you think about it, there isn't just the program that you are making to consider but also how easy your solution will be for the users to understand and use. This means that you have to take the time, in making your decision, to see what kind of user you are dealing with to see how they might react to one or the other of the explanation methods and based on the findings of that little research, use the method that can be thought the fastest and easiest.


When you talk about O.O.P. today, you'll hear some very different explanations by different software professionals. Since O.O.P. is found on the 5 pillars I mentionned about, how can these answers be so diverse and, in some cases, so out of touch with each other? The first answer I have to bring here is that depending on when developers started learning O.O.P. they were given some very different notions on what exactly O.O.P. is and how to efficiently use it for problem solving.

One of these new notions arrived when Java hit the mainstream programming industry. Which suddently told you that everything imaginable in programming is now an object including strings, integer and other datatypes. hence the base of all programming should be the object. The problem with this notion is that it's true only for languages that are designed around the same concept as Java where everything you can create is an object. This does not today constitute the majority of the popular languages you can use today. When you think about it, a datatype has no reason to be an object simply because of the way a compiler organizes memory. An object has an overhead that would represent a major waist of memory compared to storing the classic 4 bytes for integers. All these little things is what makes Java so slow and a perfect example of sloppy bloated code waiting for a faster processor to surface so it can make it look faster.

Another one of the confusions in O.O.P. definitions arrived when Objects Modelling techniques like U.M.L. (Unified Modeling Language) made surface. U.M.L. in itself is not a bad approach at all in problem solving. However, today, alot of what defines U.M.L. is confused, or atleast stated when talking about O.O.P. Often when I talk to people, they will mention such notions as agreggations and composition. The problem with this is that any language that can do O.O.P. doesn't have an aggregation or composition construct per se. But these people say that they do alot of aggregations and compositions when they develop. I then have to explain to them that these are object modeling principles and have no direct equivalent in the language itself. Aggregation denotes a whole/part relationship between objects. For example a Circle is the whole object and a point, is part of a circle objects this is created as an aggregation of two objects. A Composition can be used to create a relationship between objects too but it has the added ability to have a source and a destination (Circle knows about Point, but Point doesn't know anything about circle). These are Object Modelling principles and cannot be directly coded in a language. but when translating the principle to the selected programming language, it could mean that the module that defines Circle will have an #include "point.h". But it does not mean that because this include statement is in the Circle Module that you have created an aggregation necessarily.


If you have been to forums and message boards that compare and debate modular programming and object oriented programming, you might have noticed that many claim O.O.P. is the only intelligent methods and start enumerating reasons that have absolutely no direct relationship to O.O.P. I've seen these too many times and it's a shame to see most of them are enumerated in an effort to bring down modular program and try to boast O.O.P. as a better approach. I will be listing here some of the more popular myths about O.O.P. that I have seen and tell you what I have experienced in regards to the myths themselves.

I do have to say however that there are some myths that I found to be true however, again based on my own experience. And when you think about the reasons I give here, you'll find it hard to see it differently. This told me that O.O.P. can have it's specific place. Here are the two most widespread myths that have proven themselves to me as being true.


The bottom line is quite simple. It would not be wise to decide that everything can be made from one of these methods and stick to it alone for all your programming endeavors. In some cases, O.O.P. will naturally be able to represent a problem much more efficiently where in other cases, a modular approach could save you loads of time by being able to represent the problem much quicker, easier and cleaner than any O.O.P. model ever could. it's important to remember that Modular Programming and Object Oriented Programming are two problem solving methods and that both are designed to bring answers to questions and solutions to problems. They are two different means of implementing a solution and that is really all that needs to be remembered.

It's important that you remember that this article really reflect my own experiences with both problem solving methods and my own personal opinions about them. Others probably have a different point of view and may have all the right reasons to believe them. All I can say is so far, in my 30 years of personal and professional development, my judgement on these has not failed me once. It takes good common sense and a bit of logic to make the right decisions and opinions about them. I will finish by saying that it's not wise to destroy a problem solving method over another, they truely do have their advantages and could make your life easier if you didn't reject either of them. It is even worse to believe what others say without knowledge. This means that if you want to form your opinions, don't read comments from anyone and believe them blindly. Give Modular Programming and Object Oriented Programming atleast a fair chance, find a project for each and see where each method takes you. It won't be bad for your career to know when each methods has advantages so it should be time well spent on your part. Learn them, evaluate them, compare them THEN when you have the knowledge you need, you can make a good choice.

As you now know, with all my writings, I am always opened to discussion and comments, suggestions and even debates. You can email me whenever you want to clear things that weren't clear to you when you read this. This article is the result of my own experience with the different programming methods. Your past experiences might give you a similar or different point of view on this subject. I'd like to hear of them because I know that everyone has his or her own thoughts on this subject, I see it every day on forums I visit. Until the next time I write, happy reading and programming no matter which method you like to use.

Stéphane Richard

Download a copy of this tutorial: modularversusoop.html

Implementing Line of Sight in Qbasic Games

Written by Torahteen


Line of Sight is often overlooked in a lot of good QBasic games. This is surprising to me, because it is both easy to implement, and it adds a good touch of realism. But there are numerous ways to put in line of sight. In this tutorial, I'm going to look at two. The circular and diamond line of sight. By the way, these work best in a tile-based game. You'll have to find some other way if you're doing a FPS, in which case these are unnecisarry. Enough ranting, let's get started.

Diamond Line of Sight

Okay, first of all, I don't know what the heck you call either of these methods. I made up the names, so if you find another name for them, it's probably correct. Anyway, the first thing we're going to implement is a diamond view system. In a diamond view system, the unit can see all of everything in a sort of diamond shape around the unit. There are two different diamonds you can do. One of them, has the points of the diamond pointing up, down, left, and right relative to the screen. The other has the points pointing in those directions relative to the unit. I'll be going over the first one, although I will give a short theory as to how you can do the other one.

Since I like to make my games modular, let's make the code into a function. We'll have the game engine call the function, passing in a map, the x and y values, the distance the unit can see, and a reference to the array we should put the final coordinates in. What I mean by final coordinates is a list of points defining what squares the unit can see. So here is our function declaration (BTW, it is not a true function, but a sub):

DECLARE SUB GetLos(map() AS MapType,x AS INTEGER, y AS INTEGER, sight AS INTEGER, result() AS PointType)

MapType should be defined somewhere in the game. But as an example, here is the MapType we'll use in this game.
TYPE MapType
    mType AS BYTE
    Clip AS BYTE

mType is the type of tile (Water, Grass, Rock), and is just an example. We'll be using the Clip status to check if a tile can be seen.

The way I will do all this, is with three nested FOR loops. The first loops iterates from the top of the diamond to the bottom. The second loop increments the width of the diamond by two for every line. The third loop goes through each square in the row. Every loop, we will check each square across the line, making sure that its clip value is false. Here is the code.

SUB GetLos(map() AS MapType, x AS INTEGER, y AS INTEGER, sight AS INTEGER, result() AS PointType))
    Dim nx, ny As Integer
    Dim w, d As Integer
    Dim n As Integer

    n = 0
    w = 1

    n = 1
    redim preserve unitMove(n) as PointType
    unitMove(n).x = x
    unitMove(n).y = y

    For ny = sight To -(sight) Step -1
        For w = 1 To 2 * sight Step 2
            For nx = -(w - x) To (w-x)
                'Checks go here.
                sx = nx
                sy = y + ny
                if sx > -1 and sx < mapWidth and sy > -1 and sy < mapHeight then
                    n = n + 1
                    Redim Preserve result(n) As PointType
                    unitMove(n).x = sx
                    unitMove(n).y = sy
                end if
            Next nx
        Next w
    Next ny
End Sub

Now you're probably thinking "What the heck does this do?!". Ok, notice the three FOR loops. The first two loops basically define the shape of the diamond. Look at the following diagram.

The square in the center is our unit. See the diamond shape around him? If he were on completly clear ground, that is what his line of sight would be. What the above code does, is check each square from the top to the bottom to see if the unit is capable of seeing it or not. Of course, you could see the first part of the mountain range, but not past that. That is not part of this tutorial.

So by starting at the top, w (width) equals one. But for each line going down, it increases by one. That is, until it gets to the unit, at which point it begins decreasing. Then for each line, starting from the left side of the line, we check each square. Simple ain't it?

That is all there is to the Diamond Style line of sight. The biggest draw back of this method, is that it is unrealistic. But it works well for many different games. The next part of this tutorial discusses a more realistic version. Remember that you can also use this to make a diamond movement style. Just pass in the right parameters, and put the correct checks in there.

But what if you want the point of the diamond to always be facing the same direction as the unit is facing? Well, that one is a bit tougher, and I haven't implemented it myself. But I do have a theory. I say that you can divide the diamond into two triangles, then interpolate each one. For each position, just find out what square that is in, then add it. You can then delete the duplicat points. In theory, it should work, but it's up to you to implement it.

Circular Line of Sight

Sure, diamond is simple, and it adds a nice touch to the game. But it is unrealistic. But there is another method. Circular line of sight allows your unit to see square that mark a circle around him. It's a lot more realistic, and it is still quite simple to implement. I hope you remember some of your trig.

Okay. To do this method, we're going to use a simplified ray tracer. Ray tracing is the process of drawing imaginary lines in an outward directiong from the unit, stop when you reach an obsticle. Sound simple? It is!

What we will do, is draw imaginary lines outward from the starting square(the unit), stopping once we hit an obsticle such as a wall, or another unit. We'll draw a total of 360 of these imaginary lines. But first, another diagram...

Sorry, that diagram makes it look not-so-simple. But don't worry, it is. Alright, so what will do is from 1 TO 360, we'll draw an imaginary line from the unit to the outside of the circle. Look at the diagram. You start from the center of the unit, and in the direction theta, incrementing by one each loop. Then you find the x and y of that position, round it down to the nearest whole number, and viola, you have the x and y position. Then you check that square to see if it is a building, wall, or anything of the like. If it is, then add the square, then exit the loop, going to the next angle.

So how much do we increment it, and how do we find the x and y position? I'll answer the first question first. Remember that QBasic/FreeBasic's built in trig functions can not directly take degree measure. Instead, you must use radian measure to measure your angles. Since we need to cast a ray once every degree, we must divide the number of radians in a circle by 360. From trig, we remember that there are 2PI radians in a circle. If we declare a constant at the beginning of our program called PI, then PI = 3.1419526. The increment is then 2*PI/360.

To find the x and y positions, we just use some more of our trigonometry. Look at the example. According to what we learned in trig, SIN(theta) = y/r, and COS(theta) = x/r. We know theta and r, so:

Since we need whole numbers, not floating point, we just cast these into integers. Here is our code:

Sub GetLos(map() As MapType, x As Integer, y As Integer, sight As Integer, ByRef result() As PointType)
    Dim theta As Double
    Dim inc As Double   'Increment amount
    Dim quit As Byte
    Dim n As Integer

    n = 0               'Just in case
    inc = (2*PI)/360
    theta = 0           'Just in case

    For theta = 0 To (2*PI) Step inc '360 times
        For i = 1 To sight           'Drawing our imaginary line
            'Find the position
            nx = Int(r * COS(theta))
            ny = Int(r * SIN(theta))
            'Check the boundries
            If (nx < 0 Or nx > mapWidth Or ny < 0 Or ny > mapHeight) Then
                Exit For
            End If

            'Check for clipping
            If map(nx, ny).clip = TRUE Then
                quit = True
            End If

            'Add the square
            n = n + 1

            Redim Preserve result(n) As PointType

            unitSight(n).x = nx
            unitSight(n).y = ny

            If quit = True Then
                quit = False
                Exit For
            End If
        Next i
    Next theta
End Sub

That is pretty much it. Only thing is to get rid of doubles. We just add this at the end.

Dim IsDup As Byte
    Redim tempList(0) as PointType

    For i = 1 To uBound(result)
        IsDup = 0
        For d = 1 To uBound(tempList)
            If result(i).x = tempList(d).x AND result(i).y = tempList(d).y Then
                IsDup = 1
            End If
        Next d

        If IsDup <> 1 Then
            Redim Preserve tempList(uBound(tempList)+1) As PointType
            tempList(uBound(tempList)).x = result(i).x
            tempList(uBound(tempList)).y = result(i).y
        End If

    Redim result(uBound(tempList)) As PointType
    For d = 1 To uBound(tempList)
        result(d).x = tempList(d).x
        result(d).y = tempList(d).y
    Next i

See how simple it all is? And to think that you don't see it in more QB games.


Ok, so now you know how to implement line of sight into your games. Now you just need to go implement it! I hope you had fun reading my tutorial, it wasn't half bad writing it. Until next time...


Download a copy of this tutorial: LosTut.zip

Final Word

That's it for issue #17, folks!

Now, here's my dilemma: should I try to release another issue of QB Express by the end of the month? Technically, this is the DECEMBER issue, but it's so late in January that I don't know if I'll be able to get enough submissions to make a good issue for January. But then again, back in November, I released two good issues three weeks apart. So maybe it's possible?

For now, I'm going to go with YES! THERE WILL BE ANOTHER ISSUE THIS MONTH.

Why not? It doesn't hurt to try. If I don't get enough stuff for a decent issue, I'll extend the deadline. But for now...

Submissions are due by Saturday, January 28th. As always, send your stuff to pberg1@gmail.com.

We need EVERYTHING for this issue -- reviews, tutorials, news briefs, editorials, letters to the editor, etc., etc. So get your fingers to your keyboard and start writing!

I'll see you guys again in a few weeks.

Until then...END.


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