CONTENTS:

Sect 1-0  Services Explained
Sect 1-1  ModMaster Services
Sect 1-2  Service Substitues
Sect 1-3  WeaponMaster Services
Sect 2-0  Where to Start
Sect 3-0  Conclusion and Contact Info
Sect 4-0  Credits


///////////////////////////////////////////////////////////////////////////////
SECTION 1-0
SERVICES EXPLAINED:

  This file is probably misnamed... I am not going to be typing out a complete
tutorial due to the sheer size of that as a project, but I will be giving
many examples of what Godel and I have set as standards, and explain the
purpose of each Service.  I'll start off by describing what a service is by
describing the naming standard I created for them.  Each service has a name
that explains genarally when it is called.  Each one of these names may have
1 to 3 services associated with it.  For example, in ID's code there is a
function called ImpulseCommands() as shown (modified) below:

void() ImpulseCommands={
	//MODMASTER: Impulse
	MM_result=MM_Service(SVC_ImpulseS);
	if (MM_result) {
		if ((self.impulse>=1)&&(self.impulse<=8)) WM_Impulse();
		else if (self.impulse == 9) CheatCommand ();
		else if (self.impulse == 10) WM_CycleForward();
		else if (self.impulse == 11) ServerflagsCommand ();
		else if (self.impulse == 12) WM_CycleReverse();
		else if ((self.impulse >= WM_prevweap) &&
		         (self.impulse <= WM_auto)) WM_Impulse();
		else if (self.impulse == 255) QuadCheat ();
		else WM_ServiceAll(WSVC_Impulse,1); //See if the weapons want it
	}
	self.impulse = 0;
	MM_Service(SVC_ImpulseE);
};

  You should notice that at the top of the function, I have commented the
general name of the service provided, ie Impulse.  You should also note that
there is one function with an appended 'S' (standing for the word 'start'),
and one with an appended 'E' (for 'end').  The first service call encountered,
SVC_ImpulseS, not only has the ability to run custom code, but also has the
responsibility of letting ModMaster know whether to run ID's code or not.  This
allows the programmer to completely bypass ID's code.  As I mentioned earlier
some functions have 3 services... one to start, one to end, but what about the
third one?  The third service is usually an 'else' at the end of the if
statement, and is only called if ID's code is not run.  This could be where
you have placed your custom code.  Now the question is, what do you return
to control the default code/custom code option?  I have set up 3 defines for
this purpose... MODRET_DONT_FALLBACK is of value -1, MODRET_DONT_CARE is of
value 0, and MODRET_FALLBACK is of value 1.  These are intercepted right before
MM_Service() returns and the sum value from all the modules is checked. If the
sum is negative, the default code is not run... If the sum is positive or
zero, ID's code is run.  If this is temporarily confusiong you just remember
the following rule: If you do not need custom code to be run, just return
MODRET_DONT_CARE... If you need to make sure that ID's code is not run, return
MODRET_DONT_FALLBACK, and if you must have ID's code run (I have never used
this one) return MODRET_FALLBACK.  Now you should see the general pattern of 
the impulses: One service called before ID's code to decide whether or not to 
run the default code, one service to actually replace ID's code, and one service
called after the function has been run.  This is the standard we developed, and
it works quite well.

///////////////////////////////////////////////////////////////////////////////
SECTION 1-1
MODMASTER SERVICES:

  What services are available to me when I am coding my modules, and when are
they called?  Well, I'll start at the top and work my way down... This will take
a while! :)


//MODULE SERVICES (0-14 reserved): 

float SVC_PreCache		=0;
      This service is called once when the server is loading, and loads all the
      sounds and models you used in your module.  Never assume that another
      module is going to load your sounds/models.  There are no repercussions
      for precaching a sound or model more than once, so go crazy and be safe.

float SVC_PrintHelp		=1;
      This service prints help for all the non-admin commands that your module
      supports.  This function should contain only print commands to the
      self entity.

float SVC_PrintAdminHelp	=2;
      This service prints help for all the admin-only commands.  If your module
      has any, this is where to print them.

float SVC_StuffAliai		=3;
      This is a great service... When a client connects, this service will be
      called, and it is where you should stuff your aliai to the client.  This
      enables the client to bind keys to phrases, rather than impulse numbers,
      and also allows for dynamic impulses.

float SVC_IsGameMode		=4;
      This service is called to determine whether this is a game flow module,
      such as CTF and KOTH, or whether it is a toggle-able option module.  It
      should return a value of 1 if it is a game mode module, or 0 if it is
      a toggle module.

float SVC_IsEnabled		=5;
      This should return a 1 or 0 depending on whether the module is currently
      enabled or disabled.  ModMaster expects each module to keep track of
      this information for it.

float SVC_IsHidden		=6;
      This service should return a 1 if it is not something that should appear
      to admin when they are cycling through the available modules.  If a 0
      is returned the module will appear to the admin, and will not be skipped.

float SVC_GetName		=7;
      This service is called when ModMaster wants the module to copy it's name
      into the global variable strparm1.  Just copy the modules english name
      into this variable and return.

float SVC_Enable		=8;
      This service is called to tell the module to enable itself.  Perform all
      world initialization you need here.

float SVC_Disable		=9;
      This service is called to tell the module to disable itself.  If you
      need to cleanup the world when the module shuts down, this is where you
      should do it.

//MISC SERVICES: (15-20 reserved)

float SVC_Halfsecond		=15;
      This service is called every half second (bet you couldnt have guessed
      that one, eh?)

float SVC_1second		=16;
      Called every one second.

float SVC_5second		=17;
      Called every five seconds.

float SVC_1minute		=18;
      Called every minute.

float SVC_5minute		=19;
      Called every five minutes. i am beginning to see a pattern here.

//SYSOP SERVICES: (21-39 reserved)
These services have been set aside to use at your discretion.  If you need to
add in a hook this is where you should add it for future compatibility. If
you are putting a hook into a function that you know is commonly needed by
others, email me and I will put it into the distribution.  I just got tired
of putting hooks in, and was also concerned about adding hooks in on every
function due to the speed issue.

//MODMASTER SERVICES:

float SVC_ImpulseS		=40;
float SVC_ImpulseE		=41;
      These services are called when the player has entered an impulse
      command.  You should parse the impulse to see if it is one that controls
      your module.  ModMaster will set self.impulse to 0 for you after the
      impulse is parsed.

float SVC_InitBodyQueS		=42;
float SVC_InitBodyQue		=43;
float SVC_InitBodyQueE		=44;
      InitbodyQue is called at the very beginning of the game, and sets up
      ID's 5 body queue.  Unless you are going to handle dead bodies in
      CopyToBodyQue it is a good idea to let ID's code run.

float SVC_CopyToBodyQueS	=45;
float SVC_CopyToBodyQue		=46;
float SVC_CopyToBodyQueE	=47;
      These services are called when the entity in the variable entparm1 is
      to be made into a dead body.

float SVC_ObituaryS		=48;
float SVC_Obituary		=49;
float SVC_ObituaryE		=50;
      This service is called whenever anyone dies. entparm1 is the deceased
      player, and entparm2 is the attacker.  It is porbably not a good idea
      to bypass the default code, since WeaponMaster prints the death message
      for the target and attacker.
      
float SVC_LevelEndS		=51;
float SVC_LevelEndE		=52;
      These services are called when the level is over.  It should setup the
      intermission camera and start the intermission.

float SVC_LevelChangeS		=53;
float SVC_LevelChangeE		=54;
      These services are called when the level is going to be changed.  It
      should detect whether cvar("samelevel") is set or not, and then actually
      change the map (via changelevel())

float SVC_PlayerResetS		=55;
float SVC_PlayerResetE		=56;
      These services are called when a player respawns, and should set up their
      default weapons, armor, ammo, or whatever else needs setting up.

float SVC_PlayerChangeLevelS	=57;
float SVC_PlayerChangeLevelE	=58;
      These services are called when the level is being changed.  The self 
      entity's items must be set for level change, ie, take away their keys
      and excess health.

float SVC_PlayerDecodeS		=59;
float SVC_PlayerDecodeE		=60;
      These services are called when the server starts up.  If the map was
      changed, the parmXX variables contain the inter-level information
      needed to set up player ammo, armor etc.

float SVC_PlayerSuicideS	=61;
float SVC_PlayerSuicideE	=62;
      This is called whenever the client types 'kill'.

float SVC_SelectSpawnPointS	=63;
float SVC_SelectSpawnPoint1	=64;
float SVC_SelectSpawnPointE	=65;
      These services are called when the game is looking for a place to spawn
      them.  You can decide where you want them to start etc here.

float SVC_PutClientInServerS	=66;
float SVC_PutClientInServerE	=67;
      This is called after the spawn point has been assigned, and the player
      is actually being put into the game.

float SVC_ConnectS		=68;
float SVC_Connect		=69;
float SVC_ConnectE		=70;
      These services are called when a player connects to the server.  Note
      that in QuakeWorld a large amount of time may pass before they get put
      into the game, since they may need to download the map etc..

float SVC_DisconnectS		=71;
float SVC_Disconnect		=72;
float SVC_DisconnectE		=73;
      This service is called when a client disconnects from the server.

float SVC_ThrowGibS		=74;
float SVC_ThrowGib		=75;
float SVC_ThrowGibE		=76;
      These services are used to bypass ID's gibbing code for more flexible
      gib routines (ala TimedGib!)

float SVC_ThrowHeadS		=77;
float SVC_ThrowHead		=78;
float SVC_ThrowHeadE		=79;
      These services are called when a head is thrown into the air..

float SVC_PlayerDied		=80;
      This service is called from multiple places.  It is called when a player
      enters the 'kill' command, disconnects from the server, or dies by a
      weapon.  It is useful when making mods such as CTF and Runes.
  
float SVC_ItemPickup		=81;
      This service is called when a client picks up an item (ie a weapon,
      powerup, health etc).  If the player picked up a weapon, armor, or
      powerup, floatparm1 will be set to 1, otherwise they most likely picked
      up ammo, and it will be set to 0.  entparm1 is the item entity, and
      entparm2 is the player who picked it up.

float SVC_PlayerTeleport	=82;
      This service is called when a player touches a teleporter brush.



///////////////////////////////////////////////////////////////////////////////
SECTION 1-2
SERVICE SUBTITUTES:

  While optimizing ModMaster, Godel and I noted that services that were being
called every frame were slowing down all of Quake very dramatically.  We ended
up de-servicing these routines and instead setting up functions in modules.qc
where you can optionally call your own code.  This decentralized the modules
a little bit, but we got a speed gain of around 20x out of it, so dont
complain! :)  In any event, the following functions are treated just like
normal services, only you have to manually call your module from them (if you
need to use them):

float() MM_PlayerPreThinkS;
float() MM_PlayerPreThink;
float() MM_PlayerPreThinkE;
    These functions are called for EVERY player, EVERY frame before the 
    physics are calculated.  Minimal code here can speed things up.

float() MM_PlayerPostThinkS;
float() MM_PlayerPostThink;
float() MM_PlayerPostThinkE;
    These functions are called for EVERY player, EVERY frame after the 
    physics are calculated.  Minimal code here can speed things up.

float() MM_ExitRulesS;
float() MM_ExitRules;
float() MM_ExitRulesE;
    These functions determine whether of not to exit the map.  Values such
    as fraglimit's and timelimit's are checked here.

float() MM_CheckPowerupsS;
float() MM_CheckPowerups;
float() MM_CheckPowerupsE;
    Called for every player to make sure the powerups they are carrying arent
    worn off yet.

float() MM_IntermissionThinkS;
float() MM_IntermissionThink;
float() MM_IntermissionThinkE;
    Called every frame that the intermission is running.

float() MM_PlayerDeathThinkS;
float() MM_PlayerDeathThink;
float() MM_PlayerDeathThinkE;
    Called every frame for dead players.

float() MM_TDamageS;
float() MM_TDamage;
float() MM_TDamageE;
    Called when a player gets damaged.  entparm1 is the target, and entparm2
    is the attacker.  The damage done to the target is stored in floatparm1, and
    may be changed.

float() MM_AttackS;
float() MM_Attack;
float() MM_AttackE;
    Called when a player is firing their weapon.

///////////////////////////////////////////////////////////////////////////////
SECTION 1-3
WEAPONMASTER SERVICES:

The following services are only valid for weapon modules:

/// DEFINES:
float	WSVC_PreCache		=1;
float	WSVC_StuffAliai		=2;
float	WSVC_PlayerConnect	=3;
float	WSVC_PrintHelp		=4;
float	WSVC_PrintAdminHelp	=5;
        These services act in the same manner as their ModMaster equivalents.

float	WSVC_AssignSlot		=10;
        WeaponMaster expects the weapons to remember which slot they were 
        assigned to.  A slot is just a weapon available when pressing a
        weapon impulse more than once.  This service expects the weapon to
        store its assigned slot number, which is passed to it via weapfloat1.

float	WSVC_BestFactor		=11;
        This service is called when WeaponMaster wants to know how desirable the
        weapon is.  Rocket launchers have a high BestFactor, and the Axe has
        a low best factor.  This number should be between 0 and 100.

float	WSVC_GetImpulse		=12;
        This service is called when WeaponMaster wants to know what impulse
        your weapon should be assigned to.  The number should be between 1
        and 8.

float	WSVC_PrintName		=13;
        When this service is called, you should print the name of your
        weapon.  ie. "Super Shotgun"

float	WSVC_IsAvailable	=14;
        This service is asking you to return either a 1 or 0, depending on
        whether you weapon has enough ammo, is enabled, etc.

float	WSVC_IsEnabled		=15;
        This service expects a return value of either 1 or 0, depending on
        whether or not your weapon is currently enabled or disabled.

float	WSVC_SetCurrent		=16;
        When this service is called, your weapon should set it up as the
        current weapon, copying it's available ammo variable (ie ammo_nails)
        into self.currentammo.

float	WSVC_Fire		=17;
        When this service is called, you actually run the code to fire your
        weapon.

float	WSVC_Enable		=18;
        Called when WeaponMaster wants your weapon enabled.

float	WSVC_Disable		=19;
        Called when WeaponMaster wants your weapon disabled.

float	WSVC_GetWeapAndSlot	=20;
        When this service is run, copy your weapon's desired impulse into
        weapfloat1, and it's assigned slot into weapfloat2.

float	WSVC_Obituary		=21;
        This service asks the weapon code to display a death message to the
        world that  is appropriate for the attacker's weapon.  The attacker
        is copied into weapent1, and the deceased is copied into weapfloat2.

float	WSVC_GetAmmoType	=22;
        This service should return one of the following defines:
           WM_AMMO_NONE
           WM_AMMO_SHELLS
           WM_AMMO_NAILS
           WM_AMMO_ROCKETS
           WM_AMMO_CELLS

float	WSVC_Impulse		=23;
        This service is called when the plaer presses a button bound to an
        impulse.  Parse these for weapon controls.


  Please do not directly use the number assigned to the service in your code,
since I may decide to change them at any given time.  If I have missed some
parameters, search through items.qc, weapons.qc, player.qc, client.qc and
combat.qc for the service name and you should see exacltly how it is called.


///////////////////////////////////////////////////////////////////////////////
SECTION 2-0
WHERE TO START:

   The best way to start coding a module or weapon for WeaponMaster or
ModMaster is to star with the provided skeleton file.  For those of you
not yet familiarized with skeleton files, they are barebones files that
can be easily customized to meet your needs.  In this case they are almost
functional modules with all the basic design aspects already done for you.
All you have to do is search for and replace the word "skeleton" with you
module's complete name, replace the word "Skel" with your short module name
(which is used in the function names themselves, and the word "SKEL" with
a short version of you module's name (used in defines).  You should then
be able to make minor changes, add your code, and be ready to roll.  If you
need help at this point, look in the modules Godel and I wrote and see how
we did this stuff.  It is pretty easy to do once you understand it.


///////////////////////////////////////////////////////////////////////////////
SECTION 3-0
CONCLUSION:

   Although I dont generally have time to respond to very much email, you are
welcome to email questions regarding ModMaster to:

              mcumings@ecst.csuchico.edu

If you do this, PLEASE, and I re-emphasize the word.. PLEASE.. Ask other people
on the net who may have had experience with it.  If it is a technical question
that you cannot determine the answer to I will happily answer it.  I just don't
need to get 50 messages a day asking me how to code in QuakeC.  For those who
want to try out ModMaster, I sometimes run a server caled "Lands of War", and
I may even be found there sometimes!  Also, check out ModMaster's web page at

              http://www.ecst.csuchico.edu/~mcumings/modmaster

for more up to date information.  I may create a ModMaster FAQ if it becomes
necessary.   Enjoy the modularity, and frag someone for me,

                            Mojapo (Mike Cumings)


///////////////////////////////////////////////////////////////////////////////
SECTION 3-0
CREDITS:

ModMaster and WeaponMaster were written an optimized by:
      Mojapo (Mike Cumings)
      Godel  (David Wiedenmann)

Thanks to ID for a great, easily edited game.  You guys rock, 'nuff said.

Thanks to the QuakeWorld team for a great Internet solution.

Thanks to Zoid who is a volunteer programmer, porting Quake to the superior
      Unix platforms.  Happy days and jubilation!  Also the coder of the
      ever-popular ThreeWave CTF servers.

Thanks to all those who were creative enough to code new weapons/ideas into
      QuakeC for the enjoyment of others.  Clan Vae Victus salutes you.
