==============================================================================
Title  : Updated QCBot info for implementing bots on the quake rankings.

Date   : 07 / JUNE / 1997

Author : Alan Kivlin

E-Mail : alan.kivlin@cybersurf.co.uk
==============================================================================

Description
-----------

This is an update of my previously released information on implementing bots
on the quake rankings screen.

At the time I was unable to test in a proper multi-player environment, the 
code was slightly lacking in respect to what's needed when more than one real
player is in the game.

I've still not been able to properly test, I had one client connected to
a listen server and everything worked fine. I'm (99%) sure that it'll work
with more real players. Please e-mail me and let me know if it doesn't.

I've included the client side (CLSTART1, CLSTART2) and server side (SVSTART)
demos created while testing, as well as, a demo (50BOTS) of 50 (*FIFTY*) bots
in map start - this demo doesn't use the rankings routines since only 16
entries are available on it.

The client was a 486 (16meg) with a Cirrus Logic type card (ancient), meaning
it was incredibly slow. The server was a P100 (24meg) also with an equally 
unimpressive video card but at least it's a pentium.

The network protocol was IPX via the Win95 Direct Cable Connection (over a
serial cable).

The ability shown by the bots is very limited since I basically ripped apart
a copy of my codebase so that I could do the 50 bots demo and show basic
movement.

About QCBot
-----------

My aim is to create a bot that moves like a real player, thinks like a real
player (heh this isn't as impossible as it sounds) and hence it'll effectively
play like a real player. Everything will be customisable and I mean
everything, not just a simple skill variable.

I learned QuakeC (about 4 months ago) by rewriting v1.06 in its entirety,
removing all code not required for deathmatch play. I didn't change how it
worked, all I did was reformat it to my own style. By doing this I eventually
had a complete picture of how it all worked in my head, I was dreaming QuakeC
for a while :)

Since then I've managed to overcome *ALL* restrictions in bot movement.

What you see in the demos, is a bot that's now using 100% physics movement
(my previous release simulated physics movement most of the time by calling
walkmove, it was very realistic but some levels have areas that a bot couldn't
walk onto). Now I don't have to use walkmove or movetogoal at all for
movement!

You'll see the bot jump quite a lot (my previous demo showed the bot jumping
properly but the code needed for doing it then was beyond belief :) - one of
the features of my new movement code is that when a bot hits something that it
can jump onto, it knows that it can so it jumps. No real AI is present in the
demos - the bot finds a client then tries to move to his origin.

The demos also show basic swimming abilities, it even does the player style
jump-out-of-water. When it teleports it's not allowed to backtrack like a real
player but I've not perfected this yet since I haven't worked out what I'm
supposed to be imitating, currently it won't change direction until the
teleport_time has expired.

The bots don't make the splash sounds associated with MOVETYPE_STEP. It took
me a long time to work out how to do this, here's what you need to do, at the
start of each frame, (call a routine from StartFrame in WORLD.QC) set the
watertype for each bot in the game to 0 (ZERO) - heh that's it - weeks of
trying and it ended up being one simple line of code, you'll have to produce
your own splash sounds but it's already done, do what the player does :)

I've almost finished code that terraforms the level (dynamically) - this 
takes a small amount of time but it's amazing as once it's done the bot 
actually *KNOWS* the level - not only that, it can traverse the tree and seek
out items it wants as it knows exactly where they are and how to get to them.

This technique will probably never be as good as how a player knows the level
but I believe it's better (faster?) than pathfinding and looking for items 
via findradius. Imagine what would be possible in Quake 2 if id Software coded
into the bsp file this type of information and provided routines for
traversing etc - Quake 2 would not only be great in deathmatch (for bots) but
the creatures in single player could be incredibly level wise :)

I converted the bot for QuakeWorld - heh a qw bot seems impossible although
the testing was done on my P100 running QuakeWorld Local, the server and the
client. It seems to me that non-player entities don't get processed for
velocity etc every frame but apart from that (and the rankings messages have
changed) it worked just fine!

How To...
---------

The file RANKINGS.QC has various routines for getting the bots on the rankings
screen but you must also modify some of your existing code as follows:

The first thing you must do is add a clientInitMaxClients call, to the
beginning of worldspawn in WORLD.QC. This stores in fMaxClients, the number
of clients allowed in the game (the max number of players is held in the
maxplayers cvar but for some reason you can't access this, it always returns
0).

When a player connects, check if a bot is occupying his client number, should
this be the case then it has to be moved over to the next available client
number or in the case of there being none left, make it leave the game, also,
set the player's bitflag and transmit messages that update his rankings screen
to reflect the bots in the game. The following code does this, it should be
added to the beginning of ClientConnect in CLIENT.QC:

   local entity bot;

   self.fClientNo = self.colormap - 1;

   if( clientIsActive( self.fClientNo ) )
      botInvalidClientNo( self.fClientNo );

   clientSetUsed( self.fClientNo );

   bot = find( world, classname, "bot" );

   while( bot )
   {
      msgUpdateNameToPlayer( self, bot.fClientNo, bot.netname );
      msgUpdateColorsToPlayer( self, bot.fClientNo, bot.fShirt, bot.fPants );
      msgUpdateFragsToPlayer( self, bot.fClientNo, bot.frags );

      bot = find( bot, classname, "bot" );
   }

When a player disconnects you must reset his bitflag. Add the following to
ClientDisconnect in CLIENT.QC:

   clientSetFree( self.fClientNo );

I have included sample botConnect and botDisconnect routines. These routines
have what's needed for initialising/removing a bot from the rankings, your own
bot specific code needs to be added to both of them where indicated.

To update a bot's frags on the rankings screen, one way is to rename
ClientObituary to idClientObituary, write a new ClientObituary that calls
idClientObituary and handles bot frags updates by comparing the frags before
and after the call (I mention this method as you'll find a lot of other QC
code has modifications to ClientObituary, ie. the mission packs, so it's
probably the easiest way if you decide to have your bot support them).

Copyright and Distribution Permissions
--------------------------------------

Copyright (C) 1997 by Alan Kivlin.

Authors MAY use this modification as a basis for other
publicly available work.
^^^^^^^^

If you put this on a CD, you owe me one free copy of the CD. You also owe
everyone in the world a Quake related competition, with the prize being a
free copy of the CD to the first 10 competition winners. You pay postage
too. Don't like this? Don't put it on a CD!

