                          ==================
                           Standard Logging
                          ==================

Document Version : $Id: readme.txt 1.2 1999/04/09 11:04:41 mdavies Exp $

Please read the file artistic.txt for complete licensing and
redistribution information.


                               =======
                                Files
                               =======


   4-07-1999   9:07p        5,234  artistic.txt
   4-07-1999   9:17p        9,750  gslog.c
   4-07-1999   9:17p        1,542  gslog.h
   4-07-1999   9:16p               readme.txt
   4-07-1999   9:18p       13,790  sl_packet.c
   4-07-1999   9:18p        2,243  sl_packet.h
   4-07-1999   9:09p       79,996  stdlog.c
   4-07-1999   9:16p        3,993  stdlog.h


                            ==============
                             Instructions
                            ==============


I've yet to write a complete set of instructions on how to add
Standard Logging support to mods. Information on the log format can
be obtained from the Log Standard web page
(http://www.planetquake.com/gslogmod/logstandard.html).

In order to aid log parsers, could mod authors please alter their
code so that players have unique names.

The following is a list of files that need to be modified. The header
files that are required are listed first and then the functions that
need modifying are given. The following code includes source that
refuses connections to those players that have names that are already
used on the server. Please note that I am not using id's latest source.

You may wish to download the previous toolkit files as they include
the full modified source for both DM and CTF mods.


Build
-----

Add stdlog.c, gslog.c and sl_packet.c to your build.


g_main.c
--------

#include "stdlog.h"	//	Standard Logging
#include "gslog.h"	//	Standard Logging

void ShutdownGame (void)
{
	gi.dprintf ("==== ShutdownGame ====\n");

	sl_GameEnd( &gi, level );	// Standard Logging

	gi.FreeTags (TAG_LEVEL);
	gi.FreeTags (TAG_GAME);
}


g_save.c
--------

#include "stdlog.h"	// Standard Logging
#include "gslog.h"	// Standard Logging

void InitGame (void)
{
	sl_Logging( &gi, NULL );	// Standard Logging
	
	gi.dprintf ("==== InitGame ====\n");

    ....
    ....


g_spawn.c
---------

#include "stdlog.h"	// Standard Logging
#include "gslog.h"	// Standard Logging


void SpawnEntities (char *mapname, char *entities, char *spawnpoint)
{
	edict_t		*ent;
	int			inhibit;
	char		*com_token;
	int			i;
	float		skill_level;
    static int fStarted = 0;            // Standard Logging

    skill_level = floor (skill->value);
	if (skill_level < 0)
		skill_level = 0;
	if (skill_level > 3)
		skill_level = 3;
	if (skill->value != skill_level)
		gi.cvar_forceset("skill", va("%f", skill_level));

	SaveClientData ();

	gi.FreeTags (TAG_LEVEL);


    if( fStarted )                      // Standard Logging
        sl_GameEnd( &gi, level );       // Standard Logging


	memset (&level, 0, sizeof(level));
	memset (g_edicts, 0, game.maxentities * sizeof (g_edicts[0]));

	strncpy (level.mapname, mapname, sizeof(level.mapname)-1);
	strncpy (game.spawnpoint, spawnpoint, sizeof(game.spawnpoint)-1);

	// set client fields on player ents
	for (i=0 ; i<game.maxclients ; i++)
		g_edicts[i+1].client = game.clients + i;

	ent = NULL;
	inhibit = 0;

// parse ents
	while (1)
	{
		// parse the opening brace	
		com_token = COM_Parse (&entities);
		if (!entities)
			break;
		if (com_token[0] != '{')
			gi.error ("ED_LoadFromFile: found %s when expecting {",com_token);

		if (!ent)
			ent = g_edicts;
		else
			ent = G_Spawn ();
		entities = ED_ParseEdict (entities, ent);

		// yet another map hack
		if (!stricmp(level.mapname, "command") && !stricmp(ent->classname, "trigger_once") && !stricmp(ent->model, "*27"))
			ent->spawnflags &= ~SPAWNFLAG_NOT_HARD;

		// remove things (except the world) from different skill levels or deathmatch
		if (ent != g_edicts)
		{
			if (deathmatch->value)
			{
				if ( ent->spawnflags & SPAWNFLAG_NOT_DEATHMATCH )
				{
					G_FreeEdict (ent);	
					inhibit++;
					continue;
				}
			}
			else
			{
				if ( /* ((coop->value) && (ent->spawnflags & SPAWNFLAG_NOT_COOP)) || */
					((skill->value == 0) && (ent->spawnflags & SPAWNFLAG_NOT_EASY)) ||
					((skill->value == 1) && (ent->spawnflags & SPAWNFLAG_NOT_MEDIUM)) ||
					(((skill->value == 2) || (skill->value == 3)) && (ent->spawnflags & SPAWNFLAG_NOT_HARD))
					)
					{
						G_FreeEdict (ent);	
						inhibit++;
						continue;
					}
			}

			ent->spawnflags &= ~(SPAWNFLAG_NOT_EASY|SPAWNFLAG_NOT_MEDIUM|SPAWNFLAG_NOT_HARD|SPAWNFLAG_NOT_COOP|SPAWNFLAG_NOT_DEATHMATCH);
		}

		ED_CallSpawn (ent);
	}	

	gi.dprintf ("%i entities inhibited\n", inhibit);

	G_FindTeams ();

	PlayerTrail_Init ();

    sl_GameStart( &gi, level );	// Standard Logging

    {	// Standard Logging
        static cvar_t   *_log_style_cvar   = NULL;

        if( NULL == _log_style_cvar )
            _log_style_cvar = gi.cvar( "sl_log_style", "0", 0 );

        if( _log_style_cvar &&
            (_log_style_cvar->value >= SL_LOG_STYLE_1_2a) )
            fStarted = 1;
    }	// Standard Logging
}


p_client.c
----------

#include "stdlog.h"	//	Standard Logging
#include "gslog.h"	//	Standard Logging

#define NAME_CLASH_STR    "<Name Clash>"

void player_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
	int		n;

	VectorClear (self->avelocity);

	self->takedamage = DAMAGE_YES;
	self->movetype = MOVETYPE_TOSS;

	self->s.modelindex2 = 0;	// remove linked weapon model

	self->s.angles[0] = 0;
	self->s.angles[2] = 0;

	self->s.sound = 0;
	self->client->weapon_sound = 0;

	self->maxs[2] = -8;

//	self->solid = SOLID_NOT;
	self->svflags |= SVF_DEADMONSTER;

	if (!self->deadflag)
	{
		self->client->respawn_time = level.time + 1.0;
		LookAtKiller (self, inflictor, attacker);
		self->client->ps.pmove.pm_type = PM_DEAD;
		ClientObituary (self, inflictor, attacker);

		sl_WriteStdLogDeath( &gi, level, self, inflictor, attacker);	// Standard Logging

		TossClientWeapon (self);
		if (deathmatch->value)
			Cmd_Help_f (self);		// show scores
	}

    ....
    ....



void ClientBeginDeathmatch (edict_t *ent)
{
	G_InitEdict (ent);

	InitClientResp (ent->client);

	// locate ent at a spawn point
	PutClientInServer (ent);

	// send effect
	gi.WriteByte (svc_muzzleflash);
	gi.WriteShort (ent-g_edicts);
	gi.WriteByte (MZ_LOGIN);
	gi.multicast (ent->s.origin, MULTICAST_PVS);

	gi.bprintf (PRINT_HIGH, "%s entered the game\n", ent->client->pers.netname);

	sl_WriteStdLogPlayerEntered( &gi, level, ent );	// Standard Logging
	
	// make sure all view stuff is valid
	ClientEndServerFrame (ent);
}



void ClientUserinfoChanged (edict_t *ent, char *userinfo)
{
	char	*s;
	int		playernum;
    int     fIgnoreName = 0;

	// check for malformed or illegal info strings
	if (!Info_Validate(userinfo))
	{
		strcpy (userinfo, "\\name\\badinfo\\skin\\male/grunt");
	}

    /* Standard Logging - don't change name */
    if( '\0' != ent->client->pers.netname[0] )
    {
        Info_SetValueForKey (userinfo, "name", ent->client->pers.netname);
        fIgnoreName = 1;
    }
    
	// set name
	s = Info_ValueForKey (userinfo, "name");

    // Standard Logging - stop name clashes
    if( !fIgnoreName )
    {
        edict_t		*cl_ent;
        unsigned int i;

        for (i=0 ; i<game.maxclients ; i++)
        {
            cl_ent = g_edicts + 1 + i;
            if( cl_ent->inuse &&
                (cl_ent != ent) &&
                !strcmp(cl_ent->client->pers.netname, s) )
            {
                if( '\0' != ent->client->pers.netname[0] )
                    fIgnoreName = 1;
                else
                    s = NAME_CLASH_STR;

                Info_SetValueForKey (userinfo, "name", s);
            }
        }
    }
    // Standard Logging

    if( !fIgnoreName )
    {
        // start - Standard Logging
        // Has the player got a name
        if( strlen(ent->client->pers.netname) )
        {
            // has the name changed
            if( strcmp( ent->client->pers.netname, s ) )
            {
                // Standard Logging -  log player rename
                sl_LogPlayerRename( &gi,
                                    ent->client->pers.netname,
                                    s,
                                    level.time );
            }
        }
        // end - Standard Logging

        strncpy (ent->client->pers.netname, s, sizeof(ent->client->pers.netname)-1);
    }
    
	// set skin
	s = Info_ValueForKey (userinfo, "skin");

	playernum = ent-g_edicts-1;

	// combine name and skin into a configstring
	gi.configstring (CS_PLAYERSKINS+playernum, va("%s\\%s", ent->client->pers.netname, s) );

	// fov
	if (deathmatch->value && ((int)dmflags->value & DF_FIXED_FOV))
	{
		ent->client->ps.fov = 90;
	}
	else
	{
		ent->client->ps.fov = atoi(Info_ValueForKey(userinfo, "fov"));
		if (ent->client->ps.fov < 1)
			ent->client->ps.fov = 90;
		else if (ent->client->ps.fov > 160)
			ent->client->ps.fov = 160;
	}

	// handedness
	s = Info_ValueForKey (userinfo, "hand");
	if (strlen(s))
	{
		ent->client->pers.hand = atoi(s);
	}

	// save off the userinfo in case we want to check something later
	strncpy (ent->client->pers.userinfo, userinfo, sizeof(ent->client->pers.userinfo)-1);
}


void ClientDisconnect (edict_t *ent)
{
	int		playernum;

	if (!ent->client)
		return;

	gi.bprintf (PRINT_HIGH, "%s disconnected\n", ent->client->pers.netname);

	sl_LogPlayerDisconnect( &gi, level, ent );	// Standard Logging

	
	// send effect
	gi.WriteByte (svc_muzzleflash);
	gi.WriteShort (ent-g_edicts);
	gi.WriteByte (MZ_LOGOUT);
	gi.multicast (ent->s.origin, MULTICAST_PVS);

	gi.unlinkentity (ent);
	ent->s.modelindex = 0;
	ent->solid = SOLID_NOT;
	ent->inuse = false;
	ent->classname = "disconnected";
	ent->client->pers.connected = false;

	playernum = ent-g_edicts-1;
	gi.configstring (CS_PLAYERSKINS+playernum, "");
}




                              =========
                               Contact
                              =========


If you have any questions then please use the sl-General mailing
list. Details on the mailing lists can be obtained from the
"Mail/Mailing List" web page on the gslogmod web site
http://www.planetquake.com/gslogmod/


                         === end of file ===
