QB Source gets updated again
After a long period of no updates, QBsource.com is finally once again updated. Though the new site is not finished yet, you can already have a look on their new design.
![]() |
New Qb Top 100 With the return of QBasicnews.com, another topsites-list came alive! The QB Top 100 can be found by clicking on the button. |
QuickBasic.net is working on a comeback
Another site that hasn't been worth visiting the last months because nothing new has happened...Guess what, the webmaster is working on a comeback! We have seen a preview, and it looks promising, though a lot still needs to be done...
A new QB RPG site: qbrpgs.com
HyperRealistic Games comes with a new site, dedicated to RPGs and RPGs only.
Another QB topsites list hits the net
This topsites list is about QB sites related to QB RPGs, and is part of QBRPGs.COM. So far not many sites have signed up, so get yours in NOW!
Future Software gets rid of frames
The QB page of Future Software has been redesigned. For the first time in 3 years, the site no longer uses frames, but tables instead. Be sure to take a look!
Changes at Future Software
Qb45.com is now having a second webmaster. As Webmaster Jorden says: "I was getting tired of updating the site...Usually I get 50 files weekly, which I all try out which takes a couple of minutes. I end up adding 5 new files on average...I don't want QBasic to die, and I think that as long as QB45.com stays alive, Qbasic won't. That's why I gave Frank Korma(FK) the password to the server, and an email address which you can send him files on. Now I can concentrate more on school and my other sites. I've added more than 1000 files for the site, I think it's enough now =)"
Hopefully, the new webmaster will update the site often, so new source will be available all the time!
BUT...there are more changes!!! Stefan Hendriks, the author of Arrakis, has quit the team since he's not programming anymore. There also is a new member, Eric Cowles, who will program for the team.
QB45.COM problems
You've probably noticed it: the qb45.com domain has a lot of problems lately. The first was that the server was down occaisonally. The second was that a hacker managed to break into the domain and delete 180MB of Future Software's files. We're trying to fix the problems but it's hard because we (Nightwolf & Jorden) live in Holland and the owner of the server in the US and there is a huge time difference meaning we have to stay up real late to talk to him. Anyway, we'll try to fix it ASAP!
The sequel to AlfaFLA 2, the GUI for the Future.Library, is close to being finished. AlfaFLA 3 will be available soon. This version features less bugs, an external programming language based on Everos, and will generally have more features.
The BXNes project was cancelled, due to lack of speed in QB. The author, Big B (Bram Bouwmans), will continue his work in C++. However, he has been nice enough to give the sourcecode of the emulator to the QB Times...fully documentated! The article on QB Times can be found elsewhere in this issue of the QB Times, so check it out now!
MasterCreating has released a trailer of IMERION, their latest project. The download is quite big, but it's worth the wait, and the server is quite fast! The trailer shows a little about the game, in 800*600 resolution with sounds. The trailer (and the game) uses the Future.Library.
You thought you had seen the last thing about Wetspot by Angelo Mottola? Think again, because Angelo is working on a Gameboy Color version about the adventures of Coby and Cuby! For a screenshot of the GBC game in action, click here!
DarkAges I is under reconstruction...As DaeBreaker tells:
"All graphics are drawn by DaeBreaker except the sprites which will be drawn by Elemental. The gameplay will most likely be like the classic DA1, but with little changes. Like instead of starting in the outside world, he starts in a town with a house. Little sub quests will also be added. The engine is being recoded right now, making the code more efficient by adding the ability to switch between EMS and BASE memory(we are using DQB) and also adding XMS for sprites and tiles (FUTURE.LIBRARIES XMS routines). Blendermaps are also used to create amazing effects, like reflections of the character sprites on the water and transparent smoke, also allowing ghost. There is also realistic weather effects now, with temperature which is able to change how the weather is. We also made use of DS4QB made by Nekrophidius, before we used BWSB but it sucked up to much memory making us not able to use blender maps. An extremely advanced scripting engine is also being coded, it allows variables and many of QB's commands. A real time battle engine was going to be coded, but Michael Hoopmann didn't want to much changes to the previous DA1 so he told me to do one like the WOS battle engine."
The visitors of the QB Expo were hit by a big surprise: a demo of Untitled, the RPG of Tsugumo and FrozenEmu, has been released!!! Click here to visit the QB Expo page of Untitled!
Topic | Rating | Description |
Content | 28 / 30 | Well this site is updated weekly and is filled with articles and reviews of qbasic games. Right now they have about 70 I think. Im not really sure, I never counted. They clain to be the only 100% qbasic game review magazine which I think they accomplished! |
Programs | 18 / 20 | Well about a 50 downloads but each is reviewed with screen shots and descriptions so they get a higher score! |
Links | 7 / 20 | This is where the site can really improve. This is the only problem I seemed to find. The links are all in one straight line and really had to read by the way he has it. Also no descriptions. |
Design | 14 / 20 | The design of this site ain't really bad compared to many qbasic sites with just simple text links in a frame which really drives me nuts! This ones nice blue and red! |
Unique | 10 / 10 | This site is the only 100% qbasic game review magazine =) |
Welcome back! This is part three of the 3D modelling tutorial series. In this tutorial, we'll be covering some more advanced 3D modeling concepts, and learning how to use Bryce 3D. If you haven't read the previous two tutorials, I suggest you do so, as this tutorial follows from the knowledge gained in the previous two tutorials. Without further ado, I shall begin by opening Bryce. Bryce is a rather unknown program. It is used quite a bit for home use, and you can usually see it on store shelves. More "Professional" software is usually not found at a local computer store - you have to order it online, or go to some sort of huge megastore to find it. Generally, the people going to a computer store don't have $8000 in cash with which to pay for their purchase of SoftImage 3D. But getting back to Bryce, although it is small, cheap, and user friendly, it is very powerful as well! It is definitly the number one program for creating landscapes and natural surroundings. Nothing matches it in that aspect. It also has an excellent raytracer. What makes it great, however, is that it is incredibly easy and quick to use. First, you'll need to know how to use the Bryce interface. You already know what a lot of the Bryce tools do - since they are similar to the tools covered in Part 2 of the 3D series, when we were working with Extreme 3D. So it is important to first know how to use the interface. You have, basically, two main bars. The top bar and the sidebar on the left. The top bar is where you access all your tools. The sidebar is where you adjust all of your camera angles and settings, and where you adjust render quality settings and other general program settings. This large screenshot shows you some of the basic features of Bryce's interface. (The scene that is currently loaded in this screenshot is a brand new Zeta Level)
As you can see, it is pretty easy to identify how to use the interface. Next, we'll look at the different controls, and what they do. There are three types of controls: Create, Edit, and Sky & Fog conrols. Create controls create a variety of objects to put in your scene. Edit edits, deforms, and manipulates these objects. Sky/Fog controls the settings for the sky. This includes how high up the clouds are, what kind of stars/moon/sun will be showing, how much fog there is, what density, how high, etc. Bryce is geared heavily towards creating very realistic natural scenes. Let's take a look at what the controls look like.
The top bar is the Create controls bar. From left to right, the controls are: create water plane, create sky plane, create land plane, create terrain, create rock, create lattice, create sphere, create tall sphere, create flat sphere, create torus, create long cylinder, create tall cylinder, create horizontally flattened cylinder, create vertically flattened cylinder, create cube, create long cube, create tall cube, create pyramid, create short pyramid, create tall pyramid, create cone, create horizontally flattened cone, create tall cone, create horizontal flat circle, create vertical flat circle, create 2D object, create horizontal flat square, create vertical flat square, create ambient light, create round spotlight, create square spotlight, create box light. Phew!!! That is a lot of tools. Basically, through various combinations of all of these tools, you can create a lot of stuff.
The second bar is the Edit controls bar. The first tool, which looks like a block with a piece cut out, is the texture controls. In Part four of this series, we'll be exploring the use of textures. For now, you won't need this tool. The second tool is the resize tool, which is very useful. Simply drag on the handle you want, or click and drag the center box. The item(s) currently selected will be resized. The next tool is the rotate tool. As with the resize tool, you click on the circle which represents the direction you want to rotate in, click, and drag. The next tool is the move tool, another essential. This lets you position objects in your scene with precision. Again, just click and drag on whichever direction you want to move the object(s) in. The next tool is not used much - it is the align tool, and it used to align objects. The next tool is very useful, especially in animation. It is the random motion tool. Select a group of objects, and click the little arrow next to this tool. A list of possible transformations will appear. If you choose, for example, 3D disperse/rotate, and then click and drag the blue dot above this tool, all objects you have selected will be randomly rotated and moved outwards. This is great for scattering debris after an explosion. The final tool is the Edit tool. It is used to edit the shape of mountains, or to change settings on some objects - lights for example.
The bottom bar is the Sky & Fog bar. You don't really need to worry about this at the moment. more about skies and fog will come in later tutorials.
That's covered the basic use of Bryce. Now it is time to get into more 3D modeling! We'll start off by using one of the most useful tools in Bryce - the Terrain Tool. Create a terrain. Now, go to the edit bar and click on the Edit control. Another way to do this is to click on the little "E" next to your terrain. A window will pop up. In the upper left corner, you can see various editing tools. In the upper right is a grayscale top-view of your terrain. In the lower left is a preview. You can edit your terrain by just painting onto the grayscale image. Use the "Hard" brush setting right next to the grayscale editing window to control how hard your brush is - whether it leaves behind a gradient of color, or paints a single color. The flow control sets how much paint flows out - how much color you put down. Once you've finished editing, press the check mark, and your terrain will be changed. Terrains are incredible useful, as you can paint all sorts of things with them. You aren't limited to mountains.
The next major thing to be covered in this tutorial is Boolean Objects. Boolean logic is AND,OR, NOT, etc. A boolean object is basically where you take, say, a cube, and then cut a cylinder out of it. You can carve things out of other objects this way. We'll start off with a cube. Next, we'll switch to top view, so we can see all of this better. The next thing to do is create a cylinder. Then we'll switch to front view. As you can see, the cylinder isn't tall enough. Use the Resize control in the edit bar to make it taller. The next thing to do is set which object gets cut out. To do this, click on the little A next to the cylinder. There is a control that is set to "neutral". Change it to "negative". Press the check mark, and then select the cube and do the same. However, make the cube "positive". Now, select both objects, and press the G next to them to Group them together. The cylinder will now be cut out of the cube. You can create all sorts of incredible effects with this.
Although this may have seemed like a short tutorial, you learned two very important things - how to use terrains, and how to use Boolean objects. The last thing in this tutorial will be a few images of a scene from Zeta. This scene uses only objects from the Create menu, and it uses some major boolean objects. You haven't learned how to use textures yet, but right now, you could create this scene.
The next tutorial will cover aspects of texturing objects, and making your scenes look realistic. By the time you've read the next tutorial, you'll have all the skills to create the scene above.
Part 4 of the 3D Artwork Series will cover such concepts as giving an object a certain color or texture, and texture mapping images onto objects. Again, it is highly recommended that you have read the previous 3 articles before reading this one. Article three covered briefly the Bryce interface. Hopefully, you've experimented a bit with Bryce, and you should be pretty familiar with its interface. Most buttons or controls are pretty self-evident.
We'll begin by creating some basic objects so that we can see how texturing works. Here I've created a cone, a sphere, and a cube. Now, select the cube, and click on the little M next to it. A window will pop up. This is the material menu. Here is where you set how your object looks like. At the moment, everything is set to default - flat grey. In the main part of the screen you'll see assorted controls. There should be controls called Diffusion, Ambience, and Specularity. These are the three main controls. Diffusion controls what kind of light the object bounces off - and therefore, what color the object is. Ambience controls what color the object gives off without any light present. This will also affect the color of your object, since there is never 100% light in the scene. Specularity controls the shininess of the object. A high specularity makes an object look like plastic. There are two sets of controls for each of these. The topmost set is the color control. You'll notice the ovals next to diffuse, ambient, and specular. Clicking and holding down on these will bring up a color gradient. You can select whatever color you want. The middle set of conrols affects how MUCH diffusion, ambience, or specularity the object has. Let's try giving the cube that is selected a blue color. Right now, diffusion is at maximum, and there is a little bit of ambience. Notice that the diffusion color is set to gray, which is why the object is gray. Click on the oval next to diffusion and make it blue. Press ok, and you should see that the cube is now blue.
Now, select your sphere. We'll play around with specularity here. Click the M to get to the materials menu. At the moment, specularity is set ot 0. Move the slider bar to the left of the word "Specularity" outwards, until you have a value of about 75. As you can see from the preview image, the object now looks shiny, and does indeed look like some sort of gray plastic. Click the check mark to apply your settings to the sphere. Now, select the cone. We'll use it to play around with some more settings. Again, click the M to enter the materials menu. Now, look at the very bottom of the set of controls. You'll see two controls that are called Transparency and Reflection. These are fairly self-evident. One makes the cone transparent, while the other makes it reflective. Lets play around with these a bit. When you're done, click the check mark, and return to your scene. Render it to see how it has turned out.
As you can see, the cone can be made reflective like a metal, or see through like glass. Using all these controls together, quite a large number of textures can be created.
However, just solid colors aren't really good enough. For that reason, we'll take a look at the texture presets. Texture presets are lots of textures that come with Bryce. They can be useful on their own, but more importantly, they can provide a base for creating a huge number of other textures. To access the presets, click the small arrow to the right of the preview window.
As you can see, there are lots of preset textures. Go ahead and explore all of them. You can use them for whatever you want. Select a texture, and then play around with the reflection or transparency to create a new texture. Especially useful in the presets are the glass and water presets. With these, you can create far more realistic glass and water effects than you could by just using a regular material that you created yourself. You can modify, for example, the diffusion on a glass preset texture to get colored glass. As you can imagine, the possibilities are endless.
Once you've finished playing around with textures, create a new scene. In the middle of the scene, create a cube. The last major texture effect that we'll be looking at is texture mapping - the most useful tool by far. Click on the M to enter the materials menu. Now, open up a paint program. I'll be using photoshop, but this works perfectly well with any program - even MS Paint, for those of you who don't have anything else. Create a new document in your paint program - say 300X300 pixels. Now, paint something. It could be a logo of some kind, or whatever you want. Save your image as a BMP. If you have Photoshop, it is important to note that if you have transparency in your image, you can save as a PSD. Bryce will load this up, and your transparency will work in Bryce as well. Now, go back into Bryce. You'll have noticed that there are four collumns of dots running down the control menu. Click on the dot immediately to the right of the Diffusion Color setting. A box will open up to the right with a texture in it. This is a default texture at the moment. We want our image to appear on the side of the cube.
Right under the three little images side by side, there are two buttons one has a T on it, the other has a P. Click on the P. This will set the texture to work with an image. Now, click on the pinkish button right above to get to the image loading menu. You should see three images side by side. Above each is a little button that says Load. Click the load button on the right-most image. Load up your image.
Press the check mark to get back to the materials menu. The image will look slightly faded. That is because the Ambience setting is set up a little, and it is making the image look whiter. Set ambience to 0, and click on the check mark to apply your changes. The image will now be applied! It is in fact that easy! That's why I like Bryce so much - to do this on another program would be somewhat more difficult. You can apply images to all sorts of objects. The most important thing with 3D graphics is that you play around with them. Practice makes perfect.
As usual, at the end is an example of some stuff I've done with textures. This is another image from Zeta - the very first draft of the largest ship in the game - the BattleCruiser. This is the most powerful ship you'll be allowed to pilot in Zeta, but it is rather slow and bulky.
That concludes this tutorial! Stay alert for the next article in the 3D Graphics series. And, of course, if you have any sort of 3D program, keep on working and practicing. That's the only way you'll get better.
Game Design
in the Future.Library
Tutorial
#1: Sprite Management (inc. example)
Welcome to Tutorial #1: Sprite Management. As so many of you seem to ask others on what you should use to create a game, and other people reply "go for DirectQB" or "use QB by itself", I've decided to let y'all in on a little secret... the Future.Library is one of the best library's for Sprite Management! Yep, that's right, and if you give any advice to anybody else on this, tell them to send all the money to me!! Muuhaahaahaa... }:)
Okay, well, Sprite Management seems to be what people would look at and scream out "I want my mummy", but it's not that bad! And because people either can't or just plainly do not want to build a good sprite management system, all of the ones out there are really awful to use... (seriously, don't sue me!) Well anyways, all you need to know is the theory of it all, and then you're away... Because of an awful bug in the Future.Library that I found, I have to resort to a mixture of EMS & XMS in my programs - making them run slower... but either way, they run faster than any DirectQB programs I've seen. So, read on... (download the Future.Library 3.5 before continuing, okay?!)
EMS is great for storing images, and when you have an image stored, you can edit it just like you would with a normal screen... this could be used as a refresh component, rather than flipping between pages (much too slow for a game with sprites!), you could just make an EMS image, draw on to the image, then paste the EMS image on to the main screen - meaning that you've just refreshed a small area rather than an enormous one... this allows you to focus your computer's processing power on to what you want done; and believe me, the speed increment is vastly noticeable!
So, you can choose an area for refreshing now. So try it out...
...Copy...
'/* Sprite Management (QBTimes) */
'/* Example 1 */
'
'$INCLUDE: 'future.bi'
Set 320x200 8
'/* Set the area you want
re-drawn... */
X% = 50 : ' X position
Y% = 50 : ' Y position
W% = 100 : ' Width
H% = 80 : ' Height
'/* Make an EMS image the
width & height of the area for redrawing... */
EMS% = AllExpMem(INT(W%) * INT(H%))
'/* Set the EMS image to
EMSPage 0, and draw the area on to it... */
DefineEMSbufferSize EMS%, W%, H%, 0
SetEMSpage 0
Future.Fillbox 0, 0, W%, H%, 4
SetPage 0
'/* Paste down the re-drawn
area */
Future.EMSput X%, Y%, EMS%
'/* Remove the EMS image
from memory and exit. */
DeallExpMem EMS%
END
That example will refresh any area into a red colour, just try it and see. The only prob is, the Future.Library has a bug with putting EMS images on to EMS pages... hence, this is why you'll have to mix EMS & XMS!! So, whatcha do is, you store all of your sprites in XMS. Like this:
...Don't copy...
MySprite% = AllocateXMS(10 * 10)
Future.Fillbox 0, 0, 10, 10, 2
Future.XMSget 0, 0, 10, 10
Yep, that's all you have to do to store an XMS sprite! So... we now have to elements, EMS refresh and XMS sprites. So, all you need to do is paste all of your XMS sprites on to the EMS image, and then paste the EMS image on to the main screen! It's as simple as that, and if you need a good example of it all then click here to download my source code... (feel free to use it too)
Next tutorial (#2), learn how to give those sprites some extra features like rotation, set controls (keyboard, mouse etc.), and how to keep your source code so tidy that not even a baby could get lost in it!
This article was written by Steven Collison @ AlfawareWe'll continue this series in the middle of chapter 2. For the first chapter and the first part of chapter 2 read issue #9 of the QB Times.
CHAPTER 2: THE STORY (Continued)
We'll talk about another important aspect of story writing now, the characters! The most important character in the whole story is the main character, the one the player will control. The player has to share the feelings of the main character, like when the main character is sad (because his girlfriend died) the player also feels kind of sorry for him. A very good example of sympathizing with a character is when the boy in Secret of Mana gets banished from his village, the music, the dialogue ... *sniff* It made it very sad... *sniff* I almost got tears in my eyes when I saw it...
Anyway, I just said another important thing when writing stories! To give the right feeling to the player you should carefully think about which music you want to have with the story because it sets the theme. It intensifies what happens in the story. Let's take my example from Secret of Mana, the boy gets banished from the village. Without the music the player might get angry: "What?!? Are you banishing me? You old fool! I don't even want to stay in this crappy village anymore!" But now that you have the sad music you feel sorry for the guy and that is exactly what the storywriter wanted! And what you want to happen when people play your RPG!
OK, now that's out of the way let's talk about characters. What you basically need is a good guy (hero) and a bad guy. You can have more good guys than one, like in Final Fantasy you usually have a party of characters you can chose. When designing characters you need to think about are they male or female, how they're gonna look (tough, sneaky, old, young), what kind of character they are (fighter, rogue, magician), what kind of weapons they use (fighter uses swords, axes etc., rogue uses bow, maybe a whip or so, magician uses staffs and daggers), are they able to use magic and how much? Also try to let the character have its own mind; is he/she cowardly and would rather run away in a fight (think of the twists in your story you can have with this! The hero encounters the bad guy when he does expect it and runs away... While a heroic character would stand and fight) or make him/her heroic... Or make him/her a thief, who robs people to get money and breaks into houses. You also could give the player the option of being heroic or being a criminal. When he robs houses and people his social standing would get lower which means people don't want to help him, shopkeepers keep their shops closed to him, etc.
The bad guy is also fun to create because you can make him as cruel as you want (Kefka from Final Fantasy 3, he really is BAD!). You can make him burn down some villages and have the villagers be put into slavery. What's also a nice thing to do is to give the bad guy some charming features (like Darken Rahl in the book Wizards First Rule by Terry Goodkind, if you read the book you know what I mean) so that he isn't the ultra bad guy, which is in my opinion kind of unoriginal because in every RPG the bad guy is ultra bad. Another nice thing you can do with bad guys is that they were good guys once but turned bad when they were seduced by power and/or money (Whoopie! Prequel story! Now you can make a prequel to your game with the story how the bad guy became bad!). Also you can make the bad guy very strong or very weak. If he's strong he has lots of magic (if it's in your game of course) and very good strength etc. But when he's very weak he has lots of strong bodyguards and when you finally meet him face to face he whimpers and jumps of a cliff (or something). Basically, let the bad guy do some cruel things but don't overdo it and make him have a cool feature (Kefkas laugh was hilarious!).
Now you know how to write an interesting story we'll talk about what you can and cannot do in a story. Of course you can't do obvious things that aren't right like your hero killing the bad guy at their very first encounter. Not only is this highly unlikely (because the bad guy is much more powerful) it also destroys the game because all of a sudden there is no bad guy to fight anymore. But things like things are obvious so I'll start talking about the more subtle things.
A common used twist in RPGs is that of one of the bad guys minions turning over to the hero (General Leo in Final Fantasy 3). You can't just say "Oh, I don't like my master anymore I like you better so I'll just turn over to you." There needs to be a good reason why the person turns over. You need to give the minion a good reason to turn over. This could be for instance that the bad guy used him to raid a village and capture all the villagers. The minion does this and when he's finished the bad guy no longer needs him so he puts him in prison, where he meets the hero who has been captured just before. The minion feels betrayed and the hero and he escape together, the minion joining the hero because he wants revenge.
The minion has a good reason to join the hero now. Also something you shouldn't do is make the hero too strong at the beginning of the game. Let him be a little weak and not able to defeat every boss he comes a cross without training (level building) first. Have him to learn some magic and weapon skills before letting him fight the boss (a very drastic way of doing this is when the hero tries to enter the boss' lair have him say something like: "Oh no! I don't have a death wish!" and walk away).
Another thing you shouldn't do in a story is make things predictable. A story that is predictable is very boring and dull. Lot's of twists and turns in the story make it interesting. Let me give an example of a predictable story: The hero has just helped the king to save his daughter (or something similar) and the king has promised the hero that he could marry his daughter. The hero brings back the daughter and marries here and they live happily ever after and don't worry about the bad guy anymore. Nice story, huh? No wait! That's predictable boring and cliché. To make it interesting you can do the following thing: The hero brings back the kings daughter but instead of letting the hero marry her the king throws the hero in his dungeon. The hero tries to escape the dungeon but fails. He doesn't know what to do so he just sits down a little bit. But then in the middle of the night the guard is suddenly shot by an arrow and a cloaked figure comes into play and opens the dungeon. The cloaked figure and the hero escape the castle fighting of guards and running over the walls. When they finally reach a save plays the cloaked figure removes his cloak and (Tada) it's the princess! The princess doesn't agree with her father and promises to help you defeat the bad guy in return for saving her.
OK, OK, it isn't the most original story, I know. But it's more interesting than the first story. One last thing, do not and I repeat do not overdo things. It's okay to overdo things a little bit but, please, do not overdo things too much as it makes playing a game (in my opinion) very frustrating.
When writing a story remember the following things:
Heh, this chapter turned out to be pretty long but I think I have said all I wanted to say now. Let's go on to the next one: The Tile Editor!
And that's it for this issue! In the next issue we'll probably cover Chapter 3 and maybe Chapter 4, which is about the Map/Trigger editor.
Hello fellow QB programmers. This tutorial will give you a start to programming routines for the Extended Memory Specification, or XMS. Please note that this is for advanced QB programmers only! I also expect you know some basic assembly. If not than I would suggest not reading this. Don't say I didn't warn you! =) Now that that's out of the way, I can begin.
Is your game, utility, or whatever running out of memory? Do you get all red in the face when QuickBASIC stops your program and displays the "Out of memory" error? If so then XMS is for you. XMS gives you huge amounts of memory which is limited by your computers RAM. This will usually be enough for most QB programs. (In fact I would say all QB programs.) "Great," you say "So how do I use it then?" Well first you need to find out if your computer has XMS. (I feel sorry for you if it doesn't.) This is determined via interrupt 2Fh. The following example routine will check if it exists, initialize it for use, AND return the version installed:
XMSInit PROC mov ax,4300h ;This function lets us detect XMS int 2Fh ;Use interrupt 2Fh. cmp al,80h ;If AL isn't 80h then XMS is not present! jne NoXMS mov ax,4310h ;Since XMS is present lets get the version number int 2Fh ;and the address of the control function. mov word ptr [XMSControl],bx ;XMSControl must be a DWORD. mov word ptr [XMSControl+2],es xor ax,ax ;Now run function 00h which returns the version. call [XMSControl] ;Call the XMS Control function. ret NoXMS: mov ax,-1 ;If there's no XMS driver we return a -1 to QB. ret ENDP XMSInit
If you found that confusing the read the comments carefully. There's a funny thing about the version number returned. If you try to print it, it won't be the right number. Use this code to fix that:
XMSversion$ = str$(version% / &H100)+"."+str$(version% AND &HFF)
That will return the version as a string. version% would be the number returned by the above function. If you don't have version 3.0 or later than these functions I'm showing you might not work.
Now wouldn't you like to know how much memory is available to you? Well there's a function for that. Function 08h. It returns the largest free block in kb into AX, and the total free memory in kb into DX. Here's an example routine:
XMSInfo PROC freemem:WORD, totalmem:WORD mov ah,08h ;Use function 08h call [XMSApi] ;Call the API mov bx,totalmem ;Put the value in DX in totalmem. mov [bx],dx mov bx,freemem ;Put the value of AX in freemem mov [bx],ax ret ENDP XMSInfo
That will return the available memory in freemem and the total memory in totalmem. One thing about the above routine, it won't show an amount greater than 64MB. There is a function which will but I'm not showing you it now. I want you first to understand how it all works. Next issue you'll see. =P
Ok now, to actually use XMS you have to allocate a block of it. That is, you have to tell the computer that you want x amount of XMS for use in your program. We can do that via function 09h. With this routine it is not possible to allocate over 64MB or memory. There is a routine for it but I'll show you it next issue. Before you call the routine you have to have the amount of kb you want to allocate in DX. After you call it AX will be 0001h if it was successful. If not 0000h is returned. DX will also return the 16-bit handle of the allocated block. "Handle? What the heck!?" The handle you get is your "password" to accessing the block of memory. So when you allocate memory make sure that you keep the handle! There is no way to get it back and worse, you can't deallocate the block without it! Basically without it, you're screwed. So before I get ahead of myself, here's an example routine to allocate a block:
XMSAlloc PROC kb:WORD mov ah,09h ;Use function 09h mov dx,kb ;Move kb into DX. call [XMSApi] ;Call the API cmp ax,0001h ;Is AX = 0001h? If it is then it worked! jne AllocErr ;If it isn't then . . . too bad! =P mov ax,dx ;Move the handle into AX so its returned. ret AllocErr: ;Since we can't get a handle if it didn't work we don't ret ;want DX to get into AX. ENDP XMSAlloc
There ya go! That will allocate up to 64MB. So lets find out how to deallocate a block of memory.
Deallocating isn't that hard. It basically works the same way. We need to make use of function 0Ah for it. DX must hold the handle of the allocated block to be freed up. After called AX will have 0001h in it if successful. If not the its 0000h. Here's the code:
XMSDeAlloc PROC handle:WORD mov ah,0Ah ;Use function 0Ah mov bx,handle ;Put the handle into DX mov dx,[bx] call [XMSApi] ;Call the API ret ENDP XMSDeAlloc
Pretty simple ain't it? Now if used as a function it'll return 0001h if successful.
Now you've probably asked yourself: "How do I know what error occurs?" Well every XMS function will return an error code into BL if an error happened. There's quite a few error codes so I'll put 'em in a nice table for you all to see!
80h | Function not implemented | 92h | DX less than /HMAMIN= parameter | A4h | SOffset is invalid | ABh | Block is locked |
81h | VDISK device detected | 93h | HMA not allocated | A5h | DHandle is invalid | ACh | Block lock count overflow |
82h | A20 error occured | 94h | A20 line still enabled | A6h | DOffset is invalid | ADh | Lock failed |
8Eh | General driver error occured | A0h | All XMS allocated | A7h | Len is invalid | B0h | Smaller UMB is available |
8Fh | Unrecoverable driver error occured | A1h | All available XMS handles in use | A8h | Move has an invalid overlap | B1h | No UMBs are available |
90h | HMA does not exist | A2h | Handle is invalid | A9h | A parity error occurs | B2h | UMB segment number is invalid |
91h | HMA already in use | A3h | SHandle is invalid | AAh | Block is not locked |
Some of those errors won't apply here so you can ignore them. (Like the ones dealing with the A20 line.) What you could do is make the routine check if an error occured and then it could return that to QB. Although you don't have to.
Alright, now comes moving between XMS and QB. To do this you have to define a data structure at the beginning of your assembly source file like the one below:
MoveXMS struc ;Our main XMS data structure Len dd ? ;number of bytes to transfer SHandle dw ? ;handle of the source block SOffset dd ? ;offset into the source block DHandle dw ? ;handle of the destination block DOffset dd ? ;offset into the destination block MoveXMS ends XMSmove MoveXMS ? ;This makes it so we can use it =)
Using this structure we'll be able to specify what variable you want to move from QB to XMS and vice-versa. The best way to explain this I think is with an example. This sample routine will let you move data from QB to XMS:
XMSPut proc handle:WORD, segm:WORD, offs:WORD, bytes:DWORD, XMSoffs:DWORD mov eax,bytes ;Get the length of the data to move into Len mov XMSmove.Len,eax mov XMSmove.SHandle,0000h ;SHandle must be set to 0000h to move TO XMS. mov bx,offs ;Now we move the offset of the variable to SOffset. mov word ptr [XMSmove.SOffset],bx mov bx,segm ;Then the segment goes to SOffset+2 mov word ptr [XMSmove.SOffset+2],bx mov bx,handle ;Now we must move the destination handle. This is the mov XMSmove.DHandle,bx ;handle which we're moving the data to. mov eax,XMSoffs ;This is the location in the specified handle to move mov XMSmove.DOffset,eax ;the data to. mov si,Offset XMSmove ;Now we get the offset address of the data structure into SI mov ah,0bh ;And make sure that we call function 0Bh call [XMSApi] ;Now call the XMS driver to move the data. ret endp XMSPut
There. That will correctly move data from a variable, array, whatever in QB to the specified XMS handle. DON'T use this function unless you've allocated a block! If the move was successful AX will return 0001h or else it returns 0000h. I would make this routine a function so that you can tell from QB if it was successful or not. If that was too complicated for you than just go over it again slowly until you get it. Now, how do we move data from XMS to a variable in QB? Well we really only have to change a little bit of the above code:
XMSGet proc handle:WORD, segm:WORD, offs:WORD, bytes:DWORD, XMSoffs:DWORD mov eax,bytes ;Get the length to move into Len. mov XMSmove.Len,eax mov bx,handle ;Get the handle of the XMS block with the wanted data into mov XMSmove.SHandle,bx ;SHandle as XMS is now the source. mov eax,XMSoffs ;Also get the offset into the handle into SOffset. mov XMSmove.SOffset,eax mov XMSmove.DHandle,0000h ;DHandle must be 0000h so that we can pass the segment and ;offset of a QB variable to DOffset. mov bx,offs ;Get the offset of the QB variable. mov word ptr [XMSmove.DOffset],bx mov bx,segm ;And the segment. mov word ptr [XMSmove.DOffset+2],bx mov si, Offset XMSmove ;Now get the offset of the data structure into SI. mov ah,0bh ;Use function 0Bh call [XMSApi] ;Call the API! ret endp XMSGet
That will return the same as the other function into AX depending on what happened. As you probably saw we just used function 0Bh like before just we switched some things around. Not that hard, eh? Now all that's left for me to show you this issue is how to Reallocate a XMS block. This is handy if you need more memory for your game or something, I really don't know =). To reallocate a block you call subfunction 0Fh. Heres the commented code:
XMSReAlloc proc handle:WORD, kb:WORD mov ah,0Fh ;Use subfunction 0Fh mov bx,handle ;Get the handle to deallocate into DX. mov dx,[bx] mov bx,kb ;Get the new amount to resize the handle to into BX. call [XMSApi] ;Call the API. mov bx,handle ;Return the handle to QB. mov [bx],ax endp XMSReAlloc
As you can see it's pretty similar to the allocation routine. This like the allocation routine will only allocate up to 64MB. There is a routine that'll allow more (up to 4GB) but I want you to understand these first before you dive in. And thats all I have to say for this issue. Next issue I'll show you the other allocation routines and we'll combine this into a lib you can use. If you still don't understand any of this than don't hesitate to e-mail me
"Why?"
Why program an emulator for a system which has already been emulated almost
perfectly?
Why program an emulator in a slow language like QBasic?
Why have you decided to quit the project?
The bigger the challange, the higher the satisfaction. An emulator is not easy to program. One must emulate an entire system consisting of various subparts. Before being able to make BXNes I had to work myself through a huge pile of information on the NES. I learned how the CPU worked, how the PPU worked (kinda like the videocard for the NES) and how the memory was made up. After having done this, I decided that I was up to the challange.
I decided to program the NES emulator in QBasic, since that was the language which I knew quite well. From the beginning on I knew that speed would be a huge problem. The main idea was to implement an ASM core into the program, but it didn't turned out that well. My emulator greatest problem is speed, which makes it quite a pain in the ass to debug.
The main reason for me to quit the project was the slowness. In the beginning my goal was purely to emulate the NES without looking on how it was emulated. Now, I've came to a point were other aspects count in too. I have decided that QBasic is too slow for emulator-programming. I want to actually PLAY the games on my emulator at full speed. Therefore I've quit BXNes. However, I'm currently converting it to C. I hope that with this new compiler, I'm able to gain a fully playable NES emulator.
That's all concerning the "Why"-questions. Some people might try
making an emulator of their own in QBasic. For those people I've released the
sourcecode of the NES. I will describe how it has been made up. Note that I
don't explain how the NES works! Read the documents which can be found on the
internet.
BXnes.bas: The actual sourcecode
BXnes.def: Declaration of all functions and subs and variables
BXnes.bas consists of many subs, of which I will describe the most important
ones:
POWERON: Emulates the starting of the NES. It loads the ROM into the
memory
CPU: Emulates the CPU (uses OP.???)
PPU: Emulates the PPU (Picture Processing Unit, kinda like a videocard)
OP.???: Emulates the various opcodes of the CPU, where ??? is the name
of an opcode
WriteMemory: Emulates writing to the memory
ReadMemory: Emulates reading from the memory
After having loaded a ROM with PowerOn, the emulator will run a loop
consisting of running an opcode with the CPU and when needed running
the PPU. PPU is ran when the NES goes into a VBlank (more info
on this can again be found in the documents on the NES).
The code of BXNes is heavily commented and should therefore be quit readable.
This concludes my little article. In the zipfile with BXnes source and binary, you will also find a few demo roms to test it on! If you really don't understand the source or can't find documentation then just send me an e-mail. I will also try to aid anyone trying to make an emulator.
Special thanks go to the people behind the Emuschool project (emuschool.vintagegaming.net) and the author of Unnessential (download a copy at www.zophar.net/nes.html ). Without them I wouldn't have started the project and they gave a lot of their spare time to help me out!
Bram Bouwmans
BX software
a.a.j.bouwmans@kub.nl
http://stuwww.kub.nl~s333654