
OK this is a quick mod I (Gary Tunstall)
made.
The mod lets the server admin
create 'special' teleporters in a map. These 'gateways' transport a player to a
new server when the player walks on them and stays there for 3 seconds. They
also display info (name, name of MOD running, short description) about the
target server when the player stands near them.
It is a server side mod not
requiring the clients (players) to download anything
I have been a busy bunny and I am
releasing the source.
Well kind of...
... I am actually releasing a txt
file I made documenting the changes I made (in code form).
Its can't be compiled but if
someone knew how to code they could make a working copy out of it.
I am releasing it as most of my
knowlege came from others source and tutorials (and glitter).
I feel it is only fair I release
my source.
However I don't want anyone just
nicking it and say its theirs!
You can use it in a mod as long as
you mention me someone is some documentation (ie in a credits section or
something) and if you email me and tell me so I can have a look at it in use.
Of cause at the moment it is
probably impossible to understand what my changes mean as there are no comment
Line numbers may be out by
serveral number due to comments and linefeeds
g_main.c
--------
56: vars at top: after cvar_t
*sv_maplist;
cvar_t *save_gateways;
q_shared.h
----------
992: in //
player_state->stats[] indexes: after #define STAT_SPECTATOR 17
#define STAT_NAME 18
#define STAT_MOD 19
#define STAT_DESCRIPTION 20
#define STAT_ADDRESS 21
g_local.h
---------
536: in vars in middle: after
extern cvar_t *sv_maplist;
extern cvar_t *save_gateways;
944: in struct gclient_s: after
float respawn_time;
float gateway_mes_time;
int gateway;
995: in struct edict_s: after char
*message;
char *servername;
char *serverdescription;
char *servermod;
could have used - but not sure if
in use else where
char *pathtarget;
char *deathtarget;
char *combattarget;
p_hud.c
-------
505: in void G_SetStats (edict_t
*ent): after ent->client->ps.stats[STAT_SPECTATOR] = 0;
if
(ent->client->gateway)
{
ent->client->ps.stats[STAT_NAME] =
CS_GENERAL+(ent->client->gateway*4)
;
ent->client->ps.stats[STAT_MOD] =
CS_GENERAL+(ent->client->gateway*4)+1;
ent->client->ps.stats[STAT_DESCRIPTION] =
CS_GENERAL+(ent->client->gateway*4)+2;
ent->client->ps.stats[STAT_ADDRESS] =
CS_GENERAL+(ent->client->gateway*4)+3;
if
(ent->client->gateway_mes_time<level.time)
{
ent->client->gateway=0;
}
}
else
{
ent->client->ps.stats[STAT_NAME] =
0;
ent->client->ps.stats[STAT_MOD] = 0;
ent->client->ps.stats[STAT_DESCRIPTION] = 0;
ent->client->ps.stats[STAT_ADDRESS] = 0;
}
g_save.c
--------
22: in field_t fields[] = {: after
{"message", FOFS(message), F_LSTRING},
{"servername",
FOFS(servername), F_LSTRING},
{"serverdescription",
FOFS(serverdescription), F_LSTRING},
{"servermod",
FOFS(servermod), F_LSTRING},
190: in void InitGame (void):
after sv_maplist = gi.cvar ("sv_maplist", "", 0);
save_gateways
= gi.cvar ("allow_save_gateway", "0", CVAR_SERVERINFO);
g_cmds.c
--------
884: in file (it is a function):
after gi.cprintf(ent, PRINT_HIGH, "%s", text); } (from void
Cmd_PlayerList_f(edict_t *ent))
char *vtos_nob (vec3_t v)
{
static int index_nob;
static char str_nob[8][32];
char *s;
//
use an array so that multiple vtos won't collide
s
= str_nob[index_nob];
index_nob
= (index_nob + 1)&7;
Com_sprintf
(s, 32, "%i %i %i", (int)v[0], (int)v[1], (int)v[2]);
return
s;
}
void save_tele_to_file(edict_t
*ent)
{
FILE *outFile;
cvar_t *game_cvar;
if (save_gateways->value)
{
if
(!(gi.argv(1))||(strcmp("",gi.argv(1))==0))
{
gi.cprintf(ent,PRINT_HIGH,"Sorry
no server destination aborting\n");
return;
}
game_cvar
= gi.cvar("game", "", 0);
if
(outFile = fopen(va("%s/ent/%s.ent",game_cvar->string,level.mapname),
"a"))
{
gi.dprintf("%s
opened\n",va("%s/ent/%s.ent",game_cvar->string,level.mapname));
fprintf(outFile,
va("{\n\"classname\"
\"misc_teleporter\"\n\"origin\"
\"%s\"\n\"target\"
\"dest\"\n",vtos_nob(ent->s.origin)));
if
((gi.argv(1))&&!(strcmp("",gi.argv(1))==0))
{
fprintf(outFile,
va("\"map\" \"%s\"\n",gi.argv(1)));
}
if
((gi.argv(2))&&!(strcmp("",gi.argv(2))==0))
{
fprintf(outFile,
va("\"servername\" \"%s\"\n",gi.argv(2)));
}
if
((gi.argv(3))&&!(strcmp("",gi.argv(3))==0))
{
fprintf(outFile,
va("\"serverdescription\" \"%s\"\n",gi.argv(3)));
}
if
((gi.argv(4))&&!(strcmp("",gi.argv(4))==0))
{
fprintf(outFile,
va("\"servermod\" \"%s\"\n",gi.argv(4)));
}
if
((gi.argv(5))&&!(strcmp("",gi.argv(5))==0))
{
fprintf(outFile,
va("\"message\" \"%s\"\n",gi.argv(5)));
}
fprintf(outFile,"}\n");
fclose(outFile);
gi.dprintf("%s
closed\n",va("%s/ent/%s.ent",game_cvar->string,level.mapname));
gi.cprintf(ent,PRINT_HIGH,"Saved
new site restart map to see effect\n");
}
else
{
gi.dprintf("%s
not
opened\n",va("%s/ent/%s.ent",game_cvar->string,level.mapname));
gi.cprintf(ent,PRINT_HIGH,"Sorry
saving teleports broke!\n");
}
}
else
{
gi.cprintf(ent,PRINT_HIGH,"Sorry
saving teleports not enabled with allow_save_gateway\n");
}
}
1042: in void ClientCommand
(edict_t *ent):after Cmd_PlayerList_f(ent);
else
if (Q_stricmp(cmd, "save_gateway") == 0)
save_tele_to_file(ent);
g_spawn.c
---------
509: in void SpawnEntities (char *mapname,
char *entities, char *spawnpoint): after float skill_level;
int inhibit2;
FILE
*ent_file;
char gaztemp[70000],*gazents;
char gazbuf[101];
cvar_t *game_cvar;
game_cvar
= gi.cvar("game", "", 0);
539: in void SpawnEntities (char *mapname,
char *entities, char *spawnpoint): after g_edicts[i+1].client = game.clients +
i;
strcpy(gaztemp,"");
if (ent_file =
fopen(va("%s/ent/%s.ent",game_cvar->string,mapname),
"r"))
{
gi.dprintf("Ents:
%s ",va("%s/ent/%s.ent",game_cvar->string,mapname));
while
((fgets(gazbuf,100,ent_file)) != NULL)
{
strcat(gaztemp,
gazbuf);
}
fclose(ent_file);
gi.dprintf("read\n");
}
else
{
gi.dprintf("Ents: %s not
read\n",va("%s/ent/%s.ent",game_cvar->string,mapname));
}
616: in void SpawnEntities (char
*mapname, char *entities, char *spawnpoint): after gi.dprintf ("%i
entities inhibited\n", inhibit);
gazents=gaztemp;
inhibit2
= 0;
// parse ents
while
(1)
{
//
parse the opening brace
com_token
= COM_Parse (&gazents);
if
(!gazents)
break;
if (com_token[0] != '{')
gi.error
("ED_LoadFromFile: found %s when expecting {",com_token);
if
(!ent)
ent
= g_edicts;
else
ent
= G_Spawn ();
gazents
= ED_ParseEdict (gazents, ent);
//
yet another map hack
if
(!Q_stricmp(level.mapname, "command") &&
!Q_stricmp(ent->classname, "trigger_once") &&
!Q_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);
inhibit2++;
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);
inhibit2++;
continue;
}
}
ent->spawnflags
&=
~(SPAWNFLAG_NOT_EASY|SPAWNFLAG_NOT_MEDIUM|SPAWNFLAG_NOT_HARD|SPAWNFLAG_NOT_COOP|SPAWNFLAG_NOT_DEATHMATCH);
}
ED_CallSpawn
(ent);
}
if
(inhibit2) gi.dprintf ("%i entities from .ent inhibited\n",
inhibit2);
772: in char *single_statusbar =:
after " pic 11 " "endif "
"if 18 "
"xv 10 "
"yv 40 "
"string2 \"This teleporter goes to another server\"
"
"xv 50 "
"yv 60 "
"string2 \"Name\" "
"yv 70 "
"string2 \"MOD\" "
"yv 80 "
"string2 \"Description\" "
"yv 90 "
"string2 \"Address\" "
"xv 150 "
"yv 60 "
"stat_string 18 "
"yv 70 "
"stat_string 19 "
"yv 80 "
"stat_string 20 "
"yv 90 "
"stat_string 21 "
"endif "
877: in char *dm_statusbar =:
after "stat_string 16 " "endif "
"if 18 "
"xv 10 "
"yv 40 "
"string2 \"This teleporter goes to another server\"
"
"xv 50 "
"yv 60 "
"string2 \"Name\" "
"yv 70 "
"string2 \"MOD\" "
"yv 80 "
"string2 \"Description\" "
"yv 90 "
"string2 \"Address\" "
"xv 150 "
"yv 60 "
"stat_string 18 "
"yv 70 "
"stat_string 19 "
"yv 80 "
"stat_string 20 "
"yv 90 "
"stat_string 21 "
"endif "
g_misc.c
--------
1764: in file (it is a funtion):
after //=================================================================================
replace the whole of void
teleporter_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t
*surf)
with
void teleporter_touch (edict_t
*self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
edict_t *dest;
int i;
if(self->owner->map)
{
if
(other->client)
{
if
(level.time > (self->owner->delay+1))
{
self->owner->delay=level.time;
self->owner->wait=level.time; // reseting
count
gi.cprintf
(other, PRINT_HIGH, "Wait 3 secs to goto \"%s\"\n",
self->owner->servername);
return;
}
else
{
if
(level.time > (self->owner->wait+3))
{
gi.cprintf
(other,PRINT_MEDIUM, "Teleporting to
%s\n",self->owner->servername);
if
(self->owner->message)
{
gi.cprintf
(other,PRINT_MEDIUM, "%s\n",self->owner->message);
}
gi.WriteByte
(svc_stufftext);
gi.WriteString
(va("connect %s\n",self->owner->map));
gi.unicast(other,
true);
gi.bprintf
(PRINT_HIGH, "%s went to %s\n",
other->client->pers.netname,self->owner->servername);
self->owner->delay=level.time;
self->owner->wait=level.time; // reseting
count
}
else
{
self->owner->delay=level.time;
// gi.dprintf("delay
%f wait
%f\n",level.time-self->owner->delay,level.time-self->owner->wait);
return;
}
}
}
}
else
{
if
(!other)
return;
dest
= G_Find (NULL, FOFS(targetname), self->target);
if
(!dest)
{
gi.dprintf
("Couldn't find destination\n");
return;
}
//
unlink to make sure it can't possibly interfere with KillBox
gi.unlinkentity
(other);
VectorCopy
(dest->s.origin, other->s.origin);
VectorCopy
(dest->s.origin, other->s.old_origin);
other->s.origin[2]
+= 10;
//
clear the velocity and hold them in place briefly
VectorClear
(other->velocity);
if
(other->client)
{
other->client->ps.pmove.pm_time
= 160>>3; // hold time
other->client->ps.pmove.pm_flags
|= PMF_TIME_TELEPORT;
}
//
draw the teleport splash at source and on the player
self->owner->s.event
= EV_PLAYER_TELEPORT;
other->s.event
= EV_PLAYER_TELEPORT;
//
set angles
if
(other->client)
{
for
(i=0 ; i<3 ; i++)
{
other->client->ps.pmove.delta_angles[i]
= ANGLE2SHORT(dest->s.angles[i] - other->client->resp.cmd_angles[i]);
}
}
VectorClear
(other->s.angles);
if
(other->client)
{
VectorClear
(other->client->ps.viewangles);
VectorClear
(other->client->v_angle);
}
//
kill anything at the destination
KillBox
(other);
gi.linkentity
(other);
}
}
1859: in file (it is a function):
after gi.linkentity (other); } }
void teleporter_msg_touch (edict_t
*self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
if (!other->client)
return;
other->client->gateway=self->owner->count;
other->client->gateway_mes_time=level.time+3;
}
int no_gateways=0;
1876: in void SP_misc_teleporter (edict_t
*ent): after edict_t *trig;
edict_t *trig2;
1885: in void SP_misc_teleporter
(edict_t *ent): after return; }
if
((ent->message) && (!ent->map))
{
ent->map
= ent->message;
ent->message
= NULL;
gi.dprintf("Target
server was message (error in map) %s\n",ent->map);
}
if
(ent->map)
{
if
(!ent->servername)
{
ent->servername
= ent->map;
}
if
(!ent->serverdescription)
{
ent->serverdescription
= "None";
}
if
(!ent->servermod)
{
ent->servermod
= "Not specified";
}
no_gateways++;
ent->count=no_gateways;
gi.configstring
(CS_GENERAL+(no_gateways*4) ,
va("%s", ent->servername) );
gi.configstring
(CS_GENERAL+(no_gateways*4)+1, va("%s", ent->servermod) );
gi.configstring
(CS_GENERAL+(no_gateways*4)+2, va("%s", ent->serverdescription) );
gi.configstring
(CS_GENERAL+(no_gateways*4)+3, va("%s", ent->map) );
}
1934: in void SP_misc_teleporter
(edict_t *ent): after gi.linkentity (trig);
trig2
= G_Spawn ();
trig2->touch
= teleporter_msg_touch;
trig2->solid
= SOLID_TRIGGER;
trig2->target
= ent->target;
trig2->owner
= ent;
VectorCopy
(ent->s.origin, trig2->s.origin);
VectorSet
(trig2->mins, -75, -75, -16);
VectorSet
(trig2->maxs, 75, 75, 32);
gi.linkentity
(trig2);