Spellcaster presents: TTTTTTTTTT HH HH EEEEEEEEEE MM MM AAAA GGGGGGGGG TT HH HH EE MMM MMM AA AA GG TT HH HH EE MM M M MM AA AA GG TT HHHHHHHHHH EEEEEE MM MM MM AAAAAAAA GG TT HH HH EE MM MM AA AA GG GGGG TT HH HH EE MM MM AA AA GG GG TT HH HH EEEEEEEEEE MM MM AA AA GGGGGGGG Issue 6 8-3-96 Index 1. Introduction 1.1. About the magazine 1.2. About the author 1.3. Distribution 1.4. Contribuitions 1.5. Hellos and greets 2. Records and basic file handling 2.1. Records 2.2. Files 3. The dos and don'ts of file acessing 4. Scrolling in text mode 5. Graphics Part V - Loading a PCX file 5.1. Introduction 5.2. The PCX file structure 5.3. Decoding a PCX file 6. Hints and tips 7. Points of view 8. The adventures of Spellcaster, part 6 1. Introduction 1.1. About the magazine Welcome to number 6 of 'The Mag', brought to you, as usual, by Spellcaster, alias Diogo de Andrade. I know this issue is VERY late, but I got some exams and then my hard drive just cocked out... It still doesn't work, so I'm writing this in the school's computers, that are a piece of shit, and I've very pissed ! It's the second time I write issue 6, because I already had finished it when my hard drive died... This magazine is dedicated to all the programmers and would-be programmers out there, especially to those that can't access the Net easily to get valuable information, to those who wish to learn how to program anything, from demos to games, passing through utilities and all sort of thing your mind can think of, and to those that can't find the right information. I've made an error in the previous issues. In the virtual screens part, there's a small piece of code that reads: Procedure InitVirt; Var A:Byte; Begin For A:=1 To Npages Do Begin GetMem(Virt[A],64000); VP[A]:=Segment(Virt[A]^); End; End. You should change the Segment keyword to Seg... Small mistake... You should read now: Procedure InitVirt; Var A:Byte; Begin For A:=1 To Npages Do Begin GetMem(Virt[A],64000); VP[A]:=Seg(Virt[A]^); End; End. Sorry about that... I'm only human... When you read this magazine, I'll assume some things. First, I assume you have Borland's Turbo Pascal, version 6 and upwards (and TASM for the assembly tutorials). I'll also think you have a 80386 (or 386 for short; a 486 would be even better), a load of patience and a sense of humor. This last is almost essencial, because I don't receive any money for doing this, so I must have fun doing it. I will also take for certain you have the 9th grade (or equivelent). Finally, I will assume that you have the last issues of 'The Mag', and that you have grasped the concepts I tried to transmit. If you don't have the issues, you can get them by mail, writing to one of the adresses shown below (Snail mail and Email). As I stated above, this magazine will be made especially for those who don't know where to get information, or want it all in the same place, and to those who want to learn how to program, so I'll try to build knowledge, building up your skills issue by issue. If you sometimes fail to grasp some concept, don't despair; try to work it out. That's what I did... Almost everything I know was learnt from painfull experience. If you re-re-re-read the article, and still can't understand it, just drop a line, by mail, or just plain forget it. Most of the things I try to teach here aren't linked to each other (unless I say so), so if you don't understand something, skip it and go back to it some weeks later. It should be clearer for you then. Likewise, if you see any terms or words you don't understand, follow the same measures as before. Ok, as I'm earing the Net gurus and other god-like creatures talking already, I'm just going to explain why I use Pascal. For starters, Pascal is a very good language, ideal for the beginner, like BASIC (yech!), but it's powerfull enough to make top-notch programms. Also, I'll will be using assembly language in later issues, and Pascal makes it so EASY to use. Finally, if you don't like my choice of language, you can stop whining. The teory behind each article is very simple, and common with any of the main languages (C, C++, Assembly - Yes, that's true... BASIC isn't a decent language). Just one last thing... The final part of the magazine is a little story made up by my distorted mind. It's just a little humor I like to write, and it hasn't got nothing to do with programming (well, it has a little), but, as I said before, I just like to write it. 1.2. About the author Ok, so I'm a little egocentric, but tell me... If you had the trouble of writing hundreds of lines, wouldn't you like someone to know you, even by name ? My name is Diogo de Andrade, alias Spellcaster, and I'm the creator, editor and writer of this magazine. I live in a small town called Set£bal, just near Lisbon, the capital of Portugal... If you don't know where it is, get an encyclopedia, and look for Europe. Then, look for Spain. Next to it, there's Portugal, and Set£bal is in the middle. I'm 18 years old, and I just made it in to the university (if you do want to know, I'm in the Technical Institute of Lisbon, Portugal), so I'm not a God-Like creature, with dozens of years of practice (I only program by eight years now, and I started in a Spectrum, progressing later to an Amiga. I only program in the PC for a year or so), with a mega-computer (I own a 386SX, 16 Mhz), that wear glasses with lens that look like the bottom of a bottle (I use glasses, but only sometimes), that has his head bigger than a pumpkin (I have a normal sized head) and with an IQ of over 220 (mine is actually something like 180). I can program in C, C++, Pascal, Assembly and even BASIC (yech!). So, if I am a normal person, why do I spend time writing this ? Well, because I have the insane urge to write thousands of words every now and then, and while I'm at it, I may do something productive, like teaching someone. I may be young, but I know a lot about computers (how humble I am; I know, modesty isn't one of my qualities). Just one more thing, if you ever program anything, please send to me... I would love to see some work you got, maybe I could learn something with it. Also, give me a greet in your program/game/demo... I love seeing my name. 1.3. Distribution I don't really know when can I do another issue, so, there isn't a fixed space of time between two issues. General rule, I will try to do one every two weeks, maybe more, probably less (Eheheheh). 'The Mag' is available by the following means: - Snail Mail : My address is below, in the Contributions seccion... Just send me a disk and tell me what issues you want, and I will send you them... - E-Mail : If you E-mail me and ask me for some issues, I will Email you back with the relevant issues attached. - BBS's : I don't know for sure what BBS's have or will have my magazine, but I will try to post it in the Skyship BBS. If you have a BBS and you want to receive 'The Mag', contact me. Skyship BBS numbers: (351)+01-3158088 (351)+01-3151435 - Internet : You can access the Spellcaster page and take the issues out of there in: http://alfa.ist.utl.pt/~l42686 1.4. Contributions I as I stated before, I'm not a God... I do make mistakes, and I don't have (always) the best way of doing things. So, if you think you've spotted an error, or you have thought of a better way of doing things, let me know. I'll be happy to receive anything, even if it is just mail saying 'Keep it up'. As all human beings, I need incentive. Also, if you do like to write, please do... Send in articles, they will be welcome, and you will have the chance to see your names up in lights. They can be about anything, for a review of a book or program that can help a programmer, to a point of view or a moan. I'm specially interested in articles explaining XMS, EMS, DMA and Soundblaster/GUS. If anyone out there has a question or wants to see an article about something in particular, feel free to write... All letters will be answered, provided you give me your address. I'm also trying to start a new demo/game/utility group, and I need all sort of people, from coders (sometimes, one isn't enough), musicians (I can compose, but I'm a bit limited), graphics artists (I can't draw nothing) and spreaders... I mean, by a spreader, someone who spreads things, like this mag. If you have a BBS and you want it to include this magazine, feel free to write me... You can also contact me personally, if you study on the IST (if you don't know what the IST is, you don't study there). I'm the freshman with the black hair and dark-brown eyes... The one who's skipping classes... I recommend you to contact me personally, if you can, especially if you are a member of the opposite sex (I'm a man, for those of you who are wondering). My adress is: Praceta Carlos Manito Torres, n§4/6§C 2900 Set£bal Portugal Email: dgan@rnl.ist.utl l42686@alfa.ist.utl.pt And if you want to contact me on the lighter side, get into one of the following talkers... To do that telnet to: Lost Eden -> Ubistc.Ubi.Pt : Port 1414 Talho -> Ubistc.Ubi.Pt : Port 7000 CItal -> Zeus.Ci.Ua.Pt : Port 6969 I'm almost always there in the afternoon... As you may have guessed already, my handle is Spellcaster (I wonder why...)... 1.5. Hellos and greets I'll say hellos and thanks to all my friend, especially for those who put up with my constant whining: Special greets go to Denthor from Asphyxia (for the excelent VGA trainers), Draeden from VLA (for assembly tutorials), Joaquim Elder Guerreiro, alias Dr.Shadow (Delta Team is still up), Alex "Darkfox" (thanks for letting me use your BBS), Jo„o Neves for sugestions, testing and BBS services, and all the demo groups out there. I will also send greets to everybody that responded to my mag... Thank you very much ! 2. Records and basic file handling Ok, this article is about files and records... First, I'll talk about 2.1. Records Well, records are... ahh...er... records... I know this wasn't helpfull, but the best way to describe records is with an example. Imagine you wanted to build a program to keep track of all your friends' adresses and phone numbers. With the knowledge you have (assuming that you only know what I've been teaching you), you would have to do something like this: Var Names:Array[1..100] of String; Phone:Array[1..100] of String; Adress:Array[1..100] of String; Or something like this: Var Data:Array[1..100,1..3] of String; But this solution has several drawbacks... In the second example, you would have to remember that index 2 was the phone number and index 3 was the adress. With records, things get easier and simpler... You just have to make something like this: Type DataRec=Record Name:String; Phone:String; Adress:String; End; Var Data:Array[1..100] of DataRec; Now, you have an array called Data full of records... You can now access data in a perfectly straighward form... Data[1].Name:='Spellcaster'; Data[1].Phone:='01-551155'; They are treated as normal variables... The Name, Phone and Adress are the fields of record DataRec. This is an invalubale resource when building programs... I use them all the time. I think this is fairly simple, so I'll go on to 2.2. Files There will come a time in your programming experiences that you'll have the need to access files in your computer, to read a picture, for instance. When that time comes, you better be prepared, so read this carefully... This is very basic file accessing, and it's only usefull to read some types of data. You can't use these concepts to read a PCX file. Read the next article for that. There is a special kind of variable, called the Text type variable, that is used to read ASCII coded text. It is declared as usual variables, but it isn't used like them... I'll do a small demonstration commented program, to exemplify... Program Test_18; { This program gets string from the } { user and dumps them to a file, called } { SPELL.TXT... The program ends when the } { user returns an empty string.} Var F:Text; { Defines variable F of type text } S:String; { Defines S as a string } Begin Assign(F,'Spell.Txt'); { Associates variable with file } { SPELL.TXT. It isn't important if the } { file exists or not... } ReWrite(F); { This sets up the file F for writing. } Repeat ReadLn(S); WriteLn(F,S); { This writes the content of varible S } { to file F... } Until S=''; Close(F); { This closes file F, and saves the } { changes made to it... } End. Now, another example... Program Test_19; { This program reads the contents of } { file MAG06.TXT and dumps it in the } { screen... } Var F:Text; { Defines variable F as type Text } S:String; { Defines var S as a string } Begin Assign(F,'Mag06.txt'); { Associates var F with file MAG06.TXT } Reset(F); { Prepares file F for reading. If the } { file doesn't exist, the program will } { give you an error message. } Repeat Readln(F,S); { This reads a string from file F, and } WriteLn(S); { stores it in var S } Until Eof(F); { Repeats until End Of File F... } Close(F) { Closes file F } End; So, I think this is simple, even for a beginner... The Writeln and Readln procedures do the input and output to the file. The Reset and Rewrite keywords prepare the file for reading and writing. Notice that a file can't be open for reading AND writing simultaniously. The EOF function returns True if the file has already been totally read... Now, imagine you already had a file, and you wanted to add something in the end of it... Then you could use the Append keyword, instead of the Rewrite keyword. The difference between them is that Rewrite overwrites an existing file, and Append adds the data in the end. One last remark about files... In Pascal, all files are sequencial... This means that you, in order to access data in the middle, must access the data in the begginning. This also means you can't add data to the middle of a file. 3. The dos and don'ts of file acessing This article is an extension to the last one... It develops further more the concept of files. It teachs you to access files of other types besides text files... The name doesn't have nothing to do with the article itself, but I liked the idea... Imagine you wanted to access a file and get a byte at a time... This would be impossible with variables of type text. So, variables of type file come into action... Variables of type file are similar to varibles of type text, but more flexible... It enables to read a specified number of bytes to a variable, instead of reading entire lines... As usual, I'll suply you with an example... You know the say: An example is worth more than a thousand bytes of text... Program Test_20; Var F:File; A:Array[1..20] Of Integer; B:Integer; Begin Assign(F,'Spell.Dat'); Rewrite(F,1); For B:=1 To 20 Do A[B]:=Random(100); Blockwrite(F,A,Sizeof(A)); Close(F); End. This little program generates an array with 20 random integers and then it saves them to a file called 'Spell.Dat'. The Random(n) function gives a random integer in the 0..n range. The Blockwrite(File, Variable, Bytes) writes a certain number of Bytes that are stored away on the Variable to a certain File. The Variable can be any kind of variable, including user-defined variables. This is an unvaluble resource. I use BlockWrite and it's counterpart BlockRead in almost every program I make. Program Test_21; Var F:File; A:Array[1..20] Of Integer; B:Integer; Begin Assign(F,'Spell.Dat'); Reset(F,1); Blockread(F, A, Sizeof(A)); Close(F); For B:=1 To 20 Do Writeln(A[B]); Readln; End. The above example reads the file created with the other program and stores it on the array A. Then it types the values to the screen. Just one more thing I forgot to mention: You probably noticed the different sintax of the Reset and the Rewrite keywords. I'm not sure about what does it mean the number in front of the file identifier, but I think it is the number of bytes to read at any one time. I always read 1 byte at a time, so I always put a 1. If anyone smarter than me knows what is that number, mail me ! I'll finish this article with a piece of code I've been using for the last two issues sample programs. The procedure LoadPal reads a palette from disk and stores it in a RGBList (see the issue that talks about palette manipulation). Procedure LoadPal(Filename:String;Var Pal:RgbList); Var F:File; Begin Assign(F,Filename); Reset(F,1); Blockread(F,Pal,768); Close(F); End; This piece of code is pretty straightforward stuff, I think. 4. Scrolling in text mode Ok... This is a tricky article to understand and to write. So I'll try to do it the best I can. I wrote it because a reader asked it. This article is writen with the thought that you are understanding the graphics tutorials. Text mode can be thought as similar to mode 13h, in the respect that you could make a direct access to it, using the Mem keyword. The differences are that the address of a text screen is B000h, instead of A000h. Besides that, while $A000:0000 represented the first pixel on the screen in mode 13h, $B800:0000 represents the first character on the screen. Moving on, we need to know with the VGA card registers. For scrolling the text screen, we need to know this one: -------------------------------------------------------------------------------- Port-Index: 08h Port: 03d4h/3d5h usage: Preset row scan d7 Unused d6 Byte panning control d5 Byte panning control d0-d4 Preset row scan Description: This changes the first row of pixels to be displayed. For this article, we only need to know that if you do Port[$03d4]:=8; Port[$03d5]:=n; the first pixel to be desplayed on the screen would be n. -------------------------------------------------------------------------------- So, knowing this, the general algorythm is: You put the image, or whatever you want to scroll in in address $B800:4000. This is just out of the visual screen. |-> You scroll the screen, by changing the first pixel to be desplayed. | When you have scrolled sixteen pixels, you scroll in the memory the | image you want to scroll in, this is, you move the memory from | $B800:0160 to $B800:0000. | You go back to here | | ---------------------- Following this there is a piece of code that implements the above algorythm. It is unoptimized. Experiment with it... Change the values... Do something with it... This won't crash the computer... I think... :) Program Test_22; {$X+} Uses Crt; Var F:File; Old:Byte; N,M:Integer; Procedure WaitVbl; Assembler; Label l1,l2; Asm mov dx,3dah l1: in al,dx and al,08h jnz l1 l2: in al,dx and al,08h jz l2 End; Begin Port[$3d4]:=8; Old:=Port[$3d5]; {This saves the old value... It is usually one...} Fillchar(Mem[$B800:4000],16000,0); { This makes the image I want to scroll in be just a screen full of exlamation points... } For M:=0 To 50 Do Begin For N:=0 To 15 Do Begin Port[$3d4]:=8; Port[$3d5]:=N; WaitVbl; End; Port[$3d4]:=8; Port[$3d5]:=0; Move(Mem[$B800:160],Mem[$B800:0],16000); End; Readkey; Port[$3d4]:=8; Port[$3d5]:=Old; End. 5. Graphics Part V - Loading a PCX file 5.1. Introduction Ok, this is part 5 of the Graphics In Mode 13h tutorial. This issues's article is about reading a PCX file. This is quite simple, as reading any kind of file... You just have to know the file's structure. Just for knowledge, the PCX file format was created by ZSoft, for their popular drawing program, PaintBrush... I don't know what makes it popular, because I prefer Electronic Art's Deluxe Paint II anytime ! 5.2. The PCX's file structure Byte Item Size Description/Comments 0 Manufacturer 1 Constant Flag, 10 = ZSoft .pcx 1 Version 1 Version information 0 = Version 2.5 of PC Paintbrush 2 = Version 2.8 w/palette information 3 = Version 2.8 w/o palette information 4 = PC Paintbrush for Windows(Plus for Windows uses Ver 5) 5 = Version 3.0 and > of PC Paintbrush and PC Paintbrush +, includes Publisher's Paintbrush . Includes 24-bit .PCX files 2 Encoding 1 1 = .PCX run length encoding 3 BitsPerPixel 1 Number of bits to represent a pixel (per Plane) - 1, 2, 4, or 8 4 Window 8 Image Dimensions: Xmin,Ymin,Xmax,Ymax 12 HDpi 2 Horizontal Resolution of image in DPI* 14 VDpi 2 Vertical Resolution of image in DPI* 16 Colormap 48 Color palette setting 64 Reserved 1 Should be set to 0. 65 NPlanes 1 Number of color planes 66 BytesPerLine 2 Number of bytes to allocate for a scanline plane. MUST be an EVEN number. Do NOT calculate from Xmax-Xmin. 68 PaletteInfo 2 How to interpret palette- 1 = Color/BW, 2 = Grayscale (ignored in PB IV/ IV +) 70 HscreenSize 2 Horizontal screen size in pixels. New field found only in PB IV/IV Plus 72 VscreenSize 2 Vertical screen size in pixels. New field found only in PB IV/IV Plus 74 Filler 54 Blank to fill out 128 byte header. Set all bytes to 0 NOTES: All sizes are measured in BYTES. All variables of SIZE 2 are integers. *HDpi and VDpi represent the Horizontal and Vertical resolutions which the image was created (either printer or scanner); i.e. an image which was scanned might have 300 and 300 in each of these fields. Ok, if the above listing didn't gave you a clue, think of a PCX file like this. It is a file composed in the following form. The first 128 bytes are the header, which contains lots of informatation about the PCX file, like the size of the picture, pallete information (in less than 256 color modes). Then comes the picture data, encoded with a run-lenght algorythm... I will explain this latter. Then comes a byte with the value 12, if a 256 color palette exists. If it exists, it will be stored in the following 768 bytes. To read a PCX file, you can do like this: first, set three records, like this: Type RGBItem=Record Red:Byte; Green:Byte; Blue:Byte; End; PCXHeader=Record Manufacturer:Byte; Version:Byte; Encoding:Byte; BitsPerPixel:Byte; Window=Record Xmin:Integer; Ymin:Integer; Xmax:Integer; Ymax:Integer; End; HDpi:Integer; VDpi:Integer; Colormap:Array[0..15] Of RgbItem; Reserved:Byte; NPlanes:Byte; BytesPerLine:Integer; PaletteInfo:Integer; HScreenSize:Integer; VScreenSize:Integer; Filler:Array[1..54] Of Byte; End; RGBList=Array[0..255] Of RGBItem; Then, you read the header. You can do it with this: Var Head:PCXHeader; ...................... ...................... Assign(F,'IMAGE.PCX'); Reset(F,1); BlockRead(F,Head,128); The above piece of code will read the header of the PCX file called IMAGE.PCX. Now the variable Head, of type PCXHeader will contain all the relevant data of the PCX file. In the example I will give you, we'll ignore the header and assume the picture is a standard mode 13h image (because this is a tutorial on mode 13h). But don't worry... Anything that will be said here can be adapted to any graphic mode. 5.3. Decoding a PCX file You can now begin decoding the first scan line - read the first byte of data from the file. If the top two bits are set, the remaining six bits in the byte show how many times to duplicate the next byte in the file. If the top two bits are not set, the first byte is the data itself, with a count of one. Continue decoding the rest of the file like this. If you didn't understand what I was saying, think about this: You read a byte from the disk. Let's call this value A. If A is greater than 192, you read the next byte, and then you output it to the screen, A-192 times. It all becomes clearer with the piece of code I include next. This procedure is called LoadPCX, and it just requires the name of file. I'll assume that the graphics mode is already set. This procedure ignores the header and just reads mode13h files. The procedures PutPixel and SetPallete are user-defined before the LoadPCX file. Procedure LoadPCX(Filename:String); var Fil:File; Dx,Dy:Word; J,M:Byte; Ph:Word; Buff:Array[0..127] of byte; PCXPal:RgbList; Begin Assign(Fil,Filename); Reset(Fil,1); Blockread(Fil,Buf,128); Dx:=0; Dy:=0; Repeat Dx:=0; Repeat BlockRead(Fil,J,1); If J>192 Then Begin BlockRead(Fil,M,1); Dec(J,192); For Ph:=1 To J Do Begin PutPixel(Dx,Dy,M); Inc(Dx); End; End Else Begin PutPixel(Dx,Dy,J); Inc(Dx); End; Until Dx>=320; Inc(Dy); Until Dy=200; BlockRead(Fil,M,1); If M=12 Then Begin BlockRead(Fil,PCXPal,768); For M:=0 To 255 Do Begin PCXPal[M].R:=PCXPal[M].R Div 4; PCXPal[M].G:=PCXPal[M].G Div 4; PCXPal[M].B:=PCXPal[M].B Div 4; End; SetPalette(PCXPal); End; Close(Fil); End; In case you're wondering why did I, after I read the palette, divide it all by four, I'll explain... The registers of the VGA Palette have intensities that range from 0 to 63... The PCX file saves palette information from 0 to 255. So, before you use the palette, you must divide it all by four. I know it is stupid, but I didn't invented it ! Also, the above code is very slow, because you read the data from the file one byte at a time. You can speed it up by creating a buffer that stores part of the file in order to reduce disk access... The speed-up is tremendous ! I'll show how can it be done in next issue. 6. Hints and Tips * - Begginners tip ** - Medium tip *** - Advanced tip - Forward keyword (*) If you write that following piece of code: Procedure One; Begin Two; End; Procedure Two; Begin End; You would get an error, because when the compiler reaches to the call of procedure Two in procedure One, he doesn't know yet procedure Two... There are two ways of mending this. The first is to reverse the order the procedures appear. The second comes in hand in cases like the following: Procedure One; Begin Two; End; Procedure Two; Begin One; End; I know this would get an infinite cicle, but that's beyond the point. The only way to go around this is to use the forward keyword. The forward keyword informs the compiler that a certain procedure exists, so it will not give a 'Undefined Procedure' error. So, to validate the last piece of code, you would have to do it like this: Procedure One; Forward; Procedure Two; Forward; Procedure One; Begin Two; End; Procedure Two; Begin One; End; - Speeding up some routines (**) One way to optimize code is to calculate all the relevant stuff in an inner loop before the loop. For example, let's assume we have the following code: For A:=1 To 100 Do Begin For B:=1 To 200 Do Begin C:=A*50+B; End; End; This could be replaced by this faster code: For A:=1 To 100 Do Begin D:=A*50; For B:=1 To 200 Do Begin C:=D+B; End; End; The only drawback is the use of an extra variable, but that's almost always a constant... The more speed you want, the more memory you spend, and vice-versa. 7. Points of view Well, I don't know what to talk about in this issue, so I think I'll just ramble on... I'll start with a moan (as usual)... Why can't I get a musician and a Gfx artist for my productions ? I really want to do something like a demo or a game, but I can't because I can't do music and can't draw... And I don't have a computer good enough to run 3D Studio (the only drawing program I know that the person who uses it doesn't need to draw well to create a masterpiece...). Next, I'll send my respects to some demo and game making groups out there... Especially the ones that don't charge anything for their work... Not because I'm a cheap-stakes, it's just because those guys programm for their love for the art, not for love for the money... Of course, it isn't wrong to get money out of it... Money is good... But I admire more a guy that spends lots of time developing a program to release it free than I admire a guy that gets big bucks for doing the same thing. And why every employer nowadays whats you to know Visual C/Basic, or Windows 95 programming and other user-friendly shit like that. I HATE WINDOWS... 95 and 3.1... I hate them all... They aren't made for programmers... They are made for users... But the worse is that one day, all that there is left is Win95... And we'll have to quit doing demos and games, because most demos/games use resources that Win95 don't allow you to use... It will be like a return to the stone-age in demo/game making. I'm just too melodramatic today, ain't I ? :) Weel, I don't know when the next issue will come, nor what will it have, so keep your eyes peeled for it. I think I'll put, in the begginers part, a tutorial on how to create and use Pascal Units. In the graphics part I think I'll make an article on scrolling and I'm also thinking on including an article on Pointers (the second part of an article I've started in issue one). I'll also will try to squeeze the first of the Spellcaster Utilities, a series of programms to help you develop your programs. So I think the next issue will take longer to make that I thought in the first place. I have to code the first utilitie (I'm thinking about doing a palette editor). I'll try to make the best I can, as usual... Send all doubts to me. And your articles/articles suggestions.. I'd love to see them. I'll help if I can. 8. The adventures of Spellcaster, the rebel programmer of year 2018. Episode 6 - Hear no evil, see no evil I looked at the clock. It was 7 a.m. Only an escape plan could make me rise so early. I looked at Karl. His eyes were very bright, as if he was starting to cry. I prefered to believe that it was the sun rising up ahead that was hurting his eyes. - Let's go... - I said, starting to walk down the hill, in direction to the Sega Corporate Prison. I heard Gundsen's steps behind me. - Are you sure the virus will work ? - he asked, with a little fear on his voice. - Positive... I've run tests with it. Relax... If the virus is in the central computer, this will work... - And if it isn't ? - This will be the shortest jailbreak in history ! - I said with a dark voice. - How did you got it into the system ? - I sent a disk to the warden... He probably downloaded it in the main computer's memory. - What ?!! - shouted Gundsen, stopping. - Don't you know they scan every disk with a virus-checker ?! - Of course I know... Relax... My virus is undetectable... It is disguised like a game. - Ok... Ok... - said Gundsen, starting to walk again. We were almost two steps away from the wall of the prison, when Karl spotted a droid above the wall, with it's eyes fixed on our position. - A guard drone... The prison is managed by them... - I said, in a normal voice. - I think it is deactivated by my virus... As all the other parts of the prison. I took a lazer gun out of my pocket and I started blasting the wall... No guards appeared. It seemed my virus worked. We got into the prison, and within minutes, we opened the doors to every cell in the complex, making every prisoner there run away. I smiled, thinking of the work Comptel would have to arrest them all again... Deathripper found his sister, and we all ran away to the the jetcar. As we all returned to the Brotherhood of the Rebel Programmer home base, I was wondering if it was a good idea this new aquisition... See you in the next issue Diogo "SpellCaster" Andrade