Initial commit.

This commit is contained in:
Marco Cawthorne 2023-04-15 13:07:45 -07:00
commit 6074c787b5
Signed by: eukara
GPG Key ID: CE2032F0A2882A22
33 changed files with 4882 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

83
src/client/defs.h Normal file
View File

@ -0,0 +1,83 @@
/*
* 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/client/obituary.h"
#include "../../../valve/src/client/particles.h"
var int autocvar_cl_autoweaponswitch = TRUE;
vector g_hud_color;
vector g_hudmins;
vector g_hudres;
var string g_hud1_spr;
var string g_hud2_spr;
var string g_hud3_spr;
var string g_hud4_spr;
var string g_hud5_spr;
var string g_hud6_spr;
var string g_hud7_spr;
var string g_hudcb_spr;
var string g_hudsg_spr;
var string g_hudssg_spr;
var string g_hudng_spr;
var string g_hudsng_spr;
var string g_hudgl_spr;
var string g_hudrl_spr;
var string g_hudlg_spr;
var string g_cross_spr;
var string g_laser_spr;
var string g_hudglammo;
var string g_hudlgammo;
var string g_hudngammo;
var string g_hudrlammo;
var string g_hudsgammo;
var string g_hudsngammo;
var string g_hudssgammo;
/* muzzleflash indices */
var int MUZZLE_SMALL;
var int MUZZLE_RIFLE;
var int MUZZLE_WEIRD;
struct
{
/* hud.c */
int m_iHealthOld;
float m_flHealthAlpha;
int m_iArmorOld;
float m_flArmorAlpha;
int m_iAmmo1Old;
float m_flAmmo1Alpha;
int m_iAmmo2Old;
float m_flAmmo2Alpha;
int m_iAmmo3Old;
float m_flAmmo3Alpha;
int m_iPickupWeapon;
float m_flPickupAlpha;
int m_iHUDWeaponSelected;
float m_flHUDWeaponSelectTime;
int m_iItemsOld;
float m_flDamageIndicator;
} g_seatslocal[4], *pSeatLocal;
void HUD_DrawAmmo1(void);
void HUD_DrawAmmo2(void);
void HUD_DrawAmmo3(void);
void HUD_DrawAmmoBar(vector pos, float val, float max, float a);
void HUD_WeaponPickupNotify(int);

26
src/client/entities.qc Normal file
View File

@ -0,0 +1,26 @@
/*
* 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.
*/
int
ClientGame_EntityUpdate(float id, float new)
{
switch (id) {
default:
return (0);
}
return (1);
}

523
src/client/hud.qc Normal file
View File

@ -0,0 +1,523 @@
/*
* 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 24/256
#define NUMSIZE_Y 24/128
#define HUD_ALPHA 0.5
float spr_hudnum[10] = {
0 / 256,
24 / 256,
(24*2) / 256,
(24*3) / 256,
(24*4) / 256,
(24*5) / 256,
(24*6) / 256,
(24*7) / 256,
(24*8) / 256,
(24*9) / 256
};
/* pre-calculated sprite definitions */
float spr_health[4] = {
80 / 256, // pos x
24 / 128, // pos u
32 / 256, // size x
32 / 128 // size y
};
float spr_suit1[4] = {
0 / 256, // pos x
24 / 128, // pos u
40 / 256, // size x
40 / 128 // size y
};
float spr_suit2[4] = {
40 / 256, // pos x
24 / 128, // pos u
40 / 256, // size x
40 / 128 // 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)
{
g_cross_spr = spriteframe("sprites/crosshairs.spr", 0, 0.0f);
g_laser_spr = spriteframe("sprites/laserdot.spr", 0, 0.0f);
g_hud1_spr = spriteframe("sprites/640hud1.spr", 0, 0.0f);
g_hud2_spr = spriteframe("sprites/640hud2.spr", 0, 0.0f);
g_hud3_spr = spriteframe("sprites/640hud3.spr", 0, 0.0f);
g_hud4_spr = spriteframe("sprites/640hud4.spr", 0, 0.0f);
g_hud5_spr = spriteframe("sprites/640hud5.spr", 0, 0.0f);
g_hud6_spr = spriteframe("sprites/640hud6.spr", 0, 0.0f);
g_hud7_spr = spriteframe("sprites/640hud7.spr", 0, 0.0f);
g_hudcb_spr = spriteframe("sprites/hudcb.spr", 0, 0.0f);
g_hudsg_spr = spriteframe("sprites/hudsg.spr", 0, 0.0f);
g_hudssg_spr = spriteframe("sprites/hudssg.spr", 0, 0.0f);
g_hudng_spr = spriteframe("sprites/hudng.spr", 0, 0.0f);
g_hudsng_spr = spriteframe("sprites/hudsng.spr", 0, 0.0f);
g_hudgl_spr = spriteframe("sprites/hudgl.spr", 0, 0.0f);
g_hudrl_spr = spriteframe("sprites/hudrl.spr", 0, 0.0f);
g_hudlg_spr = spriteframe("sprites/hudlg.spr", 0, 0.0f);
g_hudglammo = spriteframe("sprites/hudglammo.spr", 0, 0.0f);
g_hudlgammo = spriteframe("sprites/hudlgammo.spr", 0, 0.0f);
g_hudngammo = spriteframe("sprites/hudngammo.spr", 0, 0.0f);
g_hudrlammo = spriteframe("sprites/hudrlammo.spr", 0, 0.0f);
g_hudsgammo = spriteframe("sprites/hudsgammo.spr", 0, 0.0f);
g_hudsngammo = spriteframe("sprites/hudsngammo.spr", 0, 0.0f);
g_hudssgammo = spriteframe("sprites/hudssgammo.spr", 0, 0.0f);
HUD_AmmoNotify_Init();
HUD_DamageNotify_Init();
HUD_ItemNotify_Init();
}
/* seperator for mainly ammo */
void
HUD_DrawSeperator(vector pos)
{
drawsubpic(pos,
[2,24],
g_hud7_spr,
[240/256, 0],
[2/256, 24/128],
g_hud_color,
HUD_ALPHA,
DRAWFLAG_ADDITIVE
);
}
/* handle single/multiple digits */
void
HUD_DrawNumber(int iNumber, vector vecPos, float fAlpha, vector vColor)
{
drawsubpic(vecPos,
[24,24],
g_hud7_spr,
[spr_hudnum[iNumber], 0],
[NUMSIZE_X, NUMSIZE_Y],
vColor,
fAlpha,
DRAWFLAG_ADDITIVE
);
}
void
HUD_DrawNums(float fNumber, vector vecPos, float fAlpha, vector vColor)
{
int i = fNumber;
if (i > 0) {
while (i > 0) {
HUD_DrawNumber((float)i % 10.0f, vecPos, fAlpha, vColor);
i = i / 10;
vecPos[0] -= 20;
}
} else {
HUD_DrawNumber(0, vecPos, fAlpha, vColor);
}
}
/* 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 + [88, g_hudres[1] - 42];
if (pl.health > 25) {
drawsubpic(
pos + [-72,-4],
[32,32],
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, pSeatLocal->m_flHealthAlpha, g_hud_color);
} else {
drawsubpic(
pos + [-72,-4],
[32,32],
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, 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;
pos = g_hudmins + [198, g_hudres[1] - 42];
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;
}
drawsubpic(
pos + [-80,-9],
[40,40],
g_hud7_spr,
[spr_suit2[0], spr_suit2[1]],
[spr_suit2[2], spr_suit2[3]],
g_hud_color,
pSeatLocal->m_flArmorAlpha,
DRAWFLAG_ADDITIVE
);
if (pl.armor > 0) {
float perc = bound(0, (pl.armor / 100), 1.0);
drawsubpic(
pos + [-80,-9] + [0, 40 * (1.0-perc)],
[40, 40 * perc],
g_hud7_spr,
[spr_suit1[0],spr_suit1[1] + spr_suit1[3] * (1.0-perc)],
[spr_suit1[2], spr_suit1[3] * perc],
g_hud_color,
pSeatLocal->m_flArmorAlpha,
DRAWFLAG_ADDITIVE
);
}
HUD_DrawNums(pl.armor, pos, pSeatLocal->m_flArmorAlpha, g_hud_color);
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];
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] - 72, g_hudres[1] - 42];
HUD_DrawNums(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] - 72, g_hudres[1] - 74];
HUD_DrawNums(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);
}
/* flashlight/torch indicator */
void
HUD_DrawFlashlight(void)
{
vector pos;
player pl = (player)pSeat->m_ePlayer;
pos = g_hudmins + [g_hudres[0] - 48, 16];
/* both on, draw both sprites at full intensity */
if (pl.gflags & GF_FLASHLIGHT) {
drawsubpic(
pos,
[32,32],
g_hud7_spr,
[spr_flash1[0], spr_flash1[1]],
[spr_flash1[2], spr_flash1[3]],
g_hud_color,
1.0f,
DRAWFLAG_ADDITIVE
);
drawsubpic(
pos,
[48,32],
g_hud7_spr,
[spr_flash2[0], spr_flash2[1]],
[spr_flash2[2], spr_flash2[3]],
g_hud_color,
1.0f,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[32,32],
g_hud7_spr,
[spr_flash1[0], spr_flash1[1]],
[spr_flash1[2], spr_flash1[3]],
g_hud_color,
HUD_ALPHA,
DRAWFLAG_ADDITIVE
);
}
}
/* logo animation used during e3 1998 */
void
HUD_DrawLogo(void)
{
vector pos;
static int f;
static float frame_timer;
frame_timer -= clframetime;
pos = [g_hudres[0] - 262, 48];
drawpic(
pos,
sprintf("sprites/640_logo.spr_%i.tga", f),
[256,48],
[1,1,1],
1.0f,
DRAWFLAG_ADDITIVE
);
if (frame_timer > 0) {
return;
}
frame_timer = 0.1f;
f++;
if (f == 31) {
f = 0;
}
}
/* weapon/ammo pickup notifications */
void
HUD_DrawNotify(void)
{
player pl = (player)self;
vector pos;
float a;
pos = g_hudmins + [g_hudres[0] - 192, 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)
{
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;
}
/* main entry */
void
HUD_Draw(void)
{
player pl = (player)pSeat->m_ePlayer;
#ifndef TFC
g_hud_color = autocvar_con_color * (1 / 255);
#endif
/* 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();
if (!(pl.g_items & ITEM_SUIT)) {
return;
}
HUD_DamageNotify_Draw();
HUD_DrawHealth();
HUD_DrawArmor();
HUD_DrawFlashlight();
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,92 @@
#ifndef GEARBOX
#define AMMO_COUNT 12
#else
#define AMMO_COUNT 17
#endif
string g_ammo_spr;
typedef struct
{
float alpha;
int count;
} ammonote_t;
ammonote_t g_ammonotify[AMMO_COUNT];
vector g_ammotype[AMMO_COUNT] = {
[0/256, 72/128], // pistol
[72/256, 72/128], // shell
[120/256, 72/128], // rocket
[0/256, 96/128], // uranium
};
void
HUD_AmmoNotify_Init(void)
{
g_ammo_spr = spriteframe("sprites/640hud7.spr", 0, 0.0f);
}
void
HUD_AmmoNotify_Draw(__inout vector pos)
{
pos[0] = g_hudmins[0] + g_hudres[0] - 40;
for (int i = 0; i < AMMO_COUNT; i++) {
vector srcpos;
float a;
/* make sure we skip any faded entries, and also null them */
if (g_ammonotify[i].alpha <= 0.0f) {
g_ammonotify[i].count = 0;
continue;
}
/* let's get the src img pos for our type */
srcpos = g_ammotype[i];
a = bound(0, g_ammonotify[i].alpha, 1.0);
/* we'll use the alpha to control the offset so it gently glides down when fading out */
pos -= [0, 32 * a]; /* go up a notch */
drawsubpic(pos,
[24,24],
g_ammo_spr,
srcpos,
[24/256, 24/128],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
drawfont = Font_GetID(FONT_20);
string txt = sprintf("%i", g_ammonotify[i].count);
float offs = stringwidth(txt, FALSE, [20,20]);
drawstring(pos + [-offs - 8,4], sprintf("%i", g_ammonotify[i].count), [20,20], g_hud_color, a, DRAWFLAG_ADDITIVE);
g_ammonotify[i].alpha -= (clframetime * 0.5);
}
}
void
HUD_AmmoNotify_Insert(int type, int count)
{
if (count <= 0)
return;
if (type == 7 && count < 8) // hornet hack!
return;
g_ammonotify[type].count += count;
g_ammonotify[type].alpha = 2.5f;
}
/* called whenever we should check for pickup updates */
void
HUD_AmmoNotify_Check(player pl)
{
HUD_AmmoNotify_Insert(0, pl.ammo_shells - pl.ammo_shells_net);
HUD_AmmoNotify_Insert(1, pl.ammo_nails - pl.ammo_nails_net);
HUD_AmmoNotify_Insert(2, pl.ammo_rockets - pl.ammo_rockets_net);
HUD_AmmoNotify_Insert(3, pl.ammo_cells - pl.ammo_cells_net);
}

View File

@ -0,0 +1,258 @@
/*
* 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] =
{
[168 / 256, 72 / 128],
[188 / 256, 72 / 128],
[208 / 256, 72 / 128],
[168 / 256, 92 / 128],
[188 / 256, 92 / 128],
[208 / 256, 92 / 128],
[188 / 256, 92 / 128],
[208 / 256, 92 / 128]
};
bool
HUD_DrawWeaponSelect_CanSwitch(player pl)
{
if (!pl.activeweapon)
return false;
for (int i = 1; i < g_weapons.length; i++) {
if (pl.g_items & g_weapons[i].id && g_weapons[i].isempty(pl) == false) {
return true;
}
}
return false;
}
void
HUD_DrawWeaponSelect_Forward(void)
{
player pl = (player)pSeat->m_ePlayer;
if (HUD_DrawWeaponSelect_CanSwitch(pl) == false) {
pSeat->m_flHUDWeaponSelectTime = time + 3;
pSeat->m_iHUDWeaponSelected = 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;
if not (pl.g_items & g_weapons[pSeat->m_iHUDWeaponSelected].id)
HUD_DrawWeaponSelect_Forward();
else if (g_weapons[pSeat->m_iHUDWeaponSelected].isempty)
if (g_weapons[pSeat->m_iHUDWeaponSelected].isempty(pl))
HUD_DrawWeaponSelect_Forward();
}
void
HUD_DrawWeaponSelect_Back(void)
{
player pl = (player)pSeat->m_ePlayer;
if (HUD_DrawWeaponSelect_CanSwitch(pl) == false) {
pSeat->m_flHUDWeaponSelectTime = time + 3;
pSeat->m_iHUDWeaponSelected = 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;
if not (pl.g_items & g_weapons[pSeat->m_iHUDWeaponSelected].id)
HUD_DrawWeaponSelect_Back();
else if (g_weapons[pSeat->m_iHUDWeaponSelected].isempty)
if (g_weapons[pSeat->m_iHUDWeaponSelected].isempty(pl))
HUD_DrawWeaponSelect_Back();
}
void
HUD_DrawWeaponSelect_Trigger(void)
{
player pl = (player)pSeat->m_ePlayer;
if (pl.activeweapon != pSeat->m_iHUDWeaponSelected)
sendevent("PlayerSwitchWeapon", "i", pSeat->m_iHUDWeaponSelected);
pl.activeweapon = 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_Num(vector vecPos, float fValue)
{
drawsubpic(vecPos, [20,20], g_hud7_spr, g_vecHUDNums[fValue], [20/256, 20/128], 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 < 8; i++) {
int slot_selected = 0;
vecPos[1] = g_hudmins[1] + 16;
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);
drawsubpic(vecPos, [170,45], g_hud3_spr,
[0,180/256], [170/256,45/256], g_hud_color, 1, DRAWFLAG_ADDITIVE);
vecPos[1] += 50;
} else if ((b=HUD_InSlotPos(i, x)) != -1) {
// Unselected Sprite
Weapons_HUDPic(pl, b, 0, vecPos, 1.0f);
vecPos[1] += 50;
}
} else if (HUD_InSlotPos(i, x) != -1) {
HUD_DrawWeaponSelect_Num(vecPos, 5);
vecPos[1] += 25;
}
}
if (slot_selected == TRUE) {
vecPos[0] += 175;
} else {
vecPos[0] += 25;
}
}
}

45
src/client/progs.src Normal file
View File

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

2
src/progs.src Normal 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

238
src/server/ammo.qc Normal file
View File

@ -0,0 +1,238 @@
/*
* 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.
*/
class item_ammo:NSRenderableEntity
{
void(void) item_ammo;
virtual void(void) Spawned;
virtual void(void) Respawn;
virtual void(entity) Touch;
};
void
item_ammo::Touch(entity eToucher)
{
if not (eToucher.flags & FL_CLIENT) {
return;
}
player pl = (player)eToucher;
Sound_Play(eToucher, CHAN_ITEM, "ammo.pickup");
Weapons_RefreshAmmo(pl);
Logging_Pickup(eToucher, this, __NULL__);
if (real_owner || cvar("sv_playerslots") == 1) {
Destroy();
} else {
Disappear();
ScheduleThink(Respawn, 30.0f);
}
}
void
item_ammo::Respawn(void)
{
SetSolid(SOLID_TRIGGER);
SetMovetype(MOVETYPE_TOSS);
SetOrigin(GetSpawnOrigin());
SetModel(GetSpawnModel());
SetSize([-16,-16,0],[16,16,16]);
ReleaseThink();
if (real_owner && time > 30.0f)
Sound_Play(this, CHAN_ITEM, "ammo.respawn");
droptofloor();
}
void
item_ammo::Spawned(void)
{
super::Spawned();
Sound_Precache("ammo.pickup");
Sound_Precache("ammo.respawn");
precache_model(model);
}
void
item_ammo::item_ammo(void)
{
m_oldModel = model;
}
/*QUAKED item_shells (0 0 0.8) (-16 -16 0) (16 16 32)
HALF-LIFE (1998) ENTITY
Ammo for the .357 Magnum Revolver.
A single ammo_shells will provide 6 bullets.
-------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
model="models/w_357ammobox.mdl"
*/
class
item_shells:item_ammo
{
void(void) item_shells;
virtual void(entity) Touch;
};
void
item_shells::item_shells(void)
{
model = "models/w_shotbox_big.mdl";
}
void
item_shells::Touch(entity eToucher)
{
if not (eToucher.flags & FL_CLIENT) {
return;
}
if (eToucher.classname == "player") {
player pl = (player)eToucher;
if (pl.ammo_shells < MAX_A_SHELLS) {
pl.ammo_shells = bound(0, pl.ammo_shells + 6, MAX_A_SHELLS);
item_ammo::Touch(eToucher);
}
}
}
/*QUAKED item_spikes (0 0 0.8) (-16 -16 0) (16 16 32)
HALF-LIFE (1998) ENTITY
Ammo for the .357 Magnum Revolver.
A single ammo_nails will provide 6 bullets.
-------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
model="models/w_357ammobox.mdl"
*/
class
item_spikes:item_ammo
{
void(void) item_spikes;
virtual void(entity) Touch;
};
void
item_spikes::item_spikes(void)
{
model = "models/b_nail1.mdl";
}
void
item_spikes::Touch(entity eToucher)
{
if not (eToucher.flags & FL_CLIENT) {
return;
}
if (eToucher.classname == "player") {
player pl = (player)eToucher;
if (pl.ammo_nails < MAX_A_NAILS) {
pl.ammo_nails = bound(0, pl.ammo_nails + 6, MAX_A_NAILS);
item_ammo::Touch(eToucher);
}
}
}
/*QUAKED item_rockets (0 0 0.8) (-16 -16 0) (16 16 32)
HALF-LIFE (1998) ENTITY
Ammo for the .357 Magnum Revolver.
A single ammo_rockets will provide 6 bullets.
-------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
model="models/w_357ammobox.mdl"
*/
class item_rockets:item_ammo
{
void(void) item_rockets;
virtual void(entity) Touch;
};
void
item_rockets::item_rockets(void)
{
model = "models/w_rpgammo.mdl";
}
void
item_rockets::Touch(entity eToucher)
{
if not (eToucher.flags & FL_CLIENT) {
return;
}
if (eToucher.classname == "player") {
player pl = (player)eToucher;
if (pl.ammo_rockets < MAX_A_ROCKETS) {
pl.ammo_rockets = bound(0, pl.ammo_rockets + 6, MAX_A_ROCKETS);
item_ammo::Touch(eToucher);
}
}
}
/*QUAKED item_cells (0 0 0.8) (-16 -16 0) (16 16 32)
HALF-LIFE (1998) ENTITY
Ammo for the .357 Magnum Revolver.
A single ammo_cells will provide 6 bullets.
-------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
model="models/w_357ammobox.mdl"
*/
class item_cells:item_ammo
{
void(void) item_cells;
virtual void(entity) Touch;
};
void
item_cells::item_cells(void)
{
model = "models/w_battery.mdl";
}
void
item_cells::Touch(entity eToucher)
{
if not (eToucher.flags & FL_CLIENT) {
return;
}
if (eToucher.classname == "player") {
player pl = (player)eToucher;
if (pl.ammo_cells < MAX_A_CELLS) {
pl.ammo_cells = bound(0, pl.ammo_cells + 6, MAX_A_CELLS);
item_ammo::Touch(eToucher);
}
}
}

133
src/server/gamerules.qc Normal file
View File

@ -0,0 +1,133 @@
/*
* 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 false;
}
void
HLGameRules::LevelDecodeParms(NSClientPlayer pp)
{
player pl = (player)pp;
g_landmarkpos[0] = parm1;
g_landmarkpos[1] = parm2;
g_landmarkpos[2] = parm3;
pl.SetAngles([parm4, parm5, parm6]);
pl.SetVelocity([parm7, parm8, parm9]);
/* game specific stuff */
pl.g_items = parm10;
pl.activeweapon = parm11;
pl.flags = parm64;
pl.ammo_shells = parm12;
pl.ammo_nails = parm13;
pl.ammo_rockets = parm14;
pl.ammo_cells = parm15;
/* reset bounds */
if (pl.HasFlags(FL_CROUCHING)) {
pl.SetSize(VEC_CHULL_MIN, VEC_CHULL_MAX);
} else {
pl.SetSize(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.GetFlags();
parm10 = pl.g_items;
parm11 = pl.activeweapon;
parm12 = pl.ammo_shells;
parm13 = pl.ammo_nails;
parm14 = pl.ammo_rockets;
parm15 = pl.ammo_cells;
}
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;
}
/* 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 pl)
{
}
void
HLGameRules::PlayerConnect(NSClientPlayer pl)
{
if (Plugin_PlayerConnect(pl) == FALSE)
bprint(PRINT_HIGH, sprintf("%s connected\n", pl.netname));
}
void
HLGameRules::PlayerDisconnect(NSClientPlayer pl)
{
if (Plugin_PlayerDisconnect(pl) == FALSE)
bprint(PRINT_HIGH, sprintf("%s disconnected\n", pl.netname));
}
void
HLGameRules::PlayerKill(NSClientPlayer pl)
{
Damage_Apply(pl, pl, pl.health, WEAPON_NONE, DMG_SKIP_ARMOR);
}
void
TriggerFlashlight(NSClient target)
{
entity oldself = self;
self = target;
Flashlight_Toggle();
self = oldself;
}
bool
HLGameRules::ImpulseCommand(NSClient bp, float num)
{
switch (num) {
case 100:
TriggerFlashlight(bp);
break;
default:
return super::ImpulseCommand(bp, num);
}
return true;
}

View File

@ -0,0 +1,283 @@
/*
* 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.
*/
const string mp_teamlist_fallback = "robo;hgrunt";
var string autocvar_mp_teamlist = mp_teamlist_fallback;
bool
HLMultiplayerRules::IsMultiplayer(void)
{
return true;
}
bool
HLMultiplayerRules::PlayerRequestRespawn(NSClientPlayer bp)
{
if (bp.TimeSinceDeath() > 0.5f) {
bp.ScheduleThink(PutClientInServer, 0.0f);
return true;
}
return false;
}
bool
HLMultiplayerRules::IsTeamplay(void)
{
return cvar("mp_teamplay") == 1 ? true : false;
}
void
HLMultiplayerRules::InitPostEnts(void)
{
MOTD_LoadDefault();
if (IsTeamplay() == true) {
int c;
/* get the segments from our cvar */
m_strTeamList = autocvar_mp_teamlist;
c = tokenizebyseparator(m_strTeamList, ";");
/* if we've got less than 2 teams, use the fallback... */
if (c < 2) {
m_strTeamList = mp_teamlist_fallback;
c = tokenizebyseparator(m_strTeamList, ";");
}
forceinfokey(world, "teams", itos(c));
/* initialize all dem teams */
for (int i = 0; i < c; i++) {
forceinfokey(world, sprintf("team_%i", i+1i), argv(i));
forceinfokey(world, sprintf("teamscore_%i", i+1i), "0");
}
} else {
forceinfokey(world, "teams", "0");
}
}
void
HLMultiplayerRules::FrameStart(void)
{
if (cvar("timelimit"))
if (time >= (cvar("timelimit") * 60)) {
IntermissionStart();
}
IntermissionCycle();
}
void
HLMultiplayerRules::CheckRules(void)
{
/* last person who killed somebody has hit the limit */
if (cvar("fraglimit"))
if (g_dmg_eAttacker.frags >= cvar("fraglimit"))
IntermissionStart();
}
void
HLMultiplayerRules::PlayerDeath(NSClientPlayer pl)
{
/* obituary networking */
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_OBITUARY);
WriteString(MSG_MULTICAST, (g_dmg_eAttacker.netname) ? g_dmg_eAttacker.netname : g_dmg_eAttacker.classname);
WriteString(MSG_MULTICAST, pl.netname);
WriteByte(MSG_MULTICAST, g_dmg_iWeapon);
WriteByte(MSG_MULTICAST, 0);
msg_entity = world;
multicast([0,0,0], MULTICAST_ALL);
Plugin_PlayerObituary(g_dmg_eAttacker, g_dmg_eTarget, g_dmg_iWeapon, g_dmg_iHitBody, g_dmg_iDamage);
/* death-counter */
pl.deaths++;
pl.SetInfoKey("*deaths", ftos(pl.deaths));
/* update score-counter */
if (pl.flags & FL_CLIENT || pl.flags & FL_MONSTER)
if (g_dmg_eAttacker.flags & FL_CLIENT) {
if (pl == g_dmg_eAttacker)
g_dmg_eAttacker.frags--;
else
g_dmg_eAttacker.frags++;
}
/* either gib, or make a corpse */
if (pl.health < -50) {
FX_GibHuman(pl.origin, vectoangles(pl.origin - g_dmg_eAttacker.origin), g_dmg_iDamage * 2.0f);
} else {
FX_Corpse_Spawn((player)pl, ANIM_DIESIMPLE);
}
/* now let's make the real client invisible */
pl.Death();
pl.SetTakedamage(DAMAGE_NO);
pl.gflags &= ~GF_FLASHLIGHT;
pl.gflags &= ~GF_EGONBEAM;
Sound_Play(pl, CHAN_AUTO, "player.die");
/* force respawn */
pl.ScheduleThink(PutClientInServer, 4.0f);
/* have we gone over the fraglimit? */
CheckRules();
}
void
HLMultiplayerRules::PlayerSpawn(NSClientPlayer pp)
{
player pl = (player)pp;
string playerModel;
/* this is where the mods want to deviate */
entity spot;
pl.classname = "player";
pl.SetMaxHealth(100);
pl.SetHealth(100);
pl.SetTakedamage(DAMAGE_YES);
pl.SetSolid(SOLID_SLIDEBOX);
pl.SetMovetype(MOVETYPE_WALK);
pl.AddFlags(FL_CLIENT);
pl.viewzoom = 1.0;
/* player model selection */
if (IsTeamplay() == true) {
int teamCount = tokenizebyseparator(m_strTeamList, ";");
int playerTeam = (int)pl.GetTeam();
/* not part of a team? pick one of the ones we have */
/* TODO: this should sort us into the lowest team */
if (playerTeam == 0) {
playerTeam = 1i + (int)floor(random(0, (float)teamCount)); /* teams start at 1 after all */
pl.SetTeam(playerTeam);
}
/* assign our player model */
playerModel = sprintf("models/player/%s/%s.mdl", argv(playerTeam - 1i), argv(playerTeam - 1i));
} else {
/* interpret the 'model' InfoKey */
playerModel = pl.GetInfoKey("model");
if (playerModel) {
playerModel = sprintf("models/player/%s/%s.mdl", playerModel, playerModel);
}
}
/* fallback is always models/player.mdl for Half-Life */
if not (whichpack(playerModel)) {
playerModel = "models/player.mdl";
}
pl.SetModel(playerModel);
pl.SetSize(VEC_HULL_MIN, VEC_HULL_MAX);
pl.ClearVelocity();
pl.gravity = __NULL__;
pl.SetFrame(1);
pl.SendFlags = UPDATE_ALL;
pl.iBleeds = TRUE;
pl.SetInfoKey("*spec", "0");
pl.SetInfoKey("*dead", "0");
pl.SetInfoKey("*deaths", ftos(pl.deaths));
LevelNewParms();
LevelDecodeParms(pl);
#if defined (VALVE) || defined (GEARBOX)
pl.g_items = ITEM_CROWBAR | ITEM_SHOTGUN | ITEM_SUIT;
pl.activeweapon = WEAPON_SHOTGUN;
pl.ammo_shells = 25;
#endif
spot = Spawn_SelectRandom("info_player_deathmatch");
pl.SetOrigin(spot.origin);
pl.SetAngles(spot.angles);
Weapons_RefreshAmmo(pl);
Client_FixAngle(pl, pl.angles);
}
bool
HLMultiplayerRules::ConsoleCommand(NSClientPlayer pp, string cmd)
{
tokenize(cmd);
switch (argv(0)) {
case "bot_add":
bot pete = (bot)Bot_AddQuick();
Bot_RandomColormap(pete);
searchhandle pm = search_begin("models/player/*/*.mdl", TRUE, TRUE);
int r = floor(random(0, search_getsize(pm)));
string mdl = substring(search_getfilename(pm, r), 0, -5);
tokenizebyseparator(mdl, "/");
forceinfokey(pete, "model", argv(2));
search_end(pm);
break;
case "jumptest":
makevectors(pp.v_angle);
traceline(pp.origin + pp.view_ofs, pp.origin + pp.view_ofs + v_forward * 1024, FALSE, pp);
pp.velocity = Route_GetJumpVelocity(pp.origin, trace_endpos, pp.gravity);
break;
default:
return (false);
}
return (true);
}
bool
HLMultiplayerRules::MonstersSpawn(void)
{
return (autocvar(mp_allowmonsters, 0)) ? true : false;
}
void
HLMultiplayerRules::HLMultiplayerRules(void)
{
/* these lines do nothing but tell the server to register those cvars */
autocvar(timelimit, 15, "Timelimit for multiplayer rounds");
autocvar(fraglimit, 15, "Points limit for multiplayer rounds");
}
void
CSEv_HLDM_Chooseteam_s(string teamName)
{
HLGameRules rules = (HLGameRules)g_grMode;
player pl = (player)self;
if (!teamName)
return;
if (rules.IsMultiplayer() == false)
return;
if (rules.IsTeamplay() == false)
return;
if (pl.IsDead() == true)
return;
HLMultiplayerRules mprules = (HLMultiplayerRules)rules;
int c = tokenizebyseparator(mprules.m_strTeamList, ";");
for (int i = 0; i < c; i++) {
if (argv(i) == teamName) {
pl.SetTeam((float)i + 1);
Damage_Apply(pl, pl, 100, 0, DMG_SKIP_ARMOR);
return;
}
}
}

View File

@ -0,0 +1,133 @@
/*
* 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
HLSingleplayerRules::IsMultiplayer(void)
{
return false;
}
void
HLSingleplayerRules::PlayerDeath(NSClientPlayer pl)
{
pl.movetype = MOVETYPE_NONE;
pl.solid = SOLID_NOT;
pl.takedamage = DAMAGE_NO;
pl.gflags &= ~GF_FLASHLIGHT;
pl.armor = pl.activeweapon = pl.g_items = pl.weapon = 0;
pl.health = 0;
Sound_Play(pl, CHAN_AUTO, "player.die");
if (cvar("coop") == 1) {
pl.think = PutClientInServer;
pl.nextthink = time + 4.0f;
}
if (pl.health < -50) {
FX_GibHuman(pl.origin, vectoangles(pl.origin - g_dmg_eAttacker.origin), g_dmg_iDamage * 2.0f);
}
/* Let's handle corpses on the clientside */
entity corpse = spawn();
setorigin(corpse, pl.origin + [0,0,32]);
setmodel(corpse, pl.model);
setsize(corpse, VEC_HULL_MIN, VEC_HULL_MAX);
corpse.movetype = MOVETYPE_TOSS;
corpse.solid = SOLID_TRIGGER;
corpse.modelindex = pl.modelindex;
corpse.frame = ANIM_DIESIMPLE;
corpse.angles = pl.angles;
corpse.velocity = pl.velocity;
}
void
HLSingleplayerRules::PlayerSpawn(NSClientPlayer pl)
{
pl.classname = "player";
pl.health = pl.max_health = 100;
pl.takedamage = DAMAGE_YES;
pl.SetSolid(SOLID_SLIDEBOX);
pl.SetMovetype(MOVETYPE_WALK);
pl.flags = FL_CLIENT;
pl.viewzoom = 1.0;
pl.model = "models/player.mdl";
if (cvar("coop") == 1) {
string mymodel = infokey(pl, "model");
if (mymodel) {
mymodel = sprintf("models/player/%s/%s.mdl", mymodel, mymodel);
if (whichpack(mymodel)) {
pl.model = mymodel;
}
}
}
setmodel(pl, pl.model);
setsize(pl, VEC_HULL_MIN, VEC_HULL_MAX);
pl.velocity = [0,0,0];
pl.gravity = __NULL__;
pl.frame = 1;
//pl.SendEntity = Player_SendEntity;
pl.SendFlags = UPDATE_ALL;
pl.customphysics = Empty;
pl.iBleeds = TRUE;
forceinfokey(pl, "*spec", "0");
forceinfokey(pl, "*deaths", ftos(pl.deaths));
/* this is where the mods want to deviate */
entity spot;
if (startspot != "") {
dprint(sprintf("^3Gamerules_Spawn^7: Startspot is %s\n", startspot));
LevelDecodeParms(pl);
setorigin(pl, Landmark_GetSpot());
} else {
LevelNewParms();
spot = find(world, ::classname, "info_player_start");
setorigin(pl, spot.origin);
pl.angles = spot.angles;
}
Weapons_RefreshAmmo(pl);
Client_FixAngle(pl, pl.angles);
}
bool
HLSingleplayerRules::ImpulseCommand(NSClient bp, float num)
{
switch (num) {
case 101:
player pl = (player)bp;
pl.health = 100;
pl.armor = 100;
pl.g_items |= ITEM_SUIT;
Weapons_AddItem(pl, WEAPON_CROWBAR, -1);
Weapons_AddItem(pl, WEAPON_SHOTGUN, -1);
Weapons_AddItem(pl, WEAPON_SUPERSHOTGUN, -1);
Weapons_AddItem(pl, WEAPON_NAILGUN, -1);
Weapons_AddItem(pl, WEAPON_SUPERNAILGUN, -1);
Weapons_AddItem(pl, WEAPON_GRENADELAUNCHER, -1);
Weapons_AddItem(pl, WEAPON_ROCKETLAUNCHER, -1);
Weapons_AddItem(pl, WEAPON_LIGHTNING, -1);
break;
default:
return super::ImpulseCommand(bp, num);
}
return true;
}

196
src/server/item_armor.qc Normal file
View File

@ -0,0 +1,196 @@
/*
* 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.
*/
class item_armor:NSRenderableEntity
{
void(void) item_armor;
virtual void(void) Spawned;
virtual void(void) Respawn;
virtual void(entity) Touch;
};
void
item_armor::Touch(entity eToucher)
{
if not (eToucher.flags & FL_CLIENT) {
return;
}
player pl = (player)eToucher;
Sound_Play(eToucher, CHAN_ITEM, "armor.pickup");
Weapons_RefreshAmmo(pl);
Logging_Pickup(eToucher, this, __NULL__);
if (real_owner || cvar("sv_playerslots") == 1) {
Destroy();
} else {
Disappear();
ScheduleThink(Respawn, 30.0f);
}
}
void
item_armor::Respawn(void)
{
SetSolid(SOLID_TRIGGER);
SetMovetype(MOVETYPE_TOSS);
SetOrigin(GetSpawnOrigin());
SetModel(GetSpawnModel());
SetSize([-16,-16,0],[16,16,16]);
ReleaseThink();
if (real_owner && time > 30.0f)
Sound_Play(this, CHAN_ITEM, "armor.respawn");
droptofloor();
}
void
item_armor::Spawned(void)
{
super::Spawned();
Sound_Precache("armor.pickup");
Sound_Precache("armor.respawn");
precache_model(model);
}
void
item_armor::item_armor(void)
{
m_oldModel = model;
}
/*QUAKED item_armor1 (0 0 0.8) (-16 -16 0) (16 16 32)
DEATHMATCH CLASSIC (1999) ENTITY
Armor item that gives you 100 armor points.
It is the green armor.
-------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
model="models/armour_g.mdl"
*/
class
item_armor1:item_armor
{
void(void) item_armor1;
virtual void(entity) Touch;
};
void
item_armor1::item_armor1(void)
{
model = "models/armour_g.mdl";
}
void
item_armor1::Touch(entity eToucher)
{
if not (eToucher.flags & FL_CLIENT) {
return;
}
if (eToucher.classname == "player") {
player pl = (player)eToucher;
if (pl.armor < 100) {
pl.armor = 100;
item_armor::Touch(eToucher);
}
}
}
/*QUAKED item_armor2 (0 0 0.8) (-16 -16 0) (16 16 32)
DEATHMATCH CLASSIC (1999) ENTITY
Armor item that gives you 150 armor points.
It is the yellow armor.
-------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
model="models/armour_y.mdl"
*/
class
item_armor2:item_armor
{
void(void) item_armor2;
virtual void(entity) Touch;
};
void
item_armor2::item_armor2(void)
{
model = "models/armour_y.mdl";
}
void
item_armor2::Touch(entity eToucher)
{
if not (eToucher.flags & FL_CLIENT) {
return;
}
if (eToucher.classname == "player") {
player pl = (player)eToucher;
if (pl.armor < 150) {
pl.armor = 150;
item_armor::Touch(eToucher);
}
}
}
/*QUAKED item_armor3 (0 0 0.8) (-16 -16 0) (16 16 32)
DEATHMATCH CLASSIC (1999) ENTITY
Armor item that gives you 200 armor points.
It is the green armor.
-------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
model="models/armour_r.mdl"
*/
class item_armor3:item_armor
{
void(void) item_armor3;
virtual void(entity) Touch;
};
void
item_armor3::item_armor3(void)
{
model = "models/armour_r.mdl";
}
void
item_armor3::Touch(entity eToucher)
{
if not (eToucher.flags & FL_CLIENT) {
return;
}
if (eToucher.classname == "player") {
player pl = (player)eToucher;
if (pl.armor < 200) {
pl.armor = 200;
item_armor::Touch(eToucher);
}
}
}

View File

@ -0,0 +1,92 @@
/*
* 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.
*/
class item_weaponbox:NSRenderableEntity
{
int weapon_items;
void(void) item_weaponbox;
virtual void(void) Spawned;
virtual void(entity) Touch;
virtual void(player) setup;
};
void
item_weaponbox::Touch(entity eToucher)
{
if (eToucher.classname != "player") {
return;
}
player pl = (player)eToucher;
Logging_Pickup(eToucher, this, __NULL__);
sound(pl, CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM);
pl.ammo_shells += ammo_shells;
pl.ammo_nails += ammo_nails;
pl.ammo_rockets += ammo_rockets;
pl.ammo_cells += ammo_cells;
/* cull */
pl.ammo_shells = min(pl.ammo_shells, MAX_A_SHELLS);
pl.ammo_nails = min(pl.ammo_nails, MAX_A_NAILS);
pl.ammo_rockets = min(pl.ammo_rockets, MAX_A_ROCKETS);
pl.ammo_cells = min(pl.ammo_cells, MAX_A_CELLS);
pl.g_items |= weapon_items;
Weapons_RefreshAmmo(pl);
Destroy();
}
void
item_weaponbox::setup(player pl)
{
/* TODO: Should the magazine bits be transferred too? */
ammo_shells = pl. ammo_shells;
ammo_nails = pl. ammo_nails;
ammo_rockets = pl.ammo_rockets;
ammo_cells = pl.ammo_cells;
weapon_items = pl.g_items;
}
void
item_weaponbox::Spawned(void)
{
super::Spawned();
SetModel("models/w_weaponbox.mdl");
SetSize([-16,-16,0], [16,16,16]);
SetSolid(SOLID_TRIGGER);
SetMovetype(MOVETYPE_TOSS);
}
void
item_weaponbox::item_weaponbox(void)
{
botinfo = BOTINFO_AMMO;
}
void
weaponbox_spawn(player spawner)
{
item_weaponbox weaponbox = spawn(item_weaponbox);
weaponbox.SetOrigin(spawner.origin);
weaponbox.setup(spawner);
}

87
src/server/progs.src Normal file
View File

@ -0,0 +1,87 @@
#pragma target fte_5768
//#pragma flag enable assumeint
#pragma progs_dat "../../progs.dat"
#define QWSSQC
#define SERVER
#define VALVE
#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
../../../valve/src/server/defs.h
../shared/include.src
../../../valve/src/server/monster_apache.qc
../../../valve/src/server/monster_alien_controller.qc
../../../valve/src/server/monster_alien_grunt.qc
../../../valve/src/server/monster_alien_slave.qc
../../../valve/src/server/monster_barnacle.qc
../../../valve/src/server/monster_barney.qc
../../../valve/src/server/monster_barney_dead.qc
../../../valve/src/server/monster_bigmomma.qc
../../../valve/src/server/monster_bloater.qc
../../../valve/src/server/monster_bullchicken.qc
../../../valve/src/server/monster_cockroach.qc
../../../valve/src/server/monster_flyer_flock.qc
../../../valve/src/server/monster_gargantua.qc
../../../valve/src/server/monster_gman.qc
../../../valve/src/server/monster_headcrab.qc
../../../valve/src/server/monster_babycrab.qc
../../../valve/src/server/monster_hevsuit_dead.qc
../../../valve/src/server/monster_houndeye.qc
../../../valve/src/server/monster_human_grunt.qc
../../../valve/src/server/monster_hgrunt_dead.qc
../../../valve/src/server/monster_human_assassin.qc
../../../valve/src/server/monster_ichthyosaur.qc
../../../valve/src/server/monster_leech.qc
../../../valve/src/server/monster_miniturret.qc
../../../valve/src/server/monster_nihilanth.qc
../../../valve/src/server/monster_osprey.qc
../../../valve/src/server/monster_rat.qc
../../../valve/src/server/monster_scientist_dead.qc
../../../valve/src/server/monster_sitting_scientist.qc
../../../valve/src/server/monster_scientist.qc
../../../valve/src/server/monster_sentry.qc
../../../valve/src/server/monster_tentacle.qc
../../../valve/src/server/monster_turret.qc
../../../valve/src/server/monster_zombie.qc
../../../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
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
ammo.qc
item_armor.qc
../../../src/botlib/include.src
gamerules.qc
gamerules_singleplayer.qc
gamerules_multiplayer.qc
../../../valve/src/server/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

61
src/server/weaponbox.qc Normal file
View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2016-2022 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.
*/
/*QUAKED weaponbox (0 0 0.8) (-16 -16 0) (16 16 32)
HALF-LIFE (1998) ENTITY
Ammo container. Used to delvier more than 1 singular ammo type, as well as
more precise control.
-------- KEYS --------
"targetname" : Name
"uranium" : Amount of Uranium (Egon, Gauss) ammo to give
"357" : Amount of 357 Python ammo to give
"9mm" : Amount of 9mm Handgun/MP5 ammo to give
"ARgrenades" : Amount of MP5 grenades to give
"bolts" : Amount of Crossbow bolts
"buckshot" : Amount of Shotgun ammo to give
"rockets" : Amount of RPG ammo to give
"556" : (Oppossing Force only) Amount for the SAW Machine Gun
"762" : (Oppossing Force only) Amount for the Sniper Rifle
"spore" : (Oppossing Force only) Amount for the Spore Launcher
-------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
model="models/models/w_weaponbox.mdl"
*/
class
weaponbox:item_weaponbox
{
void(void) weaponbox;
virtual void(string, string) SpawnKey;
};
void
weaponbox::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
}
}
void
weaponbox::weaponbox(void)
{
// do nothing
}

32
src/shared/include.src Normal file
View File

@ -0,0 +1,32 @@
#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_breakmodel.qc
../../../valve/src/shared/fx_explosion.qc
../../../valve/src/shared/fx_gibhuman.qc
../../../valve/src/shared/fx_spark.qc
../../../valve/src/shared/fx_corpse.qc
../../../valve/src/shared/fx_impact.qc
items.h
weapons.h
w_crowbar.qc
w_shotgun.qc
w_supershotgun.qc
w_nailgun.qc
w_supernailgun.qc
w_grenadelauncher.qc
w_rocketlauncher.qc
w_lightning.qc
weapons.qc
../../../valve/src/shared/weapon_common.qc
#endlist

51
src/shared/items.h Normal file
View File

@ -0,0 +1,51 @@
/*
* 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.
*/
#define ITEM_CROWBAR 0x00000001i
#define ITEM_SHOTGUN 0x00000002i
#define ITEM_SUPERSHOTGUN 0x00000004i
#define ITEM_NAILGUN 0x00000008i
#define ITEM_SUPERNAILGUN 0x00000010i
#define ITEM_GRENADELAUNCHER 0x00000020i
#define ITEM_ROCKETLAUNCHER 0x00000040i
#define ITEM_LIGHTNING 0x00000080i
#define ITEM_UNUSED10 0x00000100i
#define ITEM_UNUSED11 0x00000200i
#define ITEM_UNUSED12 0x00000400i
#define ITEM_UNUSED13 0x00000800i
#define ITEM_UNUSED14 0x00001000i
#define ITEM_UNUSED15 0x00002000i
#define ITEM_SUIT 0x00004000i
#define ITEM_LONGJUMP 0x00008000i
#define ITEM_UNUSED17 0x00010000i
#define ITEM_UNUSED18 0x00020000i
#define ITEM_UNUSED19 0x00040000i
#define ITEM_UNUSED20 0x00080000i
#define ITEM_UNUSED21 0x00100000i
#define ITEM_UNUSED22 0x00200000i
#define ITEM_UNUSED23 0x00400000i
#define ITEM_UNUSED24 0x00800000i
#define ITEM_UNUSED25 0x01000000i
#define ITEM_UNUSED26 0x02000000i
#define ITEM_UNUSED27 0x04000000i
#define ITEM_UNUSED28 0x08000000i
#define ITEM_UNUSED29 0x10000000i
#define ITEM_UNUSED30 0x20000000i
#define ITEM_UNUSED31 0x40000000i
#define ITEM_UNUSED32 0x80000000i

503
src/shared/player.qc Normal file
View File

@ -0,0 +1,503 @@
/*
* 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
/* Here's a list of bone names that we are aware of on HL player models.
Usually we'd use skeletalobjects to share the same skeleton/anim with
another model - but because FTEQW does not support that for HLMDL we
are forced to manually position the bones of our attachnment
by iterating over them and manually setting their position in 3D-space.
*/
string g_pbones[] =
{
"Bip01",
"Bip01 Footsteps",
"Bip01 Pelvis",
"Bip01 L Leg",
"Bip01 L Leg1",
"Bip01 L Foot",
"Bip01 L Toe0",
"Bip01 L Toe01",
"Bip01 L Toe02",
"Dummy16",
"Bip01 R Leg",
"Bip01 R Leg1",
"Bip01 R Foot",
"Bip01 R Toe0",
"Bip01 R Toe01",
"Bip01 R Toe02",
"Dummy11",
"Bip01 Spine",
"Bip01 Spine1",
"Bip01 Spine2",
"Bip01 Spine3",
"Bip01 Neck",
"Bip01 Head",
"Dummy21",
"Dummy08",
"Bone02",
"Bone03",
"Bone04",
"Dummy05",
"Bone09",
"Bone10",
"Dummy04",
"Bone05",
"Bone06",
"Dummy03",
"Bone07",
"Bone08",
"Dummy09",
"Bone11",
"Bone12",
"Dummy10",
"Bone13",
"Bone14",
"Bone15",
"Bip01 L Arm",
"Bip01 L Arm1",
"Bip01 L Arm2",
"Bip01 L Hand",
"Bip01 L Finger0",
"Bip01 L Finger01",
"Bip01 L Finger02",
"Dummy06",
"Bip01 L Finger1",
"Bip01 L Finger11",
"Bip01 L Finger12",
"Dummy07",
"Bip01 R Arm",
"Bip01 R Arm1",
"Bip01 R Arm2",
"Bip01 R Hand",
"Bip01 R Finger0",
"Bip01 R Finger01",
"Bip01 R Finger02",
"Dummy01",
"Bip01 R Finger1",
"Bip01 R Finger11",
"Bip01 R Finger12",
"Dummy02",
"Box02",
"Bone08",
"Bone15"
};
#endif
/* all custom SendFlags bits we can possibly send */
enumflags
{
PLAYER_TOPFRAME = PLAYER_CUSTOMFIELDSTART,
PLAYER_BOTTOMFRAME,
PLAYER_AMMO1,
PLAYER_AMMO2,
PLAYER_AMMO3,
PLAYER_UNUSED5,
PLAYER_UNUSED6,
PLAYER_UNUSED7
};
noref .float ammo_shells;
noref .float ammo_nails;
noref .float ammo_rockets;
noref .float ammo_cells;
class player:NSClientPlayer
{
void(void) player;
/* 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_FLOAT_N(ammo_shells)
PREDICTED_FLOAT_N(ammo_nails)
PREDICTED_FLOAT_N(ammo_rockets)
PREDICTED_FLOAT_N(ammo_cells)
virtual void Physics_Jump(void);
virtual void UpdatePlayerAnimation(float);
#ifdef CLIENT
////virtual void(void) draw;
//virtual float() predraw;
//virtual void(void) postdraw;
virtual void UpdatePlayerAttachments(bool);
virtual void ReceiveEntity(float,float);
virtual void PredictPreFrame(void);
virtual void PredictPostFrame(void);
virtual void UpdateAliveCam(void);
#else
virtual void EvaluateEntity(void);
virtual float SendEntity(entity, float);
virtual void Save(float);
virtual void Restore(string,string);
#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)
{
/* draw the flashlight */
if (gflags & GF_FLASHLIGHT) {
vector src;
vector ang;
if (entnum != player_localentnum) {
src = origin + view_ofs;
ang = v_angle;
} else {
src = pSeat->m_vecPredictedOrigin + [0,0,-8];
ang = view_angles;
}
makevectors(ang);
traceline(src, src + (v_forward * 8096), MOVE_NORMAL, this);
if (serverkeyfloat("*bspversion") == BSPVER_HL) {
dynamiclight_add(trace_endpos + (v_forward * -2), 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);
}
}
/* 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);
/*
=================
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(ammo_shells, PLAYER_AMMO1)
READENTITY_BYTE(ammo_nails, PLAYER_AMMO1)
READENTITY_BYTE(ammo_rockets, PLAYER_AMMO1)
READENTITY_BYTE(ammo_cells, PLAYER_AMMO1)
setorigin(this, origin);
/* 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)
{
/* the generic client attributes */
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(ammo_shells)
SAVE_STATE(ammo_nails)
SAVE_STATE(ammo_rockets)
SAVE_STATE(ammo_cells)
}
/*
=================
player::PredictPostFrame
Where we roll back our values to the ones last sent/verified by the server.
=================
*/
void
player::PredictPostFrame(void)
{
/* the generic client attributes */
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(ammo_shells)
ROLL_BACK(ammo_nails)
ROLL_BACK(ammo_rockets)
ROLL_BACK(ammo_cells)
}
#else
void
player::Save(float handle)
{
super::Save(handle);
SaveInt(handle, "anim_top", anim_top);
SaveFloat(handle, "anim_top_time", anim_top_time);
SaveFloat(handle, "anim_top_delay", anim_top_delay);
SaveInt(handle, "anim_bottom", anim_bottom);
SaveFloat(handle, "anim_bottom_time", anim_bottom_time);
/* ammo 1 */
SaveInt(handle, "ammo_shells", ammo_shells);
SaveInt(handle, "ammo_nails", ammo_nails);
SaveInt(handle, "ammo_rockets", ammo_rockets);
SaveInt(handle, "ammo_cells", ammo_cells);
}
void
player::Restore(string strKey, string strValue)
{
switch (strKey) {
case "anim_top":
anim_top = ReadInt(strValue);
break;
case "anim_top_time":
anim_top_time = ReadFloat(strValue);
break;
case "anim_top_delay":
anim_top_delay = ReadFloat(strValue);
break;
case "anim_bottom":
anim_bottom = ReadInt(strValue);
break;
case "anim_bottom_time":
anim_bottom_time = ReadFloat(strValue);
break;
/* AMMO 1 */
case "ammo_shells":
ammo_shells = ReadInt(strValue);
break;
case "ammo_nails":
ammo_nails = ReadInt(strValue);
break;
case "ammo_rockets":
ammo_rockets = ReadInt(strValue);
break;
case "ammo_cells":
ammo_cells = ReadInt(strValue);
break;
default:
super::Restore(strKey, strValue);
}
}
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(ammo_shells, PLAYER_AMMO1)
EVALUATE_FIELD(ammo_nails, PLAYER_AMMO1)
EVALUATE_FIELD(ammo_rockets, PLAYER_AMMO1)
EVALUATE_FIELD(ammo_cells, PLAYER_AMMO1)
}
/*
=================
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(ammo_shells, PLAYER_AMMO1)
SENDENTITY_BYTE(ammo_nails, PLAYER_AMMO1)
SENDENTITY_BYTE(ammo_rockets, PLAYER_AMMO1)
SENDENTITY_BYTE(ammo_cells, PLAYER_AMMO1)
return (1);
}
#endif
void
player::player(void)
{
anim_top = 0;
anim_top_time = 0;
anim_top_delay = 0;
anim_bottom = 0;
anim_bottom_time = 0;
ammo_shells = 0;
ammo_nails = 0;
ammo_rockets = 0;
ammo_cells = 0;
}

206
src/shared/w_crowbar.qc Normal file
View File

@ -0,0 +1,206 @@
/*
* 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.
*/
/*QUAKED weapon_crowbar (0 0 1) (-16 -16 0) (16 16 32)
"model" "models/w_crowbar.mdl"
DEATHMATCH CLASSIC (1999) ENTITY
Crowbar Weapon
*/
enum
{
CBAR_IDLE,
CBAR_ATTACK,
};
void
w_crowbar_precache(void)
{
#ifdef SERVER
Sound_Precache("weapon_crowbar.swing");
Sound_Precache("weapon_crowbar.hit");
Sound_Precache("weapon_crowbar.hitbody");
precache_model("models/w_crowbar.mdl");
#else
precache_model("models/v_crowbar.mdl");
precache_model("models/p_crowbar.mdl");
#endif
}
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/v_crowbar.mdl");
Weapons_ViewAnimation(pl, CBAR_IDLE);
}
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;
pl.w_attack_next = 0.5f;
pl.w_idle_next = 2.5f;
Weapons_ViewAnimation(pl, CBAR_ATTACK);
Animation_PlayerTop(pl, (pl.flags & FL_CROUCHING) ? ANIM_CR_SHOOTCROWBAR : ANIM_SHOOTCROWBAR, 0.41f);
#ifdef SERVER
Sound_Play(pl, CHAN_WEAPON, "weapon_crowbar.swing");
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 {
FX_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal);
}
if (trace_ent.takedamage) {
Damage_Apply(trace_ent, pl, Skill_GetValue("plr_crowbar", 20), WEAPON_CROWBAR, DMG_BLUNT);
if (trace_ent.iBleeds) {
Sound_Play(pl, CHAN_WEAPON, "weapon_crowbar.hitbody");
}
} else {
Sound_Play(pl, CHAN_WEAPON, "weapon_crowbar.hit");
DecalGroups_Place("Impact.Shot", trace_endpos + (v_forward * -2));
}
#endif
}
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
if (selected) {
drawsubpic(
pos,
[170,45],
g_hudcb_spr,
[0,0],
[1,0.625],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[170,45],
g_hudcb_spr,
[0,0],
[1,0.625],
g_hud_color,
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 = "axe",
.id = ITEM_CROWBAR,
.slot = 0,
.slot_pos = 0,
.weight = 0,
.draw = w_crowbar_draw,
.holster = __NULL__,
.primary = w_crowbar_primary,
.secondary = __NULL__,
.reload = __NULL__,
.release = __NULL__,
.postdraw = __NULL__,
.precache = w_crowbar_precache,
.pickup = __NULL__,
.updateammo = __NULL__,
.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
};
/* entity definitions for pickups */
#ifdef SERVER
void
weapon_crowbar(void)
{
Weapons_InitItem(WEAPON_CROWBAR);
}
void
weapon_axe(void)
{
Weapons_InitItem(WEAPON_CROWBAR);
}
#endif

View File

@ -0,0 +1,262 @@
/*
* 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.
*/
/*QUAKED weapon_hornetgun (0 0 1) (-16 -16 0) (16 16 32)
"model" "models/g_rock.mdl"
HALF-LIFE (1998) ENTITY
Hornetgun Weapon
*/
enum
{
GRENLAUNCHER_IDLE,
GRENLAUNCHER_SHOOT,
};
void
w_grenadelauncher_precache(void)
{
#ifdef SERVER
Sound_Precache("weapon_grenadelauncher.shoot");
Sound_Precache("weapon_grenadelauncher.bounce");
precache_model("models/g_rock.mdl");
precache_model("models/grenade.mdl");
#else
precache_model("models/v_rock.mdl");
precache_model("models/p_rock.mdl");
#endif
}
int
w_grenadelauncher_pickup(player pl, int new, int startammo)
{
#ifdef SERVER
if (pl.ammo_rockets < MAX_A_ROCKETS) {
pl.ammo_rockets = bound(0, pl.ammo_rockets + 5, MAX_A_ROCKETS);
} else {
if (!new)
return (0);
}
#endif
return (1);
}
void
w_grenadelauncher_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, -1, pl.ammo_rockets, -1);
}
string
w_grenadelauncher_wmodel(void)
{
return "models/g_rock.mdl";
}
string
w_grenadelauncher_pmodel(player pl)
{
return "models/p_rock.mdl";
}
string
w_grenadelauncher_deathmsg(void)
{
return "";
}
void
w_grenadelauncher_draw(player pl)
{
Weapons_SetModel("models/v_rock.mdl");
Weapons_ViewAnimation(pl, GRENLAUNCHER_IDLE);
}
#ifdef SERVER
void
w_grenadelauncher_shootnade(player pl)
{
static void Grenade_Explode(void) {
float dmg = Skill_GetValue("plr_grenadelauncher_dmg", 100);
FX_Explosion(self.origin);
Damage_Radius(self.origin, self.owner, dmg, dmg * 2.5f, TRUE, WEAPON_GRENADELAUNCHER);
sound(self, CHAN_WEAPON, sprintf("weapons/explode%d.wav", floor(random() * 2) + 3), 1, ATTN_NORM);
remove(self);
}
static void Grenade_Bounce(void) {
/* if what we are touching can be damaged, explode */
if (other.takedamage) {
Grenade_Explode();
return;
}
Sound_Play(self, CHAN_VOICE, "weapon_grenadelauncher.bounce");
}
Weapons_MakeVectors(pl);
/* spawn the 'pineapple' */
entity grenade = spawn();
setmodel(grenade, "models/grenade.mdl");
setorigin(grenade, pl.origin);
grenade.owner = pl;
if (pl.v_angle[0]) {
grenade.velocity = v_forward * 600;
grenade.velocity += v_up * 200;
grenade.velocity += ((random() - 0.5) * v_right) * 10;
grenade.velocity += ((random() - 0.5) * v_up) * 10;
} else {
grenade.velocity = v_forward * 600;
grenade.velocity[2] = 200;
}
grenade.avelocity = [300, 300, 300];
grenade.movetype = MOVETYPE_BOUNCE;
grenade.solid = SOLID_BBOX;
//grenade.flags |= FL_LAGGEDMOVE;
grenade.angles = vectoangles(grenade.velocity);
grenade.touch = Grenade_Bounce;
grenade.think = Grenade_Explode;
grenade.nextthink = time + 2.5f;
grenade.traileffectnum = particleeffectnum("weapon_rpg.trail");
setsize(grenade, [0,0,0], [0,0,0]);
Sound_Play(pl, CHAN_WEAPON, "weapon_grenadelauncher.shoot");
}
#endif
void
w_grenadelauncher_primary(player pl)
{
if (pl.w_attack_next > 0.0)
return;
if (pl.ammo_rockets <= 0)
return;
/* fire the actual projectile (on the server) */
#ifdef SERVER
w_grenadelauncher_shootnade(pl);
#endif
/* remove ammo and play the animation on view + player model */
pl.ammo_rockets--;
Weapons_ViewAnimation(pl, GRENLAUNCHER_SHOOT);
Animation_PlayerTop(pl, (pl.flags & FL_CROUCHING) ? ANIM_CR_SHOOTGAUSS : ANIM_SHOOTGAUSS, 0.43f);
pl.w_attack_next = 0.6;
}
void
w_grenadelauncher_crosshair(player pl)
{
#ifdef CLIENT
vector aicon_pos;
Cross_DrawSub(g_cross_spr, [24,24], [72/128,24/128], [0.1875, 0.1875]);
aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42];
HUD_DrawAmmo2();
drawsubpic(
aicon_pos,
[24,24],
g_hudglammo,
[0, 0],
[24/24, 24/24],
g_hud_color,
pSeatLocal->m_flAmmo2Alpha,
DRAWFLAG_ADDITIVE
);
#endif
}
float
w_grenadelauncher_aimanim(player pl)
{
return pl.flags & FL_CROUCHING ? ANIM_CR_AIMGAUSS : ANIM_AIMGAUSS;
}
int
w_grenadelauncher_isempty(player pl)
{
return (pl.ammo_rockets == 0) ? true : false;
}
void
w_grenadelauncher_hudpic(player pl, int selected, vector pos, float a)
{
#ifdef CLIENT
vector hud_col;
if (w_grenadelauncher_isempty(pl))
hud_col = [1,0,0];
else
hud_col = g_hud_color;
if (selected) {
drawsubpic(pos, [170,45], g_hudgl_spr, [0,0], [1,0.625], hud_col, a, DRAWFLAG_ADDITIVE);
} else {
drawsubpic(pos, [170,45], g_hudgl_spr, [0,0], [1,0.625], hud_col, a, DRAWFLAG_ADDITIVE);
}
HUD_DrawAmmoBar(pos, pl.ammo_rockets, MAX_A_ROCKETS, a);
#endif
}
weapontype_t
w_grenadelauncher_type(player pl)
{
return WPNTYPE_RANGED;
}
weapon_t
w_grenadelauncher =
{
.name = "grenadel",
.id = ITEM_GRENADELAUNCHER,
.slot = 5,
.slot_pos = 0,
.weight = 4,
.draw = w_grenadelauncher_draw,
.holster = __NULL__,
.primary = w_grenadelauncher_primary,
.secondary = __NULL__,
.reload = __NULL__,
.release = __NULL__,
.postdraw = w_grenadelauncher_crosshair,
.precache = w_grenadelauncher_precache,
.pickup = w_grenadelauncher_pickup,
.updateammo = w_grenadelauncher_updateammo,
.wmodel = w_grenadelauncher_wmodel,
.pmodel = w_grenadelauncher_pmodel,
.deathmsg = w_grenadelauncher_deathmsg,
.aimanim = w_grenadelauncher_aimanim,
.isempty = w_grenadelauncher_isempty,
.type = w_grenadelauncher_type,
.hudpic = w_grenadelauncher_hudpic
};
#ifdef SERVER
void
weapon_grenadelauncher(void)
{
Weapons_InitItem(WEAPON_GRENADELAUNCHER);
}
#endif

241
src/shared/w_lightning.qc Normal file
View File

@ -0,0 +1,241 @@
/*
* 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.
*/
/*QUAKED weapon_crossbow (0 0 1) (-16 -16 0) (16 16 32)
"model" "models/g_light.mdl"
HALF-LIFE (1998) ENTITY
Crossbow Weapon
*/
enum
{
LIGHTNING_IDLE,
LIGHTNING_SHOOT,
};
void
w_lightning_precache(void)
{
#ifdef SERVER
Sound_Precache("weapon_lightning.start");
precache_model("models/g_light.mdl");
#else
precache_model("models/v_light.mdl");
precache_model("models/p_light.mdl");
#endif
}
void
w_lightning_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, -1, pl.ammo_cells, -1);
}
string
w_lightning_wmodel(void)
{
return "models/g_light.mdl";
}
string
w_lightning_pmodel(player pl)
{
return "models/p_light.mdl";
}
string
w_lightning_deathmsg(void)
{
return "";
}
int
w_lightning_pickup(player pl, int new, int startammo)
{
#ifdef SERVER
if (pl.ammo_cells < MAX_A_CELLS) {
pl.ammo_cells = bound(0, pl.ammo_cells + 15, MAX_A_CELLS);
} else {
if (!new)
return (0);
}
#endif
return (1);
}
void
w_lightning_draw(player pl)
{
Weapons_SetModel("models/v_light.mdl");
Weapons_ViewAnimation(pl, LIGHTNING_IDLE);
}
void
w_lightning_primary(player pl)
{
if (pl.w_attack_next > 0.0)
return;
if (pl.ammo_cells <= 0)
return;
pl.ammo_cells--;
#ifdef SERVER
{
if (pl.WaterLevel() > 1) {
// we're underwater... fry everyone */
} else {
vector startPos = Weapons_GetCameraPos(pl);
Weapons_MakeVectors(pl);
traceline(startPos, startPos + v_forward * 600, MOVE_NORMAL, pl);
WriteByte(MSG_MULTICAST, SVC_TEMPENTITY);
WriteByte(MSG_MULTICAST, TE_LIGHTNING2);
WriteEntity(MSG_MULTICAST, pl);
WriteCoord(MSG_MULTICAST, startPos[0]);
WriteCoord(MSG_MULTICAST, startPos[1]);
WriteCoord(MSG_MULTICAST, startPos[2]);
WriteCoord(MSG_MULTICAST, trace_endpos[0]);
WriteCoord(MSG_MULTICAST, trace_endpos[1]);
WriteCoord(MSG_MULTICAST, trace_endpos[2]);
multicast(startPos, MULTICAST_PHS);
if (trace_ent.takedamage) {
Damage_Apply(trace_ent, pl, Skill_GetValue("plr_crowbar", 10), WEAPON_CROWBAR, DMG_BLUNT);
/* throw players into the air */
if (trace_ent.classname == "player") {
NSClientPlayer tp = (NSClientPlayer)trace_ent;
tp.SetVelocity(tp.GetVelocity() + [0, 0, 400]);
}
}
}
}
Sound_Play(pl, CHAN_WEAPON, "weapon_lightning.start");
#endif
Weapons_ViewAnimation(pl, LIGHTNING_SHOOT);
Animation_PlayerTop(pl, (pl.flags & FL_CROUCHING) ? ANIM_CR_SHOOTGAUSS : ANIM_SHOOTGAUSS, 0.43f);
Weapons_ViewPunchAngle(pl, [-2,0,0]);
pl.w_attack_next = 0.1f;
}
void
w_lightning_crosshair(player pl)
{
#ifdef CLIENT
vector aicon_pos;
Cross_DrawSub(g_cross_spr, [24,24], [72/128,0], [0.1875, 0.1875]);
HUD_DrawAmmo2();
aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42];
drawsubpic(
aicon_pos,
[24,24],
g_hudlgammo,
[0, 0],
[24/24, 24/24],
g_hud_color,
pSeatLocal->m_flAmmo2Alpha,
DRAWFLAG_ADDITIVE
);
#endif
}
float
w_lightning_aimanim(player pl)
{
return pl.flags & FL_CROUCHING ? ANIM_CR_AIMGAUSS : ANIM_AIMGAUSS;
}
int
w_lightning_isempty(player pl)
{
if (pl.ammo_cells <= 0)
return 1;
return 0;
}
void
w_lightning_hudpic(player pl, int selected, vector pos, float a)
{
#ifdef CLIENT
vector hud_col;
if (w_lightning_isempty(pl))
hud_col = [1,0,0];
else
hud_col = g_hud_color;
if (selected) {
drawsubpic(pos, [170,45], g_hudlg_spr, [0,0], [1,0.625], hud_col, a, DRAWFLAG_ADDITIVE);
} else {
drawsubpic(pos, [170,45], g_hudlg_spr, [0,0], [1,0.625], hud_col, a, DRAWFLAG_ADDITIVE);
}
HUD_DrawAmmoBar(pos, pl.ammo_cells, MAX_A_CELLS, a);
#endif
}
weapontype_t
w_lightning_type(player pl)
{
return WPNTYPE_RANGED;
}
weapon_t w_lightning =
{
.name = "lightning",
.id = ITEM_LIGHTNING,
.slot = 7,
.slot_pos = 0,
.weight = 1,
.draw = w_lightning_draw,
.holster = __NULL__,
.primary = w_lightning_primary,
.secondary = __NULL__,
.reload = __NULL__,
.release = __NULL__,
.postdraw = w_lightning_crosshair,
.precache = w_lightning_precache,
.pickup = w_lightning_pickup,
.updateammo = w_lightning_updateammo,
.wmodel = w_lightning_wmodel,
.pmodel = w_lightning_pmodel,
.deathmsg = w_lightning_deathmsg,
.aimanim = w_lightning_aimanim,
.isempty = w_lightning_isempty,
.type = w_lightning_type,
.hudpic = w_lightning_hudpic
};
#ifdef SERVER
void
weapon_lightning(void)
{
Weapons_InitItem(WEAPON_LIGHTNING);
}
#endif

235
src/shared/w_nailgun.qc Normal file
View File

@ -0,0 +1,235 @@
/*
* 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.
*/
/*QUAKED weapon_nailgun (0 0 1) (-16 -16 0) (16 16 32)
"model" "models/g_nail.mdl"
DEATHMATCH CLASSIC (1999) ENTITY
Nailgun
*/
enum
{
NAILGUN_IDLE,
NAILGUN_SHOOT,
};
void
w_nailgun_precache(void)
{
#ifdef SERVER
Sound_Precache("weapon_nailgun.shoot");
precache_model("models/g_nail.mdl");
#else
precache_model("models/v_nail.mdl");
precache_model("models/p_nail.mdl");
#endif
}
int
w_nailgun_pickup(player pl, int new, int startammo)
{
#ifdef SERVER
if (pl.ammo_nails < MAX_A_NAILS) {
pl.ammo_nails = bound(0, pl.ammo_nails + 30, MAX_A_NAILS);
} else {
if (!new)
return (0);
}
#endif
return (1);
}
void
w_nailgun_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, -1, pl.ammo_nails, -1);
}
string
w_nailgun_wmodel(void)
{
return "models/g_nail.mdl";
}
string
w_nailgun_pmodel(player pl)
{
return "models/p_nail.mdl";
}
string
w_nailgun_deathmsg(void)
{
return "";
}
void
w_nailgun_draw(player pl)
{
Weapons_SetModel("models/v_nail.mdl");
Weapons_ViewAnimation(pl, NAILGUN_IDLE);
}
void
w_nailgun_primary(player pl)
{
if (pl.w_attack_next > 0.0)
return;
if (pl.ammo_nails <= 0)
return;
pl.ammo_nails--;
/* Actual firing */
#ifdef CLIENT
#else
{
static void nail_touch(void) {
remove(self);
}
entity nail = spawn();
setmodel(nail, "models/spike.mdl");
setsize(nail, g_vec_null, g_vec_null);
nail.movetype = MOVETYPE_FLYMISSILE;
nail.solid = SOLID_BBOX;
nail.touch = nail_touch;
nail.owner = pl;
Weapons_MakeVectors(pl);
if (pl.ammo_nails & 1) {
setorigin(nail, Weapons_GetCameraPos(pl) + (v_right * -2) + (v_up * -5));
nail.velocity = v_forward * 1000 + (v_right * -2) + (v_up * -5);
} else {
setorigin(nail, Weapons_GetCameraPos(pl) + (v_right * 2) + (v_up * -5));
nail.velocity = v_forward * 1000 + (v_right * 2) + (v_up * -5);
}
nail.angles = vectoangles(nail.velocity);
}
Sound_Play(pl, CHAN_WEAPON, "weapon_nailgun.shoot");
#endif
Weapons_ViewPunchAngle(pl, [-2,0,0]);
Weapons_ViewAnimation(pl, NAILGUN_SHOOT);
Animation_PlayerTop(pl, (pl.flags & FL_CROUCHING) ? ANIM_CR_SHOOTMP5 : ANIM_SHOOTMP5, 0.45f);
pl.w_attack_next = 0.1f;
}
void
w_nailgun_crosshair(player pl)
{
#ifdef CLIENT
vector aicon_pos;
Cross_DrawSub(g_cross_spr, [24,24], [48/128,0], [0.1875, 0.1875]);
HUD_DrawAmmo2();
aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42];
drawsubpic(
aicon_pos,
[24,24],
g_hudngammo,
[0, 0],
[24/24, 24/24],
g_hud_color,
pSeatLocal->m_flAmmo2Alpha,
DRAWFLAG_ADDITIVE
);
#endif
}
float
w_nailgun_aimanim(player pl)
{
return pl.flags & FL_CROUCHING ? ANIM_CR_AIMMP5 : ANIM_AIMMP5;
}
int
w_nailgun_isempty(player pl)
{
if (pl.ammo_nails <= 0)
return 1;
return 0;
}
void
w_nailgun_hudpic(player pl, int selected, vector pos, float a)
{
#ifdef CLIENT
vector hud_col;
if (w_nailgun_isempty(pl))
hud_col = [1,0,0];
else
hud_col = g_hud_color;
if (selected) {
drawsubpic(pos, [170,45], g_hudng_spr, [0,0], [1,0.625], hud_col, a, DRAWFLAG_ADDITIVE);
} else {
drawsubpic(pos, [170,45], g_hudng_spr, [0,0], [1,0.625], hud_col, a, DRAWFLAG_ADDITIVE);
}
HUD_DrawAmmoBar(pos, pl.ammo_nails, MAX_A_NAILS, a);
#endif
}
weapontype_t
w_nailgun_type(player pl)
{
return WPNTYPE_RANGED;
}
weapon_t w_nailgun =
{
.name = "nailgun",
.id = ITEM_NAILGUN,
.slot = 3,
.slot_pos = 0,
.weight = 6,
.draw = w_nailgun_draw,
.holster = __NULL__,
.primary = w_nailgun_primary,
.secondary = __NULL__,
.reload = __NULL__,
.release = __NULL__,
.postdraw = w_nailgun_crosshair,
.precache = w_nailgun_precache,
.pickup = w_nailgun_pickup,
.updateammo = w_nailgun_updateammo,
.wmodel = w_nailgun_wmodel,
.pmodel = w_nailgun_pmodel,
.deathmsg = w_nailgun_deathmsg,
.aimanim = w_nailgun_aimanim,
.isempty = w_nailgun_isempty,
.type = w_nailgun_type,
.hudpic = w_nailgun_hudpic
};
/* pickups */
#ifdef SERVER
void
weapon_nailgun(void)
{
Weapons_InitItem(WEAPON_NAILGUN);
}
#endif

View File

@ -0,0 +1,236 @@
/*
* 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.
*/
/*QUAKED weapon_rocketlauncher (0 0 1) (-16 -16 0) (16 16 32)
"model" "models/g_rock2.mdl"
HALF-LIFE (1998) ENTITY
RPG Weapon
*/
enum
{
RPG_IDLE,
RPG_SHOOT
};
void
w_rocketlauncher_precache(void)
{
#ifdef SERVER
Sound_Precache("weapon_rocketlauncher.shoot");
precache_model("models/g_rock2.mdl");
precache_model("models/rocket.mdl");
#else
precache_model("models/v_rock2.mdl");
precache_model("models/p_rock2.mdl");
#endif
}
void
w_rocketlauncher_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, -1, pl.ammo_rockets, -1);
}
string
w_rocketlauncher_wmodel(void)
{
return "models/g_rock2.mdl";
}
string
w_rocketlauncher_pmodel(player pl)
{
return "models/p_rock2.mdl";
}
string
w_rocketlauncher_deathmsg(void)
{
return "";
}
int
w_rocketlauncher_pickup(player pl, int new, int startammo)
{
#ifdef SERVER
if (pl.ammo_rockets < MAX_A_ROCKETS) {
pl.ammo_rockets = bound(0, pl.ammo_rockets + 5, MAX_A_ROCKETS);
} else {
if (!new)
return (0);
}
#endif
return (1);
}
void
w_rocketlauncher_draw(player pl)
{
Weapons_SetModel("models/v_rock2.mdl");
Weapons_ViewAnimation(pl, RPG_IDLE);
}
void
w_rocketlauncher_primary(player pl)
{
if (pl.w_attack_next > 0.0)
return;
if (pl.ammo_rockets <= 0)
return;
/* visual fluff */
Weapons_ViewAnimation(pl, RPG_SHOOT);
Weapons_ViewPunchAngle(pl, [-10,0,0]);
Animation_PlayerTop(pl, (pl.flags & FL_CROUCHING) ? ANIM_CR_SHOOTGAUSS : ANIM_SHOOTGAUSS, 0.43f);
pl.w_attack_next = 0.8f;
pl.ammo_rockets--;
#ifdef SERVER
static void Rocket_Touch(void) {
float dmg = Skill_GetValue("plr_rocketlauncher_dmg", 100);
FX_Explosion(self.origin);
Damage_Radius(self.origin, self.owner, dmg, dmg * 2.5f, TRUE, WEAPON_ROCKETLAUNCHER);
sound(self, CHAN_WEAPON, sprintf("weapons/explode%d.wav", floor(random() * 2) + 3), 1, ATTN_NORM);
remove(self);
}
Weapons_MakeVectors(pl);
entity rocket = spawn();
setmodel(rocket, "models/rocket.mdl");
setorigin(rocket, Weapons_GetCameraPos(pl) + (v_forward * 16));
rocket.owner = pl;
rocket.movetype = MOVETYPE_FLYMISSILE;
rocket.solid = SOLID_BBOX;
rocket.velocity = (pl.WaterLevel() >= WATERLEVEL_SUBMERGED) ? (v_forward * 100): (v_forward * 1000);
rocket.angles = vectoangles(rocket.velocity);
rocket.avelocity[2] = 10;
rocket.touch = Rocket_Touch;
rocket.traileffectnum = particleeffectnum("weapon_rpg.trail");
setsize(rocket, [0,0,0], [0,0,0]);
Sound_Play(pl, CHAN_WEAPON, "weapon_rocketlauncher.shoot");
#endif
}
float
w_rocketlauncher_aimanim(player pl)
{
return pl.flags & FL_CROUCHING ? ANIM_CR_AIMGAUSS : ANIM_AIMGAUSS;
}
int
w_rocketlauncher_isempty(player pl)
{
if (pl.ammo_rockets <= 0)
return 1;
return 0;
}
void
w_rocketlauncher_hudpic(player pl, int selected, vector pos, float a)
{
#ifdef CLIENT
vector hud_col;
if (w_rocketlauncher_isempty(pl))
hud_col = [1,0,0];
else
hud_col = g_hud_color;
if (selected) {
drawsubpic(pos, [170,45], g_hudrl_spr, [0,0], [1,0.625], hud_col, a, DRAWFLAG_ADDITIVE);
} else {
drawsubpic(pos, [170,45], g_hudrl_spr, [0,0], [1,0.625], hud_col, a, DRAWFLAG_ADDITIVE);
}
HUD_DrawAmmoBar(pos, pl.ammo_rockets, MAX_A_ROCKETS, a);
#endif
}
void
w_rocketlauncher_hud(player pl)
{
#ifdef CLIENT
vector laser_pos;
vector aicon_pos;
Cross_DrawSub(g_cross_spr, [24,24], [24/128,48/128], [0.1875, 0.1875]);
/* ammo counters */
HUD_DrawAmmo2();
/* ammo icon */
aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42];
drawsubpic(
aicon_pos,
[24,24],
g_hudrlammo,
[0, 0],
[24/24, 24/24],
g_hud_color,
pSeatLocal->m_flAmmo2Alpha,
DRAWFLAG_ADDITIVE
);
#endif
}
weapontype_t
w_rocketlauncher_type(player pl)
{
return WPNTYPE_RANGED;
}
weapon_t
w_rocketlauncher =
{
.name = "rocketl",
.id = ITEM_ROCKETLAUNCHER,
.slot = 6,
.slot_pos = 0,
.weight = 2,
.draw = w_rocketlauncher_draw,
.holster = __NULL__,
.primary = w_rocketlauncher_primary,
.secondary = __NULL__,
.reload = __NULL__,
.release = __NULL__,
.postdraw = w_rocketlauncher_hud,
.precache = w_rocketlauncher_precache,
.pickup = w_rocketlauncher_pickup,
.updateammo = w_rocketlauncher_updateammo,
.wmodel = w_rocketlauncher_wmodel,
.pmodel = w_rocketlauncher_pmodel,
.deathmsg = w_rocketlauncher_deathmsg,
.aimanim = w_rocketlauncher_aimanim,
.isempty = w_rocketlauncher_isempty,
.type = w_rocketlauncher_type,
.hudpic = w_rocketlauncher_hudpic
};
#ifdef SERVER
void
weapon_rocketlauncher(void)
{
Weapons_InitItem(WEAPON_ROCKETLAUNCHER);
}
#endif

234
src/shared/w_shotgun.qc Normal file
View File

@ -0,0 +1,234 @@
/*
* 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.
*/
/*QUAKED weapon_shotgun (0 0 1) (-16 -16 0) (16 16 32)
"model" "models/g_shotgun.mdl"
HALF-LIFE (1998) ENTITY
Shotgun Weapon
*/
enum
{
SHOTGUN_IDLE1,
SHOTGUN_FIRE1
};
#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, "modelevent_shotgunshell.land");
}
entity eShell = spawn();
setmodel(eShell, "models/shotgunshell.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 * 20) + (v_up * -16));
}
#endif
void w_shotgun_precache(void)
{
#ifdef SERVER
Sound_Precache("weapon_shotgun.shoot");
precache_model("models/g_shot.mdl");
precache_model("models/shotgunshell.mdl");
#else
precache_model("models/v_shot.mdl");
precache_model("models/p_shot.mdl");
precache_model("models/shotgunshell.mdl");
Sound_Precache("modelevent_shotgunshell.land");
#endif
}
void
w_shotgun_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, -1, pl.ammo_shells, -1);
}
string
w_shotgun_wmodel(void)
{
return "models/g_shot.mdl";
}
string
w_shotgun_pmodel(player pl)
{
return "models/p_shot.mdl";
}
string
w_shotgun_deathmsg(void)
{
return "";
}
int
w_shotgun_pickup(player pl, int new, int startammo)
{
#ifdef SERVER
if (pl.ammo_shells < MAX_A_SHELLS) {
pl.ammo_shells = bound(0, pl.ammo_shells + 5, MAX_A_SHELLS);
} else {
if (!new)
return (0);
}
#endif
return (1);
}
void
w_shotgun_draw(player pl)
{
Weapons_SetModel("models/v_shot.mdl");
}
void
w_shotgun_primary(player pl)
{
if (pl.w_attack_next > 0.0)
return;
if (pl.ammo_shells <= 0)
return;
#ifdef SERVER
/* Singleplayer is more accurate */
TraceAttack_FireBulletsWithDecal(6, pl.origin + pl.view_ofs, Skill_GetValue("plr_shotgun_dmg", 4), [0.1,0.1], WEAPON_SHOTGUN, "Impact.BigShot");
Sound_Play(pl, CHAN_WEAPON, "weapon_shotgun.shoot");
#else
//View_AddEvent(w_shotgun_ejectshell, 0.25f);
#endif
Weapons_ViewAnimation(pl, SHOTGUN_FIRE1);
Weapons_ViewPunchAngle(pl, [-5,0,0]);
Animation_PlayerTop(pl, (pl.flags & FL_CROUCHING) ? ANIM_CR_SHOOTSHOTGUN : ANIM_SHOOTSHOTGUN, 0.5f);
pl.ammo_shells--;
pl.w_idle_next = 0.5f;
pl.w_attack_next = 0.5;
}
void
w_shotgun_crosshair(player pl)
{
#ifdef CLIENT
Cross_DrawSub(g_cross_spr, [24,24], [48/128,24/128], [0.1875, 0.1875]);
HUD_DrawAmmo2();
vector aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42];
drawsubpic(aicon_pos, [24,24], g_hudsgammo, [0, 0], [1,1], g_hud_color, pSeatLocal->m_flAmmo2Alpha, DRAWFLAG_ADDITIVE);
#endif
}
float
w_shotgun_aimanim(player pl)
{
return pl.flags & FL_CROUCHING ? ANIM_CR_AIMSHOTGUN : ANIM_AIMSHOTGUN;
}
int
w_shotgun_isempty(player pl)
{
if (pl.ammo_shells <= 0)
return 1;
return 0;
}
void
w_shotgun_hudpic(player pl, int selected, vector pos, float a)
{
#ifdef CLIENT
vector hud_col;
if (w_shotgun_isempty(pl))
hud_col = [1,0,0];
else
hud_col = g_hud_color;
if (selected) {
drawsubpic(pos, [170,45], g_hudsg_spr, [0,0], [1,0.625], hud_col, a, DRAWFLAG_ADDITIVE);
} else {
drawsubpic(pos, [170,45], g_hudsg_spr, [0,0], [1,0.625], hud_col, a, DRAWFLAG_ADDITIVE);
}
HUD_DrawAmmoBar(pos, pl.ammo_shells, MAX_A_SHELLS, a);
#endif
}
weapontype_t
w_shotgun_type(player pl)
{
return WPNTYPE_RANGED;
}
weapon_t w_shotgun =
{
.name = "shotgun",
.id = ITEM_SHOTGUN,
.slot = 1,
.slot_pos = 0,
.weight = 15,
.draw = w_shotgun_draw,
.holster = __NULL__,
.primary = w_shotgun_primary,
.secondary = __NULL__,
.reload = __NULL__,
.release = __NULL__,
.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
};
#ifdef SERVER
void
weapon_shotgun(void)
{
Weapons_InitItem(WEAPON_SHOTGUN);
}
#endif

View File

@ -0,0 +1,219 @@
/*
* 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.
*/
/*QUAKED weapon_supernailgun (0 0 1) (-16 -16 0) (16 16 32)
"model" "models/g_nail2.mdl"
HALF-LIFE (1998) ENTITY
MP5/9mmAR Weapon
Same as weapon_9mmAR
*/
/* Animations */
enum
{
SUPERNAIL_IDLE,
SUPERNAIL_SHOOT
};
void
w_supernailgun_precache(void)
{
#ifdef SERVER
Sound_Precache("weapon_supernailgun.shoot");
precache_model("models/g_nail2.mdl");
precache_model("models/spike.mdl");
#else
precache_model("models/v_nail2.mdl");
precache_model("models/p_nail2.mdl");
Sound_Precache("modelevent_shell.land");
#endif
}
int
w_supernailgun_pickup(player pl, int new, int startammo)
{
#ifdef SERVER
if (pl.ammo_nails < MAX_A_NAILS) {
pl.ammo_nails = bound(0, pl.ammo_nails + 30, MAX_A_NAILS);
} else {
if (!new)
return (0);
}
#endif
return (1);
}
void
w_supernailgun_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, -1, pl.ammo_nails, -1);
}
string
w_supernailgun_wmodel(void)
{
return "models/g_nail2.mdl";
}
string
w_supernailgun_pmodel(player pl)
{
return "models/p_nail2.mdl";
}
string
w_supernailgun_deathmsg(void)
{
return "";
}
void
w_supernailgun_draw(player pl)
{
Weapons_SetModel("models/v_nail2.mdl");
Weapons_ViewAnimation(pl, SUPERNAIL_IDLE);
}
void
w_supernailgun_primary(player pl)
{
if (pl.w_attack_next > 0.0f)
return;
pl.ammo_nails--;
Weapons_ViewAnimation(pl, SUPERNAIL_SHOOT);
Weapons_ViewPunchAngle(pl, [-2,0,0]);
Animation_PlayerTop(pl, (pl.flags & FL_CROUCHING) ? ANIM_CR_SHOOTMP5 : ANIM_SHOOTMP5, 0.1f);
#ifdef CLIENT
#else
{
static void nail_touch(void) {
remove(self);
}
entity nail = spawn();
setmodel(nail, "models/spike.mdl");
setorigin(nail, Weapons_GetCameraPos(pl) + (v_up * -5));
setsize(nail, g_vec_null, g_vec_null);
nail.movetype = MOVETYPE_FLYMISSILE;
nail.solid = SOLID_BBOX;
nail.touch = nail_touch;
nail.owner = pl;
Weapons_MakeVectors(pl);
nail.velocity = v_forward * 1000 + (v_up * -5);
nail.angles = vectoangles(nail.velocity);
}
Sound_Play(pl, CHAN_WEAPON, "weapon_supernailgun.shoot");
#endif
pl.w_attack_next = 0.085f;
pl.w_idle_next = 10.0f;
}
void
w_supernailgun_crosshair(player pl)
{
#ifdef CLIENT
vector aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42];
Cross_DrawSub(g_cross_spr, [24,24], [0,48/128], [0.1875, 0.1875]);
HUD_DrawAmmo2();
drawsubpic(aicon_pos, [24,24], g_hudsngammo, [0, 0], [1,1], g_hud_color, pSeatLocal->m_flAmmo2Alpha, DRAWFLAG_ADDITIVE);
#endif
}
float
w_supernailgun_aimanim(player pl)
{
return pl.flags & ANIM_CR_AIMMP5 ? ANIM_CR_AIMCROWBAR : ANIM_AIMMP5;
}
int
w_supernailgun_isempty(player pl)
{
if (pl.ammo_nails <= 0)
return 1;
return 0;
}
void
w_supernailgun_hudpic(player pl, int selected, vector pos, float a)
{
#ifdef CLIENT
vector hud_col;
if (w_supernailgun_isempty(pl))
hud_col = [1,0,0];
else
hud_col = g_hud_color;
if (selected) {
drawsubpic(pos, [170,45], g_hudsng_spr, [0,0], [1,0.625], hud_col, a, DRAWFLAG_ADDITIVE);
} else {
drawsubpic(pos, [170,45], g_hudsng_spr, [0,0], [1,0.625], hud_col, a, DRAWFLAG_ADDITIVE);
}
HUD_DrawAmmoBar(pos, pl.ammo_nails, MAX_A_NAILS, a);
#endif
}
weapontype_t
w_supernailgun_type(player pl)
{
return WPNTYPE_RANGED;
}
weapon_t w_supernailgun =
{
.name = "supernail",
.id = ITEM_SUPERNAILGUN,
.slot = 4,
.slot_pos = 0,
.weight = 3,
.draw = w_supernailgun_draw,
.holster = __NULL__,
.primary = w_supernailgun_primary,
.secondary = __NULL__,
.reload = __NULL__,
.release = __NULL__,
.postdraw = w_supernailgun_crosshair,
.precache = w_supernailgun_precache,
.pickup = w_supernailgun_pickup,
.updateammo = w_supernailgun_updateammo,
.wmodel = w_supernailgun_wmodel,
.pmodel = w_supernailgun_pmodel,
.deathmsg = w_supernailgun_deathmsg,
.aimanim = w_supernailgun_aimanim,
.isempty = w_supernailgun_isempty,
.type = w_supernailgun_type,
.hudpic = w_supernailgun_hudpic
};
#ifdef SERVER
void
weapon_supernailgun(void)
{
Weapons_InitItem(WEAPON_SUPERNAILGUN);
}
#endif

View File

@ -0,0 +1,252 @@
/*
* 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.
*/
/*QUAKED weapon_9mmhandgun (0 0 1) (-16 -16 0) (16 16 32)
"model" "models/g_shot2.mdl"
HALF-LIFE (1998) ENTITY
9mm Handgun/Glock Weapon
Same as weapon_glock
*/
/*QUAKED weapon_glock (0 0 1) (-16 -16 0) (16 16 32)
"model" "models/g_shot2.mdl"
HALF-LIFE (1998) ENTITY
9mm Handgun/Glock Weapon
Same as weapon_9mmhandgun
*/
enum
{
SUPERSHOT_IDLE,
SUPERSHOT_SHOOT,
};
#ifdef CLIENT
void w_supershotgun_ejectshell(void)
{
static void w_supershotgun_ejectshell_death(void) {
remove(self);
}
static void w_supershotgun_ejectshell_touch(void) {
if (other == world)
Sound_Play(self, CHAN_BODY, "modelevent_shell.land");
}
entity eShell = spawn();
setmodel(eShell, "models/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_supershotgun_ejectshell_touch;
eShell.avelocity = [0,45,900];
eShell.think = w_supershotgun_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_supershotgun_precache(void)
{
#ifdef SERVER
Sound_Precache("weapon_supershotgun.shoot");
precache_model("models/g_shot2.mdl");
precache_model("models/shell.mdl");
#else
precache_model("models/v_shot2.mdl");
precache_model("models/p_shot2.mdl");
precache_model("models/shell.mdl");
Sound_Precache("modelevent_shell.land");
#endif
}
void
w_supershotgun_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, -1, pl.ammo_shells, -1);
}
string
w_supershotgun_wmodel(void)
{
return "models/g_shot2.mdl";
}
string
w_supershotgun_pmodel(player pl)
{
return "models/p_shot2.mdl";
}
string
w_supershotgun_deathmsg(void)
{
return "";
}
int
w_supershotgun_pickup(player pl, int new, int startammo)
{
#ifdef SERVER
if (pl.ammo_shells < MAX_A_SHELLS) {
pl.ammo_shells = bound(0, pl.ammo_shells + 5, MAX_A_SHELLS);
} else {
if (!new)
return (0);
}
#endif
return (1);
}
void
w_supershotgun_draw(player pl)
{
Weapons_SetModel("models/v_shot2.mdl");
Weapons_ViewAnimation(pl, SUPERSHOT_IDLE);
}
void
w_supershotgun_primary(player pl)
{
if (pl.w_attack_next > 0.0)
return;
if (pl.ammo_shells < 2)
return;
/* actual firing */
pl.ammo_shells -= 2;
#ifdef CLIENT
View_AddEvent(w_supershotgun_ejectshell, 0.0f);
#else
TraceAttack_FireBulletsWithDecal(14, pl.origin + pl.view_ofs, Skill_GetValue("plr_supershotgun_dmg", 4), [0.14,0.08], WEAPON_SUPERSHOTGUN, "Impact.BigShot");
Sound_Play(pl, CHAN_WEAPON, "weapon_supershotgun.shoot");
#endif
Weapons_ViewPunchAngle(pl, [-2,0,0]);
Weapons_ViewAnimation(pl, SUPERSHOT_SHOOT);
Animation_PlayerTop(pl, (pl.flags & FL_CROUCHING) ? ANIM_CR_SHOOTSHOTGUN : ANIM_SHOOTSHOTGUN, 0.5f);
pl.w_attack_next = 0.7f;
}
float
w_supershotgun_aimanim(player pl)
{
return pl.flags & FL_CROUCHING ? ANIM_CR_AIMSHOTGUN : ANIM_AIMSHOTGUN;
}
void
w_supershotgun_hud(player pl)
{
#ifdef CLIENT
vector aicon_pos;
aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42];
Cross_DrawSub(g_cross_spr, [24,24], [0.1875,0], [0.1875, 0.1875]);
HUD_DrawAmmo2();
drawsubpic(aicon_pos, [24,24], g_hudssgammo, [0, 0], [1,1], g_hud_color, pSeatLocal->m_flAmmo2Alpha, DRAWFLAG_ADDITIVE);
#endif
}
int
w_supershotgun_isempty(player pl)
{
if (pl.ammo_shells <= 0)
return 1;
return 0;
}
void
w_supershotgun_hudpic(player pl, int selected, vector pos, float a)
{
#ifdef CLIENT
vector hud_col;
if (w_supershotgun_isempty(pl))
hud_col = [1,0,0];
else
hud_col = g_hud_color;
if (selected) {
drawsubpic(pos, [170,45], g_hudssg_spr, [0,0], [1,0.625], hud_col, a, DRAWFLAG_ADDITIVE);
} else {
drawsubpic(pos, [170,45], g_hudssg_spr, [0,0], [1,0.625], hud_col, a, DRAWFLAG_ADDITIVE);
}
HUD_DrawAmmoBar(pos, pl.ammo_shells, MAX_A_SHELLS, a);
#endif
}
weapontype_t
w_supershotgun_type(player pl)
{
return WPNTYPE_RANGED;
}
weapon_t w_supershotgun =
{
.name = "doubleshotgun",
.id = ITEM_SUPERSHOTGUN,
.slot = 2,
.slot_pos = 0,
.weight = 5,
.draw = w_supershotgun_draw,
.holster = __NULL__,
.primary = w_supershotgun_primary,
.secondary = __NULL__,
.reload = __NULL__,
.release = __NULL__,
.postdraw = w_supershotgun_hud,
.precache = w_supershotgun_precache,
.pickup = w_supershotgun_pickup,
.updateammo = w_supershotgun_updateammo,
.wmodel = w_supershotgun_wmodel,
.pmodel = w_supershotgun_pmodel,
.deathmsg = w_supershotgun_deathmsg,
.aimanim = w_supershotgun_aimanim,
.isempty = w_supershotgun_isempty,
.type = w_supershotgun_type,
.hudpic = w_supershotgun_hudpic
};
/* pickups */
#ifdef SERVER
void
weapon_supershotgun(void)
{
Weapons_InitItem(WEAPON_SUPERSHOTGUN);
}
#endif

34
src/shared/weapons.h Normal file
View File

@ -0,0 +1,34 @@
/*
* 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 Indices for the weapon table */
enum
{
WEAPON_NONE,
WEAPON_CROWBAR,
WEAPON_SHOTGUN,
WEAPON_SUPERSHOTGUN,
WEAPON_NAILGUN,
WEAPON_SUPERNAILGUN,
WEAPON_GRENADELAUNCHER,
WEAPON_ROCKETLAUNCHER,
WEAPON_LIGHTNING,
};
#define MAX_A_SHELLS 100
#define MAX_A_NAILS 200
#define MAX_A_ROCKETS 100
#define MAX_A_CELLS 100

28
src/shared/weapons.qc Normal file
View File

@ -0,0 +1,28 @@
/*
* 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_shotgun,
w_supershotgun,
w_nailgun,
w_supernailgun,
w_grenadelauncher,
w_rocketlauncher,
w_lightning
};

View File

@ -0,0 +1,19 @@
armor.pickup
{
}
armor.respawn
{
}
ammo.pickup
{
}
ammo.respawn
{
}

View File

@ -0,0 +1,65 @@
weapon_crowbar.swing
{
alerts
sample weapons/ax1.wav
}
weapon_crowbar.hitbody
{
alerts
sample player/axhit1.wav
}
weapon_crowbar.hit
{
alerts
sample player/axhit2.wav
}
weapon_shotgun.shoot
{
alerts
sample weapons/guncock.wav
}
weapon_supershotgun.shoot
{
alerts
sample weapons/shotgn2.wav
}
weapon_nailgun.shoot
{
alerts
sample weapons/rocket1i.wav
}
weapon_supernailgun.shoot
{
alerts
sample weapons/spike2.wav
}
weapon_grenadelauncher.shoot
{
alerts
sample weapons/grenade.wav
}
weapon_grenadelauncher.bounce
{
alerts
sample weapons/bounce.wav
}
weapon_rocketlauncher.shoot
{
alerts
sample weapons/sgun1.wav
}
weapon_lightning.start
{
alerts
sample weapons/lstart.wav
}