// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
// Ken Silverman's official web site: "http://www.advsys.net/ken"
// See the included license file "BUILDLIC.TXT" for license info.

BUILD engine Notes (10/17/95):

BUILD programmed by Ken Silverman

BUILD.TXT CONTINUED...  (BUILD.TXT WAS GETTING TOO BIG!!!)

8/12/95   - Added parameter to initmultiplayers to allow who becomes
					master at the start of a multiplayer game.

			 - Added parallaxyscale variable to BUILD.H which control the ratio
					at which the parallaxing skies scroll in relation to the
					horizon.  Default is 65536.  With lower values, you don't
					need as much artwork and can look higher, but I like 65536
					because it is the correct projection.

8/13/95   - Had MAJOR bug with my searchmap function.  If you use it, please
					re-copy from my game.c

8/14/95   - Fixed some EVIL bugs with Rt.ALT sector copying.  It shouldn't
					screw up your maps anymore!  And if you have maps that were
					screwed up with it, you can try my new map correcting key,
					L.Ctrl+L.Shift+L.Enter.  This key will not affect an already
					perfect map.  However it can SOMETIMES clean up a map that
					was screwed up.  I take no responsibility if it screws up
					your map even more, so please check them before saving!

8/16/95   - Added error correction to mmulti.obj.  Mmulti.obj is like
					multi.obj but it is made to work with Mark's real mode
					multiplayer driver that he calls COMMIT.


				MMULTI.OBJ vs. MULTI.OBJ:
				 * initmultiplayers is the same, but the parameters are ignored
				 * uninitmultiplayers can be called but does nothing.
				 * sendlogon can be called but does nothing.
				 * sendlogoff sends packet 255 to everybody else.  It does not
					  need to be called any more.
				 * sendpacket and getpacket are the same.
				 * connecthead, connectpoint2[], numplayers, myconnectindex
						are the same.  They can be externed just like before.
				 * getoutputcirclesize always returns 0.  It is not needed.
				 * setsocket does nothing.  The socket is now in commit.dat.
				 * crctable can still be externed.
				 * syncstate can still be externed but is not used.
				 * Do not use the option[4] variable.  Initmultiplayers will
						always return a valid number in numplayers from 1-16.


					You can link mmulti.obj in place of multi.obj and use
				 commit.dat as the setup file for multiplayer options.

					There are 2 ways you can run your game through commit:
						1.  Set the launch name (usually game.exe) in commit.dat
							 and type something like "commit map01 /asdf"
						2.  Type "commit launch game map01 /asdf".  This method
							 is easier if you want to use the debugger with commit
							 since you won't have to change commit.dat constantly.
							 Ex: "commit launch wd /tr=rsi game map01 /asdf"

				 I have not tested mmulti.obj with my BUILD game yet because
				 I have been using 2DRAW as my test program.  I may put up a
				 new version of mmulti.obj with better error correction for
				 extremely error-prone lines soon.

			 - Kgroup can now accept a parameter as a filename with a list of
					files to be put into the group file.
					Ex:  "kgroup @filelist.txt"

8/18/95   - Found a way to greatly reduce slave "hitching" on multiplayer
					games for faketimerhandler style communications.  It's pretty
					simple.

					Step 1:  In the beginning of faketimerhandler, change

						ototalclock = totalclock;
							TO:
						ototalclock += TICSPERFRAME;

							This makes the timing of the game more constant and to
						never miss ticks.  I should have done this in the first
						place all along.

					Step 2:  In getpackets, (for slaves only) count the number of
						times movethings is called.  Normally, movethings should
						be called exactly once for every time getpackets is called
						inside faketimerhandler.  The hitching is because
						movethings is called in a 0-2-0-2-0-2 cycle instead of the
						standard 1-1-1-1-1-1 cycle.  This happens because the
						timers of the 2 computers are aligning in such a way that
						the slave is receiving the master's packets at nearly the
						same time as it calls getpackets.  To correct the problem,
						if movethings is called an even number of times, I randomly
						add or subtract (TICSPERFRAME>>1) to ototalclock.  Throw
						this code at the end of getpackets:

					Beginning of getpackets:
						movecnt = 0;

					Where slave receives buffer in getpackets, next to movethings:
						movecnt++;

					End of getpackets:
						if ((myconnectindex != connecthead) && ((movecnt&1) == 0))
						{
							if (rand()&1) ototalclock += (TICSPERFRAME>>1);
										else ototalclock -= (TICSPERFRAME>>1);
						}

			 - Found a way to interpolate anything using the doanimations
					code for faketimerhandler style multiplayer games.  It's not
					as hard as I thought it would be (and it doesn't waste too
					much memory!)  To smooth out doanimations, since there's no
					temporary variables that can be thrown away like with tsprite,
					the current doanimations positions must be backed up at the
					beginning of drawscreen and restored at the end of drawscreen.
					If you want smooth up&down doors, do this:

					Global declaration:
						static long oanimateval[MAXANIMATES];

					Beginning of drawscreen:
						for(i=animatecnt-1;i>=0;i--)
						{
							 oanimateval[i] = *animateptr[i];  //Backup doanimations interpolation

							 j = *animateptr[i];
							 if (j < animategoal[i])
								 j = min(j+animatevel[i]*(totalclock-gotlastpacketclock),animategoal[i]);
							 else
								 j = max(j-animatevel[i]*(totalclock-gotlastpacketclock),animategoal[i]);

							 *animateptr[i] = j;
						 }

					End of drawscreen:
							//Restore doanimations interpolation
						for(i=animatecnt-1;i>=0;i--) *animateptr[i] = oanimateval[i];

8/19/95   - Added global invisibility variable.  Initengine sets it to 0
					by default.  If you set global invisibility to 1, then
					all sprites with the invisible bit set (sprite[].cstat&0x8000)
					will be shown.  This is useful for editing invisiblie sprites.

			 - Made the hitscan blocking bit for sprites be the bit checked
					when using cliptype 1 instead of the blocking bit.  Before
					I was accidently using the clipmove blocking bit on sprites
					with cliptype 1.  I should have done it this way in the first
					place.  I hope you haven't "built" around this bug too much!
					Here's how everything works now:

						Clipmove blocking bits:
							Which bits:
								wall[].cstat & 1
								sprite[].cstat & 1
							Used in these cases:
								clipmove when cliptype = 0
								getzrange when cliptype = 0

						Hitscan blocking bits:
							Which bits:
								wall[].cstat & 64
								sprite[].cstat & 256
							Used in these cases:
								clipmove when cliptype = 1
								getzrange when cliptype = 1
								hitscan always

8/20/95   - Reduced some overhead memory by combining 2 large internal
					arrays which were used in different parts of the engine.
					This is a total savings of about 90K.

8/24/95   - Changed the way 'E' mode works on ceiling and floor textures.
					64*64 and 128*128 textures are the same as before so I think
					this won't screw up your existing maps. (But I can never be
					sure)  Now, 'E' mode always smooshes the texture size by 2 for
					any size texture.

8/29/95   -               
				                                      
				                    
						                                  
				              

				New 3D EDIT MODE BUILD keys:
					Press [ or ] on a ceiling or floor to change the slope.
					Shift + [ or ] on a ceiling or floor to adjust finely.
					Press / to reset a ceiling or floor to slope 0.
					Use Alt-F in either 2D or 3D mode to change the slope's hinge.

				Sector fields used for slopes:
					The useless groudraw fields, ceilingheinum and floorheinum,
					are now being used as the slope value.  They are treated
					as signed shorts, where 0 is slope 0, of course.  To enable
					slope mode, you must also set bit 1 of the ceilingstat or
					floorstat bits.

				Known bugs:
					There are still a few bugs that I haven't gotten around to
					fixing yet.  They're not necessarily hard to fix - it's just
					that there are a lot of little things that need to be updated
					(on my part).

					- Hitscan does not hit slopes correctly.
					- Rare divide overflow bug in my wallmost function only when
					  you're very close to a red sector line of a slope.
					- Relative alignment for slopes not yet programmed.  Relative
					  alignment for slopes will allow square aspect ratio for all
					  slopes of slopes.
					- ALT-F code with passing loops would be nice.
					- Visibility not implemented for slopes yet.
					- Sometimes an annoying tiny wall is drawn at sector lines.

					Don't call me to tell me about these bugs.  I know about them.
					And if I didn't list your favorite bug of the day, it will
					probably be brought up by the 2 internal teams now working
					with BUILD.

9/4/95    - Made ALT-F select any wall of a sector, even crossing loops.
					In 3D mode, ALT-F now sets the selected wall directly to the
					first wall.

			 - Fixes related to slopes:
				 * Relative alignment now works.  Use relative alignment on high
						slopes if you don't like the way the texture is stretched
						out.
				 * Flipping now works
				 * Panning now works
				 * Fixed seams for SOME (not all) slope borders

			 - My wonderful divide overflow bugs in wallmost aren't quite as
					rare as they used to be.  Wait a minute - I thought I was
					supposed to document bug fixes here!  This is what you get
					for wanting BUILD tonight.  As soon as I fix these darn
					divide bugs, I'll put up a new version.

9/5/95    - Fixed all known divide overflow bugs related to wallmost.  I
					haven't gotten a divide overflow yet in the last few hours,
					but that doesn't guarantee that you'll never get one.  Take a
					look at GROULAND.  It has a cool new cylindrical tunnel.  On
					the other side of the level is my house in Rhode Island.

				Known bugs with slopes now:
					- Hitscan does not hit slopes correctly.
					- Visibility not implemented for slopes yet.
					- Clipmove will not allow you to walk off high sloped cliffs.

					- Also, I noticed a rare sprite drawing clipping bug.  I
						 don't know if this is new or not.

9/7/95    - Fixed an exception 0xe bug by using tsprite[MAXSPRITESONSCREEN-2]
					instead of tsprite[MAXSPRITESONSCREEN-1].  I don't understand
					why this fixed it so I expect that it will come back to haunt
					me.  Oh happy day. :(

			 - I forgot to document 2 new and useful functions in the engine:

				  long getceilzofslope(short sectnum, long x, long y); and
				  long getflorzofslope(short sectnum, long x, long y);

					  Returns the z coordinate of the ceiling/floor at that x, y
					  location.  If the sector doesn't have a ceiling/floor slope
					  then it immediately returns the sector[].floorz or
					  sector[].ceilingz so it's not that slow.  You may want to
					  check for slopes yourself ceilingstat&2/floorstat&2 if you
					  think the overhead of calling these functions are too slow.

			 - Made clipmove use getceilzofslope and getflorzofslope when
					checking for overlapping.

			 - Cleaned up mirror code for non-chained modes a little bit.  The
					mirrors should no longer have a stay line on the right anymore
					for these modes.

			 - Added Chain-Buffer mode.  See my new SETUP.EXE.  Chain-Buffer
					is a combination of the chain and screen buffer modes - a
					buffered chain mode.  This mode is faster than standard chain
					mode when a lot of screen memory is being read, for example
					when you use transluscence or mirrors.  Also, Chain-Buffer
					mode is cleaner than screen-buffer mode since you don't see
					memory being copied to the screen.  Unfortunately, in most
					cases, Chain-Buffer is the slowest of all modes.  Actually,
					Chain-Buffer mode sucks.  There is a use for this mode,
					however!  In the future, I may make some kind of chain mode
					automatically switch into chain-buffer mode for extra speed
					when there is a large area of transluscence, etc.

				ATTENTION PROGRAMMERS:  Here is the new order of modes that
					initengine accepts:

					0 = Chain mode
					1 = Chain-Buffer mode
					2 = Screen-Buffer/VESA mode
					3 = TSENG mode
					4 = Paradise mode
					5 = S3
					6 = Crystal Eyes mode
					7 = Red-Blue mode

9/9/95    - Fixed visibility for face sprites in high resolution modes.

9/14/95   - Added a new bunch of graphics modes using the new VESA 2.0 linear
					buffer.  (I replaced the useless chain-buffer mode with VESA
					2.0 modes)  See my new SETUP.  Since most cards only support
					VESA 1.2 right now, you will probably need a VESA 2.0 driver.
					I have been using the UniVBE(tm) 5.1 from SciTech Software
					(ftp: ftp.scitechsoft.com, www: http://www.scitechsoft.com)
					Note that since I inserted the new modes between chained mode
					and screen buffer mode, you will need to update your setup
					program and fix your initengine calls.

			 - Programmed a LRU/MRU-style cacheing system.  It should be fully
					compatible with the old cache1d except for the locking byte.
					The locking byte would be better described as a priority byte.
							Priority byte:

								 0 - non-cached memory, you NEVER set the byte to 0!
							1-199 - cached unlocked memory
						 200-255 - cached locked memory

					When the cacheing system needs to remove a memory block, it
					will try to remove the FEWEST number of SMALLEST blocks with
					the LOWEST priority.

					Note: Never set the priority byte to a 0!  Let the cacheing
						system do that for you.

9/15/95   - Optimized hitscan a little and made it work with slopes.

			 - Made some internal things in the build editor work better with
					sprites on slopes.

9/16/95   - Note:  Initengine now only does memory allocation for the
						 graphics modes.  The ylookup table is calculated in
						 setgamemode since with VESA, I don't know certain
						 variables such as bytesperline until the mode is
						 actually set.

			 - Cansee should now work with slopes properly.

			 - Added a new function which is a combination of the
					getceilzofslope and getflorzofslope functions.  Whenever you
					need both the ceiling and floor, it is more optimal to call
					this function instead.  The parameters are just like the other
					functions except the ceiling and floor are returned through
					pointers instead of a return value.

						getzsofslope(short sectnum, long x, long y,
										 long *ceilz, long *florz);

			 - Fixed recently introduced hitscan divide overflow bug.

			 - Fixed a sprite drawing clipping bug.

9/17/95   - ATTENTION PROGRAMMERS:  I moved the sprite shading code from
					the engine into GAME/BSTUB.  If you want sprites to shade
					like they used to, be sure to copy the code I recently added
					to the end of analyzesprites in GAME.C or ExtAnalyzeSprites
					in BSTUB.C.

			 - Added 2 new interesting functions to the engine to make moving
					slope programming easier.  These functions will align a slope
					to a given (x, y, z) point.  It will make the slope pass
					through the point.  The function will do nothing if the point
					is collinear to the first wall of the sector.

					alignceilslope(short sectnum, long x, long y, long z);
						and
					alignflorslope(short sectnum, long x, long y, long z);

9/18/95   - Kgroup will now work with subdirectories.

			 - ATTENTION PROGRAMMERS:  I have not done this yet, but I am
					planning on doing a new map version!  Before I do it, I
					want to give you a chance to give me any suggestions you may
					have.  The only changes I am planning on, besides re-arranging
					the structures for better alignment is to give the slopes some
					more bits precision.  This may limit slopes to a maximum slope
					of 4 (almost 76) which is still extremely high.  Here are the
					new structures that I am proposing:

						//40 bytes
					typedef struct
					{
						long ceilingz, floorz;
						unsigned short wallptr, wallnum;
						short ceilingstat, floorstat;
						short ceilingpicnum, ceilingheinum;
						signed char ceilingshade;
						char ceilingpal, ceilingxpanning, ceilingypanning;
						short floorpicnum, floorheinum;
						signed char floorshade;
						char floorpal, floorxpanning, floorypanning;
						char visibility, filler;
						short lotag, hitag, extra;
					} sectortype;

						//32 bytes
					typedef struct
					{
						long x, y;
						short point2, nextwall, nextsector, cstat;
						short picnum, overpicnum;
						signed char shade;
						char pal, xrepeat, yrepeat, xpanning, ypanning;
						short lotag, hitag, extra;
					} walltype;

						//44 bytes
					typedef struct
					{
						long x, y, z;
						short cstat, picnum;
						signed char shade;
						char pal, clipdist, filler;
						unsigned char xrepeat, yrepeat;
						signed char xoffset, yoffset;
						short sectnum, statnum;
						short ang, owner, xvel, yvel, zvel;
						short lotag, hitag, extra;
					} spritetype;

					Note that I am adding 1 byte of filler to the sprite structure
					(4K more) and 3 bytes of filler to the sector structure
					(3K more).  (If I'm a nice guy, one of those bytes may even
					be use for fog. (DOH!))

			 - Fixed another wonderful hitscan divide bug.

9/22/95   - Optimized slopes.  On a 486-66 w/ local bus in VESA 2.0 320*200
					mode, a full screen slope was optimized from 24fps to 35fps!

9/25/95   - Re-optimized some more assembly.

			 - ATTENTION EVERYONE!  CONVMAP7!  You know what this means.  Just
				  type "convmap7 *.map" and you'll be back in business.  P.S.
				  enjoy the newly aligned structures!

			 - ATTENTION PROGRAMMERS!  New TRANSPAL!  You can now use 2 levels
					of transluscence by using just a single 64K transluscent
					buffer, such as 33/67 and 67/33 transluscence.  I changed the
					format of palette.dat, so please run TRANSPAL before you try
					running the game with the new OBJS! If you don't, the palette
					tables will be screwed up.

					 Old PALETTE.DAT:
						 768 bytes - VGA palette
						 numshades*256 bytes - palookup[0] table
						 32640 bytes- transluscent palette (smaller from symmetry)

						 The way I used to get numshades (fun):
							 numshades = ((filelength-32640-768)>>8)

					 New PALETTE.DAT:
						 768 - VGA palette
						 2 - numshades
						 numshades*256 - palookup[0] table
						 65536 - transluscent table

					 To keep things less confusing, could you all use a
					 transluscent constant >= 128.  For example, I used 170 on
					 my PALETTE.DAT.


					READ THIS!  New bits added to things:
						Bit 5 of rotatesprite, bit 9 of both sprite[].cstat
						and bit 9 of wall[].cstat are now used for reverse
						transluscence.

			 - Added super-cool new feature to 2D EDIT MODE (that should have
					been there from the start).  Try inserting some points!

			 - ATTENTION PROGRAMMERS!  Removed overwritesprite.  Use
					rotatesprite instead.  I don't want to support a function that
					can totally be done with another better function.  I will
					eventually optimize rotatesprite for 90 cases so it's even
					faster than the current overwritesprite.  If you're too lazy
					to convert right now, then you can use this overwritesprite
					stub function:

overwritesprite (long thex, long they, short tilenum,
					  signed char shade, char stat, char dapalnum)
{
	rotatesprite(thex<<16,they<<16,65536L,(stat&8)<<7,tilenum,shade,dapalnum,
		((stat&1^1)<<4)+(stat&2)+((stat&4)>>2)+((stat&16)>>2)^((stat&8)>>1),
		windowx1,windowy1,windowx2,windowy2);
}

			 - Fixed the rotatesprite centerting bug in y-flipping mode.  Oh
				  by the way, you know how I originally said the flipping bit
				  was x?  Well, I screwed it up.  It was actually y-flipping all
				  along.

			 - This one's for hackers (N&P/Qs)  In the engine, I call
					getpalookup every time I need a pointer to a 256-byte
					palookup table.  One big limitation right now is that each
					bunch of 256-byte tables has a limit of 64K because a shade
					is being returned, not a 4-byte pointer.  This means you
					could have a maximum of 8 shades, with 8 fogs per palookup.
					It's not as expandable as I originally intended since this is
					a speed-critical function.  It is called EVERY single time a
					line is drawn - probably called 50 times more often than
					faketimerhandler.

					#pragma aux bound32 =\
						"test eax, 0ffffffe0h",\
						"jz endit",\
						"cmp eax, 80000000h",\
						"sbb eax, eax",\
						"and eax, 31",\
						"endit:",\
						parm [eax]\

					getpalookup(long davis, long dashade)
					{
						return(bound32(dashade+(davis>>8)));
					}

					This is just a start.  Eventually I hope to use some kind of
					lookup table, such as:  palookup = palptr[davis][dashade],
					but I couldn't think of a good way to make the array small
					enough for what people need.

9/26/95   - Fixed drawmapview so it actually clips to the rectangular window
					properly.  It does not clip to startumost/startdmost so you
					should call a rotatesprite to draw the status bar every frame
					if it is not rectangular.

9/30/95   - Fixed recently introduced mirror bug.

			 - Fixed rotatesprite x-positioning bug in scale mode for weird
					  resolutions.

			 - Fixed tilting for pure chained modes.

10/2/95   - Changed setbrightness call:

					setbrightness(char dabrightness, char *dapal)
						dabrightness is gamma level(0-15)
						dapal is pointer to standard VGA 768 byte palette.

10/3/95   - Fixed flicker in UNIVBE modes.

10/6/95   - Added a global visibility variable to BUILD.H specific for
					p-skies called parallaxvisibility.  Now you can do lightning
					effects without modifying the visibility for everything.

			 - Really fixed the drawmapview window clipping this time.

			 - Made my clearview function clip to the viewing window since it
					is usually used just before the drawmapview function.

			 - You can now use bit 6 (64) to tell rotatesprite whether or not
					the tile has transparent regions or not.  If there are no
					transparent regions, then it would be faster to set this bit
					because it doesn't have to check for color 255 at every pixel.

10/11/95  - Back in RI!

10/13/95  - Cleaned up setup program by having only 1 VESA menu for all
					possible VESA modes.  The engine will now auto-detect whether
					or not your computer supports VESA 2.0.  The screen buffer
					menu now only supports 320*200.  (I noticed that Mark's setup
					program doesn't list 320*400 mode even though it is supported
					by my game and UNIVBE. 320*400 is considered by some people
					the next best mode after 320*200 and 640*480.  You have my
					permission to annoy him.)

			 - I bought UNIVBE by credit card for $28!  When you buy UNIVBE,
					you don't have to struggle with beeps or date changing - and
					it loads instantly.  I try not to use TSR's whenever possible,
					but I found that UNIVBE is worth wasting 8K.  I don't think my
					computer has ever crashed due to something related to UNIVBE.

10/17/95  - Found an easy way to interpolate everything for faketimerhandler
					in my game, including swinging doors, revolving doors, and
					other moving sectors.  My doanimations interpolation now uses
					these functions instead.  Check them out in my GAME:

						setinterpolation(long *posptr);  //Call when door starts
						stopinterpolation(long *posptr); //Call when door stops
						updateinterpolations();  //Call at start of domovethings
						dointerpolations()       //Call at start of drawscreen
						restoreinterpolations()  //Call at end of drawscreen

					Call setinterpolation with a pointer to the long variable
					being interpolated.  If an object stops moving, you can
					speed things up by calling stopinterpolation.  For things
					that always move, you can call setinterpolation in pre-map
					and don't stopinterpolation for those things.  Don't forget
					to set numinterpolations to 0 in premap whenever changing
					levels in the game.

			 - Optimized lava.  You can re-copy my code if you want.

			 - Added auto screen-buffering mode for linear VESA modes.  (In
					case you didn't know, reading video memory can be 10 times
					slower than reading non-video memory.)  Auto-buffering
					means that if the engine detects that more than 1/8th of the
					screen has transluscence or mirrors, then it will switch into
					a screen-buffering mode.  Screen-buffer mode in linear VESA
					not only will still have smooth page flipping, but will be
					faster than standard screen buffer mode on some video cards
					just because it's linear memory.  (That's a good thing)

			 - Optimized screen buffer modes so they copy only the viewing
					window instead of the whole screen from non-video memory to
					video memory.  If a permanent sprite is written, as a special
					case, it will copy the whole screen - but this doesn't affect
					you.  Me and my engine babble.

			 - Moved the printext function out of the engine and into my game.
					Use printext16/printext256 instead.

			 - I tried removing chain mode twice and it didn't improve the frame
					rates of the other modes at all.  So it stays!  If you don't
					like it, then don't include it in your setup program.

			 - Made allocatepermanenttile return 0 instead of -1 if something
					bad happens.  My GAME.C was crashing in windows with a memory
					error because I was assuming all memory pointers were
					positive.  Please make sure your code will work if an
					allocation function returns a negative pointer (Windows often
					returns negative pointers).

10/19/95  - Tried to make pushmove work with face sprites, but it kept making
					the player die too much.  Also it presented some interesting
					new problems, such as:  You get pushed by your own bullets
					that you just shot - and get this - if you don't temporarily
					set yourself to non-blocking you kill yourself because you're
					inside you're own sprite!  So I have decided to comment out
					this code for now.

			 - Fixed hitscan bug with ceiling slopes.

			 - ATTENTION PROGRAMMERS!!! PERMANENTWRITESPRITE was removed from
					the engine and be put into my game as an emulated function.
					If you still use permanentwritesprite, get the emulated
					function out of my GAME.C.

				Drawing permanent areas is now easier than ever!!!  Simply
					call rotatesprite with bit 3 (&8) set or the
					permanentwritesprite stub call, and the engine now
					automatically takes care of copying the permanent region
					to all necessary pages in the future.  It even keeps track
					of whether the call was before or after drawrooms!
				I am using an internal fifo to back up the parameters for each
					rotatesprite call.  It can support up to 512 calls per
					page right now.  This number can get reached quicker than
					you think, especially if you use fonts with shadows behind
					each character.  Permanentwritespritetile could also go
					over the limit in hi-res modes since each tile is considered
					a separate call.
				I optimized out the case where an older rotatesprite region gets
					completely covered by a newer rotatesprite region with bit 6
					(&64 for non-masking) set.  Currently this has a few
					limitations - such as the x, y, zoom, and ang must be the same
					right now to knock out an older rotatesprite.

			 - I corrected an off-by 1 error in my GAME.C for window size
					calculations.  I simply used more precision. Ex:
					* changing (xdim>>1)-(screensize>>1) to ((xdim-screensize)>>1)
					* using the scale function instead of a separate mul & div.
				By the way, if you haven't already, please stick your screen
					re-sizing code BEFORE drawrooms.  It will make the screen
					re-size update more responsively and you're less likely to get
					drawing bugs.

			 - Future plans for possible rotatesprite optimizations:
				  1. Angle is 0, 512, 1024, 1536
				  2. Bit 6 (&64) is set for non-masking mode
				  3. tilesizy[tilenum] is a power of 2
				  4. If coincidentally, x=34562, y=34682, and zoom=67275
