QB Express
Issue #16 ~ November 26, 2005
"A magazine by the QB community, for the QB community!"
In This Issue
Contributors
- Pete (Editor)
- MystikShadows
- Lachie Dazdarian
- Rattrapmax6
- Matt2Jones
- mennonite
- Rick Clark
- Agamemnus
- Imortis Inglorian
- Simon Bradley
- Brandon Cornell
- Z!re
- Alec Elton
- Regular Columns
- Articles & Editorials
- Tutorials
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?
Site | Votes | Percent | Graph |
Phat Code (#8) | 6 | 14.3% | |
JacobPalm.dk (#9) | 10 | 24% | |
The Basic Network (#10) | 1 | 2.4% | |
QB45.com (#11) | 8 | 19% | |
Data Components (#12) | 4 | 9.5% | |
AAP Official Projects Squad (#13) | 5 | 12% | |
ASCII-World (#14) | 4 | 9.5% | |
Syn9's Hideout (#15) | 4 | 9.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.
- The game is in a mostly playable form.(still a little buggy)
- Graphics have been implemented,
- Damage, healing ,resistance and some detection spells work now(Parser works)
- Special items work now(potions and scrolls are gotten from the spell list so they are automatically added)
- Much larger levels.
- Slightly more intelligent monster combat.
- Visual effects(an arrow will travel down a hall, and a fireball will make a fireball)
- Editable Spells(read infospells.txt in the "doc" diretory)
- Editable Special Items Overlays
- Editable Items
- Editable Monster attacks
- Editable Monsters
- all in the "data" directory .txt files
- And prolly a lot of other stuff I can't think of right now.
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!
And here's Matt2Jones with a double-dose of BBY comics for you!
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.
- Source File Documentation:
When creating a source file, often, documentation of this source file is quickly neglected
usually because of lack of time, some think time is better spent actually coding the intended
purpose and say to themselves: "I'll document it when it works!". I myself often used that
technique as well because when there's no time there's no point. However, this project has
no deadlines. Like everyone else, I want my things done yesterday but this is suicidal on
a project this big. I'd rather wait (as impatient as I am), as long as it takes, to be sure
that what I get is both readable and understandable. As such I'll be making a special effort to
comply with the following standards.
- Module Level comments:
This is usually done at the beginning of a module, it should have the module name, project
to which it belongs, version number, creation date, author name, and other standard information
of this nature. It should also have a paragraph that explains it's purpose clearly. It could be
a sentence, sometimes a sentence is enough, other times more information is needed. Common sense
will play a role to determine how much information is needed. Right after this I leave a comment
section to add "things to do" so I don't lose track of thing or forget something that should have
been done. Finally, at the end of the module, I also like to have a history section, at the end of
the source module, so that I can track the work done.
- Procedure Level comments:
This is usually done at the beginning of a procedure or function. It should have
the name of the function or procedure, a list of parameters and their types and an indication on
whether a parameter is optional or defaulted to a value somehow. It should state what the function
returns, if any, what it assumes, what valid values are acceptable for parameters in the case of
dates for example, perhaps a date can't be earlier than a certain date. And a paragraph on the role
of the procedure or function.
- Source Level comments:
This is done just before a certain block of code within a procedure or function. usually one or two
sentences to explain the code to come when the developer knows it's a tricky part to understand. Again,
logic and common sense should guide this level of documentation, some code are clear enough as is, some
require some explanation.
And that's it, as far as commenting the code goes. Again these are suggestion, if you feel more than this should be
done, go right ahead and do it. But I believe that with this strict minimum of documentation that it will help everyone
involved, including yourself.
- Indentation and Spacing:
Indentation, to me, helps to clearly determine where a block of code begins and where it ends. For the number
of spaces to use, that's irrelevent, whatever the preference may be just as long as it's clear enough to visually
see the beginning and end of a language contruct. I believe at least 2 characters should be used, but aside that,
any indentation style is left up to the developer. Me I usually align to the next Item. like so:
IF ThisVariable = 1 THEN
CALL ThisSub
END IF
FOR Counter = 1 TO 10
CALL ThatSub
NEXT Counter
The main reason for this is that to me Aligning the CALL ThisSub under ThisVariable and ThatSub under Counter like I
did is visually cleaner in my opinion. That's just my opinion however and if I was to receive code that wasn't aligned
this way I wouldn't refuse it. Everyone has their own style of coding. Me I just happen to like it that way.
Usually indentation is used for Class definitions, If Then Else constructs, Loops, Procedure and Function declaration
and the rest of the code is then indented to the level where it should be to visually show that it is part of a given
construct. Many editors even have an Auto-Indent feature that can do a good job at indenting code for your in a more
than acceptable means. In other cases, most language have a "code beautifier" or code formatter program that can take
a source file and spruce it up visually speaking.
Common sense is really what it's all about here. If the code looks clear enough to understand then it should be perfect
just the way it is. It's all visual aids that help other understand the source file, so it should be used as a documentation
tool.
- Naming Conventions:
As far as naming conventions goes, well common sense and logic will play a very big role here as well.
When naming a source file, a procedure or function, a class definition or a variable, one has to think of others
that haven't seen the code yet. What can they say about the names you've chosen determines the quality of the
naming convention used.
- File Names:
When naming a source file, a form, a database, whatever the case may be, it's important to
keep the name of the file as clear as possible as far as it's intended purpose is concerned.
- Class Names:
Well a class is an object and therefore should be named according to how you would name any other
objects. If you are defining a class for animals for example, simply call it Animal, it needs to speak
for itself. Common sense should once again help.
- Procedure/Function Names:
A procedure or a function usually perform an action or a calculation, therefore, it is recommended that
the procedure or function name start with a verb stating that action followed by a name of what that action
is perform on. For example a function that would caculate the tax on a given amount should be called CalcTax or CalculateTax.
- Variable and DataType Names:
A variable stores information to be used later or elsewhere in the module or a given project (depending on their scope). A name, aside standard variable naming conventions (start with a letter, followed by numbers or other letters etc etc..) should
tell, by its name, what information it will store at the very least for the sake of clarity of code. A DataType
(User Defined Type that is) is a structure that will more than one piece of information It's name will need to represent the data it will hold clearly as well as end with Type to clearly see it's a TYPE definition. For example, CoordinateType. A variable
declared as that type will omit the Type ending. Hence <scope> Coordinate AS CoordinateType. Depending on the situation, an array of a given TYPE definition will be TypeNameList or the plural form of the TypeName. Finally, Global variables declaration
will start with Global and the name of the variable. Here's an example of all these:
TYPE WindowType
WindowNumber AS INTEGER
WindowTitle AS STRING
WindowTop AS INTEGER
WindowLeft AS INTEGER
WindowHeight AS INTEGER
WindowWidth AS INTEGER
ForeColor AS INTEGER
BackColor AS INTEGER
END TYPE
DIM Window AS WindowType
DIM WindowList() AS WindowType ' OR
DIM Windows() AS WindowType
DIM SHARED GlobalWindows() AS WindowType
Once again, with these coding standards in place, I think that the whole development effort will only be made easier
by trying to follow these as much as possible. There is no deadlines here, taking the time to comment and name things properly
will bring the quality of the project that much higher, in my belief. When you think of the thousands of lines we'll be dealing
with, having a standard coding style and naming convention like this really help you to know exactly where things belong as well as
and why they were named the way they were named. Now these are my standards, you could definitaly create your own that fits your
way of coding.
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).
- L.A.H.P. (Low level Access to Hardware and Peripheral)
This is a completely independant engine. This is basically a 2 level library that will give the developer (me so far in this case) a standard
system of acquiring low level information about the computer ErgonOS is currently running on. If you recall in the 2nd part of the series, the
two level are there so that I only need to change the 2nd level to adapt the library to work on any architecture.
- V.A.D.M. (Video Access Device Manager)
In a way, this could depend on LAHP to atleast know some basic information about the video card. But the dependance is so small that it can be
done more than one way. VADM will basically determine the text and graphics resolution that are available. Store them internally so that ErgonOS
can use them to offer the user the ability to change the screen resolution and color depth.
- O.S.S.I.S. (Operating System Services Interface System)
Each OS (Windows, Linux, DOS, BSD and others) have a very different way to offer access to the drives and other parts of the system hardware such as
RAM, serial and parallel ports and the likes. OSSIS will be an interface between ErgonOS OS calls and the OS functionality. Once LAHP and VADM are done
we can begin to use these through the OS itself. Since our first operating system is DOS. We'll be using interrupt calls like 10h for video, 21h for Disk
access and management, 33h for mouse etc etc. When we talk about OSSIS, later in the series, I'll detail all the different DOS interrupt there are and how
to make good use of them.
- A.S.D.A.M. (Architectural System for Digital Audio and Music)
This engine depends on OSSIS to realize itself. So it can know how to activate the sound card if needed (and if possible on the OS). Some sound cards still
work in DOS but the recent cards don't. So we'll just have to see what we can do about that (if anything) when we get to ASDAM.
- A.R.M.S. (Advanced Resource Management System)
This is, in essence, the memory manager system. ARMS will determine if a certain resource can be created or not (if there is enough memory to do so) and if there is
it will create the resource that is needed. When a resource needs to be removed ARMS will take care of that too. It will be designed to allow the creation of any type
of resources so it does not need to depend on anything else to get created except for OSSIS (to determine the memory capacity, swap file (if any is needed) and the likes.
Then, once it has determined that, it just gets itself ready to receive resource requests and process them in the order they are received.
- T.E.M.S. (Tasks and Events Management System)
This is a core engine. By that I mean that ErgonOS just isn't functional without TEMS being implemented. It will be responsible for
getting any and all events that are happening in ErgonOS (be it a system event or a user event), determine who created the event (which
document, which control, which dialog if a dialog is currenly being shown) is sending the event and then go about processing the event
accordingly. If there's any information to carry with a given event, it will be carried throughout the ErgonOS system on a global message
queue. TEMS is central and stacked at the same time. THis means that the while environment will use TEMS as well as each individual control
or document. So it doesn't really depend on anything as far as development goes but EVRIL will greatly depend on TEMS for obvious reasons
as well as the Task Scheduler (which is why I grouped the Tasks and Events together like this).
- C.A.P.S. (Command Acquisition and Processing System)
This engine by itself doesn't need anything else. It is basically a string parser that will
recognize a given set of commands and perform the action directed by the commands. The best time
to realize CAPS is at the same time as EVRIL (below). Since the main design goal of ErgonOS is to
allow everything that can be done from the GUI to be doable at the command and keyboard level. It
will be a good idea to keep CAPS and EVRIL in sync.
- E.V.R.I.L. (ErgonOS Visual Representation and Intelligent Layout)
This is what I decided to call the Visual side of ErgonOS. Atleast the visual drawing, resource creation for all the
components can be created. However to code any part of the user interaction side of things we'll need TEMS and ARMS to
be in working order before we can get to that part. The main reason is it would be a waste of time to create a temporary
mechanism of managing events and memory only to replace them with the functionality of ARMS and TEMS.
- E.A.G.L.E. (ErgonOS Application Generation Language and Environment)
This one is independant as well for the most part but only after the rest is done will we be able to really complete EAGLE.
We could, at any time define the language entirely, create a lexical analyzer and syntax checker of all the grammar involved
at any time but I chose to do it last to keep the language as independant as possible as far as OS and system architecture
are concerned, I'll obviously need LAHP, VADM, ASDAM, ARMS, TEMS and EVRIL to be done so I can use their functionality instead of
creating a second alternative to the same functionality. The compiler and linker (at the very least) will need to be done at the end
but the parser, lexical analyzer and syntax validator can be done anytime I want as they don't rely on any ErgonOS specific engine
to be able to do their job.
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.
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.
- To fully understand the diagram, you have to see it from a user's perspective. Basically, think of the user as sitting down in
front of his computer, he sees the screen layout, and begins to work on a document, the diagram explaines which engines is needed
while the user is performing whatever interaction he/she can do like mouse interaction or keyboard interaction (that's the User's computer
system defined at the top of the diagram
- The main reason why there are double sided arrows at each level of the diagram is because, indeed, at any point, things can be sent to
and/or received from the specified engine.
- The reason why E.V.R.I.L. and C.A.P.S. are at the same level is because, as I've mentionned before in the first part of the series, the command
prompt and the GUI itself both serve the same purpose, allow the exact same functionality (mouse or keyboard) and as such, they both have access
to the same engines for the same reasons as the other.
- Both E.V.R.I.L. and C.A.P.S. can also request a new document and/or a new view of an existing document at any given time, the work independantly of
each other as far as user interaction is concerned, however, once the command has been issued, or the mouse clicked on the GUI equivalent functionality
request, they will both perform the same tasks. For example, If you want to create a new HTML document you can either select the File menu then new with the mouse
or keyboard, or issue a "Create Document" command from the command prompt. Once you select New from the menu or press enter on the "Create Document" command
the exact same piece of code will be called.
- The reason why T.E.M.S. is on top of the Single View and Multiple View documents is because of the point of view. Indeed from the user's
perspective he's interacting with the document, not the GUI itself. From our perspective, T.E.M.S. is directly related to E.V.R.I.L. But to explain
the internal workings of the engines, I chose the user's perspective as it often is the clearest view on things.
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.