# QB Express

### Issue #14 ~ September 18, 2005

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

### In This Issue

Contributors

- Pete (Editor)
- MystikShadows
- Peter Lenz
- Lachie Dazdarian
- J.B.
- Rattrapmax6
- Josiah Tobin
- Torahteen
- Adigun A. Polack
- Daniel Verkamp (DrV)
- Matt2Jones
- The Awakened
- Deleter
- Moneo
- Syn9
- Wallace
- mennonite
- Seb McClouth

- Regular Columns
  - From The Editor's Desk
  - Letters
  - Express Poll
  - News Briefs
  - Gallery - FBTK Roguelike Compo
  - Awards
  - Comics - QB Horse Humor & Bobby The QBasic Maniac
  - Final Word
- Articles & Editorials
  - Review of Poxie by Lachie Dazdarian - Adigun A. Polack
  - Review of Poxie by Lachie Dazdarian - Daniel Verkamp (DrV)
  - Is QuickBasic Dead? - J.B.
  - Qbinux - Revisited - Seb McClouth
  - Review of TerraScape: Breakdown Velocity by Pieslice Productions - Lachie Dazdarian
  - Game Apathy: Another Symptom Analyzed - Deleter
  - It's Been A Dark Month, Hasn't It? - mennonite
  - Review of ASCII Scrolling Map Maker v2.5 by Rattrapmax6 - MystikShadows
  - My QBasic Story - Nathan1993
  - Searching For The Unknown - Lunatix: The Insanity Circle by Mike Snyder - Lachie Dazdarian
  - QB Horse Humor: How to Draw The Horse - Rattrapmax6
- Tutorials
  - Stylized Foliage / Clouds Tutorial - Josiah Tobin
  - Creating A Simple Spline Curve - Syn9
  - Metric Conversion Tables - Moneo
  - A* Implementation in FB: Part 2 - Torahteen
  - C++ For The BASIC Programmer - The Awakened
  - Ally Artificial Intelligence - Wallace
  - Database Design Part 3: Structured Query Language - MystikShadows

## From The Editor's Desk

### Written by Pete

Here we are again!

You know, it's funny. September 2005 has been by far the busiest month of my life. I have no weekends, no free time to speak of, and I'm down to about four hours of sleep a night. I'm running on fumes. But amid all of the hustle and bustle, I have actually become a much faster and more productive worker. This issue came together so quickly. I just set my mind to it and focused on getting it out in the miniscule time window that I could find....and here it is. I guess after fourteen issues, putting together QB Express has turned into a bit of a science.

Issue #14 turned into a great issue at the very last minute. On just Wednesday, two days before the deadline, I looked at the submissions I had and thought "this isn't enough... this issue will be practically empty." But then the submissions came roaring in, and I was pleasently surprised by the great selection of quality articles we got. After a month with no reviews, we have recovered and have a QB Express record of five reviews in this issue! That's quite an accomplishment, and I hope it becomes a trend. I feel that reviews are one of the most important parts of this magazine, and they came out in full force this month.

The tutorials and articles/editorials are also great this month. We even have two comics. Plus, for the first time in a many issues, we've actually had some proofreading. Peter Lenz volunteered to proofread about half of the articles in this issue, so you should be pleased to find that QB Express is missing many of the characteristic spelling/grammatical errors/typos that we usually find. Overall, it's one of the best issues ever.

But I don't want to keep you waiting (plus I want to get this out before my self-imposed deadline / time window runs out), so go ahead, have at it!

### 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!

-Pete

## Letters

### Letter From MystikShadows

Hi Pete, Arial is a great font choice in my book... it's a very clear, easy to read font. So you got my vote. :-)

Well, when you mentioned on the board that the magazine was half the size of QB Express #12, I was wondering what would happen to this #13 release. Well lo and behold, another outstanding issue. Looks like everybody pulled it off at the last minute and made, like you said, a very solid issue after all. Excellent work to everyone involved (err... me too ;-) ). You're right though, the newsbrief is one of the biggest part of the magazine, and that's exactly where you'd need help, I believe it. When I happen to find something I'll let you know. :-). But it seems others are better at digging out the news than I am. Seems I'm not always at the right time and place to get the news hot off the press. But whatever I do find out, I'll send you, no problem about that and I'll even format what I find into news briefs :-). Everyone that reads this should have my email by now srichard@adaworld.com (in case you don't, shame on you lol). If people that make the news, send me an email telling me about it, I'll be sure to create a newsbrief for it. I can't find them all that well for some reason (I always hear it from someone that heard it from someone, you get the picture lol, it's not news by the time I get it hehe). But if I get material, I'll be glad to turn them into newsbriefs. So people, start sending :-).

If you could, I'd like you to define and clarify what a newsbrief is. Now, if I see 3 projects, one is an idea that just got announced, a new project just getting started, one is a new release, and one is an request for help on a new or existing project. Would all three qualify as news briefs? Some I know; for example, when Los Monos Del Obos got formed as a group, it could have been announced, and other quite obvious news Items :-). When looking at potential newsbriefs do you draw a line somewhere as far as how developed a project is? Do you at least need a screen shot of a brand new game before you'll announce it or do you want to know about the game even if it's just a thought? :-) I think by clarifying this for everyone people might suddenly start to find a lot of "newsworthy" items they could send to you.

Na_th_an, what's to say about Na_th_an and his IF series. I've read so many RPG and IF tutors from your website, some were good, some, not so good. But it seems none of them was good enough to get me into game creation. That changed with Na_th_an's IF series. I thanked him on his own turf at thebasicnetwork, but now, with the contents of the 7th part of his series, I really truly need to let the QMunity know that Na_th_an's IF series has taken my whole understanding on IF gaming to a whole new level. All 7 parts of his series seem to just make sense to me, it's my kind of reading, well explained, to the point, interesting from start to end. It's exactly what I needed to read to really kick myself into gear on continuing to make some of the games I started a while back, before QB Express itself :-). Na_th_an, to me, is quite gifted in the art of putting thoughts into words, not just any words, but words that make sense, words that can really transmit an idea or a concept into a very understandable explanation. I don't usually print QB Express (unlike some other people I know... I don't want to mention names, but it's so damn tempting... Lurah! ;-) ) .... But I printed the IF series because I know I'll be using it often and referring to it. That is some quality knowledge in there and I just can't let that go unknown and unnoticed. To everyone thinking of making a game, you'll definitely want to read Na_th_an's IF (Interactive Fiction) games series from start to finish. Well at least to the 7th part. I for one can't wait to see how he'll put it all together and make it fit as intelligently as I know he will.

It's always amazing to see the news section. It's growing like weed, but in this case, it's good weed ;-). People are just busy creating things, anything and that's always a big plus side to a community. :-). and it seems today people are busier than ever creating ideas and porting QB projects to FB. Just what FB needs to gain popularity. That goes for the projects in your newsbriefs of course, but also all the libraries that are being porting for the compiler itself. FreeBASIC is gaining momentum and it's starting to gain online presence where it's needed to get it known even beyond the QMunity itself. For example, a PowerBasic programmer developed Jellyfish Editor. It was for PowerBasic but now he's putting in the effort to making it work with FB. That's awesome news in my book. Vic and the Development team are working really hard and the fruits of their efforts are really starting to spread. They deserve all the attention FB is getting :-). Great work guys.

Deleter's “Rant on Reality in Games” was quite informative. As for me, reality in games is superficial at best. I mean if you're making a game based on today's world, it wouldn't make much sense at throwing some dragons or something into the scene. I had a movie concept once about an adventures in all of the 10 known dimensions. and the only thing that would allow the viewers to recognize the main character through it's representation in all the dimensions would have been his watch. so yeah, perhaps one small detail that players can relate to would be more than enough realism for me ;-). Games should be a place where a player can escape to, a place where there are no laws, no order, no physics, a place where you could, ultimately touch and feel emotions, where dream and reality are but one. Where we can touch the intangible. No limits to imagination and no limits to creativity. :-). Did you ever want to hold Love in your hands? How do you turn something you feel into something you touch? Something you hear into something you can feel? Can you imagine that? There's definitely many ways to accomplish it (depends on imagination itself) and I'm sure all of them would be more than interesting to see. :-).

Adigun's website is a work of art in itself. He definitely deserves that award, I think even an illiterate person could spend hours looking at the graphic contents of the website. :-). He knows his graphics programs and knows how to make it all fit together quite artistically. Good job on the website Adigun. :-) Rattrap's coding efforts, what can I say, like you said he's really being productive. So productive, he's now an official contributor to http://www.ascii-world.com :-). He did so many ASCII related projects, in such a short time, that no matter how you look at it, I think he's gonna need a new keyboard soon ;-). his must still be steaming from all his work. That's how you better yourself at something, sit down and make it happen and that's all I've been seeing Rattrapmax6 do these past months. he deserves nothing less than that programmer of the month award in my book. Good work Ratt and your FreeBASIC tutorial was very well put. Keep that up too. And great job on his screensaver tutorial too. :-).

I gotta say that I really enjoyed Wallace's “Enemy Artificial Intelligence” it offered quite a different way of looking at enemy AI all together. It was very well written and easy to follow and understand. Great work there Wallace. Looking forward to reading more of your material. I also think that Torahteen's A* implementation was interesting. If this first of the series is any indication to what's up ahead in the future release in the series, it promises to be quite interesting. I always love any AI that gets thrown at me, I always like to reach the limits of those AI and see what they can really do. So great work Torahteen, can't wait to read the next part :-). Same goes for his Evolutionary Programming. That too really caught my attention. I really like his way of presenting this concept. And I can't wait to see where and how he's going to apply it.

Moneo's date and time functions, I believe, will be used quite often. In Visual Basic, date functions can almost be taken for granted. But in the world of FreeBASIC and QuickBASIC, there's not much to work with as far as date and time are concerned, I really appreciate his effort in presenting these functions to us.

What can I say, it's a definitely solid issue, and well worth the extra day or two of waiting. From the table of contents, it looks like any other issue of QB Express, not shorter, and definitely an awesome read. :-).

> MystikShadows
> Stephane Richard
> srichard@adaworld.com

> Thanks for all the great feedback.

> I really appreciate you helping me with the News Briefs, and I wish more people would join you. Writing up news briefs takes forever, so I appreciate all the help I can get!

> Now to answer your question over what is "newsworthy" and what is not:

> I guage whether a news item is "newsworthy" based on whether it's interesting to me, and whether I think it will actually pan out. A lot of announcements are made in the QB/FB scene that simply aren't gonna go anywhere, or that nobody will care about. Every newbie in history has made one or two posts announcing their epic new (vapor-ware) RPG, but unless they have something to show for it, I'll ignore it.

> I tend to give higher credence to news posts by more established/experienced members of the Qmunity. If V1ctor or lillo makes an announcement, I will almost certainly feature it in QB Express, but if Joe McNewbie makes a similar announcement, I'm most likely to ignore it. I almost always ignore posts asking for help on a project, because that's another way of saying "my project is doomed and I can't do it on my own". Almost every project that's ever had a post asking for anonymous help has not been finished.

> Here's the most general rule of thumb for newsbriefs: something is newsworthy if it announces that something new has been created, and the news poster includes something to show for it -- whether it's a screenshot, a downloadable program, or a website. If there's no *content* to back up a news announcement, it's most likely not going to pan out.

> Hopefully that answered your question!

> -Pete

### Letter From Matt2Jones

Sir,

Okay, this has been eating me up inside so I'm gonna spit it out.

12 months ago I came back to the Qbasic Scene after about a year and a half long absence, where I spent most of my time on RPG specific boards, populated mainly by C++ coders. After a while I became so fucking sick of the bullshit that kept spinning around there, like the intollerant behaviour, that I stopped posting on the boards altogether. Of course, this was in pre-FreeBasic times (I just wanted to say that), so unless you were using C+Allegro at a minimum there were guys there who considered you worse then shit. I happen to enjoy the physical act of coding in Qbasic more then in C, it doesn't mean I think it's a better language, but that didn't stop 10,000 posts on the subjects of why I, apparantly, do. And when I say C+Allegro minimum I mean fucking minimum, I remember guys who went fucking nuts unless shit was done in the most religiously Object Orientated manner, and nothing else would do, just acting like 'I don't have time for anyone who doesn't code in my specific way'. It's everyone's right.

Slowly, I found my enthusiasm for the communities had decayed, and I never returned.

After a year of no programming I wandered on Pete's New Petesqbsite, and was sucked back in. The most amazing thing of all was how TOLLERANT everyone was with each other. I remember posting on this fact a while ago, to be greeted by understanding laughs, and told I'd spent to much time hanging around C coders. It was true.

Last night I read a post on one of the QB/FB community boards that really fucking sickened me. People complain about guys spamming every fucking thread on a board to get their post counts up, but it seems that that's the only way to do things around here. Unless you have >100 posts no-ones gonna listen to you, no matter how legitimate your post is. The attitude seems to be, if a guy has a few posts, he must be a newbie, so he must be an idiot, so I flame him.

I'm all for destroying the guy who enter's declaring his greatness and his grand ambitions and orders us to line up and work for him, but I'm up for destroying him whether he types in block capitals with his elbows or whether he writes pure fucking poetry. It sounds like many of you would flock behind the banner of an articulate con-artist, as long as he kept to a formatting you like. It's what he says, not how he says it, that means someone is a retard. But many of you seem to be caught up in a such a superficial view of things, that you don't (by your own admission) bother to read a post before you rip the shit out of it.

But whatever, mistakes happen, maybe the guys were having a bad day. I've certanly vented my anger on people who don't deserve it before. But if someone then comes in and tells you to SHUT THE FUCK UP, because the dude is asking a real question, you don't respond with the pitiful arguments like I'd seen and expect to ever be taken as a individual capable of cognative thought again. There's nothing more pathetic then people trying to justify mob-mentality as if it has some kind of divine purpose (for further study, see: Religion).

On the whole, the entire scenario made me feel like I was back the the C++ coders in a world where I could never stop watching my back or I would be knifed to peices.

This letter is not a childish threat to say I will leave the community if shit doesn't change. I won't, but I wouldn't pretend it would make a difference even if I did. I am also not going to threaten you with a mass-exodus of like minded malcontents (a silent majority of support, if you will), because that won't happen either. All I'm saying is if things keeps going this way, and people in a position of respect can't pull off the act of having an IQ of over 40, then this place is going to turn to shit, and we're all going to have misreable lives here from now on.

The good feeeling you get from the Qmunity, coupled with coders who are willing to help, is one of the main reasons it's thrived. Quite simply it won't die because it won't kill itself. That won't last if you all turn into the bitter, superficially-cynical, pensioners, with ungodly egos, I've had the displeasure of witnessing. Earlier in the week I got angry at a guy because he impinged upon one of the few area's of my life I hold absolutly sacred. The Qbasic Scene is the other. Don't fuck with the good shit we have, or we will have fucking nothing.

matt

> Matt, I'm familiar with the incident that you're referring to an I agree with you completely. The reason why the QB / FB community is so darn irresistable to all of us is because of just that: it is a community. It is a group of people that (generally) get along, work together, help each other out, chat and enjoy each other's company. It's also a group that's open to new members, even if they aren't the best programmers in the world. I have never found another community on the Internet that is so open, accepting and encouraging. That's the reason why I brought my website back, and that's why I do QB Express. It doesn't matter that I don't really program in QB / FB anymore -- I'm in it for the benefit of the community.

> So when a few people start arguing and treating others like crap on forums, it really goes against the spirit of the entire scene. People get angry and feel rejected, and then they not want to be a part of the Qmunity. It's incidents like these that led to QBasic News getting shut down a few months ago -- a few too many angry forum posts set the wheels in motion, and it nearly tore apart the Qmunity. I'm glad that we survived through it.

> Anyway, I wish the few flamers and lamers on forums would just shut up, instead of rudely assaulting everybody else (the people posting about, you know, programming). If you're not going to be nice, we don't want you hanging around.

> -Pete

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

## Express Poll

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

### How often do you code in FreeBasic?

How Often | Votes | Percent | Graph
Every day | 8 | 17% |
Several Times a week | 14 | 30% |
Once a week | 1 | 2% |
Several times a month | 2 | 4% |
A few times a month | 2 | 4% |
Once or twice ever | 6 | 13% |
Never | 14 | 30% |
47 Total Votes

> Now that FreeBasic has been out for nine months, I thought it would be interesting to find out how many people have tried it, and if they had, how often they use it. The majority of voters are true FB fanatics: they code in FB either every day or several times a week. The other biggest majority is people who have never even tried FB -- another almost third of total voters. The rest of the voters were from occasional FreeBasic users.

> These are exactly the kind of results I expected from this poll. There are quite a few FB afficionados that can't get enough of FB programming, and they certainly made their voices heard. These are the people that post on the forums every single day and make the rounds of all the QB/FB sites on a regular basis. They also make up many QB Express contributors.

> And then there are the people who, for one reason or another haven't tried FreeBasic. Some of them are just lazy. But some people refuse to try FreeBasic. Instead they prefer to program in the old-school DOS / QB environment (and unfortunately make programs that none of the rest of us more modern users can't run). I don't understand it: it's the same damn language, just made better in every way. But then again, I don't understand a lot of things...

## News Briefs

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

### QB Site News

V Planet! Finally Restored

  The greatest QB reviews site to ever grace the Qmunity, V Planet!, is finally back to its former glory. After much poking, prodding and begging, new webmaster Joe King gave us what we were asking for: the old content back. You see, while V Planet! has been undergoing a massive redesign over the past year, the majority of the old reviews and news archives had been inaccessible. But luckily new webmasters Joe King and Fishstix finally gave us what we all really wanted:

  > Joe King wrote:

  > "After Nekrophidius handed control of the site over to Joe King and Fishstix, things haven't been going too well. Originally, my plan was to restore the old site whilst we work on the new site. For some reason we decided not to do that, but rather not update until the entire new site is done. Well, after a few months of virtually nothing getting done, the community's been urging that, if anything, the old site should be restored.

  > "VPlanet will continue to update on a regular basis with articles and reviews."

  The restored V Planet! features a slight redesign, as well as a few new articles by Joe King. Additionally, the V Planet! message board has been restored after being broken since sometime late last year.

  Joe King is working busily to finish the new CMS and to convert all the old V Planet! content to the new layout, but right now he's found that he's a bit of a lone ranger. At the QBasic News forums, he posted: "As of right now this is just Joe King Planet, for it to truely be VPlanet then it needs a management team of members from around the QB/FB community. If you want a job as a reviewer or article writer (or both), then email me at goathell2000@hotmail.com. QB Express encourages you all to join the V Planet! staff and help bring the site back the top of the QB world.

Alexander M. Prado Launches AMP Software

  A new website by Alexander M. Prado called AMP Software has recently been launched. It is apparently hosted by the Data Components QBasic Network. This small site has a few QB projects. MystikShadows has more:

  > I have just received a link from a member of Jacob Palm's website about a person he knows [Alexander M. Prado] that has a website which has QB (and other) related contents. Namely, QB Objects which is his creation. He was going to sell it but went the freeware direction instead. The website has quite alot of projects in more than one language, some DOS and Windows applications are featured but the big taker there is the QB Objects library available.

  > I'm trying to see if there's anything new there I emailed the fella but apparently he can't check his email too often... so I don't expect an answer too soon from him but when I do know, I'll let you know. :-) If not, might be interesting to mention the website anyways even if it's not a newsbrief per se.

  > This is MystikShadows reporting for QB Express (Always wanted to say this lol).

Pete's QBasic Site Battles Spam

  For the past several months, my site has been bombarded with spam posts from a single Texas Hold'em Poker / Cialis / Viagra / Phenteremone spammer. The spammer took advantage of the ability to anonymously submit "QB News" articles to be posted on the front page of the site. Last month, one spam attack corrupted the site database which keeps track of almost all the content in all the main sections (links, downloads, news, etc.). Luckily, I had a backup and the content was restored, minus a few of the most recent submissions.

  This month, the spam attacks became like clockwork. Ten to twenty posts would come per day, spread out evenly. After several attempts to prevent the spam without affecting the legitimate users, I finally decided that I'd had enough, and completely blocked all guest posts to the QB News on my site. This solved the problem -- there hasn't been any spam since. But there also haven't been any QB News posts. Oh well.

ASCII-World Forums Restored

  MystikShadows and Lurah's ASCII programming site, ASCII-WORLD has finally had its forums return. For the past several months, the ASCII World forums were a popular outlet for programmers who were interested in making games and applications that use no graphics and just text characters. When the site switched servers recently, the site was no longer able to access the old forum database, and as a result functionality -- and all the posts -- were lost. Now the forum has been restored, but it was restored in an empty state, with no users and no posts. So if you're a member of the ASCII-World community, go sign up and help restore the forums back to a bustling community!

### Project News

KENTAURI Unleashes Poxie

  KENTAURI (aka Lachie Dazdarian) has released a new game called Poxie and it's the first KENTAURI game written in FreeBASIC.

  Poxie is a 2D action game combining pacman and platform game concept, featuring vertical scrolling, 256 colors graphic and Sound Blaster sound effects and music.

  Poxie is very similar to Panic Vicious, a QBasic game released 7 years ago.

  Here are some of the game's features (quoted from the KENTAURI website.)

  > - 6 stages each with different background graphic
  > - 3 worlds(2 stages per world) each featuring it's own enemies and foreground graphic
  > - 6 types of enemies
  > - 2 types of enemy AIs(movement algorithm)
  > - several layers of animated graphic
  > - ability to play the game in full screen and window mode
  > - ability to play the game in stripped graphic mode (no dizzy background and animations)
  > - game ending worth being mentioned

  Poxie has already had two reviews, both featured in this issue of QB Express! Check them out here and here.

  This is MystikShadows reporting for QB Express ;-) I just love saying that.

Zero G Academy Races Along

  Syn9 is well on his way on FB follow-up to his hit QB racer, Zero G. For Zero G Academy, Syn9 is pulling out all the stops. He has created an extensive devlog which includes shots from the game's various modules, as well as renderings of ships and space highways. Syn9's also released an OpenGL demo of his racetrack engine, as you can see from the road screenshot below. All in all, some very impressive work!

FBIde 0.4.2. Released

  VonGodric has released the latest version of the best FreeBasic editing environment: FBIde. Version 0.4.2 has many minor improvements over the past version (released last month), which you can read about here. To download FBIde or the latest package of FBIde 0.4.2. + FB 0.14b, visit the official site: http://fbide.sourceforge.net

Quake in FB?

  Oz has started a project entitled "The FreeBasic Quake Translation Project" which aims to, well, translate Quake III to FreeBasic. The groundbreaking first person shooter was originally written in C, and Oz hopes to port the entire game over to FreeBasic from the freely-available source code. Currently there is a document entitled "FreeBasic Quake III Source Translation Standards" which explains some of the conventions / semantics that will be used throughout the project. This project is still in the early / vaporware stages, but it sounds very interesting. Check out the official site or this forum thread for more details.

Attack of the Kilotwerps!

  Deleter has create a game recently that I believe is worth the attention of a newsbrief. He didn't name his game yet but here is a description in Deleter's own words.

  > "You(the green circle) are the hungry Tera-mamoliny, largest organism of the Bitbytenibble world. You must eat the dynamicaly electrode infused megachow(blue circles) in order to survive. However, the kilotwerps(red circles), are selfish little buggers whom--when they take time out from there random dancing moves--want nothing more than to irritate and then eat you. Luckily, you have the peta-blast on your side(left mouse button). One discharge of this power packed punch and they'll be sorry they ever messed with you. :D You progress to the next level once you have eaten the required amount of mega-chow. "

  It's getting great comments from everyone. Check it out at this FreeBasic.net thread.

  MystikShadows reporting for QB Express :-)

  UPDATE (by Pete): Thesanman112 has released a modified version of Deleter's game, which you can check out at this FBTK thread. I'm not sure what the changes include, but at least one of them involves the word "FIRE" in big, red letters -- so it must be good.

FreeBasic Compiler Testing Version v0.15b Released

  On September 10th, V1ctor released the newest version of the FB compiler: Testing Version 0.15b. Yummy! Get it at FreeBasic.net.

Simple ASCII Drawer by Lurah

  Lurah has been a busy individual. He's been working on a little project of his own. He calls it SAD (Simple ASCII Drawer). The name is pretty much self explanatory. it's main feature is it's the first Linux ASCII Drawer made in FB.....It should also work for windows as well only it will need to be compiled for windows.

  It was made with simplicity in mind and does a good job at what it does.

  Here are a few more screenshots: http://www.geocities.com/roope00/sad/

  This is MystikShadows reporting for QB Express ;-).

FreeBASIC Winsock TCP Chat Program

  Cenozoite has posted a very useful sample program / tutorial on using Winsock in FreeBasic. It is a "small and simple, direct client-to-client two-way simultaneous chat program using Winsock TCP in FreeBASIC for Windows." A very helpful read for anyone wanting to make networked applications or games in FreeBasic.

Nekrophidius Releases PTCXL 1.1

  Nekrophidius's FreeBasic graphics / sprite library from late last year has gotten an update. It features many sprite and font routines, including some very useful alpha blending and sprite buffering options. Here's Nek's very own description of this library:

  > "This is the same PTCXL I released back in December of last year with a few changes...plus modified to work with the latest stable version of FB. PTCXL, for those who don't know, is an extension of TinyPTC which adds some basic game-related functions like sprites and image handling, as well as line and ellipse primitives. It's still a little buggy and isn't tested or debugged enough but it's pretty decent and I've used it in a couple of games already (Killers FB and Phantasm). When gfxlib2 was developed, PTCXL still had a speed advantage over it but since I've been out of the FB loop for so long, I dunno if it can still compete or not...but check it out anyways if you like. :)"

  You can get PTCXL 1.1 at this link: http://fb.nodtveidt.net/ptcxl11.zip

FreeBasic Screensaver Kit

  Jofers has put together a very handy "kit" to turn your FreeBasic graphics demos into Windows screensavers. This kit dumbs down the process of making an FB screensaver and simplifies everything. Since graphics demos seem to be the most popular type of program to come out of the FB scene in its first year of existence, I think that this kit will be an instant hit.

  You can get a copy of the FB ScreenSaver Kit at this address.

  Oh, and make sure you check out Mambazo's "Doodle" demo that comes packaged with the kit. It's really friggin' awesome.

Phat Kids Reunite and Kids of Karendow Chapter 2 In The Works!

  The Phat Kids, the guys behind the hit QuickBasic RPG Kids of Karendow are back together, and ready to take the FreeBasic scene by storm! Blair of the Phat Codes posted the following on the FreeBasic.net forums a few days ago:

  > For those of you who were around in the qbasic community about 5 years ago might remember an RPG called Kids of Karendow. For those of you know, we split the game up into multiple chapters and we never completed chapter 2.

  > Today I announce that Kids of Karendow is coming back. The old Karendow source code will be compiled in Freebasic and the game will be continued (and improved, a lot) from the existing code. It will be the entire story of Kids of Karendow told in one game.

  Blair's post was met with a warm reception of eager fans. Everyone still remembers Kids of Karendow, which is the third-highest rated QB RPG in V Planet! history, with a score of 29/35. When it's released, the FB remake of Kids of Karendow is sure to be a big hit...and you should all look forward to Chapter 2 of the epic (and hilarious) KOK storyline. Personally, I can't wait to see what the Phat Kids release next. Judging by their track record, I'm sure it will be pure gold.

  UPDATE:

  Right before press time, I got the following press release from Blair:

  > Hello,

  > As I imagine some of you have already heard, Phat Games and Kids of Karendow will be making a return to the independent video game development scene. Today, I am going to let everyone know some of the details of this new Kids of Karendow project.

  > Thanks to FreeBASIC, Kids of Karendow will have new life breathed into it. In a matter of a few short weeks, Phat Games will re-release the very original Kids of Karendow Chapter 1: The Dawn of a Revolution compiled in 32 bits. This means that many people who had problems playing the original in Windows XP will no longer experience these problems. Once this conversion is complete, Phat Games will then begin the work on a project tentatively titled "Karendow: Revisited".

  > Karendow: Revisited will include the following:

  > - The complete story for Kids of Karendow Chapter 1: The Dawn of Revolution and Chapter 2: From Dusk to Darkness
  >   - The story will be flushed out A LOT. There will no longer be random events strung together simply for furthering what little story line the game had. Kids of Karendow was and still is primarily known for it's vulgar humour, and strong musical score. While the music will remain (and even improved with the addition of a number of new tracks originally written for Kids of Karendow 2) the vulgar humour will be toned down and the story will be strengthened a lot.
  >   - The history of the Karendow nation, the world (unlikely to be called Gon-Airia), and all the characters will be flushed out and brought to life in many different ways.
  > - Enhanced 32 bit graphics
  >   - I am not promising a complete redesign of every sprite and every graphic, but we will bring you some enhancements to graphics.
  > - An enhanced battle engine
  >   - Kids of Karendow had a very strong battle engine, and changes will be made to make sure this battle engine is improved upon. The style will move slightly away from a Final Fantasy feel and more to a Phantasy Star feel without any loss to the strategy or pace the battles had.
  > - More mini games
  >   - Kids of Karendow was also well known for it's mini games. There will be more of them; need I say more?

  > Phat Games welcomes any comments and criticisms you may have. Should you want to get in touch with us, or if you have any questions, please e-mail PhatGames [at] gmail.com

  > Blair

  > Phat Games

Doctor Who?

  Marinedalek has created a cool graphics demo that mimics the slit-scan effect used in the old Dr. Who opening credits. And it looks great. Here's some more info from marinedalek:

  > "I have to admit that I'm something of a Doctor Who fan, and I've always been fascinated by the Tom Baker opening credits with the famous "Time-tunnel" slit-scan graphics.

  > "To replicate this effect I've written a program that takes a bmp as a mask and creates a virtual 3D tunnel from it. Onto the sides of the tunnel is then projected a bmp texture that scrolls, giving the impression that you are travelling down the tunnel.

  > "I also have a very similar second program hardwired for cylindrical tunnels as this produces slightly better image quality."

After creating the program, mareinedalek used it to generate a replication video of the old Dr. Who closing titles. Check out the video. Very cool!

Wizardry Style Maze Game Source Released

  Stevens522 has released the source code / demo of his Wizardry-style maze engine, called WizClone. It is just a walk-around engine with a few enemy encounters (but no actual battle engine), but it could easily be modified to be a real game. Maybe someone in the FBTK Roguelike Compo could turn this engine into a cool game.

  You can download the source code (along with a compiled version of the game) here: WizClone.zip. Check it out if you're interested in mock-3D dungeon crawlers like Wizardry or DarkDread's QB game The Legend of Lith II

Phantasm Back In Development

  Nekrophidius has begun work again on Phantasm, his traditional FreeBasic RPG with beautiful graphics. This game, which was started during one of SJ Zero's 24-hour FB coding competitions, was abandoned when Nek decided to drop all of his FB projects and focus on coding TurboGraphix games. Although he has only done a few hours more work on the game, it's coming along very nicely. Check out the screenshot below. If you'd like to see more, visit this post.

AAP Announces AFlib2

  Adigun A. Polack recently announced a new FB graphics library called AFlib2: "For those of you wondering about RelLib to be ported to FB, then hey, better look no further! ^_-=b I am so truly and generously proud to introduce to you a preview of what could well be the most talked about “8-bit graphics library”-based wrapper for Angelo Mottola’s GFXlib2: AFlib2, or Aura Flow Library 2, based upon the potentially many original implementations of RelLib from QB itself, straight to FreeBASIC!!!"

  AFlib2 already features routines for Translucent Pixels, Translucent Filled Boxes, Wu-lines, Wu-pixels and five custom 8x8 fonts with italicization and scaling features. But as Adigun says, "we are *only* warming up!!! Future versions will include more 8-bit sprite routines (translucent-, one-color-, and collision-based), as well as 8-bit gamma sprites, 8-bit sprite scaling / rotation ala the CosmoX QB library, 8-bit screen smoothing / anti-aliasing, and 8-bit water effects ala RelLib 5.0.

### Competition News

FieldView Encryption Challenge Winner

  Z!re, developer of FieldView, recently ran an Encryption / Decryption Challenge for the game. Here are the criteria for the challenge:

  > Description:
  > Create an encryption with an accompanying decryption algorithm. The functions will be used in Plantasy Studios upcoming game FieldView, proper credits will ofcourse be given.
  > Rules:
  > - Should be fully compatible with latest official version of FB (This does not include pre-releases and/or CVS builds)
  > - Resulting encrypted message should be as close (or smaller) in lenght to the original message as possible. 1:1 (or less) encryptions are favored.
  > - Should finish within a reasonable time, meaning 5-10 milliseconds or less for 200byte messages
  > - Functions should be formated as: Function (Msg As STRING, Pwd As STRING) As STRING
  > - Multiple entries are allowed, and encouraged
  > - The routines should be able to handle any ASCII char from 0 to 255

  The challenge went on for over a month at the QBasic News Forums, and get quite a few entries. Here are the official results, courtesy of Z!re:

  > Winner: Deleter
  > Valid entries:
  > BlueKeyboard: 46ms
  > Red_Marvin: 48ms
  > Neo: 65ms
  > Neo: 107ms
  > Neo: 651ms
  > Deleter: 178ms
  > BlueKeyboard: 760ms
  > The time is for one message, average length of ~600bytes. Random message and length, random password and length.
  > Disqualified entries:
  > Whitetiger0990
  > Dark_Prevail
  > Dr_Davenstein
  > Cha0s
  > Dumbledore
  > Program used for testing: http://fieldview.mine.nu/Tester.bas

  Hurrah for Deleter, winner of this challenge!

FreeBASIC Ultimate Demo Compo Ends September 30th!

  Entries for Adigun A. Polack's FreeBASIC Ultimate Demo Compo (FBudc) are due by September 30th -- less than two weeks away! This compo, entitled "The QuickBASIC Demo Stikes Back!" challenges programmers to create the best FreeBasic graphics demo they can, now that the QB demo scene has evolved to its 32-bit cousin. So far there is one official entry to the competition: "Keftedes" by Optimus. But don't let this be a one-demo race! Enter the compo and impress us with your spectacular graphics coding!

FBTK Roguelike Compo Thrives

  ...And the award for most under-covered Qmunity news story in QB Express is: the FBTK Rogue Compo!

  Seriously, this competition, to create a full "roguelike" game (dungeon crawler), is big. There are over a dozen teams signed up for it, and new demos are getting released left and right. It has its own FORUM over at FBTK... and it gets a ton of posts. Unfortunately, the fact that there are so many posts means that I can't really sum it all up in a newsbrief (and reading all of those posts and then trying to make sense of it all would just take too long). So I suggest you just head over to FreeBasic.tk and check it out for yourself.

  I've been hoping an FBTK member that's more "in the know" than myself would write up a little article to tell all of you QB Express readers more about the compo, the contestants entered in it, and the game demos released thus far... but nobody's taken the bait. With a bit more poking and prodding, maybe next month... Until then, check out this month's gallery with a bunch of random screenshots from various work-in-progress games being made for this competition.

  (The awesome screenshot you see to the right is from Dr_Davenstein/Team Dr_Zappo Inc's entry.)

Have news you want reported in QB Express? Send your News Briefs to: pberg1@gmail.com

## Gallery - FBTK Roguelikes Competition

### Written by Pete

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

Since I didn't find a good program to preview in this month's gallery, I decided to do a massive preview of as many FBTK Roguelikes compo entries as I could find in a half hour of skimming through the FBTK Rogue Compo forum.

FreeBasic.tk has been hosting its Roguelike Compo for over three months now, and a lot of progress has been made by all of the contestants. I don't have time to research and write about each of the entries, but here are a bunch of screenshots of all the demos I found. Enjoy!

### Team Rick (rdc) - Deep Deadly Dungeons

http://www.fbtk.net/phpBB2/viewtopic.php?t=495

### Dumbledore's Army of Roguers

http://www.fbtk.net/phpBB2/viewtopic.php?t=518

### Jocke The Beast - BeastRogue

http://www.fbtk.net/phpBB2/viewtopic.php?t=517

### Zap and Dr_D - Team Dr. Zappo Inc.

http://www.fbtk.net/phpBB2/viewtopic.php?t=486

### Two Man Show Kizec

http://www.fbtk.net/phpBB2/viewtopic.php?t=729

### Team LGG - Xerol

http://www.fbtk.net/phpBB2/viewtopic.php?t=478

### Team Ryan - *Nayr rof Etov*

http://www.fbtk.net/phpBB2/viewtopic.php?t=487

### Team Zweimann

http://www.fbtk.net/phpBB2/viewtopic.php?t=483

### Team Spam Kings

http://www.fbtk.net/phpBB2/viewtopic.php?t=493

Visit the FreeBasic.tk Roguelikes Compo Forum for more!

## Review of Poxie by KENTAURI

### Written by Adigun A. Polack

Our next FreeBASIC game up for review is a brand-new one that has JUST NOW been released by the great Lachie Dazdarian and it is called Poxie, a promisingly interesting little hybrid of Pac-Man and a platformer. Lachie has been such a mastermind behind such QuickBASIC classics as Rocket Fuel Mayhem, Ball Blazing Fantasy, and the superbly-played (yet unfinished) game that was created for Nek’s own Space Invaders compo entitled Evil Baron Lachie, but, will how will his very first officially released game in FB fare on my review table? Let us find out as we go along, shall we?

### G A M E • S Y N O P S I S :

When the game launches, you are taken immediately to a title screen where you can start the game, view the instructions on how to play, display the top scores, and some other stuff. Not bad here! !

When you start the game, though, you are given a nice little stage introduction telling you what the name of the stage is called and the simple clear objective that you must successfully meet in order to pass on through, which is kinda like the old original ‘80s arcade games you used to play (Namco’s Super Pac-Man and Universal’s Ladybug would come to mind here, even if you can remember them! ). Then once you press either “Enter” or “Space”, the dash is on!!

Do not forget, the character you control is a greenish tall little creature, and you have to indeed collect all of the items in a stage to get through. Throughout the game, you will be challenged with six (6) types of enemies, including the medieval armoured knights with swords, as well as some Eskimo-like characters with sharp fishing poles (you *sure* wouldn’t want to be stung by the front end of the poles themselves, believe me! ) Also, there are certain power-up and point items to aid you here, and they are:

> 500pts ::: Gives you 500 points, of course!
> 1000pts ::: Nets you a bonus of 1,000 points when gotten!
> Slow (marked with a snail) ::: When picked up, it slows down your enemies for a temporary period of time, giving you the advantage!
> Jump ::: Simply teleports you out of a current stage of play and skips you right to the next! A *really* handy item if you run into some big trouble!!
> 1up ::: Reels in one more extra life to add to your totals. VERY important!!

.....and remember also that the items will disappear after a short time period, so be wary here.

One word here about the platforms on the left and right sides of the playing field at ground level: if you are in hot pursuit of the enemies trying to wipe you off, use those little trampoline-like things to escape danger and potentially on to safely! The catch is in the direction you want to go while bouncing up, not down. Bear in mind that when the enemies use the platform with you while bouncing, you will not be harmed during that time. This part I am talking about is such a wonderful throwback to the days of Namco’s 1983 arcade game Mappy, and I like that very much as it is so splendidly captured here!!! =b !

Continuing with the platforms, the only sheer danger to them is that when one of them turns red from your continued bouncing, DO NOT get use that platform again at that point because one more bounce on it can actually throw your character off the playing field, costing you a life! However, the only way that thing can return back to its original color again is to simply take the opposite platform. Lachie has devised an excellent little strategy with the platforms themselves and the way they are designed for, adding a real depth of extra challenge and even dexterity to the game itself! Truly impressive, really, and this deserves some extra points right there!! (^_-)//

### T H E • B R E A K D O W N :

First off here, the gameplay of Poxie is originally intended to be a marriage of Pac-Man and a platform game indeed, and it pretty much shows its stuff here because this game does *quite* a good job at that, to be honest with you! ! The look of the graphics are the usual “Kentauri” style that you come to expect from Lachie himself, just like in Ball Blazing Fantasy and Rocket Fuel Mayhem and some others, and there is nothing wrong with that and the style of play as well, because gameplay matters more than just pretty graphics alone, I believe!!

Speaking of which, the keyboard play control is REALLY right on target here, with the simple taps of the left and right arrow keys that you will be using to move your character left and right, respectively. The way the game moves may be very slow at first, but do not let that fool you, ‘cause as you keep on playing (even going to the later stages!), it will end up growing on you just as it did me!

Talking about the graphics a bit further, Lachie has made the water and lava into parallax-like flowing rivers as you go rather instead of them going just in the same direction and speed, and the way your character eats and thereby leaving apple cores and chicken bones and other mostly eaten stuff to be thrown out is truly so masterfully well done, giving Poxie a more realistic arcade feeling in a whole new way in FB!! ^-^=b And some simple custom-programmed scaling apparently is used on your character mainly when he dies and gets thrown off the screen, let us not forget.

The amount of music here is very limited; however, as for the sound effects, from the “gulp” sound your character makes when eating to the “EEEK!” and slapping noise you encounter when you lose a life, they are *very* good here and are used well. But more importantly — and here is the brilliant payoff, folks — the best part in this department has gotta be the ambient sounds..... HANDS DOWN. They range from the rushing water you get in the river stage, to the chirping birds in the forest, to the fire-kindling sounds of the lava and more....... it is downright so awesome stuff and some of the convincingly best I have ever heard in this interesting little game, without question!!! d==b !! (Come to think of it, apparently Lachie must have learned so well from the other FB game that used ambience effects also, entitled The Quest for Opa-Opa! Great for him!! )

The only problem is that this game has only six stages, making it too short. But let us face it, the rest of the areas really holds such a brightly burning candle and then a lot where retro gaming in FreeBASIC is concerned!!! Remember that! By the way, this game Poxie comes in two versions for you to download: the normal version and the no-sound version. And you can zoom right on over here to lead you to the versions themselves, too!

It surprised some of the minds of the QB45/QB71/FreeBASIC community that Lachie has made such an unusual move to release this game instead of the finished FB port of Evil Baron Lachie, which is shockingly the game that he said that he gave up on over at on Kentauri’s site just now. What a shame. ! HOWEVER, he got some great and high-quality tricks up his sleeve with Poxie, as it is without a shadow of a doubt the first and very hottest retro-like game that I have ever reviewed in FreeBASIC!!! !!

### T H E • F I N A L • V E R D I C T :

— 9.2 out of 10 —

As a short yet so phenomenally sweet ride in the style of such ‘80s arcade classics as Pac-Man and Mappy, Poxie is truly both a most pleasant surprise and such an intensely fun and challenging little game in FB in its own right, definitely!! My deepest congratulations to you, Lachie Dazdarian, on creating one of the VERY best FreeBASIC-created retro games to kick off the fall of 2005!!! (^_-)//

Download Poxie at KENTAURI.

## Review of Poxie by Lachie Dazdarian

### Written by Daniel Verkamp (DrV)

Poxie, created by Lachie Dazdarian of the Kentauri game design team, is a 2D game that pulls gameplay elements from Pacman and platformer games. The game concept is based on an obscure QB game called Panic Vicious by HUR.Poxie is written in FreeBASIC and compiled for Win32 operating systems. It features sound effects and music and detailed, animated 256-color graphics.

The entire game has been designed in a way that immediately evokes thoughts of the "golden years" of computer games. The low resolution and color depth combined with carefully hand-drawn graphics and well-crafted, carefully-placed animations, along with the delightful vertical parallax scrolling, put this game graphically on par with any DOS action game from the mid-1990s. This is by no means a point against Poxie; in fact, it is the highest praise I could give any 2D game. A few times, the colors used for the textual display or the characters coincided a bit too much with the background, making them hard to distinguish, but this is probably just an artifact of the limited number of colors available. The technical details are taken care of in a professional manner - the display is always smooth, with no tearing during scrolling, and collision detection is pixel-perfect. The depth of detail was very good for such a small game; for example, the way the stages are connected (the forest seen in the distance on the first stage becomes the setting for the second; the castle in the background near the volcano shows up in the subsequent stage; and so on).

The gameplay itself is relatively easy, but it takes a little while to get the hang of the concept. After a few times of playing, the game can become frustrating, mostly because it is possible to put yourself in certain-death situations without any recourse. There are also the times when a special item appears but, despite your best effors, you cannot reach it in time. That said, the simple gameplay requires a steady hand and a mind for problem solving in order to do well. This challenge, besides the graphics and audio, is enough to keep a player's interest in the game for a number of hours. There is no true "platforming" involved, in the sense of jump'n'run-style games, but the draw of the platformer still exists in this game, and gravity plays an important part.

The controls are minimalistic (only two directional keys are used) but certainly sufficient and in fact essential to the gameplay. The controls feel responsive and make sense intuitively.

Audio during the game is an essential part of the experience; playing to the sound of a gentle, flowing river or happily chirping birds adds immeasurably to the game's enjoyability. Well-mixed sound effects are used throughout the game when important actions occur. My only complaint here is the use of a sound effect that I am quite certain I heard in The Time Warp of Dr. Brain... if you ever played that particular Dr. Brain game, you'll probably notice it immediately, but regardless, it doesn't detract from the fun of the gameplay.

The game feels complete and polished. It is not long or complex, nor is it meant to be. All in all, it is what many game designers aspire to create: a finished game with a well-defined, unwavering purpose. Poxie knows what it is and doesn't pretend to be something else. The lack of any appreciable storyline is not important; this sort of game could only be made less enjoyable by tacking on a story after the fact.

Only once during testing did the game crash; I assume it was because of the "miscellaneous program crash" described in the readme. Also, there were a few times that I thought I was in the launcher area and supposedly safe but still triggered a death when touching an enemy. These minor details did not affect gameplay adversely.

### Strategy

In playing this game, I came up with a few simple strategies that I have distilled into (hopefully) helpful guidelines for other players. I encourage you to find your own strategies as you play the game and find how best to grab all of those items.

This falls into the "look before you leap" category - before you commit yourself to jumping from a platform, make sure that your new location isn't one of those particularly nasty two-tile platforms with an enemy under it, as shown in Fig. 1. If you find yourself in this position... well, let's just say a jetpack would be quite handy.

If you are on a platform above any other enemies, use your position to your advantage. The characters found in the first four levels can be easily manipulated into walking off platforms and falling to a lower level, allowing you a clear path for collecting items. Fig. 2 illustrates the concept on the Volcano stage, where your character begins on the top level. Patience is a virtue here, and since there is no time limit, there is not much of a point to rushing things when you are not threatened.

As the instructions say, the platforms are safe havens. Use them to draw your enemies away from the items you need to collect and keep them occupied. Note that you can usually stay essentially in one spot on the lowest platform (just keep alternating between left and right) before actually jumping on the launcher so that the enemies have a chance to catch up to you without using up all of your jumps. If timed correctly, you can keep the enemies at the peak of their bounces while you run off to collect items or move to the launcher on the opposite side.

### Ratings

> Graphics: | Sound / Music: | Gameplay / Fun Factor:
> | 8/10 | 7/10 | 6/10

> Overall rating:
> 7/10

You can download Poxie at www.kentauri.cjb.net. DrV can be reached at i_am_drv@yahoo.com.

## Is QuickBasic Dead?

### Written by J.B.

For quite some time, many computers have been able to run Qbasic only through custom made life support systems. With out modifications, the shiny blue integrated development environment coughs and splutters its way through the regular debugging process with as much dignity as a soprano making her way through the Lakme opera despite having throat cancer. Indeed it is admirable that QuickBasic, as a survivor of conflicting Microsoft policies, is capable of loading into modern systems at all. But beyond loading, with the minor miracle performed, it quickly becomes apparent that the BASIC interpreter is not particularly healthy. Like a fish out of water, Qbasic has been running out of oxygen ever since Windows 95 was released. The first signs of hypoxia were, for many, constant Blue Screens Of Death. At the time, we all blamed this on the Operating System. And with good reason.

But as windows became more stable, and Blue Screens Of Death became ever more rare, signs of ill health continued to show themselves. I blame some of these nuevo problems on the reckless coder "Angelo Motella". His ambitious use of mode X techniques and EMS memory in ‘Wet spot’ led Qbasic programmers to believe that they could actually make impressive looking games on the sick and dying platform. Later, his release of DirectQB meant that Qbasic programmers could actually make High Quality projects. Other libraries like directSound4QB gave access to the windows sound system, which incidentally led to the creation of DOS-Windows hybrid programs. Such programs would only work in systems that had both full DOS support and windows sound support. Despite this, and in an act somewhat akin to that of injecting stem cells into the brains of Alzheimer’s patients, Qbasic development went stratospheric overnight. The language wasn't just alive, it was hot, hip and damn attractive. But, like a prostitute with an AIDS infection, unexpected and unwelcome surprises were just around the corner. The increased useability of Windows meant that increasing levels of Newbies began to consider themselves 'computer literate' even though they often lacked basic PIF editing skills. This false sense of computer literacy caused much of the audience of QB games to bombard developers with emails titled "What’s the EMS error mean?"; "I downloaded the zip file but it doesn't do anything."; and my personal favourite, "SonicX destroyed my computer. I am going to track you down and KILL YOU."

Dealing with the frustrations of incompetent computer users was not a real problem. We just ignored them. But with the release of Windows XP, we became one with the frustrated. Unfortunately for us, with the hordes of nuevo 'computer literate' users dwarfing the number of Qbasic hobbyist programmers, MSDOS became irrelevant to Bill Gates' future plans of world domination. The MSDOS which remained in Windows XP was an emulated shadow of its former self, and suffocated Qbasic to the realms of uselessness. EMS began to erratically and unpredictably stop working for users who actually knew what the EMM386 batch command used to do. The interface with the shell command became irritatingly different. And meanwhile, those cool utilities like directSound4QB stopped working properly under XP.

New compatible versions came out, but it was too late and pointless. The real QB programmers refused to support Windows XP, and instead continued to use Windows 98. More reasonable programmers such as myself installed dual boot systems so that both operating systems were available. But even among the XP sympathisers, Windows 98, as the first love for many, was still the only environment used for programming. It was our oxygenated fish pond where we could give QB temporary relief from the hypoxia which left it suffocated under windows XP. But now it is time to face facts. In 2005, it has become clear that mainstream users of Windows XP can not run ambitious QB programs, ie ones that use EMS and hook into the windows sound system. It's over. Qbasic is dead.

But as all hope was lost, a saviour came along who would not allow the world to exist without QB. Victor has created the excellent FreeBASIC compiler which is 95% compatible with QB. Together with Vongodric's FBide, it seems that QB has entered a higher realm of existence. So, it appears that while a manifestation of QB is no longer with us, a far better and superior version is. QB survives in the form of FreeBASIC.

J.B. (creator of SonicX. Made entirely in QB)

Visit J.B.'s site QBasic Central.

## Qbinux - Revisited

### Written by Seb McClouth

“Do you want to know what Qbinux is? If you want to know, follow the kiwi-bird.”

Yes, welcome to my third (and hopefully not the last) article about Qbinux. As you might have read on the forum, (and if not:), there is some major stuff going on with Qbinux.

1. The implantation of Novix, actually implanting Qbinux into Novix.
2. The Setup-program, which you some of you already may have seen, if not, you can download it from QbxSetup. (Please note that you need a packing program that can unrar.)

#### Next thing:

At the present moment I'm working with the real thing: Linux. Windows XP doesn't let me on the Internet anymore and I found Linux to be real helpful instead. This also gives new ideas on what to do next with Qbinux, since I'm currently trying to install all sorts of useful programs.

#### Rearranging:

In order to make Qbinux look more like Linux, I've begun to rearrange all the files, in the appropriate files/directories as you might find them on Linux-core-directory. This is how the kernel source is arranged.

This means we currently have up to 7 directories, namely:

- FS Where the source of the NoViX File System residences
- INCLUDE Where the ASM-source and .bi files residence
- INIT Where the source of the initialization residences
- KERNEL Currently contains the rest of the source.
- LIB Contains the source and libraries for Qbinux
- NVXFS Which contains the filesystem
- TOOLS Which contains extra program e.g. Qbash

#### Current development:

Currently I'm working on the sourcefiles for NVXFS, short for NoViX File System, as I have called the file system. This is just extracting all the necessary NVXFS code from the other files and move into the appropriate files.

I've been able to extract a bit of the shell of Novix, and placed it into TOOLS/Qbash. Since Bash in Linux is an external program, I though it would be wise to extract Qbash from the sources. This also gives some freedom for adding some extra's to Qbash.

It doesn't work yet the way it should, so I have extracted the file system routines from the Novix source code and have tried to figure out how it works. This could mean that the release of the next version of Qbinux (editorial note: Core v. 0.0.6, and McClouth Qbinux v.0.02) will take some more time. I have been able to redo the original files/directories of Novix, so it seems like we have some sort of a working file system. This means we have a ßeta-release before the end of this week. It will contain a home-directory for the users and the root, and most important of all, the available core-source, where it should be. As soon as I get this version running, I'll be sure to post it.

I have to admit that Z!re did a great job on Novix. Even though she says it's junk code, I think it looks marvelous. If she would ever get to moment to build a real OS of Novix, I'll be happy to help her.

#### Make:

This should sound familiar. Yes, I'm also working on a Make-program to make it easier to install separate modules. I'm using some real Make-source and some made up. Because it is under the development, I won't give it out yet, but as soon as I have a stable version which can do the make-stuff, I'll be sure to let you all know.

#### Security:

Because of the success on the file system, this means we can actually work on the security codings. Since we need this before Qbash could run.

#### Qbash:

I removed the prompt-code from INIT\nvx25.ns5 and moved in into \TOOLS\Qbash. It contains also some real Linux code.

For the rest, nothing much yet. I personally think that a proper file system is important. When I have that finished I'll get to the drawing table for Qbash.

Bte,bte,bte... That's all folks (now you can hear in your head the end tune).

> Grtz>
> Seb McClouth

## Review of TerraScape: Breakdown Velocity by Pieslice Productions, 2003/2004

### Written by Lachie Dazdarian

### Introduction:

It's really difficult to make an introduction for this review. TerraScape. A 3D-flight arcade game in QBasic. Not a demo. Completely finished, polished and long game. A game that simply amazes and demands respect.

TerraScape was released in a really awkward moment for the QBasic community. At that time the community was slowly dying. Almost nobody was developing or releasing anything grand, remaining QBasic game reviewing sites were dead or disappearing and many people were giving up on QBasic for more or less justified reasons. There was one or two threads about TerraScape in the QBasicNews forum but TerraScape's quality was never properly recognized or awarded in a form or a review or some article in a QBasic magazine. But like I said, the community was in a really poor shape back then. Let's not name-blame. Anyway, Pauli Merilainen(TerraScape developer) is known for putting almost no effort in advertising his games. If I remember correctly he didn't even take a single screenshot of TerraScape and put it on the net. People want to know what they are downloading when the package exceeds 16 MB.

At the time TerraScape was released I was unable to play it and due the rather weak response on it I've pictured TerraScape as something with amazing 3D graphic but not very playable and user-friendly. Some complex flight sim, I thought. So I was quite surprised once I finally downloaded it. It was completely different from what I imagined. From professionally designed graphic, great 3D engine to easy controls. But after several hours spent playing it that old folk wisdom popped in my mind - it's not gold all that shines. :P

Nevertheless, the final verdict and my impression of the game is highly positive. Maybe I should start with the actual review now.

### Graphics: 5/5

Definitely the strongest part of TerraScape and the main reason why TerraScape should be remembered and respected. TerraScape was done in a quite uncommon graphic resolution for me, ModeX 320*400. I can assume that there are benefits of working in it, especially with this type of 3D engine. TerraScape graphic should be observed in two parts. The first one would be the 2D graphic(the title screen, the intro, the outro, the menus, the briefing screen and the status bar). The 2D graphic is done very professionally and with care for details. The intro and the outro graphic is very good, featuring a very distinctive style. The only notable flaw I see in the images featuring the main game character and those are the only places where a human character appears in the game. It is very obvious that the developer has a problem there and the drawing program he uses doesn't appear to be very convenient for drawing people. The title screen and the main menu is impeccable in style and quality. The status bar didn't sit well with me but maybe that's just a matter of taste. It looks too shiny and plastic to me. I would prefer one that is a bit more rugged. Just for the sake of atmosphere.

The 3D graphic follows the quality of the 2D graphic. The very 3D engine is state of the art in QBasic and doesn't seem to be crippled in any way. The terrain, the sky, it all looks great. Yes, the code is not pure QBasic but how much sense there is in demanding it to be pure QBasic when most of QBasic libraries use Assembler code? The 3D objects are also awesome. Very smart choice of textures and shapes. Still, the 3D graphic is not entirely even in the quality throughout the game. I can say that 3D objects and textures are the best in missions 1 and 2 while in the mission 3 you can already notice a small decline in the quality. It doesn't go terribly down but the last mission, compared with the first two missions, is evidently poorer in quality of graphic, from the ship designs to the structures and even in the choice of texture for the terrain. One structure especially looks bad in the last mission. Also, I wish the particle effects after explosions are more visible and complex. Overall, the 3D graphic is amazing. I never saw anything better in QBasic(talking about 3D graphic). These negative remarks are just nitpicking. Nothing that should lower my final score.

### Sound/Music: 5/5

Unfortunately Pauli Merilainen decided to use DS4QB2 for sound support which I personally hate. It's a 32-bit library which means it's not compatible with DOS. It also doesn't work in Windows 2000 and NT and in most cases not in Windows XP too, which is the situation with TerraScape too. What is also annoying is that most QBasic programmers didn't allow users to bypass DS4QB2 routines which made their games impossible to start in the mentioned Windows versions(and in DOS too). Luckily this is not the case with TerraScape. But there is still the problem of not many people being able to enjoy in TerraScape properly. Who has Windows 95/98 these days? Maybe there wasn't a better choice because of the high requirements that Pauli had for the sound but there is BWSB and the sound routines used in QBasic games like Groov Buggies, PromZone or Monkey Blast which are way more compatible with Windows. Since I was not able to start the game with sound turned on I can't score this section properly. Still, having in mind the rest of the game and the environmental audio mentioned in the documentation I can guess it's on the level of the rest of the game, meaning excellent. I was able to play the music tracks in Winamp and play the game in the same time so there was no problem in checking how the music works in the game. The music tracks range from good to excellent and Pauli took the trouble to compose ten of them. It is obvious that they are composed by an experienced composer. The tracks are far beyond my capabilities and since I've been trying to compose tracks lately I can appreciate Pauli's work even more. Original sound effects, environmental audio, original music tracks and ten of them. Admirable effort.

### Gameplay: 4/5

Pauli describes TerraScape as 3rd-person perspective flight arcade game, Raptor updated to 3D. There is probably a better comparison with another 3D game but since 3D games are not my thing I can't make one. I'm sure there is more than one game like TerraScape coded in some other language, commercial or not. The main thing you should notice is that TerraScape is a 3rd-person perspective 3D game which means you play it outside your spacecraft(called Avatar) and observe it from the back. You can rotate the camera but the game is meant to be played with normal camera position(behind Avatar). I have quite mixed feelings about TerraScape gameplay since some of the elements that make it are great while some other are not that great. The first aspect of the gameplay would be the controls. Avatar is terribly easy to control which is great for the gameplay. I had a fear it would be a difficult task but since this is an arcade game my fears disappeared quickly. With right hand you steer the Avatar(left and right arrow key) and change pitch(up and down arrow key) while with left hand you change the speed using A and Y key and with SPACE key(you keep your thumb on it) you fire projectiles. Very smart choice of control keys. Other keys include numbers 1-7 for weapon change, INS/DEL for adjusting the camera(HOME resets the camera to normal position) and TAB key for toggling map on/off. The controls might seem complex but believe me, TerraScape is very easy game to play(this doesn't mean it's an easy game). You'll only use arrow keys, A and Y key for changing the speed and space for firing. Other keys are used when needed and not so often. For example, I never used camera adjusting since I see no benefit in it. The easy controls make TerraScape a very enjoyable game to play on the first ball. You will enjoy in the simplicity of blasting enemy fighters and enemy buildings, pitching up and down, flying between buildings or making crazy turns. Now when you actually try to finish a mission your excitement will start to decline.

The goal of each mission is to destroy several buildings scattered around 6-7 locations if not more. Maybe the number of locations depends on the mission. Didn't counted but it is definitely more than 6. Sometimes between locations you need to visit a specific checkpoint. You won't have problems in orienting yourself since you are guided with a pointer placed on the mini-map in the upper-right corner of the screen. One the very end of each mission the mission boss awaits you, which can be anything from a protected building to a huge spacecraft. This unlucky mission design damages the gameplay quite a lot. It makes finishing a mission a very tiring and repetitive procedure. One mission can last up to 20, 30 minutes(maybe even more) so when you get destroyed somewhere toward the end of a mission or when fighting the boss playing that mission all over again can be very discouraging and frustrating because save game feature only puts you in the beginning of the current mission. Saving the game in the middle of a specific mission only saves the weapons you have accumulated. This allows "cheating" since when you load a game you get full shield. You can collect weapons, save a game, kill yourself and then load a game. Viola! You are on the beginning of the mission but now with all the weapons from the last attempt to finish it. Still, this doesn't help much. Who will have the patience to accumulate weapons and play a specific mission several times just to have better chances against the mission boss? And you don't feel the game is meant to be played like that. Also, you will often feel that your success depends on luck since few lucky shots from an enemy ship and your shield strength is cut in half(not in missions 1 and 2). This is especially the case with some mission bosses. What helps are shield cores you can pickup from destroyed ships(very rarely) or from destroyed storage bunkers but dragging yourself with almost no shield to the next storage bunker with hopes you will be able to find another super shield core(gives you full shield) is another frustration. One shot and you are dead while the full shield was just few meters away. But I'm starting to wander. The main problem of TerraScape is the poor save game feature. If one game was ever so ruined with one bad feature then that game is TerraScape and it's save game feature. I gave up on mission 3 and it's boss. Got destroyed by it 2 times. A person simply can't have the patience to play a mission for another 30 minutes just to try out another tactic with the mission boss; approaching from low this time, flying with another speed and when it doesn't work repeat the procedure. See what I'm talking about? People want to be able to save their progress, especially if a game features missions/levels that last up to 30 minutes and are repetitive. If you are wondering how I am able to comment the rest of the game missions and the game ending Pauli showed me how to cheat. I should point out that not all the missions are placed on Earth. Actually, most aren't. Cool, eh? Anyway, the positive aspects of the game prevail, I think. The controls are something that can always make you return to the game and the missions are varied enough, featuring different enemies(air and ground units) with different attack patterns and characteristics.

### Story: 4/5

Very good. The game does start with a rather worn out story of the future controlled by evil corporations, in this game fascist corporate armies knows at The Corporates. After an attempt to police The Corporates by The Initiative(global military concordance), The Corporates launch a nuclear attack and destroy seven world's largest cities, killing 2.3 billion people in the process. The Initiative launches a counter attack. You play the role of Shara O'Neal(yes, a female person) The Initiative's best pilot and fly the Avatar, most powerful fighter in the fleet of The Initiative. The plot unfolds quite interesting with each new mission. The end is quite rewarding delivering a very original and well written epilogue. Something that is worth being seen/read. If you manage to finish TerraScape without cheating your effort will be more than awarded. Trust me.

### Replay value: 4/5

Maybe a bit too high score having in mind the terrible save game feature and what it does to the experience of playing the game but I wish to ignore that in this section. The nature of the gameplay(3D-flight game) makes the experience of playing one mission never the same. And because of the length of the game and all the content in it the replay value is quite high.

### Challenge: 3/5

I'm still unsure about which of these two sections(Replay value and Challenge) should get 3 but I know that one has to for sure. Since I was unable to finish the game or just didn't had the patience for it I can't tell how much nerves it takes to finish TerraScape and how much the difficulty is reasonable. TerraScape features 4 levels of difficulty but the game is already too difficult on the easy level. At least to me. Anyway, I have to return to the save game feature again since Pauli wrote in the documentation that it increases the challenge. Yes, it sure does but for a too high price. Challenge shouldn't be a test of patience. People don't have so much free time today. I think Pauli didn't though on that when working(or deciding not to) on the save game routine.

### Fun factor: 4/5

What has been said in the gameplay section applies to this section too. TerraScape is a game that is both fun to play and not in the same time. One single game feature ruins it all, the save game feature. All else can pass. The mission design is not that bad but in conjunction with the poor save game option results in something frustrating and unrewarding. Despite all of that I kept returning to this game several times. Once I gave up on mission 2. Tried it again a month later and reached mission 3. The elements for a great game are there. The game works but demands too much patience and time. If it was just one of these two things(patience or time) I would give TerraScape 5/5 in this section but since that is not the case I can't.

### Total Score:

> Total:
> 29/35

> Good: The graphic and the sound/music. The 3D engine. The simplicity of the controls. Large number of missions(8) with varied graphic and enemies. The overall professional approach.

> Bad: Terrible save game feature that puts you in the beginning of a mission - lowers the quality of the gameplay a lot. Repetitive mission objective design.

### Last thoughts:

You might get the wrong impression about TerraScape from the review since I like to point out the bad things. So to be clear, this game is a fundamental part of QBasic game design history. It is one of the best QBasic games ever made. In the top 5, by my opinion. If you ever belonged to the QBasic community or are interested in it you must have TerraScape in your collection. Even if that collection is consisted out of 3-4 games. This is one of those game. Get it!

> Download the game here (16.5 MB): tscape.zip
> No sound version(2.1 MB): tscape_nosound.zip
> Source code (643 KB): tscape_source.zip

Review by Dean Janjic (Lachie Dazdarian)

## Game Apathy: Another Symptom Analyzed

### Written by Deleter

It has been quite a while since I’ve written an article, but for all of you who thought I had written my fill, think again. After a somewhat anger filled conversation with an unnamed someone from the community, I realized another reason behind the dreaded game apathy. In past articles, I’ve given ways to get your game idea worked out, and ways to make sure it didn’t go down the tube. However, what I haven’t discussed is what I believe now to be one of the main reasons a game trips and dies.

A lack of meaning for their existence.

You see, games are wimpy. Humans can keep going on without a reason in life, doing their every day routines while holding out for something higher or better. Games on the other hand die without a real purpose. If the only reason you are making a game is because it is fun to code, then you might be better off just stopping now. When it comes down to that one part of the game, a crucial element that has always been your sore spot (mine is the GUI) that reason isn’t going to sustain you. Even if you have the determination and energy to hack your way through it and complete your game, not only will you be exhausted from the experience (not always a bad thing) but the resulting product won’t be the best. Sure, you could keep coding it until its refined and great, but you could also simply take preventive measures before the first line of code is even placed.

So, what’s a good reason to make a game? I can’t say, if I had an answer for that, I’d code it before someone could steal it ;). You see, the answer to that question is not one specific thing. There is no universally correct answer. However, there is a right answer, or hopefully several because lets face it, when the coding gets tough, you need some other motive to sustain you. In light of that, there are universally wrong answers. Any purpose involving solely the pleasure of development is wrong. No matter what it is, modeling, coding, or the like, there is some point were you just don’t want to do it. If the game you are working on has qualities and a purpose that you just love, you can pull yourself through it better and easier than if you have no other reason than because the hell you are putting yourself through "is fun".

However, I am not saying that you shouldn’t code a game to learn. Especially in this community, it is good to code a game to improve your skills. If you have a reason in addition to this, it will be better, because when you finish a game, you learn a lot more than if you give up on it.

So to sum it up, the reason you need a purpose for creating your game is because it gets you out of tight jams and it pushes you to do better when coding and developing your game. It really helps when you can get two models down instead of one. When you code the full GUI sub instead of the first one hundred lines. Your game doesn’t have to be some genre-busting, mega-fun behemoth either. As long as your reason will be enough, and preferably more than enough, to make the game, you are good. For example, when I made that simple game (damn, I haven’t even named it! lol) with the kilotwerps and such, my reason was "I am going to make a game right now, because I want to feel the effects of finishing something." Because it was such a small and simple game, that was enough. Just so you know, that will not work while you try to make the hl2 engine in freebasic. So, to cut a long story, erm, medium length, you have to have a reason so while you are sitting their with a excruciating headache coding distance vector spliced sub loop altruisms, you can say to yourself, "I can finish this, because (insert reason here)." So, don’t let your game die, give it a purpose in life, all right?

(And that unnamed someone, if you actually forgive me enough to read this, please don’t take any of this as an insult...It’s quite the opposite.)

Visit Deleter's site: Random Musings of a QB/FB Game Programmer.

## It's Been A Dark Month, Hasn't It?

### Written by mennonite

i don't want to get superstitious on anybody, the thing about superstition is that it (and the people that give in to it) don't seem to be any better off... they just seem to worry more.

what i'm going to say isn't about worrying, it's about hope- so bear with me... or, if you prefer, go on to the next article.

now maybe i'm imagining this, but it looks like it's been a low point this month for qb... and for everything. for qb, the forums seem to have been less active, i've personally done almost no coding whatsoever, and just to confirm this, pete's saying he needs more stuff. he always says that, but it sounds like this time he really means it.

whenever something bad happens, a horde (invariably) leaps out to declare the end- of days, of hope, of an era. if darker times are ahead still, then there has to be an end of a good era, and if there has to be an end of a good era, then there has to be an end of a dark era, too.

take any point in history, and determine if the people of the day thought things would happen just like that. maybe a handful saw something coming, but even they were unable to convince most people. unpredictability can work in our favor, however, as when we expect the worst we can rest assured (at least) that we have no reason to be sure that things will be bleak.

because you really don't know, the best thing you can do is hope for the best, and to do your best to that end. if you're reading this, chances are, you have an interest in, or are an expert with, or are possibly trying to become an expert with qbasic or freebasic.

what could be better?

well, okay, there are a few things. but programming is a useful, fulfilling, constructive activity. it combines logic with creative imagination, and rewards you with the knowledge that you've brought something into existence... this is no small thing. no matter what level you're working at, you're basically doing for the head what hours in the gym do for the body. if you're having too much fun, maybe it's more like a long, pleasant walk outside. the main point here is that it's good for you.

sometimes we have an off-month, or even an off-year. that time always ends, however, around the time we become really convinced that better things are ahead. wherever we get that little push, we eventually go back, shake the dust off, and return to what we love doing. for some of us, that's qb. for some of us, it's being in our jeep. for some of us, it's reading or time spent on a forum, but these things always happen in seasons.

it's been a dark month, indeed. some people have reached the last season they know. some people have lost their livelihoods, homes, even loved ones. one guy on the qbasic forum is trying to get back to a place he can work on a computer (of all things)- his house is underwater.

but there's a secret there, and i promise you, i'm not being glib. with the greatest sensitivity possible- life does, will, must, should go on. whatever you see as "the big picture," you may be reminded of a bigger picture this month. this month might be a hard one, and there may be more ahead. on the other hand, (and this is only partly a metaphor, to an extent it's very literal) you have almost certainly derived great pleasure from working with qb/fb(/c/asm) in the past. it may seem like a small thing, but really there is a symbol in it. there is a reason you enjoy and have enjoyed coding, and it's part of the biggest picture you can imagine. many tragedies throughout the world have taken place since some of you began coding, and you've kept doing it. whatever that may be to you, don't let go of it- it may be more important than you know. this may sound very odd, but i'm certainly not kidding. every good thing that happens in the course of human life is something that only takes place while humans are pushing towards it. don't stop pushing now.

best of things to everyone, coder and non-coder alike.

august, september 2005

Visit mennonite's site.

## Rattrapmax6's ASCII Scrolling Map Maker 2.5

### A review by Stéphane Richard (Mystikshadows)

### INTRODUCTION:

Some of you might remember the review I did, in QB Express #11 on Rattrapmax6's Scrolling Map Maker 1.0. Well Today, I have the distinct priviledge to review version 2.5 of this amazing software. As you might have guess from my last review, I've become a fan of that software and just when I thought it was at the top of what it could do, along comes Rattrapmax6 and changes my whole system of beliefs on this software by presenting me this new and improved version of his software. Just take a look at these screenshots and the list of new features I present here.

The Splash Screen:
What's an application without a good, decent, respectable splash screen? This shows off some basic application information.

New Map Option:
When you select to create a new map, the options on the right screen appear allowing you to select the height and width of the map as well as a day scene or a night scene.

The new File Dialogs:
If you have used the first version, you might have noticed the more primitive means of loading and saving a map. Well in version 2.5, that part changed quite dramatically, as you can see here you now have a more standard file dialog where you can select folders and files by simply clicking on the appropriate place in the presented dialog. A big plus in my book.

The User Tile Editor window:
The tile menu offers some 16 preset tiles. However most of the 255 ASCII Characters can be used in the creation of a map. Here is the window where you can select which tiles you want to use in your map.

The Main Application windows:
Once your map is ready to be worked on, these windows will appear so you can get busy in a very direct fashion. Being everything is in a seperate window, one of it's main advantage is you can set it up to work the way you want to work.

The Open G.L. Map Viewer:
Once your map is essentially done, you can view it with this Open G.L. viewer. You can zoom in or out and you can rotate your map in 3D as well. I ask you have you every seen a Text map that looks like this screenshot?

List of "new" features:

- Console Based S.D.I. (Single Document Interface) design.
- Now you can drag a map to the Application Icon and have it opened and ready to work.
- The S.D.I. interface allows the user to organize the windows the way they want them to be.
- Sophisticated Dialog Based File selection for loading and saving files
- Dynamically sizable maps (which can vary on any project and change on the fly to a bigger or smaller map).
- Overall operability greatly enhanced with a more intelligently designed user interface.
- The full range of 32bit color definitions can be used.
- OpenGL map view for a never before seen view of an ASCII map (quite stupendous to say the least) with zoom in/out and rotate features.

I will be reviewing this software with the same review categories I've used in the last review because I believe those are good evaluation criteria for an application of this type. So fasten your safety belts folks, cause here we go!

### Functionality and features: 9.5/10 points

After seeing all of what the application can now do, everything it allows the user to play with, the views the users can generate to view their maps, etc etc...I had to give it a score of 9.5 for just one reason only. The ability to Print the map (Version 3.0 perhaps?) .

As far as I'm concerned, this version is far more complete than it's predecessors and far more versatile and usable. You don't need to look at it too long to figure out that it is a great, all in one, complete and integrated Scrolling Map Editor and as such has been created very intelligently. I gave it a 9.5 out of ten and to me, it deserves no less.

### Layout and Disposition: 10/10 points

I know, in my last review I said that having everything on one screen like the previous layout had nothing but advantages, made things quicker to access, that I liked having all things available, etc etc. Well with version 2.5 I can say, officially, that I stand corrected. The way the different windows are organized, and the way that you can call them up only served to make everythings even more organized. The main screen is much better this way. There's just no flaws anymore and since now it has good stable file dialogs (his own creation) to top it all of, I just don't have a word to say about the layout and disposition.

This layout is so functional, that I just didn't have a choice to give it a 10 out of 10. Everything is cleaner than the previous design as well as more functional. What else can one ask for.

### Suitability to the task: 9/10 points

The way this category differers from layout and dispositions is that it also takes into consideration the functionaly AND the means to access the functionality. In that context a program with a great user interface could score low here, or vice versa, a program with a very poor user interface and score perfectly in this category if the functions are present and readily available.

As such, This version of the Scrolling Map Maker Version 2.5 scores a whopping 9 out of 10 here. Indeed looking at what's available in this new version and the means to get to that functionality, it's easy to see that the userinterface was created with ease of use and ease of learning in mind. I'm not sure if I'm the only one to say this, but when you open this program up for the first time, everything just seems to be exactly where I would typically expect them to be and to me, that helps with the review, it's how it should be and it's exactly how it is too. Great work there.

### Overall performance rating: 9/10 points

Well again here, if I click an option and have enough time to make myself a coffee while waiting for the option to execute itself, I would say it has a serious performance disability. Well This is far from the case with this program. When the system is getting the folder/file information when you choose to save/open the current map, there is a small wait, but really, nothing dramatic especially considering what is going on. The rest of the application is very responsive all around.

With this in mind. The application is so usable, as it is now, that the small wait posed no problem to me. This Map Maker software is fast in pretty much anything you try to do in there. Of course that's after the map is initialized (if it's in the bigger size range) But that would be the same for anything initializing a matrix of the same bigger size, in any language. So definitally a big 9 out of 10 in this category for me.

### The Final word: 38.5/40 (96.25%)

As a final word, all I can say is that Rattrapmax6 really outdid himself in this new version. For one thing, if you look at what a typical vesion 2.X of a product adds in features, you'll notice that this version offers far more than the average version 2.X update. He included, in this new version, more than a fair share of new functionaly and features as well as a totally redesigned user interface. So just for that he more than deserves the score I gave him for the sheer hardwork he put into the Scrolling map maker.

I'm not exactly sure what could be added, if any, to this program. But if there's another major release of this, I'll definitaly be there to review that one too. On a side note, I had a glance at the code and I do have to say that I like the coding style used. it's clear, pretty easy to follow through, excellent code. Until the next review, enjoy this program, it's worth every minute you'll put into it.

> MystikShadows
> Stéphane Richard
> srichard@adaworld.com

## My QBasic Story

### Written by Nathan1993

I first got started programming at the end of the fourth grade. I was a 9 year old that sucked at math. Our school library was giving away all of the old books in its that no one wanted, and if they weren't taken they were trashed. I was a complete outcast geek, so when someone saw a computer book they would give it to me. Someone found a book titled “Using the Home Computer”, gave it to me, and I read the introduction. It said something about robots, so I kept reading.

That book had a small part on “How to Make Games: Using QBASIC”. I found QBASIC.EXE and went on to type in a small game that I found in the book. I thought, “Hey, this looks pretty cool, and easy!” So I went on to learn its workings with extreme help from my dad, a computer programmer. But we couldn't find out what was wrong with this line of code:

>     IF choice$ = yes THEN PRINT “Yes”

We were thinking about how to solve this problem when my dad remembered about his old QBASIC book that just happened to be sitting on a nearby bookshelf. I read all 620 pages that summer, and mastered it all. I spent a year programming and learning from old stuff, I had no idea how active the community was. All I saw was occasional updates on QBASIC New Zealand and a new version of Rellib.

Then there was a ray of hope: Pete re-opened his site! I thought “Hey, one person is active! Maybe there is hope for QBASIC! Then I saw that his forums were active. It was heaven, after that QBASIC was more than just QBASIC, I upgraded to QuickBASIC, and found libraries. As time went on I thought “Well, FreeBASIC rules, but we have a major shortage of C++ programmers”, so I got djgpp and am learning C++ from www.cprogramming.com. I will probably not be posting and coding as much, but do not worry, I still love QBASIC. I cannot wait to return and be able to program in C++ and port C++ tutorials to FreeBASIC. If I suddenly stop showing up on QBASIC and FreeBASIC sites, son't worry, I have not left, I will be back with goodies. Can you say full Allegro tutorial!?

And if there is a need for it, I will make a series of “From FreeBASIC to C++” so we can all know C++. I do not care If I am hated for writing this, but I feel that another C++ programmer will not hurt. But face it, after programming in nothing but a tiny bit of assembler and QuickBASIC, your going to want something different. I will try to write some articles for QBExpress if I can think of it, but don't expect much. Be back soon!

Contact Nathan1993 through this link.

## Searching For The Unknown
Lunatix: The Insanity Circle by Mike Snyder, 1999.

### Written by Lachie Dazdarian

### Introduction

Lunatix: The Insanity Circle is an excellent "illustrated" text adventure game developed by Mike Snyder. This game is a real QBasic gem and probably the most perfect game for the column.

Mike Snyder is a relatively unknown person in the QBasic community if not completely. I cannot know how much this is true since he used to release QBasic games before I joined the community. Still, I never heard anyone mentioning him or any of his games ANYWHERE in the community and just looking at Lunatix: The Insanity Circle makes me wonder why. Maybe I should have checked some of the old QB mags before doing this article to be more sure. Oh, well. Most of his games were released in the period from 1990 till 1997 as shareware(later became freeware) under his shareware label Flogsoli Productions so that was in most part a time before Internet and the QBasic community as we know it. I think that some of his games like Lexter 1 and 2 were quite respected back then(1993) in shareware circles. He also released three other text adventure games(interactive fiction) before Lunatix; Spore, Mystic Force and Breath Pirates. From this, and some things said in the game documentation, we can guess that he was much more interested in interactive fiction than in QBasic. Which is probably another reason for him being so unknown in the community.

Mike's other interests were BBS door games and Lunatix was originally an BBS game. He even earned a nice sum of money on it. According to Breath Pirates readme file he sold around 1000 copies of Lunatix BBS for $15.00(the readme file was written in 1997). It sure was nice to be a shareware developer back then. Lunatix today is a web-based RPG(sad to admit, didn't had time to try it out) and is called Lunatix Online. In this online game you play a role of a mental hospital patient and interact with other players. We could say that Lunatix: The Insanity Circle(the QBasic game) is a by-product of this Mike Synder's decade-long, online project which is still alive.

### About Lunatix: The Insanity Circle

Like I said before, Lunatix: The Insanity Circle(L:TIC) is an excellent "illustrated" text adventure game. This "illustrated" means that it features graphical scenes and mouse controllable text boxes(mouse is not required, you can control the boxes with the keyboard too) but it plays like any other text adventure game. Like the designer says, graphical scenes are here to make the play experience more enjoyable. What's cool is that you can play L:TIC it text-only mode by starting the game with LUNATIX /T command-line parameter.

In L:TIC you play the role of Dr. Armund Hammer. After an uneventful day in your asylum you awake for an afternoon nap. It's time to go home but your keys are missing. This leaves you locked in the asylum. You must find your way out of it.

The main game screen in L:TIC is very intelligently designed. It's divided in three parts. Two boxes are placed in the upper part of the screen. The current scene is displayed in the left box while in the right box is displayed the description of the current scene(you can scroll through it). In the lower part of the screen is the game command prompt(the place where you input your commands) and the message box right above it. Message box is used to display the results of your actions(inputs) and it keeps a pretty large history of your commands and command results through which you can scroll. The choice of colors and game font is very smart and makes playing the game very comfortable for the eyes.

The very graphic scenes are quite nice. Mike Snyder used a combination of photographs and some original artwork to create the game scenes. While most scenes are cool you will find some lacking, especially the ones that are custom made. The scenes are more incoherent with one another than poor in quality. The game is a bit unbalanced in that part but overall, compared to other QBasic games, the graphic is excellent.

Now the gameplay. Those who are familiar with interactive fiction(IF) know how these games work.

For those who are not a short introduction. Your entire communication with the game is done through the game command prompt, more popularly known as parser. You simply need to type in the action you want for your character to execute. LOOK UNDER TABLE, EXAMINE BOOK, stuff like that. Like in most text adventure games moving around locations is done by typing in the direction where you want to go(for example, NORTH or NORTHEAST). Since Mike Synder is an experienced(or well informed) IF game designer L:TIC supports short substitutes for directions like N for north, U for up, SE for south-east and similar. L:TIC parser also supports X for examine, I for inventory, multiple commands at once, pronouns(for example, "GET BOOK THEN READ IT"), command recall with UNDO, ability to retrieve previously typed commands and few other things that every good IF should have. Not that these things alone make a good IF. What makes a good IF is the parser and the game script. L:TIC parser is simply brilliant. During the entire game I only had a problem on one place with phrasing what I want to do and that was probably a problem with my English vocabulary and imagination and not with the parser. Nothing more to say about the parser but that every newbie in IF game design should check L:TIC or a game with equally excellent parser just to be aware of the standards.

L:TIC is a rather difficult game. I might not be the most suitable person to express such opinion since my experience with IF games is minimal(2 games; :P) but some puzzles really have that "evil" note in them. The game also start with a quite complex and demanding puzzle which can be very discouraging for most of the players. Luckily I happened to have a walkthrough on my hard disk but then it was hard to resist to use it on some easier puzzles. I ended up finishing about 50% of the game by myself. But it was fun to play it even with a walkthrough. The other thing that increases the game difficulty is that you are not sure what is your objective or to be more precise how to accomplish it(leave the asylum). Almost the entire game you(Dr.Hammer) are under the influence of a drug(unknown pill) so for the most of the events in the game you are not sure if they are real or not. This brings me to the game script. L:TIC is a well written game. Mike Snyder sure knows how to write nice, long and often funny description and comments on your actions(inputs). Now the other thing is the plot. I already explained why. Putting the main game character under the influence of an unknown drug is a really convenient way to add illogical and bizarre content/puzzles in your game and that's where lies the only real flaw of L:TIC.

L:TIC features relatively poor sound effects and music. Ok, they are better than PC Speaker blip and blops but not terribly better. Mike Snyder used Tim Truman's(another QB game developer) sound card FM register routines to play the music and sound effects directly from the code. Music plays only during the intro, when you exit the game and when you complete the game and it doesn't sound like something fitting for the game theme. But having in mind how the music is played we should appreciate the trouble. Sound "effects" only play when you die, when you undo a move after dying and load or save a game. They are nice and fit in the game theme but since these are the ONLY sound effects in the entire game they leave you thirsty for more. It makes the rest of the game more in need for sound effects than it would without any sound effects implemented at all. In a nutshell, better than nothing which you can't say about PC Speaker sound effects/music in most cases. :P

What puts L:TIC above the majority of QBasic games is the fact it's an ILLUSTRATED text adventure game. The graphical interface, the technical perfection of it, the colors, the font and the way the screen is composed makes L:TIC unique, notable and different(in QBasic games world). I don't know if there are any IF purists in the community by they too know that if L:TIC was a classic IF game it would never be properly appreciated in the QBasic community even if Mike took the trouble to promote it. It's just the curse of IF as a genre. No matter in which language an IF game is written it will be played mostly by IF fans and not by fans/users of that specific language. Anyway, you can always choose to play L:TIC in text-only mode but you will miss the real L:TIC then. The graphical interface and the scenes(plus the good script and the parser but not only that) are the reason why L:TIC is a lost part of QBasic game design history and should be something that anyone with a minimum interest in QBasic games must check. Also, the small number of graphical adventures ever released in QBasic puts L:TIC in the top(if not in the very top) of that genre.

> Final score:
> 7.5/10

### Get Lunatix: The Insanity Circle

To download the game click here: Lunatix_TIC.zip (L:TIC works in Windows XP just fine without any need for DOS emulators but if you want to hear the sound effects and music you will have to start it with a VDMSound shortcut)

A walkthrough can be acquired by emailing Mike Snyder(the reply email is sent automatically): wyndo@prowler-pro.com

Also, check out the game readme file. It's a very well written and informative document.

That's it for this issue. Hope I brought your attention to something you didn't know about. For the next issue I will probably "do" MadMix. But I have some other things being considered too. Let's make it a surprise.

Download Lunatix or visit Lachie's site, KENTAURI.

## 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

> ASCII-World
> http://www.ascii-world.com/
> Webmasters: MystikShadows and Lurah

> "It's time computer technology went back to it's roots." That's the slogan of ASCII-World, the phenomenal retro coding site run by MystikShadows (Stéphane Richard) and lurah (Kristian Virtanen). When this site launched back in February, I was very tempted to make it the first QB Express site of the month. It has a great retro DOS/ASCII-style design, and even in its infancy, had more ASCII-related content than you can shake a stick at. But now seven months later, ASCII-World has had the chance to grow and expand into a much greater site that's even more deserving of this award.

> Over the course of the year, ASCII-World has become a community of ASCII programming enthusiasts. Its forum has become quite active with all sorts of ASCII discussion, and even after all the posts were reset as a result of a server switch this past month, it looks like the ASCII-World members will be making a full comeback.

> ASCII-World is also a great resource for programmers, with a large collection of ASCII-related tutorials and articles. Most of them are original creations, made for the site by MystikShadows and lurah, and not just reprints from other sources. ASCII-World is also a depository of ASCII-based games, libraries and applications, as well as many code snippets. Things are constantly added to ASCII-World, so be sure to check back regularly. In the past month, there have been five updates, all of them bringing brand new and interesting content for all of you ASCII-maniacs.

> Because ASCII-World is such a great and up-to-date resource, as well as perhaps the most thriving community of ASCII programmers on the web, it is hereby declared the QB Express Site of the Month!

### Programmer of the Month

> Lachie Dazdarian
> (a.k.a. Dean Janjic / KENTAURI)
> http://kentauri.digitalblackie.com/

> Lachie Dazdarian is one of the most productive coders the Qmunity has ever seen, with more than half a dozen finished games under his belt -- including Detective Academy, Ball Blazing Fantasy, Rocket Fuel Mayhem, Dark Quest, Another World Memory, Run 'Em Over, Pong Worz, Evil Baron Lachie, and his latest game, Poxie. All of his games have a strong visual style and a lot of polish. Lachie has the skill and design sense to create fun games that look and feel like the console / PC games of the early nineties that many of us grew up on.

> This month, Lachie released his first completed FreeBasic game, Poxie. As you could probably tell from the two reviews above, this is a very fun game. It has delightful stylized graphics, good music and a simple but addicting premise: collect all the food while avoiding the enemies. Because of Lachie's strong sense of design and gameplay, Poxie is a fun and balanced game that I'm sure most of us would pay money to play if we saw it at the local arcade.

> But Lachie doesn't just program, he also contributes heavily to the Qmunity. He has become a regular contributor to QB Express (he wrote two game reviews this month, one of which is part of his "Searching For The Unknown" series which brings light to great QB Games that most of have never heard of.) Lachie is also well on his way to creating "The QBasic Games Directory," an archive of all the significant QB games that have ever been released. He recently said that the archive now includes "371 game with 321 screenshot and some site sections like 'Running QBasic games'." When the QBasic Games Directory goes live, it will be perhaps the greatest library of QBasic games to ever have been created -- not only being a huge archive of games, but also including thorough descriptions, screenshots and ratings of every game. Everyone in the Qmunity should be looking forward to this incredible library of QB history.

> For Lachie's programming skills, dedication, and endless contributions to the Qmunity, he is deemed the QB Express Programmer of the Month!

## QBHH: How to Draw The Horse

### Written by Rattrapmax6

Introduction:

This is just a simple tutorial on the steps I use to make the horse in the QBHH Comic every month, and this month. If you are new to drawing, or have had a hard time in drawing stuff, you may want to read this intro:
Drawing is by far not as hard as you might think. Stop and think. If you can pick up a pen and write letters, words, numbers, ect,.. this is a form of drawing. Basicaly, drawings are just a bunch of lines shaped and put together to form a particular scene or object. The trick is, not letting fear or doubt stop you from attempting to master it. There will be no "I can't draw" or "I suck at drawing" from here on in this tutorial and later drawings you might take up on your own. Thoughts like that can promise failer right from the start.
So, clean your mind and replace those thoughts with "I can draw!",.. We may now begin. ;)

Drawing the horse:

Step 1: The very first line I draw is for the hind leg. It's the same motion you would preform to make a S. One smooth line, top to bottom, should come out like above. If you can't get it, then take your pincel and trace over the line to get the feel of the shape. Once we have that, we can continue to the next step.

Step 2: The next line forms the hind part of the hind leg. This time we make a simular movment, but, insted of going down, we go up. This alows us to get the right effects we'll need. As you notice, the leg widens some as we let it climb. This gives it a natural look. (Notice, you can do Step 3 then 2 if you want ;) )

Step 3: Here we make the barrel of the horse (Belly if you're not use to horse anatomy). To do this, we make a smooth line from the hind legs to just behind where the front legs will be. Notice too, the smooth dip just after coming away from the hind leg. This is for the rib-cage biuld. Careful how you much dip you put into it, you don't want a starved looking horse. ;)

Step 4: This is by far the most simple step. It is a near straight line down to form the hind part of the front legs (Notice the small hint of a bend also). I'm pretty sure you can handel that one. ;)

Step 5: Now we'll make the front of the leg. It's another smooth movement with a slight bend to it. A little more than last time. Try and make the bottom part of the front legs as wide as the hind legs.

Step 6: You might hate me now, but this will help you later on. Look at my picture step above this text. Study the movement of the line and see if you can figure out the motion you'll need (Starting point, where I stopped off, how I curved it, ect). Just as suggested in Step 1, you can trace over it to find the feel of it. This will help when you want to learn how to draw new things on your own. Don't worry, I'll still guide you through some of the next steps as needed.

Step 7: Yay! Back in buisness! Okay, maybe not so funny. For this line (For the back), you'll need to hump up over the back legs (to form the croup), then dip slightly to form the back stoping at the withers (where the back stops and the neck begins). Once you have that, we'll move on...

Step 8: This might be the trickiest movement yet. Basicaly I do this in one movement, thus why I have it as one step. This might take a few runs to get the feel (Bet you didn't master the letter B your first time either ;) ), just remember this is a smooth uniform movement. Also try tracing too.

Step 9: Here we will detial the head. The mouth and nose is as easy as in the sample picture. The eye is tricky. A lot of emotion can be expressed through the eyes. Normaly a happy caring eye is long and smooth at the back and steep at the front (Example above). For the ears, they tend to show where the horse's attintion is directed. Take note on the example above to get the correct shape. This ear shows his full attintion is foward. The Hair is lightly brushed in with your pincel. Notice the motion above.

Step 10: I suddenly get the feeling you just thought, "I got to draw the horse's dick?!". Actualy no. If it makes you feel better, above is actualy what you call a sheath. But, enough of that, you see how to draw it. Now for the tail: You make long smooth brushing movements to get this effect. Once you have that, we'll put on the finial touches.

Step 11: The example picture should be enough to get the ideas of the leg detials. Just mark off the hoofs and the top of the stocking marks on the legs and shade.... THEN!

Congrats!: You've just made the QBHH Horse! If you want to make his wife, then leave off the sheath. Happy drawing! ^_^

Special Thanks: My dad.. He constanly misstaked my horses for dogs. Finially one day I showed him an improved work and he replied, "Nice horse".. Thus, lol..
The Walrus.. giving me the idea to make this lil tutorial.. ;)

Visit x.t.r. GRAPHICS FreeBasic Site!

## Comics

### By Rattrapmax6 and Matt2Jones

### QBasic Horse Humor

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

### Bobby The QBasic Maniac

And after a nine issue absence, the original QB Express comic makes a come back! Here's Matt2Jones with a "Bobby The QBasic Maniac" comic! (Click to see it full size.)

(Click to view full size.)

## Stylized Foliage / Clouds Tutorial

### Written by Josiah Tobin

'Foliage? Clouds? What the hell do they have in common?'

You might find the title a bit strange... But don't worry, you'll know the reason behind it at the end of this tutorial. (Truth be told I COULD have called it 'Stylized foliage/clouds/rock texture/fire/smoke/wind tutorial', but then not only would it not make the deadline, it would look even MORE ridiculous)

Alright... As you've probably guessed this is somewhat of a multipurpose tutorial, but let's start with the original and possibly simplest idea: Trees. This is only one of the nearly infinite methods of pixelling trees, bushes, and/or foliage, and it may not be the most realistic. But it looks cool... and most of all you can use the method for so many different things.

Let's begin...

As always, start with an outline. (since this is a TREE... personally I'd go with green, but, y'know, that's just me) In this case I chose a VERY simple and rough shape to block out the lines I need: (light background used for visibility)

Easy. Fill it in, and start adding little half-circles or crescent shapes on one side in a lighter green shade-- preferably the side your chosen light source is on. The curved part of the shapes should be facing towards the light source, like so:

Also note that I've added a few little rough dots down and to the right for later reference... though I ended up ditching them. Ignore them if you want, heh. Anyway... Smooth out the brighter shapes made in the last step-- you may not need to, but I made them with a 3*3 pixel brush-- just make the ends taper and smooth out any corners. (you can also make them more 'swirly' for extra style-- think Zelda: The Wind Waker) At this stage you'll notice I also put in the rough outline of the trunk... I tend to use a sort of tan color, but use a greyish shade or dark brown if you like.

Fill in the trunk... (bet you weren't expecting that) And add some more detail to the foliage in the form of little dots and circles to fill out the blank space. (rather, dark green space)

Add a third shade to the foliage-- a brighter green-- and highlight the crescent/half circle shapes.

Note that to keep it smooth it shouldn't reach the edge of the shape on the corners. It's difficult to describe... Here's a diagram showing what I mean:

If that's not clear enough, you CAN just put the brighter shade on the rounded edge of the shapes, though it won't look as 'clean'. Anyway, you'll also notice the new shades on the trunk in the picture above that diagram-- Just two new shades, both darker. One slightly darker than the trunk color you already had, and one much darker, almost an extremely dark red/brown in this case. Actually shading the trunk can be a bit tricky; though this is a small image so it shouldn't be overly hard. Basically you want to get an almost 'stringy' feel, similar to, say, a bulging tendon in your arm-- though in this case we're going for a much more curvy look, almost wrapped around the trunk of the tree. Basically what I did is just made little angled 'slats' of a darker color in the trunk and kept adding more at corresponding angles until it was sufficiently textured. You'll notice it more in the next step...

Alright, here we go...

Dithering. Oh boy. Actually, it's not as bad as it looks. As always, I did it by hand, but you can use a tool if you so desire. I personally think the messier, hand-dithered feel works better for something like this, but you can decide. Basically, you'll want to dither the second-brightest shade on the foliage of the tree into the darkest shade, gradually. You can even dither the brightest shade into the second-brightest shade, but don't overdo it lest you lose the crescent shapes to random dither patterns. In this step I also took some time to smooth out the edges of the outline and make it more smooth and organic looking. Optional, of course, depending on the quality of your outline in the first place. Hopefully you're better at lineart than I.

Moving on to the trunk, I simply added a final, brighter shade-- a light tan color-- to highlight the tendon-like irregularities in the wood.

That's about it for the tree, really-- as you can see I added a quick shadow in there, but that's completely up to you. Just for reference I also made a slightly more pine-like tree to show the progress in a different style: (note that I used a mirrored outline and made it more uneven at the last minute)

Outlining:

Adding brighter shapes/highlights:

Smoothing out the shapes and adding more:

Adding the dots and circles for texture:

Dither, dither, dither... You'll notice I let the dithering bleed on to the right edge of the outline. This is totally optional, but I think if done subtly enough it can work nicely:

Another shade of green, a shadow, and adding the 'trunk' at the last minute. (if it can be called that)

Also making the outlines more uneven and natural. Interesting note on color conservation: This finished tree (the pine) uses only five colors not including transparency. Conserving colors is certainly a good habit to get into; not to mention working with a limited palette can be fun and challenging. I personally ALWAYS work with a 256-color palette, often less, and refuse to work in high color for pixel art. Why? I like to be able to see and organize the colors I use, and look on proudly when it's just a tiny strip of six colored boxes. ;)

But... I still haven't explained the title to this tutorial. Alright, fair enough... Clouds. This is the easy part. (AN easy part I suppose)

First, compare these two images:

Notice anything in common? The first one, the white wisp of...something, is the foliage of the first tree, palette swapped and with the darkest shade removed. (not ALL of the darkest shade; I just filled the outermost edge of it with the background color) This is the base for our cloud tile.

Copy it, make sure the background color is transparent OR you're starting on a new layer (if your program has those new-fangled layer thingamabobs... mr fancypants), and paste it like so:

Keep pasting randomly until it looks like this, roughly:

Now... How I did this next part is pretty program-specific. In the program I use, you can shift the image within the canvas and it will loop on over to the other side. This is invaluable in tile work, when you can do something like this...

...to completely get rid any 'seams' there might have been. Alternatively, you could just fill the tile with clouds FIRST and then copy and paste it like a tile to see if it loops, tweak it, and repeat, etc...

But as long as you manage to fill the tile with copies of that foliage-turned-cloud-wisp, and it tiles well enough and looks something like this, you're all set:

That particular tile is 48*48, by the way-- or 3*3 16*16 tiles, if that made any sense.

Here's what it should look like tiled:

...which makes a great parallax background, for, say, one of those high-atop-a-mountain scenes in an RPG which you obviously can't have enough of. Or an airship, if you happen to choose the route of the cliche and mundane. :}

Anyhow. That's about it. This method of texturing, and indeed this very texture (with some tweaking) can be used for any number of things. Try using different shapes instead of just crescents, too-- it's good to just experiment and make a whole bunch of different textures in different colors to see what tiles you can use them for. I hope you enjoyed the tutorial, at any rate... I hope I'm at least helping someone here. :)

## Creating A Simple Spline Curve

### Written by Syn9

Lately, I've been unsatisfied with my spline routine. I'd like to make my camera follow the line and right now the line is generated in finite increments. This makes the camera seem choppy since the camera travels at distances shorter than the spline indices...

Here is a tutorial explaining how to make this simple spline routine. You can approximate any point on the curve at any subpoint. So instead of a curve that has 16 subdivisions I can say I want to be at point 45/768 on the curve... so the curve will always be perfectly smooth.

First you have a set of reference points (white points in the corners). The green dots mark the 1/2 way point between each corner. We are going to build a curve between each green dot sinking into the corner.

Each interpolation draws a sub line from between the first green dot and the corner to between the corner and the 2nd green dot. In this picture we are looking at the 50% dot. We draw a line from 50% between the first 1/2 way point and the corner to 50% between the corner and the next 1/2 point, then draw a green dot at the 50% point on this new line. Say we wanted to draw the 20% point, we would find the line that is 20% up from the 1/2 point to 20% away from the corner to the 2nd half way point, and draw a dot at the 20% point on this new line... Do this enough times and you can see the curve start appearing.

This last picture is of a spline curve with 60 random reference points.

Visit Syn9's website: http://syn9.thingie.net

## Metric Conversion Tables

### Written by Moneo

The following table contains the most common conversions from/to the metric system.

What makes this table unique is the rightmost column which contains the formula for deriving the conversion factors.

### BASIC CONSTANTS

Before embarking on conversions, there are 11 constants, which I have called Basic Constants, which most everyone knows, or should know, such as:

>     1 foot      =     12      inches
>     1 yard      =      3      feet
>     1 mile      =  5,280      feet
>     1 meter     =    100      centimeters
>     1 kilometer =  1,000      meters
>     1 acre      = 43,560      sq. ft.
>     1 hectare   = 10,000      square meters
>     16 ounces   =      1      pound
>     2000 pounds =      1      ton (short)
>     1 quart     =      2      pints
>     1 gallon    =      4      quarts

The conversion table covers measurements of Length, Area, Volume, Liquid Capacity, and Weight. To compute all these measurements, in addition to the above-mentioned Basic Constants, only the following 3 factors are required:

>     1 inch   = 2.5400 centimeters
>     1 pound  = 0.4536 kilos
>     1 gallon = 3.7854 liters

The whole point is that the conversion factors in this table were not transcribed from another publication, but were derived using the above factors, as indicated by the formulas in the rightmost column. To eliminate possible computation errors, the results were also verified against standard metric conversion tables.

I'm sure you can see the value of this technique if you were writing a program to generate these conversions.

## CONVERSION TABLE FOR METRIC AND IMPERIAL-US SYSTEMS

### ABBREVIATIONS

>     cm2  = square centimeters
>     m2   = square meters
>     km2  = square kilometers
>     cm3  = cubic centimeters
>     m3   = cubic meters
>     (X)^2= X squared
>     (X)^3= X cubed

### LENGTH MEASUREMENTS

#### BASIC CONSTANTS

>     1 foot        =     12      inches
>     1 yard        =      3      feet
>     1 mile        =  5,280      feet
>     1 meter       =    100      centimeters
>     1 kilometer   =  1,000      meters

#### IMPERIAL-US TO METRIC

>     1 inch        =      2.5400 centimeters   2.54
>     1 inch        =      0.0254 meters        2.54/100
>     1 foot        =     30.4800 centimeters   2.54*12
>     1 foot        =      0.3048 meters        2.54*12/100
>     1 yard        =     91.4400 centimeters   2.54*12*3
>     1 yard        =      0.9144 meters        2.54*12*3/100
>     1 mile        =   1609.3440 meters        2.54*12*5280/100
>     1 mile        =      1.6093 kilometers    2.54*12*5280/100/1000

#### METRIC TO IMPERIAL-US

>     1 centimeter  =      0.3937 inches        1/2.54
>     1 meter       =     39.3700 inches        1/2.54*100
>     1 meter       =      3.2808 feet          1/2.54*100/12
>     1 meter       =      1.0936 yards         1/2.54*100/12/3
>     1 kilometer   =      0.6214 miles         1/2.54*100/12*1000/5280

### AREA MEASUREMENTS

#### BASIC CONSTANTS

>     1 acre        = 43,560      sq. ft.
>     1 hectare     = 10,000      square meters

#### IMPERIAL-US TO METRIC

>     1 sq. in.     =      6.4516 cm2           (2.54)^2
>     1 sq. ft.     =    929.0304 cm2           (2.54*12)^2
>     1 sq. ft.     =      0.0929 m2            (2.54*12/100)^2
>     1 sq. yd.     =      0.8361 m2            (2.54*12*3/100)^2
>     1 acre        =  4,046.8564 m2            (2.54*12/100)^2 * 43560
>     1 acre        =      0.4047 hectare       (2.54*12/100)^2 * 43560/10000
>     1 sq. mi.     =      2.5900 km2           (2.54*12/100)^2 * (5280/1000)^2

#### METRIC TO IMPERIAL-US

>     1 cm2         =      0.1550 sq. in.       (1/2.54)^2
>     1 m2          =  1,550.0031 sq. in.       (1/2.54*100)^2
>     1 m2          =     10.7639 sq. ft.       (1/2.54*100/12)^2
>     1 m2          =      1.1959 sq. yd.       (1/2.54*100/12/3)^2
>     1 km2         =      0.3861 sq. mi.       (1/2.54*100/12*1000/5280)^2
>     1 hectare     =      2.4711 acres         (1/2.54*100/12)^2 * 10000/43560

### VOLUME MEASUREMENTS

#### IMPERIAL-US TO METRIC

>     1 cu. in.     =     16.3871 cm3           (2.54)^3
>     1 cu. ft.     = 28,316.8466 cm3           (2.54*12)^3
>     1 cu. ft.     =      0.0283 m3            (2.54*12/100)^3
>     1 cu. yd.     =      0.7646 m3            (2.54*12*3/100)^3

#### METRIC TO IMPERIAL-US

>     1 cm3         =      0.0610 cu. in.       (1/2.54)^3
>     1 m3          = 61,023.7441 cu. in.       (1/2.54*100)^3
>     1 m3          =     35.3147 cu. ft.       (1/2.54*100/12)^3
>     1 m3          =      1.3080 cu. yd.       (1/2.54*100/12/3)^3

### LIQUID CAPACITY MEASUREMENTS

#### BASIC CONSTANTS

>     1 quart       =      2      pints
>     1 gallon      =      4      quarts

#### IMPERIAL-US TO METRIC

>     1 gallon      =      3.7854 liters
>     1 quart       =      0.9464 liters        3.7854/4
>     1 pint        =      0.4732 liters        3.7854/4/2

#### METRIC TO IMPERIAL-US

>     1 liter       =      0.2642 gallons       1/3.7854
>     1 liter       =      1.0567 quarts        1/3.7854*4
>     1 liter       =      2.1134 pints         1/3.7854*4*2

### WEIGHT MEASUREMENTS

#### BASIC CONSTANTS

>     16 ounces   =      1      pound
>     2000 pounds   =      1      ton (short)

#### IMPERIAL-US TO METRIC

>     1 pound       =      0.4536 kilos
>     1 ounce       =      0.0284 kilos         .4536/16
>     1 ton (short) =    907.2000 kilos         .4536*2000

#### METRIC TO IMPERIAL-US

>     1 kilo        =      2.2046 pounds        1/.4536
>     1 kilo        =     35.2734 ounces        1/.4536*16
>     1 metric ton  =  2,204.5855 pounds        1/.4536*1000
>     1 metric ton  =      1.1023 tons (short)  1/.4536*1000/2000

Download a copy of this tutorial: MetricConversions.txt

## A* Implementation in FB: Part 2

### Written by Torahteen

I feel bad about making such a hard to understand and totally "unprofessional" looking tutorial last time. So, I'll try to be a bit better this time. Here goes for my second tutorial ever written.

Last time I left you off with some pseudo-code. Today, I'm gonna show you how to implement this into FreeBASIC. First things first. There are a few things that every A* program needs. These are your constants, your UDTs (User Defined Types), your open and closed lists, and your subs and functions. So to start, I'm gonna go ahead and throw some code at you.

>     DefInt A-Z
>     '$Dynamic
>     Declare Sub ClearScreen()
>     Declare Sub DrawScreen()

>     Declare Sub FindPath()
>     Declare Sub AddToOpen(x As Integer, y As Integer)
>     Declare Sub AddToClosed(x As Integer, y As Integer)
>     Declare Sub AddToPath(x As Integer, y As Integer)
>     Declare Function IsOnOpen(x As Integer, y As Integer)
>     Declare Function IsOnClosed(x As Integer, y As Integer)

>     const Ground = 0
>     const Water = 1
>     const Hill = 2
>     const Cliff = 3
>     const Wall = 4
>     const Start = 5
>     const Finish = 6

>     const False = 0
>     const True = Not False

>     const GroundCost = 10
>     const HillCost = 25
>     const WaterCost = 50
>     const CliffCost = 100

>     Type SquareType
>         fScore As Integer
>         gScore As Integer
>         hScore As Integer
>         mType As Integer
>         pX As Integer
>         pY As Integer
>     End Type

>     Type PointType
>         x As Integer
>         y As Integer
>     End Type

Notice that I use dynamic arrays in my program. What we have done here is declared the subs and functions that we are using in the program (you should think ahead so you can remember what subs and/or functions you need to implement), declared the constants (we'll get to these in a bit), and set up two UDTs.

Take a look at the constants. The first seven constants are used to make and read from a user-made map. Each square on the map has an mType, which says what kind of tile it is (ground, water, walls, etc.). The next two constants are my two boolean values (true and false). The last four are the most important. These are the G scores for each of the different passable squares (if you haven't already, you should read my other tutorial, "Implementing A* in FB: Part One"). These values determine what path is the best. The higher the score, the less likely A* will choose that square for the path.

The two UDTs are SquareType and PointType. PointType is used for defining points on the map. SquareType is the type used for each tile on the map. SquareType has six variables. The f, g, and hScore variables are just that, the f, g, and h Scores for that square. The mType is one of the seven constants we defined earlier (Ground, Water, Cliff, etc.). pX and pY are the x and y values of this squares parent.

We now have to open the "board.brd" file to get the height and width of the map. We'll then dimension all the global variables that we need to:

>     Open "board.brd" For Input As #1
>     Input #1, sWidth, sHeight

>     Dim Shared Map(sWidth, sHeight) As SquareType
>     Dim Shared OpenList() As PointType
>     Dim Shared ClosedList() As PointType
>     Dim Shared Path() As PointType
>     Dim Shared mStart As PointType
>     Dim Shared mFinish As PointType
>     Dim Shared comp As PointType

>     For y = 1 To sHeight
>         For x = 1 To sWidth
>             Input #1, Map(x,y).mType
>             If Map(x,y).mType = Finish Then
>                 mFinish.x = x
>                 mFinish.y = y
>             ElseIf Map(x,y).mType = Start Then
>                 mStart.x = x
>                 mStart.y = y
>             End If
>         Next x
>     Next y
>     Close #1

>     BTW, here is the example "board.brd" file from the last tutorial.

>     10,8
>     4,4,4,4,4,4,4,4,4,4
>     4,0,0,0,0,0,0,0,0,4
>     4,0,0,0,4,0,0,0,0,4
>     4,5,0,0,4,0,0,0,0,4
>     4,0,0,0,4,0,0,6,0,4
>     4,0,0,0,4,0,0,0,0,4
>     4,0,0,0,0,0,0,0,0,4
>     4,4,4,4,4,4,4,4,4,4

Notice I put a wall around the map. You should do this or it will screw A* up (well, my program anyway).

This gets the width and height from the "board.brd" file, dimensions a multi-dimensional array of SquareType variables, and dimensions all our other variables (they are all self-explanatory, except for comp, which is used later). The nested FOR loops at the end there input one square at a time into the Map array, each time checking to see if it inputed the start or finish square.

Now that we have our variables and our map, let's implement the Subs and Functions, starting with the helper subs.

>     Sub AddToOpen(x As Integer, y As Integer)
>             Redim Preserve OpenList(uBound(OpenList) + 1)
>             OpenList(uBound(OpenList)).x = x
>             OpenList(uBound(OpenList)).y = y
>     End Sub

>     Sub AddToClosed(x As Integer, y As Integer)
>             Redim Preserve ClosedList(uBound(ClosedList) + 1)
>             ClosedList(uBound(ClosedList)).x = x
>             ClosedList(uBound(ClosedList)).y = y
>     End Sub

>     Sub AddToPath(x As Integer, y As Integer)
>             Redim Preserve Path(uBound(Path) + 1)
>             Path(uBound(Path)).x = x
>             Path(uBound(Path)).y = y
>     End Sub

>     Function IsOnOpen(x As Integer, y As Integer)
>         For i = 1 to uBound(OpenList)
>             If OpenList(i).x = x And OpenList(i).y = y Then
>             'It's on the open list
>             IsOnOpen = True
>             Exit For
>             End If
>         Next i
>     End Function

>     Function IsOnClosed(x As Integer, y As Integer)
>         For i = 1 to uBound(ClosedList)
>             If ClosedList(i).x = x And ClosedList(i).y = y Then
>             'It's on the closed list
>             IsOnClosed = True
>             Exit For
>             End If
>         Next i
>     End Function

These are all fairly self-explanatory. The AddToXXXX subs simply REDIM the appropriate array, and then add the new value to them. The two IsOnXXXX functions loop through the appropriate array and checks if the square at x,y is on the list. If it is, it returns True. If not, it returns False.

Now for the center of the whole program, the FindPath subroutine.

>     Sub FindPath()
>         'A* pathfinding Algorithm
>         Dim c As PointType              'Current Square
>         Dim onFinish As Integer

>         c.x = mStart.x                  'Set the current square to
>         c.y = mStart.y                  'the start square coord.

>         Do While onFinish = False       'Do this while we have not found the Finish square
>             Print ".";
>             AddToClosed c.x, c.y        'Add the current square to the Closed list
>             For y = -1 to 1
>                 For x = -1 to 1
>                     If Not Map((c.x + x),(c.y+y)).mType = Wall Then             'If it is not a Wall square
>                         If (IsOnClosed((c.x + x),(c.y + y))) = False Then       'If it is not on the Closed List
>                             If (IsOnOpen((c.x + x),(c.y + y))) = False Then     'It is not on the Open list, add it

>                                 'Calculate F, G, and H scores
>                                 'G First
>                                 If Map((c.x + x),(c.y + y)).mType = Ground Then
>                                     Map((c.x + x),(c.y + y)).gScore = Map((c.x),(c.y)).gScore + GroundCost
>                                 ElseIF Map((c.x + x),(c.y + y)).mType = Hill Then
>                                     Map((c.x + x),(c.y + y)).gScore = Map((c.x),(c.y)).gScore + HillCost
>                                 ElseIf Map((c.x + x),(c.y + y)).mType = Water Then
>                                     Map((c.x + x),(c.y + y)).gScore = Map((c.x),(c.y)).gScore + WaterCost
>                                 ElseIF Map((c.x + x),(c.y + y)).mType = Cliff Then
>                                     Map((c.x + x),(c.y + y)).gScore = Map((c.x),(c.y)).gScore + CliffCost
>                                 End If

>                                 'Now H score using Manhattan distance
>                                 hx = 10 * (ABS(((c.x + x)-(mFinish.x))))
>                                 hy = 10 * (ABS(((c.y + y)-(mFinish.y))))

>                                 Map((c.x + x),(c.y + y)).hScore = hx + hy

>                                 'Finally, the F score

>                                 Map((c.x + x),(c.y + y)).fScore = Map((c.x + x),(c.y + y)).gScore + Map((c.x + x),(c.y + y)).hScore

>                                 'Make the current square the parent of this square
>                                 Map((c.x + x),(c.y + y)).pX = c.x
>                                 Map((c.x + x),(c.y + y)).pY = c.y

>                                 'Then add this square to the Open List

>                                 AddToOpen (c.x + x), (c.y + y)

>                                 'If it's the finish square, we've found the path!
>                                 If (c.x + x) = mFinish.x And (c.y + y) = mFinish.y Then
>                                     onFinish = True
>                                 End If

>                             Else        'Then it is on the Open List. Check to see if this is the better route

>                                 If Map((c.x + x),(c.y + y)).mType = Ground Then
>                                     tempG = Map((c.x),(c.y)).gScore + GroundCost
>                                 ElseIF Map((c.x + x),(c.y + y)).mType = Hill Then
>                                     tempG = Map((c.x),(c.y)).gScore + HillCost
>                                 ElseIf Map((c.x + x),(c.y + y)).mType = Water Then
>                                     tempG = Map((c.x),(c.y)).gScore + WaterCost
>                                 ElseIf Map((c.x + x),(c.y + y)).mType = Cliff Then
>                                     tempG = Map((c.x),(c.y)).gScore + CliffCost
>                                 End If

>                                 If tempG < Map((c.x + x),(c.y + y)).gScore Then     'This is the better route
>                                     'Make the current square the parent of this square
>                                     Map((c.x + x),(c.y + y)).pX = c.x
>                                     Map((c.x + x),(c.y + y)).pY = c.y

>                                     'Recalculate G and F scores
>                                     'G
>                                     Map((c.x + x),(c.y + y)).gScore = tempG
>                                     'F
>                                     Map((c.x + x),(c.y + y)).fScore = Map((c.x + x),(c.y + y)).gScore + Map((c.x + x),(c.y + y)).hScore

>                                 End If

>                             End If
>                         End If
>                     End If
>                 Next x
>             Next y

>             'Go through the Open List to find the lowest F score
>             curScore = 20000    'Set to a random number to start.
>             For i = 1 to uBound(OpenList)
>             If IsOnClosed((OpenList(i).x),(OpenList(i).y)) = False Then
>                 If Map((OpenList(i).x),(OpenList(i).y)).fScore <= curScore Then
>                     c.x = OpenList(i).x
>                     c.y = OpenList(i).y
>                     curScore = Map((OpenList(i).x),(OpenList(i).y)).fScore
>                 End If
>             End If
>            Next i

>        Loop

>     'We've found the target square.
>     Dim onStart As Integer
>     c.x = mFinish.x
>     c.y = mFinish.y
>     i = 1
>     Do While onStart = False
>         AddToPath c.x,c.y

>         If c.x = mStart.x And c.y = mStart.y Then
>             onStart = True
>         End If

>         x = c.x
>         y = c.y

>         c.x = Map(x,y).pX               'Make the Current Square the parent square
>         c.y = Map(x,y).pY

>         i = i + 1                       'Increment i
>     Loop

>     End Sub

This code goes through the squares, adding them to the open or closed list, until it reaches the finishing square. At this point, it goes from the finishing square and, using the pX and pY of that square, adds each square's parent square to the path.

There are only have a two things left to do. Those are to implement the two remaining subs, DrawScreen and ClearScreen, and to make the code to show the path. The two subs are easy.

>     Sub ClearScreen()
>         Line (0,0)-(639,479), 0, BF
>     End Sub

>     Sub DrawScreen()
>         For y = 1 to uBound(Map, 2)
>             For x = 1 to uBound(Map,1)
>                 Square = Map(x,y).mType
>                 Select Case Square
>                 Case Ground: Line(x * 10, y * 10)-(x * 10 + 10, y * 10 + 10), 2, BF
>                 Case Hill: Line(x * 10, y * 10)-(x * 10 + 10, y * 10 + 10), 21, BF
>                 Case Water: Line(x * 10, y * 10)-(x * 10 + 10, y * 10 + 10), 33, BF
>                 Case Wall: Line(x * 10, y * 10)-(x * 10 + 10, y * 10 + 10), 8, BF
>                 Case Cliff: Line(x * 10, y * 10)-(x * 10 + 10, y * 10 + 10), 7, BF
>                 Case Start: Line(x * 10, y * 10)-(x * 10 + 10, y * 10 + 10), 15, BF
>                 Case Finish: Line(x * 10, y * 10)-(x * 10 + 10, y * 10 + 10), 4, BF
>                 End Select
>             Next x
>         Next y
>         Dim ox, oy As Integer
>             ox = mFinish.x
>             oy = mFinish.y

>             For i = 1 To uBound(Path)
>                 x = Path(i).x
>                 y = Path(i).y
>                 Line (ox * 10 + 5,oy * 10 + 5)-(x * 10 + 5,y * 10 + 5), 14
>                 ox = x
>                 oy = y
>             Next i
>             Circle (comp.x, comp.y), 3, 14
>         Locate 20,1
>             For i = 1 To uBound(Path)
>             Print Path(i).x;
>             Print ",";
>             Print Path(i).y;
>         Next i
>     End Sub

The DrawScreen sub goes through the map, and depending on the mType, draws a colored square at that location. It then goes through the path, drawing a yellow line from square to square. Then it draws a circle at the comp's x and y position (which will be updated in the main part of the program). Finally, it prints out each coordinate for the path (I put that there before I used a yellow line). The ClearScreen sub just draws a black box over the screen (Faster than CLS).

Now, last but not least, we write out our main program which calls the FindPath sub, and shows the user our path.

>     CLS
>     Screen 18

>     Print "Finding Path"

>     FindPath

>     Print "Path Found"
>     sleep

>     ClearScreen
>     DrawScreen

>     For i = 1 to uBound(Path)
>         comp.x = (Path(i).x * 10 + 5)
>         comp.y = (Path(i).y * 10 + 5)

>         ClearScreen
>         DrawScreen
>         Sleep
>     Next i

>     Sleep
>     End

>     That was the easiest part. Now, put it all together to get our final code!

>     DefInt A-Z
>     '$Dynamic
>     Declare Sub ClearScreen()
>     Declare Sub DrawScreen()

>     Declare Sub FindPath()
>     Declare Sub AddToOpen(x As Integer, y As Integer)
>     Declare Sub AddToClosed(x As Integer, y As Integer)
>     Declare Sub AddToPath(x As Integer, y As Integer)
>     Declare Function IsOnOpen(x As Integer, y As Integer)
>     Declare Function IsOnClosed(x As Integer, y As Integer)

>     const Ground = 0
>     const Hill = 2
>     const Water = 1
>     const Cliff = 3
>     const Wall = 4
>     const Start = 5
>     const Finish = 6

>     const False = 0
>     const True = Not False

>     const GroundCost = 10
>     const HillCost = 25
>     const WaterCost = 50
>     const CliffCost = 100

>     Type SquareType
>         fScore As Integer
>         gScore As Integer
>         hScore As Integer
>         mType As Integer
>         pX As Integer
>         pY As Integer
>     End Type

>     Type PointType
>         x As Integer
>         y As Integer
>     End Type

>     Open "board.brd" For Input As #1
>     Input #1, sWidth, sHeight

>     Dim Shared Map(sWidth, sHeight) As SquareType
>     Dim Shared OpenList() As PointType
>     Dim Shared ClosedList() As PointType
>     Dim Shared Path() As PointType
>     Dim Shared mStart As PointType
>     Dim Shared mFinish As PointType
>     Dim Shared comp As PointType

>     For y = 1 To sHeight
>         For x = 1 To sWidth
>             Input #1, Map(x,y).mType
>             If Map(x,y).mType = Finish Then
>                 mFinish.x = x
>                 mFinish.y = y
>             ElseIf Map(x,y).mType = Start Then
>                 mStart.x = x
>                 mStart.y = y
>             End If
>         Next x
>     Next y
>     Close #1

>     CLS
>     Screen 18

>     Print "Finding Path"

>     FindPath

>     Print "Path Found"
>     sleep

>     ClearScreen
>     DrawScreen

>     For i = 1 to uBound(Path)
>         comp.x = (Path(i).x * 10 + 5)
>         comp.y = (Path(i).y * 10 + 5)

>         ClearScreen
>         DrawScreen
>         Sleep
>     Next i

>     Sleep
>     End

>     Sub FindPath()
>         'A* pathfinding Algorithm
>         Dim c As PointType              'Current Square
>         Dim onFinish As Integer

>         c.x = mStart.x                  'Set the current square to
>         c.y = mStart.y                  'the start square coord.

>         Do While onFinish = False       'Do this while we have not found the Finish square
>             Print ".";
>             AddToClosed c.x, c.y        'Add the current square to the Closed list
>             For y = -1 to 1
>                 For x = -1 to 1
>                     If Not Map((c.x + x),(c.y+y)).mType = Wall Then             'If it is not a Wall square
>                         If (IsOnClosed((c.x + x),(c.y + y))) = False Then       'If it is not on the Closed List
>                             If (IsOnOpen((c.x + x),(c.y + y))) = False Then     'It is not on the Open list, add it

>                                 'Calculate F, G, and H scores
>                                 'G First
>                                 If Map((c.x + x),(c.y + y)).mType = Ground Then
>                                     Map((c.x + x),(c.y + y)).gScore = Map((c.x),(c.y)).gScore + GroundCost
>                                 ElseIF Map((c.x + x),(c.y + y)).mType = Hill Then
>                                     Map((c.x + x),(c.y + y)).gScore = Map((c.x),(c.y)).gScore + HillCost
>                                 ElseIf Map((c.x + x),(c.y + y)).mType = Water Then
>                                     Map((c.x + x),(c.y + y)).gScore = Map((c.x),(c.y)).gScore + WaterCost
>                                 ElseIF Map((c.x + x),(c.y + y)).mType = Cliff Then
>                                     Map((c.x + x),(c.y + y)).gScore = Map((c.x),(c.y)).gScore + CliffCost
>                                 End If

>                                 'Now H score using Manhattan distance
>                                 hx = 10 * (ABS(((c.x + x)-(mFinish.x))))
>                                 hy = 10 * (ABS(((c.y + y)-(mFinish.y))))

>                                 Map((c.x + x),(c.y + y)).hScore = hx + hy

>                                 'Finally, the F score

>                                 Map((c.x + x),(c.y + y)).fScore = Map((c.x + x),(c.y + y)).gScore + Map((c.x + x),(c.y + y)).hScore

>                                 'Make the current square the parent of this square
>                                 Map((c.x + x),(c.y + y)).pX = c.x
>                                 Map((c.x + x),(c.y + y)).pY = c.y

>                                 'Then add this square to the Open List

>                                 AddToOpen (c.x + x), (c.y + y)

>                                 'If it's the finish square, we've found the path!
>                                 If (c.x + x) = mFinish.x And (c.y + y) = mFinish.y Then
>                                     onFinish = True
>                                 End If

>                             Else        'Then it is on the Open List. Check to see if this is the better route

>                                 If Map((c.x + x),(c.y + y)).mType = Ground Then
>                                     tempG = Map((c.x),(c.y)).gScore + GroundCost
>                                 ElseIF Map((c.x + x),(c.y + y)).mType = Hill Then
>                                     tempG = Map((c.x),(c.y)).gScore + HillCost
>                                 ElseIf Map((c.x + x),(c.y + y)).mType = Water Then
>                                     tempG = Map((c.x),(c.y)).gScore + WaterCost
>                                 ElseIf Map((c.x + x),(c.y + y)).mType = Cliff Then
>                                     tempG = Map((c.x),(c.y)).gScore + CliffCost
>                                 End If

>                                 If tempG < Map((c.x + x),(c.y + y)).gScore Then     'This is the better route
>                                     'Make the current square the parent of this square
>                                     Map((c.x + x),(c.y + y)).pX = c.x
>                                     Map((c.x + x),(c.y + y)).pY = c.y

>                                     'Recalculate G and F scores
>                                     'G
>                                     Map((c.x + x),(c.y + y)).gScore = tempG
>                                     'F
>                                     Map((c.x + x),(c.y + y)).fScore = Map((c.x + x),(c.y + y)).gScore + Map((c.x + x),(c.y + y)).hScore

>                                 End If

>                             End If
>                         End If
>                     End If
>                 Next x
>             Next y

>             'Go through the Open List to find the lowest F score
>             curScore = 20000    'Set to a random number to start.
>             For i = 1 to uBound(OpenList)
>             If IsOnClosed((OpenList(i).x),(OpenList(i).y)) = False Then
>                 If Map((OpenList(i).x),(OpenList(i).y)).fScore <= curScore Then
>                     c.x = OpenList(i).x
>                     c.y = OpenList(i).y
>                     curScore = Map((OpenList(i).x),(OpenList(i).y)).fScore
>                 End If
>             End If
>            Next i

>        Loop

>     'We've found the target square.
>     Dim onStart As Integer
>     c.x = mFinish.x
>     c.y = mFinish.y
>     i = 1
>     Do While onStart = False
>         AddToPath c.x,c.y

>         If c.x = mStart.x And c.y = mStart.y Then
>             onStart = True
>         End If

>         x = c.x
>         y = c.y

>         c.x = Map(x,y).pX               'Make the Current Square the parent square
>         c.y = Map(x,y).pY

>         i = i + 1                       'Increment i
>     Loop

>     End Sub

>     Sub AddToOpen(x As Integer, y As Integer)
>         Dim TempOpen(uBound(OpenList)) As PointType

>         For i = 1 to uBound(OpenList)
>             TempOpen(i).x = OpenList(i).x
>             TempOpen(i).y = OpenList(i).y
>         Next i
>         size = uBound(OpenList)
>         Redim OpenList(size+1) As PointType

>         For i = 1 to uBound(TempOpen)
>             OpenList(i).x = TempOpen(i).x
>             OpenList(i).y = TempOpen(i).y
>         Next i

>         OpenList(uBound(OpenList)).x = x
>         OpenList(uBound(OpenList)).y = y
>     End Sub

>     Sub AddToClosed(x As Integer, y As Integer)
>         Dim TempClosed(uBound(ClosedList)) As PointType

>         For i = 1 to uBound(ClosedList)
>             TempClosed(i).x = ClosedList(i).x
>             TempClosed(i).y = ClosedList(i).y
>         Next i
>         size = uBound(ClosedList)
>         Redim ClosedList(size+1) As PointType

>         For i = 1 to uBound(TempClosed)
>             ClosedList(i).x = TempClosed(i).x
>             ClosedList(i).y = TempClosed(i).y
>         Next i

>         ClosedList(uBound(ClosedList)).x = x
>         ClosedList(uBound(ClosedList)).y = y
>     End Sub

>     Sub AddToPath(x As Integer, y As Integer)
>         Dim TempPath(uBound(Path)) As PointType

>         For i = 1 to uBound(Path)
>             TempPath(i).x = Path(i).x
>             TempPath(i).y = Path(i).y
>         Next i
>         size = uBound(Path)
>         Redim Path(size+1) As PointType

>         For i = 1 to uBound(TempPath)
>             Path(i).x = TempPath(i).x
>             Path(i).y = TempPath(i).y
>         Next i

>         Path(uBound(Path)).x = x
>         Path(uBound(Path)).y = y
>     End Sub

>     Function IsOnOpen(x As Integer, y As Integer)
>         For i = 1 to uBound(OpenList)
>             If OpenList(i).x = x And OpenList(i).y = y Then
>             'It's on the open list
>             IsOnOpen = True
>             Exit For
>             End If
>         Next i
>     End Function

>     Function IsOnClosed(x As Integer, y As Integer)
>         For i = 1 to uBound(ClosedList)
>             If ClosedList(i).x = x And ClosedList(i).y = y Then
>             'It's on the closed list
>             IsOnClosed = True
>             Exit For
>             End If
>         Next i
>     End Function

>     Sub ClearScreen()
>         Line (0,0)-(639,479), 0, BF
>     End Sub

>     Sub DrawScreen()
>         For y = 1 to uBound(Map, 2)
>             For x = 1 to uBound(Map,1)
>                 Square = Map(x,y).mType
>                 Select Case Square
>                 Case Ground: Line(x * 10, y * 10)-(x * 10 + 10, y * 10 + 10), 2, BF
>                 Case Hill: Line(x * 10, y * 10)-(x * 10 + 10, y * 10 + 10), 21, BF
>                 Case Water: Line(x * 10, y * 10)-(x * 10 + 10, y * 10 + 10), 33, BF
>                 Case Wall: Line(x * 10, y * 10)-(x * 10 + 10, y * 10 + 10), 8, BF
>                 Case Cliff: Line(x * 10, y * 10)-(x * 10 + 10, y * 10 + 10), 7, BF
>                 Case Start: Line(x * 10, y * 10)-(x * 10 + 10, y * 10 + 10), 15, BF
>                 Case Finish: Line(x * 10, y * 10)-(x * 10 + 10, y * 10 + 10), 4, BF
>                 End Select
>             Next x
>         Next y
>         Dim ox, oy As Integer
>             ox = mFinish.x
>             oy = mFinish.y

>             For i = 1 To uBound(Path)
>                 x = Path(i).x
>                 y = Path(i).y
>                 Line (ox * 10 + 5,oy * 10 + 5)-(x * 10 + 5,y * 10 + 5), 14
>                 ox = x
>                 oy = y
>             Next i
>             Circle (comp.x, comp.y), 3, 14
>         Locate 20,1
>             For i = 1 To uBound(Path)
>             Print Path(i).x;
>             Print ",";
>             Print Path(i).y;
>         Next i
>     End Sub

And there you have it! It really isn't too difficult. Here are a few more tips:

#### Preventing the "Go Through Walls" problem

You may notice that in a game, this would generate paths that cut through the corner of the wall. To prevent this, you need to keep A* from checking diagonal squares that are next to a wall. I haven't tried this but have been told it isn't too hard. Go ahead and give it a shot.

#### Turn it into a function

One of the greatest things about any algorithm is the ability to make it into a function. Make the FindPath sub in this code into a function that asks for:

1. An array such as the Map array in this example.
2. A starting square.
3. A Finishing square.

All it would take is a little bit of messing around with the code. Try it out!

#### There is more than the Manhattan Method

There is more than one method of calculating the H score. Here are a couple:

- Euclidean Distance

  The Euclidean Distance is the exact distance in a straight line to the finishing square. It is really only feasible if your units can move at any angle rather than in grid directions (north, southwest, etc.). The formula is:

  > H = D * SQR((TargetX - SquareX)^2 + (TargetY - SquareY)^2)

  Where D is the is the minimum cost to move from one square to another (The lowest G cost).

- Diagonal Distance

  The Diagonal Distance is perhaps a slightly better formula for diagonally moving units (such as in the example). It simply accounts for the ability to move diagonally across squares.

  > H = D * max(ABS(TargetX - SquareX) + ABS(TargetY - SquareY))

#### So in Conclusion

Thanks for taking the time to read this tutorial. I hope I did better this time. This program can be downloaded on my site in the "Programming" section. If there are any questions or comments, you can PM Torahteen on the QBN message boards, or you can post a message on my site's forum. Until next time!

Torahteen

Check out A* Implementation in FB: Part One or download a copy of this tutorial: Astar_Tut2.html

## Music Composition, Part 4

### Written by Matt2Jones

Di-di-di Di-di-di Di-di-di Di-di-di
Part V - Bass Notes

### #1. The Bass Clef

Right, you know how to pick out the chords for a melody (last installment), so now I'm gonna show you how to use those to fill out the sound of a peice of music... Introducing "The Bass Clef"

(I don't have access to a midi program on this computer so I'm gonna have to draw the scores out in paint, apologies...)

Now, the badly drawn curly thing at the right is called a Clef, but this one (unlike the trebel clef), is not called the trebel clef, it's called the bass clef. Why is it called the bass clef? Because the notes on the lines and spaces of this clef are lower in pitch then the ones on the trebel clef (think of the settings on your speakers, turn the trebel up and the sound becomes higher, turn the bass up and the sound becomes deepr). In practice it's best to think of it this way: The guitar plays notes written on the trebel clef and the bass guitar plays notes written on the BASS clef, or similarly: The right hand on a piano plays the notes on the trebel clef, and the left hand plays the notes on the bass clef.

But not only are the notes on the bass clef in a lower octave (and thus lower pitch), they are also differently arranged... Probably a throw back to the original orchestral bass instruments, but for us its just another stupid annoyance. When you look at the bass clef the most important thing to note is the line between the two dots. This line is 'F'. The rest of the notes fit into place around F the same way as the do in the alphabet, but they happen to be in a lower octave (see previous paragraph, ie. bass).

So the lines on the bass clef, from bottom to top, are:

G,B,D,F,A

And the spaces on the bass clef, from bottom to top, are:

A,C,E,G

### #2. Writing Base Notes

Okay, now you know where the notes are on the bass clef, I'm going to show you the simplist way to write a bass line for a melody, just to help you get familiar with it.

Take the Melody:

The Notes in this are:

| C, D, G, E, D, D | E, G, E, D, D, C |

Now, the easiest way to write a bassline for this melody would be to just write exactly the same thing, except on the bass clef!

ie:

(Again, I'm soooo fucking sorry for the horrible graphics.)

But that's also a really bad way of doing things, because it sounds so fucking cheesy (see my post on Pete's board for why I don't like cheesy music)...

So that's why we use chords for harmony.

Back to the original Melody. Last time we worked out that the best chords to accompany the melody would be:

Now, instead of just doubling the melody with the base, we could write any of the notes in these chords in the base and it would sound good (with one or two exceptions I will come to later).

You should be comfortable enough now (or have enough reference material from the articles) to be able to do that correctly yourself, so I'll get right to the exceptions.

### #3. Exceptions to the Rule

Take a look at the first beat in the first bar. On the trebel clef we have a C being played, and on the bass clef we have a C being played, and the chord is CEG.

Now, remember back when we did chords and I told you the first note of a chord is called the root, the next is the third, and the next is the fifth? Well you need to remember that now.

In this case the trebel clef has the first, and the bass clef also has the first. This is perfectly acceptable, likewise would be if the trebel clef had the fifth, and the base clef had the fifth, or if the bass clef had the first and the trebel clef had the fifth, or if the trebel clef had the first and the bass clef had the fifth. Basicly any combination of the first and fifth notes of a chord is fine.

However, take a look at the first beat of the second bar. The trebel clef has the third, and the bass clef also has the third. This is bad. The general rule is YOU CANNOT DOUBLE THE THIRDS. If you have a third in one clef you must have either the fifth or the third in the other.

End of Exceptions.

### #4. Rhythm

When we get on to melodies I'll explain more on how to write rhythm, but for now I just want to point out another rule of thumb.

When there is allot of movement in the trebel clef (ie. Lots of quavers, semi-quavers, etc) then there is little movement in the bass clef (ie. Lots of minums), and vice-versa.

And this concludes it.

> All we have left to do is:
> > Writing Melodies
> > Chord Progressions
> > Cadences

Then you're all educated.

matt.

Download a copy of this tutorial: Music_tut.rtf

## C++ For The BASIC Programmer

### Written by The Awakened

C++ is known to be a tougher language to learn. For a Basic programmer, it may seem a bit overwhelming to see all these arcane commands. But in reality, the Basic commands you've learned aren't all that different from C++'s equivilents. And this tutorial is aimed to help you learn the language of C++, within the frame of reference of the BASIC language. At times it's more of a reference sheet than a full out tutorial.

Maybe you never plan to code C++. But it can be useful to learn. If you want to check out source code from a cool program that was written in C++, hey, guess what? You have a relative idea of how they did it, and you can see the algorithms that they used. C++ is a powerful language, but it has many shortcuts (such as object oriented programming... if only FreeBasic was Object oriented...), and perhaps you will decide to do some code in C++.

Just so you know, I use the Dev-C++ IDE/Compiler. You can download it from www.bloodshed.net, it's totally free.

Let me also say that I have a minimal amount of experience in C++ programming, just enough to do some simple stuff. This tutorial doesn't explain every nook and cranny of each statement, just enough to get you by. Remember, this is an introduction reference, not a thorough tutorial. Personally, I think that a graduate of BASIC should be able to understand most of this fairly easily. However, it seemed like every time I tried reading a C++ tutorial, is was aimed at Computer Science majors.

So let's talk about the differences between Basic and C++. I guess an example is in order. Let's check out a Basic Program, and a C++ program. I'm sure you know what program I'm talking about...

>     [Basic]

>     PRINT "Hello, World!"

>     [C++]

>     #include <cstdio>
>     #include <cstdlib>
>     #include <iostream>
>     using namespace std;

>     int main (int nNumberofArgs, char* pszArgs[])
>     {
>     cout << "Hello, world!" << endl; //this is a comment!
>     system("PAUSE");
>     return 0;
>     }

Holy crap.

What all did we do here? Let's go line by line.

The first 3 lines include some essential files that set up things like how to print to the screen, how to get input from the user, etc. See, when QB compiles a program, it adds in a load of additional code that allows you to do all that stuff as well, that you don't have to worry about. C++ allows you to pick and choose what functions of the language you'll need to include. "using namespace std" is beyond this tutorial. "int main..." is the main part of your program. There's another difference. You need to declare the main module of your program as a function or subroutine, so that the compiler knows where to start. There must be a function declared as "main". The curly braces just represent the beginning and end of a block of code. They're used in If statements, loops, etc. The next line is the command "cout" (pronounced "see out") which is the equivilent of Print. endl represents another difference. In Basic, every time you start a new Print command, a new line is used. But in C++, if you do 2 cout statements without an endl, they'll both be on the same line. endl stands for End Line, if you didn't figure that out. // is how you declare a comment. system, I believe, is like QB's Shell command. Return 0 returns a value to the innards of the included C++ code.

Notice that there's a semicolon after some of the lines. These are after most statements, but they're not after #include's, declaration of functions, and in some other cases we'll see later.

Okay, so we've gone over the basic template, as well as the equivilent of Print. Let's move on to variables.

You must declare your variables before you use them. The syntax to declare a variable is:

>     [variable type] [variable name]

Integers, known as int when declaring them, are 32 bits wide, so they're the same as QB's LONG integers (they have a range of negative 2 billion to positive 2 billion, roughly). Unsigned integers are declared as "unsigned", and have a range of 0 to roughly 4.3 billion. Single precision decimal numbers are declared as "float", double precision decimal numbers are declared as "double". Oh, and you can use a boolean variable, simple declared as "bool".

C/C++ programmers used to have to make an array of "char" variables, and then string them together. However, the ANSI standard is currently moving away from this. There is actually a string variable type now. To use strings, you have to include the file "string".

Manipulation of variables is pretty much the same. However, there are a few things that can be used to speed up the typing of incrementing and decrementing of variables by 1. The following are the same:

> x=x+1
> x++

as are these:

> x=x-1
> x--

So here's an example where I declare a bunch of variables and assign some variables:

>     int a;
>     unsigned b;
>     float c;
>     double d; //hahaha... how'd that manage to happen? Wink
>     bool e;
>     string f;

>     a = 4;
>     b = 4000000000;
>     c = 0.98;
>     d = 3.1415;
>     e = true;
>     f = "Hello, World!";

I could do the same thing, but quicker:

>     int a = 4;
>     unsigned b = 4000000000;
>     // and so on

Arrays are simple to do as well. Example here:

>     int x[50]

This creates 50 variables of x. However, when you go to use them, the first variable is 0, the last (in this example) is 49. It's like saying OPTION BASE 0 in QB.

The next command we'll learn is cin ("see-in"). It's like Basic's INPUT command. The syntax is like this:

>     cin >> string;

Note a couple of things: first of all, you can't print text and input in the same cin command. You have to go like this:

>     cout << "What is your name? ";
>     cin >> string;

That way, you don't include an endline, and it's on the same line. Let's take a look at an example program that uses this stuff.

>     #include
>     #include
>     #include
>     #include
>     using namespace std;

>     int main (int nNumberofArgs, char* pszArgs[])
>     {
>     int nVariable;
>     string sVariable;

>     cout << "I need you to input a number for me ";
>     cin >> nVariable;
>     cout << "\nOkay, how about a string? "; // \n starts a new line
>     cin >> sVariable;
>     cout << "\nThe number was " << nVariable << "\nand the string was " << sVariable;

>     system("PAUSE");
>     return 0;
>     }

Now, that program doesn't like spaces in the string, and offhand, I'm not sure how to handle spaces.

Boolean operations are pretty simple. For starters, a subtle difference in C++ is, when you're comparing variables, to check if they're equal, you can't go just a single = sign. You must go == to differentiate from the single = sign, which represents assignment of a value. AND is represented as &&, OR is expressed as ||, and NOT is expressed as !. To check for inequality, it's !=. Greater than and less than are the same. To do completely bitwise operations, AND is represented by a single &, OR is a single |, XOR is represented by ^, and NOT is ~.

So now that we have Boolean operators, guess what's next? Conditional statements. First up is if. The syntax is:

>     if(condition)
>     {
>     //code goes here
>     }
>     elif(condition)
>     {
>     //code goes here
>     }
>     else
>     {
>     //code goes here
>     }

Note that there's no semicolon in front of the "if", "elif", or "else" statements. That's because they have the {} brackets. That's the same as functions. Also note that it's not "elseif", it's just "elif".

The other conditional statement is "switch", which is like Select Case. Syntax:

>     int variable

>     switch(variable)
>     {
>     case 1;
>     //do stuff
>     break;
>     case 2;
>     //do stuff
>     break;
>     default;
>     //do stuff
>     }

Let's note a few things. First of all, there's a break statement at the end of every case. IF YOU DON'T INCLUDE THIS STATEMENT, THE PROGRAM MOVES ON TO THE NEXT CASE, and control "falls through" to the next case selection! This is very important to distingush from QB. This can also be useful, depending on how you use it.

default is like Case Else. That's about it for control statements.

Moving on to loops... unlike QB with it's 5 or so syntaxes for 3 kinds of loops, C++ strips it down to 3 syntaxes: while, do/while, and for. The syntax for while is:

>     while(condition)
>     {
>     //code here
>     }

No "WEND", no nothing. Gotta love those squiggly brackets. Example:

>     int variable;

>     while(variable<5)
>     {
>     cout<<"Variable is less than five!"<

Remember, while statements only execute if the condition is met, as opposed to the Do...while statements, which execute the code block and then check for the condidtion. Syntax:

>     do
>     {
>     //code
>     }
>     while(condition)

Next up: For loops. The syntax is as follows:

>     for([initialization];[condition];[increment])
>     {
>     //do things... and... things
>     }

Initialization is where you declare your counting variable. In Basic, you just have to go FOR x% = ..., well, in C++, like any other case, you've gotta declare your variables before you use them. Condition is self explanatory, and increment is where you say how much the variable will be incremented by. Example:

>     for(int x = 0; x < 5; x++)
>     {
>     cout << x <<" loops so far!" << endl;
>     }

Our final topic here is subroutines and functions. In C++ coder's jargon, the word "subroutine" is eliminated, and everything is known as a function. The syntax is as follows:

>     [variable type] [function name] ([var type] [arg name], [var type] [arg name] etc.)
>     {
>     //code here
>     return [value]
>     }

Variable type is whatever type you want the function to return. If you don't want it to return a value (just be a "subroutine"), then you put "void" for the variable type, and exclude the return statement. Function name is whatever you want to call the function, and var type and arg name is where you declare the arguements of the function. You've gotta include a return statement if the function can return one. And so you know, the function "main" must be an int (or that's what my compiler tells me, not sure about other compilers).

Sadly, that's it for now. I've been busy lately, getting only about 1 to 2 hours of time off... that's not counting time I have to do homework in. Next month, I'm probably going to finalize my Object Oriented Programming tutorial (just gotta do Polymorphism), and then in that same issue, I hope to talk about the C Standard Library, files, pointers, Object oriented programming (LOADS to talk about there), and anything I missed here.

Good luck in your programming!

-The Awakened

## Ally Artificial Intelligence

### Written by Jonathan Wallace

Last month I wrote an article on writing artificial intelligence for enemies. This month I intend to explain a little bit about writing artificial intelligence for allies. Very few games, even console game, have allies that will assist you through the levels. Lots of times you want to be alone, I mean everybody is more afraid when they are alone; but then it is just you sneaking around shooting enemies. Sometimes it is good to take a break from fighting and watch a high action fight between a few allies and some enemies. The fighting is good, but the allies will shoot and toss grenades and blow stuff up, making the fight higher octane and more wild.

The allies AI is not that much different from the enemies. Both need to seek out the opponents and destroy them, but enemies tend to stay in one spot. You allies’ purpose is to assist you through the level, so they have to be able to stay around you, even if you turn a few corners.

You need to be able to write AI and an A* routine. There was a really nice A* tutorial in the last QBExpress, so you can use that to help you, or use what I do. My method will be explained later.

Allies are there to back you up. They are lower ranked then you so they are there to back up and give you support, not fight on their own. You have to have scripts in the AI for looking out for you. If you get shot they should turn on the enemy that hit you. This is pretty easy. When the player gets hit have it should change something in the AIs memory blocks. I am giving each AI construct 25 memory blocks, each one is used for something else. Say you have an array Aimemory(255, 24), make Aimemory(ally, 0) change when the player gets shot.

>     CONST TRUE = 1
>     IF Aimemory(me, 0) = TRUE THEN hitlist(me, 0) = guy_who_shot_player

The hitlist() array is how each ally knows who is it fighting and who is next after it's dead. It can also change depending on who pisses the AI off. If the player is shot then the hitlist() will change to the enemy that shot it. Who said that AI can’t have an attitude.

The ally should always be brave, but cower a little bit. Human tactics are to hide and spring around a corner and shoot in quick bursts. If the ally can’t see the subject of its hitlist variable have it strafe until it sees it. Then have it fire for about a second and strafe back behind whatever it was hiding behind.

The ally should never be too close or too far away from other allies so as to not accidentally shoot them, or get stranded. Every second or so have the player access where it is, have it add all of the distances together, then divide by how many. This takes the average of all of the distances, it should also average all of the positions of the allies, so that it knows where the center of all of the allies are.

>     IF average_distance < 3 THEN ‘too close together
>     	CALL Turn(direction(me, centrex, centrey))
>     	CALL go forwards(me)
>     ELSEIF average_distance > 6 THEN ‘too far apart
>     	CALL Turn(direction(me, centrex, centrey) + 180)
>     	CALL go forwards(me)
>     ELSE ‘just right to really fight

Between 3 and 6 seems like a small range, but it is larger than you think, remember that it is an average, you can have allies fighting off on their own tangent, as long as there are a few close together. It will make it seem like they are really fighting together, but still have that human curiosity.

So, how do we make them follow the player, but still have their own minds? First you have to know when to go towards the player. How about we set the distance trigger at 8. Now if the distance from the player to the ally is more than eight it will move towards the player. If there is a wall in between them you need to find a pathway. This requires either an A* routine or something new.

Take a look at the diagram below.

A* has some ups and downs. The biggest thing is that it gives you the straightest route (purple), however the major problem is that it is recursive. On a large map even an efficient routine can get slow, and if you have a lot of allies it could really slow up the game.

Here is my solution, make another map. Your computer has RAM to spare, not CPU ticks. Directionmap(100,100) is a great alternative to A*. Your game is probably going to be pretty linear, and you know the direction that the player will be traveling (Green.) So make a map that points the way. If your game is non-linear it give the ally a sophisticated “I’ll meet you there” type of attitude. Here is an example of a map that is fairly complex, the green dot is an ally and the red dot is the player. Most allies in Qbasic would walk directly to the wall to the right of it and just keep running into the wall (Orange.)

But with this simple line in the AI it will eventually find its way to you.

>     IF distance(me, player) > 8 THEN
>     	CALL turn(me, map(playerx(me), playery(me)))

This will guarantee that the ally will find you and help you out. With this code in the construct it will never get this far away from you, it is possible to be eight squares away and several walls away, such as above, the player is only 9 squares from the ally.

-Jonathan Wallace

Visit Wallace Software or download a copy of this tutorial: allyAI.doc

## Database Design - A Complete Study
Part 3 - Structured Query Language

### Written by Stéphane Richard (MystikShadows)

### INTRODUCTION:

And here we are, the third and final part of this series. As promised, this document will cover everything you need to know in order to create, maintain, and query a database properly using the SQL (Structured Query Language) as it is implemented in the MySQL Database System. As such, this document will have a lot of theory to cover. I'll try to keep it as simple and as basic as I can while giving you all the syntaxes you'll need to cover all bases of Database Creation and administration. Remember that the main reason I chose MySQL is because of it's resemblance to most other database systems out there. So what you learn here will help you alot if you have things to do in other database systems.

First we'll cover the theory of database creation constructs in SQL and why they are the way the are. Then we'll create scripts to create all the tables that we defined in the second part of this series including primary keys and indexes. And we'll continue with the explanation of the SQL syntax to insert, update, delete records from tables and well also see how to query the database to retreive the information you want and need. With all this, you should be equipped to create your own MySQL database projects. So then let's get right to it.

### CREATING AND SELECTING A DATABASE:

This is among the simplest statements you'll need to remember. For the sake of this series we'll call our database Business. Now, the statement to create our database is defined as follows:

>     CREATE DATABASE <DatabaseName>;

There you go, pretty simple no? This statement alone will go about creating a database for you. Now once the database is created, you won't be able to do anything with it unless you are using the database first. It's important to remember the semicolon ";" at the end of the SQL statement. Most statements in MySQL (and other SQL implementation) use this ; to indicate the end of a complete SQL construct. So put that in your brain right off the start. Next thing you need to know of course is how to use the database you just created. Here's the statement that will do just that:

>     USE <DatabaseName>

There you have it, it's that simple. This will make sure that the database is in use and ready to be used. You might notice that I didn't put a semicolon here. the USE statement is one of the rare statement that doesn't need a ; to complete it's construct. You could put one of you wanted to but it is not mandatory. Now for the purpose of our series. Here is the code you'll need to create and the use the Business database:

>     CREATE DATABASE Business;
>     USE Business

With these two statements, Business is now created, used, and ready for action. It's really as simple as that. The good thing about SQL, as you'll discover here is that it's pretty close to the english language and as such, pretty easy to understand.

### MYSQL DATA TYPE REVIEW:

Before we go ahead and create our tables, I think it's important to review the data types we have available to us when defining our table structures. There are quite a few of them to allow for a greater flexibility and accuracy in our field definitions. So let's review them here:

- CHAR(Length) and VARCHAR(Length):
  These are the text data types. CHAR(Length) is there for the text fields that will always need the same amount of characters. For example, Social Insurance Numbers always have 9 digits, and so on. VARCHAR(Length) are provided for those fields which may vary in length for whichever reason. For example, Names, descriptions and so on.
- BOOLEAN data types:
  This data type serves to indicate fields that can be represented as TRUE (1) or FALSE (0) (these constant are available in MySQL and most other database system) so you can use either the number or the TRUE or FALSE constant when comparing these fields.
- BIT(Length) data type:
  This data type offers the ability to specify it's values at the bit level. It is a binary datatype that can be of any length specified. Therefore if you define a field a BIT(4) you can set it's value to anything from "0000" to "1111" in binary (0s and 1s only). This is useful for fields that will play the role of flags to setup a given module of a program for example.
- INTEGER, FLOAT and CURRENCY data types:
  These are the basic numeric values that you can put in a database. INTEGERs are whole numbers that do not have a decimal value. FLOATs have the ability to hold a decimal point and fractional values. Depending on the role of your numeric data, using INTEGER when you can will make the table shorter in size. The CURRENCY datatype is a number that typically will only have 2 digits after the decimal point and work best for all monetary values.
- DATE and TIME data types:
  These types pretty much speak for themselves. They are designed to hold specific date and time values and are also made to be interrogated specifically based on a date and/or tume value.

NOTE: There are many more data types that you are likely to find in a MySQL table definition. Those mentionned here represent the datatypes that you will most likely need in the course of your database related projects.

### CREATING TABLES, PRIMARY KEYS AND INDEXES:

Ok, now that we have a database, it is pretty useless unless we have tables in there to store our information. Of course SQL provides a series of CREATE statements to help us create tables, primary keys and indexes. Tables are the actual table that will hold the information we have to save. Here's the definition of the CREATE TABLE construct which can be used to create a table for our database: (note that this is a simplified definition, for a complete syntax of the CREATE TABLE statement take a look here.

>     CREATE TABLE <TableName>
>                ( <FieldName>  <DataType> [UNIQUE|AUTO_INCREMENT|NOT NULL],
>                  <FieldNameN> <DataType>, ... ) ;

With this statement you can build all of your table definitions. UNIQUE means it doesn't allow DUPLICATE values for that field in a given table. The AUTO_INCREMENT and the NOT NULL attributes are ways to specify certain behaviors for a given field (see the complete CREATE TABLE statement definition mentionned above). AUTO_INCREMENT basically tells the table that the field will be incremented in value everytime a record is added to the table. NOT NULL states that the field cannot allow itself to receive a NULL value (A key field for example should never allow a NULL value to be saved or it defeats the purpose of the key).

Primary Keys are indexes that are specifically created to make sure we don't have duplicates in our table or to make sure that each record we'll save in our table can be uniquely identified (or found). Make a special note that any table you create should have a means of being able to find a record and only one record in some way or another (A big rule of thumb so to speak). They are created in the CREATE TABLE statement as part of the field definitions (inside the parenthesis) as follows:

>     CREATE TABLE <TableName>
>                ( <FieldName>  <DataType> [UNIQUE|AUTO_INCREMENT|NOT NULL],
>                  <FieldNameN> <DataType>, ...,
>      PRIMARY KEY (<FieldName>) ) ;

Indexes are preset orders in which the table records will be presented in. Like the primary key, indexes can be specified in the CREATE TABLE as well. Quite simply, it follows the same rules as PRIMARY KEY except that PRIMARY is not used. For example:

>     CREATE TABLE <TableName>
>                ( <FieldName>  <DataType> [UNIQUE|AUTO_INCREMENT|NOT NULL],
>                  <FieldNameN> <DataType>, ...,
>              KEY (<FieldName>) ) ;

That simple. Note that you can of course combine KEY statements for as many fields as you want to create an index on. Just seperate them by commas as you would use to seperate the fields in the TABLE definition. For the sake of example, let's create the complete CREATE TABLE statement to create the first table we defined in the 2nd part of this series, the Customers table. It would look like:

>     CREATE TABLE Customers
>                  (CustomerID 	INTEGER     AUTO_INCREMENT,
>                   CustomerName 	VARCHAR(50) NOT NULL,
>                   IsCompany 	BOOLEAN,
>                   CustomerSince 	DATE        NOT NULL,
>                   Address1 	        VARCHAR(60),
>                   Address2 	        VARCHAR(60),
>                   City 	        VARCHAR(40),
>                   State 	        VARCHAR(25),
>                   ZipCode 	        VARCHAR(8),
>      PRIMARY KEY (CustomerID),
>              KEY (CustomerSince) );

This is one of the many tables we have. Using the same syntax as the Customers table defined here, we could create a series of create table statements to create the whole database. I'm not going to define all the create tables at least not in the context of this series. But this table definition should help you tremendously when creating the definitions for the other tables. Here are a few useful Statements you might find yourself using often when creating databases and tables.

>     -- To Show the databases that are already created:
>     SHOW DATABASES

>     -- To show the tables that are created:
>     SHOW TABLES [FROM <DatabaseName>]

>     -- To display the structure of a table definition:
>     DESCRIBE <TableName>

>     -- To rename an existing table to another name: (very useful)
>     RENAME TABLE <ExistingName> TO <NewName>

>     -- To remove an existing table from the database:
>     DROP TABLE <ExistingName>

### INSERTING, UPDATING AND DELETING RECORDS:

So we now have a table in our Business database called Customers. The next logical step of course is to be able to add and manipulate data into the table. Here too, SQL provides all the constructs you'll need to add, update and delete records from your table(s). Let's start with Adding records. To do so, you need the INSERT statement which is defined as follows:

>     INSERT [INTO] <TableName> [(FieldName, FieldNameN, ...)]
>            VALUES (Value, Value, ...);

One thing to notice here is that the FieldNames are optional. There is a condition though. You don't have to supply the field names if your VALUES list covers all the fields of your table. If you are only saving data for some fields, you'll need to specify those fieldnames. That's the only condition. If we take this to our example, and insert a customer into our Customers table. our SQL statement will look like this:

>     INSERT INTO Customers
>          VALUES ('MystikShadows',
>                  FALSE,
>                  '09/11/2005',
>                  '99 NoName street',
>                  '',
>                  'Nowhere',
>                  'NoCountry',
>                  '00000' );

Make sure that the type of data you are inserting corresponds to the data type of the field you are inserting your value into. That's always important as you can probably imagine.

You have records and you notice you made a mistake in the values you just inserted. What do you do? Simple you use an UPDATE statement to change just the fields you need to change. This is one situation. Another situation where you might need the UPDATE statement is when a customer changes address on you and calls you to make the change. The UPDATE statement is defined as follows:

>     UPDATE <Tablename>
>        SET <FieldName>  = <Value>,
>            <FieldNameN> = <Value>, ...
>      WHERE <FieldName>  = <SearchValue> [AND/OR <FieldName>  = <SearchValue>];

This is where the PRIMARY KEY comes in handy. Say you have 2 customer records, one is identified as 1 and the other has 2 for it's CustomerID field. if you want to change the 2nd record's City and State fields, here is how it could be done in SQL:

>     UPDATE Customers
>        SET City  = 'NoPlace',
>            State = 'New York'
>      WHERE CustomerID = 2;

Once again you can see how simple things get with a language that is as close to english as SQL is. It basically says Update the Customers Table, Set City to 'NoPlace' and State to 'New York' where the CustomerID is 2. SQL will first seek the record that has CustomerID equal to 2 and then proceed to change the two fields we specified with the specified values. Note that in these examples I separated the constructs in multiple lines because they look clearer this way. but all these could be in one extra long line and would still work as they should. This is for formatting purposes only. You can use more than one field in your WHERE clause to further narrow down the resulting records that will be affected.

Now that we have records and we can change their values, what happens if you ever want to get rid of a customer alltogether as if he/she never existed? Once again SQL has a statement for the job. All you need to do is use the DELETE statement, which is defined as:

>     DELETE FROM <TableName>
>           WHERE <FieldName> = <SearchValue> [AND/OR <FieldName> = <SearchValue>];

That's it, this simple statement can either delete one specific record from the table or delete a whole set of records (depending on what you specify in the WHERE Clause and the contents of your table). In our Customers table, let's say we'd want to delete the customer that has a CustomerID field of 2, we would do it as follows:

>     DELETE FROM Customers
>           WHERE CustomerID = 2;

And there you have it. You now have all the knowledge you need to do some simple database maintenance on your own. You can now create databases, create tables in your databases, insert records, update them, delete them, you can do pretty much all you need as far databases are concerned. There's only one thing we haven't done yet as far as simple database operations are concerned. And we'll see that in the next section right now.

### SELECTING FROM A TABLE:

What use would a database have to it's users if there was no means of interrogating it's contents? Absolutely none is the right answer. Indeed if you can't find specific data that you stored in a database, the database isn't of much use. Well SQL provides all you need for doing just that. It is called the SELECT statement. Logical name to get records from a database no? The SELECT statement is defined as follows: (note again this is a simplified version, look here for a complete definition of the SELECT syntax).

>     SELECT *|<FieldName>, FieldNameN>, ...
>       FROM <TableName>
>      WHERE <FieldName> = <SearchValue> [AND/OR <FieldName> = <SearchValue>];
>     [ORDER BY <FieldName> ASC|DESC];

This indicates to select all the fields (*) or the list of field we specify from the TableName where the conditions are met to return the record or group of records. If we don't specify a where clause, all the records in the table will be returned. Basically the SELECT statement can be used in more than one way. The ORDER BY clause simply tells SQL to display the returned records in the order of the FieldName(s) specific either ASCending OR DESCending order. Here is a typical select statement from the Customers table:

>     SELECT * FROM Customers
>             ORDER BY CustomerName;

This is the shortest form of the SELECT statement, it will return every single field there is in the Customers table and all the records that have been added to the table.

>     SELECT CustomerName, Address1, Address2
>       FROM Customers
>      WHERE CustomerID = 2;

This one will select only the 3 specified fields from the database and will return only the customers that have a CustomerID of 2 (in this case, only one customer will be returned). Now, let's say we have an Invoices table and we wanted to select specific fields from both Customers and Invoices table, a very straightforward way to do so would be to simply combine them in a SELECT statement, like so:

>     SELECT Customers.CustomerName,
>            Customers.Address1,
>            Customers.Address2,
>            Invoices.InvoiceNumber,
>            Invoices.InvoiceDate,
>            Invoices.TotalInvoice
>       FROM Customers, Invoices
>      WHERE Invoices.CustomerID = 2;

What this particular SELECT statement will do is return the Customer's Name, Address1 and Address2 fields as well as the Invoices Invoice number, Date and Total all in one row for each invoices that has a CustomerID field set to two. Depending on your specific needs, this could be enough for alot of your database querying. Just combine your Fields (by specifying which table the belong to like I did) and list the tables in the FROM clause seperated by a comma. You can do this for more than 2 tables too.

Now things can get much more complicated than this. These SELECT statements are good when you only one a specific set of records (in this example, only the invoices that belong to the Customer that has a CustomerID of 2). Likewise, this is just oen set of tables. If you want to get more specific data from the database, then you just might need to learn all about the JOIN statement. For example, if you only want the details of the invoice, you could add it in the las select statement as a 3rd table, but the result will get messy, especially if you need 4 or 5 tables.

### THE JOIN STATEMENT:

The JOIN statement plays the role of connecting two or more tables with conditions. This helps keep all the tables in sync while you are doing your querying. In this document, I will only be covering standard left joins (where the parent table has a one to many relationship to the joined table) as this is what you'll need to know for atleast 95% of your JOIN experience. The other joins work the same, it really all depends which table you are starting to join from. Here is how the JOIN statement is defined (it is usually part of a SELECT statement so we'll take our previous example and JOIN it instead of a standard combined SELECT query. Again this is a simplified Definition. You can look here for the complete JOIN syntax.

>        SELECT *|<FieldName>, FieldNameN>, ...
>          FROM <ParentName>
>     LEFT JOIN (<JoinedName>)
>            ON (<ParentTable>.<FieldName> = <JoinedTable>.<FieldName>, ...)
>         WHERE <FieldName> = <SearchValue> [AND/OR <FieldName> = <SearchValue>];

RIGHT JOIN statements are for when the Parent Table has a Many To One relationship with the joined table. Quite simply put, you could get "relevant" data from 2 or more Tables using this type of join statements. As an example, let's say we have Customers, Invoices and InvoiceDetails for tables and we would like all the invoices and their details (what they purchased) for a given customer and we'd like to know the customer's name as well. Using the LEFT JOIN statement, we could do it this way:

>        SELECT Customers.CustomerName,
>               Invoices.InvoiceNumber,
>               Invoices.InvoiceDate,
>               Invoices.TotalInvoice,
>               InvoiceDetails.PartNumber,
>               InvoiceDetails.Description,
>               InvoiceDetails.UnitPrice,
>               InvoiceDetails.Quantity,
>               InvoiceDetails.LineTotal
>          FROM Invoices
>     LEFT JOIN (Customers)      ON (Invoices.CustomerID = Customers.CustomerID)
>     LEFT JOIN (InvoiceDetails) ON (InvoiceDetails.InvoiceNumber = Invoices.InvoiceNumber)
>         WHERE Invoices.CustomerID = 2
>      ORDER BY Invoices.InvoiceDate;

Now, this still seems understandable doesn't it? For all that matters it's a SELECT statement. The things to watch out for when creating a JOIN statement are. First, be sure that when you are joining two tables, the field you are using in the ON clause is relevant to the two tables. As you can see here I joined the Customers.CustomerID to the Invoices.CustomerID, both of these represent a field that Identifies the customer in both tables. I did the same thing on the 2nd LEFT JOIN Because both fields there represent an InvoiceNumber in both tables. If you can inderstand that small detail, JOINs will quickly become quite trivial to you.

### AND THE FINAL WORD OF THIS 3RD INSTALLEMENT:

This concludes our 3rd installement in this database study. The best thing to do at this point is to fire up MySQL and practice what you've learned so far, insert some relevant data into your tables work on your INSERT, UPDATE and DELETE and get familiar with them as much as you can. Then once you have a couple of tables that can be JOINed together in some way, go right ahead and practice your JOIN statements.

In the next (and final) installement, I'll teach you another side of SQL. You see, SQL isn't only used to interrogate the database or insert and delete records. SQL has another very useful purpose. That purpose is reporting. Indeed you can create some very sophisticated reports in SQL that will really help your users see the real information they want to (read need to) see. We'll cover everything that MySQL's SQL implementation has to offer to help you create some very detailed and explicitally intricate reports on data that can help the user understand what they are looking at and also quickly see totals on given intervals of time or other factors. Reporting in SQL is just as natural as it is what we've read about in this document. So get yourself ready for the next and final installement. You'll seen then exactly how useful SQL can be. Until then, happy coding. As always, you can email me with comments or questions, I love to get emails.

> MystikShadows
> Stéphane Richard
> srichard@adaworld.com

Download a copy of this tutorial.

## Final Word

Well that's it for a spectacular FOURTEENTH issue of QB Express.

Before I let you go, I'd like to share with you a few quotes on programming that were sent to me by Matt2Jones.

> "It is often been said that a person does not understand something until they can teach it to someone else. Actually, they do not understand it unless they can teach it to a computer."
> Donald Knuth - Algorithm guy.

And here's another one that I think that really reflects how this issue of QB Express came together (the fastest of any issue):

> "Speed/Space = Efficiency"

Just some food for thought for all you QB / FB coders out there.

The deadline for QB Express #15 submissions is: October 15th. Everyone please write something! QB Express wouldn't exist without submissions from you, the readers!

Until next time...END.

-Pete

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