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,
};

View file

@ -0,0 +1,33 @@
entityDef projectile_ARgrenade
{
"spawnclass" "NSProjectile"
"model" "models/weapons/ar2_grenade.mdl"
"offset" "16 0 0"
"velocity" "800 0 0"
"angular_velocity" "-300 0 0"
"gravity" "0.5"
"bounce" "1"
"mins" "0 0 0"
"maxs" "0 0 0"
"detonate_on_fuse" "0"
"detonate_on_death" "1"
"detonate_on_world" "1"
"detonate_on_actor" "1"
"snd_explode" "BaseExplosionEffect.Sound"
"model_detonate" "fx_explosion.main"
"def_damage" "damage_ARgrneadeDirect"
"def_splash_damage" "damage_ARgrneadeSplash"
}
entityDef damage_ARgrneadeDirect
{
"damage" "50"
}
entityDef damage_ARgrneadeSplash
{
"damage" "skill:plr_9mmAR_grenade"
"radius" "160"
}

View file

@ -0,0 +1,27 @@
entityDef projectile_frag
{
"spawnclass" "NSProjectile"
"model" "models/weapons/w_grenade.mdl"
"frame" "1"
"fuse" "4"
"detonate_on_fuse" "1"
"bounce" "1"
"angular_velocity" "-350 0 0"
"model_detonate" "fx_explosion.main"
"snd_explode" "fx.explosion"
"snd_bounce" "weapon_handgrenade.bounce"
"def_damage" "damage_handgrenadeDirect"
"def_splash_damage" "damage_handgrenadeSplash"
}
entityDef damage_handgrenadeDirect
{
"damage" "1"
}
entityDef damage_handgrenadeSplash
{
"damage" "skill:plr_hand_grenade"
"radius" "250"
}

View file

@ -0,0 +1,53 @@
entityDef projectile_rocket
{
"spawnclass" "NSProjectile"
"model" "models/weapons/w_missile.mdl"
"def_damage" "damage_rocketDirect"
"def_splash_damage" "damage_rocketSplash"
"health" "0"
"velocity" "250"
"angular_velocity" "0 0 200"
"fuse" "10"
"detonate_on_fuse" "0"
"detonate_on_death" "1"
"detonate_on_world" "1"
"detonate_on_actor" "1"
"impact_damage_effect" "1"
"impact_gib" "1"
"thrust" "2000"
"thrust_start" "0.1"
"thrust_end" "2"
"smoke_fly" "weapon_rpg.trail"
"model_detonate" "fx_explosion.main"
"light_color" "1 0.8 0.4"
"light_radius" "160"
"light_offset" "0 0 0"
"explode_light_color" "2 1.6 0.8"
"explode_light_radius" "320"
"explode_light_fadetime" "0.5"
"snd_explode" "fx.explosion"
}
entityDef projectile_rocket_homing
{
"inherit" "projectile_rocket"
"thrust_homing" "1"
}
entityDef damage_rocketDirect
{
"damage" "skill:plr_rocketlauncher_impact"
"damage_random" "skill:plr_rocketlauncher_impact_rand"
}
entityDef damage_rocketSplash
{
"damage" "skill:plr_rpg"
"radius" "250"
}

View file

@ -0,0 +1,66 @@
// Generic Binds
bind "ESC" "togglemenu"
bind "w" "+forward"
bind "s" "+back"
bind "a" "+moveleft"
bind "d" "+moveright"
bind "SPACE" "+jump"
bind "CTRL" "+duck"
bind "SHIFT" "+speed"
bind "0" "slot10"
bind "1" "slot1"
bind "2" "slot2"
bind "3" "slot3"
bind "4" "slot4"
bind "5" "slot5"
bind "6" "slot6"
bind "7" "slot7"
bind "8" "slot8"
bind "9" "slot9"
bind "UPARROW" "+forward"
bind "DOWNARROW" "+back"
bind "LEFTARROW" "+left"
bind "RIGHTARROW" "+right"
bind "MOUSE1" "+attack"
bind "MOUSE2" "+attack2"
bind "MWHEELDOWN" "invnext"
bind "MWHEELUP" "invprev"
bind "r" "+reload"
bind "e" "+use"
bind "TAB" "+showscores"
bind "y" "messagemode"
bind "u" "messagemode2"
bind "t" "impulse 201"
bind "f" "impulse 100"
bind "f1" "vote yes"
bind "f2" "vote no"
// Game Variables
seta "hostname" "FreeHL2 Server"
seta "maxplayers" "8"
// 2D/HUD Variables
seta "con_color" "255 150 0"
seta "vgui_color" "255 170 0"
seta "cross_color" "0 255 0"
// disable some nuclide niceties
seta cg_muzzleDLight 01
// config compat
alias mp_timelimit timelimit
alias mp_fraglimit fraglimit
// video settings
seta gl_overbright 2
seta gl_ldr 0
seta r_lightmap_format rgb9e5
seta rate 30000 // some HL configs set this to 2500 by default!
exec skill_hl2.cfg
seta cl_forwardspeed 190
seta cl_sidespeed 190
seta cl_backspeed 190
seta cl_movespeedkey 1.684
seta pm_maxspeed 320

View file

@ -0,0 +1,3 @@
path "resource/HALFLIFE2.ttf"
size_x "32"
size_y "32"

View file

@ -0,0 +1,46 @@
// Copyright (c) 2000-2019, Vera Visions. All rights reserved.
r_part default
{
texture "textures/particles/smoke"
tcoords 0 0 0.125 1 1 8 0.125
count 1
scale 32
die 1
rgb 25 25 25
spawnmode ball
blend add
veladd 64
randomvel 8 8 8
spawnorg 0.25
scalefactor 5
}
r_part +default
{
type cdecal
texture "textures/decals/impact_default"
tcoords 0 0 0.125 1 1 8 0.125
rgbf 1 1 1
scale 12 12
die 30 60
orgwrand 6 6 6
rotationstart -180 180
}
r_part +default
{
type normal
blend add
texture "textures/particles/smoke"
tcoords 0 0 0.125 1 1 8 0.125
rgbf 0 0 0
alpha 1
scale 8
scalefactor 1
scaledelta 128
cliptype bounce
die 2
veladd 25
orgwrand 6 6 6
randomvel 0 -8 8
rotationstart -180 180
}

View file

@ -0,0 +1,97 @@
r_part main
{
texture "particles/fteparticlefont.tga"
tcoords 97 97 191 191 256
count 1
scale 200
scalefactor 1
die 1
rgb 255 128 76
rgbdelta 0 -32 -32
friction 1
blend add
}
r_part +ember
{
count 1
texture "particles/fteparticlefont.tga"
tcoords 97 97 191 191 256
rgb 255 128 76
alpha 0
scale 20
scalefactor 1
die 1
friction 2.5
blend add
randomvel 15
veladd 2
rampmode delta
ramp 0 0 0 -0.5 0
ramp 0 0 0 0.1 0
ramp 0 0 0 0.1 0
ramp 0 0 0 0.1 0
ramp 0 0 0 0.1 0
ramp 0 0 0 0.1 0
}
r_part +main
{
lighttime 1
lightradius 350
lightradiusfade 300
lightrgb 1.0 0.5 0.4
lightrgbfade 0.36 0.19 0.19
count 0 0 1
model "sprites/fexplo.spr" framestart=0 framecount=29 framerate=20 additive
}
r_part +main
{
cliptype expgib
texture "particles/fteparticlefont.tga"
tcoords 97 97 191 191 256
alpha 0
count 16
die 1
randomvel 128
gravity 50
friction 2
emit ember
emitinterval 0.01
spawnmode circle
}
r_part +main
{
texture "particles/fteparticlefont.tga"
tcoords 97 97 191 191 256
count 1
scale 324
scalefactor 1
die 3
alpha 1
rgb 0 0 0
spawnmode ball
gravity -25
}
r_part +main
{
type texturedspark
texture ball
tcoords 1 65 31 95 256 8 32
scale 1
count 8
scalefactor 1
alpha 0.5
die 0.8
rgb 255 115 0
blend add
spawnmode ball
spawnvel 100
veladd 100
friction 0.5
gravity 800
}