NeoZones & SonicBlue form Blue.Tek Creations! But break up again.
As you probably already knew, NeoZones & SonicBlue had joined to become the best QBasic site on the net: Blue.Tek. By the time this issue is out the page isn't even up because the Forum consumes to much CPU space (at least the ISP thinks it does so it disabled sonicblue.com). Now Tek has put up NeoZones again at: http://neozones.quickbasic.com and has already have given it a complete revamp!
Quickbasic.com is resurrected!!
You probably noticed, Quickbasic.com was down. This is because Chuck couldn't pay his monthly bill of $20. But Marcade came to the rescue! He paid for the quickbasic.com domain name. In return of this Chuck will place some ad banners for Marcade on his page. The hosted pages of Quickbasic.com (Enhanced Creations, QB:TM, Alternate Logic, NeoZones etc.) will stay. Quickbasic.com is already up, even as ec.quickbasic.com, jd.quickbasic.com, alternatelogic.quickbasic.com, neozones.quickbasic.com, and tz.quickbasic.com.
QBASIC.COM for sale!
After 4 years of service Mallard has put QBasic.com for sale. The starting price was $50 dollars but it sold for over $200 dollars!! Jorden Chamid of Future Software, Marcade, and some other prominent QBasic programmers tried to buy it, but lion777k got it! The QB Times wishes him luck in bringing qbasic.com back along the best QBasic pages on the net!
QBasic: The Magazine stops and a new magazine arrives!
After a year of service QBasic: The Magazine stops. This was announced at their page. You can download the full QB:TM archive in a 4MB ZIP file at http://qbtm.quickbasic.com. But then there's a new magazine called: Razor. You can find it at: http://razor.quickbasic.com.
That's how it felt like when I 'played' the engine. I quoted played, because it's not really .. 'playing' yet. What Angelo gave me was a plain engine where you are in a Wolf3D world inwhich you can freely move. Too freely cuz he didn't even implement collision detection! =D
That's what project RT actually is, just an engine, not a game. Angelo WILL be making a game out of it, of course. Most likely a RPG. But that seems to be still far away. The engine was lightning fast on my P2-400, around 100 FPS, no flicker or errors that I could spot. Every walltexture connected to eachother perfectly, and there even was a moving sliding door a la Wolf 3D. Actually the only thing different in this engine, compared to wolf 3D's engine, is that this engine also has ground and ceiling textures!
About the future of the engine I have. As far as I understood it, Angelo has recoded the whole engine. He wanted to make the engine even faster and his code cleaner, so he spent some time for this purpose. He didn't implement any sprite control in the current engine yet (you know, for like enemies and objects) but he'll implement that soon.
Another difference with wolf3D is that Project RT has a simple lighting effect. The further away the walls are, the darker it gets. In the demo I got I also could change the lighting, like how light or dark it was. The lighting effect was pretty cool and, especially because it can be different colours of lighting,it will deliver a whole bunch of new cool effects, Wolf3D didn't have.
That's all I can say now about project RT.
At my first glance at Katsumi I was already amazed of how professionally the art was done, I must say it was the best compared to any QB game. I got the newest version from Marcade with a few new features and new tiles for the outside world(not just the dungeon now!!).
You might realise all I was talking about is the art, well its because the art is amazing, I'm not saying the engine is crap but just that Marcade should have had some gameplay in it(though it is an early demo), I still really loved the engine with the water effects(reflections) and the smoothness of how the engine runs, it runs at arount 70 frames per second on my computer, also the MAS(Marcade's Advance Scripting) and the NPC are also one of the great things in Katsumi. Katsumi is currently about 20 to 30 percent done so thats pretty good for 7-8 months of work.
Even though none of the demo's of Katsumi have proper gameplay in them it,it is still just an early demo and was still very amazing and its only an early demo, but I just hope the future demo's will. If you're interested in Katsumi, go to http://www.zen-tech.net/ and see if ZenTech has released a demo yet.-DaeBreaker
QBprogger has been hard at work on this project call "Final Fantasy 2 Clone". A functional but umimaginative title. I suspect that another name will be used for the final game. This game has been billed as the first game to use RPGEngine (see iss. 1 for preview/review) build 22.
<- FF2 Clone
The game, which still unfortunately still uses pixel by tile movement, is an almost exact replica of the original game. When you first start up the game, the good old Squaresoft title comes up. (Do you have copyright permission for that, QBprogger?) Of course you press a key to continue. No wait, let me correct myself. You press two keys as the first time the screen only fades out half way?!
<- Original FF2
The tiles in this game cannot be laughed at. They are of a decent standard which is a relief as this gives the game a better feel than most and makes the game look even more like the original. I must stress though that QBprogger wants me to state that this game will have "director's cuts" and some extra map added just so it isn't EXACTLY the same.
<- FF2 Clone
On the engine side of things there are a couple of flaws which tarnish an otherwise good engine. The pixel by tile scrolling I have already mentioned. A bug which catches my eye is that the layered maps are not perfect as going through doorways causes you to temporarily float above thge door frame. Also, not all the collision is finished as you can walk on the black parts of the map if you find the right place to use. What i cannot flaw is an as yet perfect events engine which gives some great potential of what to expect from the finished map engine.
<- Original FF2
The classy menu system is still there in full blender mapped glory. God I love transparency! To end with, I'd like to say that IF this gets finished, and I say IF as not many RPG games ever get finished, then this is sure to be a hit for all you nostalgic gamers with a soft spot for Final Fantasy games or those who wish to give one a go.
Anyway, on to the review and the first thing you notice is a brand spanking new intro. Some nice effects and no print function anymore, what an improvement. The only thing I still don't like is the blocky graphics with the black lines round them. They are still in my opinion, garish. Oh, and the text is very hard to read on the intro sequence at parts. Maybe a better font routine should be implemented. Also, the spelling in some parts are bad too.
On to the menu, and an improvement there too...Lots more useful options. Still don't like the fonts and graphics that much.
Starting the game there are nice intros and character selections...these are really a great addition that I like to see in games. I have not tried a two player game yet but will soon. The sprites now have shading! Well, some do. Also, the speed has been improved and the animation of the characters has been improved, but not perfect yet. ou can also move up slopes in this version of the game which I am glad they implemented. The animation when moving up and down slopes needs to be improved.
The game still has bugs...for example when you move under the little moving bar on the first level that looks like it will squash you....you just move through it!
Really that is all that has changed...Well that and the fact the DQB has now been used for library uses which in my opinion is the best of their changes.
The coding still needs to be improved and maybe a few more subs to help to organise the program would not go wrong but you can't have you cake AND eat it I suppose.
Really these are the main things which have changed and hopefully more bug-fixes will come out to help the game get better as quite frankly it still needs to.
Parallax scrolling, nice title screen, compact and neat GFX, these are all traits of Mini-Shooter. The game has powerups and also weapon upgrades. Sadly you only get one level to try them out on but it's a nicely styled albeit small level.
The control method is a let down in my opinion. Using the mouse to move makes for the feeling of unrealistic movements in the craft you control as you can move anywhere in the screen in a fraction of a second so evading enemies is far too easy. Using the keyboard with a decent handler would be an improvement in my opinion.
Next on the agenda is the introduction of status and lives which I hope will be implemented in the next version as these are missing in this version. Also, the collision detection is lacking and this makes for a less than enjoyable encounter.
Weapons in this game are well thought out and fit in with the type of game. Most are the classic lasers and rockets from the good old days of "Shoot 'em Up construction kit" on the Amiga. The scene the game sets brings back memories.
To sum up I expect this game, with some finee tuning and control changes, to be a hit
which in my opinion is even better than Entropy's current project, Vert.
Mini-Shooter - http://members.aol.com/eclipzer/x-tech/init.htm
The most important virtual inhabitants are undoubtedly the heroes who the player pretends to be. Now before I continue further, I'll warn you that I'm using my two games, Dark Ages I & II, for examples, mostly before and after to show you how a game can be made better. In Dark Ages I, the hero was a rather static character, just a standard "do-everything" kind of person, one that the person couldn't role-play much. At best you could focus your energy into increasing his magic skills before gather important weapons for his battle skill. Really, he is all that is necessary to make a good RPG, but never a great one. Dark Ages II adds some twists. You now have three characters, each with their own special abilities. Each starts as a clean slate and progresses independent of the others. You can create your magic user to be an indestructable fortress of death on the battle field and your theif to be kind and skilled in the use of medical herbs. Or you can create a fighter skilled not in brutality, but in assassination. His skills on the field can be so great that he need not use his strength to pummel someone into the ground, but rather can disembowel an opponent in one blow. Your thief perhaps finds picking locks unartful and leaves it to the warrior to bash doors in. Instead she may concentrate on disarming traps and pickpocketing. In any case, you can play the characters to be different people whenever you start a new game. Such dynamics adds value to an RPG.
Look again at the above paragraph. Not only did it show the importance of dynamic characters, but it also introduced characters of different skills and types. These are known as character classes. Classes are something so crucial to a game, it would be hard to make one without them! Imagine a world where everyone was a simple gentleman who just stood at convenient locations and dispensed quest information; ack...how boring it would be! By making character classes you provide some individuality to each person. And just like everyone in this world is different, making people different in your RPG world makes it that much more realistic. Dark Ages I had very few character classes: knights, peasants, shop keepers, nobility, dwarven warriors, and mages. The world it created wasn't one which had much depth. A better way would have been to create more occupations and use them innovatively. In your world, don't stop at knights and peasants, but classify the peasants into simple farmers, shepherds, street peddlers, and servents. Knights could be divided into different factions and followings, some of them chivalric, others terrorizing warlords. Also, add odd occupations into the game for depth. Street performers (a simple juggler perhaps), thieves who roam the streets of cities, druids who protect the forests, etc. Something I'm introducing into Dark Ages II is guilds. Guilds are simply when large classes found in the game band together to one common cause. The thieves' guild may have a mafia-like hold on a town while an engineer's guild advances the technology of a given city tenfold. Like the guilds of history, they contain several subclasses (like engineers of weapons and engineers of special tools) and may not always agree with one another.
This brings us now to a rather difficult part of RPGs, NPC (non-player character) interaction. Most games are like Dark Ages I in which the people just stand there and interact only with the player. However, to make a realistic world you must also make these people interact with their environment and each other. Perhaps the greatest example I can think of is Ultima 5 through 7. I'm still baffled today at how Origin can create worlds with 300+ people, each running on their own specific schedules! Each person got up at a different time in the morning and walked to where he or she worked, took breaks for lunch (or some didn't!), took strolls in the park before dinner, or sat by the fire before bed, etc. Such detail adds a lot of realism to a game, but other steps can be taken as well. Moving NPCs are a bonus. It doesn't seem like much, but just moving them a little is better than having them stand in the same place forever. To top things off, interaction between NPCs is essential. It doesn't have to happen often and probably will not since it takes a fair amount of precision coding, but even in Dark Ages II, I am trying to interact between NPCs. Some examples I am using is wars between feudal lords, assassinations by radical factions, or simply NPCs refuse to act without other NPCs helping out. The more you can define the roles of each NPC in their world, the better it will be.
And finally we come to the last inhabitants in your virtual world: the enemies. Depending on the type of RPG you make, you will decide on the correct type of opponents who must be defeated less they kill the heroes. A cyberpunk-futuristic RPG would have nothing but humanoid enemies while a medieval RPG could integrate mythical beasts. Whichever RPG you choose, the key to enemy creation is to make them fit their environment, fit their theme, and most importantly, follow the rules of the game. Don't create opponents who always do X-amount of damage, but instead are limited in the same way the characters are limited. Instead, create an artificial intelligence (it doesn't have to be difficult) that causes a rabbid dog to attack the closest character in battle, and an orc-veteran to instead choose the weakest character to attack. Such realism requires the player to adjust strategies and skills depending on the type of battles that occur. It makes your virtual world a much more realisitic world in which to survive.
I do admit, it makes a game much harder to code, but much greater in the long run. But even so, you don't absolutely NEED any of the above to make a good game. Instead, pick and choose what you think are good ideas and what you would like your world to be. After all, each virtual world is unique and should contain unique features of the designers choosing.
NPCs can be just 1 frame with a person on it that does nothing other than to stand and look amusing on the screen. Or with a little bit of programming magic, an NPC can be fully animated from all angles, can walk and interact, and in a sense seem more like a real person. The difference is the static, simplistic, (probably boring) NPC types from my game, Dark Ages I, to the complex and intricate NPCs of the later Ultima games who all walk, talk, follow meal and sleeping agendas, and even manipulate their environment to their own personal needs!
I don't know how Origin manages such detailed NPCs, but at least I can get everyone started on making complex NPCs. Under my method, each NPC has simple number variables that control where and when he can move and what picture to use. All the variables for all the NPCs in the current map are stored in one array using the TYPE command. For those who don't know how to use it, I'll give a brief explanation.
Imagine you have made an NPC and wish to store his map coordinates and name. You may do so using these variables:
x1 = 10 y1 = 37 name1$ = "Rhoeyce"Now let's say you wanted more than one NPC for the map, so you create 3 more variables:
x2 = 45 y2 = 7 name2$ = "Hans-Dirk"What if you want more than 2 NPCs? Suddenly you are swamped with variables! Well all that can be reduced to just one array with the TYPE command:
TYPE NPC x as integer y as integer name as string*15 END TYPE DIM SHARED People(1 to 10) AS NPCWith that simple little blurb of code, you can now store 10 NPCs in the array People. By changing the number from 1 to 10 to 1 to whatever, you can have as many NPCs as you want in the map. You can store the individual aspects of data in this manner:
People.x(1) = 10 People.y(1) = 37 People.name(1) = "Rhoeyce" People.x(2) = 45 People.y(2) = 7 People.name(2) = "Hans-Dirk"You access the information the same way, such as
newx = People.x(2) PRINT People.name(1) etc.There, TYPEs in a nutshell. Back to NPCs. What should be stored in the TYPE? I store information such as name, x and y boundaries, picture, and temporary variables such as whether or not the person is currently moving. It could look something like this:
TYPE NPC X as integer Y as integer MaxX as integer MaxY as integer MinX as integer MinY as integer Name as string*12 PictureSet as integer Frame as integer Direction as integer InMotion as integer END TYPEIt probably seems like a lot; well, it is. But the results are beautiful. By now creating a simple loop, you can run through your entire NPC array and determine whether or not they move and if they do, what direction, how long, and what picture to use. I'll try to make a pseudo-loop so you can see how it works.
First, check to see if the NPC is already in motion (InMotion variable).
If yes, then move it based on Direction, and show it's picture based on PictureSet, Direction, and Frame.
If no, then randomly select whether or not it wants to move with a random number generator.
If it was not moving and it randomly generated that it would move, have another random generator select a direction and have it stored in Direction. Then check the current X and Y coordinates. Let's say that you randomly generated a 1 for direction, which you make "up" or "north". You would now check Y-1 to make sure it was not less than MinY. If it IS less, you have to randomly select a new direction. If it is ok, that means the NPC can move north. Change the InMotion variable so that the next time the NPC loop is run, the NPC will continue to move in this direction.
That's it, run through the loop for every NPC you have on the map and it's done. Simple, isn't it? Anyway, let me explain some of the variables barely mentioned above. The first is PictureSet. If you're going to use moving NPCs, you need to have a set of frames showing movement. I like using 4 frames for each direction, for a total of 16 frames per PictureSet. Since I store all the NPC frames in one array, I need to specify where in the array the set is located. Therefore, if I have 3 NPC picture sets, I store them in an array such as this: NPCPics(1 to 48) and then qualify which picture set I am using with the numbers 1, 17, and 33.
Now that I have each NPC locked into a set of pictures, I need to find out which frame to use in the set. I can do that with Direction. Note that before it was used to determine where the NPC will move, but since the frame you will see depends on the direction the NPC is moving, it MUST also be used to determine which frame. Furthermore, the Frame variable must be used to determine which of the 4 pics per direction will be displayed. Every time I run through the loop, I have
Frame = Frame + 1 If Frame > 4 then Frame = 1That way it cycles through the pictures for the direction. Now, let's say for example that the NPC is the second picture set (PictureSet = 17), he's moving south (Direction = 3), how would you determine the right picture?
Picture = NPCPics (PictureSet + (Direction * 4) + Frame)That's it and the animation is made by cycling through the frames as shown a few lines above. We'll say we're currently at Frame = 1, so the picture drawn would be 17+12+1 or 30. The next time the loop is run, Frame will equal Frame + 1 or 2, so the new picture would be 17+12+2 or 31. The loop continues and once Frame equals 5, the code will change it back to 1 and the cycle will start over giving that look of fluid animation.
And finally, what about the InMotion variable? What I do, since I work with pixel scrolling, is I set this number to the number of pixels per tile. If I use 32x32 pixels per tile, I set InMotion to 32. Then each time I run through the loop, I subtract 1 from InMotion. When it hits 0, the NPC stops moving. That way the NPC only moves 1 tile at a time before having to go through the random number generator to determine if it wants to move again. Of course, you can set this number however you want based on how near or far you want the NPC to move.
This will give you in my opinion a nice way to manage a bunch of NPCs moving at the same time. But it's still not finished. What about collisions? After all you can't have NPCs walking through walls. This part is simple. Up above where I showed how to check the direction to see if it is beyond the Max or Min coordinates, you could also check the collision. Simple check X-1 or X+1 or Y-1 or Y+1 for a solid tile. If yes, have it choose a new direction. You can do a similar check to make sure the NPC doesn't walk into another NPC.
That's it for my tutorial. Perhaps sometime I'll add an actual demo program (don't hold me to it!!) In any case, this still doesn't explain how Origin manages personal agendas, sleep schedules, etc. Nor do I claim this to be the best or only way, just the way I decided to do it. In any case, good luck with your NPCs!
First and most importantly...sound effects MUST be added to your GDM file. There is just no other way to do this without some serious additional coding. So, to keep things simple for now, just do it! Add your sounds to the file. There's a little thing you want to watch out for, and that's placement. You see, GDM's sample slots are listed from 0. Some trackers start their sample slots at 1 (like ScreamTracker). So, you have to take this into consideration. For example, in WOS, samples start at GDM Slot 64. However, when I use ST3 to make the S3M files I will later convert with 2GDM, I have to store samples starting at 65. Some Amiga programs store starting at 0.
So, let's say that you have five sound effects you want to add. If these five sounds are meant to be heard throughout the entire game or application, a good idea would be to add then to each music file in the same order, and in the same place in the file. So, maybe CLANG.WAV goes into slot 65, STOMP.SMP goes into slot 66, and so on. The smart planner keeps this kind of thing consistant throughout all the files.
Once you've done that, you'll want to be able to play those sounds. Playing sounds requires the use of a channel. However, since all the channels alloc- ated are being used to play music, what do you do? Well, simple! When starting the sound output:
OverRate& = StartOutput(MusicChannels, 0)simply allocate more channels! For example...
OverRate& = StartOutput(MusicChannels + 2, 0)Keep in mind that more channels means more CPU time (except GUS...again!)
Now, remember what channels you allocated for sound...it will be important when playing sound effects.
So, when your tune is playing (though music doesn't have to be playing to play SFX, the module does have to be loaded) what you would do is use the PlaySample command:
PlaySample Channel%, Sample%, Rate&, Vol%, Pan%For example:you have a sample at 45 you wish to play on channel 7, full volume, at a rate of 22000, centered. Here's how you'd do it:
PlaySample 7, 45, 22000, 64, 8Some of these are quite obvious...the most unobvious would be Pan%. This can be any number from 0-15, or &HFF for 'no change'. Any number beside 0, 8, or 15 is going to take more CPU time (except...you guessed it...a GUS card!)
Defining a different volume can be useful for echoes, like listed in BWSB-REF. However, a cool effect could also be to alter the volume AND the Panning. For example, start at a low volume at pan 0, then increase the volume as you move up to pan 8. Then as you pan to 15, lower the volume. Like this:
PlaySample 7, 45, 22000, 32, 0 PlaySample 7, 45, 22000, 36, 1 PlaySample 7, 45, 22000, 40, 2 PlaySample 7, 45, 22000, 44, 3 PlaySample 7, 45, 22000, 48, 4 PlaySample 7, 45, 22000, 52, 5 PlaySample 7, 45, 22000, 56, 6 PlaySample 7, 45, 22000, 60, 7 PlaySample 7, 45, 22000, 64, 8 PlaySample 7, 45, 22000, 60, 9 PlaySample 7, 45, 22000, 56, 10 PlaySample 7, 45, 22000, 52, 11 PlaySample 7, 45, 22000, 48, 12 PlaySample 7, 45, 22000, 44, 13 PlaySample 7, 45, 22000, 40, 14 PlaySample 7, 45, 22000, 36, 15Of course, that exact method is horribly inefficient (a smart coder would have used a loop), but you get the idea.
Okay! That just about covers all you need to know for a basic sound structure! Over the next couple of months, I will be getting into some advanced programming features of BWSB, including scopes, dynamic sample allocation, and more.
Lesson no.5 ASM:Diffrent approach
.STACK 100h ;Stack will be explained later ;it is beyond the scope of this ;tutorial .CODE ;This is the code segment jmp start ;Jump to "start" no matter ;what. message db 'Hello world!', 0d, 0a, '$' start: mov dx,OFFSET message ;Get the message pointer mov ax,cs ;put code segment in ax mov ds,ax ;put code segment in data segment mov ax,0900h ;Use function 9 int 21 ;DOS service 21 (explained later) mov ax,4c00h ;Returns to DOS function int 21 ;DOS ExitWhat did that do? Run it and see. Ah there we go it printed out "Hello World". But how the heck did that happen? Simple if you follow what I say.
First by saying "jmp start" we are jumping to the label called "start". Labels behave much like they do in QB as the do in asm. Except, as you'll find out, you can do a bit more with them. Now that we are in the start, we notice we skiped a line of code up there.
message db 'Hello world!', 0d, 0a, '$'First the "message" part is actually a label. But that's a neat way of writing it. db means a integer or a string to put it in simple terms. Then we have the text the 0d 0a (Enter). At the end we have a $. This is actually to terminate the string.
So by saying that we get a label called message pointing to a string that say "Hello world".
Ok lets go back to buisness, after the start label there is a command that says:
mov dx,OFFSET messageWhat's offset you say? before you continue I suggest reading the segments and offsets tutorial that I've included. Done? About time =) Now that we know what segments and offsets are you should now understand that what we are doing is locating the offset of the data block after the label message, then puting that value in DX. Why DX? We will get to that shortly.
After that we have this pretty peice of code:
mov ax,cs mov ds,axFirstly, CS is a pointer to the segment of the program's code thats running at the momment. DS is the pointer to the DATA segment. In the case of our little program, both the Data Segment and the Code segments are the same, thus we need to make the value of the data segment, the same value of the code segment. Why not just say MOV DS,CS? Well some smart ass jerk making the computer chipset model decided that MOV DS,CS is a illegal command combination (OK OK that's not the real reason but to tell you the truth I don't know ;) ) Ofcourse there is a way out of this chocking limit.
First mov the value of CS to AX, then mov the value of AX to DS!
mov ax,cs ;mov value of cs to ax mov ds,ax ;mov value of ax to ds, therefor moving cs to ds.Aha! After we done that we see this weird part:
mov ax,0900h ;Use function 9 int 21 ;DOS service 21 (explained later)This simply says to use function 9 of the DOS service int. Remeber when we turned on the mouse? Well This int prints out a string.
First you put the string's offset in DX
mov dx,OFFSET message ;Get the message pointerThen you put the string's segment in DS
mov ax,cs ;put code segment in ax mov ds,ax ;put code segment in data segmentThen you call INT 21 with 900 in AX
mov ax,0900h ;Use function 9 int 21 ;DOS service 21 (explained later)Now we must bravely exit out of our little homemade program. There is an int perfect for this. int 21 function 4C!
mov ax,4c00h ;Returns to DOS function int 21 ;DOS ExitIf you don't get all this, read it agian, still don't get it, read it agian, still don't get it? Email me at email@example.com =)
Next month we look at more registers more commands and more asm. Don't miss out =)
*note: Pigs do not, and I repeat DO NOT FLY!*
hehehe... now that's cleared up lets begin.
Computers memory is found on the Mother board. There is ussally 4 slots where you can insert 4MG/8MG/16MG/or even new 32MG RAM Chips [Ed: Updated!now you can have 128MG and 64MG RAM! Prehaps more by the time your reading this]. Those 4 slot's memory is combinied and the computer can use them. There are many diffrent ways of accessing them including DPMI,EMS,XMS and more but for the sake of begineers I'll start off with good old 16-bit (or realmode).
Oh yeah if I were you (If you were a QB Begineer) I would read the Hex tutorial before I touch this.
Go, read it!
(abionnnn scruffeles to his coffee while the reader is reading about hexadecimal)
ahh ... oh sorry, what were we talking about agian? oh yes segments and offsets.
[To more than begineers : this is a 16-bit tutorial, there is a bigger FFFFFFFF limit to pointers for 32-bit. FFFF is only the limit to 16-bit]
Well lets look at the whole computers memory as a peice of paper. The paper is seprated into FFFF (65535, you really should have read the Hex tutorial = ) ) diffrent segments. These segments are 64K big, and to point to each diffrent byte you need to have the pointer. We write bytes in the memory like this :
Pretty simple eh? Thought you'd agree. Now one famous segment is the VGA Memory Segment, which is A000. So to point to the first byte of the VGA memory you simply right the memory like this
(note how both the segment and the pointer are both 16-bit)
and the last byte of the VGA memory is FFFF because that's the most a 16-bit number can be, ofcourse there is almost no limit for 32-bit pointers but then things would be more compilcated and I would'nt be able to finish this tutorial in time for tea. = )
So the last byte of the VGA memory would be:
_______________________ |_|_|_|_|_|_|_|_|_|_|_|_|<--- Lets look more closely at this one |_|_|_|_|_|_|_|_|_|_|_|_| |_|_|_|_|_|_|_|_|_|_|_|_| Segment 1A78 |_|_|_|_|_|_|_|_|_|_|_|_| ______________ |_|_|_|_|_|_|_|_|_|_|_|_| |0000|0001|0002|<-These numbers are offsets |_|_|_|_|_|_|_|_|_|_|_|_| |0003|0004|0005| when we write |_|_|_|_|_|_|_|_|_|_|_|_| |0006|0007|0008| |_|_|_|_|_|_|_|_|_|_|_|_| |0009|000A|000B| |_|_|_|_|_|_|_|_|_|_|_|_| |000C|000D|000E| |_|_|_|_|_|_|_|_|_|_|_|_| |000F|0010|0011| |_|_|_|_|_|_|_|_|_|_|_|_| .... .... ....Pretty simple system right? No.
In reality segments overlap. Since you can only access about 1088K of memory in real mode, there can only be 1088K worth of segments and offsets to address the memory in. If each segment actually contained 64K of memory then YIX! lets see we've got 4 Gigs of memory to address! Too much for comfort *They thought*. Segments overlap each other each 16 bytes. And there is more than 2^20 bytes worth of memory to address. If segments overlap then you can access the same memory in a diffrent segment! A000:FFFF can also be accessed at A001:FFEF and A002:FFDF and A003:FFCF. Why? Because segments overlap!
To find if which memory you are accessing. You use this formuale:
Memory=Segment*16+OffsetOr in Hex
Memory=Segment*10H+Offset.So A000:FFFF would be
A0000+FFFF=AFFFFand A001:FFEF would be
A0010+FFEF=AFFFF... the same memory! In reality this is a really shitty system. When you get to 32-bit memory addressing it gets better, there is no segments and offsets. You access memory with a 2 byte pointer. So the video memory (in 32-bit) would start at 000A0000, and end at 000AFFFF. Upto 4 Gigs can be accessed with the 32-bit system, it's a better system in reality but we'll get on to it later. At the momment as far as your concerned segments and offsets are the norm = )
-8<--------------------------------------------------------------------------- DIM variable% 'You don't really need this, but just to show 'you what variable% I'm using. And besides, 'after you allocate it once, you don't have 'to waste clock-time allocating it somewhere 'else Segment = VARSEG(variable%) 'gives us the segment. Pointer = VARPTR(variable%) 'gives us the offset PRINT "variable%'s memory location is "; PRINT HEX$(Segment);":"HEX$(Pointer) 'This writes it in Hex. ------------------------------------------------------------------------->8---There you go. The same can be done with an array.
-8<--------------------------------------------------------------------------- DIM variable%(0) 'You don't really need this, but just to show 'you what variable% I'm using. And besides, 'after you allocate it once, you don't have 'to waste clock-time allocating it somewhere 'else Segment = VARSEG(variable%(0)) 'gives us the segment. Pointer = VARPTR(variable%(0)) 'gives us the offset. PRINT "variable%'s memory location is "; PRINT HEX$(Segment);":"HEX$(Pointer) 'This writes it in Hex. ------------------------------------------------------------------------->8---Like the scissors? hehehe. Well anyway, you do get the point right? good.
QBasic/Quickbasic News is a site that is devoted to bring the latest news from the QB community. Also it reviews sites, has some links and tutorials. The first thing that caught my eye was that the page was one my screen within 1 second! Now that's a fast loading page!! So far for the intro, read the scores!!
|General Appearance:||77||A good layout. The navigation is at the top of the page which is very user-friendly.|
|Images:||70||Nice looking but not very special|
|Programs/Links:||75||Not to many programs and links but they have some nice tutorials.|
|QBasic:||95||All about QBasic|
|Unique:||80||The news thing is pretty unique but for the other things there's not really anything special.|
|Total:||81||A nice site to check out a few times a week for the news.|
The first thing that I noticed on this site was that there were so many sections! 20 in total! There are some files, and tutorials. There is an award you can win, challanges, a good collection of links, 27 tricks and some other things. Well that covers the introduction. Read the scores.
|General Appearance:||82||A well thought out layout that has not frames and loads very quickly!|
|Images:||70||Nothing special but nice to look at.|
|Programs/links:||75||Not so many programs but a good amount of links!|
|QBasic:||95||All about QBasic|
|Unique:||75||Well maybe the challanges are a bit unique but nothing else really is unique.|
|Total:||80||A big site which has many good things but I think they should add some more tutorials and programs. But when they do that it'll be a very good site!!|
Hopefully this information file will give you all the information you need to code youre own fire routines, seen in many demo's and also to actually take it all further and develop youre own effects..
Ok, so lets get on....
first thing we need to do is set up two arrays, the size of the arrays depends on the many things, screen mode, speed of computer etc, its not really important, just that they should both be the same size... I'll use 320x200 (64000 byte) arrays for this text, because that happens to be the size needed for using a whole screen in vga mode 13h.
The next thing we need to do is set a gradient palette, this can be smoothly gradiated through ANY colours, but for the purpose of this text lets assume the maximum value is a white/yellow and the bottom value is black, and it grades through red in the middle.
Ok, we have two arrays, lets call them startbuffer and screenbuffer, so we know whats going on. Firstly, we need to setup an initial value for the start buffer... so what we need is a random function, that returns a value between 0 and 199 (because our screen is 200 bytes wide) this will give us the initial values for our random "hotspots" so we do this as many times as we think is needed, and set all our bottom line values of the start buffer to the maximum colour value. (so we have the last 300 bytes of the start buffer set randomly with our maximum colour, usually if we use a full palette this would be 255 but it can be anything that is within our palette range.)
Ok, thats set the bottom line up.. so now we need to add the effect, for this we need to copy the start buffer, modify it and save it to the screenbuffer, we do this by averaging the pixels (this is in effect what each byte in our array represents) surrounding our target....
It helps to think of these operations in X,Y co-ordinates....
Lets try a little diagram for a single pixel.....
This is the startbuffer This is our screenbuffer --------------------- --------------------- |0,0|0,1|0,2|0,3|0,4| etc... | | | | | | --------------------- --------------------- |1,0|1,1|1,2|1,3|1,4| etc.. | |X,Y| | | | --------------------- --------------------- |2,0|2,1|2,2|2,3|2,4| etc.. | | | | | | --------------------- ---------------------Here we're going to calulate the value for X,Y (notice I didnt start at 0,0 for calculating our new pixel values?? thats because we need to average the 8 surrounding pixels to get out new value.. and the pixels around the edges wouldn't have 8 pixels surrounding them), so what we need to do to get the value for X,Y is to average the values for all the surrounding pixels... that means adding 0,0 0,1 0,2 + 1,0 1,2 + 2,0 2,1 2,2 and then dividing the total by 8 (the number of pixels we've takes our averages from), but there's two problems still facing us..
1) The fire stays on the bottom line....
2) Its slow....
3) The fire colours dont fade...
Ok, so first thing, we need to get the fire moving! :) this is really VERY easy. All we need to do is to take our average values from the pixel value BELOW the pixel we are calculating for, this in effect, moves the lines of the new array up one pixel... so for example our old X,Y value we were calculating for was 1,1 so now we just calculate for 2,1 and put the calculated value in the pixel at 1,1 instead.. easy..
The second problem can be approached in a few ways.. first and easiest is to actually calculate less pixels in our averaging.. so instead of the 8 surrounding pixels we calculate for example, 2 pixels, the one above and the one below our target pixel (and divide by 2 instead of 8) this saves a lot of time, another approach is to use a screen mode, where you can set 4 pixels at a time, or set up the screen so that you can use smaller arrays (jare's original used something like 80X50 mode) which in effect reduces to 1/4 the number of pixels needed to be calculated.
The third problem is just a matter of decrementing the calculated value that we get after averaging by 1 (or whatever) and storing that value.
Last but not least, we need to think about what else can be done... well, you can try setting a different palette, you can also try setting the pixel value we calculated from to another place, so say, instead of calculating from one pixel below our target pixel, you use one pixel below and 3 to the right of our target... FUN! :))
Well, I hope I didnt confuse you all too much, if you need anything clearing up about this, then email me at firstname.lastname@example.org ok?
Written by Phil Carlisle (aka Zoombapup // CodeX) 1994.