Git Repos / fte_dogmode / qc / items / weapons.qc
Last update to this file was on 2025-08-13 at 05:20.
Show weapons.qc
//==============================================================================
// items/weapons.qc -- weapons
//==============================================================================
//======================================================================
// constants
//======================================================================
#ifdef SSQC
//----------------------------------------------------------------------
// default inventory slots for weapons
//----------------------------------------------------------------------
typedef enum
{
ITEM_WEAPON_SLOT_AXE = 1, // id1 weapons first
ITEM_WEAPON_SLOT_SHOTGUN = 2,
ITEM_WEAPON_SLOT_SUPERSHOTGUN = 3,
ITEM_WEAPON_SLOT_NAILGUN = 4,
ITEM_WEAPON_SLOT_SUPERNAILGUN = 5,
ITEM_WEAPON_SLOT_GRENADELAUNCHER = 6,
ITEM_WEAPON_SLOT_ROCKETLAUNCHER = 7,
ITEM_WEAPON_SLOT_LIGHTNINGGUN = 8
} item_info_weapon_defaultslots;
const float AMMO_SHELLS_WP = 5; // shells on weapon pickup; id1 5
const float AMMO_NAILS_WP = 30; // nails on weapon pickup; id1 30
const float AMMO_ROCKETS_WP = 5; // rockets on weapon pickup; id1 5
const float AMMO_CELLS_WP = 15; // cells on weapon pickup; id1 15
const float WEAPON_RESPAWN_TIME = 30; // as the name suggests; id1 30
#endif
//======================================================================
// forward declarations
//======================================================================
// base_item_weapon
#ifdef CSQC
void(float isnew) base_item_weapon_netreceive;
#endif
#ifdef SSQC
void(vector p1, vector p2, entity from, float damage) fire_lightning;
#endif
#ifdef SSQC
// BASE_ITEM_WEAPON_HAVEWEAPON(p, w)
// BASE_ITEM_WEAPON_SLOTEMPTY(slot, p)
// BASE_ITEM_WEAPON_ADDAMMO(p, w, i)
// BASE_ITEM_WEAPON_ADDWEAPON(p, w, slot)
void(entity grabber, entity wep) base_item_weapon_grab;
void() base_item_weapon_touch;
void(string key, string value) base_item_weapon_init_field;
#endif
#if defined(CSQC) || defined(SSQC)
void(entity e) base_item_weapon_init;
#endif
#ifdef SSQC
strip void() base_item_weapon;
#endif
#ifdef SSQC
//----------------------------------------------------------------------
// original id1 & pd3 spawn functions -- CEV
//----------------------------------------------------------------------
void() weapon_axe;
void() weapon_shotgun;
void() weapon_supershotgun;
void() weapon_nailgun;
void() weapon_supernailgun;
void() weapon_grenadelauncher;
void() weapon_rocketlauncher;
void() weapon_lightning;
#endif
//------------------------------------------------------------------------------
//----------------------------------------------------------------------
// class base_item_weapon: base_item
// {
#ifdef CSQC
//--------------------------------------------------------------
void(float isnew) base_item_weapon_netreceive =
{
// creates a number of variables, including netflags -- CEV
BASE_ITEM_NETRECEIVE (base_item_weapon_init)
};
#endif
#ifdef SSQC
//--------------------------------------------------------------
// this is here 'cause LG doesn't create a projectile... -- CEV
// TODO CEV
//--------------------------------------------------------------
void(vector p1, vector p2, entity from, float damage) fire_lightning =
{
local entity e1, e2;
local vector f;
f = p2 - p1;
normalize (f);
f_x = 0 - f_y;
f_y = f_x;
f_z = 0;
f = f * 16;
e1 = e2 = world;
traceline (p1, p2, FALSE, from);
if (trace_ent.takedamage)
{
particle (trace_endpos, '0 0 100', 225, damage * 4);
t_damage2 (trace_ent, from, from, damage);
if (from.classtype == CT_PLAYER)
{
if (other.classtype == CT_PLAYER)
// fly me to the moon
trace_ent.velocity_z += 400;
}
}
e1 = trace_ent;
traceline (p1 + f, p2 + f, FALSE, from);
if (trace_ent != e1 && trace_ent.takedamage)
{
particle (trace_endpos, '0 0 100', 225, damage * 4);
t_damage2 (trace_ent, from, from, damage);
}
e2 = trace_ent;
traceline (p1 - f, p2 - f, FALSE, from);
if (trace_ent != e1 && trace_ent != e2 && trace_ent.takedamage)
{
particle (trace_endpos, '0 0 100', 225, damage * 4);
t_damage2 (trace_ent, from, from, damage);
}
};
#endif
#ifdef SSQC
//--------------------------------------------------------------
#define BASE_ITEM_WEAPON_HAVEWEAPON(p, w) \
{ \
local float haveweapon = FALSE; \
if (p.item[0] == w.weapon) haveweapon = TRUE; \
else if (p.item[1] == w.weapon) haveweapon = TRUE; \
else if (p.item[2] == w.weapon) haveweapon = TRUE; \
else if (p.item[3] == w.weapon) haveweapon = TRUE; \
else if (p.item[4] == w.weapon) haveweapon = TRUE; \
else if (p.item[5] == w.weapon) haveweapon = TRUE; \
else if (p.item[6] == w.weapon) haveweapon = TRUE; \
else if (p.item[7] == w.weapon) haveweapon = TRUE; \
local item_info_t iit = item_info[w.weapon]; \
}
//--------------------------------------------------------------
#define BASE_ITEM_WEAPON_SLOTEMPTY(xin, p) \
{ \
local float slotempty = FALSE; \
switch (xin) \
{ \
case 1: \
if (p.item[0] == ITEM_SEQ_HANDS) \
slotempty = TRUE; \
break; \
case 2: \
if (p.item[1] == ITEM_SEQ_HANDS) \
slotempty = TRUE; \
break; \
case 3: \
if (p.item[2] == ITEM_SEQ_HANDS) \
slotempty = TRUE; \
break; \
case 4: \
if (p.item[3] == ITEM_SEQ_HANDS) \
slotempty = TRUE; \
break; \
case 5: \
if (p.item[4] == ITEM_SEQ_HANDS) \
slotempty = TRUE; \
break; \
case 6: \
if (p.item[5] == ITEM_SEQ_HANDS) \
slotempty = TRUE; \
break; \
case 7: \
if (p.item[6] == ITEM_SEQ_HANDS) \
slotempty = TRUE; \
break; \
case 8: \
if (p.item[7] == ITEM_SEQ_HANDS) \
slotempty = TRUE; \
break; \
} \
}
//--------------------------------------------------------------
#define BASE_ITEM_WEAPON_ADDAMMO(p, w, i) \
{ \
switch (i.option) \
{ \
case ITEM_AMMO_SHELLS: \
p.ammo_shells += w.ammo_shells; \
break; \
case ITEM_AMMO_NAILS: \
p.ammo_nails += w.ammo_nails; \
break; \
case ITEM_AMMO_ROCKETS: \
p.ammo_rockets += w.ammo_rockets; \
break; \
case ITEM_AMMO_CELLS: \
p.ammo_cells += w.ammo_cells; \
break; \
} \
}
//--------------------------------------------------------------
#define BASE_ITEM_WEAPON_ADDWEAPON(p, w, slot) \
{ \
if (haveweapon == FALSE) \
{ \
/* assign to the currently selected slot -- CEV */ \
switch (slot) \
{ \
case 1: p.item[0] = w.weapon; break; \
case 2: p.item[1] = w.weapon; break; \
case 3: p.item[2] = w.weapon; break; \
case 4: p.item[3] = w.weapon; break; \
case 5: p.item[4] = w.weapon; break; \
case 6: p.item[5] = w.weapon; break; \
case 7: p.item[6] = w.weapon; break; \
case 8: p.item[7] = w.weapon; break; \
} \
} \
}
//--------------------------------------------------------------
void(entity pl, entity wep) base_item_weapon_grab =
{
// don't let the owner re-grab within a set time -- CEV
if (wep.owner)
if (pl == wep.owner)
if (time < wep.attack_finished)
return;
// creates the variables haveweapon, item -- CEV
BASE_ITEM_WEAPON_HAVEWEAPON (pl, wep)
// add ammo first -- CEV
BASE_ITEM_WEAPON_ADDAMMO (pl, wep, iit)
// now add the weapon -- CEV
BASE_ITEM_WEAPON_ADDWEAPON (pl, wep, pl.weapon)
// let the player know -- CEV
BASE_ITEM_PICKUPMESSAGE (pl, iit)
// restrict ammo to game maximums -- CEV
base_entity_boundammo (pl);
// don't re-grab / immediately throw the item -- CEV
if (pl.button4)
pl.flags |= FL_THROW_HELD;
if (pl.classtype == CT_PLAYER && pl.SendEntity)
pl.SendFlags |= NETFLAG_PLAYER_AMMO |
NETFLAG_PLAYER_INVENTORY;
// fire all targets / killtargets
local entity stemp = self;
local entity otemp = other;
other = pl;
self = wep;
activator = other;
sub_usetargets ();
self = stemp;
other = otemp;
// remove the grabbed item or set up for respawning -- CEV
BASE_ITEM_CHECKREMOVE (wep,
WEAPON_RESPAWN_TIME, WEAPON_RESPAWN_TIME)
};
//--------------------------------------------------------------
// weapon_touch
//--------------------------------------------------------------
void() base_item_weapon_touch =
{
if (sub_checkvalidtouch(other) == FALSE)
return;
if (!(other.flags & FL_CLIENT))
return;
// this macro creates the float 'item_index' -- CEV
BASE_ENTITY_WEAPONLOOKUP (other)
// don't touch() if other is holding a non-weapon -- CEV
if (item_index > ITEM_SEQ_W_END)
return;
// creates the variables haveweapon, item -- CEV
BASE_ITEM_WEAPON_HAVEWEAPON (other, self)
// creates the variable slotempty -- CEV
BASE_ITEM_WEAPON_SLOTEMPTY (self.weapon, other)
// behavior is different if player is holding grab -- CEV
if (other.button4 && !(other.flags & FL_THROW_HELD))
{
// when player is holding grab, don't touch if
// A. they aren't already holding the same weapon or
// B. they don't have their hands out -- CEV
if (item_index != ITEM_SEQ_HANDS)
// if (item_index != self.weapon)
return;
}
else
{
// when player isn't holding grab, don't touch if
// A. their hands aren't out and
// B. they don't already have the weapon -- CEV
if (item_index == ITEM_SEQ_HANDS)
return;
if (slotempty == FALSE)
if (haveweapon == FALSE)
return;
}
// add ammo from the pickup -- CEV
BASE_ITEM_WEAPON_ADDAMMO (other, self, iit)
// only add the weapon if the player's hands are empty -- CEV
local float destslot = 0;
if (item_index == ITEM_SEQ_HANDS)
destslot = other.weapon;
else if (slotempty)
destslot = self.weapon;
if (destslot)
{
BASE_ITEM_WEAPON_ADDWEAPON (other, self, destslot)
}
// let the player know -- CEV
BASE_ITEM_PICKUPMESSAGE (other, iit)
// restrict ammo to game maximums -- CEV
base_entity_boundammo (other);
if (other.classtype == CT_PLAYER && other.SendEntity)
other.SendFlags |= NETFLAG_PLAYER_AMMO |
NETFLAG_PLAYER_INVENTORY;
// fire all targets / killtargets
activator = other;
sub_usetargets ();
// remove the touched item or set up for respawning -- CEV
BASE_ITEM_CHECKREMOVE (self,
WEAPON_RESPAWN_TIME, WEAPON_RESPAWN_TIME)
};
//--------------------------------------------------------------
void(string key, string value) base_item_weapon_init_field =
{
base_item_init_field (key, value);
};
#endif
#if defined(CSQC) || defined(SSQC)
//--------------------------------------------------------------
void(entity e) base_item_weapon_init =
{
local item_info_t iit = item_info[e.weapon];
e.classgroup |= CG_ITEM_WEAPON;
e.netname = iit.name;
#ifdef CSQC
setmodelindex (e, e.modelindex);
e.modelflags |= MF_ROTATE;
#endif
#ifdef SSQC
e.classname = iit.classname;
e.classtype = iit.classtype;
e.touch = base_item_weapon_touch;
precache_model (iit.world_model);
precache_sound (iit.pickup_sound.wav);
setmodel (e, iit.world_model);
if (!e.dmg && iit.dmg)
e.dmg = iit.dmg;
if (!e.skin && iit.world_skin)
e.skin = iit.world_skin;
// if we have an owner pull from that entity's ammo pool -- CEV
if (e.spawnflags & SPAWNFLAG_ITEM_THROWN && e.owner)
{
local float ammo = 0;
switch (iit.option)
{
case ITEM_AMMO_SHELLS:
ammo = AMMO_SHELLS_WP;
if (e.owner.ammo_shells >= ammo)
{
e.owner.ammo_shells -= ammo;
}
else
{
ammo = e.owner.ammo_shells;
e.owner.ammo_shells = 0;
}
e.ammo_shells = ammo;
break;
case ITEM_AMMO_NAILS:
ammo = AMMO_NAILS_WP;
if (e.owner.ammo_nails >= ammo)
{
e.owner.ammo_nails -= ammo;
}
else
{
ammo = e.owner.ammo_nails;
e.owner.ammo_nails = 0;
}
e.ammo_nails = ammo;
break;
case ITEM_AMMO_ROCKETS:
ammo = AMMO_ROCKETS_WP;
if (e.owner.ammo_rockets >= ammo)
{
e.owner.ammo_rockets -= ammo;
}
else
{
ammo = e.owner.ammo_rockets;
e.owner.ammo_rockets = 0;
}
e.ammo_rockets = ammo;
break;
case ITEM_AMMO_CELLS:
ammo = AMMO_CELLS_WP;
if (e.owner.ammo_cells >= ammo)
{
e.owner.ammo_cells -= ammo;
}
else
{
ammo = e.owner.ammo_cells;
e.owner.ammo_cells = 0;
}
e.ammo_cells = ammo;
break;
default:
dprint (sprintf("base_item_weapon_"
"init: unknown ammo type %g "
"for entity type %s!\n",
iit.option, e.classname));
break;
}
// update any CSQC clients listening in -- CEV
if (e.owner.classtype == CT_PLAYER)
if (e.owner.SendEntity) {
{
e.owner.SendFlags |= NETFLAG_PLAYER_WEAPON |
NETFLAG_PLAYER_AMMO;
} }
}
else
{
// no owner, default ammo for weapon pickup -- CEV
switch (iit.option)
{
case ITEM_AMMO_SHELLS:
if (!e.ammo_shells)
e.ammo_shells = AMMO_SHELLS_WP;
break;
case ITEM_AMMO_NAILS:
if (!e.ammo_nails)
e.ammo_nails = AMMO_NAILS_WP;
break;
case ITEM_AMMO_ROCKETS:
if (!e.ammo_rockets)
e.ammo_rockets = AMMO_ROCKETS_WP;
break;
case ITEM_AMMO_CELLS:
if (!e.ammo_cells)
e.ammo_cells = AMMO_CELLS_WP;
break;
}
}
// particle offset
switch (e.weapon)
{
case ITEM_SEQ_SUPERSHOTGUN:
e.view_ofs = '0 0 33'; break;
case ITEM_SEQ_NAILGUN:
e.view_ofs = '0 0 31'; break;
case ITEM_SEQ_SUPERNAILGUN:
e.view_ofs = '0 0 34'; break;
case ITEM_SEQ_GRENADELAUNCHER:
e.view_ofs = '0 0 28'; break;
case ITEM_SEQ_ROCKETLAUNCHER:
e.view_ofs = '0 0 32'; break;
case ITEM_SEQ_LIGHTNINGGUN:
e.view_ofs = '0 0 31'; break;
}
#endif
// StartItem -- CEV
base_item_init (e);
};
#endif
#ifdef SSQC
//--------------------------------------------------------------
strip void() base_item_weapon =
{
base_item_weapon_init (self);
};
#endif
// };
//----------------------------------------------------------------------
// id1 & pd3 spawn functions -- CEV
//----------------------------------------------------------------------
#ifdef SSQC
//----------------------------------------------------------------------
#define ITEM_WEP(idx) \
/* { */ \
BASE_ITEM_PREINIT (base_item_weapon_init_field) \
self.weapon = idx; \
base_item_weapon_init (self);
/* } */
/*QUAKED weapon_axe (0 .5 .8) (-16 -16 0) (16 16 32)
Axe
*/
//----------------------------------------------------------------------
// Weapon 1: Ranger's Axe -- johnfitz -- dumptruck_ds from RRP and rubicon2
//----------------------------------------------------------------------
// class weapon_axe: base_item_weapon
// {
//--------------------------------------------------------------
void() weapon_axe = { ITEM_WEP (ITEM_SEQ_AXE) };
// };
/*QUAKED weapon_shotgun (0 .5 .8) (-16 -16 0) (16 16 32) X STYLE_1 STYLE_2 X X SPAWN_SILENT TRIGGER_SPAWNED SUSPENDED_IN_AIR NOT_ON_EASY NOT_ON_NORMAL NOT_ON_HARD_OR_NIGHTMARE NOT_IN_DEATHMATCH NOT_IN_COOP NOT_IN_SINGLEPLAYER RESPAWN_WITH_DM_EFFECTS NOT_ON_HARD_ONLY NOT_ON_NIGHTMARE_ONLY
{ model("progs/g_shotgn.mdl"); }
This is a pickup model that should be used when you want a player to spawn with only an axe and then later get the shotgun: (trigger_take_weapon or reset_items 2 in worldspawn). There are two models to choose from. Spawnflag 2 (the default) selects an unused “classic look” model from Rubicon 2 by metlslime. Spawnflag 4 is an alternate from Slapmap and has been used in a few mods.
Single-barrelled Shotgun
Shotgun
*/
//----------------------------------------------------------------------
// Weapon 2: Shotgun -- johnfitz -- dumptruck_ds from RRP and rubicon2
// new shotgun model by Starshipwaters
// removed 2 older shotguns that used spawnflags -- dumptruck_ds
//----------------------------------------------------------------------
// class weapon_shotgun: base_item_weapon
// {
//--------------------------------------------------------------
void() weapon_shotgun = { ITEM_WEP (ITEM_SEQ_SHOTGUN) };
// };
/*QUAKED weapon_supershotgun (0 .5 .8) (-16 -16 0) (16 16 32) X X X X X SPAWN_SILENT TRIGGER_SPAWNED SUSPENDED_IN_AIR NOT_ON_EASY NOT_ON_NORMAL NOT_ON_HARD_OR_NIGHTMARE NOT_IN_DEATHMATCH NOT_IN_COOP NOT_IN_SINGLEPLAYER RESPAWN_WITH_DM_EFFECTS NOT_ON_HARD_ONLY NOT_ON_NIGHTMARE_ONLY
{ model("progs/g_shot.mdl"); }
Double-barrelled Shotgun
*/
//----------------------------------------------------------------------
// Weapon 3: Super Shotgun
//----------------------------------------------------------------------
// class weapon_supershotgun: base_item_weapon
// {
//--------------------------------------------------------------
void() weapon_supershotgun = { ITEM_WEP (ITEM_SEQ_SUPERSHOTGUN) };
// };
/*QUAKED weapon_nailgun (0 .5 .8) (-16 -16 0) (16 16 32) X X X X X SPAWN_SILENT TRIGGER_SPAWNED SUSPENDED_IN_AIR NOT_ON_EASY NOT_ON_NORMAL NOT_ON_HARD_OR_NIGHTMARE NOT_IN_DEATHMATCH NOT_IN_COOP NOT_IN_SINGLEPLAYER RESPAWN_WITH_DM_EFFECTS NOT_ON_HARD_ONLY NOT_ON_NIGHTMARE_ONLY
{ model("progs/g_nail.mdl"); }
Nailgun
*/
//----------------------------------------------------------------------
// Weapon 4: Nailgun
//----------------------------------------------------------------------
// class weapon_nailgun: base_item_weapon
// {
//--------------------------------------------------------------
void() weapon_nailgun = { ITEM_WEP (ITEM_SEQ_NAILGUN) };
// };
/*QUAKED weapon_supernailgun (0 .5 .8) (-16 -16 0) (16 16 32) X X X X X SPAWN_SILENT TRIGGER_SPAWNED SUSPENDED_IN_AIR NOT_ON_EASY NOT_ON_NORMAL NOT_ON_HARD_OR_NIGHTMARE NOT_IN_DEATHMATCH NOT_IN_COOP NOT_IN_SINGLEPLAYER RESPAWN_WITH_DM_EFFECTS NOT_ON_HARD_ONLY NOT_ON_NIGHTMARE_ONLY
{ model("progs/g_nail2.mdl"); }
Perforator
*/
//----------------------------------------------------------------------
// Weapon 5: Super Nailgun
//----------------------------------------------------------------------
// class weapon_supernailgun: base_item_weapon
// {
//--------------------------------------------------------------
void() weapon_supernailgun = { ITEM_WEP (ITEM_SEQ_SUPERNAILGUN) };
// };
/*QUAKED weapon_grenadelauncher (0 .5 .8) (-16 -16 0) (16 16 32) X X X X X SPAWN_SILENT TRIGGER_SPAWNED SUSPENDED_IN_AIR NOT_ON_EASY NOT_ON_NORMAL NOT_ON_HARD_OR_NIGHTMARE NOT_IN_DEATHMATCH NOT_IN_COOP NOT_IN_SINGLEPLAYER RESPAWN_WITH_DM_EFFECTS NOT_ON_HARD_ONLY NOT_ON_NIGHTMARE_ONLY
{ model("progs/g_rock.mdl"); }
Grenade Launcher
*/
//----------------------------------------------------------------------
// Weapon 6: Grenade Launcher
//----------------------------------------------------------------------
// class weapon_grenadelauncher: base_item_weapon
// {
//--------------------------------------------------------------
void() weapon_grenadelauncher = { ITEM_WEP (ITEM_SEQ_GRENADELAUNCHER) };
// };
/*QUAKED weapon_rocketlauncher (0 .5 .8) (-16 -16 0) (16 16 32) X X X X X SPAWN_SILENT TRIGGER_SPAWNED SUSPENDED_IN_AIR NOT_ON_EASY NOT_ON_NORMAL NOT_ON_HARD_OR_NIGHTMARE NOT_IN_DEATHMATCH NOT_IN_COOP NOT_IN_SINGLEPLAYER RESPAWN_WITH_DM_EFFECTS NOT_ON_HARD_ONLY NOT_ON_NIGHTMARE_ONLY
{ model("progs/g_rock2.mdl"); }
Rocket Launcher
*/
//----------------------------------------------------------------------
// Weapon 7: Rocket Launcher
//----------------------------------------------------------------------
// class weapon_rocketlauncher: base_item_weapon
// {
//--------------------------------------------------------------
void() weapon_rocketlauncher = { ITEM_WEP (ITEM_SEQ_ROCKETLAUNCHER) };
// };
/*QUAKED weapon_lightning (0 .5 .8) (-16 -16 0) (16 16 32) X X X X X SPAWN_SILENT TRIGGER_SPAWNED SUSPENDED_IN_AIR NOT_ON_EASY NOT_ON_NORMAL NOT_ON_HARD_OR_NIGHTMARE NOT_IN_DEATHMATCH NOT_IN_COOP NOT_IN_SINGLEPLAYER RESPAWN_WITH_DM_EFFECTS NOT_ON_HARD_ONLY NOT_ON_NIGHTMARE_ONLY
{ model("progs/g_light.mdl"); }
Thunderbolt
*/
//----------------------------------------------------------------------
// Weapon 8: Lightning Gun
//----------------------------------------------------------------------
// class weapon_lightning: base_item_weapon
// {
//--------------------------------------------------------------
void() weapon_lightning = { ITEM_WEP (ITEM_SEQ_LIGHTNINGGUN) };
// };
#undef ITEM_WEP
#endif
Return to the top of this page or return to the overview of this repo.
Log weapons.qc
Date | Commit Message | Author | + | - |
---|---|---|---|---|
2025-08-13 | Another big commit. Item changes, field rework, etc. | cev | +212 | -657 |
2025-03-30 | Big commit. Entity networking, etc. | cev | +619 | -300 |
2024-07-17 | pmove changes, smooth crouching | cev | -1 | |
2024-06-15 | Major update, committing as-is, will have bugs | cev | +44 | -1 |
2024-03-24 | 2nd pass refactor, rework QC class structure | cev | +392 | -198 |
2024-02-18 | Client/player, projectiles, entrypoints refactor | cev | +80 | -96 |
2024-01-31 | Class based monster refactor & start projectiles | cev | +3 | |
2024-01-13 | Refactored items into classes, fix teleporttrain | cev | +440 | -170 |
2023-12-09 | Start OO / class-based refactor, work on items | cev | +50 | -149 |
2023-12-02 | More refactoring & moving, begin adding mdls & snd | cev | +380 |
Return to the top of this page or return to the overview of this repo.