nuclide/src/server/weapons.c

205 lines
3.9 KiB
C

#ifdef SERVER
int
Weapon_GetCount(void)
{
return g_weapons.length;
}
int
Weapon_GetBitID(int i)
{
return g_weapons[i].id;
}
void
Weapons_PickupNotify(base_player pl, int w)
{
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_WEAPON_PICKUP);
WriteByte(MSG_MULTICAST, w);
msg_entity = (entity)pl;
multicast([0,0,0], MULTICAST_ONE);
}
void
Weapons_RefreshAmmo(base_player pl)
{
if (g_weapons[pl.activeweapon].updateammo != __NULL__) {
g_weapons[pl.activeweapon].updateammo((player)pl);
}
}
void
Weapons_SwitchBest(base_player pl)
{
entity oldself = self;
self = pl;
for (int i = 0; i < g_weapons.length; i++) {
if (pl.g_items & g_weapons[i].id) {
pl.activeweapon = i;
break;
}
}
Weapons_Draw();
self = oldself;
pl.gflags |= GF_SEMI_TOGGLED;
}
/* returns TRUE if weapon pickup gets removed from this world */
int
Weapons_AddItem(base_player pl, int w, int startammo)
{
int value;
entity oldself = self;
self = pl;
/* let's check if we've got a limit */
int maxit;
CGameRules rules = (CGameRules)g_grMode;
maxit = rules.MaxItemPerSlot(g_weapons[w].slot);
if (maxit > 0) {
int wantslot = g_weapons[w].slot;
int c = 0;
for (int i = 0; i < g_weapons.length; i++) {
if (pl.g_items & g_weapons[i].id && g_weapons[i].slot == wantslot) {
c++;
/* we're over the slot limit. */
if (c >= maxit) {
self = oldself;
return FALSE;
}
}
}
}
/* in case programmer decided not to add a pickup callback */
if (g_weapons[w].pickup == __NULL__) {
if (pl.g_items & g_weapons[w].id) {
/* already present, skip */
value = FALSE;
} else {
/* new to our arsenal */
pl.g_items |= g_weapons[w].id;
value = TRUE;
/* it's new, so autoswitch? */
if (pl.activeweapon == 0) {
pl.activeweapon = w;
Weapons_Draw();
} else {
Weapons_PickupNotify(pl, w);
}
}
} else {
/* call pickup to handle the ammo */
if (pl.g_items & g_weapons[w].id) {
value = g_weapons[w].pickup(FALSE, startammo);
} else {
/* new to our arsenal */
pl.g_items |= g_weapons[w].id;
value = g_weapons[w].pickup(TRUE, startammo);
/* it's new, so autoswitch? */
if (pl.activeweapon == 0) {
pl.activeweapon = w;
Weapons_Draw();
} else {
Weapons_PickupNotify(pl, w);
}
}
}
Weapons_RefreshAmmo(pl);
self = oldself;
return value;
}
void
Weapons_RemoveItem(base_player pl, int w)
{
pl.g_items &= ~g_weapons[w].id;
Weapons_SwitchBest(pl);
}
void
Weapons_InitItem(int w)
{
item_pickup it = (item_pickup)self;
spawnfunc_item_pickup();
it.SetItem(w);
}
void
Weapons_UpdateAmmo(base_player pl, int a1, int a2, int a3)
{
/* no change */
if (a1 == -1) {
a1 = pl.a_ammo1;
}
if (a2 == -1) {
a2 = pl.a_ammo2;
}
if (a3 == -1) {
a3 = pl.a_ammo3;
}
/* Networked as bytes, since we don't need more. Clamp to avoid errors */
pl.a_ammo1 = bound(0, a1, 255);
pl.a_ammo2 = bound(0, a2, 255);
pl.a_ammo3 = bound(0, a3, 255);
}
void
Weapons_ReloadWeapon(base_player pl, .int mag, .int ammo, int max)
{
int iNeed = max - pl.(mag);
int iHave = pl.(ammo);
if (iNeed > iHave) {
pl.(mag) += iHave;
pl.(ammo) = 0;
} else {
pl.(mag) += iNeed;
pl.(ammo) -= iNeed;
}
}
void
Weapon_DropCurrentWeapon(base_player pl)
{
static void DropWeapon_Enable(void)
{
self.solid = SOLID_TRIGGER;
}
if (!pl.activeweapon)
return;
if (g_weapons[pl.activeweapon].allow_drop != TRUE)
return;
item_pickup drop = spawn(item_pickup, m_iWasDropped: TRUE, m_iClip: pl.a_ammo1);
drop.SetItem(pl.activeweapon);
setorigin(drop, pl.origin);
drop.solid = SOLID_NOT;
drop.think = DropWeapon_Enable;
drop.nextthink = time + 1.5f;
drop.movetype = MOVETYPE_TOSS;
drop.classname = "remove_me";
makevectors(pl.v_angle);
drop.velocity = v_forward * 256;
drop.avelocity[1] = 500;
Weapons_RemoveItem(pl, pl.activeweapon);
}
void
CSEv_DropWeapon(void)
{
player pl = (player)self;
Weapon_DropCurrentWeapon(pl);
}
#endif