QB Express

Issue #16  ~  November 26, 2005

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

In This Issue



From The Editor's Desk

Written by Pete

Hello again, folks!

It seems like just a few weeks ago that the last issue of QB Express came out...because it was. It's been only about three weeks since Issue #15. But despite the shorter timeline, we've still managed to scrape together another great issue.

This issue, we've got a Gallery preview of Lithium's new FPS "The Janitor," both Bobby The QBasic Maniac and QB Horse Humor comics, and more news briefs than you can shake a stick at. Lachie Dazdarian reviews Bozula Block Buster, MystikShadows looks at Tera-Mamoliny, Agamemnus tells us about Programming Language Syntax Tenets, Simon Bradley describes porting the Official Hamster Republic RPG Creation Engine, and Lachie Dazdarian provides us with a great article called "Writing A Story For A Computer Game."

For tutorials this month, MystikShadows continues his GUI Design series with parts 3 and 4, Rick Clark tells us about "Managing Complexity" and explains those data structures called Unions, and Imortis Inglorian instructs us on how to create a simple QB/FB text parser.

All in all, another great issue of QB Express. I won't hold you any longer -- go ahead and read 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

Wow, yet another outstanding issue as far as articles, reviews and tutors are concerned. And how about that news section, it sure is growing too, what a good sign of a striving community indeed :-). You must be a psychic, it is a few hours after it's release and lo and behold, and here I am making sure you hear from me lol.

Ok, I'd like to talk about what memnonite said, and what you said. I'm not exactly sure how these emails developed from the first one to the last I've read, not sure what happened in memnonite's life that basically turned him around so to speak, not sure if he'll feel the same way next month, if it was somekind of a temporary drift of reality or what. I've always had a good degree of respect towards him. And that was one of the reason I wrote what I wrote about him in my last letter to the editor. and I quote myself: "Mennonite's "It's Been A Dark Month, Hasn't It?" really left a mark. Although I don't think it's been a dark month (looking at this issue, it hasn't been a bad month at all :-). However it doesn't take anything away from his positive thoughts he projects through his letter. Everyone should print this letter and read it (and reread it too) whenever they fell like giving up. It's one of the most motivational and powerful article/letters I've ever read. It says a lot about mennonite himself. Wish more people had that kind of thinking. :-). " I said this about his letter in QB Express #14. Err am I a psychiatric case for quoting myself, doesn't it hint a dash of "talking to myself here"? lol This is the memnonite I know and respected. So I don't know why things happened the way the did in the course of the last month, like he said himself, looks like he really was depressed and I'm hoping that's just what it was and that he'll get back on track soon :-) I really enjoyed reading his material alot. To me, I agree with what you said (and I can talk about this because I'm probably atleast as big a DOS lover as he is as I've proven time and time again ;-), I even made a whole website about the subject lol. So I do know where he's coming from. He's wrong about the community itself, like you I think it's atleast trying to help out when intelligent questions are asked. I don't like to do people's homework when I know that the reason they didn't do it themselves is probably because of too many parties (college is to prepare one's self for a career, it's the future of their lives and if they wanna drink it away and have fun rather than study and work at their future, I hold no respect for that). But yeah in my opinion he's wrong, like you said the platform doesn't matter, it's the people that make the community, not the language. Now the RTFM shouldn't be taken as a flame or an insult. One thing my career as a programmer thought me is that self sufficiency is one of the most important aspect of development. If you do the 10 second google search and find the answer, you bettered yourself while the person that asked the question did not, at all. They need to be able to find the answers by other methods than asking question. The answer is out there, they just need to learn to find it. Hmmm, a tutorial on that might be a good idea :-).

I do however think that he did make a good point in all this. Now, there's no doubt that FBIDE is making excellent efforts in that regard, but it's not there yet (although it's definitaly in the right direction :-). But today, if you find a newbie on a forum and try to throw him into freebasic, to some of them, it would be like telling them to learn C. FreeBasic is much more powerful than QB, of course, as such, it's a whole different learning curve. The tools available to develop in FreeBasic aren't bad, but I'm not sure if they are "newbie" ready so to speak. FreeBasic is quite overwhelming to a soul that's just trying to learn to program. On that behalf, memnonite did make a good point about that. The language itself (v1ctor and the rest of the people are working hard on that side), the wiki is getting better too. Tools is what is missing here, user friendly tools that can make the starting programmer feel like he can do it, he can make it happen. Like I said, when FBIDE 0.5 comes out it will be a good "big" step in the right direction, but there is work to do still, it will get there, but it's not quite there yet. :-). But some of the more recent projects (like DKL's GUI Creator) are definitaly a good step in the right direction :-).

As far as the articles go, what can I say, each and everyone of them thaught me something new (well except from my own contributions lol, wouldn't that be something? lol). But yes, even at 5 AM, it was quite a read. I specifically enjoyed urger's "Some writing about writing (for the Programmer (and anyone else too))" I learned alot ;-). Althought my english isn't all that bad, I am a native french (read handicap lol) so I know that some of my sentences are probably inverted where they should have been the other way around to begin with, but in french it makes more sent to invert it so no I'm not trying to do the yoda thing, it's just my "french" way of forming sentences. So we'll see how well I learned from his article. Rick Clark has been deserving of his award and I'm glad he got it. He's been doing some great work on his DDD game but also on some other projects. I'm glad for him. The Awakened did a great follow through on his C++ learning series this time around, I think this will be a very helpful series. Ratttrap's Horse humor, made me laugh, 3 images, shortest coming he ever did and yet, the funniest of them all, go figure hehe. And the rest of the articles were very interesting to read. So again, great work to all involved, the quality of QB Express is what keeps me coming back for more :-).

MystikShadows

It's always a pleasure to get a letter to the editor from you. :-) Once again, lots of great feedback, and lots of awesome compliments. As for the whole mennonite thing, I agree with you completely -- but you can check out the next few letters to get my whole opinion on the situtation.

-Pete

Letter From mennonite

i don't know if you're going to print this (or even read it)

do what you want, it's only a letter for you (not petes qb), to you (not petes qb), but you'll do whatever you do with it.

i don't hate you, pete. i thought my last run with qbe was fitting. in it, you said you wished more people thought like me AND called me a douchebag. heh.

i suppose that's understandable, under the circumstances. although you're wrong about one thing- maybe two. one is for sure: i am not nor have i ever been anti-freebasic. what i am is ANTI anti-qb. i was passionately pro-freebasic and remain pro-freebasic.

i am also anti-ego, though i may strike some people as egotistical. i am anti-clique, even though the community has become quite the clique (by simply discluding passionate qb users *IF* nothing else) while simply firing back "no YOU are!" just because our qbasic forum talks about qbasic.

i hate bullshit, elitism, and nonsense. and yeah, we ALL have our moments, so if anything short of perfection = hypocrisy then we're all bloody hypocrites.

the other thing you're wrong about is the TON of hypocrisy and one-sidedness in the "community." the community comes to the qbasic forum to tell us about the community, as if we aren't part of it. they say they aren't a clique and we are, but they tell us "qbasic is old" (as if we didn't know) and shadowwolf calls michael a fool because michael points out a bug in fb (actually shadowwolf and michael were both partially wrong about that bug, but neither of them are fools, and it's an asshole thing to say. it's typical of the fb community to react that way whenever a shortcoming is god forbid pointed out. how is it going to improve beyond the beta stage without feedback?)

but the one-sidedness is WE can be called fools and written off (we have been THE qbasic.com forum for TEN YEARS! and mark wilhelm just comes and moves the link to our forum. that fucking sucks.) as old news while the community claims we're something separate because we still use qb. wtf?

they can flame us but we can't flame you.

that's the truth, pete. the stupid, ugly truth. but no one's gonna know. because there's too much fucking pride.

you think i care about that? why embarrass myself like i do? you think half of anyone is going to listen to my silly rantings? nah.

the bottom line is it doesn't matter. i wish it did, sure, but it doesn't.

anyway, there's my last letter to you. i thought you were pretty cool, and i tend to be right the first time, but it's just like all of this. it doesn't matter anymore.

just like qbasic, i guess. well, you know, i still care. but it definately doesn't matter.

bye, pete. it was fun.

mennonite

Here's the response I sent to mennonite after I got this email:

First off, sorry it took me so long to reply to this. I've just been busy. (Same reason why QBE #15 came out so late.)

I don't understand how you can be so anti-FreeBasic in everything you write, and then still claim that you're "passionately pro-freebasic." In all of your forum posts and all of your letters, you talk about how FB is buggy, not user friendly, doesn't have the same nostalgic feel and isn't as fun as QB, and turns the Qmunity into a bunch of assholes. I think the truth is that you're just saying your "pro-FB" to be dogmatic...or patronizing...

You say what you really are is "Anti Anti-QB," but the problem is that nobody in the Qmunity is anti-QB. We all LOVE QB, and have used it for years. Unfortunately, on modern computers, QB doesn't work anymore, and FB is the closest substitute. That's why people use FB: because it's the closest thing to QB that will work on our computers. When we tell people who are having compatibility issues with QB and Windows XP to switch to FB, we're just being rational. I don't understand how you take offense to that, if you're so "pro-FB."

As for "The QBasic Forum," you complain that we don't include you in the Qmunity -- but it's for good reason, in my opinion: you keep to yourself and don't share anything with the rest of us. Look at the major QB/FB forums these days: FreeBasic.net, QBasic News, The Basic Network, FBTK, Pete's QB Site, QB45, QBNZ and... The QBasic Forum. The thing that all of those forums have in common is that people that post on any one of those forums almost certainly posts on all of the other ones, and occasionally on The QBasic Forum. Meanwhile, the majority of the people that post on The QBasic Forum don't post anywhere else. When someone posts news on The QBasic Forum, it almost never finds its way onto the other QB/FB news sites; posters just don't see the value in sharing with the whole Qmunity. You guys are a the most exclusive clique in the Qmunity by far. If you hate cliques, then why don't you post on all the other QB/FB forums too, rather than being such a "QBasic Forum" extremist? I don't understand how you can't see your own cliquiness.

The real question is: what's the problem with cliques? I don't see it as a negative thing at all; it's only natural that people with very specific views (like people that will only code in QB and DOS and refuse to touch FB/Windows) would post with each other and ignore other boards where people don't agree with them.

Anyway, I would like to publish this letter if you don't mind... it allows you to defend yourself after I ripped on you last month. If you'd prefer it to not be published, then I'll leave it out. Let me know.

-Pete


And here's the response I got from mennonite a few days later.


First off, sorry it took me so long to reply to this. I've just been busy. (Same reason why QBE #15 came out so late.)

LOL. okay.

FB is buggy, not user friendly, doesn't have the same nostalgic feel and isn't as fun as QB, and turns the Qmunity into a bunch of assholes. I think the truth is that you're just saying your "pro-FB" to be dogmatic...or patronizing...

sigh - erm, i don't get to be patronizing. i mean, not intentionally. i'm not a Leet coder like z!re or v1ctor - i'm a user and a hobbyist.

i might be an idealist too, and i might annoy a lot of people - but i think i'd know if i was anti-fb.

read my letter over. i'm only angry at the belittling of people that like qb etc. it's the belittling that pisses me off.

i think it's hilarious that you can read what i've said in these articles

(on the forum - except where dealing with someone like shadowwolf who insists everyone switches - or someone saying "why use qb - except for the blue screen it's useless" etc. i tell people to try FB. i tell them it's a solution for memory problems and large array issues. on my old website the FIRST item on my front page was a link to freebasic.net - one of the 4 images on my website... and it was a pic that said "qb is dead. long live qb." that was from qbxl.net.

the second thing (left to right top to bottom) on my site was a link to your site.

you think i put them there to be patronizing? that just doesn't make any sense to me. i don't tend to be that subtle.)

and think i'm even remotely anti-fb. maybe it's not the kind of support that the "qmunity" wants, but in beta versions, people complaining is kind of important... now if you want to say "gee menn, i think you could be a little more civil in your complaints," so could everyone. but i already said i was hoping to make something like fb one day - until i found fb. after that i didn't feel a need to continue. the fb project was very fulfilling - because by comparison, i don't find anything OTHER THAN fb (visual basic, moonrock, etc) to be that impressive. freebasic is the best alternative to qb - and i'd like to see it be more friendly and more - what would take it beyond the beta version. and no, i don't care about the blue ide in qb. i prefer notepad usually.

You say what you really are is "Anti Anti-QB," but the problem is that nobody in the Qmunity is anti-QB. We all LOVE QB, and have used it for years. Unfortunately, on modern computers, QB doesn't work anymore, and FB is the closest substitute. That's why people use FB.

that's the other thing. when i say the fb community is anti-qb, everyone pretends it isn't. but people DO make fun of people for wanting to use qb.

geez, look at qbe #15. qb is the blue pill? like that isn't condescending. the fb community is in total denial, pete. it treats qb users like crap and makes fun of qb and then it says "man, we love qb! we're nice to newbies!"

aw, geez. anyway, i like fb. i just wish i liked it a lot more - and i wish it was a lot more like a 100% compatible replacement for qb in dos - i don't mind that it needs cwsdpmi - i don't mind that it has no ide - i don't mind that i have to play around with alternatives to chr$(0) because of c-strings.

but at a certain point i'm not having fun anymore, because instead of coding i'm debugging code that used to work - and it's all i'm doing.

who doesn't have a right to complain when something sucks?

fb doesn't suck, pete. it's great. but you know? sometimes fb DOES suck. not always. but sometimes EVERYTHING sucks. the only reason i don't get to bitch about it is because i'm ALSO pro-qb. yeah, NO ONE is going to see it that way - but that's the way it is. 100 people denying it won't change the truth.

When we tell people who are having compatibility issues with QB and Windows XP to switch to FB, we're just being rational. I don't understand how you take offense to that, if you're so "pro-FB."

i *AM* anti-xp. sometimes i tell people to try compiling in FB to get around qb problems, too. i don't find suggesting fb unreasonable - like i've said several times now, i recommend fb to people all the time.

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

catch-22? how can we share anything with you if you don't include us?

while Mac (our moderator, but mostly just the guy that keeps the place from falling down) is very protective of what many of us think is the last place we can talk about qbasic (vs freebasic) his subforums are laid out primarily for organization - the other forums have subforums - so do we. while mac DOESN'T like fb i think he's unfair about it - and i tease him about it (from a pro-fb stance.) it's all about who i'm talking to. when i'm talking to people that are anti-qb i complain.

when i talk to people who are anti-fb i tease them for being anti-fb. in my mind there is still room for both. i don't use XP and in my machine qb runs pretty nicely. i have 3 versions of fb installed - dos .13, dos .14, and windows .14 - i also have qb45 (we actually bought it that many years ago) and qb 1.x.

but what do WE have to share that YOU want anyway? we aren't developing games - a few of us are working on some cool projects, but if god forbid we use gosub instead of sub we get flamed. we're just trying to have fun and help people with qbasic questions - we don't have many big projects like the other forums do. and i've always been ready to write something for your magazine - even though i'm not sure there is an audience for it - what are we holding back, pete?

The thing that all of those forums have in common is that people that post on any one of those forums almost certainly posts on all of the other ones, and occasionally on The QBasic Forum.

Meanwhile, the majority of the people that post on The QBasic Forum don't post anywhere else.

yeah - there are two main reasons for this - 1. contrary to the self-image you guys have ( i can't speak for you - i can only tell you what i see and what i hear you say in response! ) when we come to the other forums we either feel ignored or belittled or abused. people come back to us and tell us they don't like the other forums because of they way they were treated...

mac might defend qb by attacking fb - and some people end up being anti-fb because they feel like the fb community is... well they feel like i do.

but that's not anti-fb, pete. that's anti fb-community - and that's what you guys are breeding - a group of people that don't want to use fb (Even when i suggest it to them) because they don't like the people associated with it.

i think that's goofy - it's open source. everyone can use it without the permission of the people that make it - but, people are being turned off by the attitude you guys say you don't have.

so that's one reason people don't go to the other forums.

the other reason 2. is impatience - not pride, not cliquiness, not anything but impatience... our forum is extremely active - but focused. it used to be if you put a post up you could hit F5 and in a few min there would be a reply. i'm not bragging - but there is an element of instant gratification.

we don't get that at the other forums - either because the other ones are slower... or, the other ones are heavier (not lighter) in traffic and the posts get buried, whatever the reason.

nonethless, some of our regulars - mac included, DO go to your forums. i used to. but i felt it was much slower and i was just too busy. it wasn't because i feel somehow superior.

When someone posts news on The QBasic Forum, it almost never finds its way onto the other QB/FB news sites; posters just don't see the value in sharing with the whole Qmunity.

any news we have on the qbasic forum is generally posted by people like you, who are already posting to the other forums. we're actually VERY light on news of any kind. we aren't a news-based site. but, we have a place where people from other communities can post news on our board... like the latest QBE.

if v1ctor posts a message on our board, it stands to reason that he's going to post it 5 other places, too. why would we do that as well? it's not because we're hoarding news. if anything, we only have a small fraction of what everyone else has on display, because no one posts news to us. i can't think of one bit of qb news that WE posted internally. it's all stuff we heard about on your boards.

You guys are a the most exclusive clique in the Qmunity by far.

we're not a clique. the only thing we frown on is GOTO when it isn't needed (it's just bad coding - but we don't abuse people for it) and people telling us to switch to another language. we like using qb. if liking something makes us a clique, eh. we don't go to freebasic forums and tell them to switch back to qb.

some of us defend fb. i do, parttime. especially when mac starts in. i think he's just being protective. it's not a big deal.

If you hate cliques, then why don't you post on all the other QB/FB forums too, rather than being such a "QBasic Forum" extremist?

i really don't understand this pete. no, REALLY. i already waste too much spare time on the qbasic forum. i like it there. i should be there less. i just don't have time. if i'm too busy coding to go to all the forums, does that make me an extremist or elitist? demanding someone go to forums they don't have time to go to is extreme, pete. seriously, i do everything i can do. including try one more time to clarify this (since you asked) before we part ways.

i mean cmon pete, i'm a douchebag. this whole email is a little surreal, but i used to have the UTMOST respect for you and i guess if you're going to give me a chance to say something i'll take one more opportunity. this is all an issue of incompatibility. we just disagree. we can, though.

I don't understand how you can't see your own cliquiness.

i don't think we are a clique, pete. we don't think we're better than you- at worst, we think we're less of a clique. i don't think that makes us elitists... but then you guys don't think youre cliquey either. face it man, no one is going to say "damnit, we've been real assholes" on either side. so, we might as well give up on this. do you have a better idea? i wish i did.

The real question is: what's the problem with cliques?

they get in the way of communication. they weigh things down that could be simple with bullshit politics and even homemade beaurocracy. they lead to misunderstanding, and they allow egos to soar when they should be muted. as much as possible. we're all humans. cliques get in the way of basic humanity.

I don't see it as a negative thing at all; it's only natural that people with very specific views (like people that will only code in QB and DOS and refuse to touch FB/Windows) would post with each other and ignore other boards where people don't agree with them.

people largely ignore our board. that's okay - it doesn't make people unwelcome, it makes them uninterested. everyone wants a fancy board with phpbb or the like. okay. we like network54. okay. what's the big deal? none. we also like using qb without being told it's old and useless. spend all your time coding in something and be told it's worthless and see how you feel. so some of us are protective. but we're not elitists. we're hobbyists. we're just trying to have fun, for god's sake - not be professional developers.

Anyway, I would like to publish this letter if you don't mind... it allows you to defend yourself after I ripped on you last month. If you'd prefer it to not be published, then I'll leave it out. Let me know.

sure. go ahead, pete. sorry that we couldn't come to more of an understanding. i still feel this is all very one sided - when you said i was a douchebag and that i was anti-fb (if i was anti-fb, wouldn't i know?) i kinda figured you didn't even read my article.

but i knew i couldn't write it without pissing people off. what i don't understand is why it's okay one-way but not the other.

i guess we both think the other is being one-sided. that's why there isn't any point, pete. it doesn't look like either of us are moving in any direction that has anything to do with the other.

you know, even after all this bullshit - even after your response to my article - there are still two things i put up in the version of qbasic.com i was working on before mark took over. one is the new links page i was making for qbasic.com - the first qb link was to pete's qb site "to qbasic what yahoo is to the internet"

it's still up that way, tho not on qbasic.com (mark runs the links page there, not i.)

the 2nd or 3rd link was to freebasic.net.

another thing i had done was rewritten the code in the FAQ for "how can i use arrow keys?"

it included a routine that works in QB AND FB - it changes the chr$(0) to 255 - whether you're in qb or fb, the code works. eh.

maybe i've been a bastard, pete. but i don't think i've been unfair. you think different? okay, pete. don't we all?

i AM going back to my forum now. don't take it the wrong way.

- menn

Mennonite, you make many great points here -- but you haven't managed to change my mind. I'd respond further, but I have a feeling that this argument could go on for years and we'd just go in circles.

I guess I never knew how emotionally invested some people get in web forums. I consider the Qmunity and QB Express to be a hobby and a leisure activity; I don't really take any of it all that seriously. Call it thick skin, but I don't take anything that's posted on a QB/FB forum to be "elitist" or "extremist". People will say what they will, but in the end, look at what the Qmunity is: a bunch of nerds from all over the world, mostly young men, that share homebrew programs and converse over the Internet in our spare time. The "Qmunity" is not real life, so you probably shouldn't treat it as such.

-Pete


Letter From The Big Bad Wolf

hey man dont let ppl like mennonite get to you. there is always this once in a ( hopefully ) few ppl that always get stuff the wrong way.

i like you'r mag and the site so just keep the nice work up man! only downside is that there is no boobs in it but you can't have everything eh? ;)

well take care!

/The Big Bad Wolf ( Rawr! )

Thanks for the kind words -- and sorry my site doesn't have any boobies, but I intend to keep it G-rated. As for mennonite -- he didn't get me down, I just had a disagreement with him. No harm, no foul.

-Pete


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


Express Poll

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

What is the most deserving QB Express site of the month?

SiteVotesPercentGraph
Phat Code (#8)614.3%
JacobPalm.dk (#9)1024%
The Basic Network (#10)12.4%
QB45.com (#11)819%
Data Components (#12)49.5%
AAP Official Projects Squad (#13)512%
ASCII-World (#14)49.5%
Syn9's Hideout (#15)49.5%
42 Total Votes

Although the votes were pretty evenly spread on this poll, there were a few interesting stand-outs. With 24% of the vote, JacobPalm.dk was the clear winner this month. Jacob's clearly got a lot of fans among the QB Express reader base. Congratulations, Jacob!

Also interesting is that The Basic Network got only a single vote for being "most deserving." You might recall that many people criticized issue #10 of QB Express for being rushed so that it would be out within a few days of QBasic News's shut-down, and as a result, we didn't do a very good job of covering news or selecting the site of the month. I still think that during that month, The Basic Network was undoubtedly the site of the month, because it served as a gathering point for QBasic News refugees, and helped keep the community alive during the week of the shutdown...but many would still argue, as is evidenced by this poll.



News Briefs

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

QB Site News

Major Updates to the AAP Official Projects Squad

Adigun Azikiwe Polack has been busy working on his graphics library, AFLIB2, meanwhile keeping his website up-to-date this past month. Here's a post by Adigun from QBasic News about the latest major update to his website:

In this all-important update of the official projects site of Adigun Azikiwe Polack, the official pages of the soon-to-be-released FreeBASIC game library of AFlib2 - Aura Flow Library 2 are now up, which will sure be an *absolute* treat for you RelLib fans everywhere!!!


Also, the FreeBASIC GFX Demo Central now celebrates its own first-ever anniversary with a newly repolished look, as well as two new demos added (including Lithium’s spetactular Raycasting Engine!), and two updated demos also!

Be sure to drop on into the awesome festivities waiting for you beginning at http://dhost.hopto.org/aapproj/. Meet you there!!!

Congratulations to Adigun on the anniversary and the great job in general on the website.

News Brief by Pete


QBasic News and Freebasic.net Experience Downtime

QBasic News and FreeBasic.net, the two cornerstones of the Qmunity, both experienced downtime in the past month. QBasic News, as well as NeoBasic and other sites on Wildcard's server, were down for a few days because Wildcard's webhost had some "issues." Current QBasic News administrator Sumo Jo was accused by many of "not paying the bill," despite the fact that he doesn't even host QBasic News. All the sites were restored to perfect working order within a few days.

Freebasic.net also experienced downtime because a user uploaded some type of server hack / security exploit program through the PHPBB server, and the webhost automatically suspended the account -- though I'm not sure of the details. Anyway, everything is back up and in working order now, so no harm done.

News Brief by Pete


Todd Seuss Launches QuickBasic GUI Blog

Todd Seuss recently announced the launch of a new QuickBasic GUI Blog. The blog will serve as a news source for the QB GUI community, and Todd has done a great job of posting the latest news on QB GUI since the site launched on November 20th. There have already been ten posts, and I'm sure there will be many more to come. If Todd keeps up with the pace that he's updated this blog with in the first week, this will be an incredible resource for QB & FB GUI programmers.

News Brief by Pete


QBXL Audio Edition #8 Released

After a three month absence, SJ Zero has finally released a new version of his humorous audio QB/FB news report, QBXL Audio Edition. You can find the eighth installation at this link: qbxlAudio8.mp3. 'Nuff said.

News Brief by Pete


Z!re Offers Free QB/FB Web Hosting

I, Z!re, have started offering website hosting for QB/FB coders looking for a place to host downloads and sites..

http://goddess.selfip.com/hosted/

Rules:
  • Site should be FB and/or QB related
  • Amount of space depends on the project/site you want hosted (Currently the largest hosted site has 500mb reserved for it)
  • Site bandwidth: max burst 128kbyte/s, max maintained 64kbyte/s
  • PHP/4 and HTML enabled, SQL can be requested
  • The URL you get is: http://goddess.selfip.com/hosted/Your_Site_Here
  • It will also be listed at: http://goddess.selfip.com/hosted/
  • Illegal files are not allowed, instant ban.

Access:
  • Server uptime is 24/7, with downtime for maintenance
  • File handling is done via a HTTP interface (FTP available per request)

Additional questions or contacting to sign up for hosting can be done either to: XiberLord@Gmail.com or via IRC: irc://FieldView.mine.nu/Hosting

News Brief by Z!re

Project News

Lynn's Legacy Demo on the Way!

You guys are in for a treat, because just after this issue is released, Josiah Tobin and Cha0s are going to release the first demo of their upcoming action RPG, Lynn's Legacy. And hoo boy, is it good.

I was treated to a sneak preview of the Lynn's Legacy demo, and I have nothing but good things to say about it. It is a fun, atmospheric, stylistic and polished game, and without a doubt one of the best games ever made in FB. While I was playing the demo, especially after I stumbled into a dungeon, I felt as if I were playing a Zelda game -- Lynn's Legacy is that professional and well-designed. If I hadn't already previewed the game extensively in the QB Express #13 Gallery, I would have certainly written a Gallery article about L.L. in this issue. Instead, I'll write up a mini-preview here. Next month, we'll cover this game in full.

The demo begins with Lynn and her comrades flying over an ocean, when one of the flying beasts in your party catches on fire and explodes. Lynn wakes up dazed and confused in a forest clearing and vows to figure out what happened. Within minutes, she meets villagers and steps into a portal and finds herself in a Zelda-esque dungeon. The story is told through well-written dialogue boxes and pre-scripted cinematics, and it feels like a good SNES or Game Boy Advance RPG.

The graphics, of course, are fantastic throughout -- particularly the animation. Everything moves extremely smoothly and naturally. For example, after Lynn wakes up in the clearing, there is an animation of her flipping over and standing up that is so fluid and well-drawn that it has to be seen to be believed.

What I found best about the demo, though, was the lush soundtrack and sound effects. The music is very good, and adds a lot to the atmosphere of the game. The composer (I'm not sure who it was) deserves a round of applause. The sound effects are also fantastic; whenever Lynn swings her weapon, it is accompanied by a swish and a female yell/grunt. When someone talks, a "murmuring" sound plays as the text is written out in the text box. When you pick up an item, you hear a "ding"...etc. But the most impressive acoustics in the demo were the natural / environmental sound effects, like the roaring of the ocean, birds chirping and wind rustling through branches in the forest clearing, and crickets chirping during the inter-titles. It's the little touches like this that make this game feel so professional.

Anyway, enough talk. Take a look at some screenshots from the demo:











As you can see, Lynn's Legacy looks fantastic. I'm sure you can't wait to check it out when the demo is released. (According to Josiah Tobin, it should be out within a few days of the release of this issue.)

I had a great time with the demo during the few minutes I had to play. Unfortunately, I'm on a tight schedule, so I wasn't able to play it thoroughly. I don't know how much more there was to it. According to the ReadMe file, the demo includes a boss: "Grult-- a massive airborne bat-like creature with multiple pairs of wings. He uses fire as a weapon, but despises light." (Unfortunately, I died before I ever got to the boss, in the Dungeon area.) For all I know, there could be quite a bit more gameplay past that point. I guess you'll have to get your hands on the demo to find out!

News Brief by Pete


Two Lords (Classic Version) Revived

The man of a thousand names (Nekrophidius, Nodtveidt, Adosorken, Dave Perry, and probably others), and the new father, has recently started the project to revive one of his old creations called Two Lords. This is a first person shooter game remeniscent of Doom and Duke Nukem that is sure to excite you with great action-packed gameplay.

Here are a few screenshots that have been posted by him on the freebasic.net forums:


As you can see from these screenshots, Two Lords promises to be one of the best games created in Freebasic to date. The graphics are detailed, and the animation also looks to be pretty good. Two Lords uses a raycaster engine created by Lithium as detailed in this forum thread at freebasic.net.

To find out more details about this game and get a chance to read comments from others that have seen these screenshots, you can find out all about it on the this post at the Freebasic.net forum.

News Brief by MystikShadows


Distraction Software Releases "The Guardian" QB RPG

Every few months, a long-lost QB game discovered on an old hard drive finally sees the light of day. The latest of these is The Guardian, which was just released by Terry Cavanagh. It was his final QB game, and it was never finished -- but it's definitely worth a look.

Here's the info from the original post:

I was looking around some of my old stuff recently, and came across the last thing I ever made in QB. It's the first 15 minutes of a miniRPG I made for Darkdread's pureQB contest in 2002. I never released it because I actually thought I'd lost it. Anyway, maybe it'll be of interest to some people around here, I don't know. Check it out here:

The Guardian

If you want a little more detail about it, you can check out some screenshots on the most recent post at my site, DistractionWare.com.

News Brief by Pete


Turn-Based Strategy Game in the Making

Torahteen, syn9, Ryan, SSC, Rattrapmax6, Eclipzer, and xteraco, are working together to come up with the next big thing for FreeBasic. It will be a turn based strategy game, with a near futuristic timeframe. It's going very well so far, and is looking nice. Here are some screen shots of the 3D engine by syn9.


More to come as the game progresses.

News Brief by Torahteen


Dr_D Remakes Grid Game in 3D

It all started with a post made by rdc here announcing a small but challenging grid based game where the objective was to make the curves connect to each other cause a connection chain reaction which then augmented the score. Dr_D decided that game was 3D material and created an OpenGL version of the same game. Here is a screenshot of Dr_D's creation:


This new version features all the functionality offered by the 2D version along with some very nice lightning effect on selected or affected tube curves. You select the piece you want rotated with the mouse and see how many other pieces got connected and performed a quarter turn after you select the first piece. To find out where to get this game and if you can beat the highscore, take a look at this thread started by Dr_D.

News Brief by MystikShadows


"Inspiration" Re-Started From Scratch

Wallace Software's Inspiration engine has been through many ups and downs in its development cycle these past few months. Originally, it set out to be the greatest 3D engine ever created in QB -- and it was well on its way to earning that crown. It was very impressive, even -- dare I say it -- inspirational. (Check out the preview in QB Express #5.)

A few months back, though, Inspiration was pushing the limits of QB, and Wallace decided to switch the project to FreeBasic. Since then, development of Inspiration slowed down, perhaps because the program was getting too bloated and difficult to deal with. But now, Inspiration is back on track: Wallace decided to completely re-write the engine from scratch. Check out this post from his website:

I've been doing a lot of coding recently in other languages and learning some tricks of the trade in object oriented programming. These have opened my eyes, most tricks that I have learned can be manipulated to work in FreeBASIC. I want to simplify Inspiration, make the code easier to use and easier to write. Debugging was taking up a huge portion of my time with it and it was frustrating. I have decided to start over - FROM SCRATCH. This means moving myself all of the way back to the designing stage.

What I was doing with Inspiraton was having a rough idea of what I was going to do, and then adding that as ideas came along. I'm not doing that. I'm taking a few weeks to outline every single thing that I want to get out of this engine and its components. Then creating a detailed top down design, where each branch of the tree breaks down into only a few lines of code, then packaging them all together. Using this method I hope to build a much better, unified engine, much quicker. Of course there are some things that I am going to keep, I mean no one in the right mind would throw away a 150FPS raycaster. Using this method of program design I hope to not have to put an update on my site like "I'm trying to figure out the best way to do this", I would have already known the best way to do it. Most updates on Inspiration will be commenting on what I have finished and how much further I've gotten, of course there will be problems, there are with any coding project.

The new engine is still in its early stages, but it sure sounds ambitious. Just listen to this:

You and some marines are walking down a narrow hallway. It's dimly lit and the lights are constantly flickering. Suddenly the lights go out, you and your marines switch on your flashlights. Suddenly there is a yellow flash of light and scream. Then another, you can dimly see faint creatures with swords, and yellow shadows dance on the walls of your marines getting cut clean in half. Suddenly there is a bright flash and you are face to face with one of the sworded creatures. You fire a plasma bolt, but it teleports away again. With the eriee blue glow from the plasma bolt you see most of your marines liced clean in half, there intestines and blood spewed out over the ground.

This will be part of Contact 2, not a cinematic either, real game play. Everything I mentioned above can be done in the new Inspiration engine. I have figured out a new way of lighting that allows hundreds of dynamic lights in any colour and any size. A new way of displaying certain sprites, and finally a working collision detection system has been worked out.

Wow. I can't wait to see this engine come to fruition!

Check out Wallace Software for the latest updates on Inspiration and Contact 2.

News Brief by Pete


Bungy The Game

Lurah has been working hard to finally be able to release his first version of his Bungy game (an ASCII worm like game with some rather special twists). The object of the game is to navigate your worm through the playing field avoiding the red @s while eating the yellow $ to gain points and strength.

This first screenshot is the main menu of the game:


And this one is the main playing field for the worm to navigate in:


Since lurah first announced this game on a few forums, he has been getting some great reviews from the people that gave it a try. The twists to the game, I won't mention here, you'll just have to try it for yourself. The main project page is on the ASCII World website's Project page. Look under "Game Projects."

News Brief by MystikShadows


Pc72's Bomberman Clone

Pc72 just released a brand new QB Bomberman game, which will work on anything ranging from QBasic 1.0 to PDS 7.1. Here's some info about the game, from the ReadMe file:


This game is intended to entertain. It's not designed to be very professional nor good-looking. It's made for the sole purpose of literally having a blast and generally a good time. It is nowhere near finished yet, but at least now it is at a stage where it is playable! You might want to fiddle around with the constants in it a bit, but it is as working as it could be. Bombs do blow away more than just themselves, and the bad dudes are actually bad. And, of course, you earn high scores by incinerating them and collecting treasures! The latter can give you special bonuses like more bombs and bigger explosions.

I haven't had a chance to try out this game, but it sounds pretty fun. You can download it at this link: ahibomb.zip

News Brief by Pete


Kylemc Creates His Version of a Classic

Kylemc has been busy lately, creating a FreeBasic version of classic game. His creation is called Squares and the main object is to make squares by connecting dots together with lines. I remember playing a version of this on paper back when I was in school (in those boring courses). Here's a screenshot of what the game looks like:

Squares is played on a 6 by 6 possible square grid adn each player takes turn trying to connect dots together in order to create a complete square. Whoever gets mode squares than the other wins the game.

Just get yourself to this thread and download "Squares" to see for yourself how addicting this game can be.

News Brief by MystikShadows


An Un-named Game by Pritchard

Pritchard is working on an as-of-yet untitled "game" (no genre specified), starring a character named "Alpha Petrov." So far, there are several very cool concept art drawings in this Freebasic.net thread, as well as a link to a very preliminary 100MB demo.


"Expect to fight all sorts of Characters in this game. Everyone needs to make a living, right?"

I haven't had a chance to check out this game, but I thought it had some pretty nifty artwork, and some pretty cryptic messages, so I thought I'd let you all know about it.

News Brief by Pete


AFLIB Status Report

The development of AFLIB2 by Adigun A. Polack is progressing very well. Over the past month, many new functions have been added to the FB graphics library's arsenal. Here are some of the new features that have recently been added to AFLIB2:

  • AFLIB2 now has its own set of primitives that you can use such as: Pixels, lines, circles and elipse, triangles and Gourauds all with a translucenscy optional mode of drawing.
  • It has a set of 10 different font sets (that span through the whole 255 ASCII code range) that you can use in more than one way. They also feature a special accelerated printing method to display text in a very fast way.
  • It now has fades that do not affect the color palette. For those that don't know this means that you can make an image fade out gradually from it's originally shown colors in gradual steps towards total dissapearance.
  • It can also store screen in memory to be retrieved and display at a later time. It can handle up to 64 different screens.
  • It now has screen collision features. Some of the test features really seem to do a good collision detection between moving objects and non moving drawings, between sprite and background, and others.
  • It can generate translucent star fields. From the screens shots very different and unique startfields can be generated as well.

If you want more information and details on these features as well as screenshots of everything to give you a good idea on what they are all about. Take a look at this thread and you'll see all the hard work that Adigun has been busy with lately.

News Brief by MystikShadows


Marzec Converts GFXLIB2 to Standalone Library

Marzec has taken it upon himself to make Angelo Mottola's GFXLIB2 for FB a library usable by other languages beside FB: "last night i was a bit bored and thought that making the gfxlib a standalone library for use in any other language is a good idea. after getting rid of all dependencies on the fb runtime library i succeeded in compiling, linking and using the library on windows and linux."

Check out this thread for the full story, as well as download links.

News Brief by Pete


A Cool "3D Thing" / Screensaver by Deleter

Over at QBasic News, Deleter released several versions of a "cool 3D thing" that features two circles circling around each other... I thought it looked pretty cool.


He also released a version of the demo as a screensaver. Check the thread for the sourcecode or the link to download the screensaver version.

News Brief by Pete


Competition News

One Key Challenge Revisited Results!

Back at the beginning of October, Z!re started up a "revisiting" of one of the most successful QB programming challenges ever: Lachie Dazdarian's One Key Challenge. The object of this competition was to create the best game possible that using only one key for input. Check this thread for the original announcement and official rules of the competition.

At the deadline, there were five entries, by Dio, j2krei08, matt2jones, urger and Xerol. You can find all five entries in the One Key Challenge Voting thread. For comments from different voters and general chatter surrounding the contest go there.

Now that voting has wrapped up, Xerol is the clear winner. He received an amazing 12 votes. Second place was shared by Dio and urger at 3 votes each.


Xerol's game of "shoot-the-helicopters-and-parachuting-guys" seems to have caught the imagination of QBasic News forum-goers, because it was the clear fan favorite. Despite Xerol's dominance, though, many thought that urger's entry was the more genuine and unique -- and there was an argument over this in the thread. Although Z!re preferred urger's entry, she concedes: "Xerol obviously put a lot of time and effort into his game, and he is a worthy winner. Not to mention Xerol's game gives a lot more eye-candy, which we all know is important, no matter how hard we try to deny it."

Congratulations to Xerol for the win! His game can be found here.

Disappointed you missed out on this competition? A new challenge has been started -- this one is a "Mouse Only" challenge, where programmers must make a game that uses only the movements of the mouse -- and no clicks -- for input. Sounds very interesting! The rules and more details can be found here.

News Brief by Z!re and Pete


Roque Like Compo Monthly Follow-Ups

By now, the Rogue Like Compo should be no secret to anyone. From what I've noticed this month on the Rogue Compo thread on FreeBasic.tk forum people have been the busiest I've seen so far on there projects. Let's take a look at what each team is up to so far this month.

Andrew Collins and Jocke The Beast reported this:

Jocke should be posting a new BeastRogue pretty quickly. Ver .16 is the old one up there , .17D is the one I just sent him.

Now that's what I call a list of features. Needless to say this game is looking more and more complete and should be quite fun to play when it's ready.

rdc (rick Clark) reports:

DDD is just about ready to have a 1.0 release. It needs a bit more balance, but it is just about there. Right now, I am working on my Ascii Help (AHP) system that I am going to plug into the program for an online manual. AHP is coming along really well. I have most of the basic stuff done, and I am working on parsing the source files and screen navigation.

To those of you that haven't read last month's report, rdc was and still is the furthest along in his project. His game is just about complete (probably some final tweaks here and there to do) but it looks like we'll be playing his game very soon now.

Dr_D had this to say:

Well, Zap has dropped out, so I'm probably going to work on some other small projects for a while... unless someone wants to join my team in his place. Any takers? Please??? Seriously... I'm tired of working on it by myself. I wanted to do this as a team project, but Zap simply doesn't have enough time. If anyone wants to join, send me a pm or whatever.

well it seems there was a taker after all, I've learned recently that rdc is teaming up with Dr_D to form a new team for Dr_D's project. So this game should be moving along quickly and smoothly from here on out. Stay tuned to this monthly update to see what will happen next.

Ryan added:

Work for my project has really just been in the form of getting a good, modular server working that I can then develop a client with. So... nothing's really new since the demo I put out forever ago with the concept screen/map generator. It'll be weeks before I see any progress, as I get maybe 5-6 hours coding time a week and have to do homework for my Java class during that time. Cool (And I'm learning Ruby on Rails for work.)

As you can see from this paragraph it seems ryan is planning an online version of his rogue like game. When done, this should prove an interesting game. I don't know yet if the only version will allow for teams to play together or people to play against each other or both. But an online Rogue Like game? Very interesting in my book.

As you've read just now, the teams really have been quite busy. There's just no telling what will happen in the course of this coming month, so be sure to stay tuned to this update to bring you the latest and greatest on this ongoing compo.

News Brief by MystikShadows


GUI News by Brandon Cornell

I'm back still with a News Brief but this time instead of being about me its about the GUI Community!

-Brandon Cornell

Web Site News:

GUI Releases:

The FreeBASIC Rush!
  • Everyone in the GUI programing World is starting to use FreeBASIC. Except DELTA,RocketBoy, and I. I don't like too much change and there would have to be a huge one. Jacob's GUI Costa is allready being rewritten in FB. I won't switch to FB until there is a great GUI like RushOS programmed in it.

News Briefs by Brandon Cornell


Send your QB/FB news to pberg1@gmail.com!


Gallery

Written by Pete

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

The Janitor

A few weeks ago, Lithium (Chris Adams) began porting an old Raycasting Engine he had made to FreeBasic, with hopes of creating an engine that would make it easy for just about anybody to make a first person shooter, a 3D dungeon crawler, or some other type of 3D game. This engine, which is "99% complete" uses 320x200 resolution, but offers a high-resolution "stretched mode" for compatibility with modern computers. The engine includes texture mapping on all surfaces, billboarded sprites, depth shading, fog, water and darkness effects, moving walls/dynamic blocks, and crouching/jumping abilities. The program also comes with a map editor. You can find out more about this engine at this page.

Here are some screenshots of the engine:



The engine is looking pretty spiffy, and pretty versatile. You can download the latest version here.

But it's not the raycasting engine that we're concerned with today; it is the game that Lithium is making with his Raycasting engine...The Janitor.

The Janitor is a 3D first person shooter that uses Lithium's raycasting engine, and it's already well on its way to development. The game is being made by Lithium (Code/Story/Game Design), Aaron Fevens ["Vincent Khron"] (Artwork, Game Design) and Evan Lowry ["Freyr"] (Music). Here's the game's back story, taken from the Official Site.

You're a Janitor who works in the corporate office of a large company. This company is doing illegal genetic research on humans. One of the CEOs of the company, conflicted by his own morals, decides to blow the lid on everything...but before he can, he's killed and you the janitor are framed for his murder.

Sounds like a very interesting concept for a game, and it's looking quite good already. Here are several preliminary screenshots of the game in action (originally 320x200, but blown up as they would be by the game's engine):










Suffice to say, I'm very excited about this game. It sounds like a great storyline, and the engine and textures are already looking great.

I'll end this article with a quote from Nekrophidius, from the FreeBasic.net forums: "Lithium, I believe you have opened the Pandora's Box of FB with your raycaster...I think we may see a lot more FPS games come about using your engine."

Couldn't have said it better myself.


Visit the http://lithium.dontfollowme.net/ for more information.


Searching For The Unknown
Bozula Block Buster by Johan Olofsson, 2001

Written by Lachie Dazdarian

Introduction

As you see I decided not to feature Robot Plague in this issue. There were few reasons. In short, the game just didn't turn out to be what I expected it to be and much smaller than I imagined. There is a very small chance anyone would actually play Robot Plague for real other than just check it out. I'm sure that's not what I'm trying to accomplish with this column.

Now to the topic of this issue. Bozula Block Buster is a Sokoban type of game. Not a hard-core Sokoban game but with the gameplay very similar to the one in Sokoban and it's clones. You don't know about Sokoban? Well, in Sokoban you control a character who can push boxes scattered around the level and the goal is to push all the boxes onto the designated positions in the level. The most notable fact about the Sokoban gameplay is that you can make a wrong move very easily which then makes that level impossible to finish. Sokoban levels are known for being very difficult and challenging and are distributed over then net in the popular .xsb format. Most of the levels I've tried through FreeBASIC Sokoban(reviewed in the issue #11) were very discouraging and made me quite disappointed in my thinking abilities. The concept of Sokoban is ingenious on some way since you can create the most challenging puzzles on a very small space and with small number of boxes. Place for imagination in the designing of Sokoban levels in endless. Maybe that's one of the reasons why I liked Bozula Block Buster so much. That game is much easier that the default and the better custom made Sokoban levels.

As far as I know there weren't many Sokoban games made in QBasic which I find surprising since they are not very difficult to code. Definitely less difficult to code than a Tetris game and there is like 17 Tetris games made in QBasic(and released to public), plus some Tetris-like games. I'm aware of this useless peace of information because I'm planning to write an article about QBasic Tetris games. Weee! Hmm...I think I'm getting way too excited about that article. Anyway, I should get back to the topic.

I know about 4 finished QBasic Sokoban games. David Joffe's VGA Sokoban is probably something Sokoban purists(do such people exists?) will like the most since it features very simple graphics, 90 non-original levels from XSokoban(X Window system), untouched Sokoban gameplay and tile by tile movement. Some but not all of those levels are also present in the default level set from FreeBASIC Sokoban. I personally don't like this kind of approach since it's the most unimaginative and requires very little effort to code and design. Another QBasic Sokoban game is Pushem by Danny Albocher which looks more like a test program than a real game since it features even less impressive and more generic graphics and only 5 levels. Factory John by RedXIII is probably the best game of all the QBasic Sokoban games but if it's the best in being a challenging Sokoban game that remains a question. I hope I wasn't confusing with that sentence. Factory John features above average graphics, pixel by pixel movement, animated character, non-original MIDI music and 15 original levels. It also features the best presentation. And as an extra feature in the classic Sokoban concept it introduces cement which appears in some levels and which you can use to destroy non-movable obstacles, in this game those are cracks in the floor. What most Sokoban fans won't like about this game is that the levels are relatively easy and I've finished most of them from the first attempt! The fact that they are original doesn't help here. Also, the controls were solved with the INKEY$ statement and you know how that works with pixel based movement. What I didn't like is that the game features only one small tileset and it's a bit drab. What you see from the screenshot is what you get. On the end that's not much different from VGA Sokoban or FreeBASIC Sokoban.

I hope you made it through this unnecessary long introduction because I'm finally getting to the topic of this article, Bozula Block Buster.


About Bozula Block Buster

Bozula Block Buster will very unlikely win the award for the best QBasic Sokoban game. It can't measure with VGA Sokoban in level design and their number or with Factory John in graphics and presentation but I found it to be the most interesting game of them all.

Anyway, Bozula Block Buster doesn't look very promising on the first look. The main menu is very poorly designed, if we can call that designing. A clear black background and the menu text written with the default SCREEN 12 PRINT font. What's even worst is that the designer didn't make the effort to place the menu on the center of the screen.


All the screenshots are clickable

The story of Bozula Block Buster is very simple. You are the little Zenmar who lost his small puddlings(a pet of some sort). It's up to you to find your way through all the stages and save all the puddlings. Now while this is not something very deep or interesting at least the designer introduces a story. And it's important on some way since you know who you are and why you have to pick up those small creatures in the stage before exiting it. There is some motive behind that. Definitely better than some circle picking up a triangle.


The stages are divided into 5 courses. The first course is called Dezert Practice Course and it's a...surprise, small practice course. It features 4 stages which are meant to introduce you with the game mechanics. The movement in the game is tile by tile based. What makes Bozula Block Buster different from Sokoban is the objective of each stage. In Bozula Block Buster you don't have to push all the blocks onto the designated positions but find your way to the puddlings in the stage and then exit from it. Most often both the exit and the puddlings will be blocked by movable blocks, walls and/or laser beams. Three important elements make the Bozula Block Buster's gameplay. Laser beams, red pills and movable blocks. The way you push blocks is like in Sokoban and you will push them in order to reach some part of the stage that was blocked or to block a laser beam. Laser beams are something that add a lot to the classic Sokoban gameplay. By pushing blocks onto the laser beams you can clear yourself a path to a certain part of the stage that was blocked by it. Red pills, on the other hand, turn you into some kind of angry Zenmar and while being in that state you can break one piece of wall. You can't accumulate red pills so eat them one by one. What's good is that you can't walk into a laser beam so you don't have to be careful around them. You can die only if you push a block that is blocking a laser beam away from the line of fire(rectangulary to the beam). Uh, I could use another word when referring to movable blocks.


Each of the next 3 courses(Jays Jungle Course, Lazer Lab Mayhem Course and Star Course) features 9 stages and when you finish one course then next becomes unlocked. This progress is saved so when you exit the game you don't have to worry about your "unlockings" being lost. Each course features it's own tiles while the Star Course features new sprites as well.

I must admit that the stages are not very difficult to solve but not ridiculously easy either. The Star Course was a bit disappointing on some way since almost all the stages were about pushing one block through the entire stage to block some laser. I was seriously stuck only once in the Lazer Lab Mayhem Course and that was because it took me some time to discover the trick the designer devised to fool the player. A bit evil idea since the player is not expecting to be tricked on that way(I'm so vague). What adds to the challenge is the highscores table and it's filled with default scores, thank God. Default scores is something I missed in so many games. The scores are not very easy to beat(except in the practice course) so you will have a reason to repeat a course after you finish it in order to beat the course highscore. The scoring works on a very simple way. All your moves are added to the score and every time you retry a stage(by your will or if you die) 10 points are added to your score. You can guess now - the lower the score, the better.


The last "secret" course unlocks when you finish the Star Course. It also features new graphics. I don't know why the designer refers to it as secret since it's written on the main menu even when it's still locked and it's also mentioned in the instructions. I won't reveal it all but again something new appears in the gameplay. You see, in that course you need to finish all the stages with limited number of moves. Before each stage you receive a certain number of moves and you can pass them to the next stage. Quite smart idea. I made it to the stage 8(out of 9) in the third attempt. Very challenging. Each move counts. There is a story behind this limited number of moves, don't worry. This makes 40 stages total. Not bad.

So no matter how this game fails in being very challenging that is compensated with the highscores and the last course.

Since the game comes with the source code(actually, it was distributed only in source code but I added a compiled executable) it's easy to find out how to unlock the locked courses, in case you are unable to do it regularly(really?).

As I already hinted Bozula Block Buster was made in SCREEN 12(640*480 graphics resolution) mode which I don't consider very important since high resolution graphics is not good graphics by definition. The game's graphics alone are above average(if not more) but the game feels terribly static. Not a single tile or sprite in this game is animated. Even when you move Zenmar the sprite remains the same for all the directions. So I can't say I'm happy with how the graphics were handled in this game but when I think about VGA Sokoban or FreeBASIC Sokoban I shouldn't moan too much.


Bozula Block Buster doesn't feature any music or sound but one PC Speaker sound effect used in the course 5 when you lose a game. The key word is "bomb". So this aspect of the game is pretty much non-existent.

While not being much more from an average game, and that's mainly because of the very poor presentation, Bozula Block Buster shows us how Sokoban games could and should look if the game designers were slightly more imaginative or motivated.

When I just think about making a Sokoban game I see so much beyond plain VGA Sokoban. I see a game that can load the standard .xsb levels but display them using neat and animated tiles. More wall tiles that are placed in the wall slots and animated by randomization. Several tilesets that exchanges as you advance in a certain levels package. Like every 10 levels. Pixel by pixel movement and an animated main character. Cool and polished design. Atmospheric background music. And an alternative game mode with some story and extra features like in Bozula Block Buster or some completely new. Do you see it? Heck, if I had the time I would start working on this right now. The idea itself would be relatively easy to execute. Darn, why I didn't think of this before? Oh, well. There is always someone else(I'm looking at you).

Final score
4.5/10

Get Bozula Block Buster

To download Bozula Block Buster click here: bozulabbuster.zip


Thanx for reading this dribble. I'm not sure what I'll feature in the next issue since I went with the best games in the first few issues of the column. So the next issues might be a slow decline in the quality of games. Or not. I have a lot of games on the list. I should be more optimistic. Cheers!



Programming Language Syntax Tenets

Written by Agamemnus

Two basic tenets of programming language design have arisen over the years. Rather than strict limitations, we should view them as two ends of a spectrum:

Tenet 1:
There should only be one way to do some function X.
Tenet 2:
There should be many ways to do a function X.

On the one hand, the "purists" (one way) demand that there be one concrete way to accomplish a task and that duplicate functions that accomplish the same thing corrupt the language's purity. On the other hand, the non-purists, or "poly-modus-ers", as I shall call them, demand that there be multiple ways to accomplish a task because then the code will then fit the "style" of a programmer, and not the other way around.

One the one hand, there is order and universality in meaning, but decreased flexibility, and on the other hand there is increased flexibility but chaos, when it comes to integrating two pieces of code, either written by two different programmers or written by the same programmer at different times!

This fundamental dividing line should not constrain our way of thinking. This division can be equated to two economic policy approaches with a lack of data about the initial conditions. Who is right? Democrat? Republican? It is difficult to tell because the status of the economy is often impossible to know for certain.

There is thus a relationship between "many ways" and "one way". The more flexibility (and possibly, more ambiguousness) one adds to a program, the less universality, and the more universality you add, the less flexibility (and possibly, more and difficulty in creating the program). But, the spectrum is two-dimensional. With the correct implementation, you may have flexibility and universality without a large downside of ambiguousness and/or programming difficulty. The right blend can thus achieve the optimal efficiency and utility of a programming language and a program written with that language.

I now propose that four programming elements comprise this utility spectrum. Their correct implementation can maximize both flexibility and universality while minimizing the associated costs. I do not propose here what this will look like exactly, but, in my opinion, each aspect in theory should be implemented in such a way as to allow the greatest amount of programmers “access” (from a simplicity point of view) to the features.

1) "macro rewriting".
2) "variable inheritance".
3) "function isomorphism".
4) "construct isomorphism".
5) "namespace maximization".

Macro rewriting is the process of disassembling code into simpler, but more numerous, constituents. All aspects of flexibility (2 through 5) are derived from macro rewriting. A simple example is converting a DO...LOOP from the BASIC programming language into GOTO and line statements. Anything that cannot be described easily from elements 2-5 is just “macro rewriting”, although anything that can be described by elements 2-5 is also “macro rewriting”.

Function isomorphism is a system where a basic function is subdivided into other functions that accomplish the same or similar things. Function isomorphism eliminates the need to rewrite the same function several times with only minor changes and thus increases completion speed and decreases code bugs. A simple example is an adding function that can add both strings and variables.

Construct isomorphism allows numerous syntaxes to be used to access the same parts of a construct. (a construct in this case is a hierarchical set of variables). A simple example is the ability to use, for instance, a(2, 5) and a(10) to describe the same variable. (where the array starts counting at 1)

Namespace maximization is a human analytical process that analyzes the namespace of functions, labels, constructs, and variables and determines the most convenient namespace possible that can exist with a set namespace and syntax rules. In some versions of basic, you could not use “_”. Some names may be reserved for various uses in a program.

I shall, perhaps in the future, endeavor to create what my opinion of the best BASIC-syntax implementation of these elements should look like. The implementation will be according to ease of use from my perspective alone, since implementation is, in large part, subjective.

Agamemnus


Contact Agamemnus at romaircraf@comcast.net


Porting the Official Hamster Republic RPG Creation Engine

Written by Simon Bradley (PlayerOne)

This article decribes the process of converting the Official Hamster Republic RPG Creation Engine (OHRRPGCE) from QuickBasic to FreeBasic. I thought I'd mention that straight away in case it sounds a bit dull, and you want to skip to the next item.

OHRRPGCE is a suite of programs for creating old-school top-down RPGs in DOS. It runs in 320x200, in 256 colours, and the only sound is Adlib FM-synth music. It is also user-friendly, has a flexible scripting system and has a decent community, giving a good stock of existing games.

Strangely enough, it was the disadvantages that initially attracted me. I saw it as a potential handheld game. The low resolution was perfect for the newer PalmOS handhelds, as was the comparative lack of sound. If I could only port the game player, then there was a library of games waiting to go.

Getting it to PalmOS is a long-range project, though. I'm not fool enough to leap right in and start coding the Palm version. No, my roadmap called for a gradual migration from DOS and QB via Windows and C, maintaining playability all the time. It's all about incremental changes, for me. I like to have something I can see running at every stage.

I'm not really a BASIC programmer; not even, particularly, a fan of the language - if you want to chase me out of town with pitchforks, now's the time - but I do believe in horses-for-courses, in using the right tools for the job, and FreeBasic was clearly going to be the simplest way of getting OHR working under Windows. The DOS/QB version of OHR is groaning at the seams. It needs to be freed of the constraints of real-mode DOS and QuickBasic so that it can be refactored into a more sensible structure. The problem is that it has grown organically, and the strictures of QBasic make it extremely difficult to reorganize. Most of the source files are pushing at the file size limit of QB such that making a small change can mean you need to displace another routine to a smaller source file. FreeBasic would remove this limitation, and allow the files to be rearranged on functional lines. It will also bring dynamic memory management, and will remove the 640k limit.

When OHR was first made open source, two of us began FB ports which eventually came to nothing. In fact that was the first time I had heard of FreeBasic, when Mike Caron announced his attempted port. That was back at the beginning of 2005, and both of us ran into problems. FreeBasic itself was less compatible, for a start, but the biggest problems were down to the assembly library used by the QB version. I was attempting to reproduce it in C, and Mike eventually decided not even to try, but to rewrite the whole thing from the ground up.

Some months later, I used FreeBasic for another project, a deliberately bad semi-game called HoldSpace. I used the built-in gfx library for this joke project, and realised that it mapped quite well to the OHR assembly library, so a little later on I decided to try the FreeBasic port once again, using 100% FreeBasic instead of trying to write a C library.

The first stage is the simple syntax conversion. For each file, I'd simply try to compile it and keep fixing the errors: comment out sections that had no relevance to FB (CLEAR, DEF SEG, etc) or that I couldn't deal with yet (INTERRUPT); rename variables that had the same names as keywords or arrays; that sort of thing. Nothing too dramatic, but a lot of find-and-replace. I also made a note of all my changes in a text file, in case I had to do it again. The QB version probably wouldn't stand still and wait for me, and it might be easier to reconvert a file than to add the changes.

Another early problem was BLOAD. The FreeBasic version is very different. Fortunately BLOAD was encapsulated in its own sub, which was rewritten to use GET. Then there was the integer size. I wanted to stick with 32-bit ints in FreeBasic, because it would give us more space for expansion later, and would avoid needing to declare everything as a short, but some of the file IO relied on 16-bit ints, so temporary short variables were added.

Because the QB version was still the lead edition, I wanted to keep the existing source files as close to the originals as I could. There was a new source file for the FB conversions of the assembly routines, and most of the work I needed to do could go in here. I would do extra work here to ensure code-compatibility with the originals. For example, a lot of data is stored in integer arrays, but is actually byte data. In the FreeBasic version I still only put two bytes in each integer, even though there is now space for four, since that is what other parts of the code expect. In an ideal world, they'd be ubyte arrays, but code compatibility is the goal at this stage, everything else should wait until refactoring.

Gradually I managed to get the major systems working and compatible: the graphics, the keyboard, the file access, the timer, etc. From empty stub functions, to loose approximations, to reasonably accurate duplicates of the original assembly routines. I tried not to let my lack of knowledge of assembly and of FreeBasic get in the way. Some of the routines were obvious, some could be worked out from context, some needed me to look up DOS interrupts, and some needed me to stare at the assembly source until it made sense. The keyboard handling was particularly tricky to replicate with multikey, and is still a bit odd. When a key is down, it doesn't continually register, it only registers at regular intervals. Without this repeat delay, things happen too fast: the cursor moves too fast on the selection screen, and the popup menu doesn't even get the chance to appear.

Finally, I had something that could almost play games, and I released an exe to the OHR dev community. Fame and fortune inevitably followed. Er, well, they must be on their way, right?

It was still quite rough, at that stage, and had no sound, no mouse support, and a few other omissions, but the potential was there. James Paige, the original author, set up a Subversion repository for me, and also implemented some of the simpler changes (variable names, and so on) in the QB version. In the end, the differences were comparatively small, and we wondered if it was possible for the QB and FB versions to share source.

Some early development screenshots.

Having too much time on my hands, I chipped away at this, bringing the common files closer and closer together. I created a header, compat.bi, and a source file, compat.bas, which would contain the differences for each version. The BLOAD wrapper function was moved, the default font loading routine (VGA interrupts in QB) was moved. I added a dummy CLEAR function to the FB version. I fixed the STR$ incompatibility using a #define macro replacement in the FB version of compat.bi. The macro changed each occurrence to XSTR$, a new function which added an extra space to STR$ for positive numbers, as in QB. To get the short integer declarations I needed, I added an empty sub FBDIM to the QB version, and used that to implicitly declare the integers, while the FB version used another macro to replace FBDIM with DIM AS SHORT. With a couple of compromises and a bit of preprocessor trickery, I was able to bring the source files together. Bar a small number of system-specific files, the FB and QB versions now share the same source, and can be maintained in parallel until the QB version is sidelined and the FB version becomes the lead.

Bugfixes and enhancements followed, until only one major hurdle remained: sound. The original game uses FM synthesis, which is not really supported under Windows and not found on many modern soundcards. There were two schools of thought on this, we could either try to emulate the Adlib sound somehow, or we could convert it to MIDI. I initially favoured a middle course: build a waveform from the FM instrument definition, and then use a MOD player to play it back at the necessary different pitches. There is a massive potential range of synthesized sounds, and MIDI just could not cover them all. In the end, though, this was probably too complicated, and too expensive to do on-the-fly. Also, most of the BAM music files were built using a General Midi instrument bank, so converting to MIDI would just be a case of figuring out the instrument and converting it back. Mike Caron had already written a player which worked on this principle, but I was still unsure. I wrote a little test utility to look up the instruments in a BAM file, and found that a fair number did not use the GM sound bank. Almost all of those used one other bank, which I also had access to, so I was able to set up mappings to GM. A small percentage of sounds were not in either bank, and would just have to be defaulted to something which could be entirely inappropriate. I wrote a command-line converter to test the principle, having first found out how to write minimal MIDI files, and the results were good. I incorporated it into the main project. With FMOD playback, we were finally ready for a public release.

There were a few problems with that release, some of which have yet to be fixed. Since then, FMOD has been replaced with SDL_Mixer due to licensing considerations, and the FreeBasic version has been merged back into the main trunk, the QB version. My own copies are slightly behind the times at the moment, since I have been distracted by other things.

So far, I have been entirely focused on the game player. Firstly, that was all I ever intended to port to PalmOS, and secondly, the editor is a different class of problem. There are many ways to make an editor, you simply (hah!) need to ensure that you write out the file format correctly. A proper Windows app would be possible, and there is a Python-based version under development. With the game player, everything has to be reproduced more accurately. The timing has to be right, the display has to be right, the scripting has to work the same. That said, the assembly library is shared between the player and the editor, and I have already done much of the conversion. I left out some functions that the player doesn't use, and I left out some aspects of functions, but I think it should be achievable without too much extra work, so maybe I'll have a go at that next. If it hastens the official move to 32-bit, then it can only be good.


Official OHRRPGCE page: http://www.hamsterrepublic.com/ohrrpgce/
My FBOHR page: http://www.pocketfuel.co.uk/fbohr/
OHR Community: http://www.castleparadox.com/


Review of Tera-Mamoliny by Deleter

A review by Stéphane Richard (Mystikshadows)

INTRODUCTION:

In this article, I will be review a small but very addictive game that was created by Deleter. It is called Tera-Mamoliny and the whole game is based in a primitive, cellular level world. Rather than explaining it myself, here is a screenshot of the game in play followed by the author's own words on what this game is all about.


"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."

Not a bad little story line if I do say so myself. I will be review this game based on a fiew criteria and give it my own personal score as far as the game itself goes and how well it rates in these criteria.

PLAYABILITY: Score (4/5)

As you've seen from the screenshot above, the game is rather simple, that doesn't make it any less challenging however. You need to avoid the red circles (the liketwertps) while feeding yourself a health dose of mega-chow (the blue circles). I tried the game in easy level and even at that level you need a good minimum stability with your mouse. Things can get quite hectic as the level become harder and longer to complete.

OVERALL ENTERTAINEMENT: Score (3/5)

Although simplistic in graphics, the entertainement factor doesn't seem to be affected. The levels getting harder, the enemy count getting higher as you survive through the levels, the fact that your enemy moves faster and faster as the game progresses all contribute to the overall entertainement value of the game. And believe me, these red circles show no mercy.

REPLAY VALUE: Score (3/5)

I gave this category a value of 3 because even today I find myself double clicking that program to see if I can do better. It seems that it has enough replay value to keep me clicking and playing the game every now and then just to see if "I still got it" so to speak. Before that, I was playing it to see how high I could go. That to me is what makes a game's replay value good or bad and in this case I have to say it gets quite addicting.

TECHNICAL FEATURES: Score (2/5)

By technical features I mean the amount of technology used to create the game. It by no way influences what I think of the game but rather simply what the game uses in technological point of view to give the player's it's gaming features. For one thing, so far, there's no sound in this game. Perhaps with some sound effects and an high paced background music theme, it would make the game even more addicting. Music works in strange ways sometimes. Also, this games uses standard graphics (quite effectively I might add) it is a 2D game therefore i has no need for DirectX or OpenGL to help it's cause.

EDUCATIONAL VALUE: Score (4/5)

Here I don't mean what the game teaches us per se. This game supplies the sourcecode so you can see how it was made. It features some pretty good collision detection and overlap detection (if you're on top of the mega chow, then you can eat it. and as such offers aspiring programmers some pretty good example of these techniques. This is how I define it's educational value.

THE FINAL VERDICT: 16/25 (64%)

All in all, the game is well designed, takes advantage of many things to bring you it's entertainement value and for a game developed so quickly by Deleter, it has alot of merit. There's no saying what the futur holds for this game, perhaps the author might want to add different things to the game. New types of survival techniques and so on. So we'll see just how far this game gets pushed. As it stands today though, it's definitaly worth the download if you haven't yet downloaded to give it a try.

MystikShadows
Stéphane Richard
srichard@adaworld.com

Download Tera.zip, or check out the original forum post for more info.


Site Review: Venosoft

Written by Alec Elton

Venosoft
http://www.venosoft.com/

When I first saw Venosoft's site, all I could think was wow. After exploring the site a little bit, I could easily see that the people at Venosoft had put a lot of effort into it. At the top of the page are their links and their logo. The site is formatted with a 3-column layout, providing the user with up-to-date news, project info, and highlights. The layout is sized to fit well on a 1024x768 screen perfectly. The graphics on this site are just incredible. Overall, you should find this site very easy to navigate, and should have no problems finding the content you're looking for. There were a few things that I think could have been improved, however. The links do not change to indicate the current page, and the large amount of graphics on the site could slow down the download speed for people with 56k connections. Overall, though, I'd give this site a 10/10.


As for the content of the site, well, you won't be disappointed. Their latest project is Cai's Quest, which is said to have over 45 *hours* of gameplay! That in itself is an incredible feat for a QB game. In addition to this, they have Battle Arena, another 3rd-person RPG with great graphics and addictive gameplay. Again, for content, this site receives a 10/10.



Writing A Story For A Computer Game

Written by Lachie Dazdarian

Introduction

Articles of this kind are not a rarity and just about everybody and their granny(I love using this line) has something to say on this issue. So maybe this article shouldn't come as a shock to you. :P

I don't consider myself an expert in(I say this a lot) story writing but I flatter myself that I can detect what is bad and what is good in computer game stories better than most. Also, I have a huge experience with QBasic games and somewhat less but still large with old computer games so I know what kind of stories worked for me and what didn't. This brings me to the biggest flaw of this article, subjectiveness. I can't know how much my taste and observations apply on the taste of the majority of people. Still, I like ALL computer games(well, all but flight simulations) and ALL possible types of stories and settings so at least I'm not bias in that like some are.

This article mostly deals with topics like how to write story intros and outros, how to present and pace a story and stuff like that. The basics. It will deal with story(plot) development very little. I think too many articles dealt with plot development instead with the things that make most players interested in a game before that. In one sentence this is a game design oriented story writing article.

Does your game need a story?

Not all games need a story and I've seen quite few games where a story was forced and wasn't incorporated into the game. It was just something I would half-read before starting the game and very soon forget while playing it. Ever played MHTris or Pac-Clone 2?

Just check these screenshots of Pac-Clone 2.

Totally unnecessary, especially because Pac-Clone 2 features very generic, themeless tiles. Nothing that relates to the story.

Coffee break games and similar puzzle games(I'm not saying all puzzle games, mind you) don't need a story and you can only make it worst by trying to implement a story in a game of that type and ruin the graphical design so it would fit the story.

Even some long action/arcade games don't need a story because the driving force and the reason for playing that specific game can be above all the addictive and entertaining gameplay and not some background story or a mission.

What kind of story your game should feature?

Well, any kind of story you want and can think of, of course. But you must resolve with yourself how much the story is important in your game and how much points you want to score with people when they think of your game's story. The less the story matters to you the less you need to be original and uncommon. I don't know if something can be less or more original but you know what I mean. It's always good to feature a story that was done 50 or less times before than feature a story or a setting that was done 500+ times before somewhere else, in any medium(book, comic, film, computer game,...). Unfortunately, many people consider original and intelligent the things that really aren't that. The Chronicles Of Riddick and Dark City are perfect examples of movies written by people who have a misconception about what is original and what is smart. If you want to impress others with your game's story don't feed them with that kind of junk.

Very nice examples of original computer game stories are ARC Legacy and Wandering Hamster. ARC Legacy features a story of adventurers called Archaeologists who search for the remains of the previous civilization after the Earth got devastated in a nuclear war. That kind of story is far more interesting than a story where you fight against "an unknown plague that came down on the land" placed in a classic Tolkien kind of fantasy world. Wandering Hamster is a beautiful example of a cool, quirky, different and original game world. A world filled with things like sentient hamsters living together with humans, wolves who speak Esperanto, a bubble magician who looks like a Mexican peasant and dozens of other colorful characters/places. All this content makes Wandering Hamster a very intriguing and fun game to play from the first second.


"The ARC Legacy"

"Wandering Hampster"


Both of these games show that when designing a story you can put more importance on the game world, the setting and not on the plot because a game world can be enough for the player to get hooked. Anyway, a plot is about characters interacting and on how many different ways characters can interact? Definitely on less number of ways than you can construct a whole new world with it's own history, rules and features that make it special. If an original and different world is not what you have in mind and simply don't want to go crazy with it then try to be more unconventional and uncommon with the plot. It's not the path I prefer but it doesn't mean it can be less effective. Avoiding the classic good versus evil battle no matter on which side you would put the main game character can be a good start. Just don't start your game with a story where an unknown plague came down on the land and you are destined to save it. Even if during the game the player discovers that the force behind the plague is his mother, father, sister, brother, a person from the party or he himself because all of that has been done zillion times before.

Allow me to say few words regarding the issue of humor in stories in this section since I don't know where else to put it. This paragraph is mostly inspired with my recent experience of playing Kids Of Karendow. Very good humor is pure gold for any story and can make your game several times memorable and more fun to play. Why I'm bringing the issue of humor is because I want to make this point - you must be aware of your limitations! Average jokes or average humor in general can't do much damage but not much good either. Also, there is a very thin line between average and bad humor. If you don't have a good sense of humor don't force it. This is probably the only thing you can't learn(or it's extremely difficult to learn) in game design. I should point out that good sense of humor is not the ability to copy jokes from other games, movies, books or comics. If you decide to feature a humorous story you still must keep a serious approach to the story though this may seem like a paradox. Your story mustn’t seem like something the designer didn't consider serious or important. No matter how much your story may be wacky the plot, the characters and their motives must make some sense. Make your story funny but treat it well, if you know what I mean. I think a good example of a humorous story poorly managed is The Quest For Opa Opa(reviewed in the issue #9) which starts with a really poor introduction featuring an inbreed lumberjack living in a town called Wankerville. A huge mistake especially because the rest of the game features very good humor. I was a bit disappointed and surprised how Na_th_an failed to recognize and discard bad jokes from the game and what is the worst, the story is based on them. Don't get me wrong, The Quest For Opa Opa is a very good game overall but it starts very poorly which is something you must try to avoid as I will explain it in the next section. So to return to my point. Be aware of your limitations. This doesn't apply only on the humor in games but when someone fails in being funny it hurts the most. :P


Is the story so important?

I would put the story somewhere behind the graphics and the gameplay in the list of importance when evaluating any computer game. But here is the catch. Many people might compliment your game's graphics and the gameplay but not really play it. It's not the type of users we game designers seek. We look for people who will play our game and not just try it out. The story can be crucial in capturing the player's interest and putting him or her in the positing where he or she can actually experience your game. Many games are excellent but not very enjoyable on the very start, when we are still not familiar with the game mechanics and similar. That's where the story kicks in.


Writing/designing the story intro

There are few common mistakes game designers do when writing/designing the story intro. The biggest mistake you can do is overwhelm the player with too much information and pure text. Perfect example for such a mistake is Jonathan Wallace's Contact, where you are forced to read two pages of text dealing with unnecessary background information before getting to the part that really relates to the game. A similar mistake appears in Lithium's XGmae but XGmae's story intro is just on that limit where the player is ready to skip it because the intro jabs about events that happened 1000 years before the game's current time. Luckily it's not that long. If you want your game to feature background information try to divide it from an introduction of the main plot that relates to the very game. Put it somewhere else where the player can read it if he or she is bored. Also, be sure that your game really needs this kind of information to be available. Sometimes a joy of playing some game is in discovering it's world, characters and things that make is special. Yes, the main game character should be aware of these things but we are not living this character we are only playing a computer game. Fixation with realism is bad.

It's important how you will pace and present a story. Very good example of a well written story intro is Dies Irae where the designer quite intelligently tricks you with interesting and odd events which sadly don't lead to good plot development or a rewarding ending. But that intro, the dream where you are killed by an unknown person because you refused to destroy the world with him, was the reason why I got interested in the game and played it for few hours. If I knew from the beginning what about the story really is I'm not sure I would stick for that long.


"Dies Irae"

"The Griffon Legend"

Another example of a well written and presented story is The Griffon Legend where the sentences are carefully constructed so that the story is easy to follow and read. And the intro is not too long. Just the right length.

Of course, most often you shouldn't make the intro too short. I must say, I really disliked the intro in DarkPhear which practically reveals nothing. The intro opens with a dream where some girls calls you to save her. From who? What girl? And after you wake up your master asks you to find some fruit so he could make an antidote for the King's illness. And since this task lasts too long and requires too much patience you will probably not stick long enough to get hooked if something else awaits you. It's not the reason for me to dislike the game but enough for me not to get interested in it, especially if my free time is limited and I have other games, more interesting on the first look, to play. Reveal enough to make the player curious about the setting and the plot but don't reveal it all because something has to happen and reveal between the beginning and the end of a game.

Another thing, content is more important than form. It's more important what you say and not how you say it. Nietzsche, for example, features an intro based on a very decorated and a bit pretentious(sorry SJ) style of writing which is a bad substitute for an average and unoriginal(or even less than that) plot because it can only do more damage.



I can't give you many valuable tips about story presentation but anything is better than white letters on a black background(unless we are talking about IF where you don't have a choice). Scrolling the text, adding a nice background music, taking care how to construct the sentences(making them sound good and read easily), adding some animations if there is a lot of text, ...all of this must be taken into consideration when designing the story intro.

Does your game need an intro? Well, not always. But this is limited to very specific types of stories where the main character suffers from amnesia or has been transported to an unknown location. Not telling anything can be very good in such situations since you can easily project the main character's feeling onto the player. I would reserve this option to adventure games and perhaps RPGs.


A plot line

Most of us know these things but I think an article of this kind should mention them anyway just to make it more through-out. Repetitio est mater studiorum. In rough translation, Repeater eats mother's studio. Hmmm...I forgot my point. :P

Anyway, the longer your game is you should revel less in the intro and then add new plot lines/surprises later. It's important to keep the story fresh during the game. Knowing who is the main bad guy from the beginning and where the entire plot is based on characters wanting or not wanting to help you in your quest is not fun. I will mention ARC Legacy again because that game doesn't start with a very original plot but the very setting keeps you playing it. And the huge number of plot twists and new characters brought into the game keep it interesting constantly. I'll refer to something I said in one of the previous sections. The more your game world/setting is interesting and intriguing it will be easier too keep the player interested and to add new events and story lines in the plot.

Also, your game doesn't have to carry one same plot during the entire game. Wandering Hamster shows how you can start with one plot and end with something completely different. Your main character(if your game features one) can grow and change during the game(not in the sense of RPG experience points growth).


Writing/designing the story outro

The story outro(ending) is not terribly important as the intro and plot development because it has a completely different purpose. If you made a long and challenging game keeping the player to very end of the game is already a proof of your success. Still, the outro can be very important in leaving that final mark and impression on the player. With a bad outro and possible high expectations the player might have because of the excellence in the rest of the game I sincerely believe you can lower the player's opinion of your game from "excellent" to "very good". Of course, what kind of outro your game will feature completely depends on the rest of the game. Very often experience of finishing a game is not a reward enough and the player expects something more on the end.

I will mention few games that made me have high expectations about their endings and left me very disappointed. The first two are Fury Of The Furriest and Mega Lo Mania, commercial games from the early nineties. Fury Of The Furriest is an excellent platform game and it features a really nice story intro with full screen animations and stylish graphics. The ending alone is not terrible but compared with the intro it left me disappointed. Mega Lo Mania is a classic, a brilliant strategy game featuring a unique, mystic-like style of the graphics. In Mega Lo Mania the story is presented with a cool slideshow of excellent and stylish images. The ending is almost non-existent and it was a huge disappointment because the entire game design seemed like a build-up for something grand on the end.

For an example of a QBasic game featuring a disappointing outro I'll use Robot Robbery which I reviewed for QB Express in the issue #8. As mentioned there this game features an excellent, polished, funny and relatively long intro but not any kind of outro, only the credits screen. Definitely a disappointment because the game even features cutscenes between the levels. I remember Keith(the designer of Robot Robbery) explaining me in an email that he had problems fitting an outro in the code but you mustn’t allow yourself to end up in such or similar situation.

My point is if you have the skill and will to create a very cool intro and very good or excellent graphics for the entire game don't drop the ball when making the outro. It's recommended that you work on the outro while doing the intro. Don't save that kind of work for the end of the development because then you will be burned out, fed up with the project and not in the mood to create something on the level. But even if you leave it for the end there is no need to rush with the release of the game because you don't have a strict deadline which I can assume was a reason for such disappointing endings in Fury Of The Furriest and Mega Lo Mania.

Also, while keeping the outro on the level of the intro and the rest of the game it's always good to reveal something that is not revealed during the game or by the very act of finishing it. A very good example of a good revelation saved for the end is TerraScape, a great QBasic game I reviewed in the issue #14. Unfortunately, I can't reveal what the ending from that game contains but it's a school example of what an ending needs to accomplish.


So let's wrap it up:

- decide if your game needs a story or not(not all games need it)

- decide how important the story is in your game

If the story is important to you take these things into consideration:

- try to introduce a story that was not done many times before(or at all) and try to create an interesting and colorful setting, easy to manipulate

- don't make the intro too short and not enough revealing(you must catch the player's interest; make it intriguing)

- don't make the intro too long and reveal it all(the player must have a reason to play the game other than just beat it; implement discoveries and revelations in the plot line)

- an intro is not obligatory; you can leave it out with some types of stories

- try to present the story in a way it's easy to follow and understand; don't overwhelm the player with too much background information

- if your game is relatively long implement surprises and twists in the plot; you don't have to end the game with the plot your started it with

- try to keep the outro on the level of the intro and try to reveal something new on the very end

That would be it. Of course, I don't think you should follow these tips as The Ten Holy Commandments because computer games can be so different and my observations can't apply on all of them the same. Just consider this article as a set of advices. Take what you like and leave what you don't.

Until next article, stay among the living. :P

Visit my reviews/articles site: kentauri.digitalblackie.com/articles/


Download a copy of this article: Writing_A_Story.zip


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

Wallace Software
http://www.freewebs.com/wallacesoftware/

Webmaster: Jonathan Wallace


Jonathan Wallace, the creator of the QB first person shooter Contact, and the upcoming Inspiration engine and Contact 2, runs a small website dedicated to his own programs called Wallace Software. And that website is this month's QB Express site of the month.

Why did I bother to introduce "Wallace Software"? Because I'd venture to guess that a lot of you readers have never even been to this site. It's a small, humble QB/FB site, without a flashy design, and Wallace doesn't go out of his way to promote his website on the various forums around the Qmunity.

But if you do visit Wallace Software, you'll find one of the best development blogs ever seen in the Qmunity. Wallace updates this site on a frequent basis, with well-written and interesting updates on his progress. Every time I check back at this site, I'm surprised to find one or two new news posts about Inspiration or Contact 2. In a community where 95% of the sites sit abandoned or stagnating for months between updates, this is a quite welcome surprise. There's really something to be said for regular updates. In this slow month where most QB / FB sites didn't have a single update, Wallace updated his site five times. For that reason, as well as all of the great information on Wallace's projects available on the site, Wallace Software is the site of the month.


Programmer of the Month

Lithium
(Chris Adams)
http://lithium.zext.net/
http://lithium.dontfollowme.net/

Lithium has been around the Qmunity for quite some time, and has been a very active contributor lately, especially at the FreeBasic.net forums. If you read this month's Gallery article, which previews Lithium's Raycasting engine and his upcoming First Person Shooter The Janitor, you'll know exactly why he is this month's programmer of the month. He's released a truly great engine, and he's working on a game that sounds like it will be fantastic. If you need more details, just scroll up and check out the Gallery. :)



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


Comics

By Rattrapmax6 and Matt2Jones

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



QBasic Horse Humor



And here's Matt2Jones with a double-dose of BBY comics for you!



BBY the QB Maniac



BBY the QB Maniac




Managing Complexity

Written by Richard D. Clark

One of the continuing problems of software design is managing complexity in large programs. The problem is easily defined: as a program grows, the number of interactions between code objects within a program grows at an ever-increasing rate, creating a maintenance nightmare. While defining the problem is easy, solving the problem has proven to be extremely difficult. There have been numerous white papers devoted to the subject, new programming languages created, C++ for example, notations developed and guidelines created. All have a particular take on the problem, and all address certain aspects of the problem, but as of yet, there is no all-inclusive solution to the problem, and one may not exist.

I don’t pretend to have the answer to this problem, but I have discovered techniques that help to mitigate the problem and ease the burden of tracking down bugs and minimizing the effect of code changes. When I made my living as a programmer, I had to write large, enterprise level programs, and I learned that taking the time up-front to organize code in an orderly fashion helped in managing the complexity that is bound to creep into any large-scale program. Here are some of the lessons I learned, most the hard way.

Define the Problem

Before you start to code, think about what problem you are trying to solve. All computer programs should solve one or more problems. For example, an electronic address book may solve the problem of storing names and addresses that can be quickly retrieved. Strange as it sounds, even games should be designed to solve a problem. For example, in Unreal Tournament 2004, you have a game type called Capture the Flag. The problem definition is actually simple: move to the opposing team base, grab their flag and take it back to your base. In a chess game, the problem to be solved is to capture the enemy King. Once you clearly define the problem, you can then create a set of action steps to solve the problem.

Have a Plan

The problem to be solved is the goal of your program. In the Capture the Flag (CTF) problem, once you are able to grab a flag and take it back to your base, you have achieved the goal of the program. The task is to define how that goal is achieved. One thing I like to do is to work backwards from the problem, breaking down the program into ever-smaller components and then tackle those components individually.

Let’s look at the CTF problem. There are basically 3 pairs of components: two different flags, two different bases and two different teams. The flags can be broken down into red flag and blue flag. The bases can be broken down into red base and blue base. The teams can be broken down into red team and blue team. Since CTF is a symmetrical game, we really only need to define one side of the equation, a flag, a base and a team, and that definition could be used for both the red and blue sides of the game.

Let’s define a flag. A flag is an object that resides in a base and is manipulated by a team member. Using this definition we can write down some preliminary action steps that need to be addressed when coding a flag.

1) A flag is an object, so we need to have a model of the flag.

2) A flag resides in a base, so we need some place to put the flag.

3) A flag can be manipulated so a flag must have some properties. This is a good start, but it is too general, so we need to refine the action steps.

Looking at 1 above, a flag is a model so we will need to have a base image of the flag. Since there are two flags, red and blue, we will need to have two texture sets for the flag. So for action step 1, we will need to create an untextured model of the flag and create two texture sets for the flag. For the red flag, we will paint the red texture set on the model, for the blue flag, we will paint the blue texture set.

At this point we have enough information to implement in code, a flag object. We have no place to put it and can’t interact with it, but we can create the object. Notice the progression of definitions: we defined the problem in general, then restated the problem in specific problem components, and then redefined those components into even smaller, solvable problems. Going through the same process with each aspect of the CTF game will yield a list of small action items that can be directly translated into code.

Smart Translation

The next step is to create the code, and many times this is where the programmer fails. It isn’t simply a matter of jumping in and coding the action steps, the coding has to be done intelligently. Look at the action steps and find the commonality. For example, displaying a flag and displaying a team member, involve similar techniques. They both have a model and texture set. It doesn’t make sense to have two routines, one to load a flag and one to load a team member. It would better to have one routine that does both.

The rule is, if you do have to do something twice, write the code once. Look through all the action steps and group the common functionality into general routines that can be called from different action steps. In other words, you write one routine to load a model, regardless if the model is a flag, player character or weapon. By using one routine instead of three, you have reduced the complexity of the program. If there is a bug in the model loading code, then you only have to fix one routine, not three. And, more importantly, if you need to make a change, you only have to change one routine, automatically reducing the risk of introducing a bug into the system. One routine to fix, one place to look for bugs.

Smart Organization

The next step is to organize the code in an intelligent manner. Don’t put everything in one huge source file; break up the source file into logical groups. Routines that manage the models should be placed into a single file. Routines that manage textures should be placed into another file. Non-specific routines, a random number generator, for example, should be in yet another file. The same principle that we used to define a problem should also be used to organize the source code. Group the code into small, logical groups so that if something breaks, you know where to look and if something needs to be changed, you can do it in one place.

Document the Code

For small programs, documentation usually isn’t necessary. For large programs, it is vital. Let’s say your program works for six months, and suddenly one user does something that no one has ever done before and your program quits working. When you go back to the code after not looking at it for six months, are you sure that you can remember what you were really doing? Some people can, I for one cannot. Taking a few moments to write a note about the purpose of a routine, the input and output expected and the expected results can save hours when it comes time to debug that long-forgotten routine.

As I said, this isn’t a grand solution to the problem of program complexity. However, I found that following these steps greatly reduces the time and effort needed to produce and maintain quality software, especially if that software project grows beyond a simple one-page program. The important point is to have a method, and then stick to that method. We will never solve the problem of complexity, but we can at least get a handle on it and make it somewhat more manageable.


Download a copy of this tutorial: Managing_Complexity.txt


How To Program A Simple Text Parser In FB/QB

Written by Imortis Inglorian

I have gotten so much from the QB/FB community, that I wanted to give something back. This is my first tutorial though, so please, bear with me.

A Text Whaty-What?

Well, let's get to it. First of all, I will explain what a text parser is. A text parser is a program that can take text input and break it up into meaningful components in some way. The parser that I will teach you to make will be highly expandable. You could use it for most anything. You could even use it as a base for a scripting engine.


Don't Blame Me

Now, keep in mind, there are hundreds of ways to do any one thing in QB/FB. This is but one example, and it's probably not the best. And now lets get down to the nitty gritty.


First Things First

This particular parser will be a function, so that you can use it in any program. See, Modular Programming IS fun! The first line of code needs to look something like this:

Declare Function Parse(ToParse as String)

Okay, just to be complete, here is what this means. This makes a function with the argument ToParse, which is a string. This is the text that will be broken down. (I know this is going slow, guys, but hang with me on this one.) This next line is just a matter of preference.

Dim Shared Parsed(100) as String

Now you have an array to hold your results. This is probably not the most efficent way to pass the results back to your main program, but you can write a different way when you write an article, so GET OFF MY BACK ALREADY! Ohh... Sorry... Back to the Tutorial.

Now let's set up the basic skeleton of the function:

Function Parse(ToParse as String)

End Function

What Next, Oh Wise And Brutally Handsome Programmer?

(Okay, so maybe you didn't say that, but a guy can dream can't he?) Now we are going to fill in the the skeleton. We are going to need a few support varibles.

Function Parse(ToParse as String)
	Dim CurrentPosition as Integer
	Dim CurrentCharacter as String
	Dim WordCount as Integer
	Dim WordSize as Integer
End Function

Now we will discuss what each of these is for. CurrentPosition will show us where in the string we are at tem moment. CurrentCharacter will store the character of the string at CurrentPosition in ToParse. (Still with me?) WordCount keeps track of the number of words that have been pulled out of ToParse. WordSize is the current number of characters in your word. So far so good? I hope so because I'm moving on.


So When Do We Get To Do Anything Cool?

Keep you pant's on (please)! Now we get to the good part. A programmer's best friend: the loop. We are going to have to loop for the entire length of the string, and sence we don't know the length of the string we will do it like this:

For CurrentPosition = 1 to Len(ToParse)

Next CurrentPosition

This will loop one time for every character in the string. Easy, right? Ofcourse I'm right.

For CurrentPosition = 1 to Len(ToParse)
	CurrentCharacter = MID$(ToParse,CurrentPosition,1)

	If CurrentPosition = Len(ToParse) Then
		WordSize = WordSize - 1
		Parsed(WordCount + 1) = MID$(ToParse, CurrentPosition - WordSize, WordSize + 1)
	End If
Next CurrentPosition

What happens here is that CurrentCharacter now holds 1 character, starting at CurrentPosition, from the string ToParse. The second part should go at the end of your For loop. It makes sure that you get the last word in the string. Now we get to do something with it.

Select Case CurrentCharacter
	Case " "
	Case CHR$(34), "'", ","
	Case Else
End Select

This is where you do all the work. Right now it checks for the '(apostraphe), the "(quote), the space, and the ,(comma). This is just a simple example of what you can check for. It can be extended to check for anything you want. But for now: On the the next Section!


This is the way we process our strings, process our strings, process our strings...

First we will look at what to do if we have a space. I am going to assume that we will be breaking the string on the space. Here is what we have to do. When the program hits a space we want it to do a few things.

If Not WordSize = 0 Then
	Parsed(WordCount + 1) = MID$(ToParse, CurrentPosition - WordSize, WordSize)
End If

Let's look at this before we move on. First of all this check to see if the WordSize is 0. If word size is 0, then two things could have happend.

1. This is your first pass through the string and the first character is a space.

2. You just got done parsing out a single word and it was folowed by either a punctuation or 2 spaces.

If this is not the case then we want to break the current word out of the string and store it in Parsed. We use WordCount + 1 becuase if it is the first word, WordCount will still be 0. We want to start at 1 in the array and I will tell you why later. This will also insure that you don't ever overwrite an element in your array accidentally.

The MID$ Statement will pull out the entire word (minus the space) from ToParse. Isn't that nifty?

If Not WordSize = 0 Then
	Parsed(WordCount + 1) = MID$(ToParse, CurrentPosition - WordSize, WordSize)
End If
WordCount = WordCount+1    
WordSize = 0

As you can see, I added two line to this bit of code. The first increases the WordCount by one and the other resets the WordSize to 0. This makes it so that you can start the new word fresh and clean. That is all there is to dealing with a string. Now we move on the the punctuation.

If Not WordSize = 0 Then
	Parsed(WordCount + 1) = MID$(ToParse, CurrentPosition - WordSize, WordSize)
End If
WordSize = 1
Parsed(WordCount + 1) = MID$(ToParse, CurrentPosition - WordSize + 1, WordSize)
WordCount = WordCount+1    
WordSize = 0

This is almost the same as the operations for spaces, but there are two lines different:

WordSize = 1
Parsed(WordCount + 1) = MID$(ToParse, CurrentPosition - WordSize + 1, WordSize)

What this does is saves the punctuation in to Parsed. Once again, simple and clean. We are down to the last important part of setting up the parser: What do I do if it's not a space or punctuation?

WordSize = WordSize + 1

That's it. If it's not a space or a punctuation, then it just adds one to the word count and starts all over again.

One last thing... This will make things alittle easier on you later.

Parsed(0) = MKI$(WordCount)

What this does is place the number of words into the array at element 0. Later when you want to do any processing on the text, you can use this number to get the length of the string and loop through just the right number of times.

Now here is the full code:

Declare Function Parse(ToParse as String)

Dim Shared Parsed(100) as String

Function Parse(ToParse as String)
	Dim CurrentPosition as Integer
	Dim CurrentCharacter as String
	Dim WordCount as Integer
	Dim WordSize as Integer
	For CurrentPosition = 1 to Len(ToParse)
		CurrentCharacter = MID$(ToParse,CurrentPosition,1)
		Select Case CurrentCharacter
			Case " "
				If Not WordSize = 0 Then
					Parsed(WordCount + 1) = MID$(ToParse, CurrentPosition - WordSize, WordSize)
				End If
				WordCount = WordCount + 1    
				WordSize = 0
			Case CHR$(34), "'", ","
				If Not WordSize = 0 Then
					Parsed(WordCount + 1) = MID$(ToParse, CurrentPosition - WordSize, WordSize)
				End If
				WordSize = 1
				Parsed(WordCount + 1) = MID$(ToParse, CurrentPosition - WordSize + 1, WordSize)
				WordCount = WordCount + 1    
				WordSize = 0
			Case Else
				WordSize = WordSize + 1
		End Select
		If CurrentPosition = Len(ToParse) Then
			WordSize = WordSize - 1
			Parsed(WordCount + 1) = MID$(ToParse, CurrentPosition - WordSize, WordSize + 1)
		End If
	Next CurrentPosition
	Parsed(0) = MKI$(WordCount)
End Function

And there you have it. That is how to write a text parser in FB/QB... Now, I'm sure most of you are asking the same question by now...

How Do I Use This Frickin' Thing???

Geez! You're all so demanding... Okay. Here is some simple code for accessing the parser.

Dim Typed as String
Dim I as Integer

Input "Say something will you?"; Typed

Parse(Typed)

For I = 1 to CVI(Parsed(0))
	Print Parsed(I)
Next I
Sleep

Finally...

Well, folks, that's all I have for you this time... If I hear any requests, I might show some practical uses of this code or even something different (if I can think of anything...) For now, I think I've wasted enough of Pete's space.


Download a copy of this tutorial: ParseTu.rtf


Unions

Written by Richard D. Clark

This isn’t an article about the AFL-CIO, but about those strange data structures called unions. Unions are an efficient and powerful way to organize data, but strangely enough, I don’t see many people using them. This article defines a union, describes the benefits and shows how to implement them in your own programs.

You can think of a union as a type-def that can hold different data within a single data segment. The size of a union is the size of the largest data item in the union definition. If you define a union with a 4-byte element and an 8-byte element, the size of the union is 8 bytes. Unlike a type-def though, a union can only hold a single data item at any given time. This may not sound very efficient or useful, but it is a powerful way to organize different types of data using a single data object.

A union is efficient. Using the above definition, if you use a union to hold a 4 byte data element, it may sound like you are wasting 4 bytes, but in fact you are gaining 4 bytes. Without a union, you would have to allocate a 4-byte and an 8-byte data item, using 12 bytes total. By using a union, the 4-byte data element fits within the 8-byte data segment of the union; in other words you are using the same space for the 4-byte data element and the 8-byte data element. You are saving 4 bytes by not having to allocate an extra 4 bytes for the 4-byte data element.

While efficiency in a program is always welcome, the real power of a union derives from the fact that at any given instance, a union can only hold one data item at a time. This may sound like a contradictory statement, but it is a way to manage complexity in a program but grouping disparate data items within a single container. A real-world example will illustrate this concept.

In my program Deep Deadly Dungeons (DDD), a rogue-like game, I needed a way to contain and manipulate a player character’s inventory. The inventory items include rations, weapons, ammo, armor, potions and scrolls. Each inventory item is unique; each has different properties that must be managed. At a first approximation, it would appear that a lot of coding would be required to manage all of these properties because the items are so different. Handling each one as a separate data structure would require routines for each item, increasing the complexity of the program.

It would be better to have a single data structure that would represent a general inventory object, and a single set of routines to manage that general inventory object. You can create such an object by using a union, and once you have this general-purpose object, you can create a set of routines to manipulate that single object, thereby reducing the complexity of the program. Here is how I defined my inventory object in DDD, showing only the weapon and armor type-def elements. The other elements are defined in a similar manner.

type armortype
   id as integer
   eval As Integer
   ac As Integer
   defmod As Integer
   defmagic As Integer
   defmagicmod As Integer
   strg As Integer
   cursed As Integer
   dr As Integer
   noise As Integer
End Type

type weapontype
   id as integer
   eval as integer
   hands as integer
   strg As Integer
   tohitmod As Integer
   damage as integer
   dammod as integer
   cursed as integer
   dr As Integer
   skill As Integer
   noise As Integer
End Type

type invtype
   typeid As Integer
   desc As String * 20
   union
       light as lighttype
       supply as supplytype
       ammo As ammotype
       necklace as necklacetype
       ring as ringtype
       wand as wandtype
       potion as potiontype
       scroll as scrolltype
       weapon as weapontype
       armor as armortype
       shield as shieldtype
   end union
end type

Notice that the union is inside a type-def. The union part of this type describes a single inventory item. Since only a single instance of an inventory item resides in a union, how do you determine what is in the union? My method was to use a typeid, which is an integer value that indicates what the union is holding. The id is defined within the type-def, and not the union, so it is available to each inventory item. The following defines describe the different inventory item classes.

‘item class ids
#Define supplies 1
#Define necklaces 2
#Define potions 3
#Define rings 4
#Define wands 5
#Define weapons 6
#Define armors 7
#Define lights 8
#Define ammos 9
#Define shields 10
#Define scrolls 11

If the typeid is 6, then I know that the union holds a weapon inventory item. If the typeid is 7 then I know that the inventory item is armor. I can now write a set of routines to manipulate the inventory object. Since each routine operates on a single object, I can create a high-level set of inventory methods that will work on any type of inventory item. For example, to generate an inventory item, I use the following subroutine.

sub SetItem(item as integer, inv as invtype)
   dim cursed as integer

   cursed = GetPercentage(10)
   with inv
       select case .typeid
           case supplies
               .supply.id = item
               GenSupply inv
           case necklaces
               .necklace.id = item
               GenNecklace inv
           case potions
               .potion.id = item
               GenPotion inv
           case rings
               .ring.id = item
               GenRing inv
           case wands
               .wand.id = item
               GenWand inv
           case weapons
               .weapon.id = item
               GenWeapon inv, cursed
           Case armors
               .armor.id = item
               GenArmor inv, cursed
           case lights
               .light.id = item
               GenLight inv
           Case ammos
               .ammo.id = item
               GenAmmo inv
           case shields
               .shield.id = item
               GenShield inv, cursed
           case scrolls
               .scroll.id = item
               GenSCroll inv
       end select
   end with
end sub

This subroutine sets the passed inventory object (inv as invtype) to the appropriate inventory item based on the passed item id and the typeid of the inventory object. Here I have a single method to handle any type of inventory item. If my inventory items were separate type-defs, I would have to create a SetItem for each inventory item type. By using a union I can create a single method that will handle whatever type I send it.

The preceding code shows an example of the use of a union in a real-world program. To illustrate how to create and use a union, let’s create a small, non-trivial program that implements a simple variant data type. Our variant can either be a string or an integer, and we will add methods to set the value of the variant, to add two variants together and to print a variant.

First, let’s define our union that will be our variant type.

'define our data type classes
#Define isnull 0
#Define isstring 1
#Define isinteger 2

'define our union type
Type vtype
   id As Integer
   Union
       sdata As String
       idata As Integer
   End Union
End Type

The #defines indicate what type of value is in the variant. Notice that there are three defines, one for NULL, or no value, one for string data and one for integer data. This completely covers all the various states that our union may be in any given instance. In our vtype, we have defined an id field that we will use to indicate what data type we are holding; isnull, isstring or isinteger. All of our routines will examine this id field to determine what actions to take. The actual data is stored in the union, and can either be a string, sdata or an integer, idata. Notice, that we don’t have a NULL entry in our union. If our variant is NULL, that is id = isnull, then we simply ignore any values that are contained within the union, since NULL means “no meaningful value”.

To use our new variant type, we simply create one or more variables of type vtype.

'create some variant data
Dim As vtype v1, v2, v3, v4

In order to use a variant, we must initialize it with data. This means that not only do we have to load the actual data item into the union portion of the type-def, we have to indicate what type of data is being stored in the union. The easiest way to do this is to create a set of methods that will set the id flag and load the data. In FreeBasic we can use the overload keyword to make the job of setting our variant very easy.

'define our set function using overload
Declare Sub SetV Overload (idata As Integer, v As
vtype)
Declare Sub SetV (sdata As String, v As vtype)

'create the integer set
Sub SetV(idata As Integer, v As vtype)
   v.id = isinteger
   v.idata = idata
End Sub

'create the string set
Sub SetV(sdata As String, v As vtype)
   v.id = isstring
   v.sdata = sdata
End Sub

Here we declare our set method, SetV as an overloaded subroutine that can take either an integer or a string. We then write the actual subroutines to initialize variant for each type of data being stored. If we are passing an integer to SetV, then the id is set to isinteger and the data is stored in the idata field. If the passed value is a string, then the id is set to isstring and the data is stored in the sdata field of the union. We simply call Setv with the appropriate arguments. Since we have overloaded the subroutine, the complier will use the correct subroutine based on the data being passed.

'create an integer type
SetV 10, v1

After this call, v1.id = isinteger and v1.idata = 10.

'create a string type
SetV "10", v2

After this call, v2.id = isstring and v2.sdata = “10”.

But how do we set the variant to be NULL? Since a NULL means no meaningful value, simply setting the id to isnull is enough to indicate that the value of the variant is NULL.

'create a null type
v3.id = isnull

Next we need to display the variant. Our PrintV method prints out the value of the variant based on the id value.

Sub PrintV(v As vtype)
   'print out data based on type
   If v.id = isstring Then
       Print v.sdata
   ElseIf v.id = isinteger Then
       Print v.idata
   Else
       'just print a null string for null
       Print
   End If
End Sub

Here we simply examine the id and print out the appropriate data field in the union. So to print out v1 to the screen, we would use the following code snippet.

PrintV v1

Finally, we need a way to add two variants together. This is where it gets a bit tricky, because we potentially are dealing with two different data types at the same time. That is, we may need to add a string and integer together; how do we define what the result will be? In order for this to work, we will need to come up with some rules for handling the different data types.

1. If both values are of the same type, simple add them together. If both are strings, concatenate them, if both are integers add them.

2. If one is a string and the other is an integer then:

2.1 If the string can be converted to an integer, then convert the string to an integer and add the two together.

2.2 If the string cannot be converted to an integer, then convert the integer to a string and concatenate them together.


3. If one or both are NULL, return a NULL.

That covers all the possible outcomes using our variants. Keep in mind that these rules are completely arbitrary. This is simply how I define our variants to behave. You may want to define the behavior differently. With these rules in mind, we can code the AddV method.

Sub AddV(v1 As vtype, v2 As vtype, vret As vtype)
   Dim vtmp As Integer

   'init our return value to null
    vret.id = isnull
    'check to see if both values are strings
    If v1.id = isstring And v2.id = isstring Then
       vret.id = isstring 'set the id type
       vret.sdata = v1.sdata + v2.sdata
    End If
    'check to see if both values are integers
    If v1.id = isinteger And v2.id = isinteger Then
       vret.id = isinteger 'set the id type
       vret.idata = v1.idata + v2.idata
    End If
    'check for string - integer combination
    If v1.id = isstring And v2.id = isinteger Then
       'check to see if string can be converted to integer
       vtmp = Val(v1.sdata)
       'successful conversion so add as integers
       If vtmp > 0 Then
           vret.id = isinteger 'set the id type
           vret.idata = vtmp + v2.idata
       Else
           'can't convert to integer so convert integer to string
           vret.id = isstring 'set the id type
           vret.sdata = v1.sdata + Str$(v2.idata)
       End If
    End If
    'check for integer - string combo
    If v1.id = isinteger And v2.id = isstring Then
       'check to see if string can be converted to integer
       vtmp = Val(v2.sdata)
       'successful conversion so add as integers
       If vtmp > 0 Then
           vret.id = isinteger 'set the id type
           vret.idata = vtmp + v1.idata
       Else
           'can't convert to integer so convert integer to string
           vret.id = isstring 'set the id type
           vret.sdata = Str$(v1.idata) + v2.sdata
       End If
    End If
    'if one or both values are null, return null.
    If v1.id = isnull Or v2.id = isnull Then
       vret.id = isnull
    End If
End Sub

This subroutine checks each id of the first and second parameters and then chooses the appropriate operation, returning the result in the third parameter. I coded this the “long way” to make it clear that you have to check each parameter combination; that is, string-string, integer-integer, string-integer or integer-string, and finally if either value is NULL, we simply return a NULL. Lets examine the string-string combo in detail.

    'check to see if both values are strings
    If v1.id = isstring And v2.id = isstring Then
       vret.id = isstring 'set the id type
       vret.sdata = v1.sdata + v2.sdata
    End If

Here we check the ids of v1 and v2. Since both are strings, we are going to do a concatenate operation, saving the string data in vret.sdata and indicating that we have a string value with vret.id = isstring. Let’s look at the string-integer combination.

    'check for string - integer combination
    If v1.id = isstring And v2.id = isinteger Then
       'check to see if string can be converted to integer
       vtmp = Val(v1.sdata)
       'successful conversion so add as integers
       If vtmp > 0 Then
           vret.id = isinteger 'set the id type
           vret.idata = vtmp + v2.idata
       Else
           'can't convert to integer so convert integer to string
           vret.id = isstring 'set the id type
           vret.sdata = v1.sdata + Str$(v2.idata)
       End If
    End If

Here we have a string and integer. We check to see if the string can be converted to a number using Val(v1.sdata). If vtmp is greater than 0, then we will add the value in vtmp to v2.idata and set vret as an integer type. If vtmp is 0, meaning Val() could not convert the string to a number, then we convert v2.idata to a string, Str$(v2.idata), and set vret to a string type.

To call Addv we simple pass the two data items, and the return value.

Addv v2, v1, v4

The two operands v2 and v1 are added together and returned in v4.


Complete Program

Here is the complete program.

Option Explicit
'compiled using Freebasic .14b

'define our data type classes
#Define isnull 0
#Define isstring 1
#Define isinteger 2

'define our union type
Type vtype
   id As Integer
   Union
       sdata As String
       idata As Integer
   End Union
End Type

'define our set function using overload
Declare Sub SetV Overload (idata As Integer, v As
vtype)
Declare Sub SetV (sdata As String, v As vtype)

'create the integer set
Sub SetV(idata As Integer, v As vtype)
   v.id = isinteger
   v.idata = idata
End Sub

'create the string set
Sub SetV(sdata As String, v As vtype)
   v.id = isstring
   v.sdata = sdata
End Sub

'Define our method to add two variants using the
following rules:
'1 If both are the same type, add them and return new value.
'2 If one is an integer and one is a string, convert string
'  to integer if it can be represented as an integer, otherwise
'  convert integer to string and append v2 to v1.
'3 If one or both values are null return null.
Sub AddV(v1 As vtype, v2 As vtype, vret As vtype)
   Dim vtmp As Integer

   'init our return value to null
    vret.id = isnull
    'check to see if both values are strings
    If v1.id = isstring And v2.id = isstring Then
       vret.id = isstring 'set the id type
       vret.sdata = v1.sdata + v2.sdata
    End If
    'check to see if both values are integers
    If v1.id = isinteger And v2.id = isinteger Then
       vret.id = isinteger 'set the id type
       vret.idata = v1.idata + v2.idata
    End If
    'check for string - integer combination
    If v1.id = isstring And v2.id = isinteger Then
       'check to see if string can be converted to integer
       vtmp = Val(v1.sdata)
       'successful conversion so add as integers
       If vtmp > 0 Then
           vret.id = isinteger 'set the id type
           vret.idata = vtmp + v2.idata
       Else
           'can't convert to integer so convert integer to string
           vret.id = isstring 'set the id type
           vret.sdata = v1.sdata + Str$(v2.idata)
       End If
    End If
    'check for integer - string combo
    If v1.id = isinteger And v2.id = isstring Then
       'check to see if string can be converted to integer
       vtmp = Val(v2.sdata)
       'successful conversion so add as integers
       If vtmp > 0 Then
           vret.id = isinteger 'set the id type
           vret.idata = vtmp + v1.idata
       Else
           'can't convert to integer so convert integer to string
           vret.id = isstring 'set the id type
           vret.sdata = Str$(v1.idata) + v2.sdata
       End If
    End If
    'if one or both values are null, return null.
    If v1.id = isnull Or v2.id = isnull Then
       vret.id = isnull
    End If
End Sub

'define our print routine
Sub PrintV(v As vtype)
   'print out data based on type
   If v.id = isstring Then
       Print v.sdata
   ElseIf v.id = isinteger Then
       Print v.idata
   Else
       'just print a null string for null
       Print
   End If
End Sub

'create some variant data type
Dim As vtype v1, v2, v3, v4

'create an integer type
SetV 10, v1
Print "Set integer: ",
PrintV v1
'create a string type
SetV "10", v2
Print "Set string: ",
PrintV v2
'create a null type
v3.id = isnull
Print "Set null: ",
PrintV v3
Print

'add two integers together
Addv v1, v1, v4
Print "Adding 2 integers:",
PrintV v4

'add two strings together
Addv v2, v2, v4
Print "Adding 2 strings:",
PrintV v4

'add string and integer
Addv v1, v2, v4
Print "Adding string, integer:",
PrintV v4

'add integer and string
Addv v2, v1, v4
Print "Adding integer, string:",
PrintV v4
Print

'adding null to integer
Addv v3, v1, v4
Print "Adding null, integer:",
PrintV v4

'adding integer to null
Addv v1, v3, v4
Print "Adding integer, null:",
PrintV v4

'adding null to string
Addv v3, v2, v4
Print "Adding null, string:",
PrintV v4

'adding string to null
Addv v2, v3, v4
Print "Adding string, null:",
PrintV v4

'adding null to null
Addv v3, v3, v4
Print "Adding null, null:",
PrintV v4
Print

'create a new string type
SetV "This is a string", v2
Print "Set string: ";
PrintV v2
Print

'add string and integer
Addv v2, v1, v4
Print "Adding new string, integer:",
PrintV v4

'add integer and string
Addv v1, v2, v4
Print "Adding integer, new string:",
PrintV v4


Print
Print
Print "Press any key"
Sleep

Output

And here is the output.

Set integer:    10
Set string:   10
Set null:

Adding 2 integers:           20
Adding 2 strings:           1010
Adding string, integer:      20
Adding integer, string:      20

Adding null, integer:
Adding integer, null:
Adding null, string:
Adding string, null:
Adding null, null:

Set string: This is a string

Adding new string, integer: This is a string10
Adding integer, new string: 10This is a string


Press any key


Unions are a way to reduce complexity in a program, by enabling the programmer to package different types of data within a single object, and create a single set of methods to manage the data contained within the object.


Download a copy of this tutorial: Unions.txt


Graphical User Interfaces - A Complete Study
Part 3 - ErgonOS Organization and Standards

Written by Stéphane Richard (Mystikshadows)

INTRODUCTION:

If you're reading this, I'm assuming you've read Part One and Part Two of my series already. If you didn't, please do before continuing here as the first two parts will greatly clarify what is going on in this third part of the series. In this document we'll begin to cover many aspects of what the programming will comprise. When starting to code a project this size, it's important to document yourself all the way. And this series will do just that.

Even though technically I will be working by myself on ErgonOS, one never knows what the future holds. I could be offered help in this project, I could let it go for a while and get back to it afterwards, I might even work for a good while on one part of the GUI and forget some parts that I created a while back when it's time to get back to those other modules. These are all situations where quality of code and effort in code documentation and "intelligent" organization of modules, a steady global naming convention and such type of tools can really come in handy. So before any coding begins, we'll defined these standards, and you'll see that the code I'll be writing will comply to that standard. So let's start this big wheel turning shall we?

ERGONOS CODING STANDARDS:

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

ERGONOS DEVELOPMENT STAGES:

And now that we have all the standards defined and out of the way, we can really begin to orient the project towards it's development. As you remember from the 2nd part of this series, I've enumerated 8 seperate engines that make up ErgonOS. If you had the User Interface part to the list (All the controls I enumerated and detailed) there's really 9 main engines. The main thing to remember is that all these 9 engines need to work together so they will need some means of communicating with each other and have access to each other's functionality. However. You might even think at this point (especially if you have a group of 9 people working on the project) that each could take an engine and just start coding. But that's not entirely the case. Some of these engines can be started independantly, others however will need one or more of the engines to be completed prior to their development. Let's Take these engines right here and determine their realization criteria. This way we'll know what should be done first (and even what parts of the engine, if any, could be created independantly of the the others).

There you have it. With these relationships established it will be easier to determine what's what and what should get done before whatever else. There's basically one thing left to determine and that is code module organization. That again is also mostly a question of personal taste. But just so you don't get lost in how I'll be doing things, I will explain to you now the way modules will be created and managed. Since these are all based on the engines themselves I will break them down by engine.

ERGONOS CODE MODULE ORGANIZATION:

When it comes to bigger projects, I believe that organization even at the module level, brings many benefits from the start of the development stage all the way down to the debugging phase. If you can create a system that can instantly tell you what code lies in what module instantly, it becomes much more trivial to locate where, in all the thousands of lines of code, something you're looking for is. As such, I try to organize my code in a way that really helps isolate every type of code into it's own module. Since ErgonOS has 9 engines it's easy to see how quickly code could get confusing if it was all in one module only. Code Module Organization along with intelligent error reporting can really make locating a bug a breeze. Of course Error management isn't the most passionate side of development so I like to get rid of it as soon as I can so I can get to the real fun part. So then, for each engine, each related module file will have a corresponding filename to clearly indicate, before we open the file, which engine the file belongs to and what I can expect to find in each of the engine's related modules. Here's the layout of the file naming conventions.

ErgonOS Module Naming Convention
Module Name Description
<EngineName>Constants.bi
<EngineName>Enumerations.bi
<EngineName>UserTypes.bi
<EngineName>EngineCore.bas
<EngineName>Helper.bas
<EngineName>Communicate.bi
<EngineName>UserInterface.bi
<EngineName>Events.bi
constants go here.
ENUM definitions go here
User Defined Types go here
Core Functionality goes here
Functions that help the engine go here
Information and code to transfer with other modules
User Interface related code goes here
Event Management related code goes here

Now some of these modules may not be needed for a given engine. For example, the low level libraries that do not interact with the user at all won't need the UserInterface and Events module Others might not need to communicate with other modules either, it all depends on the role of the engine in the ErgonOS hierarchy. As an example, let's illustrate this using the EVRIL engine so you can see how things will appear in the folder.

E.V.R.I.L. (ErgonOS Visual Representation and Intelligent Layout)
Module Name Description
EVRILConstants.bi
EVRILEnumerations.bi
EVRILUserTypes.bi
EVRILEngineCore.bas
EVRILHelper.bas
EVRILCommunicate.bi
EVRILUserInterface.bi
EVRILEvents.bi
constants go here.
ENUM definitions go here
User Defined Types go here
Core Functionality goes here
Functions that help the engine go here
Information and code to transfer with other modules
User Interface related code goes here
Event Management related code goes here

Aside the engine modules themselves there will be one set of module that will serve the purpose of containing elements that are shared among all other engines. For example, Keyboard Constants don't need to be defined at an engine level as any module that needs to access the keyboard can do so using the same constants. Such types of code will go in modules that are prefixed with "Shared". Here are the shared modules that we will need:

ErgonOS Shared Modules
Module Name Description
SharedConstants.bi
SharedEnumerations.bi
SharedUserTypes.bi
SharedHelper.bas
SharedCommunicate.bi
SharedUserInterface.bi
SharedEvents.bi
SharedErrorManagement.bi
Shared constants go here.
Shared ENUM definitions go here
Shared User Defined Types go here
Shared Helper functions and subs
Shared Module inter-communication facility
Shared User Interface related code goes here
Shared Event Management related code goes here
Shared Error Management and Logging facilities

Finally, as far as the user interface is concerned, each component that I have enumerated in the second part of this series will be implemented independantly in their respective module. Some modules will be bigger than others but by grouping these into control related functionality, it will help keep the whole user interface in perspective. Therefore, here are the control specific modules needed by the user interface:

ErgonOS Component Modules
Module Name Description
LabelComponent.bas
ButtonComponent.bas
CheckBoxComponent.bas
RadioButtonComponent.bas
TextBoxComponent.bas
MaskedBoxComponent.bas
SelectorBoxComponent.bas
PictureBoxComponent.bas
ListBoxComponent.bas
ListViewComponent.bas
TreeViewComponent.bas
ScrollBarComponent.bas
ComboBoxComponent.bas
CalendarDropComponent.bas
NumericDropComponent.bas
ToolbarComponent.bas
ToolboxComponent.bas
MenuBarComponent.bas
PulldownMenuComponent.bas
PopupMenuComponent.bas
StatusBarComponent.bas
IndicatorBarComponent.bas
TabbedDialogComponent.bas
TabStripComponent.bas
DocumentComponent.bas
UserDefinedComponent.bas
Static Label used to display text on the screen
Button that can be clicked, pressed or unpressed
Square component that can be checked and a label
Round component that only one can be checked
Standard text entry field type component
Text entry field that can block unwanted characters
Text entry that has 2 buttons to increment/decrement
Rectangular component to display an image
Rectangular list of selectable Item
Non Editable Grid viewing with images with multiple views
Control to represent data in a hierarchic fashion
A Slider Type control that has a min, max and current value
Combination TextBox, Button and ListBox components
Combination Maskedbox, Button and Calendar components
Combination textbox with 2 button components
Component that holds other components
Floating control that works like a toolbar component
Top of form rectangular area to hold menu options
Vertical selection appearing below a MenuBar component
Same as Pulldown Menu that appears where the mouse is
Bottom of screen rectangle that displays information
Bottom of screen rectangle to show indicators
Tabbed component that can have different page types
Tabbed component holding many of the same page type
Component to manage all supported document formats
Component to create original components from scratch

Note that this is my way of doing things, and in no means do I intend to "force" you to use this particular naming convention for your own projects. Since there are many modules involved I believe that by naming the modules accordingly and keep code organized in this manner it will greatly help the coding process by allowing me to see what is where even without opening the module. It also makes each module smaller and much more managable. For your projects you can create any standard your want because it's your project and the first person that needs to understand what's going on is you. You might work better with less modules and mode code in each module, you might even break your modules into even more modules than I've done. It all depends on what you're comfortable with and your way of doing things.

Remember that this series is to teach you everything you need to know about making a GUI. As such, and because different people read and understand things differently on different levels, I will be keeping the tutorial series and it's related code modules as clear and documented as possible so that everyone can read and understand the concepts I will be using. This is also one of the reason why the code will be organized the way it will be and why I will be following the standards I've established in this 3rd part of the document. For a project this size, not having some form of organization like this would defeat the purpose of writing this series. Let's continue with another important aspect of development (in GUI or any other programming project), I'm talking about Error Management.

ERGONOS ERROR MANAGEMENT:

Now some of you might be wondering why I'm talking about error management even before any line of code is written. The answer is simple. In big projects, if you don't implement error management right from the start, it will be a major headache to add it later in the project or at the end after you're done coding everything else. This project will easily have several thousand lines of code and atleast several hundred subs and functions, maybe thousands, imagine having to go through each and everyone of these subs and functions and having to add error management code to them all. By adding that code at the beginning it will not only rid you of he big burden of adding it later but also help you greatly in your testing and debugging phase. You'll thank yourself (and me, maybe) in the long run.

Throughout all the modules, when implementing the error management code, I'll want to be sure that it is as easy and quick to locate a bug or an error as possible. For that to successfully occur, I need a certain list of information to help me in my quest. Whether the bug is reported on screen or logged to a file this information will still help locating bugs quickly. Here's that information:

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

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

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

As you can see, it takes a little bit extra coding to implemented error management properly. I'd rather have to add 10 lines everytime I create a sub than to have to find and add a couple 100 or 1000 lines of code by doing this part in the end, after the whole coding process is done. Error management is really there for two purposes. The first is of course to document the error when it occurs in an intelligent way that will help you know where to look and what type of error you'll be fixing. But it's also there so that the program doesn't quit in an uncivilized way. For example, say the user has a document currently opened. When there's no error management and the program just exists, there's a risk that the document might be either lost or corrupted (especially if the error occured as you were saving the file). Proper error management can prevent alot of these situations that make your system that much more stable and reliable to the users.

PART THREE NOW CONCLUDED:

This is it for the third part of the GUI Development Tutorial. The main thing to remember from this series and especially this third part is that you are free to create your own names, standards (if you want), your own component names, your own graphics, your own style. What you are reading here is based on my own project and as such I have the freedom to name things the way I want to. In the same frame of mind, because this is a tutorial series designed to make you, the reader, understands everything there is to know about GUI development from the very start to the end, I am making special efforts to name things very clearly and use a standard that can help you learn the type of coding I will do as well as how you can implement similar routines and structures in your own projects. The name of the game here is that GUI development should most of all be fun to make and to use after you made it. This means if you don't want to implement Error Management right away, you don't have to, but my own personal and professional experience has thought me that if you are planning to implement error management (which I highly recommend on any project that might be used by other people) then right now is the best time to do it because you can then integrate error management in your regular coding routine. As well, when you're done coding, you won't have to go through all your code to insert the error management code later.

I think we've now had enough of the theories, standards and conventions, the next part of this series will now concentrate on the ErgonOS development itself. We'll begin to define the information we'll need when creating components, or whole system of components, we'll start to create coding structures for this information, and we'll begin to put some code in all these modules we defined in this third part of the series. I hope you're enjoying the series so far, I sure am enjoying writing it for you (of course) but for me as well, since it's my GUI project, needless to say that this series will serve as an excellent document for the development of this project. So then, let all this knowledge sink in good. Maybe you've already started to document your own project as you're reading this and you'll want to do some documentary work on your project, go right ahead. For a project like this, you'll only thank yourself in the end. As always, if you have questions, if something in this document (or the other documents in the series) that isn't quite clear or that you'd like me to elaborate on in even more details, send me an email and let me know all about it. Untill Next time, happy reading, and learning.

MystikShadows
Stéphane Richard
srichard@adaworld.com

Download a copy of this tutorial: guicompletestudy3.html


Graphical User Interfaces - A Complete Study
Part 4 - ErgonOS Development Begins

Written by Stéphane Richard (Mystikshadows)

INTRODUCTION:

Part 4, you read it right, this is where are are in this GUI Development series. There's still plenty to write about in this series so I don't foresee an end to this series any time soon. To those of you who just tuned into this series, I strongly recommend you read Part 1, Part 2 and Part 3 before continuing here. In these first 3 parts, we've covered what the ErgonOS GUI will look like, how it will work, we've enumerated the workload of what we'll need to do, we defined the order we'll be coding it and established some coding standards and naming conventions for the source modules. I've highlighted what I believe to be the importance of documenting as much as possible when undertaking a project like a GUI (it's not a small project, therefore, any time you spend documenting is time well spent). With all this in mind I believe we are now ready for the next step, The ErgonOS GUI development itself.

Note that from this point on in the series I will be including the source files. This way, you'll save alot of typing for one thing and you'll be able to really get familiar with the coding I'll be doing in the course of this series. Needless to say this zip file will grow as we add modules and code in the modules as this series progresses. So then, let's get right to it shall we?

THE ERGONOS ENGINE DIAGRAM:

A couple of days after the release of my first two part of the series, I started exchanging a few emails with an individual that asked a few questions about certain concepts. One of the suggestions he gave me was to create a diagram of the engines specifically about the dependencies of the engines and where they fall in he ErgonOS inner structures. So I created this diagram to explain these dependencies (dependencies that I detailed textwise in the 3rd part of this series.

ErgonOS Engine Diagram

I think we can all agree that in this case, a picture really is worth a 1000 words. I think this diagram really helps visualize where each engine falls in the bigger picture and also helps us locate things from a functional point of view as well. Althought the diagram pretty much speaks for itself, here are a few points that might be of interest to you.

You might want to create yourself a hardcopy of this diagram as I'll be refering to it every now and then in the rest of this series. As well, I'll be creating more of these diagrams, one for each engine to show the innerworkings of each of them. For now, this global diagram will do fine for the remainder of this 4th part of the series. I left out the E.A.G.L.E. engine as it's a programming language, not an engine per se. Needless to say that E.A.G.L.E. will have access to all other engines depending on what it needs to accomplish.

With this in mind, I think it's high time we get coding don't you? Basically, in this 4th part, we'll begin work in two parts of the projects. The first will be the ErgonOS Shared Modules (which are the Shared______ modules) and our ErgonOS Main Nodules (which are the ErgonOS______ modules as per our naming convention). We'll create some code in some of the modules in each group and we'll see where it will take us. We'll begin with the shared modules because the main modules will need some of the things we'll be defining in the shared modules.

THE ERGONOS SHARED MODULES:

Basically, anything that can be used in atleast 2 engines should be in the shared set of modules, it's really as simple as that and by doing that we can avoid alot of redundancy in our code and keep any global alterations in one place. As we develop these engines, this is one of he place that will grow and/or change alot as we fine tune our work. For now we'll basically follow that simple rule (if it can be used in more than one module it goes in the shared set of modules). Moving right along then, we'll start, like we did before, with the SharedConstants.bi module. The main reason I like to define constants is one of readability of code. Sure it might take a little longer to type KeyBackspace rather than 8 but it makes for much more readable code. The choice is yours of course, me, I prefer readable code. Since this module (and the other shared modules) will be included in other modules, we will begin by a preprocessor statement to make sure the module isn't repeatedly included.

' ----------------------------------------------- ' Preprocessor to include this module only once ' ----------------------------------------------- #IFNDEF SharedConstants #DEFINE SharedConstants

Pretty simple isn't it? This #IFNDEF tells us that if the ErgonOSConstants define doesn't exist, we can proceed with what follows in the module. The next line defined ErgonOSConstant. This means that the next time a modules includes ErgonOSConstants.bi, it will know that ErgonOSConstants has been defined and will not go into creating all the constants again (which will avoid a duplicate definition error). We'll be using this technique in all modules that will potentially be used in more than one engine. Now we can continue with the constant definitions themselves. A very common set of constants to define, that will be used throughout the whole project, is keyboard constants.

' ------------------------------- ' Keyboard Constant Definitions ' ------------------------------- CONST KeyF1 = 59 CONST KeyF2 = 60 CONST KeyF3 = 61 CONST KeyF4 = 62 CONST KeyF5 = 63 CONST KeyF6 = 64 CONST KeyF7 = 65 CONST KeyF8 = 66 CONST KeyF9 = 67 CONST KeyF10 = 68 CONST KeyF11 = 133 CONST KeyF12 = 134 CONST KeyInsert = 82 CONST KeyDelete = 83 CONST KeyHome = 71 CONST KeyEnd = 79 CONST KeyPageUp = 73 CONST KeyPageDown = 81 CONST KeyUpArrow = 72 CONST KeyDownArrow = 80 CONST KeyLeftArrow = 75 CONST KeyRightArrow = 77 CONST KeyBackspace = 14 CONST KeyTabulation = 15 CONST KeyEnter = 13 CONST KeyEscape = 27 CONST KeySpace = 32 CONST KeyLeftShift = 42 CONST KeyRightShift = 54 CONST KeyAlternate = 56 CONST KeyControl = 29 CONST KeyCapsLock = 58

You'll see later, in the main loop, that these keyboard constants will greatly help the readability of the code. Another good thing to have here are the standard DOS color constants. For part of the initialization process, we'll want to give some feedback to the user as to what is currently happening in the process. And we'll use these constant to give a clear feedback to the user in significant color combination. The color constants are defined like so:

' ---------------------------- ' Color Constant Definitions ' ---------------------------- CONST Black = 0 CONST Blue = 1 CONST Green = 2 CONST Cyan = 3 CONST Red = 4 CONST Purple = 5 CONST Brown = 6 CONST Grey = 7 CONST DarkGrey = 8 CONST LightBlue = 9 CONST LightGreen = 10 CONST LightCyan = 11 CONST LightRed = 12 CONST LightMagenta = 13 CONST Yellow = 14 CONST White = 15

Finally, well need to close the #IFNDEF statement at the beginning of the module. You might have noticed that #IFNDEF pretty much works like a standard IF statement and it does. This means that like the standard IF statement, it needs it's closing statement. In FreeBasic, you close this preprocessor like this:

' --------------------------------------------------------- ' This #ENDIF closes to module inclusion check at the top ' --------------------------------------------------------- #ENDIF

This is it for the SharedConstants.bi, atleast for now as we might think of adding a few things as the project progresses. TWe can now begin our SharedEnumerations.bi module. Enumerations are named list of values defined under a data type name. They are ideal o use when you have a fixed set of values that a given variable should have. Everywhere in the GUI project, different parts of the application will need to set the mouse cursor to different images depending on if it renders ErgonOS in a busy state, or if we're on a control that needs a different mouse cursor shape to help make clear what the expected action on the control is. So this will be the first of our enumerations. We'll also include the Module Inclusion check as it will be needed here too.

' ----------------------------------------------- ' Preprocessor to include this module only once ' ----------------------------------------------- #IFNDEF SharedEnumerations #DEFINE SharedEnumerations ' -------------------------------------------------------------- ' NAME: MousePointers ' DESCRIPTION: Enumeration to hold the different mouse pointer ' types available ' -------------------------------------------------------------- ENUM MousePointers MouseDefault MouseBlock MouseCross MouseIBeam MouseIcon MouseSize MouseLeftArrow MouseNorthSouth MouseRightArrow MouseWestEast MouseUpArrow MouseHourGlass MouseDownArrow END ENUM

Enumerations work because the first named value starts at 0 and every other named value after that increments by one. Hence MouseDefault will be at 0, MouseBlock will be 1, MouseCross will be 2 and so on and so forth. If you want to change this order of values, you just need to add an = sign and the new value. For example, if we'd change MouseIBeam to MouseIBeam = 10, then MouseIBeam would be 10, MouseIcon would be 11, MouseSize would be 12, and so on. This is important to know because in some cases, you would need to change the default enumeration pattern. In ErgonOS, any form that will appear on top of the Standard work areas (the 6 zones we defined in the first part of the series), will have different border styles depending on more than criteria. These border styles can be defined in an enumeration, like this:

' ------------------------------------------------------------- ' NAME: BorderStyles ' DESCRIPTION: Forms and frames can be drawing with different ' different border sets ' ------------------------------------------------------------- ENUM BorderStyles BorderNone BorderSolid BorderFixedSingle BorderSizableSingle BorderFixedDouble BorderSizableDouble BorderFixedSolid BorderSizableSolid END ENUM ' --------------------------------------------------------- ' This #ENDIF closes to module inclusion check at the top ' --------------------------------------------------------- #ENDIF

That's all we'll need, atleast for now, in the SharedEnumerations.bi module. As any other modules, things may be added in the future, but for now, we don't need anything else. We can jump to our SharedUserTypes.bi which is where our shared user defined types will reside. There's alot of things to put in here, I will go about gradually so it's easier to follow through. Since right now, we're concerned about the startup sequence and the configuration file, we will include only the user defined types that we will need to do just that, startup the system and load the configuration data from the file. The first type we'll define here is our ApplicationType Structure. It is defined in the following manner:

' ----------------------------------------------- ' Preprocessor to include this module only once ' ----------------------------------------------- #IFNDEF SharedUserTypes #DEFINE SharedUserTypes ' ---------------------------------------------------------------------- ' NAME: ApplicationType ' DESCRIPTION: This Type holds general Application related information ' such as the screen resolution, the color depth which ' zones are visible and the zone sizes. ' ---------------------------------------------------------------------- TYPE ApplicationType ScreenHeight AS INTEGER ScreenWidth AS INTEGER ColorDepth AS INTEGER ProjectVisible AS BYTE ProjectWidth AS INTEGER ProjectHeight AS INTEGER RelatedVisible AS BYTE RelatedWidth AS INTEGER RelatedHeight AS INTEGER SearchVisible AS BYTE SearchWidth AS INTEGER SearchHeight AS INTEGER DocumentVisible AS BYTE DocumentWidth AS INTEGER DocumentHeight AS INTEGER CommandVisible AS BYTE CommandWidth AS INTEGER CommandHeight AS INTEGER ShortcutsVisible AS BYTE ShortcutWidth AS INTEGER ShortcutHeight AS INTEGER END TYPE

Of course this started with our Module Inclusion Check for ErgonOSUserTypes. Also remember that the ApplicationType structure needs to stay as general as possible and that any specific detail on each of the zones will be defined in each of the zone structures. Although the different zones will be resizable to allow the user more space for the document zone, each of the zones can be defined with a standard WindowType data structure. Such a structure can be defined like so:

' ------------------------------------------------------------ ' TYPE NAME: WindowType ' DESCRIPTION: This holds all the needed information to ' create a window on the screen including if ' all controls on the window should be shown ' or hiding, the windows title, it's size, ' it's color combinations and its coordinates. ' ------------------------------------------------------------ TYPE WindowType WindowNumber AS INTEGER WindowType AS INTEGER WindowTitle AS STRING WindowTop AS USHORT WindowLeft AS USHORT WindowHeight AS USHORT WindowWidth AS USHORT TitleForeground AS USHORT TitleBackground AS USHORT ControlForeground AS USHORT ControlBackground AS USHORT ActiveForeground AS USHORT ActiveBackground AS USHORT InactiveForeground AS USHORT InactiveBackground AS USHORT BorderForeground AS USHORT BorderBackground AS USHORT HighlightForeground AS USHORT HighlightBackground AS USHORT ShadowForeground AS USHORT ShadowBackground AS USHORT IsActive AS BYTE ShowMinimize AS BYTE ShowMaximize AS BYTE ShowClose AS BYTE ShowControl AS BYTE ShowResizeHandle AS BYTE ShowVerticalScrollbar AS BYTE ShowHorizontalScrollbar AS BYTE END TYPE

As you can see, this is a big User Defined Type, the fields are pretty much self explanatory in their names. Every single Window and component that is shown on the screen will have it's unique WindowNumber. This will allow events to be identified with the corresponding window and controled that the event was created from. One thing to remember is that all the Show______ fields will mean that a component will be need to support each of them. hence command buttons for the Minimize, Maximize, Close and Control buttons. Another area for the Resize (at the lower right of the window and two scrollbar components for the two scroll bars will be optionally showing when drawing the window.

Next on the list is the global parameters so to speak. I like to call these environment settings as they influence the way we see things in ErgonOS. This structure will hold information like currency symbol, comma and decimal seperators, date format, time format and other global parameters such as these. This structure is called the EnvironmentType and is defined like so:

' ------------------------------------------------------------ ' TYPE NAME: EnvironmentInformation ' DESCRIPTION: This holds the environment settings and ' other configuration data that is active when ' in an ErgonOS session. ' ------------------------------------------------------------ TYPE EnvironmentType DateSeperator AS STRING ' Default '/' DateFormat AS STRING ' Default 'MM/DD/CCYY' TimeSeparator AS STRING ' Default ':' TimeFormat AS STRING ' Default 'HH:MM:SS' DecimalSeperator AS STRING ' Default '.' ThousandSeperator AS STRING ' Default ',' CurrencySymbol AS STRING ' Default '$' SystemPath AS STRING ' Where the system is DefaultProjectPath AS STRING ' Where the projects are DefaultSearchPath AS STRING ' Where to search first DefaultResourcePath AS STRING ' Where bitmaps are stored DefaultDocumentPath AS STRING ' Where Documents are stored DefaultToolsPath AS STRING ' where Tools are saved in END TYPE ' --------------------------------------------------------- ' This #ENDIF closes to module inclusion check at the top ' --------------------------------------------------------- #ENDIF

As far as Startup sequence goes, this is all we'll need in the SharedUserTypes.bi module. You'll notice our closing #ENDIF is present here too as it must. There is no doubt that alot of user defined types will be added here in the near future to accomodate the rest of the information we'll need. But again, for the sake of the startup sequence and configuration data, this is all that we will need to use. It's important to know at this stage, that once these data structures are populated with their corresponding data, we'll use them as global structures that will need to be available to any and all other engines and modules that will be present in the project.

The other shared modules, at this point of the project will simply stay empty (except for their module level comments) as nothing else is really needed at this point. Keep in mind that this will change when we start tackling the engines themselves. Since most of the constants, enumerations and user defined types have been defined here in the Shared set of modules, the main set of modules will concentrate on more functionality rather than data definition. Let's get right to the definition of the main set of modules.

THE ERGONOS MAIN MODULES:

The main set of modules are of course the modules that will contain Ergon O.S. Specifically related constants, enumerations, user defined types, subs and functions that we will need at the Ergon O.S. Level only. For example, the loading and saving of the configuration file will be at this level. Let's begin with ErgonOSConstants.bi which is where our contants will be defined.

' ----------------------------------------------- ' Preprocessor to include this module only once ' ----------------------------------------------- #IFNDEF ErgonOSConstants #DEFINE ErgonOSConstants ' ------------------------------------------------------ ' General Application Information Constant Definitions ' ------------------------------------------------------ CONST ApplicationName = "Ergon O.S." CONST AuthorName = "Stephane Richard" CONST AuthorNick = "MystikShadows" CONST AuthorEmail = "MystikShadows@gmail.com" CONST VersionMajor = 1 CONST VersionMinor = 0 CONST VersionRevision = 0 CONST VersionRelease = "a" CONST BuildNumber = 1 CONST VersionStamp = "1.00.000a Build 0001" CONST ProjectDescription = "An OpenSource Ergonomically designed document based G.U.I. system" CONST ProjectLicensing = "Released under the G.P.L. 2.0 licensing sheme." CONST ProjectCopyright = "Copyright (c) November 2005 - Stephane Richard" CONST ProjectWebsite = "Coming Soon"

These general application constants are there for informational purposes only. As you can see, they hold application specific information that we will using when displaying information about the current version of Ergon O.S. at startup and when the About Dialog is called upon. At the Ergon O.S. level, we can also add the configuration file specific constants, like so:

' ---------------------------------------------------- ' Ergon O.S. Configuration file constant definitions ' ---------------------------------------------------- CONST ConfigurationFile = "ErgonOS.CFG" CONST ApplicationSection = "[APPLICATION]" CONST EnvironmentSection = "[ENVIRONMENT]" CONST PathsSection = "[PATHS]" CONST DesktopSection = "[DESKTOP]" CONST ColorSetupSection = "[COLORS]" CONST SoftwareSection = "[SOFTWARE]" CONST StartupSection = "[STARTUP]"

Finally, we'll add two constants for known command line paramaters These will allow us to compare them later to know what part of the code to execute next in the ErgonOS startup sequence. Here are the constant definitions. At this point there's two command line parameters I'll want to add here /C and /E. Now /C will allow to load a different configuration file. If /C is not specified, "ErgonOS.cfg" will be loaded (that's the default configuration file). /E will allow to execute a file that will contain a list of standard commands to execute sequentially. If /E is not specified, then no command will be executed.

' ---------------------------------------------------- ' Ergon O.S. Configuration file constant definitions ' ---------------------------------------------------- CONST AlternateSetup = "/C" ' Load non default ErgonOS Setup File CONST CommandFileExecution = "/E" ' Load and run Specific Command File ' --------------------------------------------------------- ' This #ENDIF closes to module inclusion check at the top ' --------------------------------------------------------- #ENDIF

That's about it for now as far as this module is concerned. The configuration constants simply hold the configuration Name and the configuration sections (that will be present in the configuration file when it is created. Now, more sections might be added later, but this should be enought to give you an idea of what could go in this module. Next module is ErgonOSEnumerations.bi, however in our case (it might be different for your project, or mine, later in my development effort) but as of now, I have nothing to put into this module so I will leave it present in the folder, but empty aside it's module level comments.

This takes us to the next module, ErgonOSUserTypes.bi where the user defined types will go. Technically, you might think that we could put the user defined types we'll need to load the information from the configuration file. And at first, that's where I was going to put them. But thinking from the Ergon O.S. perspective itself, I am forced to put these user defined types in the SharedUserTypes.bi module (see above). You see, the information loaded from the configuration file will need to be accessible throughout the rest of the modules. If I put the User Types in the ErgonOSUserTypes.bi file, I will forcibly need to include two modules, rather than just one, to get the full scope of shared user defined types Programming wise, it's just an extra '#INCLUDE: '' statement, no big deal, however, from my organization's perspective, if I can use just one include, I will (which also means I will only need to look in one place if I ever need to change a field definition for example). So again, for now, I will leave ErgonOSUserTypes.bi empty aside it's module level comments.

This brings us to the ErgonOSHelper.bas module. As you recall, this modules holds essentially subs and functions that help the main module (or EngineCore module) perform it's tasks. As such, this module, for now, will have 3 functions. The first is called ValidateParameters which will make sure that the passed command line pararmeters are indeed valid ones as per the list of valid command line parameters. This function is defined like so:

' ----------------------------------------------- ' Preprocessor to include this module only once ' ----------------------------------------------- #IFNDEF ErgonOSHelper #DEFINE ErgonOSHelper ' =============================================================== ' NAME: ValidateParameters() ' PARAMETERS: None ' RETURNS: 0 of parameters are valid, Invalid Param number ' ASSUMES: Nothing ' CALLED FROM: ErgonOS.bas Main Program Section ' --------------------------------------------------------------- ' DESCRIPTION: This Sub makes sure that any parameters that ' passed to the application are valid ones. An ' Error will be reported if a parameter is not ' valid but the application will not exit instead ' the IDE will start in default mode or process ' the rest of the valid parameters. ' =============================================================== FUNCTION ValidateParameters() AS INTEGER DIM argc AS INTEGER DIM argv AS INTEGER DIM WorkResult AS INTEGER argc = 1 WorkResult = 0 DO argv = COMMAND$(argc) IF LEN(argv) = 0 THEN EXIT DO END IF IF argv <> AlternateSetup AND argv <> CommandFileExecution THEN WorkResult = argc END IF argc = argc + 1 LOOP ValidateParameters = WorkResult END FUNCTION

The next function we'll put in ErgonOSHelper.bas is the function that deals with the loading of the configuration file itself. It will open the right configuration file (ErgonOS.cfg or another file if the /C: command line parameter was passed to the executable). And peruse it while loading its values into the proper User Defined Types.

' =============================================================== ' NAME: LoadConfiguration() ' PARAMETERS: ConfigFile AS STRING ' RETURNS: 0 if no errors, Err number if anything happened ' ASSUMES: ConfigFile is valid path and file name. ' CALLED FROM: ErgonOS.bas Main Program Section ' --------------------------------------------------------------- ' DESCRIPTION: This Sub takes the passed configuration file ' name, opens it and loads up the values into the ' appropriate User Defined Types so that they are ' available to the rest of the application. ' =============================================================== FUNCTION LoadConfiguration(ConfigFile AS STRING) AS INTEGER DIM ErrorMessage AS STRING DIM WorkLine AS STRING DIM WorkResult AS INTEGER DIM FileHandle AS INTEGER ' -------------------------------- ' Turn On Local Error Management ' -------------------------------- ON LOCAL ERROR GOTO ErrorManager ' ---------------------------------------------------- ' Get next available File handle and open ConfigFile ' ---------------------------------------------------- WorkResult = 0 FileHandle = FREEFILE OPEN ConfigFile FOR INPUT AS #FileHandle ' ----------------------------------------------- ' Skip Everything until we get to the a section ' ----------------------------------------------- DO WHILE WorkLine <> "[APPLICATION]" LINE INPUT #FileHandle, WorkLine LOOP ' ---------------------------------------------------- ' Next we load field values into the data structures ' Note that this is not implemented yet but this ' will be a series of Field assignement for all the ' fields of he Application and Environment Types ' based on values read from the file Here's a few ' examples so you know how I'll do it. ' ---------------------------------------------------- LINE INPUT #FileHandle, WorkLine Application.ScreenHeight = VAL(RIGHT$(WorkLine, LEN(WorkLine) - 30)) LINE INPUT #FileHandle, WorkLine Application.ScreenWidth = VAL(RIGHT$(WorkLine, LEN(WorkLine) - 30)) LINE INPUT #FileHandle, WorkLine Application.ColorDepth = VAL(RIGHT$(WorkLine, LEN(WorkLine) - 30)) ' -------------------------------------- ' Close the file and exit the function ' -------------------------------------- CLOSE #FileHandle OpenConfigurationFile = WorkResult EXIT FUNCTION ' -------------------------- ' Error Management Section ' -------------------------- ErrorManager: ' --------------------------------------- ' Create the full ErrorMessage Contents ' --------------------------------------- ErrorMessage = "Engine: ErgonOS" + CHR$(13) + _ "Module: ErgonOS.bas" + CHR$(13) + _ "Function: LoadConfiguration()" + CHR$(13) + _ "Parameters: (" + ConfigFile + ")" + CHR$(13) + _ "Error: " + STR$(Err) + ":" + Err$ ' -------------------------------------------------------- ' Depending on settings, either log or display the error ' -------------------------------------------------------- IF ErrorLogging = True THEN LogError(ErrorMessage) ELSE DisplayError(ErrorMessage) END IF END FUNCTION

You can notice here that when reading values I used "VAL(RIGHT$(WorkLine, LEN(WorkLine) - 30))" If you are familiar with windows INI files, I am using a similar structure. Because I am not loading it using the conventional Windows API functions (since I'm in DOS), I do not suffer from the 64Kb limit that windows INI file have. So the first 30 characters of any item I will be loading will be 30 characters. As such, I only need to get from the 31st character all the way to the end of the current line which is what the code does. I didn't implement all of the function yet but all you need to know is any field that will be retrieved from the file will use either "VAL(RIGHT$(WorkLine, LEN(WorkLine) - 30))" for numeric values or "RIGHT$(WorkLine, LEN(WorkLine) - 30)" for Character values.

The last sub I will be adding to the ErgonOSHelper.bas module is called SetupDefaultConfiguration(). It has no parameters and makes no assumption. It will simply fill in the different fields I've defined in the User Defined Types for the ApplicationType and the EnvironmentType (atleast for now, more values will be assigned as other engines are implemented in the course of this series).

' =============================================================== ' NAME: SetupDefaultConfiguration() ' PARAMETERS: None ' RETURNS: No valies ' ASSUMES: Nothing ' CALLED FROM: ErgonOS.bas Main Program Section ' --------------------------------------------------------------- ' DESCRIPTION: This Sub is called when the normal loading of a ' configuration file failed. It basically assigns ' default values into the necessary data ' structures to allow ErgonOS to boot in a normal ' mode if it can. ' =============================================================== SUB SetupDefaultConfiguration() ' --------------------------------------------- ' Setup the Application's default information ' --------------------------------------------- WITH Application .ScreenWidth = 800 .ScreenHeight = 600 .ColorDepth = 8 .ProjectVisible = 1 .ProjectWidth = 200 .ProjectHeight = 200 .RelatedVisible = 1 .RelatedWidth = 200 .RelatedHeight = 200 .SearchVisible = 1 .SearchWidth = 200 .SearchHeight = 200 .DocumentVisible = 1 .DocumentWidth = 600 .DocumentHeight = 400 .CommandVisible = 1 .CommandWidth = 600 .CommandHeight = 130 .ShortcutsVisible = 1 .ShortcutWidth = 600 .ShortcutHeight = 70 END WITH ' --------------------------------------------- ' Setup the Environment's default information ' --------------------------------------------- WITH Environment .DateSeperator = "/" .DateFormat = "MM/DD/CCYY" .TimeSeperator = ":" .TimeFormat = "HH:MM:SS" .DecimalSeperator = "." .ThousandSeperator = "," .CurrencySymbol = "$" .SystemPath = "C:\ErgonOS\" .DefaultProjectPath = "C:\ErgonOS\Projects\" .DefaultSearchPath = "C:\ErgonOS\Search\" .DefaultResourcePath = "C:\ErgonOS\Resources\" .DefaultDocumentPath = "C:\ErgonOS\Documents\" .DefaultToolsPath = "C:\ErgonOS\Tools\" END WITH END SUB ' --------------------------------------------------------- ' This #ENDIF closes to module inclusion check at the top ' --------------------------------------------------------- #ENDIF

We are now at the main ErgonOS module. We'll use ErgonOS.bas as it's name. Basically, this main module is only there to get things ready for the other main engines to set themselves at which point they take over control of the program. So then, to accomplish this, the first thing ErgonOS.bas needs to do is include the modules from the other engines that it will need. In this part of the series, we'll only need to include the ErgonOS main modules and the Shared modules where we actually included code. These are included like so:

' -------------------------------------- ' Module and Library Inclusion Section ' -------------------------------------- '$INCLUDE: 'SharedConstants.bi' '$INCLUDE: 'SharedUsertypes.bi' '$INCLUDE: 'ErgonOSConstants.bi' '$INCLUDE: 'ErgonOSHelper.bas'

This is the structure I'll be using for the include order. I'll always start with the Shared modules. then the modules named from the same engine the current file pertains to. Finally, under those, as needed, I'll include other related engine modules as needed. Once we have our extermal modules included, we now need a few global variables to hold what we'll be reading from the configuration file.

' ------------------------------------------- ' Globally available Variables declarations ' ------------------------------------------- DIM SHARED Application AS ApplicationType DIM SHARED Environment AS EnvironmentType DIM SHARED ConfigFile AS STRING DIM SHARED FileResult AS INTEGER

The next part of this module deals with the command line parameters, it makes use of the function we defined in ErgonOSHelper.bas to assure that nothing invalid was passed to the ErgonOS.exe file. This early in the startup sequence, all we need to check for is if we will be using an alternate configuration file or if we'll use the default. I will also add aa check here so that if a /E: parameter was supplied. This command file will be executed after the whole system boots up because we will expect to be in the GUI itself in order to execute that command file.

' ------------------------------------------------------ ' If there's any parameters, we'll validate them here. ' ------------------------------------------------------ IF COMMAND$ <> "" THEN ValidArguments = ValidateParameters() IF ValidArguments = 0 THEN ' --------------------------------------------- ' Test to see if a /C: parameter was supplied ' --------------------------------------------- IF UCASE$(LEFT$(COMMAND$(1), 3)) = "/C:" THEN ' -------------------------------------- ' Going to open the passed config file ' -------------------------------------- ConfigFile = RIGHT$(TRIM$(COMMAND$(1)), LEN(TRIM$(COMMAND$(1))) - 3) ELSE ' --------------------------------------- ' Going to open the default config file ' --------------------------------------- ConfigFile = "ErgonOS.cfg" END IF ' --------------------------------------------- ' Test to see if a /E: parameter was supplied ' --------------------------------------------- IF UCASE$(LEFT$(COMMAND$(1), 3)) = "/E:" THEN CanExecuteCommandFile = 1 END IF END IF END IF

So far it seems simple enough doesn't it? Basically, it's time, at this point, to start giving the user some feedback as to what is going on as the bigger processes and time takers will happen, when needed, starting from this point on. So let's start by displaying some general application information to the user so he/she knows that the right application was indeed executed.

' -------------------------------------------------------- ' We start printing some general information to the user ' -------------------------------------------------------- WIDTH 80, 50 CLS COLOR White, Black: PRINT ApplicationName; COLOR White, Black: PRINT " Version " + VersionStamp COLOR Yellow, Black: PRINT ProjectDescription COLOR Yellow, Black: PRINT "Brought to you by " + AuthorName COLOR LightCyan, Black: PRINT ProjectLicensing COLOR LightCyan, Black: PRINT ProjectCopyright

Note that I used strictly constant values here, not directly typed text. The main reason is that should you decide to follow my structure and organization for your own GUI projects, you can just change these constant values to your own names and values in the right module and this will simply display the new information. One of the things this coding technique allows is to create highly reusable code. And in as many cases as possible, I will be using techniques that allow for reusable code throughout the whole project. Since I'll plan on writing more projects, coding this way right now gives you a broad repertoire of reusable code that will really save you alot of time in your future development endeavours.

The rest of this module will continue to to give the user feedback as far as what is currently happening at the different phases of the startup sequence. Right now, there's only one step, we will simply load the configuration file by calling our LoadConfiguration() function that we defined above. This will also show you how to give simple but sufficient feedback to the user as far as what's happening and how things went.

' ------------------------------------------ ' We can now load the configuration file ' ------------------------------------------ COLOR Yellow, Black: PRINT "Loading Configuration File. "; FileResult = LoadConfiguration(ConfigFile) IF FileResult = 0 THEN ' ------------------------------------------ ' If there's no errors, we print "Success" ' ------------------------------------------ COLOR LightGreen, Black: PRINT "Success" ELSE ' -------------------------------------------- ' If there was error we setup default values ' -------------------------------------------- COLOR LightRed, Black: PRINT "Failed" COLOR Yellow, Black: PRINT "Creating Default Configuration" CALL SetupDefaultConfiguration() END IF

Color coded feedback is basically what I call this. Green for success red for failure. This is how I like to give straighforward feedback to the user. You can see that in the ELSE part of this IF statement I also tried an alternate approach to make the program work. Of course some parts of the startup sequence cannot have an alternate method like this but when it can, it's a good idea to implement one as it gives the whole system a certain feeling of stability and reliability. The key rule here is "If there's a way for it to work, it should be coded.". In other words, we can't assume that everything will go perfectly or the whole project will break as soon as something doesn't go perfectly. We need to assume that nothing will work and see what we can do, in each of the situations that could present itseif, to make sure that the program has a chance to work in some way. If you can remember this at the beginning of a project like this, it will definitaly influence you whole project for the better.

The next piece of code is just a series of comments for now. Since these parts will depend on things that are not implemented yet, these will only show you what will happen when they are implemented.

' ----------------------------------------------------------- ' 1. Acquire low level System Information (from LAHP) ' 2. Acquire list of storage media (from LAHP) ' 3. Acquire all available Screen Resolutions (from VADM) ' 4. Setup all default visible components (from EVRIL) ' 5. Set the screen into desired mode (from VADM) ' 6. Draw all components on screen (from EVRIL) ' 7. Go into Main ErgonOS Event Management Loop (from TEMS) ' -----------------------------------------------------------

Now after these are implemented and the GUI system itself is loaded and ready, we can go ahead and proceed to executing a Command File if one was specified as a command line parameter when executing ErgonOS.exe. Right now it's just a comment, but when our CAPS engine will be implemented, we will be calling the ExecuteCommandFile() function.

' ------------------------------------------------------- ' If a Command file to run was specified, we execute it ' ------------------------------------------------------- IF CanExecuteCommandFile = 1 THEN ' Later we'll call the code to execute a command file. END IF

As you can see, things are pretty straightforward and sequential up this point. This is basically the reason why it's called a startup sequence. Like I mentionned before, as these steps execute themselves, if there's a possible backup plan, we will be implementing them to give our system the most possible chances to be able to start itself up as properly as it can. For each of those situation, when they arrive, i'll explain to you what can cause is and if there is an alternate way to get things done.

FINALLY, PART 4 CONCLUDED:

And there you have it. It's been quite a chapter in the series hasn't it? Basically, I'm trying to keep things as clear as I can both in the tutorial itself as well as in the source code I present. This is why things are documented as they are and why I used clear names for everything I've coded so far. As I mentioned in part 3 of the series, I will be following these standards throughout the series, it should help keep everything as clear as possible which is the ultimate goal of the series. As always, you can always send me emails if you have questions about anything you've read so far in this series. We need to make sure that you can follow through in the next parts of the series and to be able to do so, things need to be clear.

In the next part of the series, we'll concentrate on L.A.H.P. (Low level Access to Hardware and Peripheral), the first of our major engines. We'll detail everything that LAHP needs to be aware of and everything it needs to acquire to make it available to the rest of the ErgonOS engines and modules. We'll see how integrating a new module can and will affect the other engines and modules already present in the project and we'll also see how and where we will be calling the LAHP functionality from the Central ErgonOS set of modules. Until then, happy reading, learning and understanding.


MystikShadows
Stéphane Richard
srichard@adaworld.com

Download a copy of this tutorial: GUISeriesNumber4.zip


Final Word

Well, that's it for another GREAT, SPLENDID, FABULOUS, FANTASTIC, AWESOME, MAGNIFICENT, EXCELLENT, DELIGHTFUL, and WONDERFUL issue of QB Express. Thanks for reading. Hopefully you enjoyed it as much as I did!

The deadline for QB Express #17 submissions is December 15, so make sure you write something spectacular and send it to me. (Send your submissions to pberg1@gmail.com.)

See you next month!

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.