quakec/source/server/clientfuncs.qc
Steam Deck User 89742dc652 GLOBAL: Retire CTR QuakeC, Merge with PSP.
This rebrands the two under the "HANDHELD" name. The two platforms now
function identically in regards to server functions, making them
unified in behavior and general server-reliant functions.
2022-12-28 15:21:19 -05:00

650 lines
16 KiB
C++

/*
server/clientfuncs.qc
Used to communicate between server and client
Copyright (C) 2021-2022 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
void SetUpdate(entity client, float type, float val1, float val2, float val3)
{
#ifndef HANDHELD
#ifndef NX
if (type != 2)
{
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_UPDATE);
WriteByte(MSG_MULTICAST, type); // UT_HUD
WriteByte(MSG_MULTICAST, val1);
WriteByte(MSG_MULTICAST, val2);
WriteByte(MSG_MULTICAST, val3); // misc flags/vars for later if needed
msg_entity = client;
multicast('0 0 0', MULTICAST_ONE);
}
else
{
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_UPDATE);
WriteByte(MSG_MULTICAST, type); // UT_ROUNDS_CHANGE
WriteByte(MSG_MULTICAST, val1);
WriteByte(MSG_MULTICAST, val2);
WriteByte(MSG_MULTICAST, val3); // misc flags/vars for later if needed
multicast('0 0 0', MULTICAST_ALL);
}
#endif
#endif
}
#ifndef HANDHELD
#ifndef NX
void(entity to, float type, float cost, float weapon) useprint = {
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_USEPRINT);
WriteByte(MSG_MULTICAST, type);
WriteShort(MSG_MULTICAST, cost);
WriteByte(MSG_MULTICAST, weapon);
msg_entity = to;
multicast('0 0 0', MULTICAST_ONE);
}
#endif
#endif
void(vector org) CallExplosion = {
#ifndef PC
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_EXPLOSION);
WriteCoord (MSG_BROADCAST, org_x);
WriteCoord (MSG_BROADCAST, org_y);
WriteCoord (MSG_BROADCAST, org_z);
#else
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_EXPLOSION);
WriteCoord(MSG_MULTICAST, org_x);
WriteCoord(MSG_MULTICAST, org_y);
WriteCoord(MSG_MULTICAST, org_z);
multicast('0 0 0', MULTICAST_ALL);
#endif
}
void NotifyNewRound(float to) {
#ifndef HANDHELD
#ifndef NX
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_NEWROUND);
WriteByte(MSG_MULTICAST, to);
multicast('0 0 0', MULTICAST_ALL);
#endif
#endif
}
void SetRound(entity client, float to) {
#ifndef HANDHELD
#ifndef NX
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_SETROUND);
WriteByte(MSG_MULTICAST, to);
msg_entity = client;
multicast('0 0 0', MULTICAST_ONE);
#endif
#endif
}
void SetPerk(entity client, float to)
{
#ifndef HANDHELD
#ifndef NX
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_PERK);
WriteLong(MSG_MULTICAST, to);
msg_entity = client;
multicast('0 0 0', MULTICAST_ONE);
#endif
#endif
}
void(float to) SwitchWeapon =
{
#ifndef HANDHELD
#ifndef NX
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_WEAPONCHANGE);
WriteByte(MSG_MULTICAST, to);
msg_entity = self;
multicast('0 0 0', MULTICAST_ONE);
// hotfix for weapon2models not reseting
self.weapon2model = GetWeapon2Model(to);
#endif
#endif
}
void(string to, float skin) UpdateVmodel =
{
#ifndef HANDHELD
#ifndef NX
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_UPDATEVMODEL);
WriteString(MSG_MULTICAST, to);
WriteByte(MSG_MULTICAST, skin);
msg_entity = self;
multicast('0 0 0', MULTICAST_ONE);
#endif
#endif
}
void(string to, float skin) UpdateV2model =
{
#ifndef HANDHELD
#ifndef NX
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_UPDATEV2MODEL);
WriteString(MSG_MULTICAST, to);
WriteByte(MSG_MULTICAST, skin);
msg_entity = self;
multicast('0 0 0', MULTICAST_ONE);
#endif
#endif
}
void(float broadcast_time, float type) BroadcastMessage =
{
#ifndef HANDHELD
#ifndef NX
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_BROADCAST);
WriteByte(MSG_MULTICAST, broadcast_time);
WriteByte(MSG_MULTICAST, type);
multicast('0 0 0', MULTICAST_ALL);
#endif
#endif
}
void(float playernum, float points, float am, float kills, string name, entity person) UpdatePlayerPoints =
{
#ifndef HANDHELD
#ifndef NX
if (player_count == 0) {
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_POINTUPDATE);
WriteByte(MSG_MULTICAST, playernum);
WriteLong(MSG_MULTICAST, points);
WriteLong(MSG_MULTICAST, am);
WriteLong(MSG_MULTICAST, kills);
WriteString(MSG_MULTICAST, name);
msg_entity = person;
multicast('0 0 0', MULTICAST_ONE);
}
else {
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_POINTUPDATE);
WriteByte(MSG_MULTICAST, playernum);
WriteLong(MSG_MULTICAST, points);
WriteLong(MSG_MULTICAST, am);
WriteLong(MSG_MULTICAST, kills);
WriteString(MSG_MULTICAST, name);
multicast('0 0 0', MULTICAST_ALL);
}
#endif
#endif
}
void(float count) UpdatePlayerCount = {
#ifndef HANDHELD
#ifndef NX
if (count == 0)
return;
else {
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_PLAYERUPDATE);
WriteByte(MSG_MULTICAST, count);
multicast('0 0 0', MULTICAST_ALL);
}
#endif
#endif
}
void(float newtime, float newtype, entity change) PromptLevelChange =
{
#ifndef HANDHELD
#ifndef NX
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_BLACKOUT);
WriteByte(MSG_MULTICAST, newtime);
WriteByte(MSG_MULTICAST, newtype);
msg_entity = change;
multicast('0 0 0', MULTICAST_ONE);
#endif
#endif
}
void(entity who) UpdatePunchangle =
{
// naievil -- shit logic lol...but result looks clean as fuck...
#ifndef HANDHELD
#ifndef NX
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_PUNCHANGLE);
WriteCoord(MSG_MULTICAST, who.punchangle_x);
WriteCoord(MSG_MULTICAST, who.punchangle_y);
WriteCoord(MSG_MULTICAST, who.punchangle_z);
msg_entity = who;
multicast('0 0 0', MULTICAST_ONE);
vector tempv = who.punchangle;
if (fabs(who.punchangle_x) > 0.01) {
if (who.punchangle_x >= 0.05*tempv_x)
who.punchangle_x -= 0.05*tempv_x;
else if (who.punchangle_x <= -0.05*tempv_x)
who.punchangle_x -= 0.05*tempv_x;
else
who.punchangle_x = 0;
} else
who.punchangle_x = 0;
if (fabs(who.punchangle_y) > 0.01) {
if (who.punchangle_y >= 0.05*tempv_y)
who.punchangle_y -= 0.05*tempv_y;
else if (who.punchangle_y <= -0.05*tempv_y)
who.punchangle_y -= 0.05*tempv_y;
else
who.punchangle_y = 0;
} else
who.punchangle_y = 0;
if (fabs(who.punchangle_z) > 0.01) {
if (who.punchangle_z >= 0.05*tempv_z)
who.punchangle_z -= 0.05*tempv_z;
else if (who.punchangle_z <= -0.05*tempv_z)
who.punchangle_z -= 0.05*tempv_z;
else
who.punchangle_z = 0;
} else
who.punchangle_z = 0;
#endif
#endif
}
#ifndef HANDHELD
#ifndef NX
void(string h, float h2, entity who) pushHUD = {
if (player_count == 0) {
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_HUDUPDATE);
WriteString(MSG_MULTICAST, h);
WriteByte(MSG_MULTICAST, h2);
msg_entity = who;
multicast('0 0 0', MULTICAST_ONE);
} else {
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_WEAPONUPDATE);
WriteString(MSG_MULTICAST, h);
WriteByte(MSG_MULTICAST, h2);
multicast('0 0 0', MULTICAST_ALL);
}
}
void (float wepnum, string wepname, string wvmodel, float mag, float reserve, string ads, float min, float max, string flash, float flashsize, string v2, float isd, entity who) sendCustomWeapon = {
if (player_count == 0) {
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_WEAPONUPDATE);
WriteByte(MSG_MULTICAST, wepnum);
WriteString(MSG_MULTICAST, wepname);
WriteString(MSG_MULTICAST, wvmodel);
WriteByte(MSG_MULTICAST, mag);
WriteByte(MSG_MULTICAST, reserve);
WriteString(MSG_MULTICAST, ads);
WriteByte(MSG_MULTICAST, min);
WriteByte(MSG_MULTICAST, max);
WriteString(MSG_MULTICAST, flash);
WriteByte(MSG_MULTICAST, flashsize);
WriteString(MSG_MULTICAST, v2);
WriteByte(MSG_MULTICAST, isd);
msg_entity = who;
multicast('0 0 0', MULTICAST_ONE);
} else {
WriteByte(MSG_ALL, SVC_CGAMEPACKET);
WriteByte(MSG_ALL, EVENT_WEAPONUPDATE);
WriteByte(MSG_ALL, wepnum);
WriteString(MSG_ALL, wepname);
WriteString(MSG_ALL, wvmodel);
WriteByte(MSG_ALL, mag);
WriteByte(MSG_ALL, reserve);
WriteString(MSG_ALL, ads);
WriteByte(MSG_ALL, min);
WriteByte(MSG_ALL, max);
WriteString(MSG_ALL, flash);
WriteByte(MSG_ALL, flashsize);
WriteString(MSG_ALL, v2);
WriteByte(MSG_ALL, isd);
}
}
void(string msg, entity who) ScrollText = {
if (player_count == 0) {
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_SCROLLTEXT);
WriteString(MSG_MULTICAST, msg);
msg_entity = who;
multicast('0 0 0', MULTICAST_ONE);
} else {
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_SCROLLTEXT);
WriteString(MSG_MULTICAST, msg);
multicast('0 0 0', MULTICAST_ALL);
}
}
void(string chaptertitle, string location, string date, string person, entity who) WorldText = {
if (player_count == 0) {
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_WORLDDATA);
WriteString(MSG_MULTICAST, chaptertitle);
WriteString(MSG_MULTICAST, location);
WriteString(MSG_MULTICAST, date);
WriteString(MSG_MULTICAST, person);
msg_entity = who;
multicast('0 0 0', MULTICAST_ONE);
} else {
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_WORLDDATA);
WriteString(MSG_MULTICAST, chaptertitle);
WriteString(MSG_MULTICAST, location);
WriteString(MSG_MULTICAST, date);
WriteString(MSG_MULTICAST, person);
multicast('0 0 0', MULTICAST_ALL);
}
}
#endif
#endif
#ifndef NX
void (float achievement_id, optional entity who) GiveAchievement =
{
#ifndef PC
// temp
if (achievement_id > 4)
return;
#endif // PC
// this is an achievement specific to an individual
if ((who && who != world) || player_count == 0) {
if (player_count == 0) who = find(world, classname, "player");
#ifndef PC
achievement(who, achievement_id);
#else
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_ACHIEVEMENT);
WriteByte(MSG_MULTICAST, achievement_id);
msg_entity = who;
multicast('0 0 0', MULTICAST_ONE);
#endif // PC
} else {
#ifndef PC
entity players;
players = find(world, classname, "player");
while(players != world) {
achievement(players, achievement_id);
players = find(players, classname, "player");
}
#else
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_ACHIEVEMENT);
WriteByte(MSG_MULTICAST, achievement_id);
multicast('0 0 0', MULTICAST_ALL);
#endif // PC
}
}
void (float achievement_id, float progress_value, optional entity who) UpdateAchievementProgress =
{
#ifndef PC
// temp
if (achievement_id > 4)
return;
#endif // PC
// this is a progress update specific to an individual
if ((who && who != world) || player_count == 0) {
if (player_count == 0) who = find(world, classname, "player");
#ifndef PC
//achievement_progress(who, achievement_id, progress_value);
#else
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_ACHIEVEMENTPROGRESS);
WriteByte(MSG_MULTICAST, achievement_id);
WriteFloat(MSG_MULTICAST, progress_value);
msg_entity = who;
multicast('0 0 0', MULTICAST_ONE);
#endif // PC
} else {
#ifndef PC
entity players;
players = find(world, classname, "player");
while(players != world) {
//achievement_progress(players, achievement_id, progress_value);
players = find(players, classname, "player");
}
#else
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_ACHIEVEMENTPROGRESS);
WriteByte(MSG_MULTICAST, achievement_id);
WriteFloat(MSG_MULTICAST, progress_value);
multicast('0 0 0', MULTICAST_ALL);
#endif // PC
}
}
#endif // NX
// *****************************************
// Unrelated to engine, but custom functions
// *****************************************
inline void(string modelname) Precache_Set = // Precache model, and set myself to it
{
precache_model(modelname);
setmodel(self, modelname);
};
float(entity who, entity target) isFacing =
{
float who_angle = who.angles_y;
float target_angle = target.angles_y;
float difference_angle = target_angle - who_angle;
#ifdef HANDHELD
if (difference_angle < -45) {
difference_angle += 360;
}
#endif
// 180 = directly facing each other, 30 degree buffer.
if (difference_angle <= 210 && difference_angle >= 150)
return true;
return false;
}
float() crandom =
{
return 2*(random() - 0.5);
}
void WeaponSwitch(entity player) {
float wep, cmag, cmag2, cammo;
wep = other.weapon;
other.weapon = other.secondaryweapon;
other.secondaryweapon = wep;
cmag = other.currentmag;
other.currentmag = other.secondarymag;
other.secondarymag = cmag;
cmag2 = other.currentmag2;
other.currentmag2 = other.secondarymag2;
other.secondarymag2 = cmag2;
cammo = other.currentammo;
other.currentammo = other.secondaryammo;
other.secondaryammo = cammo;
entity tempe = self;
self = player;
SwitchWeapon(other.weapon);
self = tempe;
}
void(entity person, float expamt, float doublepoint) addmoney =
{
if (person.classname != "player" || person.downed)
return;
if (expamt > 0 && doublepoint == TRUE && x2_finished > time) {
expamt *= 2;
person.score += expamt;
}
// Combine the positive score with the powerup score tally
if (expamt > 0)
total_powerup_points += expamt;
person.points += expamt;
UpdatePlayerPoints(person.playernum, person.points, expamt, person.kills, person.netname, person);
};
//
// Util_GetPlayerAmmoInSlot(person, slot)
// Returns the reserve ammo the player has in a weapon slot.
//
float(entity person, float slot) Util_GetPlayerAmmoInSlot =
{
switch(slot) {
case 1: return person.currentammo; break;
case 2: return person.secondaryammo; break;
case 3: return person.thirdammo; break;
default: return 0; break;
}
}
//
// Util_SetPlayerAmmoInSlot(person, slot, ammo)
// Sets the player's reserve ammo in a slot to param3.
//
void(entity person, float slot, float ammo) Util_SetPlayerAmmoInSlot =
{
switch(slot) {
case 1: person.currentammo = ammo; break;
case 2: person.secondaryammo = ammo; break;
case 3: person.thirdammo = ammo; break;
default: return; break;
}
};
//
// Util_PlayerHasWeapon(peron, comparison, include_pap)
// Checks to see if the Player is holding a weapon in any
// of their three slots. `include_pap` dictates whether to
// consider Pack-A-Punch'd varients. Returns 1, 2, 3 depending
// on the slot the weapon is contained in.
//
float(entity person, float comparison, float include_pap) Util_PlayerHasWeapon =
{
// Storage.
float first, second, third;
// If we're including pap'd weapons, just convert the weapon set to the base
// ones to save on comparison checks.
if (include_pap == true) {
first = EqualNonPapWeapon(person.weapon);
second = EqualNonPapWeapon(person.secondaryweapon);
third = EqualNonPapWeapon(person.thirdweapon);
} else {
first = person.weapon;
second = person.secondaryweapon;
third = person.thirdweapon;
}
// Now do the comparisons
if (first == comparison)
return 1;
if (second == comparison)
return 2;
if (third == comparison)
return 3;
return 0;
};
//
// Util_WeaponIsSemiAutomatic(float weapon)
// Checks weapon firetypes and returns true if intended
// to be semi-automatic.
//
float(float weapon) Util_WeaponIsSemiAutomatic =
{
float firetype = GetFiretype(weapon);
// Valid firetypes
if (firetype == FIRETYPE_SEMIAUTO || firetype == FIRETYPE_GRENADE ||
firetype == FIRETYPE_TESLA)
return true;
return false;
}
//
// Util_WeaponFiresTraceshot(weapon)
// Simply returns true if given weapon's firetype requires a
// firetrace to be used properly.
//
float(float weapon) Util_WeaponFiresTraceshot =
{
float firetype = GetFiretype(weapon);
// Valid firetypes
if (firetype == FIRETYPE_FULLAUTO || firetype == FIRETYPE_SEMIAUTO)
return true;
return false;
}