
  The Quake2 Bot Registry HOWTO
  Terry 'Mongoose' Hendrix <stu7440@westga.edu>
  Version 1.0, 1999 07 06

  This HOWTO shows you how to add DarkBot II Prototype 
  dynamic enemy/item registries to your own Quake2 bot.
  _________________________________________________________________________

  -- Source Code Copyright ------------------------------------------------
  All the add on source code I have here is under the following 
  copyright ( copyleft? ).  The id code is under there own copyright
  and you should have a copy of it as well.

  Copyright (C) 1999 Terry Hendrix II.
 
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  -------------------------------------------------------------------------

  Table of Contents


  1. Introduction

     1.1 Contributors and Contacts
     1.2 Acknowledgments
     1.3 Revision History
     1.4 New versions of this document
     1.5 Feedback
     1.6 Distribution Policy  

  2. Design

     2.1 Why do I need this?
     2.2 Intergration with Quake2
     2.3 Intergration with your bot

  3. Programming

     3.1 Adding classnames to lacking game edicts
        3.1.1 Adding classnames to health items
     3.2 Adding Item registry
        3.2.1 Setup
        3.2.2 Adding items to item registry
        3.2.3 Removing items from item registry
     3.3 Adding Enemy registry
        3.3.1 Setup monsters
        3.3.2 Adding monsters to enemy registry
        3.3.3 Removing monsters from enemy registry
        3.3.4 Setup players
        3.3.5 Adding players to enemy registry
        3.3.6 Removing players from enemy registry
        3.3.7 Setup bots
        3.3.8 Adding bots to enemy registry
        3.3.9 Removing bots from enemy registry
     3.4 Using the registries to locate entities
        3.4.1 Items
        3.4.2 Enemies
     3.5 Adding bot data registry
        3.5.1 Registering for a bot data space 
        3.5.2 Freeing a bot data space
        3.5.3 Using your bot data space



  1. Introduction

  This document along with the companion enemy_reg, data_reg, and item_reg 
  source files.  They will enable you to add DarkBot II Prototype dynamic 
  enemy, bot data, and item registries to your own Quake2 bot.  With these 
  registries the bot can find any enemy or item in the game quicky and easily.
  The bot data registry will let you squirrel data away in an indepent data 
  structure from the game eidcts.  This makes your life as a bot coder
  more productive, as you add reg() and unreg() calls at entity spawn and
  never have to worry about searching for these entities in this context 
  agian.  This code is dedicated to the former SABIN inner circle.  You guys
  know who you are...  ;)



  1.1.  Contributors and Contacts

  HOWTO, programming, and teletubbie managemnt:
  Terry 'Mongoose' Hendrix II <stu7440@westga.edu>.



  1.2.  Acknowledgments

  Quake2 is owned by id software.  Darkbot II, S.A.B.I.N., and Athena
  bot code contained here (C) Terry 'Mongoose' Hendrix II.  I gathered
  the layout for this HOWTO from The Linux 3Dfx HOWTO by Bernd Kreimeier 
  (bk@gamers.org).  Thanks Bernd! 



  1.3. Revision History

      Version 1.2, 1999 07 12 ( current )
   
         Added bot data registry.

      Version 1.1, 1999 07 06 ( public )
      Version 1.0, 1999 07 06 ( draft )



  1.4 New versions of this document

  To obtian updated versions visit http://www.planetquake.com/botshop



  1.5.  Feedback

  If you have any suggestions, comments, or improvements email to
  Terry 'Mongoose' Hendrix II <stu7440@westga.edu> with the title of
  the HOWTO as the subject.

  Before sending bug reports or questions, please read all of the
  information in this HOWTO, and send detailed information about the
  problem.

  If you publish this document on a CD-ROM or in hardcopy form, a
  complimentary copy would be appreciated. Email me for my postal
  address. Also consider making a donation to the Linux Documentation
  Project to help support free documentation for Linux. Contact the
  Linux HOWTO coordinator, Tim Bynum (linux-howto@sunsite.unc.edu), for
  more information.



  1.6.  Distribution Policy

  Copyright (c) 1999 by Terry Hendrix II.  This document may be
  distributed under the terms set forth in the LDP license at
  sunsite.unc.edu/LDP/COPYRIGHT.html.

  This HOWTO is free documentation; you can redistribute it and/or
  modify it under the terms of the LDP license.  This document is
  distributed in the hope that it will be useful, but without any
  warranty; without even the implied warranty of merchantability or
  fitness for a particular purpose.  See the LDP license for more
  details.




  2. Design

  Let's breifly discuss desgin issues about the registry. 



  2.1. Why do I need this?

  First and foremost, this will save time coding and cycles at
  runtime.  The registry holds all the eneities that concern
  item or enemy lookup.  No more unnessary searching for edicts.

  Second, this gives you a better model to represent your bot's
  knowelge of the world.

  Third, using registries you can add/remove edicts as they 
  spawn, drop, or die from the functions themselves.  This will
  ensure your model represents the correct list of edicts.

  Fourth, the bot data abstraction let's you change your bot's
  persisant/varablibe data inside one simple struct.  See where 
  is is leading too?  Yes, making frame/packets to see over network.
  I don't know if you'll make a CS/SS bot, like me but if you do
  this model is a good start.  ;)


  Finally, it will allow for better planning and routing AI.    



  2.2. Intergration with Quake2
  
  Adding this functionality to Quake2 requires very little
  add on code.  It doesn't adversly affect Quake2's code in
  the least.  This is also why it's great for modifications
  of the Quake2 gameplay. 

  I suggest you make a directory called quake2m for your
  modified quake2 source files.  This way you keep the 
  orignals intact and only need to add a little to any
  Makefile to use your code.



  2.3. Intergration with your bot

  When you add this to your bot it will alter how the bot
  precieves edicts.  Yes, the code is very simple.  However,
  adding this code is a complete model shift for some bots.
  This is targeted to new bot developers, so I assume you
  don't have registries in your bot.  This will make your
  life easier.  I'm including some simple usage functions,
  so that you can get a quick start into porting to your 
  bot.

  I suggest you add a directory darkbot2m for your darkbot2
  files, for the same reason as quake2 above.  Also if you
  make modifications to GPL source it must be released with
  your product, and you be able to just tar/zip this directory
  with your release.




  3. Programming

  I hope you're convinced to use this code by now.  Let's
  lick this bitch...  ready to code?  Remeber to leave 
  comments with the code you add.  Try to at least use
  "Yourname: What this does".  You may wish t date it as well.


  3.1. Adding classnames to lacking game edicts

  Adding classnames to edicts allows us to be able to search 
  or identify an edict by classname alone.



  3.1.1. Adding classnames to health items

   (1) Open the g_items.c that you intend to modify.

   (2) Search for: void SP_item_health (edict_t *self) 
  
   (3) Add the lines below at the bottom of the function: 

       /* Yourname: Darkbot2 registry use */
       self->classname = "h_medium";  

   (4) Continue to add classnames in the same fashion for:

       void SP_item_health_small (edict_t *self)
       self->classname = "stimpack";

       void SP_item_health_large (edict_t *self)
       self->classname = "h_large";

       void SP_item_health_mega (edict_t *self)
       self->classname = "h_mega";

  Now when spawned these items will have classnames just
  like other edicts.



  3.2. Item registry hooks

  We'll now add calls to register/unregister items from their
  spawning/pickup functions.  This ensures correct listings, due
  to the fact that if it spawns it's in the world unless picked
  up.



  3.2.1. Setup

   (1) Open the g_items.c that you intend to modify.

   (2) Add the following line with the other #includes: 

       #include "item_reg.h"   



  3.2.2. Adding items to item registry

   (1) Search for: void DoRespawn (edict_t *ent)

   (2) At the bottom of the function add the lines:

       /* Yourname: Darkbot2 reg item */ 
       reg_item_db(ent);

   (3) In the function edict_t *Drop_Item() search for:

        gi.linkentity (dropped);

   (4) Add the following lines below it:

        /* Yourname: Darkbot2 reg dropped items */
        reg_item_db(dropped);        

   (5) Search for: void SpawnItem (edict_t *ent, gitem_t *item)

   (6) Add the following lines at the bottom of the function:

        /* Yourname: Darkbot2 reg spawned items */
        reg_item_db(ent);



  3.2.3. Removing items from item registry

   (1) In the function void Touch_Item() search for:

	if (!taken)
	    return;

   (2) Add the following lines below it:

        /* Yourname: Darkbot2 remove item from registry */
        if (!((coop->value) && (ent->item->flags & IT_STAY_COOP)))
            unreg_item_db(ent);




  3.3. Enemy registry

  This have the registry adding/removing possible enemies from 
  the enemy list as they are spawn/die from the world.



  3.3.1. Setup monsters

   (1) Open the g_monster.c that you intend to modify.

   (2) Add the following line with the other #includes: 

       #include "enemy_reg.h"  



  3.3.2. Adding monsters to enemy registry


   (1) Search for: qboolean monster_start (edict_t *self)

   (2) Add the following lines at the bottom of the function
       just above "return true;":

        /* Yourname: Darkbot2 reg spawned monsters */
        reg_enemy_db(self);

        /* Uncomment next line to print monster classname */
        /*
        gi.dprintf("%s at %s\n", self->classname, 
                      vtos(self->s.origin));
        */



   3.3.3. Removing monsters from enemy registry

   (1) Search for: void monster_death_use (edict_t *self)

   (2) Add the following lines at the top of the function:

        /* Yourname: Darkbot2 unreg dead monsters */
        unreg_enemy_db(self);


   
   3.3.4. Setup players

   (1) Open the p_client.c that you intend to modify.

   (2) Add the following line with the other #includes: 

       #include "enemy_reg.h"  



   3.3.5. Adding players to enemy registry

   (1) Find function void PutClientInServer()

   (2) At the bottom of the function just above the lines:

	// force the current weapon up
	client->newweapon = client->pers.weapon;
	ChangeWeapon (ent);

       Add the lines:

       /* Yourname: reg freshmeat */
       if (deathmatch->value)
           reg_enemy_db(ent);



   3.3.6. Removing players from enemy registry

   (1) Find the function void player_die()

   (2) Add the lines below at the bottom of the function,
       just above "gi.linkentity (self);":
        
      /* Yourname: unreg road kill */
      if (deathmatch->value)
          unreg_enemy_db(self);

	

   3.3.7. Setup bots

   (1) Open the file that has your bot spawn function.

   (2) Add the following line with the other #includes: 

       #include "enemy_reg.h"  



   3.3.8. Adding bots to enemy registry

   (1) Add the following lines in your spawn function, after
       your bot has been linked/spawned into world:

       /* Yourname: reg freshmeat */
       if (deathmatch->value)
           reg_enemy_db(ent);



   3.3.9. Removing bots from enemy registry

   (1) Add the following lines in your death function, after
       your bot has been unlinked/killed:

       /* Yourname: reg freshmeat */
       if (deathmatch->value)
           unreg_enemy_db(ent);
  


   3.4. Using the registries to locate entities

   Now that you have the registry keeping up with the
   entities you need to be able to use the registry to 
   find things.  Here are some sample functions for you
   to build on...  good luck!



   3.4.1. Items

   Here I present possible use for building path targets.  You can
   use it for visiblity and item searches in combat as well.

   /* Look for railgun on this level */
   target = item_scan(bot, "weapon_railgun");

   /*--------------------------------------------------------------
   * item_scan
   *
   * DOES:
   *  A quick and dirty lookup for any item by classname. 
   *
   * NOTE:
   *  I suggest caching resluts for proactive route targets. 
    -------------------------------------------------------------*/
   edict_t *item_scan(edict_t *self, char *classname)
   {
      edict_t *object = NULL;
      int i;

      for (i = 0; i < ITEM_MAX; i++)
      {
          object = ITEM_LIST[i];

          if (object)
	  {
              if (strcmp(classname, object->classname) == 0)
              {
                  #ifdef BOT_DEBUG
                  gi.dprintf("Target = %i, %s.\n",i,object->classname);
                  #endif
                  return object;
              }
	  }
      }

      return NULL;
   }



   3.4.2. Enemies

   /*--------------------------------------------------------------
   * enemy_scan
   *
   * DOES:
   *  A quick and dirty targeting ai function, using a nice
   *  database comprized only of enemy entities. 
   *
   * TODO:
   *  - check for teammates in friendly fire enabled games
   *  - improve enemy selection intelligence by classname
   *  - improve enemy selection by other game factors (ctf)
    -------------------------------------------------------------*/
  edict_t *enemy_scan(edict_t *self)
  {
      edict_t *object = NULL;
      int i;

      for (i = 0; i < ENEMY_MAX; i++)
      {
          object = ENEMY_LIST[i];

          if (object)
              if (object->solid != SOLID_NOT)
                  if (CanDamage(object, self))
                      if ((object->takedamage) && (object != self))
		      {
                          #ifdef BOT_DEBUG
                          gi.dprintf("Target = %i, %s.\n",i,object->classname);
                          #endif
                          return object;
		      }
      }
    
      return NULL;
  }



  3.5. Adding bot data registry

  Let's add the bot data registry now.  I'm using the following struct
  in my prototype code.  I really didn't want to do this, but rather than
  explaining a circluar queue - I'll show you path building with a string
  of characters just to be an asshole.  I can't believe it ran as fast
  as it did using a string, but then agian it's just for fun.  This way
  you'll have to read my routing HOWTO.  =)


  struct bot_data_s
  {
    char path[512];        // A char string ( or c-queue ) to hold a path
    int  last_visited;     // Last visited path node index
    int  item_hack;        // A kludge to fix a routing problem
    char inuse;            // Is this bot data in the array in use? 
    char id[8];            // Agent serial number driving the bot
    int  pos;              // string lenght ( or path posistion )
  };

  Of course, this is just an idea for you to start with.  You may wish
  to add/remove fields for your use.  Which is the idea behind this HOWTO.



  3.5.1. Registering for a bot data space 

  When you're bot has spwaned in call the following line:

     reg_data_db(self);

  Where self is an edict_t pointer to the bot, after gi linking.



  3.5.2. Freeing a bot data space

  When you're bot has died call the following line:

     unreg_data_db(self);

  Where self is an edict_t pointer to the bot, before gi unlinking.



  3.5.3. Using your bot data space

  Now the fun part.  You can now call for data in the bot data registry
  at any time.  One way is to use the field char *target in the Quake2
  edict struct you hold your bot's registry key.  I used this less than
  optimal solution in the reg_data_db() function.  It is however a safe
  way of storing the id without modifing the game edict struct.

  You can extract the key like below at any time, where self is the bot:

    int id;

    id = atoi(self->target); 


  Now with the id you can reference into the bot_data array and use your
  data.  Oh goodie goodie gumdrops you say.  Yes.  Here's some sample 
  code from the prototype below using the bot_data registry.  Enjoy.


  /*------------------------------------------------------
  * simple_ai_route
  *
  * TODO:
  * return a special char for denoting sleep "hops"
  * follwed by numeric arg to help cpu usage in path
  -----------------------------------------------------*/
  void simple_ai_route(edict_t *self)
  {
     int i, id;


     id = atoi(self->target);

     if (ITEM_LIST[BOT_DATA[id].item_hack])
         i = BOT_DATA[id].item_hack;

     build_path(self->s.origin, 1, i, BOT_DATA[id].path);

     self->pathtarget = BOT_DATA[id].path;
     BOT_DATA[id].pos = strlen(self->pathtarget);       


     BOT_DATA[id].item_hack++;

     if (BOT_DATA[id].item_hack >= 152)
         BOT_DATA[id].item_hack = 0;
  }  


  The function build_path looks for paths to enemies and items, using
  a bias for item i.  It will construct a path as a string in the form

    "0,23,423,12,234"

  To guide the bot to the pathnode nearest the goal.  Here the string
  lenght is saved into the pos field for indexing later.
  
  I'll leave the rest as an exercise.  I'm too sleepy to explain more.  =)