home *** CD-ROM | disk | FTP | other *** search
Text File | 2010-12-05 | 84.1 KB | 1,997 lines |
- 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 9
- 20-7-96
-
-
- -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
-
-
- Index:
-
- 1. Introduction
- 1.1. About the magazine
- 1.2. About the author
- 1.3. Distribution
- 1.4. Subscribing
- 1.5. Contribuitions
- 1.6. Hellos and greets
- 2. Mailroom
- 3. The Turbo Assembler Bible
- 4. Designing a text adventure - Part II
- 4.1. Looking at a room
- 4.2. Player input and the command parser
- 4.3. Basic movement commands
- 5. How to make a 100% assembly program
- 6. Scrolling horizontaly in text mode
- 7. Sprites Part II - Animation and movement
- 7.1. Animating a sprite
- 7.2. Moving a sprite
- 7.3. Doing it all together
- 8. Graphics Part VIII - Text in graphic mode
- 8.1. Basics
- 8.2. Fixed sized fonts
- 8.3. Proportional fonts
- 8.4. Colorfonts
- 9. Hints and tips
- 10. Points of view
- 11. The adventures of Spellcaster, part 9
-
-
- -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
-
-
- 1. Introduction
-
- 1.1. About the magazine
-
- Welcome to number 9 of 'The Mag', brought to you, as usual, by Spellcaster,
- alias Diogo de Andrade. Big issue... Again... This is becomming a hobbit...
- Ooopss... Sorry, a habbit... :))) I'm reading Tolkien, so this is an
- understandable mistake... :)
- This issue is _VERY_ late... This is another hobbit... :)) It is late
- because I have lots of projects and exams to do and I don't have the time.
- Also, this issue features another article by Scorpio, which like the last
- one, is pretty different from the usual...
-
- You should be reading this issue in the first of the SpellUtilities,
- SpellView ! It's a program designed to view text with some features, like
- colors and other neat stuff... :)
- You probably can get it from the same place you got this issue, but if you
- can't, look in the BBS's listed somewhere in this issue, or look in my
- HomePage... It includes full source code, so you can change it, and see how
- it was done... :)
-
- Well, thinking better, don't use SpellView... SpellView SUCKS ! I only
- now noticed that it screws up with files with a certain size... And this
- issue is very big for SpellView to read it... Shit... Well, back to the
- old drawing board... :(((
-
- Ok, other notice... You can use SpellView, but only version 1.2... That's
- a fixed version that saves up some memory... It can read files almost three
- times larger than version 1.1 could... :)))
-
- 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.
-
- 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 Setubal, 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 Setubal 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-190). 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
- month, maybe more, probably less (Eheheheh). This is getting to an issue
- every two months, so, I'll think I'll change the above text... :)
- '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.
-
- - Internet : You can access the Spellcaster page and take the issues out
- of there in:
-
- http://alfa.ist.utl.pt/~l42686
-
- Follow the docs link...
-
- - Anonymous ftp: I've put this issue of 'The Mag' on the ftp.cdrom.com
- site... I don't know if they'll accept it there, because
- that's a demo only site, and my mag doesn't cover only
- demos, but anyways, try it out... It has lots of source
- code of demos.
-
- 1.4. Subscribing
-
- If you want, I'm starting "The Mag"'s subscription list... To get 'The Mag'
- by Email every month, you just need to mail me and tell me so...
- Then, you will receive it every time a new issue is made...
-
- 1.5. 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.
-
- If you have a BBS and you want it to include this magazine, feel free to
- write me... I don't have a modem, so I can only send you 'The Mag' by Email.
-
- 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... Yes, the one that is skipping classes to
- code his (first) next demo !! :)
-
- My adress is:
- Praceta Carlos Manito Torres, nº4/6ºC
- 2900 Setúbal
- Portugal
-
- Email: l42686@alfa.ist.utl.pt
-
- And if you want to contact me on the lighter side, get into the Lost Eden
- talker... To do that telnet to:
-
- Alfa.Ist.Utl.Pt : Port 1414
-
- If that server is down, try the Cital talker, in
-
- 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.6. 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), Joao 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 !
-
- -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
-
-
- 2. Mailroom
-
- Ok, let's open up some mail... The first is from Ben Basset from Australia:
-
- -------------------------------------------------------------------------------
- First of all let me say G'DAY from me...Ben Bassett from West Australia.
-
- I started reading through your "The Mag" magazines sometime last week.
- I am currently studying Computer Science at Curtin University, so I already
- know most of the Pascal stuff. I'm learning about the mode 13h graphics
- mode from your tutorials. I'm currently working my way through issue 7,
- and my goal is to produce a half-way decent demo or game.
-
- I like your style of writing, informal yet informative, keep up the good
- work!
-
- Down to business - Circles issue 4.
-
- Note: What I write below is an observation that I made while looking
- through issue 4. I think I'm on the right track here, but if not,
- you can throw this heap of utter bollocks in the trash.
-
- *********
- I notice when you pre-generate the sin and cos values, you use
- 1800 reals for each. I think this may be a mistake. If you are
- using a radian gap of 0.005, you only need 1257 points to draw
- all the way around the circle. eg. (2*PI)/0.005 = 1256.637
-
- What you are doing when you use 1800 points is that every point
- beyond 1257 (ie. points 1258 to 1800) is drawing over a point
- that you have already plotted. You only need 1257 to reach
- 2*PI. Here's what I've done:
-
- Declare 2 constants:
-
- radian_gap=0.005;
- number_circle_points=round((2*PI)/radian_gap)+1;
-
- and use number_circle_points wherever you used to put 1799
- ie. for i:=0 to number_circle_points do
-
- you should use this when getting the memory for the sin and cos
- arrays, and also when plotting the points themselves.
-
- I tried this out on your Tunnel.pas demo, and got around 30%
- speed-up when drawing the circles.
-
- *********
-
- Well, thats about it for the serious stuff (I'm not very serious
- by nature anyway). Hope to see some cool stuff in future mags!
-
- --Ben Bassett.
-
- -------------------------------------------------------------------------------
- Ok, Ben, you got me there... I guess I made the mistake because I used a
- diferent step in my first calculations... Well, thanks for the mistake
- correction... :)
- Just to prove I'm human...
-
- The second letters comes... Let me see... Oh, Ben Basset again... :)))
-
- -------------------------------------------------------------------------------
- I forgot to mention that you should set the circle_point_gap (or whatever
- I called it) to reflect the maximum size of circle you want to draw.
- There's not much point in plotting thousands of points for circles with
- radius 4. In general I have experiented and come up with the following
- values:
-
-
- circle_point_gap radius of circle
-
- 0.1 less than 8
- 0.05 less than 13
- 0.01 less than 49
- 0.005 less than 97
- 0.001 pretty much any size.
-
-
- I only mention this because it saves time and memory (and I LIKE time
- and memory!).
-
- --Ben Bassett
-
- -------------------------------------------------------------------------------
- Well, another smart remark... Time and memory are _VERY_ important, and
- they are often opposites to each other (this is, when you want more speed,
- you have less memory, and vice versa)... But in this case, he won both...
- Is this guy learning ? He should be teaching me... :)))
- Well, that's the end of this issue's mailroom...
-
-
- -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
-
-
- 3. The Turbo Assembler Bible
-
- Ok, this is the article writen by Scorpio (Yuppi, less work for me !). I,
- Spellcaster will make my coments between square brackets []...
- Your cue, Scorpio...
-
- Allright... I'm writing another article today... I was writtin' one
- about 3DStudio, but I think that I don't have enough knowledge about 3DS to
- make an article... Just some Texture-mappings, etc... If you still think
- you could use such an article, email me and I'll be happy to send it to
- Spellcaster so that he puts it in the next issue(or so) of THE MAG .
-
- [ Write it !!! Less work for me, and a more general mag ! ]
-
- Let's get to the point, now... This is an article 'bout an Assembly
- book I'm currently reading. It is called "The Waite Group's Turbo Assembler
- Bible", a (+-)720 pages and (+-) 1.5Kg book...:)
- It was printed in 1991, its author is Gary Syck, which was working
- in various data-communications programs but that also was into graphics
- programming. The book follows the usual (academic) guidelines, and here are
- the various chapters:
-
-
- o Chapter 1: Programming the MS-DOS systems
-
- Overview of the MS-DOS Operating System
- Segments & Offsets, registers, PSP, DOS file system, etc...
-
- [ It would be very nice to see an article on the PSP... They are
- rare... HINT, HINT ! :)))) ]
-
- Introduction to Using Turbo Assembler
- Let's not forget that this is a book on TASM...
- Introduction to the Turbo Debugger
- Same as above.
-
- o Chapter 2: Processor Instructions
- Data Movement instructions
- The name says it all...
- Arithmetic, Logic, Bit-Shift Instructions
- .....
- Procedures, Loops and Jumps
- .....
- Processor control and Protected Mode Operation
- Includes some examples on how to change to Pmode and back
- to Real mode, Pmode specific instructions and some general
- info... It seems short...Also, some code to switch through
- various tasks...
-
- o Chapter 3: TASM Directives and Operators
-
- Segment declaration
- .......
- Code generation, error handling, .....
-
- o Chapter 4: Techniques
-
- Writing ASM modules for HLL (High level languages)
- Using system resources
- Acessing and controlling the Hardware
- Video control: Text and Graphics
-
- o Chapter 5: Appendixes
-
- Various TASM/TLINK, ASCII, BIOS/DOS interrupts,etc. tables...
-
-
- Allright... As you've probably noticed I've not included comments for
- some of the chapters... It's like this: I'm reading this book page by page,
- and I'm goin' very slowly... between university projects and commercial work,
- I have so little time left to read... I just can't wait to get to the PMODE
- section... Maybe (_MAYBE_) I'll do an article on it... Ok... I've read the
-
- [ I want that article on Pmode, pronto ! :)) ]
-
- first and a bit of the second chapter, and it follows the usual conventions:
- Memory segmentation, registers, flags, etc, etc, etc... it is NOT a book to
- ASM experts, yet it IS a book to ASM experts(or almost-experts).
- Why? Well,it goes from the very basics of a simple printf('Hello\n")
- (I wrote a line in C in this article???? I must be sick... :)) to some stuff
-
- [ You are definetly sick !! No more C ! Please, I hate C... Great language,
- but I don't like anyway... C is forbidden in 'The Mag'... And maybe...
- Hum... Just had an ideia... Maybe I'll do a C version of 'The Mag'...
- What do you people out there think ?? ]
-
- 'bout system resources (LIM EMS usage, mouse programming, COM, etc)...to
- PMODE, to Breshenham's line drawing algorithm, palette handling... There are
- lots of stuff to the newbies and it is also a good book for a later reference
- on some subjects...
- All of these chapters are presented in an informal way (the one we
- like :)) and easy to understand...So, if you can't find a book around there,
- check your university library, 'cos you would be surprised with what you can
- find there... I got this book from University of Minho's library... Don't know
- if anyone is from around here, but if u are... check this one out.
-
- [ IST library sucks big time !! ]
-
- Final considerations: THIS IS NOT A MUST-GET book... try PC Magazine's
- lab book, or some other... Anyway, if you can get your hands on it... don't
- loose the opportunity.
-
- WOW!!! 79 lines??? I can't believe I'm not sleeping by now...
- It's 3:36 a.m. and I have to wake up at 6:30 tomorrow... er... today...
- .. er... in 3 hours... Gotta go, ppl... PLZ let me know if you like (or not)
- this article... PLZ no more flames... I get enough already... Do you know
- what I mean, Spellcaster? Unfortunately, you do...
-
- [ I sure do, man... :((( ]
-
- Well, since I am goin' to sleep now, I'd better save this before falling
- with my face in the keyboard..r n,iuooooooooqdxoewqiyh.wizs n.wqpw OOPS!
- sorry 'bout that... CYA next time... (I hope).
- If you wanna tell me anything at all, email to: si17899@ci.uminho.pt
- (preferred) or si17899@thor.di.uminho.pt or try to find me in Moosaico (a
- Moo) at: moo.di.uminho.pt 7777 under the name of (guess:) Scorpio.
-
- [ I'm there too, sometimes... :) ]
-
- It's me, Spellcaster again... Just to say my end phrase:
-
- T-t-t-t-t-h-a-t's all folks ! :))))
-
-
- -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
-
-
- 4. Designing a text adventure - Part II
-
- This article is intended for the beginners who want to do games. I know
- that text adventures are definetly out, but the ideas behind a text adventure
- are very similar to those found in graphic adventures, so what I say here
- can be expanded to a graphic adventure...
- Note that these are my personal views on how a text adventure should be
- coded and designed...
- There can be some errors and irregularities in the code and explanations,
- because I'm writing this at the same time I'm coding the adventure, so I
- will sometimes make mistakes... If you spot one, or have any doubts, mail me !
- This particular issue is about the parser and basic commands.
-
- 4.1. Looking at a room
-
- Well, one the first thing your text adventure makes is 'looking' at the
- starting room... By 'looking at a room' I mean 'describe the current room'.
- By describing a room, I mean to output the description of the room, the
- objects that there exist, any monsters and other game characteres... Well,
- as we aren't dealing with monsters, objects and characteres, we'll simply
- output the description of the room, that is stored in Rooms[].Desc array...
- So, let's make the look procedure:
-
- Procedure Look(RoomNumber:Word);
- Var A:Byte;
- Begin
- Writeln;
- A:=1;
- While (A<11) And (Rooms[RoomNumber].Desc[A]<>'*') Do
- Begin
- Writeln(Rooms[RoomNumber].Desc[A]);
- Inc(A);
- End;
- Writeln;
- End;
-
- If you are wondering why don't you use just a For loop for writing the
- ten-line description, remember that the description can have less that 10
- lines, and in that case, the last line has a '*' character only...
- Ooopsss... I almost forgot to describe the exits... To do so, add the
- following lines:
-
- Writeln('Visible exits:');
- If Rooms[RoomNumber].North<>0 Then Write('North ');
- If Rooms[RoomNumber].South<>0 Then Write('South ');
- If Rooms[RoomNumber].East<>0 Then Write('East ');
- If Rooms[RoomNumber].West<>0 Then Write('West ');
- Writeln;
-
- To hilite this info, use a different color, like this... Add before
- describing the room:
-
- TextColor(White);
-
- And before the exits description:
-
- TextColor(Yellow);
-
- And everything will be a lot nicer... :)
- To use this, you must implement the Play procedure, that will mantain the
- core of the game... For the meanwhile, all the Play procedure does is to
- output the description of the room...
-
- Procedure Play;
- Var ExitFlag:Boolean;
- Begin
- ExitFlag:=False;
- Look(CurrentRoom);
- Repeat
- Until ExitFlag;
- End;
-
- The ExitFlag is a flag that controls the exit of the game... When it is
- set to true, the game will cease it's execution... It can be put to true
- because the players quits or wins the game...
- Then you must add to the main program a call to this procedure, and you
- must define and initialize the CurrentRoom variable... CurrentRoom stores
- the current position of the player in the game, so I make it a variable of
- type Word... And you must initialize it to the value 22, because that is the
- starting room in FangLore... Do that in the Init procedure...
-
- 4.2. Player input and the command parser
-
- Now, it is the time to receive input from the user... This is were lots
- of game fail... Why ? Because their command parser suck !!!!
- What's the command parser ?
- Well, the command parser is a procedure (more like a bunch of procedures)
- that get the input of the user, process it (separating commands and
- subjects) and then executes the instructions required... Well, I think this
- is a quite nifty thing to do for a begginner, so I'll try to explain this
- well enough...
- First thing, you must receive the input of the player... You do that using
- the Readln keyword (most adventure games have their own routines to read
- player input, but I think that's a lot more complicated to explain simply
- here).
-
- ReadLn(Command);
-
- You put this in the Play command, after the call to the Look procedure.
- You must define the Command variable as a string...
- I gave a little color to this Readln statement in the Fanglore.Pas program:
-
- TextColor(LightRed);
-
- And I also put it a prompt, so that the player knows that the game is
- awaiting input:
-
- TextColor(White);
- Writeln('What is thy bidding, master ?');
-
- Then, the next step is to split that string in it's components... The ideia
- is to, given a string like this:
-
- 'Get the mask'
-
- you get it splitted in only the words 'get' and 'mask'... The 'the' would
- vanish, like all the prenoms (I don't know if this word exists... It's similar
- to the portuguese one... :))).
- So, let's do a procedure that given a string, returns an array with the
- words separated:
-
- Procedure Parse(S:String;Var Parsed:Array[1..10] Of String);
-
- We use a procedure with a Var parameter instead of a function, because a
- function can't return a whole array... You can't even do it like it is
- above... You must define a type like this:
-
- Type ParsedType:Array[1..10] Of String;
-
- And then you can define the procedure like this:
-
- Procedure Parse(S:String;Var Parsed:ParsedType);
-
- Now, the first thing to to is to split the phrase in it's components...
- You achieve that by searching for the first space, and getting what's in
- the string from the beggining to the position of that space, and placing it
- in the array, and so forth...
- The complete procedure is like this:
-
- Procedure Parse(S:String;Var Parsed:ParsedType);
- Var ArrayIndex:Byte;
- StringIndex:Byte;
- NextSpace:Byte;
- Begin
- ArrayIndex:=1;
- StringIndex:=0;
- NextSpace:=FindSpace(S,StringIndex);
- While (StringIndex>=Length(S)) And (ArrayIndex<11) Do
- Begin
- NextSpace:=FindSpace(S,StringIndex);
- Parsed[ArrayIndex]:=GetString(S,StringIndex,NextSpace);
- StringIndex:=NextSpace;
- Inc(ArrayIndex);
- End;
- End;
-
- This parses the string... It uses two functions, FindSpace and GetString,
- whose code is given next... The first of these finds the next space after
- the given starting location, while the other grabs a part of a string.
-
- Function FindSpace(S:String;Start:Byte):Byte;
- Begin
- While (S[Start+1]<>' ') And (Start<Length(S)) Do Inc(Start);
- FindSpace:=Start;
- End;
-
- Function GetString(S:String;Start,Finish:Byte):String;
- Var A:Byte;
- Tmp:String;
- Begin
- Tmp:='';
- For A:=Start+1 To Finish Do Tmp:=Tmp+S[A];
- GetString:=Tmp;
- End;
-
- Don't to forget to call the Parse procedure after you read the command:
-
- Parse(Command,Parsed);
-
- And remember also to define the Parsed array:
-
- Var Parsed:ParsedType;
-
- Now, you have an array with the parsed command... You must now convert all
- to uppercase... Why ?
- Well, because you don't want the program to tell you to take a hike if you
- write 'get' or 'Get' instead of 'GET'... Don't forget that uppercase and
- lowercase are very different to the computer...
- So, let's use the Upper procedure to do so:
-
- Function Upper(S:String):String;
- Var Tmp:String;
- A:Byte;
- Begin
- Tmp:='';
- For A:=1 To Length(S) Do Tmp:=Tmp+UpCase(S[A]);
- Upper:=Tmp;
- End;
-
- The UpCase function is a standart Pascal function that converts a character
- that is in lowercase to uppercase, not affecting special simbols and the
- uppercase characteres... Call the Upper procedure for every element of the
- Parsed array, after you parse the command.
- Now, you should eliminate all the prenoms of the parsed array:
-
- Procedure EliminPrenoms(Var Parsed:ParsedType);
- Var A:Byte;
- Begin
- For A:=1 To 10 Do
- Begin
- If Parsed[A]='THE' Then Elimin(Parsed,A);
- If Parsed[A]='A' Then Elimin(Parsed,A);
- End;
- End;
-
- You should make an If to every word you want eliminated... I don't recall
- any more at this time... The Elimin procedure is a procedure that given a
- variable of type ParsedType and an index number, it eliminates the word
- corresponding to that index... It works by filling that position of the
- array with the next position of the array, that is filled with the one after
- it, and so forth...
-
- Procedure Elimin(Var Parsed:ParsedType;Var Index:Byte);
- Var A:Byte;
- Begin
- For A:=Index To 9 Do Parsed[A]:=Parsed[A+1];
- Parsed[10]:='';
- Dec(Index);
- End;
-
- The two variables in this procedure passed by reference (using the Var
- keyword), because we need to decrement the Index after each call to this
- procedure, because the procedure changes the parsed array... I'll do an
- example, imagining that the Parsed array has only four elements...
- Imagine that the phrase given was 'Spellcaster The The Best'. So, the
- parsed array would be like this:
-
- 1:Spellcaster
- 2:The
- 3:The
- 4:Best
-
- So, the EliminPrenoums would scan the parsed array, starting on index 1.
- Seeing the word 'Spellcaster', it would increase the index. Now index=2.
- Then, it would see the word 'The'... It would call the Elimin procedure,
- and the parsed array would be like this:
-
- 1:Spellcaster
- 2:The
- 3:Best
- 4:
-
- But, if you don't pass the Index by reference and decreased in the end of
- the Elimin procedure, the index would be incremented and would be equal to
- 3 now, so it would skip the 2nd 'The'... So, if you decrease the Index, you
- will be again in Index=2, so the second 'The' is eliminated also... Cool,
- isn't it ?
- Don't forget to call the EliminPrenoms after the other parsing procedures.
- Now probably you have in index 1 of the array the main command, and in
- the other indexes you have the name of the object in which the action will
- be performed, etc...
- Now, you should have a flag that is set when a command is executed
- sucessfully, and when the variable is not set, you should give out an error
- message saying that you didn't understand the command... Define it as a
- variable of type Boolean, and set it to false just after the Repeat keyword.
- Then, every time you execute a command, set it to true, and in the end,
- just before the Until keyword, check if it is true... If it isn't, type out
- an error message... You could even alter the error messages, so that the
- player don't grow tired of the same message over and over again !
- In the example program, the program selects randomly one of two 'Unknown
- command' irritating phrases... :)
-
- Now, let's implement two simple commands... The Look command and the Quit
- command... These should be easy to compreend... Just add the following lines
- to the program, after it parses the phrase:
-
- If Parsed[1]='LOOK' Then
- Begin
- Valid:=True;
- Look(CurrentRoom);
- End;
- If Parsed[1]='QUIT' Then
- Begin
- Valid:=True;
- TextColor(BrightRed);
- Writeln;
- Writeln('Are you sure you want to quit FangLore (Y/N) ?');
- C:=ReadKey;
- If UpCase(C)='Y' Then ExitFlag:=True;
- End;
-
- Define the variable C as a variable of type Char...
- And voila'... Two commands !! Fanglore is really shaping up... :)))
-
- 4.3. Movement commands
-
- Well, this is fairly obvious to do... You just have to check if the
- corresponding word as been pressed (i.e. 'North', 'N', 'South', etc...), and
- if there is an exit that way, make sure it goes that way... If it goes that
- way, then look at the room... Coding wise:
-
- If (Parsed[1]='N') Or (Parsed[1]='NORTH') Then
- Begin
- If Rooms[CurrentRoom].North=0 Then
- Begin
- TextColor(LightRed);
- Writeln;
- Writeln('Sorry, oh Great Lord, but I can''t go that way !');
- Writeln;
- End
- Else
- Begin
- TextColor(LightRed);
- Writeln;
- Writeln('You go north...');
- CurrentRoom:=Rooms[CurrentRoom].North;
- Writeln;
- Look(CurrentRoom);
- End;
- Valid:=True;
- End;
-
- And do likewise for the other three directions... Cool, isn't it ?
- Well, so you can look, quit and wander in Fanglore... In the next article
- of the series, I will delve into objects and their interection...
- Every piece of this issue's code is added to the FangLore program, that
- you should get with the ZIP file...
-
-
- -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
-
- 5. How too make a 100% assembly program
-
- Ok, this is going to be a short article, since I'm writing this at 22:00,
- and I must wake up at 5 am tomorrow... I'm feeling sleepy just thinking
- about it...
- Well, this article is about coding an 100% assembly program, but I guess
- you knew that already because of the title... Well, I'll add some information
- that isn't on the title... When I say '100% assembly program' I mean a
- program out of Turbo Pascal !!!! Yuppy !!! No Pascal... Ehhehehe... Don't
- take me wrong, Pascal is a great language, but assembly is even better for
- _REAL_ coders... :)))) Ok... Enough for fun... Let's get started...
-
- First of all, I'll will show you the frame for the vast majority of
- assembler programs, and then I will explain it:
-
- DOSSEG
- .MODEL SMALL
- .286
- .STACK 200h
-
- .DATA
-
- .CODE
-
- START:
- END START
-
- You should use your favorite text editor (one that save in ASCII format...
- I usually use Turbo Pascal 6.0 !!! ) to type this up, then save this file
- with any name (example: Test.Asm).
- Then, if your using TASM, you should do something like this in the DOS
- prompt:
-
- TASM Test.Asm
-
- The program would compile and a new file, called Test.Obj would be
- created... Then you should LINK it (in other issue I will explain what this
- is)... You should use:
-
- TLINK Test.Obj
-
- Then, miracle of miracles ! The Test.Exe file will appear and you can
- execute it !!!!
- Now, I'll explain what each of those commands do...
-
- DOSSEG - Tells the compiler to organize the segments in your program like
- DOS and other high level languages (like Pascal and C) do, that
- is it creates three segments (code, data and stack).
-
- .MODEL - Tells the compiler in which model to compile.
- The model can be though as segment limitations...
- If the model is TINY, the code plus data must be smaller than
- 64 Kb (this is, by definition, a COM file). If the model is
- SMALL, the code and the data (separetly) can have a maximum of
- 64 Kb. Other modes are:
-
- MEDIUM: Code > 64 Kb Data < 64 Kb
- COMPACT: Code < 64 Kb Data > 64 Kb
- LARGE: Code > 64 Kb Data > 64 Kb
- HUGE: Code > 64 Kb Data > 64 Kb Arrays > 64 Kb
-
- LARGE and HUGE models are equivelent, but the later is used by
- high level languages. It isn't of no use to us...
-
- .286 - Enables 286 instructions... It can be .386, .386P (for protected
- mode), etc... I usually use .386... If you don't put anything, the
- compiler will assume 8086 instructions...
-
- .STACK - Tells the compiler the size of the stack, in bytes... I will
- discuss the stack later. I usually use 200h (that's about
- 512 bytes).
-
- .DATA - Tells the program that the following 'stuff' (you will see what is
- the stuff later) is to be placed in the data segment.
-
- .CODE - Tells the program that the following 'stuff' is to be placed in
- the code segment.
-
- START: - Tells the compiler where the main program begins.
-
- END START - Tells the compiler that this is the place where the code ends.
-
- I will explain most of this stuff in greater detail later. Right now, if
- you compiled this and run it, you would expect it to just do nothing and
- return to Dos... You're partially right... It doesn't do nothing, but it
- doesn't return to Dos either !!! Why ? Because assembler programs are so
- stupid that they must tell Dos that they are over... To do that, you must
- call the Dos interrupt 21h, function 4c, to end the code... So, to do nothing
- and return to dos, the program would have to be something like this:
-
- DOSSEG
- .MODEL SMALL
- .286
- .STACK 200h
-
- .DATA
-
- .CODE
-
- START:
-
- Mov AX,4c00h ; This is a comment... Anything after a semi-
- ; -colon will be ignored... Just to tell you
- ; that 4c00h is an hexadecimal number...
- Int 21h
-
- END START
-
- The 'Mov AX,4c00h' command moves to the AX register (I think I already
- told you what a register is) the value 4c00 in hexadecimal (19456 in
- decimal)... I know I told you that the function number is 4c, but this is
- to be put in the high part of the word AX... The low part is the exit-code
- (in this case, it is 0) and is to be used in by parent programs, that is,
- programs that call other programs.
- The 'Int 21h' command, calls interrupt 21h (the Dos interrupt)... More on
- it later...
- Well, it's just 23:00... I think I'm going to bed know... I'll finish this
- tomorrow... Yawn !!! :)))
- Ok, I'm back... I fell a lot better now, after a good (but short) night of
- sleep... Now, I'll talk about the stack...
-
- The stack is a very important part in your program... It's a wonderfull
- place where you can store stuff you will need later. I've talked about the
- stack in issue 3 of 'The Mag'... Ehehehe... This was short...
-
- Now, about the 'stuff'... In assembler, you can also define variables,
- altough it is a bit more complicated subject... Variables in assembler
- are composed by an identifier (like Pascal identifiers), and a type:
-
- DB - Byte
- DW - Word
- DD - DoubleWord
-
- So, no strings or chars... Just plain numbers... Arrays are also defined
- in a different way... But, let's take a step at a time:
-
- Spell DB 10
- VidSeg DW 0a000h
- Large DD 010101010101001b
-
- These lines define three variables, named Spell, VidSeg and Large, of
- types Byte, Word and DoubleWord, respectively, and with initial values
- 10, 0a000 (hexadecimal) and 010101010101001 (binary). If you don't want to
- assign an initial value, just put a '?' there... Example:
-
- Spell DB ?
-
- To access the value of a variable, you put the name of the variable
- in square brackets... Example:
-
- Mov AX,[VidSeg] -> This would load the value of variable VidSeg
- in register AX... Remember that there exist
- some commands that don't work with variables.
-
- One important thing to notice is that how data is organized in an asm.
- For example, imagine you made the program like this:
-
- .Data
- Spell DB 10
- VidSeg DW 0a000h
- Large DD 010101010101001b
-
- This means that the variables are in the Data segment. And now for the fun
- stuff... The address of variable Spell:
-
- Segment: DS (Data Segment)
- Offset : 0000
-
- Cool, isn't it ? But that's not all... Addresses of variables VidSeg and
- Large:
-
- Seg(VidSeg)=DS Seg(Large)=DS
- Ofs(VidSeg)=0001 Ofs(Large)=0003
-
- What can you make of this ? That memory addressing is sequencial !!! That
- can be usefull, for accessing arrays... But I'll talk about them later. For
- now, let's talk about tables. Do you knew that you could have something like
- this:
-
- Vector1 DB 10,20,30
- DB 20,10,30
- DB 30,30,20
-
- Imagine that as a triangle defined by it's corners, with it's (x,y,z)
- coordinates... You can have all that in just one variable. To access, for
- example, the y coordinate of the second corner (the 2nd value of the 2nd
- line), you would have to do something like this:
-
- Mov AX,[Vector+4]
-
- If the variable was defined as Words (DW) and not bytes (DB), you would
- have to add 8 to the base address of the variable, that is stored in Vector.
- So, really, Vector is a pointer to the first element of data after it's
- definition... [Vector] is the real value of the element (in this case 10).
- Vector+1 would point to the 2nd element, Vector+2 to the 3rd, etc, while
- [Vector+1] would return the 2nd value, [Vector+2] the 3rd, etc...
-
- Now, let's go to arrays... To define a one-dimensional array, you use use
- the 'dup' keyword... Example, to define an array with 100 elements of type
- Word, you would do:
-
- SpellArray DW 100 Dup(0)
-
- This would make an array initialized with zeros... If you wanted to create
- an unitialized array, you would have to use a '?' instead of a '0'.
- SpellArray will now point to the first element, etc...
- To define a two-dimensional array, you would use... well, I'd rather
- demonstrate... Imagine you want to define a 100x50 array (100 columns, 50
- lines). You would do it like this:
-
- SpellArray DW 5000 Dup (?) ; Because 100*50=5000
-
- Surprise !! No two-dimensional arrays... But you can use a trick to
- simulate them... Remember the first article I did on mode 13h ? Well, this
- is similar... Imagine youwant to access the element Xth element of line Y.
- You must multiply the Y for the size in columns of the array, and then add
- the X... For example:
-
- Mov AX,[SpellArray+Y*100+X] ; would load AX with the value of
- ; element desired.
-
- So, I think that it is all said now...
- Check out the example program FLSCR.ASM, that fills the screen in mode 13h,
- with random colors... Notice on how fast it is... :) God, I love assembler...
- Toy with it... In the worst case, you'll crash up your computer and nuke
- your hard drive (you don't knwo how easy is to do this... :))
- Cya in another article...
-
- -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
-
-
- 6. Scrolling horizontaly in text mode
-
- Well, this article is made to order... :)
- It's quite easy to scroll horizontally text, altough it is complicated
- (I don't think it's even possible) to do it smoothly in text mode. By
- smoothly I mean to make appear a pixel at a time... I only know how to do
- scrolling in text mode making a character appear at a time (though I'm
- currently studying the possibility of doing this a pixel at a time... Not
- much success, though ! :).
- The ideia is this... You have a string S:
-
- S:='Spellcaster can''t code anything in Pascal, let alone ASM !';
-
- And you want to scroll it around a window with only 10 characteres wide.
- What you have to do is this:
-
- | |
- | | <---- This represents the screen...
- | |
-
- | |
- | |Spellcaster can''t code...... (the text is off screen)
- | |
-
- | |
- | S|pellcaster can''t code......
- | |
-
- and later you have:
-
- | |
- Spel|lcaster ca|n''t code......
- | |
-
- Get the picture ? You must choose what piece of text to display...
- So, some code (I'll use the GetString function from the article number 4).
-
- Program HScroll;
-
- Uses Crt;
-
- Const WhereX=10; { X coordinate of scroller }
- WhereY=10; { Y coordinate of scroller }
- NChars=10; { Number of characters to display at one time }
-
- Var S:String;
- Index:Byte;
-
- Function GetString(S:String;Start,Finish:Byte):String;
- Var A:Byte;
- Tmp:String;
- Begin
- Tmp:='';
- For A:=Start+1 To Finish Do Tmp:=Tmp+S[A];
- GetString:=Tmp;
- End;
-
- Begin
- S:='Spellcaster can''t code in Pascal, let alone ASM ! ';
- Index:=1;
- Repeat
- { Scroll the area we want to the left }
- Move(Mem[$B800:((WhereY*80)+WhereX+1)*2],
- Mem[$B800:((WhereY*80)+WhereX)*2],NChars*2);
- { Write the character that enters by the right }
- GotoXY(WhereX+NChars+1,WhereY+1);
- Write(S[Index]);
- Inc(Index);
- If Index>Length(S) Then Index:=1;
- { Put a small delay, so that you can actually read }
- { something... }
- Delay(50);
- Until KeyPressed;
- End.
-
- You can add a little color, if you want... It would be nicer... :)
- If you are wondering why you multiply by two when you are converting (X,Y)
- coordinates to an Offset value, you must know one thing:
-
- Text mode is very similar to graphics mode in the memory adressing with
- some differences:
-
- - Base address is B800, not A000 like in mode 13h
- - You have two bytes per character, not one byte per pixel.
- The first byte stores the ASCII value of the character, while the second
- byte stores the attributes. The attributes in text mode are: the
- foreground color (the text color), the background color, and if that
- character blinks or not...
-
- So, you can directly access Text Memory, and that's the reason why I
- multiply by two the calculations... The rest is similar to mode 13h.
- The attribute byte is organized like this:
-
- Bit No. 7 6 5 4 3 2 1 0
-
- Bits 0-3 are the foreground color (16 colors possible).
- Bits 4-6 are the background color (8 colors possible).
- Bit 7 is the blinking attribute (if it is set, the text will blink).
-
- I think this is fairly simple... Any doubts, mail me... :)
-
- A last minute correction... I've stated in the beggining of this article
- that I didn't think that scrolling smoothly in text mode was possible...
- Well, I was wrong... A friend of mine did it... At least, he says he did it.
- I didn't had the chance to see it, but I'll try to, and to get the code
- also... If I understand it, I will do an article on that...
-
-
- -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
-
-
- 7. Sprites Part II - Animation and movement
-
- So, let's continue our sprite tutorial... In this issue, we'll discuss
- basic animation and movement control... We'll use the procedures in the
- Sprite unit I gave last issue... Let's start with...
-
- 7.1. Animating a sprite
-
- Animation is what you see in a cartoon, right ? WRONG ! In computer terms,
- an animation is... Well...er... it is, for example, a static objects that
- changes itself...
- But, what is animation really ? How can we create it ?
- Well, we use the same principle as the movies... Our eyes have a limit
- number of 'updates' that it can receive... By updates, I mean changes in the
- enviroment... I think the limit is 22 changes per second... The movies, for
- example, change the image 50 or 60 times a second, that is, the image is
- slightly altered 50 or 60 times a second... So, the eyes are deceiveds in
- thinking the image is moving... You change the image rapidly... But, you
- don't need to change the image 22 times a second to obtain an animation...
- You can change it just 1 time a second, or one time every 10 seconds... It
- doens't really matter, altough the movement is smoother if you update the
- image more frequently... But enough talk... Let's get to business...
- I've created two sprites of a spaceship, and they are slightly different
- from each other... So, I will display one after another on the screen, in
- the same coordinate, so you'll get the illusion of animation... The
- procedures are the same used in the last issue of The Mag...
-
- Program Animation;
-
- Uses Mode13H, Sprites, Crt;
-
- Var Images:Array[1..2] Of Pointer;
- F:File;
-
- Begin
- { Initialize graphics and palette }
- InitGraph;
- SetColor(1,63,0,0);
- SetColor(2,63,40,0);
- SetColor(3,63,63,0);
- { Load images from a file }
- Assign(F,'Ship.Img');
- Reset(F,1);
- LoadImage(F,Images[1]);
- LoadImage(F,Images[2]);
- Close(F);
- { Animate them, until a keypressed occurs !! }
- Repeat
- PutImage(160,100,Images[1],VGA);
- Delay(150);
- PutImage(160,100,Images[2],VGA);
- Delay(150);
- Until Keypressed;
- { Wraps things up }
- KillImage(Images[1]);
- KillImage(Images[2]);
- CloseGraph;
- End.
-
- Not too impressive, I know... But it's a start... The next part is
- better...
-
- 7.2. Moving a sprite
-
- Moving a sprite follows the same ideia as animating it... The ideia is
- to move the sprite, draw it, clear it, move it again, and so forth...
- Adapting to the last piece of code... Let's define two more variables,
- X and Ix, of type Word and ShortInt. Initialize variable X with the value 0,
- and variable Ix with value 1. Then, replace the Repeat Until cicle with...
- Or, stuff it, I'll dump here the full code:
-
- Program Movement;
-
- Uses Mode13H, Sprites, Crt;
-
- Var Images:Array[1..2] Of Pointer;
- F:File;
- X:Word;
- Ix:ShortInt;
-
- Begin
- { Initialize graphics and palette }
- InitGraph;
- SetColor(1,63,0,0);
- SetColor(2,63,40,0);
- SetColor(3,63,63,0);
- { Load image from a file }
- Assign(F,'Ship.Img');
- Reset(F,1);
- LoadImage(F,Images[1]);
- Close(F);
- { Move it, until a keypressed occurs !! }
- X:=0;
- Ix:=3; { The bigger the Ix, the faster the sprite will move }
- Repeat
- { Draw it }
- PutImage(X,100,Images[1],VGA);
- Delay(50);
- { Clear it }
- Cls(0,VGA);
- { Update it }
- X:=X+Ix;
- If X>=300 Then Ix:=-3;
- If X=0 Then Ix:=3;
- Until Keypressed;
- { Wraps things up }
- KillImage(Images[1]);
- KillImage(Images[2]);
- CloseGraph;
- End.
-
- Well, this flickers a lot... The way to mend this is by using virtual
- screens, or clear just the part of the screen... You should be able to do
- that yourself... I'm so lazy today...
-
- 7.3. Doing it all together
-
- So, you know how to move it and you know how to animate it... But do you
- know how to do it at the same time ?
- This is easy... For each frame it draws, it shows a picture that has been
- both moved and animated... Let's see some code, because I'm too lazy to
- explain it... and because this is soooo easy:
-
- Program Animation_And_Movement;
-
- Uses Mode13H, Sprites, Crt;
-
- Var Images:Array[1..2] Of Pointer;
- F:File;
- X:Word;
- Ix:ShortInt;
- Pic:Byte;
-
- Begin
- { Initialize graphics and palette }
- InitGraph;
- SetColor(1,63,0,0);
- SetColor(2,63,40,0);
- SetColor(3,63,63,0);
- { Load images from a file }
- Assign(F,'Ship.Img');
- Reset(F,1);
- LoadImage(F,Images[1]);
- LoadImage(F,Images[2]);
- Close(F);
- { Animate them, until a keypressed occurs !! }
- X:=0;
- Ix:=1; { The bigger the Ix, the faster the sprite will move }
- Pic:=1;
- Repeat
- { Draw it }
- PutImage(X,100,Images[Pic],VGA);
- Delay(50);
- { Clear it }
- Cls(0,VGA);
- { Update it }
- X:=X+Ix;
- If X>=300 Then Ix:=-3;
- If X=0 Then Ix:=3;
- If Pic=1 Then Pic:=2 Else Pic:=1;
- Until Keypressed;
- { Wraps things up }
- KillImage(Images[1]);
- KillImage(Images[2]);
- CloseGraph;
- End.
-
- So, here you have it... This is very easy...
- Let's wrap it up... In next tutorial about sprites, I'll teach you how to
- make this move over a background, transparency, and maybe a couple of
- tricks...
-
-
- -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
-
-
- 8. Graphics Part VIII - Text in graphic mode
-
- 8.1. Basics
-
- Text in graphic mode is very different from text in text mode (as the name
- implies)... You can't use the standart function Writeln (that is, you can,
- but it will look UGLY !), nor can you use the Readln (you must program your
- own function to read input in graphic mode).
- It's fairly easy to do text in graphics mode. You just have to take in
- account WHAT do you want to print, WHERE do you want to print it, and with
- what type of character... Yes, you can use various kinds of characters.
- That's one the advantages of using text in graphics.
- To the diferent types of characters (that is, every charset) you call
- a font.
- There are several kinds of fonts:
-
- - Fixed sized fonts -> As the name implies, the characters have all the
- same width and height, not to mention color.
-
- - Proportional fonts -> Characters can have different widths and heights,
- altough usually they only change in width. The
- color is the same in all character.
-
- - Colorfonts -> Colorfonts can be fixed sized or proportional. The only
- difference between this and the last ones I mentioned,
- is that the characters can have different colors... Not
- different from each others, it's different inside them.
- You'll see what I mean latter...
-
- Graphical text can be very important in any kind of program you make;
- almost every demo has a scroller (I'll do an article on them someday), every
- game shows the score or the briefing or something... Trust me... They are
- important... So, let's get down and dirty...
-
- 8.2. Fixed sized fonts
-
- The principle behind this is easy: you use the theory behind the sprite,
- changing the procedures a little (you don't need to read the size of the
- sprite, it's already set; you don't put different colors; you don't use
- pointers, etc...). Let's check out the procedures... Oh, I almost forgot...
- You must create a structure that lets you store the various characters:
-
- Const XSize=16;
- YSize=16;
-
- Type FSFont=Array[1..XSize,1..YSize] Of Byte;
- Chars=array[' '..'º'] Of FSFont;
-
- Var Font:Chars;
-
- In case you're wondering, you can define an array like that... You access
- the elements of the array, like this, for example:
-
- Font['A',10,10]:=10;
-
- Or
-
- C:Char;
- ..........
- ..........
- C:='A';
- Font[C,10,10]:=10;
-
- So, let's read the font:
-
- Procedure LoadFont(Filename:String);
- Var F:File;
- Garbage:Word;
- Begin
- Assign(F,Filename);
- Reset(F,1);
- Blockread(F,Garbage,2);
- Blockread(F,Garbage,2);
- Blockread(F,Ptr(Seg(Font),Ofs(Font))^,Filesize(F)-4);
- Close(F);
- End;
-
- The structure of the file I'm using has it's first four bytes indicating
- the X and Y size of the font (you might need it... In this case it isn't
- needed, so we read them to discardable variables: Garbage). Then it has
- a sequence of bytes indicating if a certain point is on or off... Caution:
- in this case, that isn't the color, but if the pixel is draw or not... We'll
- get to colorfonts soon...
- I'll just explain the instruction that really reads the data:
-
- Blockread(F,Ptr(Seg(Font),Ofs(Font))^,Filesize(F)-4);
-
- Well, I think I've already talked about the Ptr function... Well, the Ptr
- function is usefull to transforms any structure into a pointer. Basically
- what it does is transform two values (segment and offset) in a pointer. If
- you supply the two values as beeing the segment and offset of an existing
- structure (as you do above), and then read to that place in memory, the data
- will be read into that structure... That's quite useful, as you can see... :)
- So, let's move on... Putting down a letter... Nothing could be easier:
-
- Procedure PutLetter(X,Y:Integer;Col:Byte;N:Char;Where:Word);
- Var Cfx,Cfy:Byte;
- Ccc:Byte;
- Begin
- For Cfy:=1 To YSize Do
- Begin
- For Cfx:=1 To XSize Do
- Begin
- Ccc:=Font[N,Cfy,Cfx];
- If Ccc<>0 Then PutPixel(X+Cfx-1,Y+Cfy-1,Col,Where);
- End;
- End;
- End;
-
- Well, what the hell is this ??? Simple... You just scan the array for
- the character you want, then the computer scans the X and Y indexes of that
- particular character... When it finds an element different of 0, it places
- a pixel of the specified color in the VGA screen or in any of the virtual
- screens... Quite easy, I think...
- To write a string, you just have to go through the string, writing the
- characters it founds in sequence. Notice that the increment of the X
- coordinate is fixed, because all the letters have the same size:
-
- Procedure PutString(X,Y:Integer;Col:Byte;N:String;Where:Word);
- Var Index:Byte;
- Begin
- For Index:=0 To Length(N)-1 Do
- PutLetter(X+Index*16,Y,Col,N[Index+1],Where);
- End;
-
- I've included a sample font, to use with the example program, but that font
- only contains uppercase letters, so use if wisely, my sons... I intend to
- release a font editor/grab, together with a sprite editor/graber... Maybe
- I'll ask help from anyone, since I don't have enough time to do all I want...
- But, without further due, here's a complete working example:
-
- Program FixedSizedFont;
-
- Uses Crt,Mode13h;
-
- Const XSize=16;
- YSize=16;
-
- Type FSFont=Array[1..XSize,1..YSize] Of Byte;
- Chars=array[' '..'º'] Of FSFont;
-
- Var Font:Chars;
-
- Procedure LoadFont(Filename:String);
- Var F:File;
- Garbage:Word;
- Begin
- Assign(F,Filename);
- Reset(F,1);
- Blockread(F,Garbage,2);
- blockread(F,Garbage,2);
- Blockread(F,Ptr(Seg(Font),Ofs(Font))^,Filesize(F)-4);
- Close(F);
- End;
-
- Procedure PutLetter(X,Y:Integer;Col:Byte;N:Char;Where:Word);
- Var Cfx,Cfy:Byte;
- Ccc:Byte;
- Begin
- For Cfy:=1 To YSize Do
- Begin
- For Cfx:=1 To XSize Do
- Begin
- Ccc:=Font[N,Cfy,Cfx];
- If Ccc<>0 Then PutPixel(X+Cfx-1,Y+Cfy-1,Col,Where);
- End;
- End;
- End;
-
- Procedure PutString(X,Y:Integer;Col:Byte;N:String;Where:Word);
- Var Index:Byte;
- Begin
- For Index:=0 To Length(N)-1 Do
- PutLetter(X+Index*16,Y,Col,N[Index+1],Where);
- End;
-
- Begin
- LoadFont('Fixed.Fnt');
- InitGraph;
- SetColor(1,63,63,0);
- SetColor(2,63,0,0);
- SetColor(3,0,63,0);
- SetColor(4,0,63,63);
- PutString(0,0,1,'THIS IS A TEST !',VGA);
- PutString(0,30,2,'SPELLCASTER RULES !',VGA);
- PutString(0,60,3,'I KNOW MODESTY IS',VGA);
- PutString(0,90,4,'NOT ONE OF MY',VGA);
- PutString(0,120,5,'QUALITIES...',VGA);
- Repeat Until Keypressed;
- Closegraph;
- End.
-
- So, if this is understood, let's move forward... If it isn't, read it
- again, and experiment !!! Experimentation is the key to good programming
- practice... :)
- I think I'll stop here for now... I'm sleepy (I just write this at night,
- after college, so it's very tiring)... I'll write the next stuff tomorrow...
-
- 8.3. Proportional fonts
-
- I'm back !!! Well, where was I... er... Oh... Proportional fonts... So,
- what's a proportional font ?
- To answear simply... It's a font that isn't fixed in size... So, the x and
- y sizes of the font varie from character to character... Evidently, we can
- not use the same structure as above. But, if the bitmaps for the chars are
- of different sizes, why not use the sprite system implemented in last
- issue ? So, for all chars:
-
- Type Chars=array[' '..'º'] Of Pointer;
-
- So, you read the font to the array of pointers, using the LoadImage
- function that I gave last issue. So, after you read the chars that matter
- (in the example program I'll give, I only read some chars, because I didn't
- had time to draw more chars), you must write them out... To draw _ONE_ char,
- you use the PutImage_C procedure (we use the clipping procedure because we
- don't know if the text is wider than the screen).
- So, the real difficulty is in writing a string. So, when the font was fixed
- sized, you just used the formula:
-
- X:=Xi+CharNumber*XSize
-
- to find out the X coordinate of the character indexed by CharNumber. Xi is
- the original X coordinate (the coordinate of the first character), and XSize
- is the horizontal size of the font. So, if the horizontal size varies, this
- formula must varie. Let's use a variable, that increases with the size of
- the font. For example, we initialize that variable to Xi in the start of the
- WriteString procedure:
-
- X:=Xi;
-
- Then, imagine the first character was 20 pixels wide. We draw it, and then
- add that number to var X:
-
- X:=X+XSize(FirstCharacter)+Space
-
- And so forth... The Space is any number that specifies the number of pixels
- computer should leave between chars... If you don't put it there, the letters
- will be all crunched together...
- See ? Easy... Let's see some _CODE_ !!! :)))
- Oooopppppssss... I almost forgot... We must change the PutImage_C procedure
- for two reasons:
-
- 1) What is saved in the file is whetever a certain pixel is on or off,
- not it's color.
- 2) This procedure erases all background image, and usually text is output
- on the top of an image or something.
-
- When can fix up both problems in just one sitting:
-
- Procedure PutChar(X,Y:Integer;Var Img:Pointer;Where:Word);
- Var Dx,Dy:Word;
- A,B:Word;
- Segm,Offs:Word;
- Begin
- Segm:=Seg(Img^);
- Offs:=Ofs(Img^);
- Move(Mem[Segm:Offs],Dx,2);
- Move(Mem[Segm:Offs+2],Dy,2);
- Offs:=Offs+4;
- A:=Y;
- While (A<=Y+DY-1) And (A<MaxY) Do
- Begin
- B:=X;
- While (B<=X+DX-1) And (B<MaxX) Do
- Begin
- If (X>=MinX) And (Y>=MinY) Then
- { Check if the pixel is to be set or not }
- If Mem[Segm:Offs]<>0 Then
- PutPixel(B,A,Mem[Segm:Offs],Where);
- Inc(Offs);
- Inc(B);
- End;
- Inc(A);
- End;
- End;
-
- Another thing we'll need is a function that returns the X size of a
- certain character. This is easy:
-
- Function GetX(Img:Pointer):Word;
- Var Dx:Word;
- Segm,Offs:Word;
- Begin
- Segm:=Seg(Img^);
- Offs:=Ofs(Img^);
- Move(Mem[Segm:Offs],Dx,2);
- GetX:=Dx;
- End;
-
- Well, this is excessive programming, but... :))) It's easier to
- understand...
- So, the example program:
-
- Program Proportional;
-
- Uses Crt,Sprites,Mode13h;
-
- Type Chars=array[' '..'º'] Of Pointer;
-
- Var Font:Chars;
-
- Procedure ReadFont;
- Var F:File;
- A:Char;
- Begin
- Assign(F,'Proport.Fnt');
- Reset(F,1);
- LoadImage(F,Font[' ']);
- LoadImage(F,Font['!']);
- LoadImage(F,Font[',']);
- LoadImage(F,Font['-']);
- LoadImage(F,Font['.']);
- For A:='0' To '9' Do LoadImage(F,Font[A]);
- For A:='A' To 'Z' Do LoadImage(F,Font[A]);
- Close(F);
- { I just loaded some characters because the file only }
- { had those characters, saved in that order. }
- End;
-
- Procedure PutChar(X,Y:Integer;Col:Byte;N:Char;Where:Word);
- Var Dx,Dy:Word;
- A,B:Word;
- Segm,Offs:Word;
- Img:Pointer;
- Begin
- Img:=Font[N];
- Segm:=Seg(Img^);
- Offs:=Ofs(Img^);
- Move(Mem[Segm:Offs],Dx,2);
- Move(Mem[Segm:Offs+2],Dy,2);
- Offs:=Offs+4;
- A:=Y;
- While (A<=Y+DY-1) And (A<MaxY) Do
- Begin
- B:=X;
- While (B<=X+DX-1) And (B<MaxX) Do
- Begin
- If (X>=MinX) And (Y>=MinY) Then
- { Check if the pixel is to be set or not }
- If Mem[Segm:Offs]<>0 Then
- PutPixel(B,A,Col,Where);
- Inc(Offs);
- Inc(B);
- End;
- Inc(A);
- End;
- End;
-
- Function GetX(Img:Pointer):Word;
- Var Dx:Word;
- Segm,Offs:Word;
- Begin
- Segm:=Seg(Img^);
- Offs:=Ofs(Img^);
- Move(Mem[Segm:Offs],Dx,2);
- GetX:=Dx;
- End;
-
- Procedure PutString(X,Y:Integer;Col:Byte;N:String;Where:Word);
- Var Index:Byte;
- Dx:Word;
- Begin
- Dx:=X;
- For Index:=0 To Length(N)-1 Do
- Begin
- PutChar(Dx,Y,Col,N[Index+1],Where);
- Dx:=Dx+GetX(Font[N[Index+1]])+3;
- End;
- End;
-
- Begin
- ReadFont;
- InitGraph;
- SetColor(1,63,63,0);
- SetColor(2,63,0,0);
- SetColor(3,0,63,0);
- SetColor(4,0,63,63);
- PutString(0,0,1,'GRABING',VGA);
- PutString(0,50,2,'PROPORTIONAL',VGA);
- PutString(0,100,3,'FONTS',VGA);
- PutString(0,150,4,'SUCKS !',VGA);
- Repeat Until Keypressed;
- Closegraph;
- End.
-
- Again, don't use lowercase letters, because they aren't drawn...
- The problem of proportional fonts is that they must well designed, or else
- it will happen to some chars the same as happened to 'u' in the example
- program...
- Proportional fonts are just a variation of fixed sized fonts... Easy and
- effective... Personally, I hate proportional fonts... But if you have enough
- pacience to work with them, go ahead... They always look good...
- Well, I'm going to bed again... I'll finish this tomorrow... It's almost
- 2 am... And I must rise at 5 am... LIFE SUCKS !!!! :))) Cya tomorrow... ;)
-
- 8.4. Colorfonts
-
- Ok, back again... I'm really getting fed up with this issue of 'The Mag',
- so I'm gonna wrap this up really quickly... :))))
-
- Colorfonts are fonts with colors in the same char... So, when you store a
- colorfont, you don't store only if the pixel is on or off, you store it's
- color... So, as I want to get this over, I'll just dump some code onto
- your screen... This is a complete example program, that shows how fixed
- sized colorfonts work:
-
- Program ColorFonts;
-
- Uses Crt,Mode13h;
-
- Const XSize=16;
- YSize=16;
-
- Type FSFont=Array[1..XSize,1..YSize] Of Byte;
- Chars=array[' '..'º'] Of FSFont;
-
- Var Font:Chars;
- CFontPal:RGBList;
-
- Procedure LoadFont(Filename:String);
- Var F:File;
- Garbage:Word;
- Begin
- Assign(F,Filename);
- Reset(F,1);
- Blockread(F,Garbage,2);
- blockread(F,Garbage,2);
- Blockread(F,Ptr(Seg(Font),Ofs(Font))^,Filesize(F)-4);
- Close(F);
- End;
-
- Procedure PutLetter(X,Y:Word;N:Char;Where:Word);
- Var Cfx,Cfy:Byte;
- Ccc:Byte;
- Begin
- For Cfy:=1 To YSize Do
- Begin
- For Cfx:=1 To XSize Do
- Begin
- Ccc:=Font[N,Cfy,Cfx];
- If Ccc<>0 Then PutPixel(X+Cfx-1,Y+Cfy-1,Ccc,Where);
- End;
- End;
- End;
-
- Procedure PutString(X,Y:Integer;N:String;Where:Word);
- Var Index:Byte;
- Begin
- For Index:=0 To Length(N)-1 Do
- PutLetter(X+Index*16,Y,N[Index+1],Where);
- End;
-
- Begin
- LoadFont('CFont.Fnt');
- { Load a palette to use with the font }
- LoadPal('CFont.Pal',CFontPal);
- InitGraph;
- SetPalette(CFontPal);
- PutString(0,0,'THIS IS A TEST !',VGA);
- PutString(0,30,'SPELLCASTER RULES !',VGA);
- PutString(0,60,'I KNOW MODESTY IS',VGA);
- PutString(0,90,'NOT ONE OF MY',VGA);
- PutString(0,120,'QUALITIES !!!',VGA);
- Repeat Until Keypressed;
- Closegraph;
- End.
-
- I know I'm lazy... :))
- This program reads a palette for the color font... You get the ideia when
- you run it...
- Try the program out and experiment stuff, like scrolling text and other
- stuff like that... Scrollies are a part in almost every demo made by men
- and aliens... And colorfonts are usually a part of them... So, I say
- goodbye for now...
-
-
- -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
-
-
- 9. Hints and Tips
-
- * - Begginners tip
- ** - Medium tip
- *** - Advanced tip
-
- This issue's Hints and Tips will go deeper into the subject of using
- logic operators with "normal" numbers.
-
- - Odd or Even ? (**)
-
- Imagine you want to find out if a certain number is odd or even.
- Think of the internal representation of the numbers 50 and 51:
-
- 50 = 00110010
- 51 = 00110011
-
- Have you seen the difference ? An even number has it's rightmost bit
- unset and an odd number has it set... So, how can you check for it ?
- Simple, use the AND operand:
-
- A:=50 AND 1
-
- Now, A is equal to 0, that means that the number is even.
- So, what's the ideia ?
-
- 50 = 00110010
- 1 = 00000001
- 50 AND 1 = 00000000
-
- If we used 51:
-
- 51 = 00110011
- 1 = 00000001
- 51 AND 1 = 00000001
-
- 51 AND 1 would return 1 !!! Cool, isn't it ?
-
- - Positive or negative ? (**)
-
- In the internal conception, integer numbers are represented with 15 bits
- for the value and 1 bit to act as a flag for positive/negative.
- So, knowing that the signal bit is the leftmost, we can use a method
- similar to the one we used to determine if the number was odd or even.
- For example:
-
- -50 = 1000000000110010
- -0 = 1000000000000000
-
- I know that -0 doesn't really exist, but in computer terms it exists.
- Notice this:
-
- -0 = 1000000000000000
- ||-------------|
- Signal Bit Value Bits
-
- So, continuing with the explanation:
-
- -50 AND -0 = -0
-
- Getting a -0 means the number is negative. Otherwise the "function"
- returns a +0.
- Well, but in Pascal you can't use -0 as an operand, so how do you
- resolve the problem ?
- Well, as Pascal is a very flexible language , it can mix integers with
- words (unsigned integers), so integer (-0) is equal word 32768. So:
-
- -50 = 1000000000110010
- 32768 = 1000000000000000
- -50 AND 32768 = 1000000000000000
-
- So, if the result is equal to 32768, then the number is negative...
-
- These are two of the many effects you can do with this kind of algebra.
- You can even compare numbers... But I'll leave that for next issue...
- I'm tired and I want to go to bed... Yawn...
- Just before I fall asleep in front of the keyboard, I'll just tell you
- that this kind of think is called masking... You are masking bits
- (covering them up)... Just for the record, it was Scorpio who reminded
- me of these effects... Cya in another article...
-
-
- -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
-
-
- 10. Points of View
-
- God, I'm tired of this issue... It was a struggle to make this, because
- I'm in the middle of exams and all... But, finally it's over...
- This was the biggest of all issues of 'The Mag' so far... The Mag is
- growing... Next issue, the continuation of the Text Adventure tut, plus an
- article on how to make the flame effect (made by Scorpio... I'll just add
- somethings I was meaning to do for ages...). Also, I'll continue to do
- the articles on Sprites (transparency and moving over a background)... On
- the mode 13h tutorials, I'll teach how to convert the procedures to
- assembler... Yep, that's right... Full assembly procedures in next issue...
- I'll probably start basic 3d stuff, just to introduce a couple of effects
- that use standart 3d transformations... I'll also teach how to do 2d
- rotation of a sprite... Er... I think that's it... Maybe I'll remember
- something else to put there... Maybe I'll convince Scorpio to do some
- article (eheheh... Did you hear me, Scorpio ???? :)))) ).
- Well, That's all the time I've got for this issue... I'm already receiving
- death threat's by people complaining about the long delay on this issue...
- Oh, just a bit of publicity... Get the 'Infinity Mag, Issue 1'... That's a
- portuguese mag made by people in the portuguese demoscene, about the
- demoscene... Issue 2 is almost out, and both issues include my articles of
- 'The Mag'... So, stay tuned and get it... It's pretty cool... Altough it
- requires a computer with VESA... But the look is great... Download it and
- see... You can get it at the ftp.cdrom.com site (it was in the
- pub/demos/incoming/mags directory when I last checked, but maybe Snowman
- moved it from there... If you can't find it in that dir, try the
- pub/demos/mags/1996... The filename is infy1.zip). You can also try the
- Realm Of Darkness BBS... The numbers are somewhere in this issue or in the
- info file... So, bye bye folks... See you in super-special-issue 10 !! :)
-
-
- -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x
-
-
- 11. The adventures of Spellcaster, the rebel programmer of year 2018.
-
- Episode 9 - Living on a razor's edge (sometimes cut)
-
- As predicted by Deathripper, Kristie was back before supper, but she
- refuse to say even a word to me...
- - Let's get over the plan again... - I said, looking at the Gundsen Brothers.
- - Again ?!! - said finally Kristie, in a loud voice. - How many times will
- we have to go over that blasted plan ?!! I'm sick and tired of it !! You
- make it sound like it is complicated !
- - Hey, I just don't want any complications... - I responded in a calm voice.
- - Knock it off, you two ! - Karl said. - Can't you be a little time together
- without killing each other ?
- - It's not my fault that this no-good programmer keeps treating use like
- morons !!! - Excalibur said.
- - No good-programmer ? - I responded, in an angry tone. - Twice you called
- me a lammer, Kristie... If you keep up like this, I will walk away and you
- can both blow Comptel alone... If you can without me...
- - Well, mister Shitcaster... If that's the way you think, go right ahead...
- Good ridance... - Kristie said, looking me in the eyes... For a moment, I
- thought about swallowing my pride, and confess to her my love, but I
- restrained myself and I turn my back to both of them and walked away.
- - Good work, Kristie... - Gundsen said.
- - Well, Karl, what are we supposed to do now ?
- - He'll be back... - Karl said, with a smile on his face
- Kristie just looked at Karl, with a sad look on her face.
- - I don't think he hates you... - said Karl, laughing and turning his back
- on Kristie, who looked very embaressed...
-
- Again, Karl's previsions turned out right... In the morning after, the
- morning of the attack to the COHISS, I was waiting for them near the jetcar.
- - You came back ! - said Excalibur, excited, calming down in the next
- second. - I mean... It's about time ! - she continued in a stern voice.
- - I want to destroy Comptel... And I don't care who does it with me... - I
- answered.
- - So, let's go ! - Karl said, going into the car...
- Kristie led the car, until we arrived at 100 meters from the COHISS: a
- small shop, full of hitech equipment... A small fortress... One meter of
- solid cement, and lot's of guards with lazer machine-guns on the roof.
- - So, this is it... Are you sure you want to go throuht with this ? - I
- questioned.
- - Yep... - Karl said, without hesitating.
- - As damn sure as I'm gonna be... - Kristie answered, pressing the accelerator
- pedal to the ground, directly aimming the car at the COHISS's door...
- The guards on the roof opened fire, but the armour of our vehicle holded
- on, and we crashed against the door !
- The door collapsed with the strength of the Durallium block. We went off
- the car, with lazer riffles in our hands and we started to defend ourselfs
- from the guards, while Kristie loaded the car with the stuff we needed.
- In less than ten minutes, the vehicle was loaded, and we started to hear
- in the distance the sound of a airship comming in our direction. Almost
- twenty guards laid in front of us, dead, dripping blood from every wound.
- - Let's go !! Reinforcements are coming ! - Karl shouted, running for the
- car.
- Suddently, one of the dead guards wasn't so dead after all, and he lifted
- himself up, and he shot Karl right in the chest... He screamed and fell on
- the ground. I opened fire on the guard and hitted him in his head, making
- blood spill all over the place.
- - NOOOOOOOO !!!! - Me and Kristie shouted simultaneosly.
- - Shit ! - I said, running for Karl's body. He was still breathing... At
- some cost, I managed to pull him to the car, and then Kristie accelerated.
- We had killed almost every guard in the place, and running from the others
- was easy... Difficult was to outrace the above airship, but even that was
- simple, because we went into narrow streets, where it couldn't follow.
- - Hang on Karl... - I said, holding Karl's hand. He looked at me, with pain
- and agony visible in his eyes.
- - Take care of Kristie... - he said, almost in a whisper.
- - Hang on just a little bit more. - I said.
- Kristie continued to speed up the jetcar in the streets, trying to reach
- out headquarters, before it was too late...
-
- See you in the next issue
- Diogo "SpellCaster" Andrade