Initial commit of the fixed codebase

This commit is contained in:
Marco Cawthorne 2021-02-11 19:06:14 +01:00
commit 542bc73bef
48 changed files with 5979 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

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

@ -0,0 +1,26 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <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
Game_Entity_Update(float id, float new)
{
switch (id) {
default:
return FALSE;
}
return TRUE;
}

154
src/client/game_event.qc Normal file
View file

@ -0,0 +1,154 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
void
Game_Parse_Event(float fHeader)
{
switch (fHeader) {
case EV_OBITUARY:
Obituary_Parse();
break;
case EV_SPARK:
vector vSparkPos, vSparkAngle;
vSparkPos[0] = readcoord();
vSparkPos[1] = readcoord();
vSparkPos[2] = readcoord();
vSparkAngle[0] = readcoord();
vSparkAngle[1] = readcoord();
vSparkAngle[2] = readcoord();
FX_Spark(vSparkPos, vSparkAngle);
break;
case EV_GIBHUMAN:
vector vGibPos;
vGibPos[0] = readcoord();
vGibPos[1] = readcoord();
vGibPos[2] = readcoord();
FX_GibHuman(vGibPos);
break;
case EV_BLOOD:
vector vBloodPos;
vector vBloodColor;
vBloodPos[0] = readcoord();
vBloodPos[1] = readcoord();
vBloodPos[2] = readcoord();
vBloodColor[0] = readbyte() / 255;
vBloodColor[1] = readbyte() / 255;
vBloodColor[2] = readbyte() / 255;
FX_Blood(vBloodPos, vBloodColor);
break;
case EV_LEGO:
vector vLegoPos;
vLegoPos[0] = readcoord();
vLegoPos[1] = readcoord();
vLegoPos[2] = readcoord();
FX_Lego(vLegoPos);
break;
case EV_LEGOPIECE:
vector vLegoPiecePos;
vLegoPiecePos[0] = readcoord();
vLegoPiecePos[1] = readcoord();
vLegoPiecePos[2] = readcoord();
FX_LegoPiece(vLegoPiecePos);
break;
case EV_SODA:
vector vSodaPos;
int vSodaColor;
vSodaPos[0] = readcoord();
vSodaPos[1] = readcoord();
vSodaPos[2] = readcoord();
vSodaColor = readbyte();
FX_Soda(vSodaPos, vSodaColor);
break;
case EV_EXPLOSION:
vector vExploPos;
vExploPos[0] = readcoord();
vExploPos[1] = readcoord();
vExploPos[2] = readcoord();
FX_Explosion(vExploPos);
break;
case EV_MODELGIB:
vector vecPos;
vecPos[0] = readcoord();
vecPos[1] = readcoord();
vecPos[2] = readcoord();
vector vSize;
vSize[0] = readcoord();
vSize[1] = readcoord();
vSize[2] = readcoord();
float fStyle = readbyte();
int count = readbyte();
FX_BreakModel(count, vecPos, vSize, [0,0,0], fStyle);
break;
case EV_IMPACT:
int iType;
vector vOrigin, vNormal;
iType = (int)readbyte();
vOrigin[0] = readcoord();
vOrigin[1] = readcoord();
vOrigin[2] = readcoord();
vNormal[0] = readcoord();
vNormal[1] = readcoord();
vNormal[2] = readcoord();
FX_Impact(iType, vOrigin, vNormal);
break;
case EV_CHAT:
float fSender = readbyte();
float fTeam = readbyte();
string sMessage = readstring();
CSQC_Parse_Print(sprintf("%s: %s", getplayerkeyvalue(fSender, "name"), sMessage), PRINT_CHAT);
break;
case EV_CHAT_TEAM:
float fSender2 = readbyte();
float fTeam2 = readbyte();
string sMessage2 = readstring();
CSQC_Parse_Print(sprintf("[TEAM] %s: %s", getplayerkeyvalue(fSender2, "name"), sMessage2), PRINT_CHAT);
break;
case EV_CHAT_VOX:
Vox_Play(readstring());
break;
case EV_VIEWMODEL:
View_PlayAnimation(readbyte());
break;
case EV_WEAPON_PICKUP:
int w = readbyte();
if (autocvar_cl_autoweaponswitch == 1) {
sendevent("PlayerSwitchWeapon", "i", w);
}
HUD_WeaponPickupNotify(w);
break;
}
}

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

@ -0,0 +1,395 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <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 HUD_NUMS "sprites/640_numbers.spr_0.tga"
#define NUMSIZE_X 32/256
#define NUMSIZE_Y 32/64
#define HUD_ALPHA 1.0
vector spr_hudnum[10] = {
[0 / 256, 0],
[32 / 256, 0],
[(32*2) / 256, 0],
[(32*3) / 256, 0],
[(32*4) / 256, 0],
[(32*5) / 256, 0],
[(32*6) / 256, 0],
[(32*7) / 256, 0],
[0 / 256, 32/64],
[32 / 256, 32/64]
};
/* pre-calculated sprite definitions */
float spr_health[4] = {
80 / 256, // pos x
24 / 128, // pos y
32 / 256, // size x
32 / 128 // size y
};
#define HUD_SUIT "sprites/640_suit.spr_0.tga"
#define SUITSIZE_X 32/128
#define SUITSIZE_Y 32/64
float spr_suit1[4] = {
0 / 128, // pos x
0 / 128, // pos y
40 / 128, // size x
40 / 64 // size y
};
float spr_suit2[4] = {
40 / 128, // pos x
0 / 128, // pos y
40 / 128, // size x
40 / 64 // size y
};
#define HUD_FLASH "sprites/640hud7.spr_0.tga"
#define FLASHSIZE_X 24/256
#define FLASHSIZE_Y 24/128
float spr_flash1[4] = {
160 / 256, // pos x
24 / 128, // pos y
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)
{
precache_model("sprites/640_cross.spr");
precache_model("sprites/640_numbers.spr");
precache_model("sprites/640_logo.spr");
precache_model("sprites/640_suit.spr");
precache_model("sprites/640hud7.spr");
}
/* handle single/multiple digits */
void
HUD_DrawNumber(int iNumber, vector vecPos, float fAlpha, vector vColor)
{
drawsubpic(vecPos,
[32,32],
"sprites/640_numbers.spr_0.tga",
spr_hudnum[iNumber],
[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, vecPos, fAlpha, vColor);
i = i / 10;
vecPos[0] -= 32;
}
} else {
HUD_DrawNumber(0, vecPos, fAlpha, vColor);
}
}
/* health */
/* We don't need the changing color if case
* it's always red in Household DEATH! */
void
HUD_DrawHealth(void)
{
vector pos;
player pl = (player)pSeat->m_ePlayer;
if (pl.health != pSeat->m_iHealthOld) {
pSeat->m_flHealthAlpha = 1.0;
}
if (pSeat->m_flHealthAlpha >= HUD_ALPHA) {
pSeat->m_flHealthAlpha -= clframetime * 0.5;
} else {
pSeat->m_flHealthAlpha = HUD_ALPHA;
}
pos = g_hudmins + [14, g_hudres[1] - 42];
drawpic(
pos,
"sprites/640_cross.spr_0.tga",
[32,32],
[1,1,1],
pSeat->m_flHealthAlpha
);
HUD_DrawNums(pl.health, pos + [96], pSeat->m_flHealthAlpha, g_hud_color);
pSeat->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 != pSeat->m_iArmorOld) {
pSeat->m_flArmorAlpha = 1.0;
}
if (pSeat->m_flArmorAlpha >= HUD_ALPHA) {
pSeat->m_flArmorAlpha -= clframetime * 0.5;
} else {
pSeat->m_flArmorAlpha = HUD_ALPHA;
}
drawsubpic(
pos + [-48,-9],
[40,40],
HUD_SUIT,
[spr_suit2[0], spr_suit2[1]],
[spr_suit2[2], spr_suit2[3]],
[1,1,1],
1.0f
);
if (pl.armor > 0) {
drawsubpic(
pos + [-48,-9],
[40, 40 * (pl.armor / 100)],
HUD_SUIT,
[spr_suit1[0],
spr_suit1[1]],
[spr_suit1[2], spr_suit1[3] * (pl.armor / 100)],
[1,1,1],
1.0f
);
}
HUD_DrawNums(pl.armor, pos + [48] , pSeat->m_flArmorAlpha, g_hud_color);
pSeat->m_iArmorOld = pl.armor;
}
/* magazine/clip ammo */
void
HUD_DrawAmmo1(void)
{
player pl = (player)pSeat->m_ePlayer;
vector pos;
if (pl.a_ammo1 != pSeat->m_iAmmo1Old) {
pSeat->m_flAmmo1Alpha = 1.0;
pSeat->m_iAmmo1Old = pl.a_ammo1;
}
if (pSeat->m_flAmmo1Alpha >= HUD_ALPHA) {
pSeat->m_flAmmo1Alpha -= clframetime * 0.5;
} else {
pSeat->m_flAmmo1Alpha = HUD_ALPHA;
}
pos = g_hudmins + [g_hudres[0] - 152, g_hudres[1] - 42];
HUD_DrawNums(pl.a_ammo1, pos, pSeat->m_flAmmo1Alpha, g_hud_color);
}
/* leftover type ammo */
void
HUD_DrawAmmo2(void)
{
player pl = (player)pSeat->m_ePlayer;
vector pos;
if (pl.a_ammo2 != pSeat->m_iAmmo2Old) {
pSeat->m_flAmmo2Alpha = 1.0;
pSeat->m_iAmmo2Old = pl.a_ammo2;
}
if (pSeat->m_flAmmo2Alpha >= HUD_ALPHA) {
pSeat->m_flAmmo2Alpha -= clframetime * 0.5;
} else {
pSeat->m_flAmmo2Alpha = HUD_ALPHA;
}
pos = g_hudmins + [g_hudres[0] - 72, g_hudres[1] - 42];
HUD_DrawNums(pl.a_ammo2, pos, pSeat->m_flAmmo2Alpha, g_hud_color);
}
/* special ammo */
void
HUD_DrawAmmo3(void)
{
player pl = (player)pSeat->m_ePlayer;
vector pos;
if (pl.a_ammo3 != pSeat->m_iAmmo3Old) {
pSeat->m_flAmmo3Alpha = 1.0;
pSeat->m_iAmmo3Old = pl.a_ammo3;
}
if (pSeat->m_flAmmo3Alpha >= HUD_ALPHA) {
pSeat->m_flAmmo3Alpha -= clframetime * 0.5;
} else {
pSeat->m_flAmmo3Alpha = HUD_ALPHA;
}
pos = g_hudmins + [g_hudres[0] - 72, g_hudres[1] - 74];
HUD_DrawNums(pl.a_ammo3, pos, pSeat->m_flAmmo3Alpha, g_hud_color);
}
/* 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],
HUD_FLASH,
[spr_flash1[0], spr_flash1[1]],
[spr_flash1[2], spr_flash1[3]],
g_hud_color,
1.0f,
DRAWFLAG_ADDITIVE
);
drawsubpic(
pos,
[48,32],
HUD_FLASH,
[spr_flash2[0], spr_flash2[1]],
[spr_flash2[2], spr_flash2[3]],
g_hud_color,
1.0f,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[32,32],
HUD_FLASH,
[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)
{
vector pos;
if (pSeat->m_flPickupAlpha <= 0.0f) {
return;
}
pos = g_hudmins + [g_hudres[0] - 192, g_hudres[1] - 128];
Weapons_HUDPic(pSeat->m_iPickupWeapon, 1, pos, pSeat->m_flPickupAlpha);
pSeat->m_flPickupAlpha -= clframetime;
}
void
HUD_WeaponPickupNotify(int w)
{
pSeat->m_iPickupWeapon = w;
pSeat->m_flPickupAlpha = 1.0f;
}
/* main entry */
void
HUD_Draw(void)
{
player pl = (player)pSeat->m_ePlayer;
g_hud_color = autocvar_con_color * (1 / 255);
/* little point in not drawing these, even if you don't have a suit */
Weapons_DrawCrosshair();
HUD_DrawWeaponSelect();
Obituary_Draw();
if (!(pl.g_items & ITEM_SUIT)) {
return;
}
HUD_DrawHealth();
HUD_DrawArmor();
HUD_DrawFlashlight();
HUD_DrawNotify();
Damage_Draw();
}
/* specatator main entry */
void
HUD_DrawSpectator(void)
{
// FIXME
}

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

@ -0,0 +1,55 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
float(entity foo, float chanid) getchannellevel = #0;
/*
=================
Client_Init
Comparable to worldspawn in SSQC in that it's mostly used for precaches
=================
*/
void
Client_Init(float apilevel, string enginename, float engineversion)
{
}
void
Client_InitDone(void)
{
Obituary_Init();
}
void
Game_RendererRestarted(string rstr)
{
FX_Blood_Init();
FX_BreakModel_Init();
FX_Explosion_Init();
FX_GibHuman_Init();
FX_Spark_Init();
FX_Impact_Init();
FX_Lego_Init();
FX_Soda_Init();
precache_model("sprites/640_death.spr");
precache_model("sprites/640_cross.spr");
precache_model("sprites/640_numbers.spr");
precache_model("sprites/640_suit.spr");
precache_model("sprites/640hud7.spr");
}

215
src/client/obituary.qc Normal file
View file

@ -0,0 +1,215 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <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
Obituary_Init(void)
{
int c;
int i;
filestream fh;
string line;
vector tmp;
if (g_obtype_count > 0) {
return;
}
print("Init Obituaries\n");
g_obtype_count = 0;
i = 0;
fh = fopen("sprites/hud.txt", FILE_READ);
if (fh < 0) {
return;
}
/* count valid entries */
while ((line = fgets(fh))) {
if (substring(line, 0, 2) == "d_") {
c = tokenize(line);
if (c == 7 && argv(1) == "640") {
g_obtype_count++;
}
}
}
g_obtypes = memalloc(sizeof(obituaryimg_t) * g_obtype_count);
fseek(fh, 0);
/* read them in */
while ((line = fgets(fh))) {
if (substring(line, 0, 2) == "d_") {
c = tokenize(line);
/* we only care about the high-res (640) variants. the 320
* HUD is useless to us. Just use the builtin scaler */
if (c == 7 && argv(1) == "640") {
g_obtypes[i].name = substring(argv(0), 2, -1);
g_obtypes[i].src_sprite = sprintf("sprites/%s.spr", argv(2));
precache_model(g_obtypes[i].src_sprite);
g_obtypes[i].sprite = sprintf("sprites/%s.spr_0.tga", argv(2));
g_obtypes[i].size[0] = stof(argv(5));
g_obtypes[i].size[1] = stof(argv(6));
tmp = drawgetimagesize(g_obtypes[i].sprite);
g_obtypes[i].src_pos[0] = stof(argv(3)) / tmp[0];
g_obtypes[i].src_pos[1] = stof(argv(4)) / tmp[1];
g_obtypes[i].src_size[0] = g_obtypes[i].size[0] / tmp[0];
g_obtypes[i].src_size[1] = g_obtypes[i].size[1] / tmp[1];
i++;
}
}
}
fclose(fh);
}
void
Obituary_Precache(void)
{
print("Precache Obituaries\n");
for (int i = 0; i < g_obtype_count; i++)
precache_model(g_obtypes[i].src_sprite);
}
void
Obituary_KillIcon(int id, float w)
{
for (int i = 0; i < g_obtype_count; i++) {
if (g_weapons[w].name == g_obtypes[i].name) {
g_obituary[id].icon = i;
return;
}
}
/* look for skull instead */
for (int i = 0; i < g_obtype_count; i++) {
if (g_obtypes[i].name == "skull") {
g_obituary[id].icon = i;
return;
}
}
}
void
Obituary_Add(string attacker, string victim, float weapon, float flags)
{
int i;
int x, y;
x = OBITUARY_LINES;
/* we're not full yet, so fill up the buffer */
if (g_obituary_count < x) {
y = g_obituary_count;
g_obituary[y].attacker = attacker;
g_obituary[y].victim = victim;
Obituary_KillIcon(y, weapon);
g_obituary_count++;
} else {
for (i = 0; i < (x-1); i++) {
g_obituary[i].attacker = g_obituary[i+1].attacker;
g_obituary[i].victim = g_obituary[i+1].victim;
g_obituary[i].icon = g_obituary[i+1].icon;
}
/* after rearranging, add the newest to the bottom. */
g_obituary[x-1].attacker = attacker;
g_obituary[x-1].victim = victim;
Obituary_KillIcon(x-1, weapon);
}
g_obituary_time = OBITUARY_TIME;
}
void
Obituary_Draw(void)
{
int i;
vector pos;
vector item;
drawfont = FONT_CON;
pos = g_hudmins + [g_hudres[0] - 18, 56];
if (g_obituary_time <= 0 && g_obituary_count > 0) {
for (i = 0; i < (OBITUARY_LINES-1); i++) {
g_obituary[i].attacker = g_obituary[i+1].attacker;
g_obituary[i].victim = g_obituary[i+1].victim;
g_obituary[i].icon = g_obituary[i+1].icon;
}
g_obituary[OBITUARY_LINES-1].attacker = "";
g_obituary_time = OBITUARY_TIME;
g_obituary_count--;
}
if (g_obituary_count <= 0) {
return;
}
item = pos;
for (i = 0; i < OBITUARY_LINES; i++) {
string a, v;
if (!g_obituary[i].attacker) {
break;
}
item[0] = pos[0];
v = g_obituary[i].victim;
drawstring_r(item + [0,2], v, [12,12], [1,1,1], 1.0f, 0);
item[0] -= stringwidth(v, TRUE, [12,12]) + 4;
item[0] -= g_obtypes[g_obituary[i].icon].size[0];
drawsubpic(
item,
[g_obtypes[g_obituary[i].icon].size[0], g_obtypes[g_obituary[i].icon].size[1]],
g_obtypes[g_obituary[i].icon].sprite,
[g_obtypes[g_obituary[i].icon].src_pos[0],g_obtypes[g_obituary[i].icon].src_pos[1]],
[g_obtypes[g_obituary[i].icon].src_size[0],g_obtypes[g_obituary[i].icon].src_size[1]],
[1,1,1],
1.0f,
0
);
a = g_obituary[i].attacker;
drawstring_r(item + [-4,2], a, [12,12], [1,1,1], 1.0f, 0);
item[1] += 18;
}
g_obituary_time = max(0, g_obituary_time - clframetime);
}
void
Obituary_Parse(void)
{
string attacker;
string victim;
float weapon;
float flags;
attacker = readstring();
victim = readstring();
weapon = readbyte();
flags = readbyte();
if (!attacker) {
return;
}
Obituary_Add(attacker, victim, weapon, flags);
}

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

@ -0,0 +1,42 @@
#pragma target fte
#pragma progs_dat "../../csprogs.dat"
#define CSQC
#define CLIENT
#define VALVE
#define HHDEATH
#define CLASSIC_VGUI
#define GS_RENDERFX
#includelist
../../../src/shared/fteextensions.qc
../../../src/shared/defs.h
../../../valve/src/client/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/predict.qc
init.qc
../../../valve/src/client/player.qc
entities.qc
../../../valve/src/client/cmds.qc
game_event.qc
../../../valve/src/client/view.qc
obituary.qc
hud.qc
../../../valve/src/client/hud_weaponselect.qc
../../../valve/src/client/scoreboard.qc
../../../valve/src/client/input.qc
../../../base/src/client/modelevent.qc
../../../src/client/include.src
../../../src/shared/include.src
#endlist

2
src/progs.src Executable file
View file

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

4
src/server/Makefile Normal file
View file

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

171
src/server/ammo_hd.qc Normal file
View file

@ -0,0 +1,171 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
* Copyright (c) 2020 Gethyn ThomasQuail <xylemon@posteo.net>
*
* 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:CBaseEntity
{
void(void) item_ammo;
virtual void(void) Respawn;
virtual void(void) touch;
};
void item_ammo::touch(void)
{
if not (other.flags & FL_CLIENT) {
return;
}
player pl = (player)other;
Sound_Play(other, CHAN_ITEM, "ammo.pickup");
Weapons_RefreshAmmo(pl);
Logging_Pickup(other, this, __NULL__);
if (cvar("sv_playerslots") == 1) {
remove(self);
} else {
Hide();
think = Respawn;
nextthink = time + 20.0f;
}
}
void item_ammo::Respawn(void)
{
SetSolid(SOLID_TRIGGER);
SetMovetype(MOVETYPE_TOSS);
SetSize([-16,-16,0],[16,16,16]);
SetOrigin(m_oldOrigin);
SetModel(m_oldModel);
think = __NULL__;
nextthink = -1;
Sound_Play(this, CHAN_ITEM, "ammo.respawn");
droptofloor();
}
void item_ammo::item_ammo(void)
{
m_oldModel = model;
SetModel(m_oldModel);
CBaseEntity::CBaseEntity();
}
/*QUAKED ammo_forks (0 0 0.8) (-16 -16 0) (16 16 32)
Household DEATH! (2003) ENTITY
Ammo for the throwable Forks.
A single fork, despite name. It's just a fork man.
*/
class ammo_forks:item_ammo
{
void(void) ammo_forks;
virtual void(void) touch;
};
void ammo_forks::ammo_forks(void)
{
model = "models/w_fork2.mdl";
item_ammo::item_ammo();
SetRenderMode(RM_FULLBRIGHT);
SetRenderAmt(1.0f);
}
void ammo_forks::touch(void)
{
if not (other.flags & FL_CLIENT) {
return;
}
if (other.classname == "player") {
player pl = (player)other;
if (pl.ammo_forks < MAX_A_FORKS) {
pl.ammo_forks = bound(0, pl.ammo_forks + 1, MAX_A_FORKS);
item_ammo::touch();
}
}
}
/*QUAKED ammo_legoblocks (0 0 0.8) (-16 -16 0) (16 16 32)
Household DEATH! (2003) ENTITY
Ammo for the Lego Launcher.
A single pack provides 12 legos.
*/
class ammo_legoblocks:item_ammo
{
void(void) ammo_legoblocks;
virtual void(void) touch;
};
void ammo_legoblocks::ammo_legoblocks(void)
{
model = "models/legoblocks.mdl";
item_ammo::item_ammo();
SetRenderMode(RM_FULLBRIGHT);
SetRenderAmt(1.0f);
}
void ammo_legoblocks::touch(void)
{
if not (other.flags & FL_CLIENT) {
return;
}
if (other.classname == "player") {
player pl = (player)other;
if (pl.ammo_legos < MAX_A_LEGOS) {
pl.ammo_legos = bound(0, pl.ammo_legos + 12, MAX_A_LEGOS);
item_ammo::touch();
}
}
}
/*QUAKED ammo_sodacans (0 0 0.8) (-16 -16 0) (16 16 32)
Household DEATH! (2003) ENTITY
Ammo for the Soda Launcher.
A single pack provides 6 soda cans.
*/
class ammo_sodacans:item_ammo
{
void(void) ammo_sodacans;
virtual void(void) touch;
};
void ammo_sodacans::ammo_sodacans(void)
{
model = "models/nukacola.mdl";
item_ammo::item_ammo();
SetRenderMode(RM_FULLBRIGHT);
SetRenderAmt(1.0f);
}
void ammo_sodacans::touch(void)
{
if not (other.flags & FL_CLIENT) {
return;
}
if (other.classname == "player") {
player pl = (player)other;
if (pl.ammo_soda < MAX_A_SODA) {
pl.ammo_soda = bound(0, pl.ammo_soda + 6, MAX_A_SODA);
item_ammo::touch();
}
}
}

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

@ -0,0 +1,18 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <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 "gamerules.h"
#include "../../../valve/src/server/items.h"

33
src/server/gamerules.h Normal file
View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <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 "../../../src/server/gamerules.h"
class HHDMultiplayerRules:CGameRules
{
/* client */
virtual void(base_player) PlayerSpawn;
virtual void(base_player) PlayerConnect;
virtual void(base_player) PlayerDisconnect;
virtual void(base_player) PlayerKill;
virtual void(base_player) PlayerDeath;
virtual void(base_player) PlayerPain;
virtual void(base_player) PlayerPostFrame;
virtual void(base_player) LevelDecodeParms;
virtual void(base_player) LevelChangeParms;
virtual void(void) LevelNewParms;
};

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

@ -0,0 +1,347 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <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.
*/
var int autocvar_sv_playerkeepalive = TRUE;
void
HHDMultiplayerRules::PlayerDeath(base_player pl)
{
/* obituary networking */
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_OBITUARY);
if (g_dmg_eAttacker.netname)
WriteString(MSG_MULTICAST, g_dmg_eAttacker.netname);
else
WriteString(MSG_MULTICAST, 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);
/* death-counter */
pl.deaths++;
forceinfokey(pl, "*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++;
}
pl.movetype = MOVETYPE_NONE;
pl.solid = SOLID_NOT;
pl.takedamage = DAMAGE_NO;
pl.gflags &= ~GF_FLASHLIGHT;
pl.armor = pl.activeweapon = pl.g_items = 0;
pl.think = PutClientInServer;
pl.nextthink = time + 4.0f;
Sound_Play(pl, CHAN_AUTO, "player.die");
if (pl.health < -50) {
pl.health = 0;
FX_GibHuman(pl.origin);
return;
}
pl.health = 0;
/* 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
HHDMultiplayerRules::PlayerPain(base_player pl)
{
/* Vampire Rune
* steals health from enemies */
if (g_dmg_eAttacker.flags & RUNE_VAMPIRE)
g_dmg_eAttacker.health += g_dmg_iDamage;
/* This probably doesn't go here?
* damage checks for vampire rune */
if (g_dmg_eAttacker == (entity)pl)
return;
if (!(g_dmg_eAttacker.flags & FL_CLIENT))
return;
}
void
HHDMultiplayerRules::PlayerSpawn(base_player pp)
{
player pl = (player)pp;
/* this is where the mods want to deviate */
entity spot;
pl.classname = "player";
pl.health = pl.max_health = 100;
pl.takedamage = DAMAGE_YES;
pl.solid = SOLID_SLIDEBOX;
pl.movetype = MOVETYPE_WALK;
pl.flags = FL_CLIENT;
pl.viewzoom = 1.0;
pl.model = "models/player.mdl";
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.view_ofs = VEC_PLAYER_VIEWPOS;
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));
spot = Spawn_SelectRandom("info_player_deathmatch");
setorigin(pl, spot.origin);
pl.angles = spot.angles;
pl.g_items = ITEM_BROOM | ITEM_SUIT;
pl.activeweapon = WEAPON_BROOM;
Weapons_RefreshAmmo(pl);
Client_FixAngle(pl, pl.angles);
}
void
HHDMultiplayerRules::LevelDecodeParms(base_player pp)
{
player pl = (player)pp;
g_landmarkpos[0] = parm1;
g_landmarkpos[1] = parm2;
g_landmarkpos[2] = parm3;
pl.angles[0] = parm4;
pl.angles[1] = parm5;
pl.angles[2] = parm6;
pl.velocity[0] = parm7;
pl.velocity[1] = parm8;
pl.velocity[2] = parm9;
pl.g_items = parm10;
pl.activeweapon = parm11;
pl.flags = parm18;
pl.ammo_forks = parm12;
pl.ammo_knives = parm13;
pl.ammo_legogrenade = parm14;
pl.ammo_legos = parm15;
pl.ammo_soda = parm16;
pl.ammo_spray = parm17;
if (pl.flags & FL_CROUCHING) {
setsize(pl, VEC_CHULL_MIN, VEC_CHULL_MAX);
} else {
setsize(pl, VEC_HULL_MIN, VEC_HULL_MAX);
}
}
void
HHDMultiplayerRules::LevelChangeParms(base_player pp)
{
player pl = (player)pp;
parm1 = g_landmarkpos[0];
parm2 = g_landmarkpos[1];
parm3 = g_landmarkpos[2];
parm4 = pl.angles[0];
parm5 = pl.angles[1];
parm6 = pl.angles[2];
parm7 = pl.velocity[0];
parm8 = pl.velocity[1];
parm9 = pl.velocity[2];
parm64 = pl.flags;
parm10 = pl.g_items;
parm11 = pl.activeweapon;
parm12 = pl.ammo_forks;
parm13 = pl.ammo_knives;
parm14 = pl.ammo_legogrenade;
parm15 = pl.ammo_legos;
parm16 = pl.ammo_soda;
parm17 = pl.ammo_spray;
}
void
HHDMultiplayerRules::LevelNewParms(void)
{
parm1 = parm2 = parm3 = parm4 = parm5 = parm6 = parm7 =
parm8 = parm9 = parm10 = parm11 = parm12 = parm13 = parm14 =
parm15 = parm16 = parm17 = 0;
parm18 = FL_CLIENT;
}
/* we check what fields have changed over the course of the frame and network
* only the ones that have actually changed */
void
HHDMultiplayerRules::PlayerPostFrame(base_player pp)
{
player pl = (player)pp;
Animation_PlayerUpdate();
if (autocvar_sv_playerkeepalive)
pl.SendFlags |= PLAYER_KEEPALIVE;
if (pl.old_modelindex != pl.modelindex)
pl.SendFlags |= PLAYER_MODELINDEX;
if (pl.old_origin[0] != pl.origin[0])
pl.SendFlags |= PLAYER_ORIGIN;
if (pl.old_origin[1] != pl.origin[1])
pl.SendFlags |= PLAYER_ORIGIN;
if (pl.old_origin[2] != pl.origin[2])
pl.SendFlags |= PLAYER_ORIGIN_Z;
if (pl.old_angles[0] != pl.v_angle[0])
pl.SendFlags |= PLAYER_ANGLES_X;
if (pl.old_angles[1] != pl.angles[1])
pl.SendFlags |= PLAYER_ANGLES_Y;
if (pl.old_angles[2] != pl.angles[2])
pl.SendFlags |= PLAYER_ANGLES_Z;
if (pl.old_velocity[0] != pl.velocity[0])
pl.SendFlags |= PLAYER_VELOCITY;
if (pl.old_velocity[1] != pl.velocity[1])
pl.SendFlags |= PLAYER_VELOCITY;
if (pl.old_velocity[2] != pl.velocity[2])
pl.SendFlags |= PLAYER_VELOCITY_Z;
if (pl.old_flags != pl.flags)
pl.SendFlags |= PLAYER_FLAGS;
if (pl.old_activeweapon != pl.activeweapon)
pl.SendFlags |= PLAYER_WEAPON;
if (pl.old_items != pl.g_items)
pl.SendFlags |= PLAYER_ITEMS;
if (pl.old_health != pl.health)
pl.SendFlags |= PLAYER_HEALTH;
if (pl.old_armor != pl.armor)
pl.SendFlags |= PLAYER_ARMOR;
if (pl.old_movetype != pl.movetype)
pl.SendFlags |= PLAYER_MOVETYPE;
if (pl.old_viewofs != pl.view_ofs[2])
pl.SendFlags |= PLAYER_VIEWOFS;
if (pl.old_baseframe != pl.baseframe)
pl.SendFlags |= PLAYER_BASEFRAME;
if (pl.old_frame != pl.frame)
pl.SendFlags |= PLAYER_FRAME;
if (pl.old_a_ammo1 != pl.a_ammo1)
pl.SendFlags |= PLAYER_AMMO1;
if (pl.old_a_ammo2 != pl.a_ammo2)
pl.SendFlags |= PLAYER_AMMO2;
if (pl.old_a_ammo3 != pl.a_ammo3)
pl.SendFlags |= PLAYER_AMMO3;
pl.old_modelindex = pl.modelindex;
pl.old_origin = pl.origin;
pl.old_angles = pl.angles;
pl.old_angles[0] = pl.v_angle[0];
pl.old_velocity = pl.velocity;
pl.old_flags = pl.flags;
pl.old_activeweapon = pl.activeweapon;
pl.old_items = pl.g_items;
pl.old_health = pl.health;
pl.old_armor = pl.armor;
pl.old_movetype = pl.movetype;
pl.old_viewofs = pl.view_ofs[2];
pl.old_baseframe = pl.baseframe;
pl.old_frame = pl.frame;
pl.old_a_ammo1 = pl.a_ammo1;
pl.old_a_ammo2 = pl.a_ammo2;
pl.old_a_ammo3 = pl.a_ammo3;
/* Almost all powerups are on a timer */
pl.powerup_time = bound(0.0f, pl.powerup_time - frametime, pl.powerup_time);
/* and remove when time runs out ;) */
if (pl.powerup_time <= 0.0f) {
pl.g_items &= ~ITEM_RUNE_HASTE;
}
}
void
HHDMultiplayerRules::PlayerConnect(base_player pl)
{
entity a;
bprint(PRINT_HIGH, sprintf("%s connected\n", pl.netname));
int playercount = 0;
for (a = world; (a = find(a, ::classname, "player"));) {
playercount++;
}
}
void
HHDMultiplayerRules::PlayerDisconnect(base_player pl)
{
bprint(PRINT_HIGH, sprintf("%s disconnected\n", pl.netname));
/* Make this unusable */
pl.solid = SOLID_NOT;
pl.movetype = MOVETYPE_NONE;
pl.modelindex = 0;
pl.health = 0;
pl.takedamage = 0;
pl.SendFlags = PLAYER_MODELINDEX;
}
void
HHDMultiplayerRules::PlayerKill(base_player pp)
{
player pl = (player)pp;
Damage_Apply(pl, pl, pl.health, WEAPON_NONE, DMG_SKIP_ARMOR);
}

View file

@ -0,0 +1,84 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <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 info_runespawn (0 0 0.8) (-16 -16 0) (16 16 36)
HALF-LIFE (1998) ENTITY
HEV Suit energy battery.
It adds the following energy values to the HEV Suit by default:
Skill 1 (Easy): 15
Skill 2 (Medium): 15
Skill 3 (Hard): 10
The values can be tweaked in the skill.cfg file.
*/
class info_runespawn:CBaseEntity
{
void(void) info_runespawn;
virtual void(void) Respawn;
virtual void(void) touch;
};
void info_runespawn::touch(void)
{
if (other.classname != "player") {
return;
}
/* TODO runestuff
*if (other.rune >= 1) {
* return;
* }
*/
Logging_Pickup(other, this, __NULL__);
Sound_Play(other, CHAN_ITEM, "item.armor");
think = Respawn;
nextthink = time + 30.0f;
}
void info_runespawn::Respawn(void)
{
SetSolid(SOLID_TRIGGER);
SetMovetype(MOVETYPE_NONE);
/* One of the models is transparent, and we need to set additive
SetRenderMode(RM_ADDITIVE);
SetRenderAmt(255);
SetSize([-16,-16,0],[16,16,16]);
* Rotation
* avelocity[1] = 420; */
/* Always spawns a little above origin */
SetOrigin(m_oldOrigin + [0,0,16]);
SetModel(m_oldModel);
think = __NULL__;
nextthink = -1;
Sound_Play(this, CHAN_ITEM, "item.respawn");
}
void info_runespawn::info_runespawn(void)
{
Sound_Precache("item.armor");
Sound_Precache("item.respawn");
/* TODO actually uses two models... */
model = "models/rune_stand.mdl";
CBaseEntity::CBaseEntity();
item_healthkit::Respawn();
}

77
src/server/input.qc Normal file
View file

@ -0,0 +1,77 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <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.
*/
/*
=================
Input_Handle
Handles impulse and whatnot
=================
*/
void Game_Input(void)
{
CGameRules rules = (CGameRules)g_grMode;
if (rules.m_iIntermission) {
rules.IntermissionEnd();
return;
}
if (input_buttons & INPUT_BUTTON0) {
Weapons_Primary();
} else if (input_buttons & INPUT_BUTTON4) {
Weapons_Reload();
} else if (input_buttons & INPUT_BUTTON3) {
Weapons_Secondary();
} else {
Weapons_Release();
}
if (input_buttons & INPUT_BUTTON5) {
Player_UseDown();
} else {
Player_UseUp();
}
if (self.impulse == 100) {
Flashlight_Toggle();
}
if (self.impulse == 240)
Bot_AddQuick();
/* Uncomment rune weapons if you desire */
if (cvar("sv_cheats") == 1) {
player pl = (player)self;
if (self.impulse == 101) {
pl.health = 100;
pl.armor = 100;
pl.g_items |= ITEM_SUIT;
Weapons_AddItem(pl, WEAPON_BROOM, -1);
Weapons_AddItem(pl, WEAPON_FORKS, -1);
Weapons_AddItem(pl, WEAPON_FRYINGPAN, -1);
/* Weapons_AddItem(pl, WEAPON_GLOVE, -1); */
Weapons_AddItem(pl, WEAPON_HAIRSPRAY, -1);
Weapons_AddItem(pl, WEAPON_KNIFE, -1);
Weapons_AddItem(pl, WEAPON_LEGO, -1);
Weapons_AddItem(pl, WEAPON_LEGOLAUNCHER, -1);
Weapons_AddItem(pl, WEAPON_MACHETTE, -1);
Weapons_AddItem(pl, WEAPON_SODALAUNCHER, -1);
}
}
self.impulse = 0;
}

View file

@ -0,0 +1,91 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <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 item_battery (0 0 0.8) (-16 -16 0) (16 16 36)
HALF-LIFE (1998) ENTITY
HEV Suit energy battery.
It adds the following energy values to the HEV Suit by default:
Skill 1 (Easy): 15
Skill 2 (Medium): 15
Skill 3 (Hard): 10
The values can be tweaked in the skill.cfg file.
*/
class item_battery:CBaseEntity
{
void(void) item_battery;
virtual void(void) Respawn;
virtual void(void) touch;
};
void item_battery::touch(void)
{
if (other.classname != "player") {
return;
}
base_player pl = (base_player)other;
if (pl.armor >= 100) {
return;
}
/* Move this somewhere else? */
pl.armor += Skill_GetValue("battery", 10);
if (pl.armor > 100) {
pl.armor = 100;
}
Logging_Pickup(other, this, __NULL__);
Sound_Play(other, CHAN_ITEM, "item.battery");
if (cvar("sv_playerslots") == 1) {
remove(self);
} else {
Hide();
think = Respawn;
nextthink = time + 20.0f;
}
}
void item_battery::Respawn(void)
{
SetSolid(SOLID_TRIGGER);
SetMovetype(MOVETYPE_NONE);
/* One of the models is transparent, and we need to set additive */
SetRenderMode(RM_ADDITIVE);
SetRenderAmt(255);
SetSize([-16,-16,0],[16,16,16]);
/* Always spawns a little above origin */
SetOrigin(m_oldOrigin + [0,0,16]);
SetModel(m_oldModel);
think = __NULL__;
nextthink = -1;
Sound_Play(this, CHAN_ITEM, "item.respawn");
}
void item_battery::item_battery(void)
{
Sound_Precache("item.armor");
Sound_Precache("item.respawn");
/* TODO actually uses two models... */
model = "models/armor.mdl";
CBaseEntity::CBaseEntity();
item_healthkit::Respawn();
}

View file

@ -0,0 +1,83 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <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 item_healthkit (0 0 0.8) (-16 -16 0) (16 16 36)
HALF-LIFE (1998) ENTITY
Healthkit item.
Adds 20 of health to the player.
*/
class item_healthkit:CBaseEntity
{
void(void) item_healthkit;
virtual void(void) Respawn;
virtual void(void) touch;
};
void item_healthkit::touch(void)
{
if (other.classname != "player") {
return;
}
if (other.health >= other.max_health) {
return;
}
Damage_Apply(other, this, -20, 0, DMG_GENERIC);
Sound_Play(this, CHAN_ITEM, "item.healthkit");
Logging_Pickup(other, this, __NULL__);
if (cvar("sv_playerslots") == 1) {
remove(self);
} else {
Hide();
think = Respawn;
nextthink = time + 20.0f;
}
}
void item_healthkit::Respawn(void)
{
SetSolid(SOLID_TRIGGER);
SetMovetype(MOVETYPE_NONE);
/* One of the models is transparent, and we need to set additive */
SetRenderMode(RM_ADDITIVE);
SetRenderAmt(255);
SetSize([-16,-16,0],[16,16,16]);
/* Always spawns a little above origin */
SetOrigin(m_oldOrigin + [0,0,16]);
SetModel(m_oldModel);
think = __NULL__;
nextthink = -1;
Sound_Play(this, CHAN_ITEM, "item.respawn");
}
void item_healthkit::item_healthkit(void)
{
Sound_Precache("item.health");
Sound_Precache("item.respawn");
entity base = spawn();
setorigin(base, this.origin);
setmodel(base, "models/health2.mdl");
model = "models/health.mdl";
CBaseEntity::CBaseEntity();
item_healthkit::Respawn();
}

View file

@ -0,0 +1,95 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
* Copyright (c) 2020 Gethyn ThomasQuail <xylemon@posteo.net>
*
* 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 item_rune_haste (0 0 0.8) (-16 -16 0) (16 16 36)
Household DEATH! (2003) ENTITY
Haste Rune
Doubles the player's speed for 30 seconds.
*/
class item_rune_haste:CBaseTrigger
{
void(void) item_rune_haste;
virtual void(void) touch;
virtual void(void) Respawn;
};
void item_rune_haste::touch(void)
{
if (other.classname != "player") {
return;
}
/* Make sure we don't have more than one powerup */
player pl = (player)other;
if (pl.g_items & ITEM_MACHETTE) {
return;
}
if (pl.g_items & ITEM_RUNE_HASTE) {
return;
}
Logging_Pickup(other, this, __NULL__);
/* Replace with proper sounds
* sound(other, CHAN_ITEM, "fvox/bell.wav", 1, ATTN_NORM);
sound(other, CHAN_VOICE, "fvox/hev_logon.wav", 1, ATTN_NORM); */
pl.g_items |= ITEM_RUNE_HASTE;
pl.powerup_time = 30.0f;
CBaseTrigger::UseTargets(this, TRIG_TOGGLE, 0.0f);
if (cvar("sv_playerslots") == 1) {
remove(self);
} else {
Hide();
think = Respawn;
nextthink = time + 30.0f;
}
}
void item_rune_haste::Respawn(void)
{
SetSolid(SOLID_TRIGGER);
SetMovetype(MOVETYPE_NONE);
SetSize(VEC_HULL_MIN, VEC_HULL_MAX);
SetOrigin(m_oldOrigin);
SetModel(m_oldModel);
think = __NULL__;
nextthink = -1;
sound(this, CHAN_ITEM, "items/suitchargeok1.wav", 1, ATTN_NORM, 150);
}
void item_rune_haste::item_rune_haste(void)
{
/* Powerups have a base model always visable */
entity base = spawn();
setorigin(base, this.origin);
setmodel(base, "models/rune_stand.mdl");
model = "models/rune_haste.mdl";
precache_sound("items/suitchargeok1.wav");
precache_sound("fvox/hev_logon.wav");
precache_sound("fvox/bell.wav");
CBaseTrigger::CBaseTrigger();
}

View file

@ -0,0 +1,96 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
* Copyright (c) 2020 Gethyn ThomasQuail <xylemon@posteo.net>
*
* 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 item_rune_stalker (0 0 0.8) (-16 -16 0) (16 16 36)
Household DEATH! (2003) ENTITY
Stalker Rune
Turns the player into a health and speed boosted killer...
Includes a trademark throwable machette weapon!
*/
class item_rune_stalker:CBaseTrigger
{
void(void) item_rune_stalker;
virtual void(void) touch;
virtual void(void) Respawn;
};
void item_rune_stalker::touch(void)
{
if (other.classname != "player") {
return;
}
/* Make sure we don't have more than one powerup */
player pl = (player)other;
if (pl.g_items & ITEM_MACHETTE) {
return;
}
if (pl.g_items & ITEM_RUNE_HASTE) {
return;
}
Logging_Pickup(other, this, __NULL__);
Sound_Play(other, CHAN_ITEM, "weapon_machette.pickup");
env_message_single(other, "Activating Rune STALKER!");
pl.g_items = ITEM_SUIT | ITEM_MACHETTE;
pl.health = 300; /* Player gets more health */
pl.activeweapon = WEAPON_MACHETTE;
Weapons_RefreshAmmo(pl);
CBaseTrigger::UseTargets(this, TRIG_TOGGLE, 0.0f);
if (cvar("sv_playerslots") == 1) {
remove(self);
} else {
Hide();
think = Respawn;
nextthink = time + 30.0f;
}
}
void item_rune_stalker::Respawn(void)
{
SetSolid(SOLID_TRIGGER);
SetMovetype(MOVETYPE_TOSS);
SetSize(VEC_HULL_MIN, VEC_HULL_MAX);
SetOrigin(m_oldOrigin);
SetModel(m_oldModel);
think = __NULL__;
nextthink = -1;
sound(this, CHAN_ITEM, "items/suitchargeok1.wav", 1, ATTN_NORM, 150);
}
void item_rune_stalker::item_rune_stalker(void)
{
/* Powerups have a base model always visable */
entity base = spawn();
setorigin(base, this.origin);
setmodel(base, "models/rune_stand.mdl");
model = "models/rune_stalker.mdl";
Sound_Precache("weapon_machette.pickup");
CBaseTrigger::CBaseTrigger();
}

View file

@ -0,0 +1,88 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <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:CBaseEntity
{
int ammo_forks;
int ammo_knives;
int ammo_legogrenade;
int ammo_legos;
int ammo_soda;
int ammo_spray;
int weapon_items;
void(void) item_weaponbox;
virtual void(void) touch;
virtual void(player) setup;
};
void item_weaponbox::touch(void)
{
if (other.classname != "player") {
return;
}
player pl = (player)other;
Logging_Pickup(other, this, __NULL__);
sound(pl, CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM);
pl.ammo_forks += ammo_forks;
pl.ammo_knives += ammo_knives;
pl.ammo_legogrenade += ammo_legogrenade;
pl.ammo_legos += ammo_legos;
pl.ammo_soda += ammo_soda;
pl.ammo_spray += ammo_spray;
/* cull */
pl.ammo_forks = min(pl.ammo_forks, MAX_A_FORKS);
pl.ammo_knives = min(pl.ammo_knives, MAX_A_KNIVES);
pl.ammo_legogrenade = min(pl.ammo_legogrenade, MAX_A_LEGOGRENADE);
pl.ammo_legos = min(pl.ammo_legos, MAX_A_LEGOS);
pl.ammo_soda = min(pl.ammo_soda, MAX_A_SODA);
pl.ammo_spray = min(pl.ammo_spray, MAX_A_SPRAY);
pl.g_items |= weapon_items;
Weapons_RefreshAmmo(pl);
remove(this);
}
void item_weaponbox::setup(player pl)
{
/* TODO: Should the magazine bits be transferred too? */
ammo_forks = pl.ammo_forks;
ammo_knives = pl.ammo_knives;
ammo_legogrenade = pl.ammo_legogrenade;
ammo_legos = pl.ammo_legos;
ammo_soda = pl.ammo_soda;
ammo_spray = pl.ammo_spray;
weapon_items = pl.g_items;
}
void item_weaponbox::item_weaponbox(void)
{
SetModel("models/basket.mdl");
SetSize([-16,-16,0], [16,16,16]);
SetSolid(SOLID_TRIGGER);
SetMovetype(MOVETYPE_TOSS);
}
void weaponbox_spawn(player spawner)
{
item_weaponbox weaponbox = spawn(item_weaponbox);
weaponbox.SetOrigin(spawner.origin);
weaponbox.setup(spawner);
}

93
src/server/items.qc Normal file
View file

@ -0,0 +1,93 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <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 item_pickup::touch(void)
{
if (other.classname != "player") {
return;
}
player pl = (player)other;
if (pl.g_items & ITEM_MACHETTE) {
return;
}
/* don't remove if AddItem fails */
if (Weapons_AddItem((player)other, id, m_iClip) == FALSE) {
return;
}
Logging_Pickup(other, this, __NULL__);
Sound_Play(other, CHAN_ITEM, "weapon.pickup");
CBaseTrigger::UseTargets(this, TRIG_TOGGLE, 0.0f);
if (real_owner || m_iWasDropped == 1 || cvar("sv_playerslots") == 1) {
remove(self);
} else {
Hide();
think = Respawn;
nextthink = time + 30.0f;
}
}
void item_pickup::SetItem(int i)
{
id = i;
m_oldModel = Weapons_GetWorldmodel(id);
SetModel(m_oldModel);
}
void item_pickup::SetFloating(int i)
{
m_bFloating = rint(bound(0, m_bFloating, 1));
}
void item_pickup::Respawn(void)
{
SetSolid(SOLID_TRIGGER);
SetOrigin(m_oldOrigin);
/* At some points, the item id might not yet be set */
if (m_oldModel) {
SetModel(m_oldModel);
}
SetSize([-16,-16,0], [16,16,16]);
think = __NULL__;
nextthink = -1;
if (!m_iWasDropped && cvar("sv_playerslots") > 1) {
if (!real_owner)
Sound_Play(this, CHAN_ITEM, "item.respawn");
m_iClip = -1;
}
if (!m_bFloating) {
droptofloor();
SetMovetype(MOVETYPE_TOSS);
}
}
void item_pickup::item_pickup(void)
{
Sound_Precache("item.respawn");
Sound_Precache("weapon.pickup");
CBaseTrigger::CBaseTrigger();
Respawn();
}

52
src/server/progs.src Executable file
View file

@ -0,0 +1,52 @@
#pragma target fte
#pragma progs_dat "../../progs.dat"
#define QWSSQC
#define SERVER
#define VALVE
#define HHDEATH
#define GS_RENDERFX
#includelist
../../../src/shared/fteextensions.qc
../../../src/gs-entbase/server/defs.h
../../../src/shared/defs.h
../../../src/server/defs.h
../../../src/gs-entbase/server.src
../../../src/gs-entbase/shared.src
../shared/include.src
defs.h
../../../valve/src/server/monster_scientist_dead.qc
../../../valve/src/server/player.qc
../../../valve/src/server/spectator.qc
items.qc
../../../valve/src/server/item_suit.qc
item_healthkit.qc
item_battery.qc
item_rune_haste.qc
item_rune_stalker.qc
item_weaponbox.qc
../../../valve/src/server/world_items.qc
ammo_hd.qc
gamerules.qc
../../../valve/src/server/client.qc
server.qc
../../../valve/src/server/damage.qc
../../../valve/src/server/rules.qc
../../../src/botlib/include.src
../../../valve/src/server/flashlight.qc
../../../base/src/server/modelevent.qc
input.qc
../../../valve/src/server/spawn.qc
../../../src/server/include.src
../../../src/shared/include.src
#endlist

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

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

22
src/shared/events.h Normal file
View file

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

42
src/shared/flags.h Normal file
View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "../../../valve/src/shared/flags.h"
/* game flags */
#define GF_UNUSED1 (1<<0)
#define GF_UNUSED2 (1<<1)
#define GF_UNUSED3 (1<<2)
#define GF_UNUSED4 (1<<3)
#define GF_UNUSED5 (1<<4)
#define GF_UNUSED6 (1<<5)
#define GF_UNUSED7 (1<<6)
#define GF_UNUSED8 (1<<7)
#define GF_UNUSED9 (1<<8)
#define GF_UNUSED10 (1<<9)
#define GF_UNUSED11 (1<<10)
#define GF_UNUSED12 (1<<11)
#define GF_UNUSED13 (1<<12)
#define GF_UNUSED14 (1<<14)
#define GF_UNUSED15 (1<<16)
#define GF_UNUSED16 (1<<13)
#define GF_UNUSED17 (1<<17)
#define GF_UNUSED18 (1<<18)
#define GF_UNUSED19 (1<<19)
#define GF_UNUSED20 (1<<20)
#define GF_UNUSED21 (1<<21)
#define GF_UNUSED22 (1<<22)
#define RUNE_VAMPIRE (1<<23)

95
src/shared/fx_lego.qc Normal file
View file

@ -0,0 +1,95 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef CLIENT
var float PARTICLE_LEGO;
void
FX_Lego_Init(void)
{
Sound_Precache("weapon_lego.explode");
precache_model("models/lego.mdl");
PARTICLE_LEGO = particleeffectnum("part_lego");
}
string g_fxlego_sets[12] = {
"geomset 0 1",
"geomset 0 2",
"geomset 0 3",
"geomset 0 4",
"geomset 0 5",
"geomset 0 6",
"geomset 0 7",
"geomset 0 8",
"geomset 0 9",
"geomset 0 10",
"geomset 0 11",
"geomset 0 12",
};
#endif
void
FX_Lego(vector pos)
{
#ifdef SERVER
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_LEGO);
WriteCoord(MSG_MULTICAST, pos[0]);
WriteCoord(MSG_MULTICAST, pos[1]);
WriteCoord(MSG_MULTICAST, pos[2]);
msg_entity = self;
multicast(pos, MULTICAST_PVS);
#else
static void Lego_Remove(void) {
remove(self);
}
/* cast an explosive effect minus the fire */
/* wrong decal atm, decal.wad loading is messy in HL */
Decals_Place(pos, "{spraypaint");
/* has a different smoke sprite */
env_sprite eSmoke = spawn(env_sprite);
setorigin(eSmoke, pos);
setmodel(eSmoke, "sprites/stmbal1.spr");
Sound_Play(eSmoke, CHAN_WEAPON, "weapon_lego.explode");
eSmoke.effects = EF_ADDITIVE;
eSmoke.drawmask = MASK_ENGINE;
eSmoke.maxframe = modelframecount(eSmoke.modelindex);
eSmoke.loops = 0;
eSmoke.framerate = 15;
eSmoke.nextthink = time + 0.05f;
/* there are many different lego submodels */
for (int i = 0; i < 12; i++) {
entity eLego = spawn();
setorigin(eLego, pos);
setmodel(eLego, "models/lego.mdl");
eLego.movetype = MOVETYPE_BOUNCE;
eLego.gravity = 0.5f;
eLego.scale = 1.0f;
eLego.drawmask = MASK_ENGINE;
eLego.velocity = randomvec() * 192;
eLego.think = Lego_Remove;
eLego.nextthink = time + 5.0f;
eLego.solid = SOLID_BBOX;
setcustomskin(eLego, "", g_fxlego_sets[floor(random(0,12))]);
setsize(eLego, [0,0,0], [0,0,0]);
}
#endif
}

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef CLIENT
var float PARTICLE_LEGOPIECE;
void
FX_LegoPiece_Init(void)
{
precache_model("models/lego.mdl");
PARTICLE_LEGOPIECE = particleeffectnum("part_legopiece");
}
#endif
void
FX_LegoPiece(vector pos)
{
#ifdef SERVER
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_LEGOPIECE);
WriteCoord(MSG_MULTICAST, pos[0]);
WriteCoord(MSG_MULTICAST, pos[1]);
WriteCoord(MSG_MULTICAST, pos[2]);
msg_entity = self;
multicast(pos, MULTICAST_PVS);
#else
static void LegoPiece_Remove(void) {
remove(self);
}
entity eLegoPiece = spawn();
setorigin(eLegoPiece, pos);
setmodel(eLegoPiece, "models/lego.mdl");
eLegoPiece.movetype = MOVETYPE_BOUNCE;
eLegoPiece.gravity = 0.5f;
eLegoPiece.scale = 1.0f;
eLegoPiece.drawmask = MASK_ENGINE;
eLegoPiece.velocity = randomvec() * 128;
eLegoPiece.think = LegoPiece_Remove;
eLegoPiece.nextthink = time + 5.0f;
eLegoPiece.solid = SOLID_BBOX;
setcustomskin(eLegoPiece, "", g_fxlego_sets[floor(random(0,12))]);
setsize(eLegoPiece, [0,0,0], [0,0,0]);
#endif
}

114
src/shared/fx_soda.qc Normal file
View file

@ -0,0 +1,114 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef CLIENT
var float PARTICLE_SODA;
void
FX_Soda_Init(void)
{
precache_model("sprites/blooddrop.spr");
precache_model("sprites/soda2.spr");
PARTICLE_SODA = particleeffectnum("part_soda");
}
#endif
void
FX_Soda(vector pos, int col)
{
#ifdef SERVER
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_SODA);
WriteCoord(MSG_MULTICAST, pos[0]);
WriteCoord(MSG_MULTICAST, pos[1]);
WriteCoord(MSG_MULTICAST, pos[2]);
WriteByte(MSG_MULTICAST, col);
msg_entity = self;
multicast(pos, MULTICAST_PVS);
#else
vector color;
/* Decals use a palette to set color, we need to set sprite colors by hand.
* The order is important, we need to keep the clients and server in sync
* for the view model, soda projectile, and soda spill effect */
switch (col) {
case 1:
Decals_Place(pos, "{sodared");
color = [1,0,0];
break;
case 2:
Decals_Place(pos, "{sodapurple");
color = [1,0,1];
break;
case 3:
Decals_Place(pos, "{sodayellow");
color = [1,1,0];
break;
case 4:
Decals_Place(pos, "{sodablue");
color = [0,0,1];
break;
case 5:
Decals_Place(pos, "{sodabrown");
color = [1,0.5,0];
break;
default:
Decals_Place(pos, "{sodagreen");
color = [0,1,0];
break;
}
/* enchancement from mod */
env_sprite eSoda = spawn(env_sprite);
setorigin(eSoda, pos);
setmodel(eSoda, "sprites/soda1.spr");
eSoda.effects = EF_ADDITIVE;
eSoda.drawmask = MASK_ENGINE;
eSoda.maxframe = modelframecount(eSoda.modelindex);
eSoda.loops = 0;
eSoda.scale = 1.0f;
eSoda.m_vecRenderColor = color;
eSoda.framerate = 20;
eSoda.nextthink = time + 0.05f;
static void Soda_Remove(void) {
remove(self);
}
/* Has a dripping effect from spill */
for (int i = 0; i < 10; i++) {
env_sprite eSodaPart = spawn(env_sprite);
setorigin(eSodaPart, pos);
setmodel(eSodaPart, "sprites/soda2.spr");
eSodaPart.movetype = MOVETYPE_TOSS;
eSodaPart.gravity = 0.3f;
eSodaPart.scale = 0.5f;
eSodaPart.effects = EF_ADDITIVE;
eSodaPart.drawmask = MASK_ENGINE;
eSodaPart.maxframe = modelframecount(eSodaPart.modelindex);
eSodaPart.loops = 1;
eSodaPart.m_vecRenderColor = color;
eSodaPart.framerate = 10;
eSodaPart.touch = Soda_Remove;
eSodaPart.nextthink = time + 0.1f;
eSodaPart.velocity = randomvec() * 128;
eSodaPart.solid = SOLID_BBOX;
setsize(eSodaPart, [0,0,0], [0,0,0]);
}
#endif
}

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

@ -0,0 +1,36 @@
#includelist
../../../valve/src/shared/entities.h
flags.h
events.h
player.qc
../../../valve/src/shared/weapon_common.h
../../../valve/src/shared/animations.h
../../../valve/src/shared/animations.qc
pmove.qc
../../../valve/src/shared/pmove_water.qc
../../../valve/src/shared/fx_blood.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_impact.qc
fx_lego.qc
fx_legopiece.qc
fx_soda.qc
items.h
weapons.h
w_broom.qc
w_forks.qc
w_fryingpan.qc
w_glove.qc
w_hairspray.qc
w_knife.qc
w_lego.qc
w_legolauncher.qc
w_machette.qc
w_sodalauncher.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 Hladik <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_BROOM 0x00000001i
#define ITEM_FORKS 0x00000002i
#define ITEM_FRYINGPAN 0x00000004i
#define ITEM_GLOVE 0x00000008i
#define ITEM_HAIRSPRAY 0x00000010i
#define ITEM_KNIFE 0x00000020i
#define ITEM_LEGO 0x00000040i
#define ITEM_LEGOLAUNCHER 0x00000080i
#define ITEM_MACHETTE 0x00000100i
#define ITEM_SODALAUNCHER 0x00000200i
#define ITEM_SUIT 0x00000400i
#define ITEM_LONGJUMP 0x00000800i
#define ITEM_RUNE_HASTE 0x00001000i
#define ITEM_UNUSED14 0x00002000i
#define ITEM_UNUSED15 0x00004000i
#define ITEM_UNUSED16 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

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

@ -0,0 +1,42 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <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 input_sequence;
class player:base_player
{
#ifdef CLIENT
/* External model */
entity p_model;
int p_hand_bone;
int p_model_bone;
float pitch;
float lastweapon;
virtual void(void) gun_offset;
virtual void(void) draw;
virtual float() predraw;
virtual void(void) postdraw;
#else
int ammo_forks;
int ammo_knives;
int ammo_legogrenade;
int ammo_legos;
int ammo_soda;
int ammo_spray;
float powerup_time;
#endif
};

69
src/shared/pmove.qc Normal file
View file

@ -0,0 +1,69 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <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 PHY_JUMP_CHAINWINDOW 0.5
#define PHY_JUMP_CHAIN 100
#define PHY_JUMP_CHAINDECAY 50
.float waterlevel;
.float watertype;
float GamePMove_Maxspeed(player target)
{
/* The Haste Rune doubles player speed */
if (target.g_items & 0x00001000i) {
return (target.flags & FL_CROUCHING) ? 200 : 420;
} else {
return (target.flags & FL_CROUCHING) ? 100 : 220;
}
}
void GamePMove_Fall(player target, float impactspeed)
{
if (impactspeed > 580) {
#ifdef SERVER
float fFallDamage = (impactspeed - 580) * (100 / (1024 - 580));
Damage_Apply(self, world, fFallDamage, 0, DMG_FALL);
/* TODO add armor specific fall damage */
Sound_Play(self, CHAN_AUTO, "player.fall");
#endif
}
}
void GamePMove_Jump(player target)
{
float flJumptimeDelta;
float flChainBonus;
if (target.waterlevel >= 2) {
if (target.watertype == CONTENT_WATER) {
target.velocity[2] = 100;
} else if (target.watertype == CONTENT_SLIME) {
target.velocity[2] = 80;
} else {
target.velocity[2] = 50;
}
} else {
target.velocity[2] += 240;
}
if (target.jumptime > 0) {
flJumptimeDelta = 0 - (target.jumptime - PHY_JUMP_CHAINWINDOW);
flChainBonus = PHY_JUMP_CHAIN - (((PHY_JUMP_CHAINWINDOW - (PHY_JUMP_CHAINWINDOW - flJumptimeDelta)) * 2) * PHY_JUMP_CHAINDECAY);
target.velocity[2] += flChainBonus;
}
target.jumptime = PHY_JUMP_CHAINWINDOW;
}

236
src/shared/w_broom.qc Normal file
View file

@ -0,0 +1,236 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
* Copyright (c) 2019-2020 Gethyn ThomasQuail <xylemon@posteo.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
enum
{
BROOM_IDLE,
BROOM_DRAW,
BROOM_HOLSTER,
BROOM_ATTACK1HIT,
BROOM_ATTACK1MISS,
BROOM_ATTACK2MISS,
BROOM_ATTACK2HIT,
BROOM_ATTACK3MISS,
BROOM_ATTACK3HIT
};
void
w_broom_precache(void)
{
#ifdef SERVER
Sound_Precache("weapon_broom.hit");
Sound_Precache("weapon_broom.miss");
Sound_Precache("weapon_broom.hitbody");
#endif
precache_model("models/v_broom.mdl");
precache_model("models/w_broom.mdl");
precache_model("models/p_broom.mdl");
}
void
w_broom_updateammo(player pl)
{
#ifdef SERVER
Weapons_UpdateAmmo(pl, -1, -1, -1);
#endif
}
string
w_broom_wmodel(void)
{
return "models/w_broom.mdl";
/* model = "models/w_broom.mdl";
SetRenderMode(RM_FULLBRIGHT);
SetRenderAmt(255); */
}
string
w_broom_pmodel(void)
{
return "models/p_broom.mdl";
}
string
w_broom_deathmsg(void)
{
return "";
}
void
w_broom_draw(void)
{
Weapons_SetModel("models/v_broom.mdl");
Weapons_ViewAnimation(BROOM_DRAW);
}
void
w_broom_holster(void)
{
Weapons_ViewAnimation(BROOM_HOLSTER);
}
void
w_broom_primary(void)
{
int anim = 0;
vector src;
player pl = (player)self;
if (pl.w_attack_next) {
return;
}
Weapons_MakeVectors();
src = pl.origin + pl.view_ofs;
/* make sure we can gib corpses */
int oldhitcontents = self.hitcontentsmaski;
self.hitcontentsmaski = CONTENTBITS_POINTSOLID | CONTENTBIT_CORPSE;
traceline(src, src + (v_forward * 32), FALSE, pl);
self.hitcontentsmaski = oldhitcontents;
if (trace_fraction >= 1.0) {
pl.w_attack_next = 0.5f;
} else {
pl.w_attack_next = 0.25f;
}
pl.w_idle_next = 2.5f;
int r = (float)input_sequence % 3;
switch (r) {
case 0:
Weapons_ViewAnimation(trace_fraction >= 1 ? BROOM_ATTACK1MISS:BROOM_ATTACK1HIT);
break;
case 1:
Weapons_ViewAnimation(trace_fraction >= 1 ? BROOM_ATTACK2MISS:BROOM_ATTACK2HIT);
break;
default:
Weapons_ViewAnimation(trace_fraction >= 1 ? BROOM_ATTACK3MISS:BROOM_ATTACK3HIT);
}
#ifdef SERVER
if (pl.flags & FL_CROUCHING) {
Animation_PlayerTopTemp(ANIM_SHOOTCROWBAR, 0.5f);
} else {
Animation_PlayerTopTemp(ANIM_CR_SHOOTCROWBAR, 0.42f);
}
Sound_Play(self, CHAN_WEAPON, "weapon_broom.miss");
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]);
}
if (trace_ent.takedamage) {
Damage_Apply(trace_ent, pl, Skill_GetValue("plr_crowbar", 10), WEAPON_BROOM, DMG_BLUNT);
if (trace_ent.iBleeds) {
Sound_Play(self, CHAN_WEAPON, "weapon_broom.hitbody");
}
} else {
Sound_Play(self, CHAN_WEAPON, "weapon_broom.hit");
}
#endif
}
void
w_broom_release(void)
{
player pl = (player)self;
if (pl.w_idle_next) {
return;
}
Weapons_ViewAnimation(BROOM_IDLE);
pl.w_idle_next = 15.0f;
}
float
w_broom_aimanim(void)
{
return self.flags & FL_CROUCHING ? ANIM_CR_AIMCROWBAR : ANIM_AIMCROWBAR;
}
void
w_broom_hudpic(int selected, vector pos, float a)
{
#ifdef CLIENT
if (selected) {
drawsubpic(
pos,
[170,45],
"sprites/640hud4.spr_0.tga",
[0,0],
[170/256,45/256],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[170,45],
"sprites/640hud1.spr_0.tga",
[0,0],
[170/256,45/256],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
}
#endif
}
weapon_t w_broom =
{
.name = "broom",
.id = ITEM_BROOM,
.slot = 0,
.slot_pos = 0,
.draw = w_broom_draw,
.holster = w_broom_holster,
.primary = w_broom_primary,
.secondary = __NULL__,
.reload = __NULL__,
.release = w_broom_release,
.crosshair = __NULL__,
.precache = w_broom_precache,
.pickup = __NULL__,
.updateammo = w_broom_updateammo,
.wmodel = w_broom_wmodel,
.pmodel = w_broom_pmodel,
.deathmsg = w_broom_deathmsg,
.aimanim = w_broom_aimanim,
.hudpic = w_broom_hudpic
};
/* entity definitions for pickups */
#ifdef SERVER
void
weapon_broom(void)
{
Weapons_InitItem(WEAPON_BROOM);
/*item_pickup item = (item_pickup)self;
item.SetRenderMode(RM_FULLBRIGHT);
item.SetRenderAmt(1.0f);*/
}
#endif

348
src/shared/w_forks.qc Normal file
View file

@ -0,0 +1,348 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
* Copyright (c) 2019-2020 Gethyn ThomasQuail <xylemon@posteo.net>
*
* 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_forks (0 0 1) (-16 -16 0) (16 16 32)
"model" "models/w_fork.mdl"
Household DEATH! (2003) ENTITY
Throwable Forks Weapon
Pile of 6 forks.
*/
enum
{
FORKS_IDLE1,
FORKS_IDLE2,
FORKS_IDLE3,
FORKS_STAB,
FORKS_THROW,
FORKS_DRAW,
FORKS_HOLSTER
};
void
w_forks_precache(void)
{
#ifdef SERVER
Sound_Precache("weapon_forks.hit");
Sound_Precache("weapon_forks.hitbody");
Sound_Precache("weapon_forks.stick");
Sound_Precache("weapon_forks.throw");
#endif
precache_model("sprites/hud_fork.spr");
precache_model("models/v_fork.mdl");
precache_model("models/w_fork.mdl");
precache_model("models/p_fork.mdl");
}
void
w_forks_updateammo(player pl)
{
#ifdef SERVER
Weapons_UpdateAmmo(pl, __NULL__, pl.ammo_forks, __NULL__);
#endif
}
string
w_forks_wmodel(void)
{
return "models/w_forks.mdl";
}
string
w_forks_pmodel(void)
{
return "models/p_fork.mdl";
}
string
w_forks_deathmsg(void)
{
return "";
}
int
w_forks_pickup(int new, int startammo)
{
#ifdef SERVER
player pl = (player)self;
if (pl.ammo_forks < MAX_A_FORKS) {
pl.ammo_forks = bound(0, pl.ammo_forks + 6, MAX_A_FORKS);
} else {
return FALSE;
}
#endif
return TRUE;
}
void
w_forks_draw(void)
{
Weapons_SetModel("models/v_fork.mdl");
Weapons_ViewAnimation(FORKS_DRAW);
}
void
w_forks_holster(void)
{
Weapons_ViewAnimation(FORKS_HOLSTER);
}
void
w_forks_primary(void)
{
int anim = 0;
vector src;
player pl = (player)self;
if (pl.w_attack_next) {
return;
}
Weapons_MakeVectors();
src = pl.origin + pl.view_ofs;
traceline(src, src + (v_forward * 32), FALSE, pl);
pl.w_attack_next = 0.4f;
pl.w_idle_next = 2.5f;
Weapons_ViewAnimation(FORKS_STAB);
#ifdef SERVER
if (pl.flags & FL_CROUCHING) {
Animation_PlayerTopTemp(ANIM_SHOOTCROWBAR, 0.5f);
} else {
Animation_PlayerTopTemp(ANIM_CR_SHOOTCROWBAR, 0.42f);
}
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, 5, WEAPON_FORKS, DMG_BLUNT);
if (trace_ent.iBleeds) {
Sound_Play(self, CHAN_WEAPON, "weapon_forks.hitbody");
}
} else {
Sound_Play(self, CHAN_WEAPON, "weapon_forks.hit");
}
#endif
}
void
w_forks_secondary(void)
{
player pl = (player)self;
if (pl.w_attack_next > 0.0) {
return;
}
/* Ammo check */
#ifdef CLIENT
if (pl.a_ammo2 <= 0) {
return;
}
#else
if (pl.ammo_forks <= 0) {
return;
}
#endif
/* Secondary has an ammo based throw function */
#ifdef SERVER
static void Fork_Touch(void) {
setmodel(self, "models/fork.mdl");
/* don't bother with decals, we got squibs */
if (trace_ent.iBleeds) {
FX_Blood(trace_endpos, [1,0,0]);
remove(self);
} else {
FX_Impact(IMPACT_DEFAULT, trace_endpos, trace_plane_normal);
}
if (other.takedamage == DAMAGE_YES) {
Damage_Apply(other, self.owner, 15, WEAPON_FORKS, DMG_GENERIC);
Sound_Play(self, CHAN_WEAPON, "weapon_forks.hitbody");
} else {
Sound_Play(self, CHAN_WEAPON, "weapon_forks.stick");
}
self.movetype = MOVETYPE_NONE;
}
Weapons_MakeVectors();
entity fork = spawn();
setmodel(fork, "models/fork.mdl");
setorigin(fork, Weapons_GetCameraPos() + (v_forward * 16));
fork.owner = self;
fork.velocity = v_forward * 2000;
fork.movetype = MOVETYPE_FLY;
fork.solid = SOLID_BBOX;
fork.angles = vectoangles(fork.velocity);
fork.avelocity[2] = 10;
fork.touch = Fork_Touch;
setsize(fork, [0,0,0], [0,0,0]);
pl.ammo_forks--;
Sound_Play(pl, CHAN_WEAPON, "weapon_forks.throw");
#else
Weapons_ViewPunchAngle([-2,0,0]);
Weapons_ViewAnimation(FORKS_THROW);
#endif
pl.w_attack_next = 0.5f;
pl.w_idle_next = 5.0f;
}
void
w_forks_release(void)
{
player pl = (player)self;
if (pl.w_idle_next > 0.0) {
return;
}
int r;
r = (float)input_sequence % 3;
switch (r) {
case 1:
Weapons_ViewAnimation(FORKS_IDLE1);
pl.w_idle_next = 1.3f;
break;
case 2:
Weapons_ViewAnimation(FORKS_IDLE2);
pl.w_idle_next = 3.0f;
break;
default:
Weapons_ViewAnimation(FORKS_IDLE3);
pl.w_idle_next = 1.285f;
}
}
void
w_forks_crosshair(void)
{
#ifdef CLIENT
static vector cross_pos;
cross_pos = g_hudmins + (g_hudres / 2) + [-12,-12];
drawsubpic(
cross_pos,
[24,24],
"sprites/crosshairs.spr_0.tga",
[72/128,48/128],
[0.1875, 0.1875],
[1,1,1],
1,
DRAWFLAG_NORMAL
);
HUD_DrawAmmo2();
vector aicon_pos = g_hudmins + [g_hudres[0] - 42, g_hudres[1] - 64];
drawpic(
aicon_pos,
"sprites/hud_fork.spr_0.tga",
[32,64],
[1,1,1],
pSeat->m_flAmmo2Alpha,
0
);
#endif
}
float
w_forks_aimanim(void)
{
return w_broom_aimanim();
}
void
w_forks_hudpic(int selected, vector pos, float a)
{
#ifdef CLIENT
if (selected) {
drawsubpic(
pos,
[170,45],
"sprites/tfchud04.spr_0.tga",
[0,135/256],
[170/256,45/256],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[170,45],
"sprites/tfchud03.spr_0.tga",
[0,90/256],
[170/256,45/256],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
}
#endif
}
weapon_t w_forks =
{
.name = "fork",
.id = ITEM_FORKS,
.slot = 0,
.slot_pos = 2,
.draw = w_forks_draw,
.holster = w_forks_holster,
.primary = w_forks_primary,
.secondary = w_forks_secondary,
.reload = __NULL__,
.release = w_forks_release,
.crosshair = w_forks_crosshair,
.precache = w_forks_precache,
.pickup = w_forks_pickup,
.updateammo = w_forks_updateammo,
.wmodel = w_forks_wmodel,
.pmodel = w_forks_pmodel,
.deathmsg = w_forks_deathmsg,
.aimanim = w_forks_aimanim,
.hudpic = w_forks_hudpic
};
/* entity definitions for pickups */
#ifdef SERVER
void
weapon_forks(void)
{
Weapons_InitItem(WEAPON_FORKS);
/*item_pickup item = (item_pickup)self;
item.SetRenderMode(RM_FULLBRIGHT);
item.SetRenderAmt(1.0f);*/
}
#endif

256
src/shared/w_fryingpan.qc Normal file
View file

@ -0,0 +1,256 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
* Copyright (c) 2019-2020 Gethyn ThomasQuail <xylemon@posteo.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
enum
{
FRYINGPAN_IDLE1,
FRYINGPAN_IDLE2,
FRYINGPAN_HIT1,
FRYINGPAN_HIT2,
FRYINGPAN_DRAW,
FRYINGPAN_HOLSTER
};
void
w_fryingpan_precache(void)
{
#ifdef SERVER
Sound_Precache("weapon_fryingpan.hit");
Sound_Precache("weapon_fryingpan.miss");
Sound_Precache("weapon_fryingpan.hitbody");
#endif
precache_model("models/v_pan.mdl");
precache_model("models/w_pan.mdl");
precache_model("models/p_pan.mdl");
}
void
w_fryingpan_updateammo(player pl)
{
w_broom_updateammo(pl);
}
string
w_fryingpan_wmodel(void)
{
return "models/w_pan.mdl";
}
string
w_fryingpan_pmodel(void)
{
return "models/p_pan.mdl";
}
string
w_fryingpan_deathmsg(void)
{
return "";
}
void
w_fryingpan_draw(void)
{
Weapons_SetModel("models/v_pan.mdl");
Weapons_ViewAnimation(FRYINGPAN_DRAW);
}
void
w_fryingpan_holster(void)
{
w_broom_holster();
}
void
w_fryingpan_primary(void)
{
int anim = 0;
vector src;
player pl = (player)self;
if (pl.w_attack_next) {
return;
}
Weapons_MakeVectors();
src = pl.origin + pl.view_ofs;
traceline(src, src + (v_forward * 32), FALSE, pl);
pl.w_attack_next = 1.0f;
pl.w_idle_next = 2.5f;
Weapons_ViewAnimation(FRYINGPAN_HIT1);
#ifdef SERVER
if (pl.flags & FL_CROUCHING) {
Animation_PlayerTopTemp(ANIM_SHOOTCROWBAR, 0.5f);
} else {
Animation_PlayerTopTemp(ANIM_CR_SHOOTCROWBAR, 0.42f);
}
Sound_Play(self, CHAN_WEAPON, "weapon_fryingpan.miss");
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, 5, WEAPON_FRYINGPAN, DMG_BLUNT);
if (trace_ent.iBleeds) {
Sound_Play(self, CHAN_WEAPON, "weapon_fryingpan.hitbody");
}
} else {
Sound_Play(self, CHAN_WEAPON, "weapon_fryingpan.hit");
}
#endif
}
void
w_fryingpan_secondary(void)
{
int anim = 0;
vector src;
player pl = (player)self;
if (pl.w_attack_next) {
return;
}
Weapons_MakeVectors();
src = pl.origin + pl.view_ofs;
traceline(src, src + (v_forward * 32), FALSE, pl);
pl.w_attack_next = 1.0f;
pl.w_idle_next = 2.5f;
Weapons_ViewAnimation(FRYINGPAN_HIT2);
#ifdef SERVER
if (pl.flags & FL_CROUCHING) {
Animation_PlayerTopTemp(ANIM_SHOOTCROWBAR, 0.5f);
} else {
Animation_PlayerTopTemp(ANIM_CR_SHOOTCROWBAR, 0.42f);
}
Sound_Play(self, CHAN_WEAPON, "weapon_fryingpan.miss");
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, 5, WEAPON_FRYINGPAN, DMG_BLUNT);
if (trace_ent.iBleeds) {
Sound_Play(self, CHAN_WEAPON, "weapon_fryingpan.hitbody");
}
} else {
Sound_Play(self, CHAN_WEAPON, "weapon_fryingpan.hit");
}
#endif
}
void
w_fryingpan_release(void)
{
w_broom_release();
}
float
w_fryingpan_aimanim(void)
{
return w_broom_aimanim();
}
void
w_fryingpan_hudpic(int selected, vector pos, float a)
{
#ifdef CLIENT
if (selected) {
drawsubpic(
pos,
[170,45],
"sprites/tfchud04.spr_0.tga",
[0,135/256],
[170/256,45/256],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[170,45],
"sprites/tfchud03.spr_0.tga",
[0,90/256],
[170/256,45/256],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
}
#endif
}
weapon_t w_fryingpan =
{
.name = "fryingpan",
.id = ITEM_FRYINGPAN,
.slot = 0,
.slot_pos = 1,
.draw = w_fryingpan_draw,
.holster = w_fryingpan_holster,
.primary = w_fryingpan_primary,
.secondary = w_fryingpan_secondary,
.reload = __NULL__,
.release = w_fryingpan_release,
.crosshair = __NULL__,
.precache = w_fryingpan_precache,
.pickup = __NULL__,
.updateammo = w_fryingpan_updateammo,
.wmodel = w_fryingpan_wmodel,
.pmodel = w_fryingpan_pmodel,
.deathmsg = w_fryingpan_deathmsg,
.aimanim = w_fryingpan_aimanim,
.hudpic = w_fryingpan_hudpic
};
/* entity definitions for pickups */
#ifdef SERVER
void
weapon_fryingpan(void)
{
Weapons_InitItem(WEAPON_FRYINGPAN);
/*item_pickup item = (item_pickup)self;
item.SetRenderMode(RM_FULLBRIGHT);
item.SetRenderAmt(1.0f);*/
}
#endif

266
src/shared/w_glove.qc Normal file
View file

@ -0,0 +1,266 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
* Copyright (c) 2019-2020 Gethyn ThomasQuail <xylemon@posteo.net>
*
* 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 item_rune_slasher (0 0 1) (-16 -16 0) (16 16 32)
"model" "models/rune_slasher.mdl"
Household DEATH! (2003) ENTITY
Powerup/Weapon that turns players into a similar looking legally
copyrighted character.
*/
enum
{
GLOVE_IDLE,
GLOVE_DRAW,
GLOVE_HOLSTER,
GLOVE_SLICE,
GLOVE_DICE
};
void
w_glove_precache(void)
{
#ifdef SERVER
Sound_Precache("weapon_glove.hit");
Sound_Precache("weapon_glove.miss");
Sound_Precache("weapon_glove.hitbody");
Sound_Precache("weapon_glove.pickup");
#endif
precache_model("models/v_glove.mdl");
precache_model("models/rune_slasher.mdl");
precache_model("models/p_glove.mdl");
}
void
w_glove_updateammo(player pl)
{
w_broom_updateammo(pl);
}
string
w_glove_wmodel(void)
{
return "models/rune_slasher.mdl";
}
string
w_glove_pmodel(void)
{
return "models/p_glove.mdl";
}
string
w_glove_deathmsg(void)
{
return "";
}
void
w_glove_pickup(void)
{
#ifdef SERVER
/* Broadcast a message and sound upon picking up Rune */
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_TEXT);
WriteByte(MSG_MULTICAST, 0);
WriteString(MSG_MULTICAST, sprintf("One... Two... %s's coming for you...", self.netname));
WriteFloat(MSG_MULTICAST, -1);
WriteFloat(MSG_MULTICAST, -1);
WriteByte(MSG_MULTICAST, 0);
WriteByte(MSG_MULTICAST, 255);
WriteByte(MSG_MULTICAST, 0);
WriteByte(MSG_MULTICAST, 0);
WriteByte(MSG_MULTICAST, 255);
WriteByte(MSG_MULTICAST, 0);
WriteByte(MSG_MULTICAST, 0);
WriteFloat(MSG_MULTICAST, 0.2);
WriteFloat(MSG_MULTICAST, 0.5);
WriteFloat(MSG_MULTICAST, 5.0);
WriteFloat(MSG_MULTICAST, 0);
msg_entity = world;
multicast([0,0,0], MULTICAST_ALL);
Sound_Play(self, CHAN_ITEM, "weapon_glove.pickup");
#endif
return TRUE;
}
void
w_glove_draw(void)
{
Weapons_SetModel("models/v_glove.mdl");
Weapons_ViewAnimation(GLOVE_DRAW);
}
void
w_glove_holster(void)
{
Weapons_ViewAnimation(GLOVE_HOLSTER);
}
void
w_glove_primary(void)
{
int anim = 0;
vector src;
player pl = (player)self;
if (pl.w_attack_next) {
return;
}
Weapons_MakeVectors();
src = pl.origin + pl.view_ofs;
traceline(src, src + (v_forward * 32), FALSE, pl);
if (trace_fraction >= 1.0) {
pl.w_attack_next = 0.5f;
} else {
pl.w_attack_next = 0.25f;
}
pl.w_idle_next = 2.5f;
int r = (float)input_sequence % 2;
switch (r) {
case 1:
Weapons_ViewAnimation(GLOVE_SLICE);
pl.w_idle_next = 3.6f;
break;
default:
Weapons_ViewAnimation(GLOVE_DICE);
pl.w_idle_next = 3.6f;
break;
}
#ifdef SERVER
if (pl.flags & FL_CROUCHING) {
Animation_PlayerTopTemp(ANIM_SHOOTCROWBAR, 0.5f);
} else {
Animation_PlayerTopTemp(ANIM_CR_SHOOTCROWBAR, 0.42f);
}
Sound_Play(self, CHAN_WEAPON, "weapon_glove.miss");
if (trace_fraction >= 1.0) {
return;
}
/* Since it has custom decals we do both FX and decal placement */
if (trace_ent.iBleeds) {
FX_Blood(trace_endpos, [1,0,0]);
} else {
FX_Spark(trace_endpos, trace_plane_normal);
int r = (float)input_sequence % 2;
Decals_Place(trace_endpos, r == 1 ? "{slash1" : "{slash2");
}
if (trace_ent.takedamage) {
Damage_Apply(trace_ent, pl, Skill_GetValue("plr_crowbar", 10), WEAPON_GLOVE, DMG_BLUNT);
if (trace_ent.iBleeds) {
Sound_Play(self, CHAN_WEAPON, "weapon_glove.hitbody");
}
} else {
Sound_Play(self, CHAN_WEAPON, "weapon_glove.hit");
}
#endif
}
void
w_glove_release(void)
{
player pl = (player)self;
if (pl.w_idle_next) {
return;
}
Weapons_ViewAnimation(GLOVE_IDLE);
pl.w_idle_next = 2.0f;
}
float
w_glove_aimanim(void)
{
return w_broom_aimanim();
}
void
w_glove_hudpic(int selected, vector pos, float a)
{
#ifdef CLIENT
if (selected) {
drawsubpic(
pos,
[170,45],
"sprites/tfchud04.spr_0.tga",
[0,135/256],
[170/256,45/256],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[170,45],
"sprites/tfchud03.spr_0.tga",
[0,90/256],
[170/256,45/256],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
}
#endif
}
weapon_t w_glove =
{
.name = "glove",
.id = ITEM_GLOVE,
.slot = 1,
.slot_pos = 0,
.draw = w_glove_draw,
.holster = w_glove_holster,
.primary = w_glove_primary,
.secondary = __NULL__,
.reload = __NULL__,
.release = w_glove_release,
.crosshair = __NULL__,
.precache = w_glove_precache,
.pickup = w_glove_pickup,
.updateammo = w_glove_updateammo,
.wmodel = w_glove_wmodel,
.pmodel = w_glove_pmodel,
.deathmsg = w_glove_deathmsg,
.aimanim = w_glove_aimanim,
.hudpic = w_glove_hudpic
};
/* entity definitions for pickups */
#ifdef SERVER
void
item_rune_slasher(void)
{
Weapons_InitItem(WEAPON_GLOVE);
}
#endif

285
src/shared/w_hairspray.qc Normal file
View file

@ -0,0 +1,285 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
* Copyright (c) 2019-2020 Gethyn ThomasQuail <xylemon@posteo.net>
*
* 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_hairspray (0 0 1) (-16 -16 0) (16 16 32)
"model" "models/w_knife.mdl"
Household DEATH! (2003) ENTITY
Flamethrower Hairspray Weapon
*/
enum
{
HAIRSPRAY_IDLE,
HAIRSPRAY_FIRE,
HAIRSPRAY_DRAW,
HAIRSPRAY_HOLSTER
};
void
w_hairspray_precache(void)
{
#ifdef SERVER
Sound_Precache("weapon_hairspray.fire");
#endif
precache_model("sprites/flame.spr");
precache_model("sprites/hud_haircan.spr");
precache_model("models/v_hairspray.mdl");
precache_model("models/w_hairspray.mdl");
precache_model("models/p_hairspray.mdl");
}
void
w_hairspray_updateammo(player pl)
{
#ifdef SERVER
Weapons_UpdateAmmo(pl, __NULL__, pl.ammo_spray, __NULL__);
#endif
}
string
w_hairspray_wmodel(void)
{
return "models/w_hairspray.mdl";
}
string
w_hairspray_pmodel(void)
{
return "models/p_hairspray.mdl";
}
string
w_hairspray_deathmsg(void)
{
return "";
}
int
w_hairspray_pickup(int new, int startammo)
{
#ifdef SERVER
player pl = (player)self;
if (pl.ammo_spray < MAX_A_SPRAY) {
pl.ammo_spray = bound(0, pl.ammo_spray + 20, MAX_A_SPRAY);
} else {
return FALSE;
}
#endif
return TRUE;
}
void
w_hairspray_draw(void)
{
Weapons_SetModel("models/v_hairspray.mdl");
Weapons_ViewAnimation(HAIRSPRAY_DRAW);
}
void
w_hairspray_holster(void)
{
Weapons_ViewAnimation(HAIRSPRAY_HOLSTER);
}
#ifdef SERVER
void
Flame_Touch(void)
{
if (other.takedamage != DAMAGE_YES) {
remove(self);
return;
}
/* anything else that can take damage */
Damage_Apply(other, self.owner, 40, WEAPON_HAIRSPRAY, DMG_BURN);
remove(self);
}
#endif
void
w_hairspray_primary(void)
{
player pl = (player)self;
if (pl.w_attack_next > 0.0) {
return;
}
/* Ammo check */
#ifdef CLIENT
if (pl.a_ammo2 <= 0) {
return;
}
#else
if (pl.ammo_spray <= 0) {
return;
}
#endif
/* Actual firing */
#ifdef CLIENT
Weapons_ViewAnimation(HAIRSPRAY_FIRE);
pl.a_ammo2--;
#else
Weapons_MakeVectors();
entity flame = spawn();
setmodel(flame, "sprites/flame.spr");
setorigin(flame, Weapons_GetCameraPos() + (v_forward * 16));
flame.owner = self;
flame.velocity = v_forward * 300;
flame.movetype = MOVETYPE_FLYMISSILE;
flame.solid = SOLID_BBOX;
//flame.flags |= FL_LAGGEDMOVE;
flame.angles = vectoangles(flame.velocity);
flame.avelocity[2] = 10;
flame.touch = Flame_Touch;
flame.think = Flame_Touch;
flame.nextthink = time + 1.0f;
flame.effects |= EF_BRIGHTLIGHT;
setsize(flame, [0,0,0], [0,0,0]);
pl.ammo_spray--;
Sound_Play(pl, CHAN_WEAPON, "weapon_hairspray.fire");
/* Remove weapon if we run out of ammo */
if (pl.ammo_spray <= 0) {
Weapons_RemoveItem(pl, WEAPON_HAIRSPRAY);
return;
}
#endif
pl.w_attack_next = 0.2f;
pl.w_idle_next = 2.5f;
}
void
w_hairspray_release(void)
{
player pl = (player)self;
if (pl.w_idle_next) {
return;
}
sound(pl, CHAN_WEAPON, "", 1.0, ATTN_NORM);
Weapons_ViewAnimation(HAIRSPRAY_IDLE);
pl.w_idle_next = 2.0f;
}
void
w_hairspray_crosshair(void)
{
#ifdef CLIENT
static vector cross_pos;
cross_pos = g_hudmins + (g_hudres / 2) + [-12,-12];
drawsubpic(
cross_pos,
[24,24],
"sprites/crosshairs.spr_0.tga",
[72/128,48/128],
[0.1875, 0.1875],
[1,1,1],
1,
DRAWFLAG_NORMAL
);
HUD_DrawAmmo2();
vector aicon_pos = g_hudmins + [g_hudres[0] - 42, g_hudres[1] - 64];
drawpic(
aicon_pos,
"sprites/hud_haircan.spr_0.tga",
[32,64],
[1,1,1],
pSeat->m_flAmmo2Alpha,
0
);
#endif
}
float
w_hairspray_aimanim(void)
{
return self.flags & FL_CROUCHING ? ANIM_CR_AIMBOW : ANIM_AIMBOW;
}
void
w_hairspray_hudpic(int selected, vector pos, float a)
{
#ifdef CLIENT
if (selected) {
drawsubpic(
pos,
[170,45],
"sprites/tfchud04.spr_0.tga",
[0,45/256],
[170/256,45/256],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[170,45],
"sprites/tfchud03.spr_0.tga",
[0,0/256],
[170/256,45/256],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
}
#endif
}
weapon_t w_hairspray =
{
.name = "flame",
.id = ITEM_HAIRSPRAY,
.slot = 0,
.slot_pos = 6,
.draw = w_hairspray_draw,
.holster = w_hairspray_holster,
.primary = w_hairspray_primary,
.secondary = __NULL__,
.reload = __NULL__,
.release = w_hairspray_release,
.crosshair = w_hairspray_crosshair,
.precache = w_hairspray_precache,
.pickup = w_hairspray_pickup,
.updateammo = w_hairspray_updateammo,
.wmodel = w_hairspray_wmodel,
.pmodel = w_hairspray_pmodel,
.deathmsg = w_hairspray_deathmsg,
.aimanim = w_hairspray_aimanim,
.hudpic = w_hairspray_hudpic
};
#ifdef SERVER
void
weapon_hairspray(void)
{
Weapons_InitItem(WEAPON_HAIRSPRAY);
/*item_pickup item = (item_pickup)self;
item.SetRenderMode(RM_FULLBRIGHT);
item.SetRenderAmt(1.0f);*/
}
#endif

315
src/shared/w_knife.qc Normal file
View file

@ -0,0 +1,315 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <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_knife (0 0 1) (-16 -16 0) (16 16 32)
"model" "models/w_knife.mdl"
Household DEATH! (2003) ENTITY
Throwable Butcher/Cleaver Knife Weapon
*/
enum
{
KNIFE_IDLE1,
KNIFE_IDLE2,
KNIFE_IDLE3,
KNIFE_THROW,
KNIFE_DRAW,
KNIFE_HOLSTER
};
void
w_knife_precache(void)
{
#ifdef SERVER
Sound_Precache("weapon_knife.hitbody");
Sound_Precache("weapon_knife.move");
Sound_Precache("weapon_knife.stick");
Sound_Precache("weapon_knife.throw");
#endif
precache_model("sprites/hud_knife.spr");
precache_model("models/knife.mdl");
precache_model("models/v_knife.mdl");
precache_model("models/w_knife.mdl");
precache_model("models/p_knife.mdl");
}
void
w_knife_updateammo(player pl)
{
#ifdef SERVER
Weapons_UpdateAmmo(pl, __NULL__, pl.ammo_knives, __NULL__);
#endif
}
string
w_knife_wmodel(void)
{
return "models/w_knife.mdl";
}
string
w_knife_pmodel(void)
{
return "models/p_knife.mdl";
}
string
w_knife_deathmsg(void)
{
return "";
}
int
w_knife_pickup(int new, int startammo)
{
#ifdef SERVER
player pl = (player)self;
if (pl.ammo_knives < MAX_A_KNIVES) {
pl.ammo_knives = bound(0, pl.ammo_knives + 1, MAX_A_KNIVES);
} else {
return FALSE;
}
#endif
return TRUE;
}
void
w_knife_draw(void)
{
Weapons_SetModel("models/v_knife.mdl");
Weapons_ViewAnimation(KNIFE_DRAW);
}
void
w_knife_holster(void)
{
Weapons_ViewAnimation(KNIFE_HOLSTER);
}
void
w_knife_primary(void)
{
player pl = (player)self;
if (pl.w_attack_next > 0.0) {
return;
}
/* Ammo check */
#ifdef CLIENT
if (pl.a_ammo2 <= 0) {
return;
}
#else
if (pl.ammo_knives <= 0) {
return;
}
#endif
/* Actual firing */
#ifdef SERVER
static void Knife_Touch(void) {
/* Has two submodels, changes random in view and world model */
setmodel(self, "models/knife.mdl");
/* Bleed and remove model if player, stick and spark if wall */
if (trace_ent.iBleeds) {
FX_Blood(trace_endpos, [1,0,0]);
remove(self);
} else {
FX_Spark(trace_endpos, trace_plane_normal);
}
if (other.takedamage == DAMAGE_YES) {
Damage_Apply(other, self.owner, 15, WEAPON_KNIFE, DMG_GENERIC);
Sound_Play(self, CHAN_WEAPON, "weapon_knife.hitbody");
} else {
Sound_Play(self, CHAN_WEAPON, "weapon_knife.stick");
}
self.movetype = MOVETYPE_NONE;
}
Weapons_MakeVectors();
entity knife = spawn();
setmodel(knife, "models/w_knife.mdl");
setorigin(knife, Weapons_GetCameraPos());
knife.owner = self;
knife.velocity = v_forward * 1200;
knife.movetype = MOVETYPE_FLY;
knife.solid = SOLID_BBOX;
knife.angles = vectoangles(knife.velocity);
knife.avelocity[2] = 10;
knife.touch = Knife_Touch;
/* TODO Knife randomly changes submodel upon firing, no API support yet
* int r = (float)input_sequence % 2;
* setcustomskin(knife, "", r == 1 ? "geomset 1 0\n" : "geomset 1 1\n"); */
setsize(knife, [0,0,0], [0,0,0]);
/* The thrown knife has it's own movement sound */
Sound_Play(knife, CHAN_WEAPON, "weapon_knife.move");
pl.ammo_knives--;
Sound_Play(pl, CHAN_WEAPON, "weapon_knife.throw");
/* Remove weapon if we run out of knives */
if (pl.ammo_knives <= 0) {
Weapons_RemoveItem(pl, WEAPON_KNIFE);
return;
}
#else
Weapons_ViewPunchAngle([-2,0,0]);
Weapons_ViewAnimation(KNIFE_THROW);
/* Knife randomly changes submodel upon firing */
int r = (float)input_sequence % 2;
Weapons_SetGeomset(r == 1 ? "geomset 0 0\n" : "geomset 0 1\n");
#endif
pl.w_attack_next = 0.8f;
pl.w_idle_next = 5.0f;
}
void
w_knife_release(void)
{
player pl = (player)self;
if (pl.w_idle_next > 0.0) {
return;
}
int r;
r = (float)input_sequence % 3;
switch (r) {
case 1:
Weapons_ViewAnimation(KNIFE_IDLE1);
pl.w_idle_next = 2.0f;
break;
case 2:
Weapons_ViewAnimation(KNIFE_IDLE2);
pl.w_idle_next = 3.0f;
break;
default:
Weapons_ViewAnimation(KNIFE_IDLE3);
pl.w_idle_next = 1.285f;
}
}
void
w_knife_crosshair(void)
{
#ifdef CLIENT
static vector cross_pos;
cross_pos = g_hudmins + (g_hudres / 2) + [-12,-12];
drawsubpic(
cross_pos,
[24,24],
"sprites/crosshairs.spr_0.tga",
[72/128,48/128],
[0.1875, 0.1875],
[1,1,1],
1,
DRAWFLAG_NORMAL
);
HUD_DrawAmmo2();
vector aicon_pos = g_hudmins + [g_hudres[0] - 42, g_hudres[1] - 64];
drawpic(
aicon_pos,
"sprites/hud_knife.spr_0.tga",
[32,64],
[1,1,1],
pSeat->m_flAmmo2Alpha,
0
);
#endif
}
float
w_knife_aimanim(void)
{
return self.flags & FL_CROUCHING ? ANIM_CR_AIMBOW : ANIM_AIMBOW;
}
void
w_knife_hudpic(int selected, vector pos, float a)
{
#ifdef CLIENT
if (selected) {
drawsubpic(
pos,
[170,45],
"sprites/640hud5.spr_0.tga",
[0,0],
[170/256,45/256],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[170,45],
"sprites/640hud2.spr_0.tga",
[0,0],
[170/256,45/256],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
}
#endif
}
weapon_t w_knife =
{
.name = "knife",
.id = ITEM_KNIFE,
.slot = 0,
.slot_pos = 3,
.draw = w_knife_draw,
.holster = w_knife_holster,
.primary = w_knife_primary,
.secondary = __NULL__,
.reload = __NULL__,
.release = w_knife_release,
.crosshair = w_knife_crosshair,
.precache = w_knife_precache,
.pickup = w_knife_pickup,
.updateammo = w_knife_updateammo,
.wmodel = w_knife_wmodel,
.pmodel = w_knife_pmodel,
.deathmsg = w_knife_deathmsg,
.aimanim = w_knife_aimanim,
.hudpic = w_knife_hudpic
};
#ifdef SERVER
void
weapon_knife(void)
{
Weapons_InitItem(WEAPON_KNIFE);
/*item_pickup item = (item_pickup)self;
item.SetRenderMode(RM_FULLBRIGHT);
item.SetRenderAmt(1.0f);
item.SetFloating(TRUE);*/
}
#endif

276
src/shared/w_lego.qc Normal file
View file

@ -0,0 +1,276 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <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_handgrenade (0 0 1) (-16 -16 0) (16 16 32)
"model" "models/w_lego.mdl"
HALF-LIFE (1998) ENTITY
Handgrenade Weapon
*/
enum
{
LEGO_IDLE,
LEGO_DRAW,
LEGO_PULLPIN,
LEGO_THROW,
LEGO_HOLSTER
};
void w_lego_precache(void)
{
precache_model("sprites/hud_lego.spr");
precache_model("models/v_lego.mdl");
precache_model("models/w_lego.mdl");
precache_model("models/p_lego.mdl");
}
void w_lego_updateammo(player pl)
{
#ifdef SERVER
Weapons_UpdateAmmo(pl, -1, pl.ammo_legogrenade, -1);
#endif
}
string w_lego_wmodel(void)
{
return "models/w_lego.mdl";
}
string w_lego_pmodel(void)
{
return "models/p_lego.mdl";
}
string w_lego_deathmsg(void)
{
return "";
}
int w_lego_pickup(int new, int startammo)
{
#ifdef SERVER
player pl = (player)self;
if (pl.ammo_legogrenade < MAX_A_LEGOGRENADE) {
pl.ammo_legogrenade = bound(0, pl.ammo_legogrenade + 1, MAX_A_LEGOGRENADE);
} else {
return FALSE;
}
#endif
return TRUE;
}
#ifdef SERVER
void w_lego_throw(void)
{
static void WeaponLego_Throw_Touch(void) {
float dmg = Skill_GetValue("plr_hand_grenade", 150);
FX_Lego(trace_endpos);
Damage_Radius(self.origin, self.owner, dmg, dmg * 1.5f, TRUE, WEAPON_LEGO);
remove(self);
}
player pl = (player)self;
vector vPLAngle = pl.v_angle;
if (vPLAngle[0] < 0) {
vPLAngle[0] = -10 + vPLAngle[0] * ((90 - 10) / 90.0);
} else {
vPLAngle[0] = -10 + vPLAngle[0] * ((90 + 10) / 90.0);
}
float flVel = (90 - vPLAngle[0]) * 5;
if (flVel > 1000) {
flVel = 1000;
}
makevectors(vPLAngle);
vector vecSrc = pl.origin + pl.view_ofs + v_forward * 16;
vector vecThrow = v_forward * flVel + pl.velocity;
entity eGrenade = spawn();
eGrenade.owner = pl;
eGrenade.classname = "remove_me";
eGrenade.solid = SOLID_BBOX;
eGrenade.frame = 1;
eGrenade.velocity = vecThrow;
eGrenade.movetype = MOVETYPE_BOUNCE;
eGrenade.touch = WeaponLego_Throw_Touch;
eGrenade.nextthink = time + 4.0f;
setmodel(eGrenade, "models/lego2.mdl");
setsize(eGrenade, [0,0,0], [0,0,0]);
setorigin(eGrenade, vecSrc);
}
#endif
void w_lego_draw(void)
{
#ifdef CLIENT
Weapons_SetModel("models/v_lego.mdl");
Weapons_ViewAnimation(LEGO_DRAW);
#endif
}
void w_lego_holster(void)
{
}
void w_lego_primary(void)
{
player pl = (player)self;
if (pl.w_attack_next > 0.0) {
return;
}
/* We're abusing this network variable for the holding check */
if (pl.a_ammo3 > 0) {
return;
}
/* Ammo check */
#ifdef CLIENT
if (pl.a_ammo2 <= 0) {
return;
}
#else
if (pl.ammo_legogrenade <= 0) {
return;
}
#endif
#ifdef CLIENT
Weapons_ViewAnimation(LEGO_PULLPIN);
#endif
pl.a_ammo3 = 1;
pl.w_attack_next = 0.5f;
pl.w_idle_next = 0.5f;
}
void w_lego_hud(void)
{
#ifdef CLIENT
static vector cross_pos;
cross_pos = g_hudmins + (g_hudres / 2) + [-12,-12];
drawsubpic(
cross_pos,
[24,24],
"sprites/crosshairs.spr_0.tga",
[72/128,48/128],
[0.1875, 0.1875],
[1,1,1],
1,
DRAWFLAG_NORMAL
);
HUD_DrawAmmo2();
vector aicon_pos = g_hudmins + [g_hudres[0] - 42, g_hudres[1] - 64];
drawpic(
aicon_pos,
"sprites/hud_lego.spr_0.tga",
[32,64],
[1,1,1],
pSeat->m_flAmmo2Alpha,
0
);
#endif
}
void w_lego_release(void)
{
player pl = (player)self;
if (pl.w_idle_next > 0.0) {
return;
}
if (pl.a_ammo3 == 1) {
#ifdef CLIENT
pl.a_ammo2--;
Weapons_ViewAnimation(LEGO_THROW);
#else
pl.ammo_legogrenade--;
w_lego_throw();
#endif
pl.a_ammo3 = 2;
pl.w_attack_next = 1.0f;
pl.w_idle_next = 0.5f;
} else if (pl.a_ammo3 == 2) {
#ifdef CLIENT
Weapons_ViewAnimation(LEGO_DRAW);
#else
if (!pl.ammo_legogrenade) {
Weapons_RemoveItem(pl, WEAPON_LEGO);
}
#endif
pl.w_attack_next = 0.5f;
pl.w_idle_next = 0.5f;
pl.a_ammo3 = 0;
} else {
Weapons_ViewAnimation(LEGO_IDLE);
pl.w_idle_next = 3.0f;
}
}
float
w_lego_aimanim(void)
{
return self.flags & FL_CROUCHING ? ANIM_CR_AIMCROWBAR : ANIM_AIMCROWBAR;
}
void
w_lego_hudpic(int selected, vector pos, float a)
{
#ifdef CLIENT
if (selected) {
drawsubpic(pos, [170,45], "sprites/640hud6.spr_0.tga", [0,0], [170/256,45/256], g_hud_color, a, DRAWFLAG_ADDITIVE);
} else {
drawsubpic(pos, [170,45], "sprites/640hud3.spr_0.tga", [0,0], [170/256,45/256], g_hud_color, a, DRAWFLAG_ADDITIVE);
}
#endif
}
weapon_t w_lego =
{
.name = "lego",
.id = ITEM_LEGO,
.slot = 0,
.slot_pos = 5,
.draw = w_lego_draw,
.holster = w_lego_holster,
.primary = w_lego_primary,
.secondary = __NULL__,
.reload = __NULL__,
.release = w_lego_release,
.crosshair = w_lego_hud,
.precache = w_lego_precache,
.pickup = w_lego_pickup,
.updateammo = w_lego_updateammo,
.wmodel = w_lego_wmodel,
.pmodel = w_lego_pmodel,
.deathmsg = w_lego_deathmsg,
.aimanim = w_lego_aimanim,
.hudpic = w_lego_hudpic
};
#ifdef SERVER
void weapon_lego(void)
{
Weapons_InitItem(WEAPON_LEGO);
/*item_pickup item = (item_pickup)self;
item.SetRenderMode(RM_FULLBRIGHT);
item.SetRenderAmt(1.0f);*/
}
#endif

View file

@ -0,0 +1,299 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <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_legolauncher (0 0 1) (-16 -16 0) (16 16 32)
"model" "models/w_legolauncher.mdl"
Household DEATH! (2003) ENTITY
Lego Launcher Weapon
*/
enum
{
LEGOLAUNCHER_IDLE,
LEGOLAUNCHER_SHOOT,
LEGOLAUNCHER_DRAW,
LEGOLAUNCHER_HOLSTER
};
void
w_legolauncher_precache(void)
{
#ifdef SERVER
Sound_Precache("weapon_legolauncher.fire");
Sound_Precache("weapon_legolauncher.hit");
Sound_Precache("weapon_legolauncher.hitbody");
#endif
precache_model("models/lego.mdl");
precache_model("models/v_legolauncher.mdl");
precache_model("models/w_legolauncher.mdl");
precache_model("models/p_legolauncher.mdl");
}
void
w_legolauncher_updateammo(player pl)
{
#ifdef SERVER
Weapons_UpdateAmmo(pl, __NULL__, pl.ammo_legos, __NULL__);
#endif
}
string
w_legolauncher_wmodel(void)
{
return "models/w_legolauncher.mdl";
}
string
w_legolauncher_pmodel(void)
{
return "models/p_legolauncher.mdl";
}
string
w_legolauncher_deathmsg(void)
{
return "";
}
int
w_legolauncher_pickup(int new, int startammo)
{
#ifdef SERVER
player pl = (player)self;
if (pl.ammo_legos < MAX_A_LEGOS) {
pl.ammo_legos = bound(0, pl.ammo_legos + 40, MAX_A_LEGOS);
} else {
return FALSE;
}
#endif
return TRUE;
}
void
w_legolauncher_draw(void)
{
Weapons_SetModel("models/v_legolauncher.mdl");
Weapons_ViewAnimation(LEGOLAUNCHER_DRAW);
}
void
w_legolauncher_holster(void)
{
Weapons_ViewAnimation(LEGOLAUNCHER_HOLSTER);
}
#ifdef SERVER
void
w_legolauncher_shootlego(void)
{
player pl = (player)self;
static void Lego_Touch(void) {
FX_LegoPiece(trace_endpos);
/* different effects/sounds for players and walls */
if (trace_ent.iBleeds) {
FX_Blood(trace_endpos, [1,0,0]);
} else {
FX_Impact(IMPACT_DEFAULT, self.origin, trace_plane_normal);
}
if (other.takedamage == DAMAGE_YES) {
Damage_Apply(other, self.owner, 15, WEAPON_LEGOLAUNCHER, DMG_GENERIC);
Sound_Play(self, CHAN_WEAPON, "weapon_legolauncher.hitbody");
} else {
Sound_Play(self, CHAN_WEAPON, "weapon_legolauncher.hit");
}
remove(self);
}
Weapons_MakeVectors();
entity lego = spawn();
setmodel(lego, "models/lego.mdl");
/* TODO needs to spawn more to the right */
setorigin(lego, Weapons_GetCameraPos() + (v_forward * 16) + (v_right * 4) + (v_up * -8));
lego.owner = self;
lego.velocity = v_forward * 2000;
lego.movetype = MOVETYPE_FLY;
lego.solid = SOLID_BBOX;
lego.angles = vectoangles(lego.velocity);
lego.avelocity[2] = 10;
lego.touch = Lego_Touch;
setsize(lego, [0,0,0], [0,0,0]);
if (self.flags & FL_CROUCHING)
Animation_PlayerTopTemp(ANIM_SHOOT1HAND, 0.45f);
else
Animation_PlayerTopTemp(ANIM_CR_SHOOT1HAND, 0.45f);
}
#endif
void
w_legolauncher_primary(void)
{
player pl = (player)self;
if (pl.w_attack_next > 0.0) {
return;
}
/* Ammo check */
#ifdef CLIENT
if (pl.a_ammo2 <= 0) {
return;
}
#else
if (pl.ammo_legos <= 0) {
return;
}
#endif
/* Actual firing */
#ifdef SERVER
w_legolauncher_shootlego();
pl.ammo_legos--;
Sound_Play(pl, CHAN_WEAPON, "weapon_legolauncher.fire");
#else
Weapons_ViewPunchAngle([-2,0,0]);
Weapons_ViewAnimation(LEGOLAUNCHER_SHOOT);
#endif
pl.w_attack_next = 0.15f;
pl.w_idle_next = 5.0f;
}
void
w_legolauncher_release(void)
{
player pl = (player)self;
if (pl.w_idle_next > 0.0) {
return;
}
Weapons_ViewAnimation(LEGOLAUNCHER_IDLE);
pl.w_idle_next = 3.0f;
}
void
w_legolauncher_crosshair(void)
{
#ifdef CLIENT
vector aicon_pos;
static vector cross_pos;
cross_pos = g_hudmins + (g_hudres / 2) + [-12,-12];
drawsubpic(
cross_pos,
[24,24],
"sprites/crosshairs.spr_0.tga",
[72/128,48/128],
[0.1875, 0.1875],
[1,1,1],
1,
DRAWFLAG_NORMAL
);
HUD_DrawAmmo2();
aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42];
drawsubpic(
aicon_pos,
[52,20],
"sprites/640_death.spr_0.tga",
[0/128,100/128],
[60/128,20/128],
[1,1,1],
pSeat->m_flAmmo2Alpha,
0
);
#endif
}
float
w_legolauncher_aimanim(void)
{
return self.flags & FL_CROUCHING ? ANIM_CR_AIMBOW : ANIM_AIMBOW;
}
void
w_legolauncher_hudpic(int selected, vector pos, float a)
{
#ifdef CLIENT
if (selected) {
drawsubpic(
pos,
[170,45],
"sprites/640hud5.spr_0.tga",
[0,0],
[170/256,45/256],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[170,45],
"sprites/640hud2.spr_0.tga",
[0,0],
[170/256,45/256],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
}
#endif
}
weapon_t w_legolauncher =
{
.name = "legoblock",
.id = ITEM_LEGOLAUNCHER,
.slot = 0,
.slot_pos = 7,
.draw = w_legolauncher_draw,
.holster = w_legolauncher_holster,
.primary = w_legolauncher_primary,
.secondary = __NULL__,
.reload = __NULL__,
.release = w_legolauncher_release,
.crosshair = w_legolauncher_crosshair,
.precache = w_legolauncher_precache,
.pickup = w_legolauncher_pickup,
.updateammo = w_legolauncher_updateammo,
.wmodel = w_legolauncher_wmodel,
.pmodel = w_legolauncher_pmodel,
.deathmsg = w_legolauncher_deathmsg,
.aimanim = w_legolauncher_aimanim,
.hudpic = w_legolauncher_hudpic
};
#ifdef SERVER
void
weapon_legolauncher(void)
{
Weapons_InitItem(WEAPON_LEGOLAUNCHER);
/*item_pickup item = (item_pickup)self;
item.SetRenderMode(RM_FULLBRIGHT);
item.SetRenderAmt(1.0f);*/
}
#endif

298
src/shared/w_machette.qc Normal file
View file

@ -0,0 +1,298 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
* Copyright (c) 2019-2020 Gethyn ThomasQuail <xylemon@posteo.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
enum
{
MACHETTE_IDLE1,
MACHETTE_IDLE2,
MACHETTE_IDLE3,
MACHETTE_THROW,
MACHETTE_DRAW,
MACHETTE_HOLSTER
};
void
w_machette_precache(void)
{
#ifdef SERVER
Sound_Precache("weapon_crowbar.hit");
Sound_Precache("weapon_crowbar.miss");
Sound_Precache("weapon_crowbar.hitbody");
#endif
precache_model("models/v_machette.mdl");
precache_model("models/rune_stalker.mdl");
precache_model("models/p_machette.mdl");
}
void
w_machette_updateammo(player pl)
{
w_broom_updateammo(pl);
}
string
w_machette_wmodel(void)
{
return "models/w_machette.mdl";
}
string
w_machette_pmodel(void)
{
return "models/p_machette.mdl";
}
string
w_machette_deathmsg(void)
{
return "";
}
void
w_machette_pickup(void)
{
#ifdef SERVER
/* Broadcast a message and sound upon picking up Rune */
Sound_Play(self, CHAN_ITEM, "weapon_machette.pickup");
env_message_single(self, "Activating Rune STALKER!");
#endif
return TRUE;
}
void
w_machette_draw(void)
{
Weapons_SetModel("models/v_machette.mdl");
Weapons_ViewAnimation(MACHETTE_DRAW);
}
void
w_machette_holster(void)
{
Weapons_ViewAnimation(MACHETTE_HOLSTER);
}
void
w_machette_primary(void)
{
int anim = 0;
vector src;
player pl = (player)self;
if (pl.w_attack_next) {
return;
}
Weapons_MakeVectors();
src = pl.origin + pl.view_ofs;
traceline(src, src + (v_forward * 32), FALSE, pl);
pl.w_attack_next = 0.4f;
pl.w_idle_next = 2.5f;
Weapons_ViewAnimation(MACHETTE_THROW);
#ifdef SERVER
if (pl.flags & FL_CROUCHING) {
Animation_PlayerTopTemp(ANIM_SHOOTCROWBAR, 0.5f);
} else {
Animation_PlayerTopTemp(ANIM_CR_SHOOTCROWBAR, 0.42f);
}
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, 5, WEAPON_MACHETTE, DMG_BLUNT);
if (trace_ent.iBleeds) {
Sound_Play(self, CHAN_WEAPON, "weapon_machette.hitbody");
}
} else {
Sound_Play(self, CHAN_WEAPON, "weapon_machette.hit");
}
#endif
}
#ifdef SERVER
void
w_machette_throw(void)
{
player pl = (player)self;
static void Machette_Touch(void) {
setmodel(self, "models/machette.mdl");
/* squibs */
if (trace_ent.iBleeds) {
FX_Blood(trace_endpos, [1,0,0]);
remove(self);
} else {
FX_Impact(IMPACT_DEFAULT, trace_endpos, trace_plane_normal);
}
if (other.takedamage == DAMAGE_YES) {
Damage_Apply(other, self.owner, 15, WEAPON_MACHETTE, DMG_GENERIC);
Sound_Play(self, CHAN_WEAPON, "weapon_machette.hitbody");
} else {
Sound_Play(self, CHAN_WEAPON, "weapon_machette.stick");
}
self.movetype = MOVETYPE_NONE;
}
Weapons_MakeVectors();
entity machette = spawn();
setmodel(machette, "models/machette.mdl");
setorigin(machette, Weapons_GetCameraPos() + (v_forward * 16));
machette.owner = self;
machette.velocity = v_forward * 2000;
machette.movetype = MOVETYPE_FLY;
machette.solid = SOLID_BBOX;
machette.angles = vectoangles(machette.velocity);
machette.avelocity[2] = 10;
machette.touch = Machette_Touch;
setsize(machette, [0,0,0], [0,0,0]);
if (self.flags & FL_CROUCHING)
Animation_PlayerTopTemp(ANIM_SHOOT1HAND, 0.45f);
else
Animation_PlayerTopTemp(ANIM_CR_SHOOT1HAND, 0.45f);
}
#endif
void
w_machette_secondary(void)
{
player pl = (player)self;
if (pl.w_attack_next > 0.0) {
return;
}
/* Actual firing */
#ifdef SERVER
w_machette_throw();
Sound_Play(pl, CHAN_WEAPON, "weapon_machette.throw");
#else
Weapons_ViewPunchAngle([-2,0,0]);
Weapons_ViewAnimation(MACHETTE_THROW);
#endif
pl.w_attack_next = 0.5f;
pl.w_idle_next = 5.0f;
}
void
w_machette_release(void)
{
player pl = (player)self;
if (pl.w_idle_next > 0.0) {
return;
}
int r;
r = (float)input_sequence % 3;
switch (r) {
case 1:
Weapons_ViewAnimation(MACHETTE_IDLE1);
pl.w_idle_next = 1.3f;
break;
case 2:
Weapons_ViewAnimation(MACHETTE_IDLE2);
pl.w_idle_next = 3.0f;
break;
default:
Weapons_ViewAnimation(MACHETTE_IDLE3);
pl.w_idle_next = 1.285f;
}
}
float
w_machette_aimanim(void)
{
return w_broom_aimanim();
}
void
w_machette_hudpic(int selected, vector pos, float a)
{
#ifdef CLIENT
if (selected) {
drawsubpic(
pos,
[170,45],
"sprites/tfchud04.spr_0.tga",
[0,135/256],
[170/256,45/256],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[170,45],
"sprites/tfchud03.spr_0.tga",
[0,90/256],
[170/256,45/256],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
}
#endif
}
weapon_t w_machette =
{
.name = "machette",
.id = ITEM_MACHETTE,
.slot = 1,
.slot_pos = 1,
.draw = w_machette_draw,
.holster = w_machette_holster,
.primary = w_machette_primary,
.secondary = w_machette_secondary,
.reload = __NULL__,
.release = w_machette_release,
.crosshair = __NULL__,
.precache = w_machette_precache,
.pickup = w_machette_pickup,
.updateammo = w_machette_updateammo,
.wmodel = w_machette_wmodel,
.pmodel = w_machette_pmodel,
.deathmsg = w_machette_deathmsg,
.aimanim = w_machette_aimanim,
.hudpic = w_machette_hudpic
};
/* entity definitions for pickups */
#ifdef SERVER
void
rune_stalker(void)
{
Weapons_InitItem(WEAPON_MACHETTE);
}
#endif

View file

@ -0,0 +1,357 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <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_sodalauncher (0 0 1) (-16 -16 0) (16 16 32)
"model" "models/w_soda.mdl"
HALF-LIFE (1998) ENTITY
MP5/9mmAR Weapon
Same as weapon_9mmAR
*/
/* Animations */
enum
{
SODA_IDLE,
SODA_IDLE_NOSODA,
SODA_SHOOT_RELOAD,
SODA_SHOOT,
SODA_DRAW,
SODA_DRAW_NOSODA,
SODA_HOLSTER,
SODA_HOLSTER_NOSODA
};
void
w_sodalauncher_precache(void)
{
#ifdef SERVER
Sound_Precache("weapon_sodalauncher.fire");
Sound_Precache("weapon_sodalauncher.explode");
#endif
precache_model("sprites/hud_sodacan.spr");
precache_model("models/v_soda.mdl");
precache_model("models/w_soda.mdl");
precache_model("models/p_soda.mdl");
precache_model("models/sodacan.mdl");
}
int
w_sodalauncher_pickup(int new, int startammo)
{
#ifdef SERVER
player pl = (player)self;
if (pl.ammo_soda < MAX_A_SODA) {
pl.ammo_soda = bound(0, pl.ammo_soda + 3, MAX_A_SODA);
} else {
return FALSE;
}
#endif
return TRUE;
}
void
w_sodalauncher_updateammo(player pl)
{
#ifdef SERVER
Weapons_UpdateAmmo(pl, __NULL__, pl.ammo_soda, __NULL__);
#endif
}
string
w_sodalauncher_wmodel(void)
{
return "models/w_soda.mdl";
}
string
w_sodalauncher_pmodel(void)
{
return "models/p_soda.mdl";
}
string
w_sodalauncher_deathmsg(void)
{
return "";
}
void
w_sodalauncher_draw(void)
{
#ifdef CLIENT
Weapons_SetModel("models/v_soda.mdl");
Weapons_ViewAnimation(SODA_DRAW);
/* needs the skin value to be set, no API yet
* the soda cans in the viewmodel sync up with
* the projectile and spill decals */
#endif
}
void
w_sodalauncher_holster(void)
{
Weapons_ViewAnimation(SODA_HOLSTER);
}
/* TODO now just need parameters */
#ifdef SERVER
void
w_sodalauncher_shoot(void)
{
player pl = (player)self;
/* Apply force */
if (pl.flags & FL_ONGROUND) {
pl.velocity += v_forward * -100;
} else {
pl.velocity += v_forward * -300;
}
static void Soda_ExplodeTouch(void) {
float dmg = Skill_GetValue("plr_9mmAR_grenade", 150);
FX_Soda(trace_endpos, self.skin);
Damage_Radius(self.origin, self.owner, dmg, dmg * 2.5f, TRUE, WEAPON_SODALAUNCHER);
Sound_Play(self, 1, "weapon_sodalauncher.explode");
remove(self);
}
Weapons_MakeVectors();
entity soda = spawn();
setmodel(soda, "models/sodacan.mdl");
setorigin(soda, Weapons_GetCameraPos() + (v_forward * 16));
soda.skin = floor(random(0,6));
soda.owner = self;
soda.velocity = v_forward * 800;
soda.angles = vectoangles(soda.velocity);
soda.avelocity[0] = random(-100, -500);
soda.gravity = 0.5f;
soda.movetype = MOVETYPE_BOUNCE;
//soda.flags |= FL_LAGGEDMOVE;
soda.solid = SOLID_BBOX;
setsize(soda, [0,0,0], [0,0,0]);
soda.touch = Soda_ExplodeTouch;
}
#else
/* TODO make server side
* Sprite code in Nuclide is still WIP
* so this is client-only for now */
void
w_sodalauncher_exhaust(void) {
env_sprite eExhaust = spawn(env_sprite);
setorigin(eExhaust, Weapons_GetCameraPos() + (v_forward * 16));
setmodel(eExhaust, "sprites/co2_puff.spr");
eExhaust.effects = EF_ADDITIVE;
eExhaust.drawmask = MASK_ENGINE;
eExhaust.maxframe = modelframecount(eExhaust.modelindex);
eExhaust.loops = 0;
eExhaust.scale = 0.5f;
eExhaust.framerate = 20;
eExhaust.nextthink = time + 0.05f;
}
#endif
void
w_sodalauncher_primary(void)
{
player pl = (player)self;
if (pl.w_attack_next > 0.0) {
return;
}
/* Ammo check */
#ifdef CLIENT
if (pl.a_ammo2 <= 0) {
return;
}
#else
if (pl.ammo_soda <= 0) {
return;
}
#endif
/* Actual firing
* TODO make this one fast straight */
#ifdef CLIENT
Weapons_ViewPunchAngle([-10,0,0]);
Weapons_ViewAnimation(SODA_SHOOT_RELOAD);
w_sodalauncher_exhaust();
#else
w_sodalauncher_shoot();
pl.ammo_soda--;
Sound_Play(pl, CHAN_WEAPON, "weapon_sodalauncher.fire");
#endif
pl.w_attack_next = 1.0f;
pl.w_idle_next = 10.0f;
}
/* TODO Actual secondary fire is the current primary fire code, just WIP */
void
w_sodalauncher_secondary(void)
{
player pl = (player)self;
if (pl.w_attack_next > 0.0) {
return;
}
/* Ammo check */
#ifdef CLIENT
if (pl.a_ammo2 <= 0) {
return;
}
#else
if (pl.ammo_soda <= 0) {
return;
}
#endif
/* TODO make this one sag and slower */
#ifdef CLIENT
Weapons_ViewPunchAngle([-10,0,0]);
Weapons_ViewAnimation(SODA_SHOOT_RELOAD);
w_sodalauncher_exhaust();
#else
w_sodalauncher_shoot();
pl.ammo_soda--;
Sound_Play(pl, CHAN_WEAPON, "weapon_sodalauncher.fire");
#endif
pl.w_attack_next = 1.0f;
pl.w_idle_next = 10.0f;
}
void
w_sodalauncher_release(void)
{
player pl = (player)self;
if (pl.w_idle_next) {
return;
}
Weapons_ViewAnimation(SODA_IDLE);
pl.w_idle_next = 3.0f;
}
void
w_sodalauncher_crosshair(void)
{
#ifdef CLIENT
static vector cross_pos;
cross_pos = g_hudmins + (g_hudres / 2) + [-12,-12];
drawsubpic(
cross_pos,
[24,24],
"sprites/crosshairs.spr_0.tga",
[72/128,48/128],
[0.1875, 0.1875],
[1,1,1],
1,
DRAWFLAG_NORMAL
);
HUD_DrawAmmo2();
vector aicon_pos = g_hudmins + [g_hudres[0] - 42, g_hudres[1] - 64];
drawpic(
aicon_pos,
"sprites/hud_sodacan.spr_0.tga",
[32,64],
[1,1,1],
pSeat->m_flAmmo2Alpha,
0
);
#endif
}
float
w_sodalauncher_aimanim(void)
{
return self.flags & FL_CROUCHING ? ANIM_CR_AIMBOW : ANIM_AIMBOW;
}
void
w_sodalauncher_hudpic(int selected, vector pos, float a)
{
#ifdef CLIENT
if (selected) {
drawsubpic(
pos,
[170,45],
"sprites/640hud4.spr_0.tga",
[0,135/256],
[170/256,45/256],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[170,45],
"sprites/640hud1.spr_0.tga",
[0,135/256],
[170/256,45/256],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
}
#endif
}
weapon_t w_sodalauncher = {
.name = "sodacan",
.id = ITEM_SODALAUNCHER,
.slot = 0,
.slot_pos = 4,
.draw = w_sodalauncher_draw,
.holster = w_sodalauncher_holster,
.primary = w_sodalauncher_primary,
.secondary = w_sodalauncher_secondary,
.reload = __NULL__,
.release = w_sodalauncher_release,
.crosshair = w_sodalauncher_crosshair,
.precache = w_sodalauncher_precache,
.pickup = w_sodalauncher_pickup,
.updateammo = w_sodalauncher_updateammo,
.wmodel = w_sodalauncher_wmodel,
.pmodel = w_sodalauncher_pmodel,
.deathmsg = w_sodalauncher_deathmsg,
.aimanim = w_sodalauncher_aimanim,
.hudpic = w_sodalauncher_hudpic
};
#ifdef SERVER
void
weapon_sodalauncher(void)
{
Weapons_InitItem(WEAPON_SODALAUNCHER);
/*item_pickup item = (item_pickup)self;
item.SetRenderMode(RM_FULLBRIGHT);
item.SetRenderAmt(1.0f);
item.SetFloating(TRUE);*/
}
#endif

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

@ -0,0 +1,39 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <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_BROOM,
WEAPON_FRYINGPAN,
WEAPON_FORKS,
WEAPON_KNIFE,
WEAPON_SODALAUNCHER,
WEAPON_LEGO,
WEAPON_HAIRSPRAY,
WEAPON_LEGOLAUNCHER,
WEAPON_GLOVE,
WEAPON_MACHETTE
};
#define MAX_A_FORKS 25
#define MAX_A_KNIVES 15
#define MAX_A_LEGOGRENADE 3
#define MAX_A_LEGOS 200
#define MAX_A_SODA 24
#define MAX_A_SPRAY 100

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

@ -0,0 +1,30 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <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_broom,
w_fryingpan,
w_forks,
w_knife,
w_sodalauncher,
w_lego,
w_hairspray,
w_legolauncher,
w_glove,
w_machette
};

View file

@ -0,0 +1,29 @@
ammo.pickup
{
sample items/pickup.wav
}
ammo.respawn
{
sample items/respawn.wav
}
item.armor
{
sample items/pickup_armor.wav
}
item.health
{
sample items/takehealth.wav
}
item.respawn
{
sample items/respawn.wav
}
weapon.pickup
{
sample items/pickup.wav
}

View file

@ -0,0 +1,9 @@
player.die
{
sample player/killed.wav
}
player.fallarmor
{
sample player/fall_armor.wav
}

View file

@ -0,0 +1,145 @@
weapon_broom.hit
{
sample weapons/broom_hit1.wav
sample weapons/broom_hit2.wav
}
weapon_broom.hitbody
{
sample weapons/broom_hitbod1.wav
sample weapons/broom_hitbod2.wav
sample weapons/broom_hitbod3.wav
}
weapon_broom.miss
{
sample weapons/broom_swing1.wav
sample weapons/broom_swing2.wav
}
weapon_forks.hitbody
{
sample weapons/fork_stick_body.wav
}
weapon_forks.hit
{
sample weapons/fork_hit_wall.wav
}
weapon_forks.stick
{
sample weapons/fork_stick.wav
}
weapon_forks.throw
{
sample weapons/fork_throw.wav
}
weapon_fryingpan.hit
{
sample weapons/pan_hitwall1.wav
}
weapon_fryingpan.hitbody
{
sample weapons/pan_hitbody1.wav
sample weapons/pan_hitbody2.wav
}
weapon_fryingpan.miss
{
sample weapons/pan_swing1.wav
sample weapons/pan_swing2.wav
}
weapon_glove.hitbody
{
sample weapon/glove_hitbod1.wav
sample weapon/glove_hitbod2.wav
sample weapon/glove_hitbod3.wav
}
weapon_glove.hit
{
sample weapon/glove_hit1.wav
sample weapon/glove_hit2.wav
}
weapon_glove.miss
{
sample weapons/glove_swing1.wav
sample weapons/glove_swing2.wav
}
weapon_glove.pickup
{
sample runes/on_slasher.wav
}
weapon_hairspray.fire
{
sample weapons/hspray_loop.wav
}
weapon_knife.hitbody
{
sample weapons/knife_stick_wall.wav
}
/* should have looping flag but can't due to engine bug */
weapon_knife.move
{
follow
sample weapons/knife_move.wav
}
weapon_knife.stick
{
sample weapons/knife_stick_wall.wav
}
weapon_knife.throw
{
sample weapons/knife_throw1.wav
sample weapons/knife_throw2.wav
}
weapon_lego.explode
{
sample gibs/lego_explode1.wav
sample gibs/lego_explode2.wav
}
weapon_legolauncher.fire
{
sample weapons/launch_lego.wav
}
weapon_legolauncher.hitbody
{
sample weapons/launch_lego.wav
}
weapon_legolauncher.hit
{
sample gibs/lego_bounce1.wav
sample gibs/lego_bounce2.wav
sample gibs/lego_bounce3.wav
sample gibs/lego_bounce4.wav
sample gibs/lego_bounce5.wav
sample gibs/lego_bounce6.wav
}
weapon_sodalauncher.explode
{
sample weapons/soda_spill.wav
}
weapon_sodalauncher.fire
{
sample weapons/launch_soda.wav
}