Initial commit, first day of work.

This commit is contained in:
Marco Cawthorne 2023-09-25 00:42:05 -07:00
commit 49189c008d
Signed by: eukara
GPG key ID: CE2032F0A2882A22
43 changed files with 6794 additions and 0 deletions

5
src/Makefile Normal file
View file

@ -0,0 +1,5 @@
CC=fteqcc
all:
cd client && $(MAKE)
cd server && $(MAKE)

4
src/client/Makefile Normal file
View file

@ -0,0 +1,4 @@
CC=fteqcc
all:
$(CC) progs.src

27
src/client/cmds.qc Normal file
View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2016-2020 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
void VGUI_ChooseClass(float);
int
ClientGame_ConsoleCommand(void)
{
switch(argv(0)) {
default:
return (0);
}
return (1);
}

2
src/client/defs.h Normal file
View file

@ -0,0 +1,2 @@
font_s FONT_HUD_CROSS;

26
src/client/draw.qc Normal file
View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2016-2021 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
void
ClientGame_PreDraw(void)
{
}
void
ClientGame_PostDraw(void)
{
}

21
src/client/flashlight.qc Normal file
View file

@ -0,0 +1,21 @@
/*
* Copyright (c) 2016-2020 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
void
Player_Flashlight(NSClientPlayer pl)
{
}

612
src/client/hud.qc Normal file
View file

@ -0,0 +1,612 @@
/*
* Copyright (c) 2016-2021 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
void HUD_DrawWeaponSelect(void);
/* Use first frame for drawing (needs precache) */
#define NUMSIZE_X 20/256
#define NUMSIZE_Y 28/64
#define HUD_ALPHA 0.75
float spr_hudnum[10] = {
2 / 256,
22 / 256,
42 / 256,
62 / 256,
82 / 256,
102 / 256,
122 / 256,
142 / 256,
162 / 256,
182 / 256
};
float spr_hudnum_small[12] = {
0 / 256,
10 / 256,
20 / 256,
30 / 256,
40 / 256,
50 / 256,
60 / 256,
70 / 256,
80 / 256,
90 / 256,
100 / 256,
110 / 256
};
/* pre-calculated sprite definitions */
float spr_health[4] = {
163 / 256, // pos x
29 / 64, // pos u
48 / 256, // size x
16 / 64 // size y
};
float spr_armor[4] = {
223 / 256, // pos x
28 / 64, // pos u
32 / 256, // size x
16 / 64 // size y
};
float spr_ammo[4] = {
120 / 256, // pos x
28 / 64, // pos u
32 / 256, // size x
16 / 64 // size y
};
float spr_flash1[4] = {
160 / 256, // pos x
24 / 128, // pos u
32 / 256, // size x
32 / 128 // size y
};
float spr_flash2[4] = {
112 / 256, // pos x
24 / 128, // pos u
48 / 256, // size x
32 / 128 // size y
};
/* precaches */
void
HUD_Init(void)
{
Font_Load("fonts/hud_cross.font", FONT_HUD_CROSS);
g_cross_spr = spriteframe("sprites/crosshairs.spr", 0, 0.0f);
g_laser_spr = spriteframe("sprites/laserdot.spr", 0, 0.0f);
g_hud1_spr = "materials/Sprites/hud1";
g_hud2_spr = "materials/Sprites/hud1";
g_hud3_spr = "materials/Sprites/hud1";
g_hud4_spr = "materials/Sprites/hud1";
g_hud5_spr = "materials/Sprites/hud1";
g_hud6_spr = "materials/Sprites/hud1";
g_hud7_spr = "materials/Sprites/hud1";
HUD_AmmoNotify_Init();
HUD_DamageNotify_Init();
HUD_ItemNotify_Init();
}
/* seperator for mainly ammo */
void
HUD_DrawSeperator(vector pos)
{
drawsubpic(pos,
[10,28],
g_hud7_spr,
[240/256, 0.0],
[10/256, 28/64],
g_hud_color,
1.0,
DRAWFLAG_ADDITIVE
);
}
/* handle single/multiple digits */
void
HUD_DrawNumber(int iNumber, vector vecPos, float fAlpha, vector vColor)
{
drawsubpic(vecPos,
[20,28],
g_hud7_spr,
[spr_hudnum[iNumber], 0],
[NUMSIZE_X, NUMSIZE_Y],
vColor,
fAlpha,
DRAWFLAG_ADDITIVE
);
}
void
HUD_DrawNumberS(int iNumber, vector vecPos, float fAlpha, vector vColor)
{
drawsubpic(vecPos,
[10,12],
g_hud7_spr,
[spr_hudnum_small[iNumber], 29/64],
[10/256, 12/64],
vColor,
fAlpha,
DRAWFLAG_ADDITIVE
);
}
void
HUD_DrawAmmoSeparator(vector vecPos)
{
drawsubpic(vecPos,
[10,28],
g_hud7_spr,
[240/256, 0.0],
[10/256, 28/256],
g_hud_color,
1.0,
DRAWFLAG_ADDITIVE
);
}
void
HUD_DrawNums(float fNumber, vector vecPos, float fAlpha, vector vColor)
{
int i = fNumber;
/* always draw 3 digits */
for (int x = 0; x < 3; x++) {
int b = (float)i % 10;
/* don't allow anything below 0 */
if (b < 0)
b = 0;
/* if we're a zero, but a leading one... */
if (b == 0)
if ((fNumber < 100 && x == 2) || (fNumber < 10 && x == 1) || (fNumber == 0))
fAlpha = 0.25f;
if (x == 1) {
drawsubpic(vecPos,
[20,28],
g_hud7_spr,
[220/256, 0.0],
[NUMSIZE_X, NUMSIZE_Y],
vColor,
fAlpha,
DRAWFLAG_ADDITIVE
);
} else if (x == 2) {
drawsubpic(vecPos,
[20,28],
g_hud7_spr,
[200/256, 0.0],
[NUMSIZE_X, NUMSIZE_Y],
vColor,
fAlpha,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(vecPos,
[20,28],
g_hud7_spr,
[200/256, 0.0],
[NUMSIZE_X, NUMSIZE_Y],
vColor,
fAlpha,
DRAWFLAG_ADDITIVE
);
}
HUD_DrawNumber(b, vecPos, fAlpha, vColor);
i = i / 10;
vecPos[0] -= 20;
}
}
void
HUD_DrawNumsS(float fNumber, vector vecPos, float fAlpha, vector vColor)
{
int i = fNumber;
/* always draw 3 digits */
for (int x = 0; x < 3; x++) {
int b = (float)i % 10;
/* don't allow anything below 0 */
if (b < 0)
b = 0;
/* if we're a zero, but a leading one... */
if (b == 0)
if ((fNumber < 100 && x == 2) || (fNumber < 10 && x == 1) || (fNumber == 0))
fAlpha = 0.25f;
if (x == 1) {
drawsubpic(vecPos,
[10,12],
g_hud7_spr,
[spr_hudnum_small[11], 29/64],
[10/256, 12/64],
vColor,
fAlpha,
DRAWFLAG_ADDITIVE
);
} else if (x == 2) {
drawsubpic(vecPos,
[10,12],
g_hud7_spr,
[spr_hudnum_small[10], 29/64],
[10/256, 12/64],
vColor,
fAlpha,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(vecPos,
[10,12],
g_hud7_spr,
[spr_hudnum_small[10], 29/64],
[10/256, 12/64],
vColor,
fAlpha,
DRAWFLAG_ADDITIVE
);
}
HUD_DrawNumberS(b, vecPos, fAlpha, vColor);
i = i / 10;
vecPos[0] -= 10;
}
}
/* health */
void
HUD_DrawHealth(void)
{
vector pos;
player pl = (player)pSeat->m_ePlayer;
if (pl.health != pSeatLocal->m_iHealthOld) {
pSeatLocal->m_flHealthAlpha = 1.0;
}
if (pSeatLocal->m_flHealthAlpha >= HUD_ALPHA) {
pSeatLocal->m_flHealthAlpha -= clframetime * 0.5;
} else {
pSeatLocal->m_flHealthAlpha = HUD_ALPHA;
}
pos = g_hudmins + [16, g_hudres[1] - 42];
if (pl.health > 25) {
drawsubpic(
pos + [0,-14],
[48,16],
g_hud7_spr,
[spr_health[0], spr_health[1]],
[spr_health[2], spr_health[3]],
g_hud_color,
pSeatLocal->m_flHealthAlpha,
DRAWFLAG_ADDITIVE
);
HUD_DrawNums(pl.health, pos + [40, 0], pSeatLocal->m_flHealthAlpha, g_hud_color);
} else {
drawsubpic(
pos + [-72,-14],
[48,16],
g_hud7_spr,
[spr_health[0], spr_health[1]],
[spr_health[2], spr_health[3]],
[1,0,0],
pSeatLocal->m_flHealthAlpha,
DRAWFLAG_ADDITIVE
);
HUD_DrawNums(pl.health, pos + [40, 0], pSeatLocal->m_flHealthAlpha, [1,0,0]);
}
pSeatLocal->m_iHealthOld = pl.health;
}
/* armor/suit charge */
void
HUD_DrawArmor(void)
{
vector pos;
player pl = (player)pSeat->m_ePlayer;
if (pl.armor != pSeatLocal->m_iArmorOld) {
pSeatLocal->m_flArmorAlpha = 1.0;
}
if (pSeatLocal->m_flArmorAlpha >= HUD_ALPHA) {
pSeatLocal->m_flArmorAlpha -= clframetime * 0.5;
} else {
pSeatLocal->m_flArmorAlpha = HUD_ALPHA;
}
pos = g_hudmins + [16+96, g_hudres[1] - 42];
if (pl.armor > 25) {
drawsubpic(
pos + [0,-14],
[32,16],
g_hud7_spr,
[spr_armor[0], spr_armor[1]],
[spr_armor[2], spr_armor[3]],
g_hud_color,
pSeatLocal->m_flArmorAlpha,
DRAWFLAG_ADDITIVE
);
HUD_DrawNums(pl.armor, pos + [40, 0], pSeatLocal->m_flArmorAlpha, g_hud_color);
} else {
drawsubpic(
pos + [-72,-14],
[32,16],
g_hud7_spr,
[spr_armor[0], spr_armor[1]],
[spr_armor[2], spr_armor[3]],
[1,0,0],
pSeatLocal->m_flArmorAlpha,
DRAWFLAG_ADDITIVE
);
HUD_DrawNums(pl.armor, pos + [40, 0], pSeatLocal->m_flArmorAlpha, [1,0,0]);
}
pSeatLocal->m_iArmorOld = pl.armor;
}
/* magazine/clip ammo */
void
HUD_DrawAmmo1(void)
{
player pl = (player)pSeat->m_ePlayer;
vector pos;
if (pl.a_ammo1 != pSeatLocal->m_iAmmo1Old) {
pSeatLocal->m_flAmmo1Alpha = 1.0;
pSeatLocal->m_iAmmo1Old = pl.a_ammo1;
}
if (pSeatLocal->m_flAmmo1Alpha >= HUD_ALPHA) {
pSeatLocal->m_flAmmo1Alpha -= clframetime * 0.5;
} else {
pSeatLocal->m_flAmmo1Alpha = HUD_ALPHA;
}
pos = g_hudmins + [g_hudres[0] - 152, g_hudres[1] - 42];
drawsubpic(
pos + [-38,-14],
[32,16],
g_hud7_spr,
[spr_ammo[0], spr_ammo[1]],
[spr_ammo[2], spr_ammo[3]],
g_hud_color,
pSeatLocal->m_flArmorAlpha,
DRAWFLAG_ADDITIVE
);
HUD_DrawNums(pl.a_ammo1, pos, pSeatLocal->m_flAmmo1Alpha, g_hud_color);
HUD_DrawSeperator(pos + [30,0]);
}
/* leftover type ammo */
void
HUD_DrawAmmo2(void)
{
player pl = (player)pSeat->m_ePlayer;
vector pos;
if (pl.a_ammo2 != pSeatLocal->m_iAmmo2Old) {
pSeatLocal->m_flAmmo2Alpha = 1.0;
pSeatLocal->m_iAmmo2Old = pl.a_ammo2;
}
if (pSeatLocal->m_flAmmo2Alpha >= HUD_ALPHA) {
pSeatLocal->m_flAmmo2Alpha -= clframetime * 0.5;
} else {
pSeatLocal->m_flAmmo2Alpha = HUD_ALPHA;
}
pos = g_hudmins + [g_hudres[0] - 80, g_hudres[1] - 42 + 5];
HUD_DrawNumsS(pl.a_ammo2, pos, pSeatLocal->m_flAmmo2Alpha, g_hud_color);
}
/* special ammo */
void
HUD_DrawAmmo3(void)
{
player pl = (player)pSeat->m_ePlayer;
vector pos;
if (pl.a_ammo3 != pSeatLocal->m_iAmmo3Old) {
pSeatLocal->m_flAmmo3Alpha = 1.0;
pSeatLocal->m_iAmmo3Old = pl.a_ammo3;
}
if (pSeatLocal->m_flAmmo3Alpha >= HUD_ALPHA) {
pSeatLocal->m_flAmmo3Alpha -= clframetime * 0.5;
} else {
pSeatLocal->m_flAmmo3Alpha = HUD_ALPHA;
}
pos = g_hudmins + [g_hudres[0] - 42, g_hudres[1] - 42 + 5];
HUD_DrawNumsS(pl.a_ammo3, pos, pSeatLocal->m_flAmmo3Alpha, g_hud_color);
}
/* ammo bar */
void
HUD_DrawAmmoBar(vector pos, float val, float max, float a)
{
if (val <= 0)
return;
float perc;
perc = val / max;
//drawfill(pos + [10,0], [20,4], g_hud_color, a, DRAWFLAG_NORMAL);
//drawfill(pos + [10,0], [20 * perc,4], [0,1,0], a, DRAWFLAG_NORMAL);
}
/* weapon/ammo pickup notifications */
void
HUD_DrawNotify(void)
{
player pl = (player)self;
vector pos;
float a;
pos = g_hudmins + [g_hudres[0] - 150, g_hudres[1] - 128];
if (pSeatLocal->m_flPickupAlpha <= 0.0f) {
pos[1] += 48;
//HUD_ItemNotify_Draw(pos);
//HUD_AmmoNotify_Draw(pos);
return;
}
a = bound(0.0, pSeatLocal->m_flPickupAlpha, 1.0);
pos[1] += 48 * (1.0 - a);
Weapons_HUDPic(pl, pSeatLocal->m_iPickupWeapon, 1, pos, a);
//HUD_ItemNotify_Draw(pos);
//HUD_AmmoNotify_Draw(pos);
pSeatLocal->m_flPickupAlpha -= (clframetime * 0.5);
}
void
HUD_WeaponPickupNotify(int w)
{
#if defined (VALVE) || defined (GEARBOX)
switch (w) {
case WEAPON_SNARK:
case WEAPON_SATCHEL:
case WEAPON_HANDGRENADE:
case WEAPON_TRIPMINE:
#if defined(GEARBOX)
case WEAPON_PENGUIN:
#endif
return;
default:
}
#endif
pSeatLocal->m_iPickupWeapon = w;
pSeatLocal->m_flPickupAlpha = 2.5f;
}
void
HUD_DrawDamageIndicator(void)
{
vector cross_pos;
if (pSeatLocal->m_flDamageIndicator <= 0.0)
return;
cross_pos = g_hudmins + (g_hudres / 2) + [-12,-12];
/*drawsubpic(
cross_pos,
[24,24],
g_cross_spr,
[0.0, 72/128],
[0.1875, 0.1875],
[1,1,1] * pSeatLocal->m_flDamageIndicator,
1.0f,
DRAWFLAG_ADDITIVE
);*/
pSeatLocal->m_flDamageIndicator -= clframetime;
}
void
HUD_TimeRemaining(void)
{
vector iconPos = g_hudmins + [16, g_hudres[1] - 64];
/* display time if timelimit is being hit */
if (serverkeyfloat("timelimit")) {
string tempstr = strcat("Time Remaining: ", Util_GetTime());
Font_DrawText_RGB(iconPos, tempstr, g_hud_color, FONT_20);
}
}
/* main entry */
void
HUD_Draw(void)
{
player pl = (player)pSeat->m_ePlayer;
g_hud_color = [1, 0.75f, 0.25];
/* little point in not drawing these, even if you don't have a suit */
Weapons_DrawCrosshair(pl);
{
}
HUD_DrawDamageIndicator();
HUD_DrawWeaponSelect();
Obituary_Draw();
Textmenu_Draw();
HUD_TimeRemaining();
if (!(pl.g_items & ITEM_SUIT)) {
return;
}
HUD_DamageNotify_Draw();
HUD_DrawHealth();
HUD_DrawArmor();
HUD_DrawNotify();
Damage_Draw();
}
string g_specmodes[] = {
"Free Camera",
"Third Person",
"First Person"
};
/* specatator main entry */
void
HUD_DrawSpectator(void)
{
Textmenu_Draw();
NSClientSpectator spec = (NSClientSpectator)pSeat->m_ePlayer;
drawfont = Font_GetID(FONT_20);
vector vecPos = [0.0f, 0.0f, 0.0f];
string strText = __NULL__;
float palpha = 1.0f;
if (spec.spec_mode == SPECMODE_FREE) {
palpha = 0.5f;
}
strText = sprintf("Tracking: %s", getplayerkeyvalue(spec.spec_ent - 1, "name"));
vecPos[0] = g_hudmins[0] + (g_hudres[0] / 2) - (stringwidth(strText, TRUE, [20,20]) / 2);
vecPos[1] = g_hudmins[1] + g_hudres[1] - 60;
drawstring(vecPos, strText, [20,20], [1,1,1], palpha, DRAWFLAG_ADDITIVE);
strText = sprintf("Mode: %s", g_specmodes[spec.spec_mode]);
vecPos[0] = g_hudmins[0] + (g_hudres[0] / 2) - (stringwidth(strText, TRUE, [20,20]) / 2);
vecPos[1] = g_hudmins[1] + g_hudres[1] - 40;
drawstring(vecPos, strText, [20,20], [1,1,1], 1.0f, DRAWFLAG_ADDITIVE);
}

View file

@ -0,0 +1,247 @@
/*
* Copyright (c) 2016-2020 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
vector g_vecHUDNums[8] =
{
[46 / 256,44 / 64],
[66 / 256,44 / 64],
[87 / 256,44 / 64],
[109 / 256,44 / 64],
[131 / 256,44 / 64],
[153 / 256,44 / 64],
[175 / 256,44 / 64],
[197 / 256,44 / 64],
};
void
HUD_DrawWeaponSelect_Forward(void)
{
player pl = (player)pSeat->m_ePlayer;
if (!pl.activeweapon) {
return;
}
if (pSeat->m_flHUDWeaponSelectTime < time) {
pSeat->m_iHUDWeaponSelected = pl.activeweapon;
sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_hudon.wav", 0.5, ATTN_NONE);
} else {
sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_moveselect.wav", 0.5, ATTN_NONE);
pSeat->m_iHUDWeaponSelected--;
if (pSeat->m_iHUDWeaponSelected <= 0) {
pSeat->m_iHUDWeaponSelected = g_weapons.length - 1;
}
}
pSeat->m_flHUDWeaponSelectTime = time + 3;
/* compiler bug */
if (pl.g_items & g_weapons[pSeat->m_iHUDWeaponSelected].id) {
} else {
HUD_DrawWeaponSelect_Forward();
}
}
void
HUD_DrawWeaponSelect_Back(void)
{
player pl = (player)pSeat->m_ePlayer;
if (!pl.activeweapon) {
return;
}
if (pSeat->m_flHUDWeaponSelectTime < time) {
pSeat->m_iHUDWeaponSelected = pl.activeweapon;
sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_hudon.wav", 0.5, ATTN_NONE);
} else {
sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_moveselect.wav", 0.5, ATTN_NONE);
pSeat->m_iHUDWeaponSelected++;
if (pSeat->m_iHUDWeaponSelected >= g_weapons.length) {
pSeat->m_iHUDWeaponSelected = 1;
}
}
pSeat->m_flHUDWeaponSelectTime = time + 3;
/* compiler bug */
if (pl.g_items & g_weapons[pSeat->m_iHUDWeaponSelected].id) {
} else {
HUD_DrawWeaponSelect_Back();
}
}
void
HUD_DrawWeaponSelect_Trigger(void)
{
player pl = (player)pSeat->m_ePlayer;
pl.activeweapon = pSeat->m_iHUDWeaponSelected;
sendevent("PlayerSwitchWeapon", "i", pSeat->m_iHUDWeaponSelected);
sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_select.wav", 0.5f, ATTN_NONE);
pSeat->m_iHUDWeaponSelected = pSeat->m_flHUDWeaponSelectTime = 0;
}
void
HUD_DrawWeaponSelect_Last(void)
{
player pl = (player)pSeat->m_ePlayer;
if (pl.g_items & g_weapons[pSeat->m_iOldWeapon].id) {
pl.activeweapon = pSeat->m_iOldWeapon;
sendevent("PlayerSwitchWeapon", "i", pSeat->m_iOldWeapon);
}
}
void
HUD_DrawWeaponSelect_Num2(vector vecPos, float fValue)
{
drawsubpic(vecPos, [16,16], g_hud7_spr, [24/256, 44/64], [16/256, 16/64], g_hud_color, 1, DRAWFLAG_ADDITIVE);
drawsubpic(vecPos, [16,16], g_hud7_spr, g_vecHUDNums[fValue], [16/255, 16/64], g_hud_color, 1, DRAWFLAG_ADDITIVE);
}
void
HUD_DrawWeaponSelect_Num(vector vecPos, float fValue)
{
drawsubpic(vecPos, [16,16], g_hud7_spr, g_vecHUDNums[fValue], [16/255, 16/64], g_hud_color, 1, DRAWFLAG_ADDITIVE);
}
int
HUD_InSlotPos(int slot, int pos)
{
player pl = (player)pSeat->m_ePlayer;
for (int i = 1; i < g_weapons.length; i++) {
if (g_weapons[i].slot == slot && g_weapons[i].slot_pos == pos) {
if (pl.g_items & g_weapons[i].id) {
return i;
} else {
return (-1);
}
}
}
return (-1);
}
void
HUD_SlotSelect(int slot)
{
player pl = (player)pSeat->m_ePlayer;
int curslot = g_weapons[pSeat->m_iHUDWeaponSelected].slot;
int i;
if (g_textmenu != "") {
Textmenu_Input(slot);
return;
}
/* hack to see if we have ANY weapons at all. */
if (!pl.activeweapon) {
return;
}
if (pSeat->m_flHUDWeaponSelectTime < time) {
sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_hudon.wav", 0.5, ATTN_NONE);
} else {
sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_moveselect.wav", 0.5, ATTN_NONE);
}
/* weren't in that slot? select the first one then */
if (curslot != slot) {
for (i = 1; i < g_weapons.length; i++) {
if (g_weapons[i].slot == slot && pl.g_items & g_weapons[i].id) {
pSeat->m_iHUDWeaponSelected = i;
pSeat->m_flHUDWeaponSelectTime = time + 3;
break;
}
}
} else {
int first = -1;
for (i = 1; i < g_weapons.length; i++) {
if (g_weapons[i].slot == slot && pl.g_items & g_weapons[i].id) {
if (i < pSeat->m_iHUDWeaponSelected && first == -1) {
first = i;
} else if (i > pSeat->m_iHUDWeaponSelected) {
first = -1;
pSeat->m_iHUDWeaponSelected = i;
pSeat->m_flHUDWeaponSelectTime = time + 3;
break;
}
}
}
if (first > 0) {
pSeat->m_iHUDWeaponSelected = first;
pSeat->m_flHUDWeaponSelectTime = time + 3;
}
}
}
void
HUD_DrawWeaponSelect(void)
{
player pl = (player)pSeat->m_ePlayer;
if (!pl.activeweapon) {
return;
}
if (pSeat->m_flHUDWeaponSelectTime < time) {
if (pSeat->m_iHUDWeaponSelected) {
sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_hudoff.wav", 0.5, ATTN_NONE);
pSeat->m_iHUDWeaponSelected = 0;
}
return;
}
vector vecPos = g_hudmins + [16,16];
int b;
int wantslot = g_weapons[pSeat->m_iHUDWeaponSelected].slot;
int wantpos = g_weapons[pSeat->m_iHUDWeaponSelected].slot_pos;
for (int i = 0; i < 6; i++) {
int slot_selected = 0;
vecPos[1] = g_hudmins[1] + 16;
if (i == wantslot)
HUD_DrawWeaponSelect_Num2(vecPos, i);
else
HUD_DrawWeaponSelect_Num(vecPos, i);
vecPos[1] += 20;
for (int x = 0; x < 32; x++) {
if (i == wantslot) {
slot_selected = TRUE;
if (x == wantpos) {
// Selected Sprite
Weapons_HUDPic(pl, pSeat->m_iHUDWeaponSelected, 1, vecPos, 1.0f);
Weapons_HUDPic(pl, pSeat->m_iHUDWeaponSelected, 1, vecPos, 1.0f);
vecPos[1] += 64;
} else if ((b=HUD_InSlotPos(i, x)) != -1) {
// Unselected Sprite
Weapons_HUDPic(pl, b, 0, vecPos, 1.0f);
vecPos[1] += 64;
}
} else if (HUD_InSlotPos(i, x) != -1) {
HUD_DrawWeaponSelect_Num(vecPos, 7);
vecPos[1] += 25;
}
}
if (slot_selected == TRUE) {
vecPos[0] += 128;
} else {
vecPos[0] += 25;
}
}
}

55
src/client/init.qc Normal file
View file

@ -0,0 +1,55 @@
/*
* Copyright (c) 2016-2020 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
float(entity foo, float chanid) getchannellevel = #0;
void VGUI_ChooseTeam(void);
/*
=================
ClientGame_Init
Comparable to worldspawn in SSQC in that it's mostly used for precaches
=================
*/
void
ClientGame_Init(float apilevel, string enginename, float engineversion)
{
registercommand("changeteam");
registercommand("changeclass");
Obituary_Init();
}
void
ClientGame_InitDone(void)
{
}
void HLSprite_Init(void);
void
ClientGame_RendererRestart(string rstr)
{
Obituary_Precache();
Damage_Precache();
FX_Blood_Init();
/* there's also muzzleflash.spr, but that's just MUZZLE_SMALL again */
MUZZLE_RIFLE = (int)getmodelindex("sprites/muzzleflash1.spr");
MUZZLE_SMALL = (int)getmodelindex("sprites/muzzleflash2.spr");
MUZZLE_WEIRD = (int)getmodelindex("sprites/muzzleflash3.spr");
BEAM_TRIPMINE = particleeffectnum("weapon_tripmine.beam");
}

46
src/client/progs.src Normal file
View file

@ -0,0 +1,46 @@
#pragma target fte_5768
//#pragma flag enable assumeint
#pragma progs_dat "../../csprogs.dat"
#define CSQC
#define CLIENT
#define HL2
#includelist
../../../src/shared/fteextensions.qc
../../../src/shared/defs.h
../../../valve/src/client/defs.h
../../../src/client/defs.h
defs.h
../../../src/vgui/include.src
../../../src/gs-entbase/client.src
../../../src/gs-entbase/shared.src
../shared/include.src
flashlight.qc
../../../valve/src/client/damage.qc
draw.qc
init.qc
../../../valve/src/client/entities.qc
cmds.qc
../../../valve/src/client/game_event.qc
../../../valve/src/client/camera.qc
viewmodel.qc
../../../valve/src/client/view.qc
../../../valve/src/client/obituary.qc
../../../valve/src/client/hud_sprite.qc
../../../valve/src/client/hud_ammonotify.qc
../../../valve/src/client/hud_dmgnotify.qc
../../../valve/src/client/hud_itemnotify.qc
hud.qc
hud_weaponselect.qc
../../../valve/src/client/scoreboard.qc
../../../valve/src/client/modelevent.qc
../../../src/client/include.src
vgui_changechar.qc
vgui_chooseteam.qc
../../../src/shared/include.src
#endlist

View file

@ -0,0 +1,304 @@
/*
* Copyright (c) 2016-2020 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
static string g_charDescrAdrian;
static string g_charDescrBarney;
static string g_charDescrCivRandom;
static string g_charDescrCleansuit;
static string g_charDescrDrillsgt;
static string g_charDescrGina;
static string g_charDescrGordon;
static string g_charDescrGrunt;
static string g_charDescrRandom;
static string g_charDescrOtis;
static string g_charDescrTandom;
static string g_charDescrRecruit;
static string g_charDescrScientist;
static string g_charDescrSquadleader;
static string g_charDescrTower;
static void
OP4Char_Init(void)
{
g_charDescrAdrian = textfile_to_string("classes/short_adrian.txt");
g_charDescrBarney = textfile_to_string("classes/short_barney.txt");
g_charDescrCivRandom = textfile_to_string("classes/short_civ_random.txt");
g_charDescrCleansuit = textfile_to_string("classes/short_cleansuit.txt");
g_charDescrDrillsgt = textfile_to_string("classes/short_drillsgt.txt");
g_charDescrGina = textfile_to_string("classes/short_gina.txt");
g_charDescrGordon = textfile_to_string("classes/short_gordon.txt");
g_charDescrGrunt = textfile_to_string("classes/short_grunt.txt");
g_charDescrRandom = textfile_to_string("classes/short_op4_random.txt");
g_charDescrOtis = textfile_to_string("classes/short_otis.txt");
g_charDescrTandom = textfile_to_string("classes/short_random.txt");
g_charDescrRecruit = textfile_to_string("classes/short_recruit.txt");
g_charDescrScientist = textfile_to_string("classes/short_scientist.txt");
g_charDescrSquadleader = textfile_to_string("classes/short_squadleader.txt");
g_charDescrTower = textfile_to_string("classes/short_tower.txt");
}
static VGUIWindow winCharSelection;
static VGUIPic imgCharPreview;
static VGUILabel lblCharTitle;
static VGUILabel lblCharDescription;
static VGUILabel lblCharCounter;
class OP4CharButton:VGUIButton
{
void OP4CharButton(void);
virtual void OnMouseUp(void);
virtual void OnMouseEntered(void);
};
void
OP4CharButton::OP4CharButton(void)
{
}
void
OP4CharButton::OnMouseUp(void)
{
int classSelection = GetTag();
sendevent("ClassJoin", "f", (float)classSelection);
winCharSelection.Hide();
}
void
OP4CharButton::OnMouseEntered(void)
{
int classSelection = GetTag();
switch (classSelection) {
case 1:
lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_Barney"));
imgCharPreview.SetImage("gfx/vgui/640_barney");
lblCharDescription.SetTitle(g_charDescrBarney);
break;
case 2:
lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_Cleansuit"));
imgCharPreview.SetImage("gfx/vgui/640_cleansuit");
lblCharDescription.SetTitle(g_charDescrCleansuit);
break;
case 3:
lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_Gina"));
imgCharPreview.SetImage("gfx/vgui/640_gina");
lblCharDescription.SetTitle(g_charDescrGina);
break;
case 4:
lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_Gordon"));
imgCharPreview.SetImage("gfx/vgui/640_gordon");
lblCharDescription.SetTitle(g_charDescrGordon);
break;
case 5:
lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_Otis"));
imgCharPreview.SetImage("gfx/vgui/640_otis");
lblCharDescription.SetTitle(g_charDescrOtis);
break;
case 6:
lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_Scientist"));
imgCharPreview.SetImage("gfx/vgui/640_scientist");
lblCharDescription.SetTitle(g_charDescrScientist);
break;
case 0:
lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_Civ_Random"));
imgCharPreview.SetImage("gfx/vgui/640_civ_random");
lblCharDescription.SetTitle(g_charDescrCivRandom);
break;
case 7:
lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_SquadLeader"));
imgCharPreview.SetImage("gfx/vgui/640_squadleader");
lblCharDescription.SetTitle(g_charDescrSquadleader);
break;
case 8:
lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_DrillSgt"));
imgCharPreview.SetImage("gfx/vgui/640_drillsgt");
lblCharDescription.SetTitle(g_charDescrDrillsgt);
break;
case 9:
lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_Grunt"));
imgCharPreview.SetImage("gfx/vgui/640_grunt");
lblCharDescription.SetTitle(g_charDescrGrunt);
break;
case 10:
lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_Recruit"));
imgCharPreview.SetImage("gfx/vgui/640_recruit");
lblCharDescription.SetTitle(g_charDescrRecruit);
break;
case 11:
lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_Adrian"));
imgCharPreview.SetImage("gfx/vgui/640_adrian");
lblCharDescription.SetTitle(g_charDescrAdrian);
break;
case 12:
lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_Tower"));
imgCharPreview.SetImage("gfx/vgui/640_tower");
lblCharDescription.SetTitle(g_charDescrTower);
break;
case 13:
lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_Op4_Random"));
imgCharPreview.SetImage("gfx/vgui/640_op4_random");
lblCharDescription.SetTitle(g_charDescrTandom);
break;
}
}
/*
Char/Char list:
Barney
CleansuitSci
Gina
Freeman
Otis
Walter(Scientist)
Random
Squad Leader
Drill Sgt
Grunt
Recruit
Shepard
Tower
OP4Random
*/
string g_classnames_blackmesa [] = {
"Barney",
"Cleansuit",
"Gina",
"Gordon",
"Otis",
"Scientist",
"Civ_Random"
};
string g_classnames_opfor [] = {
"SquadLeader",
"DrillSgt",
"Grunt",
"Recruit",
"Adrian",
"Tower",
"Op4_Random"
};
void
VGUI_ChooseClass(float teamChoice)
{
static int initialized;
static OP4CharButton *btns;
static VGUILabel lblSelectChar;
static VGUIFrame frmCharInfo;
if (!teamChoice)
teamChoice = getplayerkeyfloat(player_localnum, "*team");
if (!initialized) {
vector btnpos = [40,80];
initialized = TRUE;
OP4Char_Init();
winCharSelection = spawn(VGUIWindow);
winCharSelection.SetSize([640, 480]);
winCharSelection.SetStyleMask(VGUIWindowBorderless | VGUIWindowFullscreen);
lblSelectChar = spawn(VGUILabel);
lblSelectChar.SetTitle(Titles_GetTextBody("CTFTitle_SelectYourCharacter"));
lblSelectChar.SetTextSize(19);
lblSelectChar.SetPos([40, 38]);
lblSelectChar.SetSize([400, 24]);
frmCharInfo = spawn(VGUIFrame);
frmCharInfo.SetPos([176, 80]);
frmCharInfo.SetSize([424, 312]);
imgCharPreview = spawn(VGUIPic);
imgCharPreview.SetPos([190, 90]);
lblCharTitle = spawn(VGUILabel);
lblCharTitle.SetPos([338, 90]);
lblCharTitle.SetTextSize(19);
lblCharTitle.SetSize([320, 24]);
lblCharCounter = spawn(VGUILabel);
lblCharCounter.SetPos([338, 90 + 32]);
lblCharCounter.SetSize([320, 18]);
lblCharDescription = spawn(VGUILabel);
lblCharDescription.SetPos([338, 90 + 32 + 32]);
lblCharDescription.SetSize([250, 240]);
g_uiDesktop.Add(winCharSelection);
winCharSelection.Add(lblSelectChar);
winCharSelection.Add(frmCharInfo);
winCharSelection.Add(imgCharPreview);
winCharSelection.Add(lblCharTitle);
winCharSelection.Add(lblCharCounter);
winCharSelection.Add(lblCharDescription);
btns = memalloc(sizeof(OP4CharButton) * g_classnames_blackmesa.length);
for (int i = 0; i < g_classnames_blackmesa.length; i++) {
btns[i] = spawn(OP4CharButton);
btns[i].SetTitle(Titles_GetTextBody(g_classnames_blackmesa[i]));
btns[i].SetSize([124, 24]);
btns[i].SetPos(btnpos);
if (i == 7) {
btns[i].SetKeyEquivalent("0");
btns[i].SetTag(0);
} else {
btns[i].SetKeyEquivalent(ftos((float)i+1));
btns[i].SetTag(i+1i);
}
winCharSelection.Add(btns[i]);
btnpos[1] += 32;
}
}
/* relabel the buttons for the currently selected team. */
for (int i = 0; i < g_classnames_blackmesa.length; i++) {
if (teamChoice == 1) {
btns[i].SetTitle(Titles_GetTextBody(g_classnames_blackmesa[i]));
if (i == 6) {
btns[i].SetKeyEquivalent("0");
btns[i].SetTag(0);
} else {
btns[i].SetKeyEquivalent(ftos((float)i+1));
btns[i].SetTag(i+1i);
}
} else {
btns[i].SetTitle(Titles_GetTextBody(g_classnames_opfor[i]));
if (i == 6) {
btns[i].SetTag(13);
btns[i].SetKeyEquivalent("0");
} else {
btns[i].SetTag(6 + i+1i);
btns[i].SetKeyEquivalent(ftos((float)i+1));
}
}
}
winCharSelection.Show();
winCharSelection.SetPos((video_res / 2) - (winCharSelection.GetSize() / 2));
}

View file

@ -0,0 +1,165 @@
/*
* Copyright (c) 2016-2020 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
static VGUIWindow winChooseTeam;
class OP4TeamButton:VGUIButton
{
void OP4TeamButton(void);
virtual void OnMouseUp(void);
};
void
OP4TeamButton::OP4TeamButton(void)
{
}
void
OP4TeamButton::OnMouseUp(void)
{
int tag = GetTag();
VGUI_ChooseClass(tag);
sendevent("TeamJoin", "f", (float)tag);
winChooseTeam.Hide();
}
string
VGUI_ChooseTeam_MapInfo(void)
{
static string mapinfo = __NULL__;
if (mapinfo != __NULL__)
return mapinfo;
filestream fileMap = fopen(strcat("maps/", mapname, ".txt"), FILE_READ);
string temp;
if (fileMap != -1) {
while ((temp = fgets(fileMap))) {
mapinfo = strcat(mapinfo, temp, "\n");
}
} else {
mapinfo = Titles_GetTextBody("Map_Description_not_available");
}
return mapinfo;
}
void
VGUI_ChooseTeam(void)
{
static int initialized;
static VGUIButton btnAutoAssign;
static VGUIButton btnGoSpectator;
static VGUIFrame frmMapInfo;
static VGUILabel lblSelectTeam;
static VGUILabel lblMapName;
static VGUILabel lblMapInfo;
static void VGUI_AutoAssign(void) {
float tag = (random() < 0.5) ? 1 : 2;
VGUI_ChooseClass(tag);
sendevent("TeamJoin", "f", tag);
winChooseTeam.Hide();
}
static void VGUI_GoSpectator(void) {
sendevent("TeamJoin", "f", 0);
winChooseTeam.Hide();
}
if (!initialized) {
vector btnpos = [40,80];
initialized = TRUE;
winChooseTeam = spawn(VGUIWindow);
winChooseTeam.SetSize('640 480');
winChooseTeam.SetStyleMask(VGUIWindowBorderless | VGUIWindowFullscreen);
lblSelectTeam = spawn(VGUILabel);
lblSelectTeam.SetTitle(Titles_GetTextBody("CTFTitle_SelectYourTeam"));
lblSelectTeam.SetTextSize(19);
lblSelectTeam.SetPos([40, 38]);
lblSelectTeam.SetSize('400 24');
frmMapInfo = spawn(VGUIFrame);
frmMapInfo.SetPos('176 80');
frmMapInfo.SetSize('424 312');
lblMapName = spawn(VGUILabel);
lblMapName.SetTitle(mapname);
lblMapName.SetTextSize(19);
lblMapName.SetPos('194 105');
lblMapName.SetSize('250 312');
lblMapInfo = spawn(VGUILabel);
lblMapInfo.SetTitle(VGUI_ChooseTeam_MapInfo());
lblMapInfo.SetPos('194 129');
lblMapInfo.SetSize('375 250');
for (int t = 1; t <= serverkeyfloat("teams"); t++) {
OP4TeamButton btnForTeam;
string team_name = serverkey(sprintf("team_%i", t));
btnForTeam = spawn(OP4TeamButton);
btnForTeam.SetTitle(team_name);
btnForTeam.SetPos(btnpos);
btnForTeam.SetKeyEquivalent(ftos((float)t));
btnForTeam.SetSize('124 24');
switch (team_name) {
case "Black Mesa":
btnForTeam.SetTag(1);
break;
case "Opposing Force":
btnForTeam.SetTag(2);
break;
}
winChooseTeam.Add(btnForTeam);
btnpos[1] += 32;
}
btnAutoAssign = spawn(VGUIButton);
btnAutoAssign.SetTitle(Titles_GetTextBody("CTFTeam_AutoAssign"));
btnAutoAssign.SetPos(btnpos);
btnAutoAssign.SetSize('124 24');
btnAutoAssign.SetKeyEquivalent("5");
btnAutoAssign.SetFunc(VGUI_AutoAssign);
btnpos[1] += 32;
btnGoSpectator = spawn(VGUIButton);
btnGoSpectator.SetTitle(Titles_GetTextBody("CTFMenu_Spectate"));
btnGoSpectator.SetPos(btnpos);
btnGoSpectator.SetSize('124 24');
btnGoSpectator.SetKeyEquivalent("6");
btnGoSpectator.SetFunc(VGUI_GoSpectator);
g_uiDesktop.Add(winChooseTeam);
winChooseTeam.Add(frmMapInfo);
winChooseTeam.Add(lblSelectTeam);
winChooseTeam.Add(lblMapName);
winChooseTeam.Add(lblMapInfo);
winChooseTeam.Add(btnAutoAssign);
winChooseTeam.Add(btnGoSpectator);
}
winChooseTeam.Show();
winChooseTeam.SetPos((video_res / 2) - (winChooseTeam.GetSize() / 2));
}

162
src/client/viewmodel.qc Normal file
View file

@ -0,0 +1,162 @@
/*
* Copyright (c) 2016-2021 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* very primitive bobbing code, similar to Quake. Some ideas:
- allow for a second bob that runs at a separate cycle speed
- second bob could be applied to the side, would give a Doom III/HL2/TS
like viewmodel bob that people may like
*/
var float autocvar_v_bob = 0.005;
var float autocvar_v_bobcycle = 0.6;
var float autocvar_v_bobup = 0.5;
var float autocvar_v_bob2 = 0.005;
var float autocvar_v_bob2cycle = 1.4;
var float autocvar_v_bob2up = 0.5;
struct
{
float m_flBobTime;
float m_flBob;
float m_flBobCycle;
float m_flSpeed;
} g_viewBobVars[4], *pViewBob;
struct
{
float m_flBobTime;
float m_flBob;
float m_flBobCycle;
float m_flSpeed;
} g_viewBobVars2[4], *pViewBob2;
void
Viewmodel_CalcBob2(void)
{
vector vecVel;
float flBob;
int iCycle;
int s = (float)getproperty(VF_ACTIVESEAT);
pViewBob2 = &g_viewBobVars2[s];
float var_bob;
float var_cycle;
float var_up;
var_bob = autocvar_v_bob;
var_cycle = autocvar_v_bob2cycle;
var_up = autocvar_v_bob2up;
/* how many cycles have we done in total */
iCycle = (pViewBob2->m_flBobTime / var_cycle);
/* increment the input value for our cycle */
pViewBob2->m_flBobTime += frametime;
/* calculate the point in the cycle based on the input time */
pViewBob2->m_flBobCycle = pViewBob2->m_flBobTime - (iCycle * var_cycle);
pViewBob2->m_flBobCycle /= var_cycle;
/* prepare for our cycle value to be placed into sin() to get the wave motion */
pViewBob2->m_flBobCycle = MATH_PI * (pViewBob2->m_flBobCycle / var_up);
/* we based the speed on the clients movement speed, but ignore any height/jump velocity */
vecVel = pSeat->m_vecPredictedVelocity;
vecVel[2] = 0;
pViewBob2->m_flSpeed = vlen(vecVel);
/* bob equals speed times strength times cycle */
flBob = ((pViewBob2->m_flSpeed * var_bob) * sin(pViewBob2->m_flBobCycle));
/* clamp between -8 and 4 units */
pViewBob2->m_flBob = bound(-8, flBob, 4);
/* make sure it's adjusted for scale */
pViewBob2->m_flBob *= autocvar_cg_viewmodelScale;
}
/* bob vars are calculated separately from application, so that if there's
* more than one viewmodel we won't affect the speed of the bob by running
* the math too many times */
void
Viewmodel_CalcBob(void)
{
vector vecVel;
float flBob;
int iCycle;
int s = (float)getproperty(VF_ACTIVESEAT);
pViewBob = &g_viewBobVars[s];
float var_bob;
float var_cycle;
float var_up;
var_bob = autocvar_v_bob;
var_cycle = autocvar_v_bobcycle;
var_up = autocvar_v_bobup;
/* how many cycles have we done in total */
iCycle = (pViewBob->m_flBobTime / var_cycle);
/* increment the input value for our cycle */
pViewBob->m_flBobTime += frametime;
/* calculate the point in the cycle based on the input time */
pViewBob->m_flBobCycle = pViewBob->m_flBobTime - (iCycle * var_cycle);
pViewBob->m_flBobCycle /= var_cycle;
/* prepare for our cycle value to be placed into sin() to get the wave motion */
pViewBob->m_flBobCycle = MATH_PI * (pViewBob->m_flBobCycle / var_up);
/* we based the speed on the clients movement speed, but ignore any height/jump velocity */
vecVel = pSeat->m_vecPredictedVelocity;
vecVel[2] = 0;
pViewBob->m_flSpeed = vlen(vecVel);
/* bob equals speed times strength times cycle */
flBob = ((pViewBob->m_flSpeed * var_bob) * sin(pViewBob->m_flBobCycle));
/* clamp between -8 and 4 units */
pViewBob->m_flBob = bound(-8, flBob, 4);
/* make sure it's adjusted for scale */
pViewBob->m_flBob *= autocvar_cg_viewmodelScale;
Viewmodel_CalcBob2();
}
float
Viewmodel_GetBob(void)
{
int s = (float)getproperty(VF_ACTIVESEAT);
pViewBob = &g_viewBobVars[s];
return pViewBob->m_flBob;
}
void
Viewmodel_ApplyBob(entity gun)
{
int s = (float)getproperty(VF_ACTIVESEAT);
pViewBob = &g_viewBobVars[s];
/* apply the gun offset based on our bob */
gun.origin += v_up * (pViewBob->m_flBob * 0.2) + v_right * (pViewBob2->m_flBob * 0.4);
}

2
src/progs.src Executable file
View file

@ -0,0 +1,2 @@
#pragma sourcefile client/progs.src
#pragma sourcefile server/progs.src

4
src/server/Makefile Normal file
View file

@ -0,0 +1,4 @@
CC=fteqcc
all:
$(CC) progs.src

106
src/server/ctfitem.qc Normal file
View file

@ -0,0 +1,106 @@
/*
* Copyright (c) 2023 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
class OP4CTFItem:NSRenderableEntity
{
public:
void OP4CTFItem(void);
virtual void Respawn(void);
virtual void Touch(entity);
nonvirtual bool CanPlayerGrabPowerup(entity);
virtual void SpawnKey(string, string);
private:
int m_iItemID;
float m_iTeamID;
string m_strScoreIcon;
vector m_vecScoreColor;
};
void
OP4CTFItem::OP4CTFItem(void)
{
m_iItemID = 0i;
m_strScoreIcon = __NULL__;
m_iTeamID = 0;
m_vecScoreColor = [1,1,1];
}
void
OP4CTFItem::Respawn(void)
{
SetSolid(SOLID_TRIGGER);
SetMovetype(MOVETYPE_NONE);
SetOrigin(GetSpawnOrigin());
SetModel(GetSpawnModel());
SetSize([-16, -16, 0], [16, 16, 72]);
DropToFloor();
}
void
OP4CTFItem::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "goal_no":
m_iTeamID = ReadFloat(strValue);
break;
default:
super::SpawnKey(strKey, strValue);
}
}
void
OP4CTFItem::Touch(entity toucherEntity)
{
player pl = (player)toucherEntity;
if (!m_iItemID)
return;
if (!(toucherEntity.flags & FL_CLIENT))
return;
if (CanPlayerGrabPowerup(toucherEntity) == false)
return;
pl.g_items |= m_iItemID; /* add to inventory */
forceinfokey(pl, "*icon2", m_strScoreIcon);
forceinfokey(pl, "*icon2_r", ftos(m_vecScoreColor[0]));
forceinfokey(pl, "*icon2_g", ftos(m_vecScoreColor[1]));
forceinfokey(pl, "*icon2_b", ftos(m_vecScoreColor[2]));
Destroy();
}
bool
OP4CTFItem::CanPlayerGrabPowerup(entity playerEntity)
{
player pl = (player)playerEntity;
if (pl.g_items & ITEM_CTF_JUMPPACK)
return false;
if (pl.g_items & ITEM_CTF_SHIELD)
return false;
if (pl.g_items & ITEM_CTF_HEALTH)
return false;
if (pl.g_items & ITEM_CTF_DEATH)
return false;
if (pl.g_items & ITEM_CTF_BACKPACK)
return false;
return true;
}

19
src/server/defs.h Normal file
View file

@ -0,0 +1,19 @@
/*
* Copyright (c) 2016-2023 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "../../../valve/src/server/gamerules.h"
#include "../../../valve/src/server/items.h"
#include "../../../valve/src/server/flashlight.h"

224
src/server/gamerules.qc Normal file
View file

@ -0,0 +1,224 @@
/*
* Copyright (c) 2016-2020 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
bool
HLGameRules::IsMultiplayer(void)
{
return true;
}
/* we check what fields have changed over the course of the frame and network
* only the ones that have actually changed */
void
HLGameRules::PlayerPostFrame(NSClientPlayer pp)
{
}
void
HLGameRules::LevelNewParms(void)
{
parm1 = parm2 = parm3 = parm4 = parm5 = parm6 = parm7 =
parm8 = parm9 = parm10 = parm11 = parm12 = parm13 = parm14 =
parm15 = parm16 = parm17 = parm18 = parm19 = parm20 = parm21 =
parm22 = parm23 = parm24 = parm25 = parm26 = parm27 = parm28 =
parm29 = parm30 = 0;
parm64 = FL_CLIENT;
}
void
HLGameRules::LevelDecodeParms(NSClientPlayer pp)
{
player pl = (player)pp;
g_landmarkpos[0] = parm1;
g_landmarkpos[1] = parm2;
g_landmarkpos[2] = parm3;
pl.angles[0] = parm4;
pl.angles[1] = parm5;
pl.angles[2] = parm6;
pl.velocity[0] = parm7;
pl.velocity[1] = parm8;
pl.velocity[2] = parm9;
pl.g_items = parm10;
pl.activeweapon = parm11;
pl.flags = parm64;
pl.ammo_9mm = parm12;
pl.ammo_357 = parm13;
pl.ammo_buckshot = parm14;
pl.ammo_m203_grenade = parm15;
pl.ammo_bolt = parm16;
pl.ammo_rocket = parm17;
pl.ammo_uranium = parm18;
pl.ammo_handgrenade = parm19;
pl.ammo_satchel = parm20;
pl.ammo_tripmine = parm21;
pl.ammo_snark = parm22;
pl.ammo_hornet = parm23;
pl.glock_mag = parm24;
pl.mp5_mag = parm25;
pl.python_mag = parm26;
pl.shotgun_mag = parm27;
pl.crossbow_mag = parm28;
pl.rpg_mag = parm29;
pl.satchel_chg = parm30;
/* near gearbox additions */
pl.ammo_556 = parm31;
pl.ammo_762 = parm32;
pl.ammo_spore = parm33;
pl.ammo_shock = parm34;
pl.ammo_penguin = parm35;
pl.eagle_mag = parm36;
pl.sniper_mag = parm37;
pl.m249_mag = parm38;
pl.sporelauncher_mag = parm39;
if (pl.flags & FL_CROUCHING) {
setsize(pl, VEC_CHULL_MIN, VEC_CHULL_MAX);
} else {
setsize(pl, VEC_HULL_MIN, VEC_HULL_MAX);
}
}
void
HLGameRules::LevelChangeParms(NSClientPlayer pp)
{
player pl = (player)pp;
parm1 = g_landmarkpos[0];
parm2 = g_landmarkpos[1];
parm3 = g_landmarkpos[2];
parm4 = pl.angles[0];
parm5 = pl.angles[1];
parm6 = pl.angles[2];
parm7 = pl.velocity[0];
parm8 = pl.velocity[1];
parm9 = pl.velocity[2];
parm64 = pl.flags;
parm10 = pl.g_items;
parm11 = pl.activeweapon;
parm12 = pl.ammo_9mm;
parm13 = pl.ammo_357;
parm14 = pl.ammo_buckshot;
parm15 = pl.ammo_m203_grenade;
parm16 = pl.ammo_bolt;
parm17 = pl.ammo_rocket;
parm18 = pl.ammo_uranium;
parm19 = pl.ammo_handgrenade;
parm20 = pl.ammo_satchel;
parm21 = pl.ammo_tripmine;
parm22 = pl.ammo_snark;
parm23 = pl.ammo_hornet;
parm24 = pl.glock_mag;
parm25 = pl.mp5_mag;
parm26 = pl.python_mag;
parm27 = pl.shotgun_mag;
parm28 = pl.crossbow_mag;
parm29 = pl.rpg_mag;
parm30 = pl.satchel_chg;
/* near gearbox additions */
parm31 = pl.ammo_556;
parm32 = pl.ammo_762;
parm33 = pl.ammo_spore;
parm34 = pl.ammo_shock;
parm35 = pl.ammo_penguin;
parm36 = pl.eagle_mag;
parm37 = pl.sniper_mag;
parm38 = pl.m249_mag;
parm39 = pl.sporelauncher_mag;
}
void
HLGameRules::PlayerConnect(NSClientPlayer pl)
{
if (Plugin_PlayerConnect(pl) == FALSE)
bprint(PRINT_HIGH, sprintf("%s connected\n", pl.netname));
}
void
HLGameRules::PlayerDisconnect(NSClientPlayer pl)
{
bprint(PRINT_HIGH, sprintf("%s disconnected\n", pl.netname));
/* Make this unusable */
pl.solid = SOLID_NOT;
pl.movetype = MOVETYPE_NONE;
pl.modelindex = 0;
pl.health = 0;
pl.takedamage = 0;
pl.SendFlags = PLAYER_MODELINDEX;
}
void
HLGameRules::PlayerKill(NSClientPlayer pp)
{
player pl = (player)pp;
Damage_Apply(pl, pl, pl.health, WEAPON_NONE, DMG_SKIP_ARMOR);
}
void
TriggerFlashlight(NSClient target)
{
entity oldself = self;
self = target;
Flashlight_Toggle();
self = oldself;
}
void
DropCTFItem(NSClientPlayer pl)
{
string item;
if (pl.classname != "player")
return;
if (pl.g_items & ITEM_CTF_JUMPPACK) {
item = "item_ctflongjump";
pl.g_items &= ~ ITEM_CTF_JUMPPACK;
} else if (pl.g_items & ITEM_CTF_SHIELD) {
item = "item_ctfportablehev";
pl.g_items &= ~ ITEM_CTF_SHIELD;
} else if (pl.g_items & ITEM_CTF_HEALTH) {
item = "item_ctfregeneration";
pl.g_items &= ~ ITEM_CTF_HEALTH;
} else if (pl.g_items & ITEM_CTF_DEATH) {
item = "item_ctfaccelerator";
pl.g_items &= ~ ITEM_CTF_DEATH;
} else if (pl.g_items & ITEM_CTF_BACKPACK) {
item = "item_ctfbackpack";
pl.g_items &= ~ ITEM_CTF_BACKPACK;
}
}
bool
HLGameRules::ImpulseCommand(NSClient bp, float num)
{
switch (num) {
case 100:
TriggerFlashlight(bp);
break;
case 205:
DropCTFItem((player)bp);
break;
default:
return super::ImpulseCommand(bp, num);
}
return true;
}

53
src/server/progs.src Normal file
View file

@ -0,0 +1,53 @@
#pragma target fte_5768
//#pragma flag enable assumeint
#pragma progs_dat "../../progs.dat"
#define QWSSQC
#define SERVER
#define HL2
#includelist
../../../src/shared/fteextensions.qc
../../../src/shared/defs.h
../../../src/server/defs.h
../../../src/botlib/botinfo.h
../../../src/gs-entbase/server.src
../../../src/gs-entbase/shared.src
defs.h
../shared/include.src
../../../valve/src/server/player.qc
../../../valve/src/server/items.qc
../../../valve/src/server/item_longjump.qc
../../../valve/src/server/item_suit.qc
../../../valve/src/server/item_healthkit.qc
../../../valve/src/server/item_battery.qc
../../../valve/src/server/item_weaponbox.qc
../../../valve/src/server/world_items.qc
../../../valve/src/server/xen_spore_small.qc
../../../valve/src/server/xen_spore_medium.qc
../../../valve/src/server/xen_spore_large.qc
../../../valve/src/server/xen_hair.qc
../../../valve/src/server/xen_plantlight.qc
../../../valve/src/server/ammo.qc
../../../src/botlib/include.src
gamerules.qc
../../../valve/src/server/gamerules_singleplayer.qc
../../../valve/src/server/gamerules_multiplayer.qc
server.qc
../../../valve/src/server/damage.qc
../../../valve/src/server/flashlight.qc
../../../valve/src/server/modelevent.qc
../../../valve/src/server/spawn.qc
../../../src/server/include.src
../../../src/shared/include.src
#endlist

42
src/server/server.qc Normal file
View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 2016-2023 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
void
Game_InitRules(void)
{
forceinfokey(world, "ctf", "0");
if (cvar("sv_playerslots") == 1 || cvar("coop") == 1) {
g_grMode = spawn(HLSingleplayerRules);
} else {
g_grMode = spawn(HLMultiplayerRules);
}
}
void
Game_Worldspawn(void)
{
Sound_Precache("ammo.pickup");
Sound_Precache("ammo.respawn");
Sound_Precache("player.die");
Sound_Precache("player.fall");
Sound_Precache("player.lightfall");
precache_model("models/player.mdl");
precache_model("models/w_weaponbox.mdl");
Weapons_Init();
Player_Precache();
FX_Corpse_Init();
}

31
src/shared/include.src Normal file
View file

@ -0,0 +1,31 @@
#includelist
../../../valve/src/shared/entities.h
../../../valve/src/shared/events.h
../../../valve/src/shared/flags.h
player.qc
../../../valve/src/shared/weapon_common.h
../../../valve/src/shared/animations.h
../../../valve/src/shared/animations.qc
../../../valve/src/shared/pmove.qc
../../../valve/src/shared/fx_blood.qc
../../../valve/src/shared/fx_gaussbeam.qc
../../../valve/src/shared/fx_corpse.qc
items.h
weapons.h
w_357.qc
w_ar2.qc
w_bugbait.qc
w_crossbow.qc
w_crowbar.qc
w_frag.qc
w_gravitygun.qc
w_pistol.qc
w_rpg.qc
w_shotgun.qc
w_smg1.qc
weapons.qc
../../../valve/src/shared/weapon_common.qc
#endlist

59
src/shared/items.h Normal file
View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 2016-2023 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define ITEM_CROWBAR 0x00000001i
#define ITEM_GLOCK 0x00000002i
#define ITEM_PYTHON 0x00000004i
#define ITEM_MP5 0x00000008i
#define ITEM_CROSSBOW 0x00000010i
#define ITEM_SHOTGUN 0x00000020i
#define ITEM_RPG 0x00000040i
#define ITEM_GAUSS 0x00000080i
#define ITEM_EGON 0x00000100i
#define ITEM_HORNETGUN 0x00000200i
#define ITEM_HANDGRENADE 0x00000400i
#define ITEM_TRIPMINE 0x00000800i
#define ITEM_SATCHEL 0x00001000i
#define ITEM_SNARK 0x00002000i
#define ITEM_SUIT 0x00004000i
#define ITEM_LONGJUMP 0x00008000i
#define ITEM_PIPEWRENCH 0x00010000i
#define ITEM_KNIFE 0x00020000i
#define ITEM_GRAPPLE 0x00040000i
#define ITEM_EAGLE 0x00080000i
#define ITEM_M249 0x00100000i
#define ITEM_DISPLACER 0x00200000i
#define ITEM_SNIPERRIFLE 0x00400000i
#define ITEM_PENGUIN 0x00800000i
#define ITEM_SHOCKRIFLE 0x01000000i
#define ITEM_SPORELAUNCHER 0x02000000i
#define ITEM_CTF_JUMPPACK 0x04000000i
#define ITEM_CTF_SHIELD 0x08000000i
#define ITEM_CTF_HEALTH 0x10000000i
#define ITEM_CTF_DEATH 0x20000000i
#define ITEM_CTF_BACKPACK 0x40000000i
#define ITEM_GOALITEM 0x80000000i
typedef enum
{
CTFFLAG_IDLE = 0,
CTFFLAG_TAKEN,
CTFFlAG_MISSING
} ctfflag_state;

612
src/shared/player.qc Normal file
View file

@ -0,0 +1,612 @@
/*
* Copyright (c) 2016-2021 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "../../../valve/src/shared/skeleton.h"
/* all potential SendFlags bits we can possibly send */
enumflags
{
PLAYER_TOPFRAME = PLAYER_CUSTOMFIELDSTART,
PLAYER_BOTTOMFRAME,
PLAYER_AMMO1,
PLAYER_AMMO2,
PLAYER_AMMO3,
PLAYER_FLAG,
PLAYER_UNUSED6,
PLAYER_UNUSED7
};
class player:NSClientPlayer
{
/* animation */
PREDICTED_INT(anim_top)
PREDICTED_FLOAT(anim_top_time)
PREDICTED_FLOAT(anim_top_delay)
PREDICTED_INT(anim_bottom)
PREDICTED_FLOAT(anim_bottom_time)
/* ammo 1 */
PREDICTED_INT(glock_mag)
PREDICTED_INT(mp5_mag)
PREDICTED_INT(python_mag)
PREDICTED_INT(shotgun_mag)
PREDICTED_INT(crossbow_mag)
PREDICTED_INT(rpg_mag)
PREDICTED_INT(satchel_chg)
/* ammo 2 */
PREDICTED_INT(ammo_9mm)
PREDICTED_INT(ammo_357)
PREDICTED_INT(ammo_buckshot)
PREDICTED_INT(ammo_bolt)
PREDICTED_INT(ammo_rocket)
PREDICTED_INT(ammo_uranium)
PREDICTED_INT(ammo_handgrenade)
PREDICTED_INT(ammo_satchel)
PREDICTED_INT(ammo_tripmine)
PREDICTED_INT(ammo_snark)
PREDICTED_INT(ammo_hornet)
/* ammo 3 */
PREDICTED_INT(ammo_m203_grenade)
PREDICTED_INT(ammo_gauss_volume)
PREDICTED_INT(ammo_rpg_state)
PREDICTED_INT(mode_tempstate)
/* gearbox */
PREDICTED_INT(eagle_mag)
PREDICTED_INT(sniper_mag)
PREDICTED_INT(m249_mag)
PREDICTED_INT(sporelauncher_mag)
PREDICTED_INT(ammo_556)
PREDICTED_INT(ammo_762)
PREDICTED_INT(ammo_spore)
PREDICTED_INT(ammo_shock)
PREDICTED_INT(ammo_penguin)
PREDICTED_INT(mode_displacer)
PREDICTED_INT(mode_eagle)
PREDICTED_INT(mode_wrench)
PREDICTED_INT(mode_sporelauncher)
PREDICTED_INT(mode_m249)
PREDICTED_FLOAT(flagmodel)
PREDICTED_FLOAT(flagskin)
virtual void(void) Physics_Jump;
virtual void UpdatePlayerAnimation(float);
#ifdef CLIENT
NSRenderableEntity m_eFlag;
virtual void UpdatePlayerAttachments(bool);
virtual void(float,float) ReceiveEntity;
virtual void(void) PredictPreFrame;
virtual void(void) PredictPostFrame;
virtual void UpdateAliveCam(void);
virtual void OnRemoveEntity(void);
#else
entity hook;
float m_flPickUpTime;
virtual void(void) EvaluateEntity;
virtual float(entity, float) SendEntity;
#endif
};
void Animation_PlayerUpdate(player);
void Animation_TimerUpdate(player, float);
void
player::UpdatePlayerAnimation(float timelength)
{
/* calculate our skeletal progression */
Animation_PlayerUpdate(this);
/* advance animation timers */
Animation_TimerUpdate(this, timelength);
}
#ifdef CLIENT
void Camera_RunPosBob(vector angles, __inout vector camera_pos);
void Camera_StrafeRoll(__inout vector camera_angle);
void Shake_Update(NSClientPlayer);
void
player::UpdateAliveCam(void)
{
vector cam_pos = GetEyePos();
Camera_RunPosBob(view_angles, cam_pos);
g_view.SetCameraOrigin(cam_pos);
Camera_StrafeRoll(view_angles);
g_view.SetCameraAngle(view_angles);
if (vehicle) {
NSVehicle veh = (NSVehicle)vehicle;
if (veh.UpdateView)
veh.UpdateView();
} else if (health) {
if (autocvar_pm_thirdPerson == TRUE) {
makevectors(view_angles);
vector vStart = [pSeat->m_vecPredictedOrigin[0], pSeat->m_vecPredictedOrigin[1], pSeat->m_vecPredictedOrigin[2] + 16] + (v_right * 4);
vector vEnd = vStart + (v_forward * -48) + [0,0,16] + (v_right * 4);
traceline(vStart, vEnd, FALSE, this);
g_view.SetCameraOrigin(trace_endpos + (v_forward * 5));
}
}
Shake_Update(this);
g_view.AddPunchAngle(punchangle);
}
.string oldmodel;
string Weapons_GetPlayermodel(player, int);
void
player::UpdatePlayerAttachments(bool visible)
{
if (gflags & GF_FLASHLIGHT) {
vector src;
vector ang;
if (entnum != player_localentnum) {
src = origin + view_ofs;
ang = v_angle;
} else {
src = pSeat->m_vecPredictedOrigin + view_ofs;
ang = view_angles;
}
makevectors(ang);
traceline(src, src + (v_forward * 8096), MOVE_NORMAL, this);
if (serverkeyfloat("*bspversion") == BSPVER_HL) {
dynamiclight_add(trace_endpos + (trace_plane_normal * 4), 128, [1,1,1]);
} else {
float p = dynamiclight_add(src, 512, [1,1,1], 0, "textures/flashlight");
dynamiclight_set(p, LFIELD_ANGLES, ang);
dynamiclight_set(p, LFIELD_FLAGS, 3);
}
effects |= EF_NOSHADOW;
}
if (m_eFlag != world) {
m_eFlag.SetOrigin(origin);
m_eFlag.SetAngles([0, angles[1], 0]);
}
/* FIXME: this needs to be incorporated and simplified, now that we can handle it all in-class */
if (!visible)
return;
/* what's the current weapon model supposed to be anyway? */
p_model.oldmodel = Weapons_GetPlayermodel(this, activeweapon);
/* we changed weapons, update skeletonindex */
if (p_model.model != p_model.oldmodel) {
/* free memory */
if (p_model.skeletonindex)
skel_delete(p_model.skeletonindex);
/* set the new model and mark us updated */
setmodel(p_model, p_model.oldmodel);
p_model.model = p_model.oldmodel;
/* set the new skeletonindex */
p_model.skeletonindex = skel_create(p_model.modelindex);
/* hack this thing in here FIXME: this should be done when popping in/out of a pvs */
if (autocvar(cl_himodels, 1, "Use high-quality thisayer models over lower-definition ones"))
setcustomskin(this, "", "geomset 0 2\n");
else
setcustomskin(this, "", "geomset 0 1\n");
}
/* follow thisayer at all times */
setorigin(p_model, origin);
p_model.angles = angles;
skel_build(p_model.skeletonindex, p_model, p_model.modelindex,0, 0, -1);
/* we have to loop through all valid bones of the weapon model and match them
* to the thisayer one */
for (float i = 0; i < g_pbones.length; i++) {
vector bpos;
float pbone = gettagindex(this, g_pbones[i]);
float wbone = gettagindex(p_model, g_pbones[i]);
/* if the bone doesn't ignore in either skeletal mesh, ignore */
if (wbone <= 0 || pbone <= 0)
continue;
bpos = gettaginfo(this, pbone);
/* the most expensive bit */
skel_set_bone_world(p_model, wbone, bpos, v_forward, v_right, v_up);
}
}
void Weapons_AmmoUpdate(entity);
void HUD_AmmoNotify_Check(player pl);
void HUD_ItemNotify_Check(player pl);
void
player::OnRemoveEntity(void)
{
super::OnRemoveEntity();
if (m_eFlag) {
m_eFlag.Destroy();
}
}
/*
=================
player::ReceiveEntity
=================
*/
void
player::ReceiveEntity(float new, float flChanged)
{
/* the generic client attributes */
NSClientPlayer::ReceiveEntity(new, flChanged);
/* animation */
READENTITY_BYTE(anim_top, PLAYER_TOPFRAME)
READENTITY_FLOAT(anim_top_time, PLAYER_TOPFRAME)
READENTITY_FLOAT(anim_top_delay, PLAYER_TOPFRAME)
READENTITY_BYTE(anim_bottom, PLAYER_BOTTOMFRAME)
READENTITY_FLOAT(anim_bottom_time, PLAYER_BOTTOMFRAME)
READENTITY_BYTE(glock_mag, PLAYER_AMMO1)
READENTITY_BYTE(mp5_mag, PLAYER_AMMO1)
READENTITY_BYTE(python_mag, PLAYER_AMMO1)
READENTITY_BYTE(shotgun_mag, PLAYER_AMMO1)
READENTITY_BYTE(crossbow_mag, PLAYER_AMMO1)
READENTITY_BYTE(rpg_mag, PLAYER_AMMO1)
READENTITY_BYTE(satchel_chg, PLAYER_AMMO1)
READENTITY_BYTE(ammo_9mm, PLAYER_AMMO2)
READENTITY_BYTE(ammo_357, PLAYER_AMMO2)
READENTITY_BYTE(ammo_buckshot, PLAYER_AMMO2)
READENTITY_BYTE(ammo_bolt, PLAYER_AMMO2)
READENTITY_BYTE(ammo_rocket, PLAYER_AMMO2)
READENTITY_BYTE(ammo_uranium, PLAYER_AMMO2)
READENTITY_BYTE(ammo_handgrenade, PLAYER_AMMO2)
READENTITY_BYTE(ammo_satchel, PLAYER_AMMO2)
READENTITY_BYTE(ammo_tripmine, PLAYER_AMMO2)
READENTITY_BYTE(ammo_snark, PLAYER_AMMO2)
READENTITY_BYTE(ammo_hornet, PLAYER_AMMO2)
READENTITY_BYTE(ammo_m203_grenade, PLAYER_AMMO3)
READENTITY_BYTE(ammo_gauss_volume, PLAYER_AMMO3)
READENTITY_BYTE(ammo_rpg_state, PLAYER_AMMO3)
READENTITY_BYTE(mode_tempstate, PLAYER_AMMO3)
/* gearbox */
READENTITY_BYTE(eagle_mag, PLAYER_AMMO1)
READENTITY_BYTE(sniper_mag, PLAYER_AMMO1)
READENTITY_BYTE(m249_mag, PLAYER_AMMO1)
READENTITY_BYTE(sporelauncher_mag, PLAYER_AMMO1)
READENTITY_BYTE(ammo_556, PLAYER_AMMO2)
READENTITY_BYTE(ammo_762, PLAYER_AMMO2)
READENTITY_BYTE(ammo_spore, PLAYER_AMMO2)
READENTITY_BYTE(ammo_shock, PLAYER_AMMO2)
READENTITY_BYTE(ammo_penguin, PLAYER_AMMO2)
READENTITY_BYTE(mode_displacer, PLAYER_AMMO3)
READENTITY_BYTE(mode_eagle, PLAYER_AMMO3)
READENTITY_BYTE(mode_wrench, PLAYER_AMMO3)
READENTITY_BYTE(mode_sporelauncher, PLAYER_AMMO3)
READENTITY_BYTE(mode_m249, PLAYER_AMMO3)
READENTITY_FLOAT(flagmodel, PLAYER_FLAG)
READENTITY_BYTE(flagskin, PLAYER_FLAG)
setorigin(this, origin);
/* add/remove flag model */
if (flagmodel != 0) {
if (!m_eFlag)
m_eFlag = spawn(NSRenderableEntity);
m_eFlag.SetModelindex(flagmodel);
m_eFlag.SetSkin(flagskin);
m_eFlag.SetFrame(2);
} else if (m_eFlag) {
m_eFlag.Destroy();
remove(m_eFlag);
m_eFlag = 0;
}
/* these only concern the current player */
CSQC_UpdateSeat();
if (this != pSeat->m_ePlayer)
return;
/* do not notify us of updates when spawning initially */
if (flChanged == UPDATE_ALL)
PredictPreFrame();
if (flChanged & PLAYER_AMMO1 || flChanged & PLAYER_AMMO2 || flChanged & PLAYER_AMMO3) {
Weapons_AmmoUpdate(this);
HUD_AmmoNotify_Check(this);
}
if (flChanged & PLAYER_ITEMS || flChanged & PLAYER_HEALTH)
HUD_ItemNotify_Check(this);
}
/*
=================
player::PredictPostFrame
Save the last valid server values away in the _net variants of each field
so we can roll them back later.
=================
*/
void
player::PredictPreFrame(void)
{
NSClientPlayer::PredictPreFrame();
SAVE_STATE(anim_top)
SAVE_STATE(anim_top_delay)
SAVE_STATE(anim_top_time)
SAVE_STATE(anim_bottom)
SAVE_STATE(anim_bottom_time)
SAVE_STATE(glock_mag)
SAVE_STATE(mp5_mag)
SAVE_STATE(python_mag)
SAVE_STATE(shotgun_mag)
SAVE_STATE(crossbow_mag)
SAVE_STATE(rpg_mag)
SAVE_STATE(satchel_chg)
SAVE_STATE(ammo_9mm)
SAVE_STATE(ammo_357)
SAVE_STATE(ammo_buckshot)
SAVE_STATE(ammo_bolt)
SAVE_STATE(ammo_rocket)
SAVE_STATE(ammo_uranium)
SAVE_STATE(ammo_handgrenade)
SAVE_STATE(ammo_satchel)
SAVE_STATE(ammo_tripmine)
SAVE_STATE(ammo_snark)
SAVE_STATE(ammo_hornet)
SAVE_STATE(ammo_m203_grenade)
SAVE_STATE(ammo_gauss_volume)
SAVE_STATE(ammo_rpg_state)
SAVE_STATE(mode_tempstate)
/* gearbox */
SAVE_STATE(eagle_mag)
SAVE_STATE(sniper_mag)
SAVE_STATE(m249_mag)
SAVE_STATE(sporelauncher_mag)
SAVE_STATE(ammo_556)
SAVE_STATE(ammo_762)
SAVE_STATE(ammo_spore)
SAVE_STATE(ammo_shock)
SAVE_STATE(ammo_penguin)
SAVE_STATE(mode_displacer)
SAVE_STATE(mode_eagle)
SAVE_STATE(mode_wrench)
SAVE_STATE(mode_sporelauncher)
SAVE_STATE(mode_m249)
SAVE_STATE(flagmodel)
SAVE_STATE(flagskin)
}
/*
=================
player::PredictPostFrame
Where we roll back our values to the ones last sent/verified by the server.
=================
*/
void
player::PredictPostFrame(void)
{
NSClientPlayer::PredictPostFrame();
ROLL_BACK(anim_top)
ROLL_BACK(anim_top_delay)
ROLL_BACK(anim_top_time)
ROLL_BACK(anim_bottom)
ROLL_BACK(anim_bottom_time)
ROLL_BACK(glock_mag)
ROLL_BACK(mp5_mag)
ROLL_BACK(python_mag)
ROLL_BACK(shotgun_mag)
ROLL_BACK(crossbow_mag)
ROLL_BACK(rpg_mag)
ROLL_BACK(satchel_chg)
ROLL_BACK(ammo_9mm)
ROLL_BACK(ammo_357)
ROLL_BACK(ammo_buckshot)
ROLL_BACK(ammo_bolt)
ROLL_BACK(ammo_rocket)
ROLL_BACK(ammo_uranium)
ROLL_BACK(ammo_handgrenade)
ROLL_BACK(ammo_satchel)
ROLL_BACK(ammo_tripmine)
ROLL_BACK(ammo_snark)
ROLL_BACK(ammo_hornet)
ROLL_BACK(ammo_m203_grenade)
ROLL_BACK(ammo_gauss_volume)
ROLL_BACK(ammo_rpg_state)
ROLL_BACK(mode_tempstate)
/* gearbox */
ROLL_BACK(eagle_mag)
ROLL_BACK(sniper_mag)
ROLL_BACK(m249_mag)
ROLL_BACK(sporelauncher_mag)
ROLL_BACK(ammo_556)
ROLL_BACK(ammo_762)
ROLL_BACK(ammo_spore)
ROLL_BACK(ammo_shock)
ROLL_BACK(ammo_penguin)
ROLL_BACK(mode_displacer)
ROLL_BACK(mode_eagle)
ROLL_BACK(mode_wrench)
ROLL_BACK(mode_sporelauncher)
ROLL_BACK(mode_m249)
ROLL_BACK(flagmodel)
ROLL_BACK(flagskin)
}
#else
void
player::EvaluateEntity(void)
{
/* the generic client attributes */
NSClientPlayer::EvaluateEntity();
EVALUATE_FIELD(anim_top, PLAYER_TOPFRAME)
EVALUATE_FIELD(anim_top_time, PLAYER_TOPFRAME)
EVALUATE_FIELD(anim_top_delay, PLAYER_TOPFRAME)
EVALUATE_FIELD(anim_bottom, PLAYER_BOTTOMFRAME)
EVALUATE_FIELD(anim_bottom_time, PLAYER_BOTTOMFRAME)
EVALUATE_FIELD(glock_mag, PLAYER_AMMO1)
EVALUATE_FIELD(mp5_mag, PLAYER_AMMO1)
EVALUATE_FIELD(python_mag, PLAYER_AMMO1)
EVALUATE_FIELD(shotgun_mag, PLAYER_AMMO1)
EVALUATE_FIELD(crossbow_mag, PLAYER_AMMO1)
EVALUATE_FIELD(rpg_mag, PLAYER_AMMO1)
EVALUATE_FIELD(satchel_chg, PLAYER_AMMO1)
EVALUATE_FIELD(ammo_9mm, PLAYER_AMMO2)
EVALUATE_FIELD(ammo_357, PLAYER_AMMO2)
EVALUATE_FIELD(ammo_buckshot, PLAYER_AMMO2)
EVALUATE_FIELD(ammo_bolt, PLAYER_AMMO2)
EVALUATE_FIELD(ammo_rocket, PLAYER_AMMO2)
EVALUATE_FIELD(ammo_uranium, PLAYER_AMMO2)
EVALUATE_FIELD(ammo_handgrenade, PLAYER_AMMO2)
EVALUATE_FIELD(ammo_satchel, PLAYER_AMMO2)
EVALUATE_FIELD(ammo_tripmine, PLAYER_AMMO2)
EVALUATE_FIELD(ammo_snark, PLAYER_AMMO2)
EVALUATE_FIELD(ammo_hornet, PLAYER_AMMO2)
EVALUATE_FIELD(ammo_m203_grenade, PLAYER_AMMO3)
EVALUATE_FIELD(ammo_gauss_volume, PLAYER_AMMO3)
EVALUATE_FIELD(ammo_rpg_state, PLAYER_AMMO3)
EVALUATE_FIELD(mode_tempstate, PLAYER_AMMO3)
/* gearbox */
EVALUATE_FIELD(eagle_mag, PLAYER_AMMO1)
EVALUATE_FIELD(sniper_mag, PLAYER_AMMO1)
EVALUATE_FIELD(m249_mag, PLAYER_AMMO1)
EVALUATE_FIELD(sporelauncher_mag, PLAYER_AMMO1)
EVALUATE_FIELD(ammo_556, PLAYER_AMMO2)
EVALUATE_FIELD(ammo_762, PLAYER_AMMO2)
EVALUATE_FIELD(ammo_spore, PLAYER_AMMO2)
EVALUATE_FIELD(ammo_shock, PLAYER_AMMO2)
EVALUATE_FIELD(ammo_penguin, PLAYER_AMMO2)
EVALUATE_FIELD(mode_displacer, PLAYER_AMMO3)
EVALUATE_FIELD(mode_eagle, PLAYER_AMMO3)
EVALUATE_FIELD(mode_wrench, PLAYER_AMMO3)
EVALUATE_FIELD(mode_sporelauncher, PLAYER_AMMO3)
EVALUATE_FIELD(mode_m249, PLAYER_AMMO3)
EVALUATE_FIELD(flagmodel, PLAYER_FLAG)
EVALUATE_FIELD(flagskin, PLAYER_FLAG)
}
/*
=================
player::SendEntity
=================
*/
float
player::SendEntity(entity ePEnt, float flChanged)
{
/* don't broadcast invisible players */
if (IsFakeSpectator() && ePEnt != this)
return (0);
if (!GetModelindex() && ePEnt != this)
return (0);
flChanged = OptimiseChangedFlags(ePEnt, flChanged);
WriteByte(MSG_ENTITY, ENT_PLAYER);
WriteFloat(MSG_ENTITY, flChanged);
/* the generic client attributes */
NSClientPlayer::SendEntity(ePEnt, flChanged);
SENDENTITY_BYTE(anim_top, PLAYER_TOPFRAME)
SENDENTITY_FLOAT(anim_top_time, PLAYER_TOPFRAME)
SENDENTITY_FLOAT(anim_top_delay, PLAYER_TOPFRAME)
SENDENTITY_BYTE(anim_bottom, PLAYER_BOTTOMFRAME)
SENDENTITY_FLOAT(anim_bottom_time, PLAYER_BOTTOMFRAME)
SENDENTITY_BYTE(glock_mag, PLAYER_AMMO1)
SENDENTITY_BYTE(mp5_mag, PLAYER_AMMO1)
SENDENTITY_BYTE(python_mag, PLAYER_AMMO1)
SENDENTITY_BYTE(shotgun_mag, PLAYER_AMMO1)
SENDENTITY_BYTE(crossbow_mag, PLAYER_AMMO1)
SENDENTITY_BYTE(rpg_mag, PLAYER_AMMO1)
SENDENTITY_BYTE(satchel_chg, PLAYER_AMMO1)
SENDENTITY_BYTE(ammo_9mm, PLAYER_AMMO2)
SENDENTITY_BYTE(ammo_357, PLAYER_AMMO2)
SENDENTITY_BYTE(ammo_buckshot, PLAYER_AMMO2)
SENDENTITY_BYTE(ammo_bolt, PLAYER_AMMO2)
SENDENTITY_BYTE(ammo_rocket, PLAYER_AMMO2)
SENDENTITY_BYTE(ammo_uranium, PLAYER_AMMO2)
SENDENTITY_BYTE(ammo_handgrenade, PLAYER_AMMO2)
SENDENTITY_BYTE(ammo_satchel, PLAYER_AMMO2)
SENDENTITY_BYTE(ammo_tripmine, PLAYER_AMMO2)
SENDENTITY_BYTE(ammo_snark, PLAYER_AMMO2)
SENDENTITY_BYTE(ammo_hornet, PLAYER_AMMO2)
SENDENTITY_BYTE(ammo_m203_grenade, PLAYER_AMMO3)
SENDENTITY_BYTE(ammo_gauss_volume, PLAYER_AMMO3)
SENDENTITY_BYTE(ammo_rpg_state, PLAYER_AMMO3)
SENDENTITY_BYTE(mode_tempstate, PLAYER_AMMO3)
/* gearbox */
SENDENTITY_BYTE(eagle_mag, PLAYER_AMMO1)
SENDENTITY_BYTE(sniper_mag, PLAYER_AMMO1)
SENDENTITY_BYTE(m249_mag, PLAYER_AMMO1)
SENDENTITY_BYTE(sporelauncher_mag, PLAYER_AMMO1)
SENDENTITY_BYTE(ammo_556, PLAYER_AMMO2)
SENDENTITY_BYTE(ammo_762, PLAYER_AMMO2)
SENDENTITY_BYTE(ammo_spore, PLAYER_AMMO2)
SENDENTITY_BYTE(ammo_shock, PLAYER_AMMO2)
SENDENTITY_BYTE(ammo_penguin, PLAYER_AMMO2)
SENDENTITY_BYTE(mode_displacer, PLAYER_AMMO3)
SENDENTITY_BYTE(mode_eagle, PLAYER_AMMO3)
SENDENTITY_BYTE(mode_wrench, PLAYER_AMMO3)
SENDENTITY_BYTE(mode_sporelauncher, PLAYER_AMMO3)
SENDENTITY_BYTE(mode_m249, PLAYER_AMMO3)
SENDENTITY_FLOAT(flagmodel, PLAYER_FLAG)
SENDENTITY_BYTE(flagskin, PLAYER_FLAG)
return (1);
}
#endif

321
src/shared/w_357.qc Normal file
View file

@ -0,0 +1,321 @@
/*
* Copyright (c) 2016-2021 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
enum
{
PYTHON_IDLE,
PYTHON_FIRE,
PYTHON_DRAW,
PYTHON_RELOAD,
PYTHON_HOLSTER,
PYTHON_IDLE_TO_LOW,
PYTHON_LOW_TO_IDLE,
PYTHON_LOW_IDLE
};
void
w_357_precache(void)
{
#ifdef SERVER
precache_model("models/w_357.mdl");
#else
precache_model("models/weapons/v_357.mdl");
precache_model("models/p_357.mdl");
#endif
}
int
w_357_pickup(player pl, int new, int startammo)
{
#ifdef SERVER
int addAmmo = (startammo == -1) ? 6 : startammo;
if (new) {
pl.python_mag = addAmmo;
return (1);
}
if (pl.ammo_357 < MAX_A_357) {
pl.ammo_357 = bound(0, pl.ammo_357 + addAmmo, MAX_A_357);
} else {
if (!new)
return (0);
}
#endif
return (1);
}
void
w_357_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, pl.python_mag, pl.ammo_357, -1);
}
string
w_357_wmodel(void)
{
return "models/w_357.mdl";
}
string
w_357_pmodel(player pl)
{
return "models/p_357.mdl";
}
string
w_357_deathmsg(void)
{
return "";
}
void
w_357_draw(player pl)
{
Weapons_SetModel("models/weapons/v_357.mdl");
/* singleplayer doesn't do scope */
if (serverkeyfloat("sv_playerslots") == 1) {
Weapons_SetGeomset("geomset 4 1\n");
} else {
Weapons_SetGeomset("geomset 4 2\n");
}
Weapons_ViewAnimation(pl, PYTHON_DRAW);
pl.w_idle_next = 1.0f;
}
void
w_357_holster(player pl)
{
Weapons_ViewAnimation(pl, PYTHON_HOLSTER);
pl.w_idle_next = 0.3660f;
}
void
w_357_primary(player pl)
{
if (pl.w_attack_next > 0.0)
return;
if (pl.gflags & GF_SEMI_TOGGLED)
return;
/* Ammo check */
if ((pl.python_mag <= 0) || (pl.WaterLevel() >= WATERLEVEL_SUBMERGED)) {
#ifdef SERVER
Sound_Play(pl, CHAN_AUTO, "weapon_357.empty");
#endif
pl.gflags |= GF_SEMI_TOGGLED;
return;
}
pl.python_mag--;
/* Actual firing */
#ifdef CLIENT
View_SetMuzzleflash(MUZZLE_SMALL);
#else
TraceAttack_FireBullets(1, pl.origin + pl.view_ofs, Skill_GetValue("plr_357_bullet", 40), [0.008, 0.008], WEAPON_357);
Sound_Play(pl, CHAN_WEAPON, "Weapon_357.Single");
#endif
Weapons_ViewPunchAngle(pl, [-10,0,0]);
Weapons_ViewAnimation(pl, PYTHON_FIRE);
if (pl.flags & FL_CROUCHING)
Animation_PlayerTop(pl, ANIM_CR_SHOOTPYTHON, 0.43f);
else
Animation_PlayerTop(pl, ANIM_SHOOTPYTHON, 0.43f);
pl.w_attack_next = 0.833f;
pl.w_idle_next = 0.833f;
}
void
w_357_secondary(player pl)
{
if (pl.w_attack_next > 0.0) {
return;
}
/* singleplayer doesn't do scope */
if (serverkeyfloat("sv_playerslots") == 1) {
return;
}
/* Simple toggle of fovs */
if (pl.viewzoom == 1.0f) {
pl.viewzoom = 0.5f;
} else {
pl.viewzoom = 1.0f;
}
pl.w_attack_next = 0.25f;
}
void
w_357_reload(player pl)
{
if (pl.w_attack_next > 0.0) {
return;
}
/* Ammo check */
if (pl.python_mag >= 6) {
return;
}
if (pl.ammo_357 <= 0) {
return;
}
/* undo our zoom */
pl.viewzoom = 1.0f;
/* Audio-Visual bit */
Weapons_ViewAnimation(pl, PYTHON_RELOAD);
#ifdef SERVER
static void w_357_reload_done(void) {
player pl = (player)self;
Weapons_ReloadWeapon(pl, player::python_mag, player::ammo_357, 6);
}
pl.think = w_357_reload_done;
pl.nextthink = time + 3.15f;
Sound_Play(pl, CHAN_WEAPON, "Weapon_357.Reload");
#endif
pl.w_attack_next = 3.7f;
pl.w_idle_next = 3.7f;
}
void
w_357_release(player pl)
{
/* auto-reload if need be */
if (pl.w_attack_next <= 0.0)
if (pl.python_mag == 0 && pl.ammo_357 > 0) {
Weapons_Reload(pl);
return;
}
if (pl.w_idle_next > 0.0) {
return;
}
Weapons_ViewAnimation(pl, PYTHON_IDLE);
pl.w_idle_next = 4.0f;
}
void
w_357_crosshair(player pl)
{
#ifdef CLIENT
HUD_DrawAmmo1();
HUD_DrawAmmo2();
vector pos = g_hudmins + [g_hudres[0] / 2, g_hudres[1] / 2];
Font_DrawText_RGBA(pos + [-7, -14], "Q", g_hud_color, 1.0, FONT_HUD_CROSS);
#endif
}
float
w_357_aimanim(player pl)
{
return pl.flags & FL_CROUCHING ? ANIM_CR_AIMPYTHON : ANIM_AIMPYTHON;
}
void
w_357_hudpic(player pl, int selected, vector pos, float a)
{
#ifdef CLIENT
vector hud_col;
if (pl.python_mag == 0 && pl.ammo_357 == 0)
hud_col = [1,0,0];
else
hud_col = g_hud_color;
if (selected) {
drawsubpic(
pos,
[128,64],
"materials/Sprites/w_icons1",
[0.5, 0.25],
[128/256,64/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[128,64],
"materials/Sprites/w_icons1",
[0.5, 0.25],
[128/256,64/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
}
HUD_DrawAmmoBar(pos, pl.ammo_357, MAX_A_357, a);
#endif
}
int
w_357_isempty(player pl)
{
if (pl.python_mag <= 0 && pl.ammo_357 <= 0)
return 1;
return 0;
}
weapontype_t
w_357_type(player pl)
{
return WPNTYPE_RANGED;
}
weapon_t w_357 =
{
.name = "357",
.id = ITEM_PYTHON,
.slot = 1,
.slot_pos = 1,
.weight = 15,
.draw = w_357_draw,
.holster = w_357_holster,
.primary = w_357_primary,
.secondary = w_357_secondary,
.reload = w_357_reload,
.release = w_357_release,
.postdraw = w_357_crosshair,
.precache = w_357_precache,
.pickup = w_357_pickup,
.updateammo = w_357_updateammo,
.wmodel = w_357_wmodel,
.pmodel = w_357_pmodel,
.deathmsg = w_357_deathmsg,
.aimanim = w_357_aimanim,
.isempty = w_357_isempty,
.type = w_357_type,
.hudpic = w_357_hudpic
};

291
src/shared/w_ar2.qc Normal file
View file

@ -0,0 +1,291 @@
/*
* Copyright (c) 2016-2021 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
enum
{
AR2_IDLE,
AR2_FIRE1,
AR2_FIRE2,
AR2_FIRE3,
AR2_FIRE4,
AR2_ALTFIRE,
AR2_RELOAD,
AR2_DRAW,
AR2_HOLSTER,
AR2_IDLE_TO_LOW,
AR2_LOW_TO_IDLE,
AR2_SHAKE,
AR2_VENT_NEUTRAL,
AR2_VENT_OPEN,
AR2_VENT_CLOSED
};
void
w_ar2_precache(void)
{
#ifdef SERVER
precache_model("models/w_hgun.mdl");
precache_model("models/hornet.mdl");
#else
precache_model("models/weapons/v_irifle.mdl");
precache_model("models/p_hgun.mdl");
#endif
}
int
w_ar2_pickup(player pl, int new, int startammo)
{
#ifdef SERVER
/* only pick it up once */
if (new) {
pl.ammo_hornet = MAX_A_HORNET;
return (1);
}
#endif
return (0);
}
void
w_ar2_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, -1, pl.ammo_hornet, -1);
}
string w_ar2_wmodel(void)
{
return "models/w_hgun.mdl";
}
string w_ar2_pmodel(player pl)
{
return "models/p_hgun.mdl";
}
string w_ar2_deathmsg(void)
{
return "";
}
void
w_ar2_draw(player pl)
{
Weapons_SetModel("models/weapons/v_irifle.mdl");
Weapons_ViewAnimation(pl, AR2_DRAW);
pl.w_idle_next = 0.8f;
}
void
w_ar2_holster(player pl)
{
Weapons_ViewAnimation(pl, AR2_HOLSTER);
}
#ifdef SERVER
void
w_ar2_shoothornet(player pl)
{
}
#endif
void
w_ar2_release(player pl)
{
if (pl.w_idle_next > 0.0) {
return;
}
if (pl.w_idle_next > 0.0) {
return;
}
Weapons_ViewAnimation(pl, AR2_IDLE);
pl.w_idle_next = 1.0f;
}
void
w_ar2_primary(player pl)
{
if (pl.w_attack_next > 0.0) {
return;
}
/* Ammo check */
if (pl.ammo_hornet <= 0) {
// w_ar2_release(pl);
//return;
}
#ifdef SERVER
w_ar2_shoothornet(pl);
Sound_Play(pl, CHAN_WEAPON, "Weapon_AR2.Single");
#endif
// pl.ammo_hornet--;
int r = floor(pseudorandom() * 4.0);
Weapons_ViewAnimation(pl, AR2_FIRE1 + r);
if (pl.flags & FL_CROUCHING)
Animation_PlayerTop(pl, ANIM_CR_SHOOTHIVE, 0.43f);
else
Animation_PlayerTop(pl, ANIM_SHOOTHIVE, 0.43f);
pl.w_attack_next = 0.1f;
pl.w_idle_next = 0.2f;
}
void
w_ar2_secondary(player pl)
{
if (pl.w_attack_next) {
return;
}
/* Ammo check */
if (pl.ammo_hornet <= 0) {
w_ar2_release(pl);
return;
}
#ifdef SERVER
// w_ar2_shoothornet(pl);
Sound_Play(pl, CHAN_WEAPON, "Weapon_AR2.Double");
#endif
pl.ammo_hornet--;
Weapons_ViewAnimation(pl, AR2_ALTFIRE);
if (pl.flags & FL_CROUCHING)
Animation_PlayerTop(pl, ANIM_CR_SHOOTHIVE, 0.43f);
else
Animation_PlayerTop(pl, ANIM_SHOOTHIVE, 0.43f);
pl.w_attack_next = 0.7f;
pl.w_idle_next = 0.7f;
}
void
w_ar2_reload(player pl)
{
if (pl.w_attack_next) {
return;
}
#ifdef SERVER
// w_ar2_shoothornet(pl);
Sound_Play(pl, CHAN_WEAPON, "Weapon_AR2.Reload");
#endif
Weapons_ViewAnimation(pl, AR2_RELOAD);
pl.w_attack_next = 1f;
pl.w_idle_next = 1f;
}
void
w_ar2_crosshair(player pl)
{
#ifdef CLIENT
HUD_DrawAmmo2();
vector pos = g_hudmins + [g_hudres[0] / 2, g_hudres[1] / 2];
Font_DrawText_RGBA(pos + [-7, -14], "Q", g_hud_color, 1.0, FONT_HUD_CROSS);
#endif
}
float
w_ar2_aimanim(player pl)
{
return pl.flags & FL_CROUCHING ? ANIM_CR_AIMHIVE : ANIM_AIMHIVE;
}
void
w_ar2_hudpic(player pl, int selected, vector pos, float a)
{
#ifdef CLIENT
vector hud_col = g_hud_color;
if (selected) {
drawsubpic(
pos,
[128,64],
"materials/Sprites/w_icons2",
[0.0, 0.25],
[128/256,64/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[128,64],
"materials/Sprites/w_icons2",
[0.0, 0.25],
[128/256,64/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
}
HUD_DrawAmmoBar(pos, pl.ammo_hornet, MAX_A_HORNET, a);
#endif
}
int
w_ar2_isempty(player pl)
{
return 0;
}
weapontype_t
w_ar2_type(player pl)
{
return WPNTYPE_RANGED;
}
weapon_t w_ar2 =
{
.name = "hornet",
.id = ITEM_HORNETGUN,
.slot = 2,
.slot_pos = 1,
.weight = 10,
.draw = w_ar2_draw,
.holster = w_ar2_holster,
.primary = w_ar2_primary,
.secondary = w_ar2_secondary,
.reload = w_ar2_reload,
.release = w_ar2_release,
.postdraw = w_ar2_crosshair,
.precache = w_ar2_precache,
.pickup = w_ar2_pickup,
.updateammo = w_ar2_updateammo,
.wmodel = w_ar2_wmodel,
.pmodel = w_ar2_pmodel,
.deathmsg = w_ar2_deathmsg,
.aimanim = w_ar2_aimanim,
.isempty = w_ar2_isempty,
.type = w_ar2_type,
.hudpic = w_ar2_hudpic
};
#ifdef CLIENT
void w_tripmine_parse(void)
{
}
#endif

283
src/shared/w_bugbait.qc Normal file
View file

@ -0,0 +1,283 @@
/*
* Copyright (c) 2016-2021 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef SERVER
.float nadeCookingTime;
#endif
enum
{
BUGBAIT_DRAWBACK,
BUGBAIT_THROW,
BUGBAIT_IDLE,
BUGBAIT_DRAW,
BUGBAIT_HOLSTER,
BUGBAIT_SQUEEZE
};
void w_bugbait_precache(void)
{
#ifdef SERVER
Sound_Precache("weapon_frag.bounce");
precache_model("models/w_grenade.mdl");
particleeffectnum("fx_explosion.main");
precache_model("sprites/fexplo.spr");
#else
precache_model("models/weapons/v_bugbait.mdl");
precache_model("models/p_grenade.mdl");
#endif
}
void w_bugbait_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, -1, pl.ammo_handgrenade, -1);
}
string w_bugbait_wmodel(void)
{
return "models/w_grenade.mdl";
}
string w_bugbait_pmodel(player pl)
{
return "models/p_grenade.mdl";
}
string w_bugbait_deathmsg(void)
{
return "";
}
int w_bugbait_pickup(player pl, int new, int startammo)
{
#ifdef SERVER
int addAmmo = (startammo == -1) ? 1 : startammo;
if (pl.ammo_handgrenade < MAX_A_HANDGRENADE) {
pl.ammo_handgrenade = bound(0, pl.ammo_handgrenade + addAmmo, MAX_A_HANDGRENADE);
} else {
if (!new)
return (0);
}
#endif
return (1);
}
void w_bugbait_draw(player pl)
{
pl.mode_tempstate = 0;
Weapons_SetModel("models/weapons/v_bugbait.mdl");
Weapons_ViewAnimation(pl, BUGBAIT_DRAW);
pl.w_idle_next = 0.9f;
}
void w_bugbait_holster(player pl)
{
}
void w_bugbait_primary(player pl)
{
if (pl.w_attack_next > 0.0) {
return;
}
/* We're abusing this network variable for the holding check */
if (pl.mode_tempstate > 0) {
return;
}
/* Ammo check */
if (pl.ammo_handgrenade <= 0) {
return;
}
Weapons_ViewAnimation(pl, BUGBAIT_DRAWBACK);
pl.mode_tempstate = 1;
pl.w_attack_next = 0.5f;
pl.w_idle_next = 0.5f;
#ifdef SERVER
pl.nadeCookingTime = time;
#endif
}
void w_bugbait_secondary(player pl)
{
if (pl.w_attack_next > 0.0) {
return;
}
/* Ammo check */
if (pl.ammo_handgrenade <= 0) {
return;
}
#ifdef SERVER
Sound_Play(pl, CHAN_WEAPON, "Weapon_Bugbait.Splat");
#endif
Weapons_ViewAnimation(pl, BUGBAIT_SQUEEZE);
pl.w_attack_next = 0.5f;
pl.w_idle_next = 0.6f;
}
void w_bugbait_hud(player pl)
{
#ifdef CLIENT
HUD_DrawAmmo2();
vector pos = g_hudmins + [g_hudres[0] / 2, g_hudres[1] / 2];
Font_DrawText_RGBA(pos + [-7, -14], "Q", g_hud_color, 1.0, FONT_HUD_CROSS);
#endif
}
void w_bugbait_release(player pl)
{
if (pl.w_idle_next > 0.0) {
return;
}
if (pl.mode_tempstate == 1) {
Weapons_ViewAnimation(pl, BUGBAIT_THROW);
#ifdef SERVER
vector throwDirection;
float throwingStrength;
NSProjectile nade = (NSProjectile )EntityDef_CreateClassname("projectile_frag");
nade.SetOwner(pl);
throwDirection = pl.v_angle;
throwDirection[0] = -10.0f; /* always aim a bit up */
/* diminish when aiming up */
if (pl.v_angle[0] < 0) {
throwDirection[0] += (pl.v_angle[0] * 0.9f);
} else { /* increase when aiming down */
throwDirection[0] += (pl.v_angle[0] * 1.1f);
}
throwingStrength = bound(0, (90 - throwDirection[0]) * 5.0f, 1000);
nade.Launch(pl.GetEyePos(), pl.v_angle, time - pl.nadeCookingTime, 0.0f, 0.0f);
makevectors(throwDirection);
nade.SetVelocity((v_forward * throwingStrength) + pl.GetVelocity());
#endif
pl.ammo_handgrenade--;
pl.mode_tempstate = 2;
pl.w_attack_next = 1.0f;
pl.w_idle_next = 0.5f;
if (pl.flags & FL_CROUCHING)
Animation_PlayerTop(pl, ANIM_CR_SHOOTCROWBAR, 0.41f);
else
Animation_PlayerTop(pl, ANIM_SHOOTCROWBAR, 0.5f);
} else if (pl.mode_tempstate == 2) {
Weapons_ViewAnimation(pl, BUGBAIT_DRAW);
#ifdef SERVER
if (!pl.ammo_handgrenade) {
Weapons_RemoveItem(pl, WEAPON_BUGBAIT);
}
#endif
pl.w_attack_next = 0.5f;
pl.w_idle_next = 0.5f;
pl.mode_tempstate = 0;
} else {
Weapons_ViewAnimation(pl, BUGBAIT_IDLE);
pl.w_idle_next = 3.0f;
}
}
float
w_bugbait_aimanim(player pl)
{
return pl.flags & FL_CROUCHING ? ANIM_CR_AIMCROWBAR : ANIM_AIMCROWBAR;
}
void
w_bugbait_hudpic(player pl, int selected, vector pos, float a)
{
#ifdef CLIENT
vector hud_col = g_hud_color;
if (selected) {
drawsubpic(
pos,
[128,64],
"materials/Sprites/w_icons3",
[0, 0.5],
[128/256,64/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[128,64],
"materials/Sprites/w_icons3",
[0, 0.5],
[128/256,64/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
}
HUD_DrawAmmoBar(pos, pl.ammo_handgrenade, MAX_A_HANDGRENADE, a);
#endif
}
int
w_bugbait_isempty(player pl)
{
if (pl.ammo_handgrenade <= 0)
return 1;
return 0;
}
weapontype_t
w_bugbait_type(player pl)
{
return WPNTYPE_THROW;
}
weapon_t w_bugbait =
{
.name = "grenade",
.id = ITEM_HANDGRENADE,
.slot = 5,
.slot_pos = 0,
.weight = 5,
.draw = w_bugbait_draw,
.holster = w_bugbait_holster,
.primary = w_bugbait_primary,
.secondary = w_bugbait_secondary,
.reload = __NULL__,
.release = w_bugbait_release,
.postdraw = w_bugbait_hud,
.precache = w_bugbait_precache,
.pickup = w_bugbait_pickup,
.updateammo = w_bugbait_updateammo,
.wmodel = w_bugbait_wmodel,
.pmodel = w_bugbait_pmodel,
.deathmsg = w_bugbait_deathmsg,
.aimanim = w_bugbait_aimanim,
.isempty = w_bugbait_isempty,
.type = w_bugbait_type,
.hudpic = w_bugbait_hudpic
};

357
src/shared/w_crossbow.qc Normal file
View file

@ -0,0 +1,357 @@
/*
* Copyright (c) 2016-2021 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
enum
{
CROSSBOW_IDLE,
CROSSBOW_IDLE_EMPTY,
CROSSBOW_DRAW,
CROSSBOW_FIRE,
CROSSBOW_RELOAD,
CROSSBOW_HOLSTER,
CROSSBOW_IDLE_TO_LOW,
CROSSBOW_LOW_TO_IDLE,
CROSSBOW_LOW_IDLE
};
void
w_crossbow_precache(void)
{
#ifdef SERVER
Sound_Precache("weapon_crossbow.fire");
Sound_Precache("weapon_crossbow.empty");
Sound_Precache("weapon_crossbow.hit");
Sound_Precache("weapon_crossbow.hitbody");
Sound_Precache("weapon_crossbow.reload");
precache_model("models/crossbow_bolt.mdl");
precache_model("models/w_crossbow.mdl");
#else
precache_model("models/weapons/v_crossbow_dx7.mdl");
precache_model("models/p_crossbow.mdl");
#endif
}
void
w_crossbow_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, pl.crossbow_mag, pl.ammo_bolt, -1);
}
string
w_crossbow_wmodel(void)
{
return "models/w_crossbow.mdl";
}
string
w_crossbow_pmodel(player pl)
{
return "models/p_crossbow.mdl";
}
string
w_crossbow_deathmsg(void)
{
return "";
}
int
w_crossbow_pickup(player pl, int new, int startammo)
{
#ifdef SERVER
int addAmmo = (startammo == -1) ? 1 : startammo;
if (new) {
pl.crossbow_mag = addAmmo;
return (1);
}
if (pl.ammo_bolt < MAX_A_BOLT) {
pl.ammo_bolt = bound(0, pl.ammo_bolt + addAmmo, MAX_A_BOLT);
} else {
if (!new)
return (0);
}
#endif
return (1);
}
void
w_crossbow_draw(player pl)
{
Weapons_SetModel("models/weapons/v_crossbow_dx7.mdl");
Weapons_ViewAnimation(pl, CROSSBOW_DRAW);
pl.w_idle_next = 1.0f;
}
void
w_crossbow_holster(player pl)
{
Weapons_ViewAnimation(pl, CROSSBOW_HOLSTER);
}
void
w_crossbow_primary(player pl)
{
if (pl.w_attack_next > 0.0)
return;
if (pl.gflags & GF_SEMI_TOGGLED)
return;
/* ammo check */
if ((pl.crossbow_mag <= 0i) ? true : false) {
#ifdef SERVER
Sound_Play(pl, CHAN_AUTO, "weapon_crossbow.empty");
#endif
pl.gflags |= GF_SEMI_TOGGLED;
return;
}
pl.crossbow_mag--;
#ifndef CLIENT
HLGameRules rules = (HLGameRules) g_grMode;
/* multiplayer uses hitscan when zoomed in */
if (rules.IsMultiplayer() == true && pl.viewzoom < 1.0) {
vector src, dest;
src = pl.origin + pl.view_ofs;
Weapons_MakeVectors(pl);
dest = src + v_forward * 4096;
traceline(src, dest, MOVE_LAGGED, pl);
if (trace_ent.takedamage == DAMAGE_YES)
Damage_Apply(trace_ent, pl, Skill_GetValue("plr_xbow_bolt_monster", 50), WEAPON_CROSSBOW, DMG_BLUNT);
if (other.iBleeds == FALSE)
pointparticles(particleeffectnum("platform.spark"), self.origin, trace_plane_normal, 1);
else
FX_Blood(trace_endpos, [1,0,0]);
/* fake bolt */
if (trace_ent == world) {
NSRenderableEntity bolt_used = spawn(NSRenderableEntity);
bolt_used.SetSolid(SOLID_NOT);
bolt_used.SetMovetype(MOVETYPE_NONE);
bolt_used.SetModel("models/crossbow_bolt.mdl");
bolt_used.SetSize([0,0,0], [0,0,0]);
bolt_used.SetAngles(pl.v_angle);
bolt_used.SetOrigin(trace_endpos + v_forward * -16);
bolt_used.think = Util_Destroy;
bolt_used.nextthink = time + 10.0f;
}
} else {
/* zoomed out = explosive */
if (rules.IsMultiplayer() == true) {
NSProjectile_SpawnDef("projectile_arrowExplosive", pl);
} else {
NSProjectile_SpawnDef("projectile_arrow", pl);
}
}
if (pl.crossbow_mag > 0) {
Sound_Play(pl, 8, "weapon_crossbow.hitbody");
}
Sound_Play(pl, CHAN_WEAPON, "weapon_crossbow.fire");
#endif
Weapons_ViewAnimation(pl, CROSSBOW_FIRE);
if (pl.flags & FL_CROUCHING)
Animation_PlayerTop(pl, ANIM_CR_SHOOTBOW, 0.25f);
else
Animation_PlayerTop(pl, ANIM_SHOOTBOW, 0.25f);
Weapons_ViewPunchAngle(pl, [-2,0,0]);
pl.w_attack_next =
pl.w_idle_next = 0.65f;
}
void
w_crossbow_secondary(player pl)
{
if (pl.w_attack_next) {
return;
}
/* Simple toggle of fovs */
if (pl.viewzoom == 1.0f) {
pl.viewzoom = 0.2f;
} else {
pl.viewzoom = 1.0f;
}
pl.w_attack_next = 0.5f;
}
void
w_crossbow_reload(player pl)
{
NSTimer reload = __NULL__;
if (pl.w_attack_next > 0.0) {
return;
}
if (pl.ammo_bolt <= 0) {
return;
}
if (pl.crossbow_mag >= 1) {
return;
}
/* undo our zoom */
pl.viewzoom = 1.0f;
#ifdef SERVER
static void w_crossbow_reload_done(void) {
player pl = (player)self;
Weapons_ReloadWeapon(pl, player::crossbow_mag, player::ammo_bolt, 1);
Weapons_ViewAnimation(pl, CROSSBOW_IDLE);
}
reload.TemporaryTimer(pl, w_crossbow_reload_done, 4.4f, false);
Sound_Play(pl, CHAN_ITEM, "weapon_crossbow.reload");
#endif
Weapons_ViewAnimation(pl, CROSSBOW_RELOAD);
pl.w_attack_next =
pl.w_idle_next = 1.8f;
}
void
w_crossbow_release(player pl)
{
/* auto-reload if need be */
if (pl.w_attack_next <= 0.0)
if (pl.crossbow_mag == 0 && pl.ammo_bolt > 0) {
Weapons_ViewAnimation(pl, CROSSBOW_IDLE);
Weapons_Reload(pl);
return;
}
if (pl.w_idle_next > 0.0) {
return;
}
if (pl.crossbow_mag) {
Weapons_ViewAnimation(pl, CROSSBOW_IDLE);
} else {
Weapons_ViewAnimation(pl, CROSSBOW_IDLE_EMPTY);
}
pl.w_idle_next = 0.0f;
}
void
w_crossbow_crosshair(player pl)
{
#ifdef CLIENT
vector pos = g_hudmins + [g_hudres[0] / 2, g_hudres[1] / 2];
Font_DrawText_RGBA(pos + [-7, -14], "Q", g_hud_color, 1.0, FONT_HUD_CROSS);
HUD_DrawAmmo1();
HUD_DrawAmmo2();
#endif
}
float
w_crossbow_aimanim(player pl)
{
return pl.flags & FL_CROUCHING ? ANIM_CR_AIMBOW : ANIM_AIMBOW;
}
void
w_crossbow_hudpic(player pl, int selected, vector pos, float a)
{
#ifdef CLIENT
vector hud_col;
if (pl.crossbow_mag == 0 && pl.ammo_bolt == 0)
hud_col = [1,0,0];
else
hud_col = g_hud_color;
if (selected) {
drawsubpic(
pos,
[128,64],
"materials/Sprites/w_icons2",
[0, 0.75],
[128/256,64/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[128,64],
"materials/Sprites/w_icons2",
[0, 0.75],
[128/256,64/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
}
HUD_DrawAmmoBar(pos, pl.ammo_bolt, MAX_A_BOLT, a);
#endif
}
int
w_crossbow_isempty(player pl)
{
if (pl.crossbow_mag <= 0 && pl.ammo_bolt <= 0)
return 1;
return 0;
}
weapontype_t w_crossbow_type(player pl)
{
return WPNTYPE_RANGED;
}
weapon_t w_crossbow =
{
.name = "crossbow",
.id = ITEM_CROSSBOW,
.slot = 3,
.slot_pos = 1,
.weight = 10,
.draw = w_crossbow_draw,
.holster = w_crossbow_holster,
.primary = w_crossbow_primary,
.secondary = w_crossbow_secondary,
.reload = w_crossbow_reload,
.release = w_crossbow_release,
.postdraw = w_crossbow_crosshair,
.precache = w_crossbow_precache,
.pickup = w_crossbow_pickup,
.updateammo = w_crossbow_updateammo,
.wmodel = w_crossbow_wmodel,
.pmodel = w_crossbow_pmodel,
.deathmsg = w_crossbow_deathmsg,
.aimanim = w_crossbow_aimanim,
.isempty = w_crossbow_isempty,
.type = w_crossbow_type,
.hudpic = w_crossbow_hudpic
};

234
src/shared/w_crowbar.qc Normal file
View file

@ -0,0 +1,234 @@
/*
* Copyright (c) 2016-2020 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
enum
{
CBAR_IDLE,
CBAR_DRAW,
CBAR_ATTACK1MISS,
CBAR_ATTACK2MISS,
CBAR_ATTACK1HIT,
CBAR_ATTACK2HIT,
CBAR_ATTACK3HIT,
CBAR_ATTACK3MISS,
CBAR_HOLSTER
};
void
w_crowbar_precache(void)
{
#ifdef SERVER
Sound_Precache("weapon_crowbar.hit");
Sound_Precache("weapon_crowbar.miss");
Sound_Precache("weapon_crowbar.hitbody");
precache_model("models/w_crowbar.mdl");
#else
precache_model("models/weapons/v_crowbar.mdl");
precache_model("models/p_crowbar.mdl");
#endif
}
void
w_crowbar_updateammo(player pl)
{
}
string
w_crowbar_wmodel(void)
{
return "models/w_crowbar.mdl";
}
string
w_crowbar_pmodel(player pl)
{
return "models/p_crowbar.mdl";
}
string
w_crowbar_deathmsg(void)
{
return "%s was assaulted by %s's Crowbar.";
}
void
w_crowbar_draw(player pl)
{
Weapons_SetModel("models/weapons/v_crowbar.mdl");
Weapons_ViewAnimation(pl, CBAR_DRAW);
pl.w_idle_next = 0.8f;
}
void
w_crowbar_holster(player pl)
{
Weapons_ViewAnimation(pl, CBAR_HOLSTER);
}
void
w_crowbar_primary(player pl)
{
int anim = 0;
vector src;
if (pl.w_attack_next) {
return;
}
Weapons_MakeVectors(pl);
src = pl.origin + pl.view_ofs;
/* make sure we can gib corpses */
int oldhitcontents = pl.hitcontentsmaski;
pl.hitcontentsmaski = CONTENTBITS_POINTSOLID | CONTENTBIT_CORPSE;
traceline(src, src + (v_forward * 64), FALSE, pl);
pl.hitcontentsmaski = oldhitcontents;
if (trace_fraction >= 1.0) {
pl.w_attack_next = 0.5f;
pl.w_idle_next = 0.65f;
} else {
pl.w_attack_next = 0.45f;
pl.w_idle_next = 0.5f;
}
int r = (float)input_sequence % 3.0f;
switch (r) {
case 0:
Weapons_ViewAnimation(pl, trace_fraction >= 1 ? CBAR_ATTACK1MISS:CBAR_ATTACK1HIT);
break;
case 1:
Weapons_ViewAnimation(pl, trace_fraction >= 1 ? CBAR_ATTACK2MISS:CBAR_ATTACK2HIT);
break;
default:
Weapons_ViewAnimation(pl, trace_fraction >= 1 ? CBAR_ATTACK2MISS:CBAR_ATTACK3HIT);
}
if (pl.flags & FL_CROUCHING)
Animation_PlayerTop(pl, ANIM_CR_SHOOTCROWBAR, 0.41f);
else
Animation_PlayerTop(pl, ANIM_SHOOTCROWBAR, 0.5f);
#ifdef SERVER
Sound_Play(pl, CHAN_WEAPON, "Weapon_Crowbar.Single");
if (trace_fraction >= 1.0) {
return;
}
/* don't bother with decals, we got squibs */
if (trace_ent.iBleeds) {
FX_Blood(trace_endpos, [1,0,0]);
} else {
SurfData_Impact(trace_ent, trace_endpos, trace_plane_normal);
}
if (trace_ent.takedamage) {
Damage_Apply(trace_ent, pl, Skill_GetValue("plr_crowbar", 10), WEAPON_CROWBAR, DMG_BLUNT);
if (trace_ent.iBleeds) {
Sound_Play(pl, CHAN_WEAPON, "Weapon_Crowbar.Melee_Hit");
}
} else {
//Sound_Play(pl, CHAN_WEAPON, "Weapon_Crowbar.Melee_HitWorld");
}
#endif
}
void
w_crowbar_release(player pl)
{
if (pl.w_idle_next > 0.0) {
return;
}
Weapons_ViewAnimation(pl, CBAR_IDLE);
pl.w_idle_next = 15.0f;
}
float
w_crowbar_aimanim(player pl)
{
return pl.flags & FL_CROUCHING ? ANIM_CR_AIMCROWBAR : ANIM_AIMCROWBAR;
}
void
w_crowbar_hudpic(player pl, int selected, vector pos, float a)
{
#ifdef CLIENT
vector hud_col = g_hud_color;
if (selected) {
drawsubpic(
pos,
[128,64],
"materials/Sprites/w_icons1",
[0, 0],
[128/256,64/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[128,64],
"materials/Sprites/w_icons1",
[0, 0],
[128/256,64/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
}
#endif
}
int
w_crowbar_isempty(player pl)
{
return 0;
}
weapontype_t w_crowbar_type(player pl)
{
return WPNTYPE_CLOSE;
}
weapon_t w_crowbar =
{
.name = "crowbar",
.id = ITEM_CROWBAR,
.slot = 0,
.slot_pos = 0,
.weight = 0,
.draw = w_crowbar_draw,
.holster = w_crowbar_holster,
.primary = w_crowbar_primary,
.secondary = __NULL__,
.reload = __NULL__,
.release = w_crowbar_release,
.postdraw = __NULL__,
.precache = w_crowbar_precache,
.pickup = __NULL__,
.updateammo = w_crowbar_updateammo,
.wmodel = w_crowbar_wmodel,
.pmodel = w_crowbar_pmodel,
.deathmsg = w_crowbar_deathmsg,
.aimanim = w_crowbar_aimanim,
.isempty = w_crowbar_isempty,
.type = w_crowbar_type,
.hudpic = w_crowbar_hudpic
};

264
src/shared/w_frag.qc Normal file
View file

@ -0,0 +1,264 @@
/*
* Copyright (c) 2016-2021 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef SERVER
.float nadeCookingTime;
#endif
enum
{
HANDGRENADE_IDLE,
HANDGRENADE_DRAWBACKHIGH,
HANDGRENADE_DRAWBACKLOW,
HANDGRENADE_THROW,
HANDGRENADE_ROLL,
HANDGRENADE_LOB,
HANDGRENADE_DRAW,
};
void w_frag_precache(void)
{
#ifdef SERVER
Sound_Precache("weapon_frag.bounce");
precache_model("models/w_grenade.mdl");
particleeffectnum("fx_explosion.main");
precache_model("sprites/fexplo.spr");
#else
precache_model("models/weapons/v_grenade.mdl");
precache_model("models/p_grenade.mdl");
#endif
}
void w_frag_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, -1, pl.ammo_handgrenade, -1);
}
string w_frag_wmodel(void)
{
return "models/w_grenade.mdl";
}
string w_frag_pmodel(player pl)
{
return "models/p_grenade.mdl";
}
string w_frag_deathmsg(void)
{
return "";
}
int w_frag_pickup(player pl, int new, int startammo)
{
#ifdef SERVER
int addAmmo = (startammo == -1) ? 1 : startammo;
if (pl.ammo_handgrenade < MAX_A_HANDGRENADE) {
pl.ammo_handgrenade = bound(0, pl.ammo_handgrenade + addAmmo, MAX_A_HANDGRENADE);
} else {
if (!new)
return (0);
}
#endif
return (1);
}
void w_frag_draw(player pl)
{
pl.mode_tempstate = 0;
Weapons_SetModel("models/weapons/v_grenade.mdl");
Weapons_ViewAnimation(pl, HANDGRENADE_DRAW);
pl.w_idle_next = 0.95f;
}
void w_frag_holster(player pl)
{
}
void w_frag_primary(player pl)
{
if (pl.w_attack_next > 0.0) {
return;
}
/* We're abusing this network variable for the holding check */
if (pl.mode_tempstate > 0) {
return;
}
/* Ammo check */
if (pl.ammo_handgrenade <= 0) {
return;
}
Weapons_ViewAnimation(pl, HANDGRENADE_DRAWBACKHIGH);
pl.mode_tempstate = 1;
pl.w_attack_next = 0.3f;
pl.w_idle_next = 0.2f;
#ifdef SERVER
pl.nadeCookingTime = time;
#endif
}
void w_frag_hud(player pl)
{
#ifdef CLIENT
HUD_DrawAmmo2();
#endif
}
void w_frag_release(player pl)
{
if (pl.w_idle_next > 0.0) {
return;
}
if (pl.mode_tempstate == 1) {
Weapons_ViewAnimation(pl, HANDGRENADE_THROW);
#ifdef SERVER
vector throwDirection;
float throwingStrength;
NSProjectile nade = (NSProjectile )EntityDef_CreateClassname("projectile_frag");
nade.SetOwner(pl);
throwDirection = pl.v_angle;
throwDirection[0] = -10.0f; /* always aim a bit up */
/* diminish when aiming up */
if (pl.v_angle[0] < 0) {
throwDirection[0] += (pl.v_angle[0] * 0.9f);
} else { /* increase when aiming down */
throwDirection[0] += (pl.v_angle[0] * 1.1f);
}
throwingStrength = bound(0, (90 - throwDirection[0]) * 5.0f, 1000);
nade.Launch(pl.GetEyePos(), pl.v_angle, time - pl.nadeCookingTime, 0.0f, 0.0f);
makevectors(throwDirection);
nade.SetVelocity((v_forward * throwingStrength) + pl.GetVelocity());
#endif
pl.ammo_handgrenade--;
pl.mode_tempstate = 2;
pl.w_attack_next = 1.0f;
pl.w_idle_next = 0.5f;
if (pl.flags & FL_CROUCHING)
Animation_PlayerTop(pl, ANIM_CR_SHOOTCROWBAR, 0.41f);
else
Animation_PlayerTop(pl, ANIM_SHOOTCROWBAR, 0.5f);
} else if (pl.mode_tempstate == 2) {
Weapons_ViewAnimation(pl, HANDGRENADE_DRAW);
#ifdef SERVER
if (!pl.ammo_handgrenade) {
Weapons_RemoveItem(pl, WEAPON_FRAG);
}
#endif
pl.w_attack_next = 1.2f;
pl.w_idle_next = 1.2f;
pl.mode_tempstate = 0;
} else {
Weapons_ViewAnimation(pl, HANDGRENADE_IDLE);
pl.w_idle_next = 3.0f;
}
}
float
w_frag_aimanim(player pl)
{
return pl.flags & FL_CROUCHING ? ANIM_CR_AIMCROWBAR : ANIM_AIMCROWBAR;
}
void
w_frag_hudpic(player pl, int selected, vector pos, float a)
{
#ifdef CLIENT
vector hud_col = g_hud_color;
if (selected) {
drawsubpic(
pos,
[128,64],
"materials/Sprites/w_icons2",
[0.5, 0.5],
[128/256,64/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[128,64],
"materials/Sprites/w_icons2",
[0.5, 0.5],
[128/256,64/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
}
HUD_DrawAmmoBar(pos, pl.ammo_handgrenade, MAX_A_HANDGRENADE, a);
#endif
}
int
w_frag_isempty(player pl)
{
if (pl.ammo_handgrenade <= 0)
return 1;
return 0;
}
weapontype_t
w_frag_type(player pl)
{
return WPNTYPE_THROW;
}
weapon_t w_frag =
{
.name = "grenade",
.id = ITEM_HANDGRENADE,
.slot = 4,
.slot_pos = 0,
.weight = 5,
.draw = w_frag_draw,
.holster = w_frag_holster,
.primary = w_frag_primary,
.secondary = __NULL__,
.reload = __NULL__,
.release = w_frag_release,
.postdraw = w_frag_hud,
.precache = w_frag_precache,
.pickup = w_frag_pickup,
.updateammo = w_frag_updateammo,
.wmodel = w_frag_wmodel,
.pmodel = w_frag_pmodel,
.deathmsg = w_frag_deathmsg,
.aimanim = w_frag_aimanim,
.isempty = w_frag_isempty,
.type = w_frag_type,
.hudpic = w_frag_hudpic
};

283
src/shared/w_gravitygun.qc Normal file
View file

@ -0,0 +1,283 @@
/*
* Copyright (c) 2016-2021 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef CLIENT
var float TRAIL_EGONBEAM;
string w_gravitygun_sparkframes[11];
void
w_gravitygun_beamfx(vector vecPos, vector vecEndPos, entity eOwner)
{
trailparticles(TRAIL_EGONBEAM, eOwner, vecPos, vecEndPos);
}
#endif
enum
{
GRAVGUN_PADDING1,
GRAVGUN_PADDING2,
GRAVGUN_IDLE,
GRAVGUN_HOLD_IDLE,
GRAVGUN_DRAW,
GRAVGUN_HOLSTER,
GRAVGUN_FIRE,
GRAVGUN_ALTFIRE,
};
void w_gravitygun_precache(void)
{
#ifdef SERVER
precache_sound("weapons/egon_windup2.wav");
precache_sound("weapons/egon_run3.wav");
precache_sound("weapons/egon_off1.wav");
precache_model("models/w_gravitygun.mdl");
Sound_Precache("weapon_egon.empty");
#else
TRAIL_EGONBEAM = particleeffectnum("weapon_egon.beam");
precache_model("models/weapons/v_physcannon.mdl");
precache_model("models/p_egon.mdl");
precache_model("sprites/xspark1.spr");
for (int i = 0; i < 11; i++)
w_gravitygun_sparkframes[i] = spriteframe("sprites/xspark1.spr", i, 0.0f);
#endif
}
void w_gravitygun_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, -1, pl.ammo_uranium, -1);
}
string w_gravitygun_wmodel(void)
{
return "models/w_gravitygun.mdl";
}
string w_gravitygun_pmodel(player pl)
{
return "models/p_egon.mdl";
}
string w_gravitygun_deathmsg(void)
{
return "";
}
int w_gravitygun_pickup(player pl, int new, int startammo)
{
#ifdef SERVER
int addAmmo = (startammo == -1) ? 20 : startammo;
if (pl.ammo_uranium < MAX_A_URANIUM) {
pl.ammo_uranium = bound(0, pl.ammo_uranium + addAmmo, MAX_A_URANIUM);
} else {
if (!new)
return (0);
}
#endif
return (1);
}
void w_gravitygun_draw(player pl)
{
pl.mode_tempstate = 0;
Weapons_SetModel("models/weapons/v_physcannon.mdl");
Weapons_ViewAnimation(pl, GRAVGUN_DRAW);
pl.w_idle_next = 0.95f;
}
void w_gravitygun_holster(player pl)
{
Weapons_ViewAnimation(pl, GRAVGUN_HOLSTER);
}
void w_gravitygun_release(player pl);
void w_gravitygun_primary(player pl)
{
if (pl.w_attack_next > 0.0f) {
return;
}
Weapons_ViewAnimation(pl, GRAVGUN_FIRE);
pl.w_attack_next = 0.6f;
pl.w_idle_next = 0.6f;
}
void w_gravitygun_secondary(player pl)
{
if (pl.w_attack_next > 0.0f) {
return;
}
Weapons_ViewAnimation(pl, GRAVGUN_FIRE);
pl.w_attack_next = 0.4f;
pl.w_idle_next = 0.4f;
}
void w_gravitygun_reload(player pl)
{
}
void w_gravitygun_release(player pl)
{
if (pl.w_idle_next > 0.0)
return;
Weapons_ViewAnimation(pl, GRAVGUN_IDLE);
pl.w_idle_next = 2.0f;
}
void
w_gravitygun_postdraw(player pl, int thirdperson)
{
#ifdef CLIENT
if (!(pl.gflags & GF_EGONBEAM))
return;
vector src;
vector endpos;
if (thirdperson) {
makevectors(pl.v_angle);
src = pl.origin;
endpos = pl.origin + (v_forward * 1024);
traceline(src, endpos, MOVE_NORMAL, pl);
w_gravitygun_beamfx(gettaginfo(pl.p_model, 10), trace_endpos, pl);
} else {
vector gunpos = gettaginfo(pSeat->m_eViewModel, 33);
src = gettaginfo(pSeat->m_eViewModel, 0);
makevectors(view_angles);
endpos = src + v_forward * 1024;
traceline(src, endpos, FALSE, pl);
w_gravitygun_beamfx(gunpos, endpos, pl);
}
int i = (cltime*10.0f) % 11.0f;
vector fsize = [32,32];
makevectors(view_angles);
trace_endpos += v_forward * -16; /* nudge towards our camera */
dynamiclight_add(trace_endpos, 128, [0.5, 0.5, 1.0]);
R_BeginPolygon(w_gravitygun_sparkframes[i], 1, 0);
R_PolygonVertex(trace_endpos + v_right * fsize[0] - v_up * fsize[1],
[1,1], [1,1,1], 1.0f);
R_PolygonVertex(trace_endpos - v_right * fsize[0] - v_up * fsize[1],
[0,1], [1,1,1], 1.0f);
R_PolygonVertex(trace_endpos - v_right * fsize[0] + v_up * fsize[1],
[0,0], [1,1,1], 1.0f);
R_PolygonVertex(trace_endpos + v_right * fsize[0] + v_up * fsize[1],
[1,0], [1,1,1], 1.0f);
R_EndPolygon();
#endif
}
void w_gravitygun_crosshair(player pl)
{
#ifdef CLIENT
vector pos = g_hudmins + [g_hudres[0] / 2, g_hudres[1] / 2];
Font_DrawText_RGBA(pos + [-7, -14], "Q", g_hud_color, 1.0, FONT_HUD_CROSS);
HUD_DrawAmmo2();
#endif
}
float w_gravitygun_aimanim(player pl)
{
return pl.flags & FL_CROUCHING ? ANIM_CR_AIMEGON : ANIM_AIMEGON;
}
void w_gravitygun_hudpic(player pl, int selected, vector pos, float a)
{
#ifdef CLIENT
vector hud_col;
if (pl.ammo_uranium == 0)
hud_col = [1,0,0];
else
hud_col = g_hud_color;
if (selected) {
drawsubpic(
pos,
[128,64],
"materials/Sprites/w_icons2",
[0.5, 0.75],
[128/256,64/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[128,64],
"materials/Sprites/w_icons2",
[0.5, 0.75],
[128/256,64/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
}
HUD_DrawAmmoBar(pos, pl.ammo_uranium, MAX_A_URANIUM, a);
#endif
}
int
w_gravitygun_isempty(player pl)
{
if (pl.ammo_uranium <= 0)
return 1;
return 0;
}
weapontype_t
w_gravitygun_type(player pl)
{
return WPNTYPE_FULLAUTO;
}
weapon_t w_gravitygun =
{
.name = "egon",
.id = ITEM_EGON,
.slot = 0,
.slot_pos = 1,
.weight = 15,
.draw = w_gravitygun_draw,
.holster = w_gravitygun_holster,
.primary = w_gravitygun_primary,
.secondary = w_gravitygun_secondary,
.reload = w_gravitygun_reload,
.release = w_gravitygun_release,
.postdraw = w_gravitygun_crosshair,
.precache = w_gravitygun_precache,
.pickup = w_gravitygun_pickup,
.updateammo = w_gravitygun_updateammo,
.wmodel = w_gravitygun_wmodel,
.pmodel = w_gravitygun_pmodel,
.deathmsg = w_gravitygun_deathmsg,
.aimanim = w_gravitygun_aimanim,
.hudpic = w_gravitygun_hudpic,
.isempty = w_gravitygun_isempty,
.type = w_gravitygun_type,
.predraw = w_gravitygun_postdraw
};

364
src/shared/w_pistol.qc Normal file
View file

@ -0,0 +1,364 @@
/*
* Copyright (c) 2016-2021 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
enum
{
PISTOL_IDLE, // 0
PISTOL_IDLE_EMPTY, // 1
PISTOL_FIRE1, // 2
PISTOL_FIRE2, // 3
PISTOL_FIRE3, // 4
PISTOL_FIRE4, // 5
PISTOL_FIRE_EMPTY, // 6
PISTOL_DRAW, //7
PISTOL_DRAW_EMPTY, // 8
PISTOL_RELOAD, // 9
PISTOL_HOLSTER,
PISTOL_HOLSTER_EMPTY,
PISTOL_IDLE_TO_LOW,
PISTOL_LOW_TO_IDLE,
PISTOL_LOW_IDLE
};
#ifdef CLIENT
void w_pistol_ejectshell(void)
{
static void w_pistol_ejectshell_death(void) {
remove(self);
}
static void w_pistol_ejectshell_touch(void) {
if (other == world)
Sound_Play(self, CHAN_BODY, "Bounce.Shell");
}
entity eShell = spawn();
setmodel(eShell, "models/weapons/shell.mdl");
eShell.solid = SOLID_BBOX;
eShell.movetype = MOVETYPE_BOUNCE;
eShell.drawmask = MASK_ENGINE;
eShell.angles = [pSeat->m_eViewModel.angles[0], pSeat->m_eViewModel.angles[1], 0];
eShell.velocity = pSeat->m_vecPredictedVelocity;
makevectors(pSeat->m_eViewModel.angles);
eShell.velocity += (v_forward * 0);
eShell.velocity += (v_right * 80);
eShell.velocity += (v_up * 100);
eShell.touch = w_pistol_ejectshell_touch;
eShell.avelocity = [0,45,900];
eShell.think = w_pistol_ejectshell_death;
eShell.nextthink = time + 2.5f;
setsize(eShell, [0,0,0], [0,0,0]);
setorigin(eShell, pSeat->m_eViewModel.origin + (v_forward * 26) + (v_right * 8) + (v_up * -4));
}
#endif
void
w_pistol_precache(void)
{
#ifdef SERVER
precache_model("models/w_9mmhandgun.mdl");
precache_model("models/weapons/shell.mdl");
#else
precache_model("models/weapons/v_pistol.mdl");
precache_model("models/p_9mmhandgun.mdl");
precache_model("models/weapons/shell.mdl");
#endif
}
void
w_pistol_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, pl.glock_mag, pl.ammo_9mm, -1);
}
string
w_pistol_wmodel(void)
{
return "models/w_9mmhandgun.mdl";
}
string
w_pistol_pmodel(player pl)
{
return "models/p_9mmhandgun.mdl";
}
string
w_pistol_deathmsg(void)
{
return "";
}
int
w_pistol_pickup(player pl, int new, int startammo)
{
#ifdef SERVER
int addAmmo = (startammo == -1) ? 18 : startammo;
if (new) {
pl.glock_mag = addAmmo;
return (1);
}
if (pl.ammo_9mm < MAX_A_9MM) {
pl.ammo_9mm = bound(0, pl.ammo_9mm + addAmmo, MAX_A_9MM);
} else {
if (!new)
return (0);
}
#endif
return (1);
}
void
w_pistol_draw(player pl)
{
Weapons_SetModel("models/weapons/v_pistol.mdl");
if (pl.glock_mag)
Weapons_ViewAnimation(pl, PISTOL_DRAW);
else
Weapons_ViewAnimation(pl, PISTOL_DRAW_EMPTY);
pl.w_idle_next = 0.8f;
}
void
w_pistol_holster(player pl)
{
if (pl.glock_mag)
Weapons_ViewAnimation(pl, PISTOL_HOLSTER);
else
Weapons_ViewAnimation(pl, PISTOL_HOLSTER_EMPTY);
}
int
w_pistol_isempty(player pl)
{
if (pl.glock_mag <= 0 && pl.ammo_9mm <= 0)
return 1;
return 0;
}
void
w_pistol_primary(player pl)
{
if (pl.w_attack_next > 0.0)
return;
if (pl.gflags & GF_SEMI_TOGGLED)
return;
/* ammo check */
if ((pl.glock_mag <= 0i) ? true : false) {
#ifdef SERVER
Sound_Play(pl, CHAN_AUTO, "Weapon_Pistol.Empty");
#endif
pl.gflags |= GF_SEMI_TOGGLED;
return;
}
/* actual firing */
pl.glock_mag--;
#ifdef CLIENT
View_SetMuzzleflash(MUZZLE_SMALL);
View_AddEvent(w_pistol_ejectshell, 0.0f);
#else
TraceAttack_FireBullets(1, pl.origin + pl.view_ofs, Skill_GetValue("plr_9mm_bullet", 8), [0.01,0.01], WEAPON_PISTOL);
Sound_Play(pl, CHAN_WEAPON, "Weapon_Pistol.Single");
#endif
Weapons_ViewPunchAngle(pl, [-2,0,0]);
if (pl.glock_mag) {
int r = floor(pseudorandom() * 3.0f);
Weapons_ViewAnimation(pl, PISTOL_FIRE2 + r);
} else {
Weapons_ViewAnimation(pl, PISTOL_FIRE_EMPTY);
}
if (pl.flags & FL_CROUCHING)
Animation_PlayerTop(pl, ANIM_CR_SHOOT1HAND, 0.2f);
else
Animation_PlayerTop(pl, ANIM_SHOOT1HAND, 0.2f);
pl.w_attack_next = 0.1f;
pl.w_idle_next = 0.4f;
pl.gflags |= GF_SEMI_TOGGLED;
}
void
w_pistol_secondary(player pl)
{
}
void
w_pistol_reload(player pl)
{
if (pl.w_attack_next > 0.0) {
return;
}
if (pl.glock_mag >= 18) {
return;
}
if (pl.ammo_9mm <= 0) {
return;
}
Weapons_ViewAnimation(pl, PISTOL_RELOAD);
#ifdef SERVER
static void w_pistol_reload_done(void) {
player pl = (player)self;
Weapons_ReloadWeapon(pl, player::glock_mag, player::ammo_9mm, 18);
}
pl.think = w_pistol_reload_done;
pl.nextthink = time + 1.38f;
Sound_Play(pl, CHAN_WEAPON, "Weapon_Pistol.Reload");
#endif
pl.w_attack_next = 1.40f;
pl.w_idle_next = 1.40f;
}
void
w_pistol_release(player pl)
{
int r;
/* auto-reload if need be */
if (pl.w_attack_next <= 0.0)
if (pl.glock_mag == 0 && pl.ammo_9mm > 0) {
Weapons_ViewAnimation(pl, PISTOL_IDLE);
Weapons_Reload(pl);
return;
}
if (pl.w_idle_next > 0.0)
return;
if (pl.glock_mag)
Weapons_ViewAnimation(pl, PISTOL_IDLE);
else
Weapons_ViewAnimation(pl, PISTOL_IDLE_EMPTY);
}
float
w_pistol_aimanim(player pl)
{
return pl.flags & FL_CROUCHING ? ANIM_CR_AIM1HAND : ANIM_AIM1HAND;
}
void
w_pistol_hud(player pl)
{
#ifdef CLIENT
vector pos = g_hudmins + [g_hudres[0] / 2, g_hudres[1] / 2];
Font_DrawText_RGBA(pos + [-7, -14], "Q", g_hud_color, 1.0, FONT_HUD_CROSS);
#if 0
drawsubpic(
pos + [-28, -28],
[56,56],
"materials/Sprites/qi_center",
[0,36/128],
[56/128, 56/128],
g_hud_color,
1.0f,
DRAWFLAG_ADDITIVE
);
#endif
HUD_DrawAmmo1();
HUD_DrawAmmo2();
#endif
}
void
w_pistol_hudpic(player pl, int selected, vector pos, float a)
{
#ifdef CLIENT
vector hud_col;
if (pl.glock_mag == 0 && pl.ammo_9mm == 0)
hud_col = [1,0,0];
else
hud_col = g_hud_color;
if (selected) {
drawsubpic(
pos,
[128,64],
"materials/Sprites/w_icons1",
[0.5, 0.0],
[128/256,64/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[128,64],
"materials/Sprites/w_icons1",
[0.5, 0.0],
[128/256,64/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
}
HUD_DrawAmmoBar(pos, pl.ammo_9mm, MAX_A_9MM, a);
#endif
}
weapontype_t
w_pistol_type(player pl)
{
return WPNTYPE_RANGED;
}
weapon_t w_pistol =
{
.name = "9mmhandgun",
.id = ITEM_GLOCK,
.slot = 1,
.slot_pos = 0,
.weight = 10,
.draw = w_pistol_draw,
.holster = w_pistol_holster,
.primary = w_pistol_primary,
.secondary = w_pistol_secondary,
.reload = w_pistol_reload,
.release = w_pistol_release,
.postdraw = w_pistol_hud,
.precache = w_pistol_precache,
.pickup = w_pistol_pickup,
.updateammo = w_pistol_updateammo,
.wmodel = w_pistol_wmodel,
.pmodel = w_pistol_pmodel,
.deathmsg = w_pistol_deathmsg,
.aimanim = w_pistol_aimanim,
.isempty = w_pistol_isempty,
.type = w_pistol_type,
.hudpic = w_pistol_hudpic
};

321
src/shared/w_rpg.qc Normal file
View file

@ -0,0 +1,321 @@
/*
* Copyright (c) 2016-2021 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
enum
{
RPG_IDLE,
RPG_DRAW,
RPG_FIRE,
RPG_RELOAD,
RPG_UP_TO_DOWN,
RPG_DOWN_TO_UP,
RPG_DOWN_IDLE
};
void w_rpg_precache(void)
{
#ifdef SERVER
Sound_Precache("weapon_rpg.shoot");
Sound_Precache("weapon_rpg.empty");
precache_model("models/w_rpg.mdl");
precache_model("models/rpgrocket.mdl");
Sound_Precache("fx.explosion");
#else
precache_model("models/weapons/v_rpg.mdl");
precache_model("models/p_rpg.mdl");
precache_model("sprites/laserdot.spr");
#endif
}
void w_rpg_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, pl.rpg_mag, pl.ammo_rocket, -1);
}
string w_rpg_wmodel(void)
{
return "models/w_rpg.mdl";
}
string w_rpg_pmodel(player pl)
{
return "models/p_rpg.mdl";
}
string w_rpg_deathmsg(void)
{
return "";
}
int w_rpg_pickup(player pl, int new, int startammo)
{
#ifdef SERVER
int addAmmo = (startammo == -1) ? 2 : startammo;
if (new) {
if (addAmmo > 1) {
pl.rpg_mag = 1;
pl.ammo_rocket = bound(0, pl.ammo_rocket + 1, MAX_A_ROCKET);
} else {
pl.rpg_mag = addAmmo;
}
return (1);
}
if (pl.ammo_rocket < MAX_A_ROCKET) {
pl.ammo_rocket = bound(0, pl.ammo_rocket + 2, MAX_A_ROCKET);
} else {
if (!new)
return (0);
}
#endif
return (1);
}
void w_rpg_draw(player pl)
{
Weapons_SetModel("models/weapons/v_rpg.mdl");
Weapons_ViewAnimation(pl, RPG_DRAW);
pl.ammo_rpg_state = 1;
pl.w_idle_next = 1.13f;;
}
void w_rpg_holster(player pl)
{
}
void w_rpg_primary(player pl)
{
if (pl.w_attack_next > 0.0)
return;
if (pl.gflags & GF_SEMI_TOGGLED)
return;
/* ammo check */
if ((pl.rpg_mag <= 0i) ? true : false) {
#ifdef SERVER
Sound_Play(pl, CHAN_AUTO, "weapon_rpg.empty");
#endif
pl.gflags |= GF_SEMI_TOGGLED;
return;
}
pl.rpg_mag--;
#ifdef SERVER
if (pl.ammo_rpg_state > 0) {
NSProjectile_SpawnDef("projectile_rocket_homing", pl);
} else {
NSProjectile_SpawnDef("projectile_rocket", pl);
}
Sound_Play(pl, CHAN_WEAPON, "weapon_rpg.shoot");
#endif
Weapons_ViewAnimation(pl, RPG_FIRE);
Weapons_ViewPunchAngle(pl, [-10,0,0]);
if (pl.flags & FL_CROUCHING)
Animation_PlayerTop(pl, ANIM_CR_SHOOTRPG, 0.43f);
else
Animation_PlayerTop(pl, ANIM_SHOOTRPG, 0.43f);
pl.w_attack_next =
pl.w_idle_next = 1.16f;
}
void w_rpg_reload(player pl)
{
if (pl.w_attack_next > 0) {
return;
}
/* Ammo check */
if (pl.rpg_mag >= 1) {
return;
}
if (pl.ammo_rocket <= 0) {
return;
}
Weapons_ViewAnimation(pl, RPG_RELOAD);
/* Audio-Visual Bit */
#ifdef SERVER
static void w_rpg_reload_done(void) {
player pl = (player)self;
Weapons_ReloadWeapon(pl, player::rpg_mag, player::ammo_rocket, 1);
}
pl.think = w_rpg_reload_done;
pl.nextthink = time + 2.15f;
#endif
pl.w_attack_next = 1.70f;
pl.w_idle_next = 1.70f;
}
void w_rpg_release(player pl)
{
/* auto-reload if need be */
if (pl.w_attack_next <= 0.0)
if (pl.rpg_mag == 0 && pl.ammo_rocket > 0) {
Weapons_Reload(pl);
return;
}
if (pl.w_idle_next > 0.0) {
return;
}
Weapons_ViewAnimation(pl, RPG_IDLE);
}
void w_rpg_secondary(player pl)
{
if (pl.w_attack_next > 0.0) {
return;
}
/* toggle laser */
pl.ammo_rpg_state = 1 - pl.ammo_rpg_state;
pl.w_attack_next = 0.25f;
w_rpg_release(pl);
}
float w_rpg_aimanim(player pl)
{
return pl.flags & FL_CROUCHING ? ANIM_CR_AIMRPG : ANIM_AIMRPG;
}
void w_rpg_hudpic(player pl, int selected, vector pos, float a)
{
#ifdef CLIENT
vector hud_col;
if (pl.rpg_mag == 0 && pl.ammo_rocket == 0)
hud_col = [1,0,0];
else
hud_col = g_hud_color;
if (selected) {
drawsubpic(
pos,
[128,64],
"materials/Sprites/w_icons3",
[0, 0.25],
[128/256,64/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[128,64],
"materials/Sprites/w_icons3",
[0, 0.25],
[128/256,64/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
}
HUD_DrawAmmoBar(pos, pl.ammo_rocket, MAX_A_ROCKET, a);
#endif
}
void w_rpg_hud(player pl)
{
#ifdef CLIENT
vector laser_pos;
vector aicon_pos;
/* crosshair/laser */
if (pl.ammo_rpg_state == 1) {
float lerp;
vector jitter = [0.0f, 0.0f, 0.0f];
Weapons_MakeVectors(pl);
vector src = pl.origin + pl.view_ofs;
traceline(src, src + (v_forward * 256), FALSE, pl);
lerp = Math_Lerp(18,6, trace_fraction);
jitter[0] = (random(0,2) - 2) * (1 - trace_fraction);
jitter[1] = (random(0,2) - 2) * (1 - trace_fraction);
laser_pos = g_hudmins + (g_hudres / 2) + ([-lerp,-lerp] / 2);
drawsubpic(
laser_pos + jitter,
[lerp,lerp],
g_laser_spr,
[0,0],
[1.0, 1.0],
[1,1,1],
1.0f,
DRAWFLAG_ADDITIVE
);
}
vector pos = g_hudmins + [g_hudres[0] / 2, g_hudres[1] / 2];
Font_DrawText_RGBA(pos + [-7, -14], "Q", g_hud_color, 1.0, FONT_HUD_CROSS);
/* ammo counters */
HUD_DrawAmmo1();
HUD_DrawAmmo2();
#endif
}
int
w_rpg_isempty(player pl)
{
if (pl.rpg_mag <= 0 && pl.ammo_rocket <= 0)
return 1;
return 0;
}
weapontype_t
w_rpg_type(player pl)
{
return WPNTYPE_RANGED;
}
weapon_t w_rpg =
{
.name = "rpg_rocket",
.id = ITEM_RPG,
.slot = 4,
.slot_pos = 1,
.weight = 20,
.draw = w_rpg_draw,
.holster = w_rpg_holster,
.primary = w_rpg_primary,
.secondary = w_rpg_secondary,
.reload = w_rpg_reload,
.release = w_rpg_release,
.postdraw = w_rpg_hud,
.precache = w_rpg_precache,
.pickup = w_rpg_pickup,
.updateammo = w_rpg_updateammo,
.wmodel = w_rpg_wmodel,
.pmodel = w_rpg_pmodel,
.deathmsg = w_rpg_deathmsg,
.aimanim = w_rpg_aimanim,
.isempty = w_rpg_isempty,
.type = w_rpg_type,
.hudpic = w_rpg_hudpic
};

452
src/shared/w_shotgun.qc Normal file
View file

@ -0,0 +1,452 @@
/*
* Copyright (c) 2016-2021 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
enum
{
SHOTGUN_IDLE,
SHOTGUN_FIRE,
SHOTGUN_ALTFIRE,
SHOTGUN_DRAW,
SHOTGUN_HOLSTER,
SHOTGUN_START_RELOAD,
SHOTGUN_INSERT_SHELL,
SHOTGUN_END_RELOAD,
SHOTGUN_PUMP,
SHOTGUN_DRYFIRE,
SHOTGUN_LOW,
SHOTGUN_LOW_TO_IDLE,
SHOTGUN_IDLE_TO_LOW
};
enum
{
SHOTTY_IDLE,
SHOTTY_RELOAD_START,
SHOTTY_RELOAD,
SHOTTY_MOVEDOWN,
SHOTTY_RELOAD_END,
SHOTTY_COCKSOUND
};
#ifdef CLIENT
void w_shotgun_ejectshell(void)
{
static void w_shotgun_ejectshell_death(void) {
remove(self);
}
static void w_shotgun_ejectshell_touch(void) {
if (other == world)
Sound_Play(self, CHAN_BODY, "Bounce.ShotgunShell");
}
entity eShell = spawn();
setmodel(eShell, "models/weapons/shotgun_shell.mdl");
eShell.solid = SOLID_BBOX;
eShell.movetype = MOVETYPE_BOUNCE;
eShell.drawmask = MASK_ENGINE;
eShell.angles = [pSeat->m_eViewModel.angles[0], pSeat->m_eViewModel.angles[1], 0];
eShell.velocity = pSeat->m_vecPredictedVelocity;
makevectors(pSeat->m_eViewModel.angles);
eShell.velocity += (v_forward * 0);
eShell.velocity += (v_right * 80);
eShell.velocity += (v_up * 100);
eShell.touch = w_shotgun_ejectshell_touch;
eShell.avelocity = [0,45,900];
eShell.think = w_shotgun_ejectshell_death;
eShell.nextthink = time + 2.5f;
setsize(eShell, [0,0,0], [0,0,0]);
setorigin(eShell, pSeat->m_eViewModel.origin + (v_forward * 26) + (v_right * 8) + (v_up * -8));
}
#endif
void w_shotgun_precache(void)
{
#ifdef SERVER
precache_model("models/w_shotgun.mdl");
precache_model("models/shotgunshell.mdl");
#else
precache_model("models/weapons/v_shotgun.mdl");
precache_model("models/p_shotgun.mdl");
precache_model("models/shotgunshell.mdl");
#endif
}
void
w_shotgun_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, pl.shotgun_mag, pl.ammo_buckshot, -1);
}
string
w_shotgun_wmodel(void)
{
return "models/w_shotgun.mdl";
}
string
w_shotgun_pmodel(player pl)
{
return "models/p_shotgun.mdl";
}
string
w_shotgun_deathmsg(void)
{
return "";
}
int
w_shotgun_pickup(player pl, int new, int startammo)
{
#ifdef SERVER
int addAmmo = (startammo == -1) ? 8 : startammo;
if (new) {
pl.shotgun_mag = addAmmo;
return (1);
}
if (pl.ammo_buckshot < MAX_A_BUCKSHOT) {
pl.ammo_buckshot = bound(0, pl.ammo_buckshot + addAmmo, MAX_A_BUCKSHOT);
} else {
if (!new)
return (0);
}
#endif
return (1);
}
void
w_shotgun_draw(player pl)
{
pl.mode_tempstate = 0;
Weapons_SetModel("models/weapons/v_shotgun.mdl");
Weapons_ViewAnimation(pl, SHOTGUN_DRAW);
pl.w_idle_next = 0.7f;
}
void
w_shotgun_holster(player pl)
{
Weapons_ViewAnimation(pl, SHOTGUN_HOLSTER);
pl.w_idle_next = 0.3f;
}
void w_shotgun_release(player pl);
void
w_shotgun_reload(player pl)
{
if (pl.shotgun_mag >= 8) {
return;
}
if (pl.ammo_buckshot <= 0) {
return;
}
if (pl.mode_tempstate > SHOTTY_IDLE) {
return;
}
pl.mode_tempstate = SHOTTY_RELOAD_START;
pl.w_idle_next = 0.0f;
}
void
w_shotgun_primary(player pl)
{
if (pl.gflags & GF_SEMI_TOGGLED)
return;
/* Ammo check */
if ((pl.shotgun_mag <= 0) || (pl.WaterLevel() >= WATERLEVEL_SUBMERGED)) {
#ifdef SERVER
Sound_Play(pl, CHAN_AUTO, "Weapon_Shotgun.Empty");
#endif
pl.gflags |= GF_SEMI_TOGGLED;
return;
}
if (pl.w_attack_next) {
w_shotgun_release(pl);
return;
}
/* interrupt reloading if no longer empty */
if (pl.mode_tempstate == SHOTTY_RELOAD && pl.shotgun_mag >= 1) {
pl.mode_tempstate = SHOTTY_RELOAD_END;
w_shotgun_release(pl);
return;
} else if (pl.mode_tempstate > SHOTTY_IDLE) {
w_shotgun_release(pl);
return;
}
/* Ammo check */
if (pl.shotgun_mag <= 0) {
w_shotgun_release(pl);
return;
}
#ifdef SERVER
/* Singleplayer is more accurate */
if (serverkeyfloat("sv_playerslots") == 1) {
TraceAttack_FireBullets(6, pl.origin + pl.view_ofs, Skill_GetValue("plr_buckshot", 5), [0.08716,0.08716], WEAPON_SHOTGUN);
} else {
TraceAttack_FireBullets(4, pl.origin + pl.view_ofs, Skill_GetValue("plr_buckshot", 5), [0.08716,0.04362], WEAPON_SHOTGUN);
}
Sound_Play(pl, CHAN_WEAPON, "Weapon_Shotgun.Single");
#else
View_SetMuzzleflash(MUZZLE_WEIRD);
View_AddEvent(w_shotgun_ejectshell, 0.5f);
#endif
Weapons_ViewAnimation(pl, SHOTGUN_FIRE);
Weapons_ViewPunchAngle(pl, [-5,0,0]);
if (pl.flags & FL_CROUCHING)
Animation_PlayerTop(pl, ANIM_CR_SHOOTSHOTGUN, 0.41f);
else
Animation_PlayerTop(pl, ANIM_SHOOTSHOTGUN, 0.5f);
pl.shotgun_mag--;
/* after 1/2 a second, play the cocksound and eject shell */
pl.mode_tempstate = SHOTTY_RELOAD_END;
pl.w_idle_next = 0.3f;
pl.w_attack_next = 0.3f;
}
void
w_shotgun_secondary(player pl)
{
if (pl.gflags & GF_SEMI_TOGGLED)
return;
/* Ammo check */
if ((pl.shotgun_mag <= 1) || (pl.WaterLevel() >= WATERLEVEL_SUBMERGED)) {
#ifdef SERVER
Sound_Play(pl, CHAN_AUTO, "Weapon_Shotgun.Empty");
#endif
pl.gflags |= GF_SEMI_TOGGLED;
return;
}
if (pl.w_attack_next) {
w_shotgun_release(pl);
return;
}
/* interrupt reloading if no longer empty */
if (pl.mode_tempstate == SHOTTY_RELOAD && pl.shotgun_mag >= 2) {
pl.mode_tempstate = SHOTTY_RELOAD_END;
w_shotgun_release(pl);
return;
} else if (pl.mode_tempstate > SHOTTY_IDLE) {
w_shotgun_release(pl);
return;
}
/* Ammo check */
if (pl.shotgun_mag <= 1) {
w_shotgun_reload(pl);
return;
}
Weapons_ViewAnimation(pl, SHOTGUN_ALTFIRE);
Weapons_ViewPunchAngle(pl, [-10,0,0]);
if (pl.flags & FL_CROUCHING)
Animation_PlayerTop(pl, ANIM_CR_SHOOTSHOTGUN, 0.41f);
else
Animation_PlayerTop(pl, ANIM_SHOOTSHOTGUN, 0.5f);
#ifdef SERVER
/* Singleplayer is more accurate */
if (serverkeyfloat("sv_playerslots") == 1) {
TraceAttack_FireBullets(12, pl.origin + pl.view_ofs, 5, [0.08716,0.08716], WEAPON_SHOTGUN);
} else {
TraceAttack_FireBullets(8, pl.origin + pl.view_ofs, 5, [0.17365,0.04362], WEAPON_SHOTGUN);
}
Sound_Play(pl, CHAN_WEAPON, "Weapon_Shotgun.Double");
#else
View_SetMuzzleflash(MUZZLE_WEIRD);
View_AddEvent(w_shotgun_ejectshell, 1.0f);
#endif
/* after 1 second, play the cocksound and eject shell */
pl.mode_tempstate = SHOTTY_RELOAD_END;
pl.shotgun_mag -= 2;
pl.w_attack_next = 0.5f;
pl.w_idle_next = 0.5f;
}
void
w_shotgun_release(player pl)
{
/* auto-reload if need be */
if (pl.w_attack_next <= 0.0)
if (pl.mode_tempstate == SHOTTY_IDLE && pl.shotgun_mag == 0 && pl.ammo_buckshot > 0) {
Weapons_Reload(pl);
return;
}
if (pl.w_idle_next > 0.0) {
return;
}
if (pl.mode_tempstate == SHOTTY_IDLE) {
Weapons_ViewAnimation(pl, SHOTGUN_IDLE);
pl.w_idle_next = 5.00f;
} else if (pl.mode_tempstate == SHOTTY_RELOAD_START) {
Weapons_ViewAnimation(pl, SHOTGUN_START_RELOAD);
pl.mode_tempstate = SHOTTY_RELOAD;
pl.w_idle_next = 0.5f;
} else if (pl.mode_tempstate == SHOTTY_RELOAD) {
Weapons_ViewAnimation(pl, SHOTGUN_INSERT_SHELL);
pl.shotgun_mag++;
pl.ammo_buckshot--;
#ifdef SERVER
Sound_Play(pl, CHAN_WEAPON, "Weapon_Shotgun.Reload");
#endif
if (pl.ammo_buckshot <= 0 || pl.shotgun_mag >= 8) {
pl.mode_tempstate = SHOTTY_MOVEDOWN;
}
Weapons_UpdateAmmo(pl, pl.shotgun_mag, pl.ammo_buckshot, pl.mode_tempstate);
pl.w_idle_next = 0.4f;
} else if (pl.mode_tempstate == SHOTTY_MOVEDOWN) {
Weapons_ViewAnimation(pl, SHOTGUN_END_RELOAD);
pl.mode_tempstate = SHOTTY_RELOAD_END;
pl.w_idle_next = 0.4f;
pl.w_attack_next = 0.4f;
} else if (pl.mode_tempstate == SHOTTY_RELOAD_END) {
Weapons_ViewAnimation(pl, SHOTGUN_PUMP);
#ifdef SERVER
Sound_Play(pl, CHAN_AUTO, "Weapon_Shotgun.Special1");
#endif
pl.mode_tempstate = SHOTTY_IDLE;
pl.w_idle_next = 0.5f;
pl.w_attack_next = 0.5f;
} else if (pl.mode_tempstate == SHOTTY_COCKSOUND) {
#ifdef CLIENT
#else
//Sound_Play(pl, CHAN_WEAPON, "Weapon_Shotgun.Special1");
#endif
pl.mode_tempstate = SHOTTY_IDLE;
pl.w_idle_next = 0.55f;
pl.w_attack_next = 0.55f;
}
}
void
w_shotgun_crosshair(player pl)
{
#ifdef CLIENT
vector pos = g_hudmins + [g_hudres[0] / 2, g_hudres[1] / 2];
Font_DrawText_RGBA(pos + [-7, -14], "Q", g_hud_color, 1.0, FONT_HUD_CROSS);
HUD_DrawAmmo1();
HUD_DrawAmmo2();
#endif
}
float
w_shotgun_aimanim(player pl)
{
return pl.flags & FL_CROUCHING ? ANIM_CR_AIMSHOTGUN : ANIM_AIMSHOTGUN;
}
void
w_shotgun_hudpic(player pl, int selected, vector pos, float a)
{
#ifdef CLIENT
vector hud_col;
if (pl.shotgun_mag == 0 && pl.ammo_buckshot == 0)
hud_col = [1,0,0];
else
hud_col = g_hud_color;
if (selected) {
drawsubpic(
pos,
[128,64],
"materials/Sprites/w_icons2",
[0, 0.5],
[128/256,64/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[128,64],
"materials/Sprites/w_icons2",
[0, 0.5],
[128/256,64/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
}
HUD_DrawAmmoBar(pos, pl.ammo_buckshot, MAX_A_BUCKSHOT, a);
#endif
}
int
w_shotgun_isempty(player pl)
{
if (pl.shotgun_mag <= 0 && pl.ammo_buckshot <= 0)
return 1;
return 0;
}
weapontype_t
w_shotgun_type(player pl)
{
return WPNTYPE_RANGED;
}
weapon_t w_shotgun =
{
.name = "shotgun",
.id = ITEM_SHOTGUN,
.slot = 3,
.slot_pos = 0,
.weight = 15,
.draw = w_shotgun_draw,
.holster = w_shotgun_holster,
.primary = w_shotgun_primary,
.secondary = w_shotgun_secondary,
.reload = w_shotgun_reload,
.release = w_shotgun_release,
.postdraw = w_shotgun_crosshair,
.precache = w_shotgun_precache,
.pickup = w_shotgun_pickup,
.updateammo = w_shotgun_updateammo,
.wmodel = w_shotgun_wmodel,
.pmodel = w_shotgun_pmodel,
.deathmsg = w_shotgun_deathmsg,
.aimanim = w_shotgun_aimanim,
.isempty = w_shotgun_isempty,
.type = w_shotgun_type,
.hudpic = w_shotgun_hudpic
};

388
src/shared/w_smg1.qc Normal file
View file

@ -0,0 +1,388 @@
/*
* Copyright (c) 2016-2021 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
enum
{
SMG1_IDLE,
SMG1_FIRE1,
SMG1_FIRE2,
SMG1_FIRE3,
SMG1_FIRE4,
SMG1_ALTFIRE,
SMG1_DRAW,
SMG1_RELOAD,
SMG1_DRYFIRE,
SMG1_IDLE_TO_LOW,
SMG1_LOW_TO_IDLE,
SMG1_LOW
};
#ifdef CLIENT
void w_smg1_ejectshell(void)
{
static void w_smg1_ejectshell_death(void) {
remove(self);
}
static void w_smg1_ejectshell_touch(void) {
if (other == world)
Sound_Play(self, CHAN_BODY, "Bounce.Shell");
}
entity eShell = spawn();
setmodel(eShell, "models/weapons/rifleshell.mdl");
eShell.solid = SOLID_BBOX;
eShell.movetype = MOVETYPE_BOUNCE;
eShell.drawmask = MASK_ENGINE;
eShell.angles = [pSeat->m_eViewModel.angles[0], pSeat->m_eViewModel.angles[1], 0];
eShell.velocity = pSeat->m_vecPredictedVelocity;
float r = random(0.0, 50.0);
makevectors(pSeat->m_eViewModel.angles);
eShell.velocity += (v_forward * 0);
eShell.velocity += (v_right * 45);
eShell.velocity += (v_up * (145 + r));
eShell.touch = w_smg1_ejectshell_touch;
eShell.avelocity = [0,45,900];
eShell.think = w_smg1_ejectshell_death;
eShell.nextthink = time + 2.5f;
setsize(eShell, [0,0,0], [0,0,0]);
setorigin(eShell, pSeat->m_eViewModel.origin + (v_forward * 30) + (v_right * 8) + (v_up * -15));
}
#endif
void
w_smg1_precache(void)
{
#ifdef SERVER
precache_model("models/w_9mmar.mdl");
precache_model("models/grenade.mdl");
#else
precache_model("models/weapons/v_smg1.mdl");
precache_model("models/p_9mmar.mdl");
#endif
}
int
w_smg1_pickup(player pl, int new, int startammo)
{
#ifdef SERVER
#ifdef GEARBOX
int addAmmo = (startammo == -1) ? 50 : startammo;
#else
int addAmmo = (startammo == -1) ? 25 : startammo;
#endif
if (new) {
pl.mp5_mag = addAmmo;
return (1);
}
if (pl.ammo_9mm < MAX_A_9MM) {
pl.ammo_9mm = bound(0, pl.ammo_9mm + addAmmo, MAX_A_9MM);
} else {
if (!new)
return (0);
}
#endif
return (1);
}
void
w_smg1_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, pl.mp5_mag, pl.ammo_9mm, pl.ammo_m203_grenade);
}
string
w_smg1_wmodel(void)
{
return "models/w_9mmar.mdl";
}
string
w_smg1_pmodel(player pl)
{
return "models/p_9mmar.mdl";
}
string
w_smg1_deathmsg(void)
{
return "";
}
void
w_smg1_draw(player pl)
{
Weapons_SetModel("models/weapons/v_smg1.mdl");
Weapons_ViewAnimation(pl, SMG1_DRAW);
pl.w_idle_next = 0.8f;
}
void
w_smg1_holster(player pl)
{
Weapons_ViewAnimation(pl, SMG1_LOW);
}
void
w_smg1_primary(player pl)
{
if (pl.w_attack_next > 0.0f)
return;
if (pl.gflags & GF_SEMI_TOGGLED)
return;
/* Ammo check */
bool out_of_ammo = (pl.mp5_mag <= 0i) ? true : false;
if (out_of_ammo || (pl.WaterLevel() >= WATERLEVEL_SUBMERGED)) {
#ifdef SERVER
Sound_Play(pl, CHAN_AUTO, "Weapon_SMG1.Empty");
#endif
pl.gflags |= GF_SEMI_TOGGLED;
return;
}
pl.mp5_mag--;
/* Actual firing */
int r = floor(pseudorandom() * 4.0f);
switch (r) {
case 1:
Weapons_ViewAnimation(pl, SMG1_FIRE1);
break;
case 2:
Weapons_ViewAnimation(pl, SMG1_FIRE2);
break;
case 3:
Weapons_ViewAnimation(pl, SMG1_FIRE2);
break;
default:
Weapons_ViewAnimation(pl, SMG1_FIRE3);
break;
}
Weapons_ViewPunchAngle(pl, [-2,0,0]);
#ifdef CLIENT
View_SetMuzzleflash(MUZZLE_RIFLE);
View_AddEvent(w_smg1_ejectshell, 0.0f);
#else
/* singleplayer is more accurate */
if (cvar("sv_playerslots") == 1) {
TraceAttack_FireBullets(1, Weapons_GetCameraPos(pl), Skill_GetValue("plr_9mmAR_bullet", 5), [0.025,0.025], WEAPON_SMG1);
} else {
TraceAttack_FireBullets(1, Weapons_GetCameraPos(pl), Skill_GetValue("plr_9mmAR_bullet", 5), [0.05,0.05], WEAPON_SMG1);
}
Sound_Play(pl, CHAN_WEAPON, "Weapon_SMG1.Single");
#endif
if (pl.flags & FL_CROUCHING)
Animation_PlayerTop(pl, ANIM_CR_SHOOTMP5, 0.1f);
else
Animation_PlayerTop(pl, ANIM_SHOOTMP5, 0.1f);
pl.w_attack_next = 0.085f;
pl.w_idle_next = 0.233f;
}
void
w_smg1_secondary(player pl)
{
if (pl.w_attack_next > 0.0f)
return;
if (pl.gflags & GF_SEMI_TOGGLED)
return;
/* Ammo check */
bool out_of_ammo = (pl.ammo_m203_grenade <= 0i) ? true : false;
if (out_of_ammo || pl.WaterLevel() >= WATERLEVEL_SUBMERGED) {
#ifdef SERVER
Sound_Play(pl, CHAN_AUTO, "Weapon_SMG1.Empty");
#endif
pl.gflags |= GF_SEMI_TOGGLED;
return;
}
pl.ammo_m203_grenade--;
#ifdef SERVER
NSProjectile_SpawnDef("projectile_ARgrenade", pl);
Sound_Play(pl, CHAN_WEAPON, "Weapon_SMG1.Double");
#endif
Weapons_ViewPunchAngle(pl, [-10.0f, 0.0f, 0.0f]);
Weapons_ViewAnimation(pl, SMG1_ALTFIRE);
if (pl.flags & FL_CROUCHING)
Animation_PlayerTop(pl, ANIM_CR_SHOOTMP5, 0.45f);
else
Animation_PlayerTop(pl, ANIM_SHOOTMP5, 0.45f);
pl.w_attack_next = 0.5f;
pl.w_idle_next = 0.5f;
}
void
w_smg1_reload(player pl)
{
if (pl.w_attack_next) {
return;
}
/* Ammo check */
if (pl.mp5_mag >= 50) {
return;
}
if (pl.ammo_9mm <= 0) {
return;
}
Weapons_ViewAnimation(pl, SMG1_RELOAD);
#ifdef SERVER
static void w_smg1_reload_done(void) {
player pl = (player)self;
Weapons_ReloadWeapon(pl, player::mp5_mag, player::ammo_9mm, 50);
}
pl.think = w_smg1_reload_done;
pl.nextthink = time + 1.4f;
#endif
pl.w_attack_next = 1.5f;
pl.w_idle_next = 1.5f;
}
void
w_smg1_release(player pl)
{
/* auto-reload if need be */
if (pl.w_attack_next <= 0.0)
if (pl.mp5_mag == 0 && pl.ammo_9mm > 0) {
Weapons_Reload(pl);
return;
}
if (pl.w_idle_next > 0.0) {
return;
}
Weapons_ViewAnimation(pl, SMG1_IDLE);
pl.w_idle_next = 15.0f;
}
void
w_smg1_crosshair(player pl)
{
#ifdef CLIENT
vector pos = g_hudmins + [g_hudres[0] / 2, g_hudres[1] / 2];
Font_DrawText_RGBA(pos + [-7, -14], "Q", g_hud_color, 1.0, FONT_HUD_CROSS);
HUD_DrawAmmo1();
HUD_DrawAmmo2();
HUD_DrawAmmo3();
#endif
}
float
w_smg1_aimanim(player pl)
{
return pl.flags & ANIM_CR_AIMMP5 ? ANIM_CR_AIMCROWBAR : ANIM_AIMMP5;
}
void
w_smg1_hudpic(player pl, int selected, vector pos, float a)
{
#ifdef CLIENT
vector hud_col;
if (pl.mp5_mag == 0 && pl.ammo_9mm == 0 && pl.ammo_m203_grenade == 0)
hud_col = [1,0,0];
else
hud_col = g_hud_color;
if (selected) {
drawsubpic(
pos,
[128,64],
"materials/Sprites/w_icons1",
[0.5, 0.5],
[128/256,64/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[128,64],
"materials/Sprites/w_icons1",
[0.5, 0.5],
[128/256,64/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
}
HUD_DrawAmmoBar(pos, pl.ammo_9mm, MAX_A_9MM, a);
HUD_DrawAmmoBar(pos + [25, 0], pl.ammo_m203_grenade, MAX_A_M203_GRENADE, a);
#endif
}
int
w_smg1_isempty(player pl)
{
if (pl.mp5_mag <= 0 && pl.ammo_9mm <= 0 && pl.ammo_m203_grenade <= 0)
return 1;
return 0;
}
weapontype_t
w_smg1_type(player pl)
{
return WPNTYPE_RANGED;
}
weapon_t w_smg1 =
{
.name = "9mmAR",
.id = ITEM_MP5,
.slot = 2,
.slot_pos = 0,
.weight = 15,
.draw = w_smg1_draw,
.holster = w_smg1_holster,
.primary = w_smg1_primary,
.secondary = w_smg1_secondary,
.reload = w_smg1_reload,
.release = w_smg1_release,
.postdraw = w_smg1_crosshair,
.precache = w_smg1_precache,
.pickup = w_smg1_pickup,
.updateammo = w_smg1_updateammo,
.wmodel = w_smg1_wmodel,
.pmodel = w_smg1_pmodel,
.deathmsg = w_smg1_deathmsg,
.aimanim = w_smg1_aimanim,
.isempty = w_smg1_isempty,
.type = w_smg1_type,
.hudpic = w_smg1_hudpic
};

52
src/shared/weapons.h Normal file
View file

@ -0,0 +1,52 @@
/*
* Copyright (c) 2016-2021 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* Weapon Indices for the weapon table */
enum
{
WEAPON_NONE,
WEAPON_CROWBAR,
WEAPON_GRAVITYGUN,
WEAPON_PISTOL,
WEAPON_357,
WEAPON_SMG1,
WEAPON_AR2,
WEAPON_SHOTGUN,
WEAPON_CROSSBOW,
WEAPON_FRAG,
WEAPON_RPG,
WEAPON_BUGBAIT
};
#define MAX_A_9MM 250
#define MAX_A_357 36
#define MAX_A_BUCKSHOT 125
#define MAX_A_M203_GRENADE 10
#define MAX_A_BOLT 50
#define MAX_A_ROCKET 5
#define MAX_A_URANIUM 100
#define MAX_A_HANDGRENADE 10
#define MAX_A_SATCHEL 5
#define MAX_A_TRIPMINE 10
#define MAX_A_SNARK 10
#define MAX_A_HORNET 8
/* gearbox */
#define MAX_A_556 200
#define MAX_A_PENGUIN 9
#define MAX_A_SHOCK 10
#define MAX_A_762 15
#define MAX_A_SPORE 20

31
src/shared/weapons.qc Normal file
View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2016-2020 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
weapon_t w_null = {};
weapon_t g_weapons[] = {
w_null,
w_crowbar,
w_gravitygun,
w_pistol,
w_357,
w_smg1,
w_ar2,
w_shotgun,
w_crossbow,
w_frag,
w_rpg,
w_bugbait,
};