Initial commit, carried over from Nuclide's Git on March 8th 2021

This commit is contained in:
Marco Cawthorne 2021-03-08 10:53:48 +01:00
commit 1a25ccc334
137 changed files with 17088 additions and 0 deletions

15
LICENSE Normal file
View File

@ -0,0 +1,15 @@
ISC License
Copyright (c) 2016-2021, Marco "eukara" Hladik <marco@icculus.org>
Permission to use, copy, modify, and/or 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 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.

46
README.md Normal file
View File

@ -0,0 +1,46 @@
# FreeHL
Clean-room reimplementation of Half-Life: Deathmatch and Half-Life (Experimental).
Similar to FreeCS, this aims to recreate the feeling of the original game.
It's designed to work with the content from the CD version of the game.
Netplay improvements, such as prediction of both player physics and weapon-logic
are present.
This is 100% original code, feel free to audit however you wish.
No proprietary SDKs have been looked at or taken apart, unlike similar projects.
![Preview 1](img/preview1.jpg)
![Preview 2](img/preview2.jpg)
![Preview 3](img/preview3.jpg)
![Preview 4](img/preview4.jpg)
## Building
Clone the repository into the Nuclide-SDK:
> git clone REPOURL valve
then either run Nuclide's ./build_game.sh shell script, or issue 'make' inside
./valve/src!
Obviously make sure that Nuclide has fteqw and fteqcc set-up for building.
## Community
Join us on #halflife via irc.frag-net.com and chat.
## License
ISC License
Copyright (c) 2016-2021 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.

BIN
img/preview1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

BIN
img/preview2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

BIN
img/preview3.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

BIN
img/preview4.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

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

25
src/client/cmds.qc Normal file
View File

@ -0,0 +1,25 @@
/*
* 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
ClientGame_ConsoleCommand(void)
{
switch(argv(0)) {
default:
return FALSE;
}
return TRUE;
}

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

@ -0,0 +1,131 @@
/*
* Copyright (c) 2016-2021 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 "obituary.h"
#include "particles.h"
var int autocvar_cl_autoweaponswitch = TRUE;
vector g_hud_color;
vector g_hudmins;
vector g_hudres;
var string g_hud1_spr;
var string g_hud2_spr;
var string g_hud3_spr;
var string g_hud4_spr;
var string g_hud5_spr;
var string g_hud6_spr;
var string g_hud7_spr;
var string g_cross_spr;
var string g_laser_spr;
struct
{
/* viewmodel stuff */
entity m_eViewModel;
entity m_eMuzzleflash;
int m_iVMBones;
int m_iVMEjectBone;
int m_iLastWeapon;
int m_iOldWeapon;
float m_flBobTime;
float m_flBob;
/* damage overlay */
float m_flDamageAlpha;
vector m_vecDamagePos;
/* +zoomin cmd */
int m_iZoomed;
float m_flZoomTime;
/* player fields */
entity m_ePlayer;
vector m_vecPredictedOrigin;
vector m_vecPredictedOriginOld;
vector m_vecPredictedVelocity;
float m_flPredictedFlags;
/* camera fields */
vector m_vecCameraOrigin;
vector m_vecCameraAngle;
float m_flCameraTime;
/* hud.c */
int m_iHealthOld;
float m_flHealthAlpha;
int m_iArmorOld;
float m_flArmorAlpha;
int m_iAmmo1Old;
float m_flAmmo1Alpha;
int m_iAmmo2Old;
float m_flAmmo2Alpha;
int m_iAmmo3Old;
float m_flAmmo3Alpha;
int m_iPickupWeapon;
float m_flPickupAlpha;
/* This is seperated from the other VGUI stuff so we can check scores
* while buying and whatnot */
int m_iScoresVisible;
int m_iHUDWeaponSelected;
float m_flHUDWeaponSelectTime;
/* saturn controller */
int m_iSaturnMenu;
/* centerprint related */
float m_flCenterprintAlpha;
float m_flCenterprintTime;
float m_iCenterprintLines;
string m_strCenterprintBuffer[18];
/* chat related */
float m_flPrintTime;
string m_strPrintBuffer[5];
int m_iPrintLines;
int m_iInputAttack2;
int m_iInputReload;
int m_iInputUse;
int m_iInputDuck;
float m_flInputBlockTime;
/* fading */
float m_flFadeDuration;
float m_flFadeHold;
float m_flFadeMaxAlpha;
float m_flFadeStyle;
float m_flFadeAlpha;
float m_flFadeTime;
vector m_vecFadeColor;
int m_iFadeActive;
/* shake */
float m_flShakeFreq;
float m_flShakeDuration;
float m_flShakeTime;
float m_flShakeAmp;
entity m_pWeaponFX;
} g_seats[4], *pSeat;
void HUD_DrawAmmo1(void);
void HUD_DrawAmmo2(void);
void HUD_DrawAmmo3(void);
void HUD_DrawAmmoBar(vector pos, float val, float max, float a);
void HUD_WeaponPickupNotify(int);

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

@ -0,0 +1,29 @@
/*
* 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
ClientGame_EntityUpdate(float id, float new)
{
switch (id) {
case ENT_TRIPMINE:
w_tripmine_parse();
break;
default:
return FALSE;
}
return TRUE;
}

124
src/client/game_event.qc Normal file
View File

@ -0,0 +1,124 @@
/*
* 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
ClientGame_EventParse(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_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;
}
}

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

@ -0,0 +1,438 @@
/*
* Copyright (c) 2016-2021 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 NUMSIZE_X 24/256
#define NUMSIZE_Y 24/128
#define HUD_ALPHA 0.5
float spr_hudnum[10] = {
0 / 256,
24 / 256,
(24*2) / 256,
(24*3) / 256,
(24*4) / 256,
(24*5) / 256,
(24*6) / 256,
(24*7) / 256,
(24*8) / 256,
(24*9) / 256
};
/* pre-calculated sprite definitions */
float spr_health[4] = {
80 / 256, // pos x
24 / 128, // pos u
32 / 256, // size x
32 / 128 // size y
};
float spr_suit1[4] = {
0 / 256, // pos x
24 / 128, // pos u
40 / 256, // size x
40 / 128 // size y
};
float spr_suit2[4] = {
40 / 256, // pos x
24 / 128, // pos u
40 / 256, // size x
40 / 128 // size y
};
float spr_flash1[4] = {
160 / 256, // pos x
24 / 128, // pos u
32 / 256, // size x
32 / 128 // size y
};
float spr_flash2[4] = {
112 / 256, // pos x
24 / 128, // pos u
48 / 256, // size x
32 / 128 // size y
};
/* precaches */
void
HUD_Init(void)
{
g_cross_spr = spriteframe("sprites/crosshairs.spr", 0, 0.0f);
g_laser_spr = spriteframe("sprites/laserdot.spr", 0, 0.0f);
g_hud1_spr = spriteframe("sprites/640hud1.spr", 0, 0.0f);
g_hud2_spr = spriteframe("sprites/640hud2.spr", 0, 0.0f);
g_hud3_spr = spriteframe("sprites/640hud3.spr", 0, 0.0f);
g_hud4_spr = spriteframe("sprites/640hud4.spr", 0, 0.0f);
g_hud5_spr = spriteframe("sprites/640hud5.spr", 0, 0.0f);
g_hud6_spr = spriteframe("sprites/640hud6.spr", 0, 0.0f);
g_hud7_spr = spriteframe("sprites/640hud7.spr", 0, 0.0f);
}
/* seperator for mainly ammo */
void
HUD_DrawSeperator(vector pos)
{
drawsubpic(pos,
[2,24],
g_hud7_spr,
[240/256, 0],
[2/256, 24/128],
g_hud_color,
HUD_ALPHA,
DRAWFLAG_ADDITIVE
);
}
/* handle single/multiple digits */
void
HUD_DrawNumber(int iNumber, vector vecPos, float fAlpha, vector vColor)
{
drawsubpic(vecPos,
[24,24],
g_hud7_spr,
[spr_hudnum[iNumber], 0],
[NUMSIZE_X, NUMSIZE_Y],
vColor,
fAlpha,
DRAWFLAG_ADDITIVE
);
}
void
HUD_DrawNums(float fNumber, vector vecPos, float fAlpha, vector vColor)
{
int i = fNumber;
if (i > 0) {
while (i > 0) {
HUD_DrawNumber((float)i % 10, vecPos, fAlpha, vColor);
i = i / 10;
vecPos[0] -= 20;
}
} else {
HUD_DrawNumber(0, vecPos, fAlpha, vColor);
}
}
/* health */
void
HUD_DrawHealth(void)
{
vector pos;
player pl = (player)pSeat->m_ePlayer;
if (pl.health != 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 + [88, g_hudres[1] - 42];
if (pl.health > 25) {
drawsubpic(
pos + [-72,-4],
[32,32],
g_hud7_spr,
[spr_health[0], spr_health[1]],
[spr_health[2], spr_health[3]],
g_hud_color,
pSeat->m_flHealthAlpha,
DRAWFLAG_ADDITIVE
);
HUD_DrawNums(pl.health, pos, pSeat->m_flHealthAlpha, g_hud_color);
} else {
drawsubpic(
pos + [-72,-4],
[32,32],
g_hud7_spr,
[spr_health[0], spr_health[1]],
[spr_health[2], spr_health[3]],
[1,0,0],
pSeat->m_flHealthAlpha,
DRAWFLAG_ADDITIVE
);
HUD_DrawNums(pl.health, pos, pSeat->m_flHealthAlpha, [1,0,0]);
}
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 + [-80,-9],
[40,40],
g_hud7_spr,
[spr_suit2[0], spr_suit2[1]],
[spr_suit2[2], spr_suit2[3]],
g_hud_color,
pSeat->m_flArmorAlpha,
DRAWFLAG_ADDITIVE
);
if (pl.armor > 0) {
drawsubpic(
pos + [-80,-9],
[40, 40 * (pl.armor / 100)],
g_hud7_spr,
[spr_suit1[0],
spr_suit1[1]],
[spr_suit1[2], spr_suit1[3] * (pl.armor / 100)],
g_hud_color,
pSeat->m_flArmorAlpha,
DRAWFLAG_ADDITIVE
);
}
HUD_DrawNums(pl.armor, pos, 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);
HUD_DrawSeperator(pos + [30,0]);
}
/* 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);
}
/* ammo bar */
void
HUD_DrawAmmoBar(vector pos, float val, float max, float a)
{
if (val <= 0)
return;
float perc;
perc = val / max;
drawfill(pos + [10,0], [20,4], g_hud_color, a, DRAWFLAG_NORMAL);
drawfill(pos + [10,0], [20 * perc,4], [0,1,0], a, DRAWFLAG_NORMAL);
}
/* flashlight/torch indicator */
void
HUD_DrawFlashlight(void)
{
vector pos;
player pl = (player)pSeat->m_ePlayer;
pos = g_hudmins + [g_hudres[0] - 48, 16];
/* both on, draw both sprites at full intensity */
if (pl.gflags & GF_FLASHLIGHT) {
drawsubpic(
pos,
[32,32],
g_hud7_spr,
[spr_flash1[0], spr_flash1[1]],
[spr_flash1[2], spr_flash1[3]],
g_hud_color,
1.0f,
DRAWFLAG_ADDITIVE
);
drawsubpic(
pos,
[48,32],
g_hud7_spr,
[spr_flash2[0], spr_flash2[1]],
[spr_flash2[2], spr_flash2[3]],
g_hud_color,
1.0f,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[32,32],
g_hud7_spr,
[spr_flash1[0], spr_flash1[1]],
[spr_flash1[2], spr_flash1[3]],
g_hud_color,
HUD_ALPHA,
DRAWFLAG_ADDITIVE
);
}
}
/* logo animation used during e3 1998 */
void
HUD_DrawLogo(void)
{
vector pos;
static int f;
static float frame_timer;
frame_timer -= clframetime;
pos = [g_hudres[0] - 262, 48];
drawpic(
pos,
sprintf("sprites/640_logo.spr_%i.tga", f),
[256,48],
[1,1,1],
1.0f,
DRAWFLAG_ADDITIVE
);
if (frame_timer > 0) {
return;
}
frame_timer = 0.1f;
f++;
if (f == 31) {
f = 0;
}
}
/* weapon/ammo pickup notifications */
void
HUD_DrawNotify(void)
{
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();
Textmenu_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
Textmenu_Draw();
}

View File

@ -0,0 +1,228 @@
/*
* 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.
*/
vector g_vecHUDNums[6] =
{
[168 / 256, 72 / 128],
[188 / 256, 72 / 128],
[208 / 256, 72 / 128],
[168 / 256, 92 / 128],
[188 / 256, 92 / 128],
[208 / 256, 92 / 128]
};
void
HUD_DrawWeaponSelect_Forward(void)
{
player pl = (player)pSeat->m_ePlayer;
if (!pl.activeweapon) {
return;
}
if (pSeat->m_flHUDWeaponSelectTime < time) {
pSeat->m_iHUDWeaponSelected = pl.activeweapon;
sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_hudon.wav", 0.5, ATTN_NONE);
} else {
sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_moveselect.wav", 0.5, ATTN_NONE);
pSeat->m_iHUDWeaponSelected--;
if (pSeat->m_iHUDWeaponSelected <= 0) {
pSeat->m_iHUDWeaponSelected = g_weapons.length - 1;
}
}
pSeat->m_flHUDWeaponSelectTime = time + 3;
if not (pl.g_items & g_weapons[pSeat->m_iHUDWeaponSelected].id) {
HUD_DrawWeaponSelect_Forward();
}
}
void
HUD_DrawWeaponSelect_Back(void)
{
player pl = (player)pSeat->m_ePlayer;
if (!pl.activeweapon) {
return;
}
if (pSeat->m_flHUDWeaponSelectTime < time) {
pSeat->m_iHUDWeaponSelected = pl.activeweapon;
sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_hudon.wav", 0.5, ATTN_NONE);
} else {
sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_moveselect.wav", 0.5, ATTN_NONE);
pSeat->m_iHUDWeaponSelected++;
if (pSeat->m_iHUDWeaponSelected >= g_weapons.length) {
pSeat->m_iHUDWeaponSelected = 1;
}
}
pSeat->m_flHUDWeaponSelectTime = time + 3;
if not (pl.g_items & g_weapons[pSeat->m_iHUDWeaponSelected].id) {
HUD_DrawWeaponSelect_Back();
}
}
void
HUD_DrawWeaponSelect_Trigger(void)
{
player pl = (player)pSeat->m_ePlayer;
pl.activeweapon = pSeat->m_iHUDWeaponSelected;
sendevent("PlayerSwitchWeapon", "i", pSeat->m_iHUDWeaponSelected);
sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_select.wav", 0.5f, ATTN_NONE);
pSeat->m_iHUDWeaponSelected = pSeat->m_flHUDWeaponSelectTime = 0;
}
void
HUD_DrawWeaponSelect_Last(void)
{
player pl = (player)pSeat->m_ePlayer;
if (pl.g_items & g_weapons[pSeat->m_iOldWeapon].id) {
pl.activeweapon = pSeat->m_iOldWeapon;
sendevent("PlayerSwitchWeapon", "i", pSeat->m_iOldWeapon);
}
}
void
HUD_DrawWeaponSelect_Num(vector vecPos, float fValue)
{
drawsubpic(vecPos, [20,20], g_hud7_spr, g_vecHUDNums[fValue], [20/256, 20/128], g_hud_color, 1, DRAWFLAG_ADDITIVE);
}
int
HUD_InSlotPos(int slot, int pos)
{
player pl = (player)pSeat->m_ePlayer;
for (int i = 1; i < g_weapons.length; i++) {
if (g_weapons[i].slot == slot && g_weapons[i].slot_pos == pos) {
if (pl.g_items & g_weapons[i].id) {
return i;
} else {
return -1;
}
}
}
return -1;
}
void
HUD_SlotSelect(int slot)
{
player pl = (player)pSeat->m_ePlayer;
int curslot = g_weapons[pSeat->m_iHUDWeaponSelected].slot;
int i;
if (g_textmenu != "") {
Textmenu_Input(slot);
return;
}
/* hack to see if we have ANY weapons at all. */
if (!pl.activeweapon) {
return;
}
if (pSeat->m_flHUDWeaponSelectTime < time) {
sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_hudon.wav", 0.5, ATTN_NONE);
} else {
sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_moveselect.wav", 0.5, ATTN_NONE);
}
/* weren't in that slot? select the first one then */
if (curslot != slot) {
for (i = 1; i < g_weapons.length; i++) {
if (g_weapons[i].slot == slot && pl.g_items & g_weapons[i].id) {
pSeat->m_iHUDWeaponSelected = i;
pSeat->m_flHUDWeaponSelectTime = time + 3;
break;
}
}
} else {
int first = -1;
for (i = 1; i < g_weapons.length; i++) {
if (g_weapons[i].slot == slot && pl.g_items & g_weapons[i].id) {
if (i < pSeat->m_iHUDWeaponSelected && first == -1) {
first = i;
} else if (i > pSeat->m_iHUDWeaponSelected) {
first = -1;
pSeat->m_iHUDWeaponSelected = i;
pSeat->m_flHUDWeaponSelectTime = time + 3;
break;
}
}
}
if (first > 0) {
pSeat->m_iHUDWeaponSelected = first;
pSeat->m_flHUDWeaponSelectTime = time + 3;
}
}
}
void
HUD_DrawWeaponSelect(void)
{
player pl = (player)pSeat->m_ePlayer;
if (!pl.activeweapon) {
return;
}
if (pSeat->m_flHUDWeaponSelectTime < time) {
if (pSeat->m_iHUDWeaponSelected) {
sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_hudoff.wav", 0.5, ATTN_NONE);
pSeat->m_iHUDWeaponSelected = 0;
}
return;
}
vector vecPos = g_hudmins + [16,16];
int b;
int wantslot = g_weapons[pSeat->m_iHUDWeaponSelected].slot;
int wantpos = g_weapons[pSeat->m_iHUDWeaponSelected].slot_pos;
for (int i = 0; i < 5; i++) {
int slot_selected = 0;
vecPos[1] = g_hudmins[1] + 16;
HUD_DrawWeaponSelect_Num(vecPos, i);
vecPos[1] += 20;
for (int x = 0; x < 32; x++) {
if (i == wantslot) {
slot_selected = TRUE;
if (x == wantpos) {
// Selected Sprite
Weapons_HUDPic(pSeat->m_iHUDWeaponSelected, 1, vecPos, 1.0f);
drawsubpic(vecPos, [170,45], g_hud3_spr,
[0,180/256], [170/256,45/256], g_hud_color, 1, DRAWFLAG_ADDITIVE);
vecPos[1] += 50;
} else if ((b=HUD_InSlotPos(i, x)) != -1) {
// Unselected Sprite
Weapons_HUDPic(b, 0, vecPos, 1.0f);
vecPos[1] += 50;
}
} else if (HUD_InSlotPos(i, x) != -1) {
HUD_DrawWeaponSelect_Num(vecPos, 5);
vecPos[1] += 25;
}
}
if (slot_selected == TRUE) {
vecPos[0] += 175;
} else {
vecPos[0] += 25;
}
}
}

48
src/client/init.qc Normal file
View File

@ -0,0 +1,48 @@
/*
* 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.
*/
/*
=================
ClientGame_Init
Comparable to worldspawn in SSQC in that it's mostly used for precaches
=================
*/
void
ClientGame_Init(float apilevel, string enginename, float engineversion)
{
Obituary_Init();
}
void
ClientGame_InitDone(void)
{
}
void
ClientGame_RendererRestart(string rstr)
{
Obituary_Precache();
FX_Blood_Init();
FX_BreakModel_Init();
FX_Explosion_Init();
FX_GibHuman_Init();
FX_Spark_Init();
FX_Impact_Init();
BEAM_TRIPMINE = particleeffectnum("weapon_tripmine.beam");
}

29
src/client/input.qc Normal file
View File

@ -0,0 +1,29 @@
/*
* 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_Input(void)
{
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();
}
}

48
src/client/obituary.h Normal file
View File

@ -0,0 +1,48 @@
/*
* 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 OBITUARY_LINES 4
#define OBITUARY_TIME 5
/* imagery */
typedef struct {
string name; /* name of the weapon/type, e.g. d_crowbar */
string sprite; /* name of the spritesheet it's from */
float size[2]; /* on-screen size in pixels */
float src_pos[2]; /* normalized position in the sprite sheet */
float src_size[2]; /* normalized size in the sprite sheet */
string src_sprite; /* precaching reasons */
} obituaryimg_t;
obituaryimg_t *g_obtypes;
int g_obtype_count;
/* actual obituary storage */
typedef struct
{
string attacker;
string victim;
int icon;
} obituary_t;
obituary_t g_obituary[OBITUARY_LINES];
int g_obituary_count;
float g_obituary_time;
void Obituary_Init(void);
void Obituary_Precache(void);
void Obituary_Draw(void);
void Obituary_Parse(void);

221
src/client/obituary.qc Normal file
View File

@ -0,0 +1,221 @@
/*
* 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;
}
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 = spriteframe(sprintf("sprites/%s.spr", argv(2)), 0, 0.0f);
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)
{
for (int i = 0; i < g_obtype_count; i++)
precache_model(g_obtypes[i].src_sprite);
}
void
Obituary_KillIcon(int id, float w)
{
if (w > 0)
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;
if (g_weapons[weapon].deathmsg) {
string conprint = g_weapons[weapon].deathmsg();
if (conprint != "") {
print(sprintf(conprint, attacker, victim));
print("\n");
}
}
}
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]],
g_hud_color,
1.0f,
DRAWFLAG_ADDITIVE
);
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);
}

17
src/client/particles.h Normal file
View File

@ -0,0 +1,17 @@
/*
* 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 float BEAM_TRIPMINE;

44
src/client/player.qc Normal file
View File

@ -0,0 +1,44 @@
/*
* 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
Player_PreDraw(base_player pl, int thirdperson)
{
/* Handle the flashlights... */
if (pl.gflags & GF_FLASHLIGHT) {
vector src;
vector ang;
if (pl.entnum != player_localentnum) {
src = pl.origin + pl.view_ofs;
ang = [pl.pitch, pl.angles[1], pl.angles[2]];
} else {
src = pSeat->m_vecPredictedOrigin + [0,0,-8];
ang = view_angles;
}
makevectors(ang);
traceline(src, src + (v_forward * 8096), MOVE_NORMAL, pl);
if (serverkeyfloat("*bspversion") == BSPVER_HL) {
dynamiclight_add(trace_endpos + (v_forward * -2), 128, [1,1,1]);
} else {
float p = dynamiclight_add(src, 512, [1,1,1], 0, "textures/flashlight");
dynamiclight_set(p, LFIELD_ANGLES, ang);
dynamiclight_set(p, LFIELD_FLAGS, 3);
}
}
}

25
src/client/predict.qc Normal file
View File

@ -0,0 +1,25 @@
/*
* 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
GamePredict_PreFrame(player pl)
{
}
void
GamePredict_PostFrame(player pl)
{
}

38
src/client/progs.src Executable file
View File

@ -0,0 +1,38 @@
#pragma target fte
#pragma progs_dat "../../csprogs.dat"
#define CSQC
#define CLIENT
#define VALVE
#define CLASSIC_VGUI
#define GS_RENDERFX
#includelist
../../../src/shared/fteextensions.qc
../../../src/shared/defs.h
defs.h
../../../src/client/defs.h
../../../src/vgui/include.src
../../../src/gs-entbase/client.src
../../../src/gs-entbase/shared.src
../shared/include.src
predict.qc
init.qc
player.qc
entities.qc
cmds.qc
game_event.qc
view.qc
obituary.qc
hud.qc
hud_weaponselect.qc
scoreboard.qc
input.qc
../../../base/src/client/modelevent.qc
../../../src/client/include.src
../../../src/shared/include.src
#endlist

181
src/client/scoreboard.qc Normal file
View File

@ -0,0 +1,181 @@
/*
* 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 SCORE_HEADER_C [255/255,156/255,0]
#define SCORE_LINE_C [255/255,200/255,0]
var int autocvar_cl_centerscores = FALSE;
var int g_scores_teamplay = 0;
void
Scores_Init(void)
{
g_scores_teamplay = (int)serverkeyfloat("teamplay");
}
void
Scores_DrawTeam(player pl, vector pos)
{
drawfill(pos, [290, 1], SCORE_LINE_C, 1.0f, DRAWFLAG_ADDITIVE);
drawfont = FONT_20;
drawstring(pos + [0,-18], "Teams", [20,20], SCORE_HEADER_C, 1.0f, DRAWFLAG_ADDITIVE);
drawstring(pos + [124,-18], "kills / deaths", [20,20], SCORE_HEADER_C, 1.0f, DRAWFLAG_ADDITIVE);
drawstring(pos + [240,-18], "latency", [20,20], SCORE_HEADER_C, 1.0f, DRAWFLAG_ADDITIVE);
pos[1] += 12;
for (int t = 1; t <= serverkeyfloat("teams"); t++) {
float l;
string temp;
drawstring(pos, serverkey(sprintf("team_%i", t)), [20,20], SCORE_HEADER_C, 1.0f, DRAWFLAG_ADDITIVE);
temp = serverkey(sprintf("teamscore_%i", t));
l = stringwidth(temp, FALSE, [20,20]);
drawstring(pos + [150-l, 0], temp, [20,20], SCORE_HEADER_C, 1.0f, DRAWFLAG_ADDITIVE);
drawstring(pos + [158, 0], "wins", [20,20], SCORE_HEADER_C, 1.0f, DRAWFLAG_ADDITIVE);
pos[1] += 16;
for (int i = -1; i > -32; i--) {
if (getplayerkeyfloat(i, "*team") != t) {
continue;
}
temp = getplayerkeyvalue(i, "name");
/* Out of players */
if (!temp) {
break;
} else if (temp == getplayerkeyvalue(pl.entnum-1, "name")) {
drawfill(pos, [290, 13], [0,0,1], 0.5f, DRAWFLAG_ADDITIVE);
}
drawstring(pos + [24,0], getplayerkeyvalue(i, "name"), [20,20], [1,1,1], 1.0f, DRAWFLAG_ADDITIVE);
drawstring(pos + [154,0], "/", [20,20], [1,1,1], 1.0f, DRAWFLAG_ADDITIVE);
/* Get the kills and align them left to right */
temp = getplayerkeyvalue(i, "frags");
l = stringwidth(temp, FALSE, [20,20]);
drawstring(pos + [150 - l,0], temp, [20,20], [1,1,1], 1.0f, DRAWFLAG_ADDITIVE);
/* Deaths are right to left aligned */
temp = getplayerkeyvalue(i, "*deaths");
drawstring(pos + [165,0], temp, [20,20], [1,1,1], 1.0f, DRAWFLAG_ADDITIVE);
/* Get the latency and align it left to right */
temp = getplayerkeyvalue(i, "ping");
l = stringwidth(temp, FALSE, [20,20]);
if (getplayerkeyfloat(i, "*dead") == 1) {
drawsubpic(
pos - [8,0],
[32,16],
g_hud1_spr,
[224/256, 240/256],
[32/256, 16/256],
[1,0,0],
1.0f,
DRAWFLAG_ADDITIVE
);
}
drawstring(pos + [290 - l,0], temp, [20,20], [1,1,1], 1.0f, DRAWFLAG_ADDITIVE);
pos[1] += 20;
}
pos[1] += 12;
}
drawfont = FONT_CON;
}
void
Scores_DrawNormal(player pl, vector pos)
{
drawfill(pos, [290, 1], SCORE_LINE_C, 1.0f, DRAWFLAG_ADDITIVE);
drawfont = FONT_20;
drawstring(pos + [0,-18], "Player", [20,20], SCORE_HEADER_C, 1.0f, DRAWFLAG_ADDITIVE);
drawstring(pos + [124,-18], "kills / deaths", [20,20], SCORE_HEADER_C, 1.0f, DRAWFLAG_ADDITIVE);
drawstring(pos + [240,-18], "latency", [20,20], SCORE_HEADER_C, 1.0f, DRAWFLAG_ADDITIVE);
pos[1] += 12;
for (int i = -1; i > -32; i--) {
float l;
string ping;
string kills;
string deaths;
string name;
name = getplayerkeyvalue(i, "name");
/* Out of players */
if (!name) {
break;
} else if (name == getplayerkeyvalue(pl.entnum-1, "name")) {
drawfill(pos, [290, 13], [0,0,1], 0.5f, DRAWFLAG_ADDITIVE);
}
drawstring(pos, getplayerkeyvalue(i, "name"), [20,20], [1,1,1], 1.0f, DRAWFLAG_ADDITIVE);
drawstring(pos + [154,0], "/", [20,20], [1,1,1], 1.0f, DRAWFLAG_ADDITIVE);
/* Get the kills and align them left to right */
kills = getplayerkeyvalue(i, "frags");
l = stringwidth(kills, FALSE, [20,20]);
drawstring(pos + [150 - l,0], kills, [20,20], [1,1,1], 1.0f, DRAWFLAG_ADDITIVE);
/* Deaths are right to left aligned */
deaths = getplayerkeyvalue(i, "*deaths");
drawstring(pos + [165,0], deaths, [20,20], [1,1,1], 1.0f, DRAWFLAG_ADDITIVE);
/* Get the latency and align it left to right */
ping = getplayerkeyvalue(i, "ping");
l = stringwidth(ping, FALSE, [20,20]);
drawstring(pos + [290 - l,0], ping, [20,20], [1,1,1], 1.0f, DRAWFLAG_ADDITIVE);
pos[1] += 20;
}
drawfont = FONT_CON;
}
void
Scores_Draw(void)
{
vector pos;
player pl;
pl = (player)pSeat->m_ePlayer;
if (autocvar_cl_centerscores) {
int c = 10;
/* calculate all valid entries */
for (int i = -1; i > -32; i--) {
if (getplayerkeyvalue(i, "name")) {
break;
}
c += 10;
}
pos = video_mins + [(video_res[0] / 2) - 145, (video_res[1] / 2) - c];
} else {
pos = video_mins + [(video_res[0] / 2) - 145, 30];
}
if (serverkeyfloat("teams") > 0) {
Scores_DrawTeam(pl, pos);
} else {
Scores_DrawNormal(pl, pos);
}
}

51
src/client/view.qc 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.
*/
void
View_UpdateWeapon(entity vm, entity mflash)
{
player pl = (player)pSeat->m_ePlayer;
/* only bother upon change */
if (pSeat->m_iLastWeapon == pl.activeweapon) {
return;
}
pSeat->m_iOldWeapon = pSeat->m_iLastWeapon;
pSeat->m_iLastWeapon = pl.activeweapon;
if (!pl.activeweapon) {
return;
}
/* hack, we changed the wep, move this into Game_Input/PMove */
Weapons_Draw();
/* we forced a weapon call outside the prediction,
* thus we need to update all the net variables to
* make sure these updates are recognized. this is
* vile but it'll have to do for now */
pl.net_w_attack_next = pl.w_attack_next;
pl.net_w_idle_next = pl.w_idle_next;
pl.net_viewzoom = pl.viewzoom;
pl.net_weapontime = pl.weapontime;
/* figure out when the attachments start. in FTE attachments for
* HLMDL are treated as bones. they start at numbones + 1 */
skel_delete(mflash.skeletonindex);
mflash.skeletonindex = skel_create(vm.modelindex);
pSeat->m_iVMBones = skel_get_numbones(mflash.skeletonindex) + 1;
pSeat->m_iVMEjectBone = pSeat->m_iVMBones + 1;
}

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

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

@ -0,0 +1,364 @@
/*
* 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_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 (real_owner || 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;
if (real_owner)
Sound_Play(this, CHAN_ITEM, "ammo.respawn");
droptofloor();
}
void item_ammo::item_ammo(void)
{
precache_model(model);
m_oldModel = model;
SetModel(m_oldModel);
CBaseEntity::CBaseEntity();
}
/*QUAKED ammo_357 (0 0 0.8) (-16 -16 0) (16 16 32)
HALF-LIFE (1998) ENTITY
Ammo for the .357 Magnum Revolver.
A single ammo_357 will provide 6 bullets.
*/
class ammo_357:item_ammo
{
void(void) ammo_357;
virtual void(void) touch;
};
void ammo_357::ammo_357(void)
{
model = "models/w_357ammobox.mdl";
item_ammo::item_ammo();
}
void ammo_357::touch(void)
{
if not (other.flags & FL_CLIENT) {
return;
}
if (other.classname == "player") {
player pl = (player)other;
if (pl.ammo_357 < MAX_A_357) {
pl.ammo_357 = bound(0, pl.ammo_357 + 6, MAX_A_357);
item_ammo::touch();
}
}
}
/*QUAKED ammo_9mmAR (0 0 0.8) (-16 -16 0) (16 16 32)
HALF-LIFE (1998) ENTITY
Ammo for the 9mm Handgun and the 9mm AR.
A single ammo_9mmAR will provide 50 bullets.
*/
class ammo_9mmAR:item_ammo
{
void(void) ammo_9mmAR;
virtual void(void) touch;
};
void ammo_9mmAR::ammo_9mmAR(void)
{
model = "models/w_9mmarclip.mdl";
item_ammo::item_ammo();
}
void ammo_9mmAR::touch(void)
{
if not (other.flags & FL_CLIENT) {
return;
}
if (other.classname == "player") {
player pl = (player)other;
if (pl.ammo_9mm < MAX_A_9MM) {
pl.ammo_9mm = bound(0, pl.ammo_9mm + 50, MAX_A_9MM);
item_ammo::touch();
}
}
}
CLASSEXPORT(ammo_mp5clip, ammo_9mmAR)
/*QUAKED ammo_9mmbox (0 0 0.8) (-16 -16 0) (16 16 32)
HALF-LIFE (1998) ENTITY
Ammo for the 9mm Handgun and the 9mm AR.
A single ammo_9mmbox will provide 200 bullets.
*/
class ammo_9mmbox:item_ammo
{
void(void) ammo_9mmbox;
virtual void(void) touch;
};
void ammo_9mmbox::ammo_9mmbox(void)
{
model = "models/w_chainammo.mdl";
item_ammo::item_ammo();
}
void ammo_9mmbox::touch(void)
{
if not (other.flags & FL_CLIENT) {
return;
}
if (other.classname == "player") {
player pl = (player)other;
if (pl.ammo_9mm < MAX_A_9MM) {
pl.ammo_9mm = bound(0, pl.ammo_9mm + 200, MAX_A_9MM);
item_ammo::touch();
}
}
}
/*QUAKED ammo_9mmclip (0 0 0.8) (-16 -16 0) (16 16 32)
HALF-LIFE (1998) ENTITY
Ammo for the 9mm Handgun and the 9mm AR.
A single ammo_9mmclip will provide 17 bullets.
*/
class ammo_9mmclip:item_ammo
{
void(void) ammo_9mmclip;
virtual void(void) touch;
};
void ammo_9mmclip::ammo_9mmclip(void)
{
model = "models/w_9mmclip.mdl";
item_ammo::item_ammo();
}
void ammo_9mmclip::touch(void)
{
if not (other.flags & FL_CLIENT) {
return;
}
if (other.classname == "player") {
player pl = (player)other;
if (pl.ammo_9mm < MAX_A_9MM) {
pl.ammo_9mm = bound(0, pl.ammo_9mm + 17, MAX_A_9MM);
item_ammo::touch();
}
}
}
/*QUAKED ammo_ARgrenades (0 0 0.8) (-16 -16 0) (16 16 32)
HALF-LIFE (1998) ENTITY
Ammo for the 9mm AR's secondary fire.
A single ammo_ARgrenades will provide 2 AR grenades.
*/
class ammo_ARgrenades:item_ammo
{
void(void) ammo_ARgrenades;
virtual void(void) touch;
};
void ammo_ARgrenades::ammo_ARgrenades(void)
{
model = "models/w_argrenade.mdl";
item_ammo::item_ammo();
}
void ammo_ARgrenades::touch(void)
{
if not (other.flags & FL_CLIENT) {
return;
}
if (other.classname == "player") {
player pl = (player)other;
if (pl.ammo_m203_grenade < MAX_A_M203_GRENADE) {
pl.ammo_m203_grenade = bound(0, pl.ammo_m203_grenade + 2, MAX_A_M203_GRENADE);
item_ammo::touch();
}
}
}
CLASSEXPORT(ammo_mp5grenades, ammo_ARgrenades)
/*QUAKED ammo_buckshot (0 0 0.8) (-16 -16 0) (16 16 32)
HALF-LIFE (1998) ENTITY
Ammo for the Shotgun.
A single ammo_buckshot will provide 12 shells.
*/
class ammo_buckshot:item_ammo
{
void(void) ammo_buckshot;
virtual void(void) touch;
};
void ammo_buckshot::ammo_buckshot(void)
{
model = "models/w_shotbox.mdl";
item_ammo::item_ammo();
}
void ammo_buckshot::touch(void)
{
if not (other.flags & FL_CLIENT) {
return;
}
if (other.classname == "player") {
player pl = (player)other;
if (pl.ammo_buckshot < MAX_A_BUCKSHOT) {
pl.ammo_buckshot = bound(0, pl.ammo_buckshot + 12, MAX_A_BUCKSHOT);
item_ammo::touch();
}
}
}
/*QUAKED ammo_crossbow (0 0 0.8) (-16 -16 0) (16 16 32)
HALF-LIFE (1998) ENTITY
Ammo for the Crossbow.
A single ammo_crossbow will provide 5 bolts.
*/
class ammo_crossbow:item_ammo
{
void(void) ammo_crossbow;
virtual void(void) touch;
};
void ammo_crossbow::ammo_crossbow(void)
{
model = "models/w_crossbow_clip.mdl";
item_ammo::item_ammo();
}
void ammo_crossbow::touch(void)
{
if not (other.flags & FL_CLIENT) {
return;
}
if (other.classname == "player") {
player pl = (player)other;
if (pl.ammo_bolt < MAX_A_BOLT) {
pl.ammo_bolt = bound(0, pl.ammo_bolt + 5, MAX_A_BOLT);
item_ammo::touch();
}
}
}
/*QUAKED ammo_gaussclip (0 0 0.8) (-16 -16 0) (16 16 32)
HALF-LIFE (1998) ENTITY
Ammo for the Tau Cannon and the Gluon Gun.
A single ammo_gaussclip will provide 20 cells.
*/
class ammo_gaussclip:item_ammo
{
void(void) ammo_gaussclip;
virtual void(void) touch;
};
void ammo_gaussclip::ammo_gaussclip(void)
{
model = "models/w_gaussammo.mdl";
item_ammo::item_ammo();
}
void ammo_gaussclip::touch(void)
{
if not (other.flags & FL_CLIENT) {
return;
}
player pl = (player)other;
if (pl.ammo_uranium < MAX_A_URANIUM) {
pl.ammo_uranium = bound(0, pl.ammo_uranium + 20, MAX_A_URANIUM);
item_ammo::touch();
}
}
/*QUAKED ammo_rpgclip (0 0 0.8) (-16 -16 0) (16 16 32)
HALF-LIFE (1998) ENTITY
Ammo for the RPG.
A single ammo_rpgclip will provide 1 rocket.
*/
class ammo_rpgclip:item_ammo
{
void(void) ammo_rpgclip;
virtual void(void) touch;
};
void ammo_rpgclip::ammo_rpgclip(void)
{
model = "models/w_rpgammo.mdl";
item_ammo::item_ammo();
}
void ammo_rpgclip::touch(void)
{
if not (other.flags & FL_CLIENT) {
return;
}
player pl = (player)other;
if (pl.ammo_rocket < MAX_A_ROCKET) {
pl.ammo_rocket = bound(0, pl.ammo_rocket + 1, MAX_A_ROCKET);
item_ammo::touch();
}
}

77
src/server/client.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.
*/
/* called every input frame */
void
Game_RunClientCommand(void)
{
Footsteps_Update();
Animation_PlayerUpdate();
PMove_Run();
}
/* custom chat packet */
void
SV_SendChat(entity sender, string msg, entity eEnt, float fType)
{
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, fType == 0 ? EV_CHAT:EV_CHAT_TEAM);
WriteByte(MSG_MULTICAST, num_for_edict(sender) - 1);
WriteByte(MSG_MULTICAST, sender.team);
WriteString(MSG_MULTICAST, msg);
if (eEnt) {
msg_entity = eEnt;
multicast([0,0,0], MULTICAST_ONE);
} else {
multicast([0,0,0], MULTICAST_ALL);
}
localcmd(sprintf("echo [SERVER] %s: %s\n", sender.netname, msg));
}
/* client cmd overrides happen here */
void
Game_ParseClientCommand(string cmd)
{
tokenize(cmd);
if (argv(1) == "timeleft") {
string msg;
string timestring;
float timeleft;
timeleft = cvar("mp_timelimit") - (time / 60);
timestring = Vox_TimeToString(timeleft);
msg = sprintf("we have %s minutes remaining", timestring);
Vox_Singlecast(self, msg);
return;
}
if (argv(0) == "say") {
SV_SendChat(self, argv(1), world, 0);
return;
} else if (argv(0) == "say_team") {
entity a;
for (a = world; (a = find(a, ::classname, "player"));) {
if (a.team == self.team) {
SV_SendChat(self, argv(1), a, 1);
}
}
return;
}
clientcommand(self, cmd);
}

166
src/server/damage.qc Normal file
View File

@ -0,0 +1,166 @@
/*
* 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.
*/
/* generic function that applies damage, pain and suffering */
void
Damage_Apply(entity t, entity c, float dmg, int w, int type)
{
base_player tp = (base_player)t;
CGameRules rules = (CGameRules)g_grMode;
if (t.flags & FL_GODMODE) {
return;
}
/* already dead, please avoid recursion */
if (t.health <= 0) {
return;
}
/* skip armor */
if not (type & DMG_SKIP_ARMOR)
if (tp.armor && dmg > 0) {
float flArmor;
float flNewDamage;
flNewDamage = dmg * 0.2;
flArmor = (dmg - flNewDamage) * 0.5;
if (flArmor > tp.armor) {
flArmor = tp.armor;
flArmor *= (1/0.5);
flNewDamage = dmg - flArmor;
tp.armor = 0;
} else {
tp.armor -= flArmor;
}
dmg = flNewDamage;
}
dmg = rint(dmg);
t.health -= dmg;
/* the globals... */
g_dmg_eAttacker = c;
g_dmg_eTarget = t;
g_dmg_iDamage = dmg;
g_dmg_iHitBody = trace_surface_id;
g_dmg_iFlags = type;
g_dmg_iWeapon = w;
if (dmg > 0) {
t.dmg_take = dmg;
t.dmg_inflictor = c;
} else if (t.max_health && t.health > t.max_health) {
t.health = t.max_health;
}
/* set this global in case we need it later */
g_eAttacker = c;
CBaseEntity s = (CBaseEntity)t;
if (s.health <= 0) {
if (s.flags & FL_CLIENT) {
rules.PlayerDeath((player)s);
} else {
s.Death();
}
} else {
if (s.flags & FL_CLIENT) {
rules.PlayerPain((player)s);
} else {
s.Pain();
}
}
}
/* physical check of whether or not we can trace important parts of an ent */
float
Damage_CheckTrace(entity t, vector vecHitPos)
{
/* We're lazy. Who cares */
if (t.solid == SOLID_BSP) {
return TRUE;
}
traceline(vecHitPos, t.origin, 1, self);
if (trace_fraction == 1) {
return TRUE;
}
traceline(vecHitPos, t.origin + [15,15,0], 1, self);
if (trace_fraction == 1) {
return TRUE;
}
traceline(vecHitPos, t.origin + [-15,-15,0], 1, self);
if (trace_fraction == 1) {
return TRUE;
}
traceline(vecHitPos, t.origin + [-15,15,0], 1, self);
if (trace_fraction == 1) {
return TRUE;
}
traceline(vecHitPos, t.origin + [15,-15,0], 1, self);
if (trace_fraction == 1) {
return TRUE;
}
return FALSE;
}
/* even more pain and suffering, mostly used for explosives */
void
Damage_Radius(vector org, entity attacker, float dmg, float r, int check, int w)
{
float new_dmg;
float dist;
float diff;
vector pos;
for (entity e = world; (e = findfloat(e, ::takedamage, DAMAGE_YES));) {
pos[0] = e.absmin[0] + (0.5 * (e.absmax[0] - e.absmin[0]));
pos[1] = e.absmin[1] + (0.5 * (e.absmax[1] - e.absmin[1]));
pos[2] = e.absmin[2] + (0.5 * (e.absmax[2] - e.absmin[2]));
/* don't bother if it's not anywhere near us */
dist = vlen(org - pos);
if (dist > r) {
continue;
}
/* can we physically hit this thing? */
if (Damage_CheckTrace(e, org) == FALSE) {
if (check == TRUE) {
continue;
}
}
/* calculate new damage values */
diff = vlen(org - pos);
diff = (r - diff) / r;
new_dmg = rint(dmg * diff);
if (diff > 0) {
Damage_Apply(e, attacker, new_dmg, w, DMG_EXPLODE);
/* approximate, feel free to tweak */
if (e.movetype == MOVETYPE_WALK) {
makevectors(vectoangles(e.origin - org));
e.velocity += v_forward * (new_dmg * 5);
}
}
}
}

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 "items.h"

42
src/server/flashlight.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.
*/
void Flashlight_Toggle(void)
{
if (cvar("sv_playerslots") != 1) {
if (cvar("mp_flashlight") != 1) {
return;
}
}
#ifdef VALVE
player pl = (player)self;
if (!(pl.g_items & ITEM_SUIT)) {
return;
}
#endif
if (self.health <= 0) {
return;
}
if (self.gflags & GF_FLASHLIGHT) {
self.gflags &= ~GF_FLASHLIGHT;
} else {
self.gflags |= GF_FLASHLIGHT;
}
sound(self, CHAN_ITEM, "items/flashlight1.wav", 1, ATTN_IDLE);
}

47
src/server/gamerules.h Normal file
View File

@ -0,0 +1,47 @@
/*
* 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 HLGameRules:CGameRules
{
virtual void(base_player) PlayerConnect;
virtual void(base_player) PlayerDisconnect;
virtual void(base_player) PlayerKill;
virtual void(base_player) PlayerPostFrame;
virtual void(base_player) LevelDecodeParms;
virtual void(base_player) LevelChangeParms;
virtual void(void) LevelNewParms;
};
class HLSingleplayerRules:HLGameRules
{
/* client */
virtual void(base_player) PlayerSpawn;
virtual void(base_player) PlayerDeath;
};
class HLMultiplayerRules:HLGameRules
{
int m_iIntermission;
int m_iIntermissionTime;
virtual void(void) FrameStart;
/* client */
virtual void(base_player) PlayerSpawn;
virtual void(base_player) PlayerDeath;
virtual float(base_player, string) ConsoleCommand;
};

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

@ -0,0 +1,143 @@
/*
* 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
HLGameRules::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 = parm64;
pl.ammo_9mm = parm12;
pl.ammo_357 = parm13;
pl.ammo_buckshot = parm14;
pl.ammo_m203_grenade = parm15;
pl.ammo_bolt = parm16;
pl.ammo_rocket = parm17;
pl.ammo_uranium = parm18;
pl.ammo_handgrenade = parm19;
pl.ammo_satchel = parm20;
pl.ammo_tripmine = parm21;
pl.ammo_snark = parm22;
pl.ammo_hornet = parm23;
pl.glock_mag = parm24;
pl.mp5_mag = parm25;
pl.python_mag = parm26;
pl.shotgun_mag = parm27;
pl.crossbow_mag = parm28;
pl.rpg_mag = parm29;
pl.satchel_chg = parm30;
if (pl.flags & FL_CROUCHING) {
setsize(pl, VEC_CHULL_MIN, VEC_CHULL_MAX);
} else {
setsize(pl, VEC_HULL_MIN, VEC_HULL_MAX);
}
}
void
HLGameRules::LevelChangeParms(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_9mm;
parm13 = pl.ammo_357;
parm14 = pl.ammo_buckshot;
parm15 = pl.ammo_m203_grenade;
parm16 = pl.ammo_bolt;
parm17 = pl.ammo_rocket;
parm18 = pl.ammo_uranium;
parm19 = pl.ammo_handgrenade;
parm20 = pl.ammo_satchel;
parm21 = pl.ammo_tripmine;
parm22 = pl.ammo_snark;
parm23 = pl.ammo_hornet;
parm24 = pl.glock_mag;
parm25 = pl.mp5_mag;
parm26 = pl.python_mag;
parm27 = pl.shotgun_mag;
parm28 = pl.crossbow_mag;
parm29 = pl.rpg_mag;
parm30 = pl.satchel_chg;
}
void
HLGameRules::LevelNewParms(void)
{
parm1 = parm2 = parm3 = parm4 = parm5 = parm6 = parm7 =
parm8 = parm9 = parm10 = parm11 = parm12 = parm13 = parm14 =
parm15 = parm16 = parm17 = parm18 = parm19 = parm20 = parm21 =
parm22 = parm23 = parm24 = parm25 = parm26 = parm27 = parm28 =
parm29 = parm30 = 0;
parm64 = FL_CLIENT;
}
/* we check what fields have changed over the course of the frame and network
* only the ones that have actually changed */
void
HLGameRules::PlayerPostFrame(base_player pl)
{
}
void
HLGameRules::PlayerConnect(base_player pl)
{
if (Plugin_PlayerConnect(pl) == FALSE)
bprint(PRINT_HIGH, sprintf("%s connected\n", pl.netname));
}
void
HLGameRules::PlayerDisconnect(base_player pl)
{
if (Plugin_PlayerDisconnect(pl) == FALSE)
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 = -1;
}
void
HLGameRules::PlayerKill(base_player pl)
{
Damage_Apply(pl, pl, pl.health, WEAPON_NONE, DMG_SKIP_ARMOR);
}

View File

@ -0,0 +1,166 @@
/*
* 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
HLMultiplayerRules::FrameStart(void)
{
if (cvar("mp_timelimit"))
if (time >= (cvar("mp_timelimit") * 60)) {
IntermissionStart();
}
IntermissionCycle();
}
void
HLMultiplayerRules::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);
Plugin_PlayerObituary(g_dmg_eAttacker, g_dmg_eTarget, g_dmg_iWeapon, g_dmg_iHitBody, g_dmg_iDamage);
/* 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++;
}
/* in DM we only care about the frags */
if (cvar("mp_fraglimit"))
if (g_dmg_eAttacker.frags >= cvar("mp_fraglimit")) {
IntermissionStart();
}
weaponbox_spawn((player)pl);
/* either gib, or make a corpse */
if (pl.health < -50) {
FX_GibHuman(pl.origin);
} else {
/* 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;
}
/* now let's make the real client invisible */
pl.SetModelindex(0);
pl.SetMovetype(MOVETYPE_NONE);
pl.SetSolid(SOLID_NOT);
pl.takedamage = DAMAGE_NO;
pl.gflags &= ~GF_FLASHLIGHT;
pl.armor = pl.activeweapon = pl.g_items = 0;
pl.health = 0;
Sound_Play(pl, CHAN_AUTO, "player.die");
/* force respawn */
pl.think = PutClientInServer;
pl.nextthink = time + 4.0f;
}
void
HLMultiplayerRules::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));
LevelNewParms();
LevelDecodeParms(pl);
pl.g_items = ITEM_CROWBAR | ITEM_GLOCK | ITEM_SUIT;
pl.activeweapon = WEAPON_GLOCK;
pl.glock_mag = 18;
pl.ammo_9mm = 44;
spot = Spawn_SelectRandom("info_player_deathmatch");
setorigin(pl, spot.origin);
pl.angles = spot.angles;
Weapons_RefreshAmmo(pl);
Client_FixAngle(pl, pl.angles);
}
float
HLMultiplayerRules::ConsoleCommand(base_player pp, string cmd)
{
tokenize(cmd);
switch (argv(0)) {
case "bot_add":
Bot_AddQuick();
break;
default:
return FALSE;
}
return TRUE;
}

View File

@ -0,0 +1,103 @@
/*
* 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
HLSingleplayerRules::PlayerDeath(base_player pl)
{
pl.movetype = MOVETYPE_NONE;
pl.solid = SOLID_NOT;
pl.takedamage = DAMAGE_NO;
pl.gflags &= ~GF_FLASHLIGHT;
pl.armor = pl.activeweapon = pl.g_items = pl.weapon = 0;
pl.health = 0;
Sound_Play(pl, CHAN_AUTO, "player.die");
if (cvar("coop") == 1) {
pl.think = PutClientInServer;
pl.nextthink = time + 4.0f;
}
if (pl.health < -50) {
FX_GibHuman(pl.origin);
}
/* Let's handle corpses on the clientside */
entity corpse = spawn();
setorigin(corpse, pl.origin + [0,0,32]);
setmodel(corpse, pl.model);
setsize(corpse, VEC_HULL_MIN, VEC_HULL_MAX);
corpse.movetype = MOVETYPE_TOSS;
corpse.solid = SOLID_TRIGGER;
corpse.modelindex = pl.modelindex;
corpse.frame = ANIM_DIESIMPLE;
corpse.angles = pl.angles;
corpse.velocity = pl.velocity;
}
void
HLSingleplayerRules::PlayerSpawn(base_player pl)
{
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";
if (cvar("coop") == 1) {
string mymodel = infokey(pl, "model");
if (mymodel) {
mymodel = sprintf("models/player/%s/%s.mdl", mymodel, mymodel);
if (whichpack(mymodel)) {
pl.model = mymodel;
}
}
}
setmodel(pl, pl.model);
setsize(pl, VEC_HULL_MIN, VEC_HULL_MAX);
pl.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));
/* this is where the mods want to deviate */
entity spot;
if (startspot != "") {
dprint(sprintf("^3Gamerules_Spawn^7: Startspot is %s\n", startspot));
LevelDecodeParms(pl);
setorigin(pl, Landmark_GetSpot());
} else {
LevelNewParms();
spot = find(world, ::classname, "info_player_start");
setorigin(pl, spot.origin);
pl.angles = spot.angles;
}
Weapons_RefreshAmmo(pl);
Client_FixAngle(pl, pl.angles);
}

108
src/server/input.qc Normal file
View File

@ -0,0 +1,108 @@
/*
* 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 (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_CROWBAR, -1);
Weapons_AddItem(pl, WEAPON_GLOCK, -1);
Weapons_AddItem(pl, WEAPON_PYTHON, -1);
Weapons_AddItem(pl, WEAPON_MP5, -1);
Weapons_AddItem(pl, WEAPON_SHOTGUN, -1);
Weapons_AddItem(pl, WEAPON_CROSSBOW, -1);
Weapons_AddItem(pl, WEAPON_RPG, -1);
Weapons_AddItem(pl, WEAPON_GAUSS, -1);
Weapons_AddItem(pl, WEAPON_EGON, -1);
Weapons_AddItem(pl, WEAPON_HORNETGUN, -1);
Weapons_AddItem(pl, WEAPON_HANDGRENADE, -1);
Weapons_AddItem(pl, WEAPON_SATCHEL, -1);
Weapons_AddItem(pl, WEAPON_TRIPMINE, -1);
Weapons_AddItem(pl, WEAPON_SNARK, -1);
#ifdef GEARBOX
Weapons_AddItem(pl, WEAPON_PIPEWRENCH, -1);
Weapons_AddItem(pl, WEAPON_KNIFE, -1);
Weapons_AddItem(pl, WEAPON_GRAPPLE, -1);
Weapons_AddItem(pl, WEAPON_EAGLE, -1);
Weapons_AddItem(pl, WEAPON_PENGUIN, -1);
Weapons_AddItem(pl, WEAPON_M249, -1);
Weapons_AddItem(pl, WEAPON_DISPLACER, -1);
Weapons_AddItem(pl, WEAPON_SNIPERRIFLE, -1);
Weapons_AddItem(pl, WEAPON_SPORELAUNCHER, -1);
Weapons_AddItem(pl, WEAPON_SHOCKRIFLE, -1);
#endif
}
if (self.impulse == 102) {
// Respawn all the entities
for (entity a = world; (a = findfloat(a, ::identity, 1));) {
CBaseEntity caw = (CBaseEntity)a;
caw.Respawn();
caw.SendFlags |=
BASEFL_CHANGED_ORIGIN |
BASEFL_CHANGED_ANGLES |
BASEFL_CHANGED_MODELINDEX |
BASEFL_CHANGED_SIZE |
BASEFL_CHANGED_SOLID |
BASEFL_CHANGED_FRAME |
BASEFL_CHANGED_SKIN |
BASEFL_CHANGED_MOVETYPE |
BASEFL_CHANGED_EFFECTS;
}
bprint(PRINT_HIGH, "Respawning all map entities...\n");
}
}
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", 15);
if (pl.armor > 100) {
pl.armor = 100;
}
Logging_Pickup(other, this, __NULL__);
Sound_Play(other, CHAN_ITEM, "item.battery");
if (real_owner || cvar("sv_playerslots") == 1) {
remove(self);
} else {
Hide();
think = Respawn;
nextthink = time + 20.0f;
}
}
void item_battery::Respawn(void)
{
SetSolid(SOLID_TRIGGER);
SetMovetype(MOVETYPE_TOSS);
SetSize([-16,-16,0],[16,16,16]);
SetOrigin(m_oldOrigin);
SetModel(m_oldModel);
// botinfo = BOTINFO_ARMOR;
think = __NULL__;
nextthink = -1;
if (!real_owner)
Sound_Play(this, CHAN_ITEM, "item.respawn");
droptofloor();
}
void item_battery::item_battery(void)
{
Sound_Precache("item.battery");
Sound_Precache("item.respawn");
model = "models/w_battery.mdl";
CBaseEntity::CBaseEntity();
item_healthkit::Respawn();
}

View File

@ -0,0 +1,80 @@
/*
* 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 (real_owner || cvar("sv_playerslots") == 1) {
remove(self);
} else {
Hide();
think = Respawn;
nextthink = time + 20.0f;
}
}
void item_healthkit::Respawn(void)
{
SetSolid(SOLID_TRIGGER);
SetMovetype(MOVETYPE_TOSS);
SetSize([-16,-16,0],[16,16,16]);
SetOrigin(m_oldOrigin);
SetModel(m_oldModel);
//botinfo = BOTINFO_HEALTH;
think = __NULL__;
nextthink = -1;
if (!real_owner)
Sound_Play(this, CHAN_ITEM, "item.respawn");
droptofloor();
}
void item_healthkit::item_healthkit(void)
{
Sound_Precache("item.healthkit");
Sound_Precache("item.respawn");
model = "models/w_medkit.mdl";
CBaseEntity::CBaseEntity();
item_healthkit::Respawn();
}

108
src/server/item_longjump.qc Normal file
View File

@ -0,0 +1,108 @@
/*
* 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_longjump (0 0 0.8) (-16 -16 0) (16 16 36)
HALF-LIFE (1998) ENTITY
Longjump module.
Allows the player to jump longer distance by holding crouch
and pressing jump.
*/
class item_longjump:CBaseTrigger
{
string m_strOnPlayerTouch;
void(void) item_longjump;
virtual void(void) touch;
virtual void(void) Respawn;
virtual void(string, string) SpawnKey;
};
void
item_longjump::touch(void)
{
if (other.classname != "player") {
return;
}
player pl = (player)other;
if (pl.g_items & ITEM_LONGJUMP) {
return;
}
Logging_Pickup(other, this, __NULL__);
sound(other, CHAN_ITEM, "fvox/blip.wav", 1, ATTN_NORM);
sound(other, CHAN_VOICE, "fvox/powermove_on.wav", 1, ATTN_NORM);
pl.g_items |= ITEM_LONGJUMP;
if (!target) {
UseOutput(other, m_strOnPlayerTouch);
} else {
UseTargets(other, TRIG_TOGGLE, m_flDelay);
}
if (real_owner || cvar("sv_playerslots") == 1) {
remove(self);
} else {
Hide();
think = Respawn;
nextthink = time + 30.0f;
}
}
void
item_longjump::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;
if (!real_owner)
Sound_Play(this, CHAN_ITEM, "item.respawn");
}
void
item_longjump::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "OnPlayerTouch":
strValue = strreplace(",", ",_", strValue);
m_strOnPlayerTouch = strcat(m_strOnPlayerTouch, ",_", strValue);
break;
default:
CBaseTrigger::SpawnKey(strKey, strValue);
break;
}
}
void
item_longjump::item_longjump(void)
{
model = "models/w_longjump.mdl";
precache_sound("items/suitchargeok1.wav");
precache_sound("fvox/powermove_on.wav");
precache_sound("fvox/blip.wav");
CBaseTrigger::CBaseTrigger();
Respawn();
}

113
src/server/item_suit.qc Normal file
View File

@ -0,0 +1,113 @@
/*
* 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_suit (0 0 0.8) (-16 -16 0) (16 16 36) SUIT_LONGINTRO
HALF-LIFE (1998) ENTITY
HEV Suit
Provides the player with armor, a flashlight and a Heads-Up-Display.
When SUIT_LONGINTRO is set, the intro dialog will be longer.
*/
class item_suit:CBaseTrigger
{
string m_strOnPlayerTouch;
void(void) item_suit;
virtual void(void) touch;
virtual void(void) Respawn;
virtual void(string, string) SpawnKey;
};
void
item_suit::touch(void)
{
if (other.classname != "player") {
return;
}
player pl = (player)other;
if (pl.g_items & ITEM_SUIT) {
return;
}
Logging_Pickup(other, this, __NULL__);
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_SUIT;
m_iValue = TRUE;
if (!target) {
UseOutput(other, m_strOnPlayerTouch);
} else {
UseTargets(other, TRIG_TOGGLE, m_flDelay);
}
if (real_owner || cvar("sv_playerslots") == 1) {
remove(self);
} else {
Hide();
think = Respawn;
nextthink = time + 30.0f;
}
}
void
item_suit::Respawn(void)
{
SetSolid(SOLID_TRIGGER);
SetMovetype(MOVETYPE_TOSS);
SetSize(VEC_HULL_MIN, VEC_HULL_MAX);
SetOrigin(m_oldOrigin);
SetModel(m_oldModel);
m_iValue = FALSE;
think = __NULL__;
nextthink = -1;
if (!real_owner)
Sound_Play(this, CHAN_ITEM, "item.respawn");
}
void
item_suit::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "OnPlayerTouch":
strValue = strreplace(",", ",_", strValue);
m_strOnPlayerTouch = strcat(m_strOnPlayerTouch, ",_", strValue);
break;
default:
CBaseTrigger::SpawnKey(strKey, strValue);
break;
}
}
void
item_suit::item_suit(void)
{
model = "models/w_suit.mdl";
precache_sound("items/suitchargeok1.wav");
precache_sound("fvox/hev_logon.wav");
precache_sound("fvox/bell.wav");
CBaseTrigger::CBaseTrigger();
m_strOnPlayerTouch = CreateOutput(m_strOnPlayerTouch);
}

View File

@ -0,0 +1,112 @@
/*
* 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_9mm;
int ammo_357;
int ammo_buckshot;
int ammo_m203_grenade;
int ammo_bolt;
int ammo_rocket;
int ammo_uranium;
int ammo_handgrenade;
int ammo_satchel;
int ammo_tripmine;
int ammo_snark;
int ammo_hornet;
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_9mm += ammo_9mm;
pl.ammo_357 += ammo_357;
pl.ammo_buckshot += ammo_buckshot;
pl.ammo_m203_grenade += ammo_m203_grenade;
pl.ammo_bolt += ammo_bolt;
pl.ammo_rocket += ammo_rocket;
pl.ammo_uranium += ammo_uranium;
pl.ammo_handgrenade += ammo_handgrenade;
pl.ammo_satchel += ammo_satchel;
pl.ammo_tripmine += ammo_tripmine;
pl.ammo_snark += ammo_snark;
pl.ammo_hornet += ammo_hornet;
/* cull */
pl.ammo_9mm = min(pl.ammo_9mm, MAX_A_9MM);
pl.ammo_357 = min(pl.ammo_357, MAX_A_357);
pl.ammo_buckshot = min(pl.ammo_buckshot, MAX_A_BUCKSHOT);
pl.ammo_m203_grenade = min(pl.ammo_m203_grenade, MAX_A_M203_GRENADE);
pl.ammo_bolt = min(pl.ammo_bolt, MAX_A_BOLT);
pl.ammo_rocket = min(pl.ammo_rocket, MAX_A_ROCKET);
pl.ammo_uranium = min(pl.ammo_uranium, MAX_A_URANIUM);
pl.ammo_handgrenade = min(pl.ammo_handgrenade, MAX_A_HANDGRENADE);
pl.ammo_satchel = min(pl.ammo_satchel, MAX_A_SATCHEL);
pl.ammo_tripmine = min(pl.ammo_tripmine, MAX_A_TRIPMINE);
pl.ammo_snark = min(pl.ammo_snark, MAX_A_SNARK);
pl.ammo_hornet = min(pl.ammo_hornet, MAX_A_HORNET);
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_9mm = pl.ammo_9mm;
ammo_357 = pl.ammo_357;
ammo_buckshot = pl.ammo_buckshot;
ammo_m203_grenade = pl.ammo_m203_grenade;
ammo_bolt = pl.ammo_bolt;
ammo_rocket = pl.ammo_rocket;
ammo_uranium = pl.ammo_uranium;
ammo_handgrenade = pl.ammo_handgrenade;
ammo_satchel = pl.ammo_satchel;
ammo_tripmine = pl.ammo_tripmine;
ammo_snark = pl.ammo_snark;
ammo_hornet = pl.ammo_hornet;
weapon_items = pl.g_items;
}
void item_weaponbox::item_weaponbox(void)
{
SetModel("models/w_weaponbox.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);
}

30
src/server/items.h 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.
*/
/* PICKUP ITEMS */
class item_pickup:CBaseTrigger
{
int m_bFloating;
int m_iClip;
int m_iWasDropped;
int id;
void(void) item_pickup;
virtual void(void) touch;
virtual void(int i) SetItem;
virtual void(void) Respawn;
virtual void(int) SetFloating;
};

88
src/server/items.qc Normal file
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.
*/
void item_pickup::touch(void)
{
if (other.classname != "player") {
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");
UseTargets(other, TRIG_TOGGLE, m_flDelay);
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();
}

View File

@ -0,0 +1,128 @@
/*
* 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 monster_alien_controller (0 0.8 0.8) (-16 -16 0) (16 16 72)
HALF-LIFE (1998) ENTITY
Alien Controller
*/
enum
{
CON_ATTACK,
CON_ATTACK2,
CON_THROW,
CON_IDLE2,
CON_BLOCK,
CON_SHOOT,
CON_FLINCH,
CON_FLINCH2,
CON_FALL,
CON_FORWARD,
CON_BACKWARD,
CON_UP,
CON_DOWN,
CON_RIGHT,
CON_LEFT,
CON_IDLE,
CON_UNUSED,
CON_UNUSED2,
CON_DIE
};
class monster_alien_controller:CBaseMonster
{
float m_flIdleTime;
float m_flPainTime;
void(void) monster_alien_controller;
virtual void(void) Pain;
virtual void(void) Death;
virtual void(void) IdleNoise;
virtual void(void) Respawn;
};
void
monster_alien_controller::Pain(void)
{
CBaseMonster::Pain();
if (m_flPainTime > time) {
return;
}
if (random() < 0.25f) {
return;
}
Sound_Play(this, CHAN_VOICE, "monster_alien_controller.die");
SetFrame(CON_FLINCH + floor(random(0, 2)));
m_flPainTime = time + 0.25f;
}
void
monster_alien_controller::Death(void)
{
/* if we're already dead (corpse) don't change animations */
if (style != MONSTER_DEAD) {
SetFrame(CON_DIE);
Sound_Play(this, CHAN_VOICE, "monster_alien_controller.die");
}
/* set the functional differences */
CBaseMonster::Death();
}
void
monster_alien_controller::IdleNoise(void)
{
/* don't make noise if we're dead (corpse) */
if (style == MONSTER_DEAD) {
return;
}
if (m_flIdleTime > time) {
return;
}
m_flIdleTime = time + random(2,10);
Sound_Play(this, CHAN_VOICE, "monster_alien_controller.idle");
}
void
monster_alien_controller::Respawn(void)
{
CBaseMonster::Respawn();
SetFrame(CON_IDLE);
}
void
monster_alien_controller::monster_alien_controller(void)
{
Sound_Precache("monster_alien_controller.alert");
Sound_Precache("monster_alien_controller.attack");
Sound_Precache("monster_alien_controller.die");
Sound_Precache("monster_alien_controller.idle");
Sound_Precache("monster_alien_controller.pain");
netname = "Alien Controller";
model = "models/controller.mdl";
base_mins = [-16,-16,0];
base_maxs = [16,16,72];
CBaseMonster::CBaseMonster();
}

View File

@ -0,0 +1,153 @@
/*
* 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 monster_alien_grunt (0 0.8 0.8) (-32 -32 0) (32 32 64)
HALF-LIFE (1998) ENTITY
Alien Grunt
*/
enum
{
AG_IDLE,
AG_THREAT,
AG_WALK,
AG_RUN,
AG_LEFT,
AG_RIGHT,
AG_FLINCH,
AG_FLINCHBIG,
AG_ATTACK,
AG_ATTACK2,
AG_VICTORYSQUAT,
AG_VICTORYEAT,
AG_VICTORYSTAND,
AG_FLINCHARML,
AG_FLINCHLEGL,
AG_FLINCHARMR,
AG_FLINCHLEGR,
AG_SHOOTUP,
AG_SHOOTDOWN,
AG_SHOOT,
AG_SHOOTQUICK,
AG_SHOOTLONG,
AG_DIEHS,
AG_DIEGUT,
AG_DIEFORWARD,
AG_DIE,
AG_DIEBACK,
AG_FLOAT,
AG_SCARE,
AG_OPEN,
AG_SMASHRAIL,
AG_LAND
};
class monster_alien_grunt:CBaseMonster
{
float m_flIdleTime;
float m_flPainTime;
void(void) monster_alien_grunt;
virtual void(void) Pain;
virtual void(void) Death;
virtual void(void) IdleNoise;
virtual void(void) Respawn;
};
void
monster_alien_grunt::Pain(void)
{
CBaseMonster::Pain();
if (m_flPainTime > time) {
return;
}
if (random() < 0.25f) {
return;
}
Sound_Play(this, CHAN_VOICE, "monster_alien_grunt.pain");
SetFrame(AG_FLINCH + floor(random(0, 2)));
m_flPainTime = time + 0.25f;
}
void
monster_alien_grunt::Death(void)
{
/* if we're already dead (corpse) don't change animations */
if (style != MONSTER_DEAD) {
/* headshots == different animation */
if (g_dmg_iHitBody == BODY_HEAD) {
if (random() < 0.5) {
SetFrame(AG_DIEHS);
} else {
SetFrame(AG_DIEFORWARD);
}
} else {
SetFrame(AG_DIE + floor(random(0, 2)));
}
Sound_Play(this, CHAN_VOICE, "monster_alien_grunt.die");
}
/* set the functional differences */
CBaseMonster::Death();
}
void
monster_alien_grunt::IdleNoise(void)
{
/* don't make noise if we're dead (corpse) */
if (style == MONSTER_DEAD) {
return;
}
if (m_flIdleTime > time) {
return;
}
m_flIdleTime = time + random(2,10);
Sound_Play(this, CHAN_VOICE, "monster_alien_grunt.idle");
}
void
monster_alien_grunt::Respawn(void)
{
CBaseMonster::Respawn();
SetFrame(AG_IDLE);
}
void
monster_alien_grunt::monster_alien_grunt(void)
{
Sound_Precache("monster_alien_grunt.alert");
Sound_Precache("monster_alien_grunt.attack");
Sound_Precache("monster_alien_grunt.die");
Sound_Precache("monster_alien_grunt.idle");
Sound_Precache("monster_alien_grunt.pain");
netname = "Alien Grunt";
model = "models/agrunt.mdl";
base_mins = [-32,-32,0];
base_maxs = [32,32,64];
base_health = Skill_GetValue("agrunt_health", 90);
CBaseMonster::CBaseMonster();
}

View File

@ -0,0 +1,254 @@
/*
* 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 monster_alien_slave (0 0.8 0.8) (-16 -16 0) (16 16 72)
HALF-LIFE (1998) ENTITY
Alien Slave
*/
enum
{
SLV_IDLE,
SLV_IDLE2,
SLV_IDLE3,
SLV_CROUCH,
SLV_WALK,
SLV_WALK2,
SLV_RUN,
SLV_RIGHT,
SLV_LEFT,
SLV_JUMP,
SLV_STAIRUP,
SLV_ATTACK,
SLV_ATTACKZAP,
SLV_FLINCH,
SLV_FLINCHLA,
SLV_FLINCHRA,
SLV_FLINCHL,
SLV_FLINCHR,
SLV_DIEHS,
SLV_DIE,
SLV_DIEBACK,
SLV_DIEFORWARD,
SLV_COLLAR,
SLV_COLLAR2,
SLV_PUSHUP,
SLV_GRAB,
SLV_UPDOWN,
SLV_DOWNUP,
SLV_JIBBER,
SLV_JABBER
};
class monster_alien_slave:CBaseNPC
{
float m_flIdleTime;
float m_flPainTime;
void(void) monster_alien_slave;
virtual void(void) Death;
virtual void(void) Pain;
virtual void(void) IdleChat;
virtual void(void) Respawn;
virtual int(void) AnimIdle;
virtual int(void) AnimWalk;
virtual int(void) AnimRun;
virtual int(void) AttackMelee;
virtual void(void) AttackFlail;
virtual int(void) AttackRanged;
virtual void(void) AttackBeam;
};
int
monster_alien_slave::AnimIdle(void)
{
return SLV_IDLE;
}
int
monster_alien_slave::AnimWalk(void)
{
return SLV_WALK;
}
int
monster_alien_slave::AnimRun(void)
{
return SLV_RUN;
}
int
monster_alien_slave::AttackMelee(void)
{
/* visual */
AnimPlay(SLV_ATTACK);
m_flAttackThink = m_flAnimTime;
/* functional */
think = AttackFlail;
nextthink = 0.25f;
return TRUE;
}
void
monster_alien_slave::AttackFlail(void)
{
traceline(origin, m_eEnemy.origin, FALSE, this);
if (trace_fraction >= 1.0 || trace_ent.takedamage != DAMAGE_YES) {
Sound_Play(this, CHAN_WEAPON, "monster_zombie.attackmiss");
return;
}
Damage_Apply(trace_ent, this, 25, 0, 0);
Sound_Play(this, CHAN_WEAPON, "monster_zombie.attackhit");
}
int
monster_alien_slave::AttackRanged(void)
{
/* visual */
AnimPlay(SLV_ATTACKZAP);
m_flAttackThink = m_flAnimTime;
Sound_Play(this, CHAN_VOICE, "monster_alien_slave.attack_charge");
/* functional */
think = AttackBeam;
nextthink = time + 1.5f;
return TRUE;
}
void
monster_alien_slave::AttackBeam(void)
{
traceline(origin, m_eEnemy.origin, FALSE, this);
Sound_Play(this, CHAN_WEAPON, "monster_alien_slave.attack_shoot");
if (trace_fraction >= 1.0 || trace_ent.takedamage != DAMAGE_YES) {
//Sound_Play(this, CHAN_WEAPON, "monster_zombie.attackmiss");
return;
}
Damage_Apply(trace_ent, this, 100, 0, 0);
}
void
monster_alien_slave::IdleChat(void)
{
if (m_flIdleTime > time) {
return;
}
Sentence(m_talkIdle);
m_flIdleTime = time + 5.0f + random(0,20);
}
void
monster_alien_slave::Pain(void)
{
CBaseNPC::Pain();
if (m_flPainTime > time) {
return;
}
if (random() < 0.25f) {
return;
}
Sound_Play(this, CHAN_VOICE, "monster_alien_slave.pain");
SetFrame(SLV_FLINCH + floor(random(0, 2)));
m_flPainTime = time + 0.25f;
}
void
monster_alien_slave::Death(void)
{
/* if we're already dead (corpse) don't change animations */
if (style != MONSTER_DEAD) {
/* headshots == different animation */
if (g_dmg_iHitBody == BODY_HEAD) {
if (random() < 0.5) {
SetFrame(SLV_DIEHS);
} else {
SetFrame(SLV_DIEBACK);
}
} else {
SetFrame(SLV_DIE + floor(random(0, 3)));
}
Sound_Play(this, CHAN_VOICE, "monster_alien_slave.die");
}
/* set the functional differences */
CBaseNPC::Death();
}
void
monster_alien_slave::Respawn(void)
{
CBaseNPC::Respawn();
SetFrame(SLV_IDLE);
}
void
monster_alien_slave::monster_alien_slave(void)
{
Sound_Precache("monster_alien_slave.die");
Sound_Precache("monster_alien_slave.pain");
Sound_Precache("monster_alien_slave.attack_charge");
Sound_Precache("monster_alien_slave.attack_shoot");
Sound_Precache("monster_zombie.attackhit");
Sound_Precache("monster_zombie.attackmiss");
m_talkAnswer = "";
m_talkAsk = "";
m_talkAllyShot = "";
m_talkGreet = "SLV_ALERT";
m_talkIdle = "!SLV_IDLE";
m_talkSmelling = "";
m_talkStare = "";
m_talkSurvived = "";
m_talkWounded = "";
m_talkPlayerAsk = "";
m_talkPlayerGreet = "!SLV_ALERT";
m_talkPlayerIdle = "";
m_talkPlayerWounded1 = "";
m_talkPlayerWounded2 = "";
m_talkPlayerWounded3 = "";
m_talkUnfollow = "";
m_talkFollow = "";
m_talkStopFollow = "";
netname = "Alien Slave";
model = "models/islave.mdl";
base_health = Skill_GetValue("islave_health", 30);
base_mins = [-16,-16,0];
base_maxs = [16,16,72];
m_iAlliance = MAL_ALIEN;
CBaseNPC::CBaseNPC();
}

View File

@ -0,0 +1,48 @@
/*
* 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 monster_apache (0 0.8 0.8) (-300 -300 -172) (300 300 8)
HALF-LIFE (1998) ENTITY
Boeing AH-64 Apache
*/
class monster_apache:CBaseMonster
{
void(void) monster_apache;
virtual void(void) Respawn;
};
void monster_apache::Respawn(void)
{
CBaseMonster::Respawn();
movetype = MOVETYPE_NONE;
takedamage = DAMAGE_NO;
iBleeds = FALSE;
setsize(this, [-300,-300,-172], [300, 300, 8]);
}
void monster_apache::monster_apache(void)
{
netname = "Apache";
model = "models/apache.mdl";
base_mins = [-16,-16,0];
base_maxs = [16,16,72];
base_health = Skill_GetValue("apache_health", 250);
CBaseMonster::CBaseMonster();
}

View File

@ -0,0 +1,34 @@
/*
* 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 monster_babycrab (0 0.8 0.8) (-16 -16 0) (16 16 36)
HALF-LIFE (1998) ENTITY
Baby Headcrab
*/
class monster_babycrab:monster_headcrab
{
void(void) monster_babycrab;
};
void
monster_babycrab::monster_babycrab(void)
{
monster_headcrab::monster_headcrab();
}

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 monster_barnacle (0 0.8 0.8) (-16 -16 -36) (16 16 0)
HALF-LIFE (1998) ENTITY
Barnacle
*/
enum
{
BCL_IDLE,
BCL_IDLE2,
BCL_IDLE3,
BCL_FLINCH,
BCL_ATTACK,
BCL_CHEW,
BCL_DIE
};
class monster_barnacle:CBaseMonster
{
void(void) monster_barnacle;
virtual void(void) Death;
virtual void(void) Respawn;
virtual void(void) Physics;
};
void
monster_barnacle::Physics(void)
{
movetype = MOVETYPE_NONE;
}
void
monster_barnacle::Death(void)
{
/* if we're already dead (corpse) don't change animations */
if (style != MONSTER_DEAD) {
SetFrame(BCL_DIE);
Sound_Play(this, CHAN_VOICE, "monster_barnacle.die");
}
/* set the functional differences */
CBaseMonster::Death();
}
void
monster_barnacle::Respawn(void)
{
CBaseMonster::Respawn();
SetFrame(BCL_IDLE);
}
void monster_barnacle::monster_barnacle(void)
{
Sound_Precache("monster_barnacle.attackchew");
Sound_Precache("monster_barnacle.attackpull");
Sound_Precache("monster_barnacle.die");
netname = "Barnacle";
model = "models/barnacle.mdl";
base_mins = [-16,-16,-36];
base_maxs = [16,16,0];
base_health = Skill_GetValue("barnacle_health", 25);
CBaseMonster::CBaseMonster();
}

View File

@ -0,0 +1,209 @@
/*
* 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 monster_barney (0 0.8 0.8) (-16 -16 0) (16 16 72)
HALF-LIFE (1998) ENTITY
Barney Calhoun
*/
enum
{
BA_IDLE1,
BA_IDLE2,
BA_IDLE3,
BA_IDLE4,
BA_WALK,
BA_RUN,
BA_SHOOT1,
BA_SHOOT2,
BA_DRAW,
BA_HOLSTER,
BA_RELOAD,
BA_TURNLEFT,
BA_TURNRIGHT,
BA_FLINCH_LA,
BA_FLINCH_RA,
BA_FLINCH_LL,
BA_FLINCH_RL,
BA_FLINCH_SML
};
class monster_barney:CBaseNPC
{
void(void) monster_barney;
virtual void(void) Respawn;
virtual void(void) OnPlayerUse;
virtual void(void) Pain;
virtual void(void) Death;
virtual int(void) AnimIdle;
virtual int(void) AnimWalk;
virtual int(void) AnimRun;
virtual void(void) AttackDraw;
virtual void(void) AttackHolster;
virtual int(void) AttackMelee;
virtual int(void) AttackRanged;
};
int
monster_barney::AnimIdle(void)
{
return BA_IDLE1;
}
int
monster_barney::AnimWalk(void)
{
return BA_WALK;
}
int
monster_barney::AnimRun(void)
{
return BA_RUN;
}
void
monster_barney::AttackDraw(void)
{
AnimPlay(BA_DRAW);
m_flAttackThink = m_flAnimTime;
}
void
monster_barney::AttackHolster(void)
{
AnimPlay(BA_HOLSTER);
m_flAttackThink = m_flAnimTime;
}
int
monster_barney::AttackMelee(void)
{
return AttackRanged();
}
int
monster_barney::AttackRanged(void)
{
/* visual */
AnimPlay(BA_SHOOT1);
m_flAttackThink = time + 0.4f;
/* functional */
v_angle = vectoangles(m_eEnemy.origin - origin);
TraceAttack_FireBullets(1, origin + [0,0,16], 8, [0.01,0.01], 2);
Sound_Play(this, CHAN_WEAPON, "weapon_glock.fire");
return TRUE;
}
void
monster_barney::OnPlayerUse(void)
{
if (spawnflags & MSF_PREDISASTER) {
Sentence("!BA_POK");
return;
}
CBaseNPC::OnPlayerUse();
}
void
monster_barney::Pain(void)
{
CBaseNPC::Pain();
WarnAllies();
if (m_flAnimTime > time) {
return;
}
if (random() < 0.25f) {
return;
}
Sound_Speak(this, "monster_barney.pain");
AnimPlay(BA_FLINCH_LA + floor(random(0, 5)));
m_flAttackThink = m_flAnimTime;
m_iFlags |= MONSTER_FEAR;
}
void
monster_barney::Death(void)
{
WarnAllies();
if (style != MONSTER_DEAD) {
SetFrame(25 + floor(random(0, 6)));
Sound_Speak(this, "monster_barney.die");
}
/* now mark our state as 'dead' */
CBaseNPC::Death();
}
void
monster_barney::Respawn(void)
{
CBaseNPC::Respawn();
m_iFlags |= MONSTER_CANFOLLOW;
PlayerUse = OnPlayerUse;
}
void
monster_barney::monster_barney(void)
{
Sound_Precache("monster_barney.die");
Sound_Precache("monster_barney.pain");
/* TODO
* BA_MAD - When player gets too naughty
* */
m_talkAnswer = "!BA_ANSWER";
m_talkAsk = "!BA_QUESTION";
m_talkAllyShot = "!BA_SHOOT";
m_talkGreet = "";
m_talkIdle = "!BA_IDLE";
m_talkHearing = "!BA_HEAR";
m_talkSmelling = "!BA_SMELL";
m_talkStare = "!BA_STARE";
m_talkSurvived = "!BA_WOUND";
m_talkWounded = "!BA_WOUND";
m_talkPlayerAsk = "!BA_QUESTION";
m_talkPlayerGreet = "!BA_HELLO";
m_talkPlayerIdle = "!BA_IDLE";
m_talkPlayerWounded1 = "!BA_CUREA";
m_talkPlayerWounded2 = "!BA_CUREB";
m_talkPlayerWounded3 = "!BA_CUREC";
m_talkUnfollow = "!BA_WAIT";
m_talkFollow = "!BA_OK";
m_talkStopFollow = "!BA_STOP";
model = "models/barney.mdl";
netname = "Barney";
base_health = Skill_GetValue("barney_health", 35);
base_mins = [-16,-16,0];
base_maxs = [16,16,72];
m_iAlliance = MAL_FRIEND;
CBaseNPC::CBaseNPC();
}

View File

@ -0,0 +1,89 @@
/*
* 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 monster_barney_dead (0 0.8 0.8) (-16 -16 0) (16 16 72)
HALF-LIFE (1998) ENTITY
Barney's corpse
*/
class monster_barney_dead:CBaseEntity
{
int m_iPose;
void(void) monster_barney_dead;
virtual void(void) Hide;
virtual void(void) Respawn;
virtual void(void) Gib;
virtual void(string, string) SpawnKey;
};
void
monster_barney_dead::Gib(void)
{
takedamage = DAMAGE_NO;
FX_GibHuman(this.origin);
Hide();
}
void
monster_barney_dead::Hide(void)
{
SetModel("");
solid = SOLID_NOT;
movetype = MOVETYPE_NONE;
}
void
monster_barney_dead::Respawn(void)
{
v_angle[0] = Math_FixDelta(m_oldAngle[0]);
v_angle[1] = Math_FixDelta(m_oldAngle[1]);
v_angle[2] = Math_FixDelta(m_oldAngle[2]);
SetOrigin(m_oldOrigin);
angles = v_angle;
solid = SOLID_CORPSE;
movetype = MOVETYPE_NONE;
SetModel(m_oldModel);
setsize(this, VEC_HULL_MIN + [0,0,36], VEC_HULL_MAX + [0,0,36]);
takedamage = DAMAGE_YES;
health = 0;
velocity = [0,0,0];
iBleeds = TRUE;
SetFrame(35 + m_iPose);
}
void
monster_barney_dead::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "pose":
m_iPose = stoi(strValue);
break;
default:
CBaseMonster::SpawnKey(strKey, strValue);
}
}
void
monster_barney_dead::monster_barney_dead(void)
{
model = "models/barney.mdl";
CBaseMonster::CBaseMonster();
}

View File

@ -0,0 +1,132 @@
/*
* 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 monster_bigmomma (0 0.8 0.8) (-95 -95 0) (95 95 190)
HALF-LIFE (1998) ENTITY
Gonarch
*/
enum
{
GON_IDLE,
GON_IDLE2,
GON_WALK,
GON_RUN,
GON_DIE,
GON_CLAW,
GON_CLAW2,
GON_CLAW3,
GON_SPAWN,
GON_SHOOT,
GON_FLINCH,
GON_DEFEND,
GON_JUMP,
GON_ANGRY,
GON_ANGRY2,
GON_ANGRY3,
GON_BREAKWALL,
GON_FALL,
GON_FALL2,
GON_FALLDIE
};
class monster_bigmomma:CBaseMonster
{
float m_flIdleTime;
void(void) monster_bigmomma;
virtual void(void) Death;
virtual void(void) Pain;
virtual void(void) IdleNoise;
virtual void(void) Respawn;
};
void
monster_bigmomma::IdleNoise(void)
{
/* don't make noise if we're dead (corpse) */
if (style == MONSTER_DEAD) {
return;
}
if (m_flIdleTime > time) {
return;
}
/* timing needs to adjusted as sounds conflict */
m_flIdleTime = time + random(2,10);
Sound_Play(this, CHAN_VOICE, "monster_bigmomma.idle");
}
void
monster_bigmomma::Pain(void)
{
CBaseMonster::Pain();
if (m_flAnimTime > time) {
return;
}
if (random() < 0.25f) {
return;
}
Sound_Play(this, CHAN_VOICE, "monster_bigmomma.pain");
SetFrame(GON_FLINCH);
m_flAnimTime = time + 0.25f;
}
void
monster_bigmomma::Death(void)
{
/* if we're already dead (corpse) don't change animations */
if (style != MONSTER_DEAD) {
SetFrame(GON_DIE);
Sound_Play(this, CHAN_VOICE, "monster_bigmomma.die");
}
/* set the functional differences */
CBaseMonster::Death();
}
void
monster_bigmomma::Respawn(void)
{
CBaseMonster::Respawn();
SetFrame(GON_IDLE);
}
void monster_bigmomma::monster_bigmomma(void)
{
Sound_Precache("monster_bigmomma.alert");
Sound_Precache("monster_bigmomma.attack");
Sound_Precache("monster_bigmomma.child");
Sound_Precache("monster_bigmomma.die");
Sound_Precache("monster_bigmomma.idle");
Sound_Precache("monster_bigmomma.pain");
Sound_Precache("monster_bigmomma.step");
netname = "Gonarch";
model = "models/big_mom.mdl";
/* health is based on factor, for it's not killable until last stage */
base_health = Skill_GetValue("bigmomma_health_factor", 1.5) * 300;
base_mins = [-95,-95,0];
base_maxs = [95,95,190];
CBaseMonster::CBaseMonster();
}

View File

@ -0,0 +1,37 @@
/*
* 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 monster_bloater (0 0.8 0.8) (-16 -16 0) (16 16 72)
HALF-LIFE (1998) ENTITY
Flocking Floater
*/
class monster_bloater:CBaseMonster
{
void(void) monster_bloater;
};
void monster_bloater::monster_bloater(void)
{
netname = "Floater";
model = "models/floater.mdl";
base_mins = [-16,-16,0];
base_maxs = [16,16,72];
CBaseMonster::CBaseMonster();
}

View File

@ -0,0 +1,155 @@
/*
* 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 monster_bullchicken (0 0.8 0.8) (-32 -32 0) (32 32 64)
HALF-LIFE (1998) ENTITY
Bullsquid
*/
enum
{
BULL_WALK,
BULL_RUN,
BULL_SURPIRSE,
BULL_FLINCH,
BULL_FLINCH2,
BULL_LEFT,
BULL_RIGHT,
BULL_IDLE,
BULL_WHIP,
BULL_BITE,
BULL_RANGE,
BULL_LOOK,
BULL_SEECRAB,
BULL_EAT,
BULL_INSPECT,
BULL_SNIFF,
BULL_DIE,
BULL_DIE2,
BULL_JUMP,
BULL_DRAGIDLE,
BULL_DRAG,
BULL_SCARE,
BULL_FALLIDLE,
BULL_FALL
};
/* the growls are used in combination with the bite sounds
* for close range attacks
*/
class monster_bullchicken:CBaseMonster
{
float m_flIdleTime;
void(void) monster_bullchicken;
virtual void(void) Death;
virtual void(void) Pain;
virtual void(void) IdleNoise;
virtual int(void) AnimIdle;
virtual int(void) AnimWalk;
virtual int(void) AnimRun;
};
int
monster_bullchicken::AnimIdle(void)
{
return BULL_IDLE;
}
int
monster_bullchicken::AnimWalk(void)
{
return BULL_WALK;
}
int
monster_bullchicken::AnimRun(void)
{
return BULL_RUN;
}
void
monster_bullchicken::IdleNoise(void)
{
/* don't make noise if we're dead (corpse) */
if (style == MONSTER_DEAD) {
return;
}
if (m_flIdleTime > time) {
return;
}
/* timing needs to adjusted as sounds conflict */
m_flIdleTime = time + random(2,10);
Sound_Play(this, CHAN_VOICE, "monster_bullchicken.idle");
}
void
monster_bullchicken::Pain(void)
{
CBaseMonster::Pain();
if (m_flAnimTime > time) {
return;
}
if (random() < 0.25f) {
return;
}
Sound_Play(this, CHAN_VOICE, "monster_bullchicken.pain");
SetFrame((random() < 0.5) ? BULL_FLINCH : BULL_FLINCH2);
m_flAnimTime = time + 0.25f;
}
void
monster_bullchicken::Death(void)
{
/* if we're already dead (corpse) don't change animations */
if (style != MONSTER_DEAD) {
/* two different animations */
SetFrame((random() < 0.5) ? BULL_DIE : BULL_DIE2);
Sound_Play(this, CHAN_VOICE, "monster_bullchicken.die");
}
/* set the functional differences */
CBaseMonster::Death();
}
void monster_bullchicken::monster_bullchicken(void)
{
Sound_Precache("monster_bullchicken.alert");
Sound_Precache("monster_bullchicken.attack");
Sound_Precache("monster_bullchicken.attackbite");
Sound_Precache("monster_bullchicken.attackshoot");
Sound_Precache("monster_bullchicken.die");
Sound_Precache("monster_bullchicken.idle");
Sound_Precache("monster_bullchicken.pain");
netname = "Bullsquid";
model = "models/bullsquid.mdl";
base_health = Skill_GetValue("bullsquid_health", 40);
base_mins = [-32,-32,0];
base_maxs = [32,32,64];
CBaseMonster::CBaseMonster();
}

View File

@ -0,0 +1,54 @@
/*
* 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 monster_cockroach (0 0.8 0.8) (-4 -4 0) (4 4 4)
HALF-LIFE (1998) ENTITY
Cockroach
*/
class monster_cockroach:CBaseMonster
{
void(void) monster_cockroach;
virtual void(void) Death;
};
void
monster_cockroach::Death(void)
{
/* if we're already dead (corpse) don't change animations */
if (style != MONSTER_DEAD) {
Sound_Play(this, CHAN_VOICE, "monster_cockroach.die");
}
/* make sure we gib this thing */
health = -100;
/* set the functional differences */
CBaseMonster::Death();
}
void monster_cockroach::monster_cockroach(void)
{
Sound_Precache("monster_cockroach.die");
netname = "Cockroach";
model = "models/roach.mdl";
base_mins = [-1,-1,0];
base_maxs = [1,1,1];
CBaseMonster::CBaseMonster();
}

View File

@ -0,0 +1,37 @@
/*
* 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 monster_flyer_flock (0 0.8 0.8) (-16 -16 0) (16 16 16)
HALF-LIFE (1998) ENTITY
Boid
*/
class monster_flyer_flock:CBaseMonster
{
void(void) monster_flyer_flock;
};
void monster_flyer_flock::monster_flyer_flock(void)
{
netname = "Boid";
model = "models/aflock.mdl";
base_mins = [-16,-16,0];
base_maxs = [16,16,16];
CBaseMonster::CBaseMonster();
}

View File

@ -0,0 +1,138 @@
/*
* 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 monster_gargantua (0 0.8 0.8) (-32 -32 0) (32 32 128)
HALF-LIFE (1998) ENTITY
Gargantua
*/
enum
{
GARG_IDLE,
GARG_IDLE2,
GARG_IDLE3,
GARG_IDLE4,
GARG_WALK,
GARG_RUN,
GARG_SHOOT,
GARG_SHOOT2,
GARG_ATTACK,
GARG_STOMP,
GARG_LEFT,
GARG_RIGHT,
GARG_FLINCH,
GARG_FLINCH2,
GARG_DIE,
GARG_BITEHEAD,
GARG_THROW,
GARG_SMASH,
GARG_ROLLCAR,
GARG_KICKCAR,
GARG_PUSHCAR,
GARG_BUST
};
class monster_gargantua:CBaseMonster
{
float m_flIdleTime;
void(void) monster_gargantua;
virtual void(void) Death;
virtual void(void) Pain;
virtual void(void) IdleNoise;
virtual void(void) Respawn;
};
void
monster_gargantua::IdleNoise(void)
{
/* don't make noise if we're dead (corpse) */
if (style == MONSTER_DEAD) {
return;
}
if (m_flIdleTime > time) {
return;
}
/* timing needs to adjusted as sounds conflict */
m_flIdleTime = time + random(2,10);
Sound_Play(this, CHAN_VOICE, "monster_gargantua.idle");
}
void
monster_gargantua::Pain(void)
{
CBaseMonster::Pain();
if (m_flAnimTime > time) {
return;
}
if (random() < 0.25f) {
return;
}
Sound_Play(this, CHAN_VOICE, "monster_gargantua.pain");
SetFrame((random() < 0.5) ? GARG_FLINCH : GARG_FLINCH2);
m_flAnimTime = time + 0.25f;
}
void
monster_gargantua::Death(void)
{
/* if we're already dead (corpse) don't change animations */
if (style != MONSTER_DEAD) {
SetFrame(GARG_DIE);
Sound_Play(this, CHAN_VOICE, "monster_gargantua.die");
}
/* set the functional differences */
CBaseMonster::Death();
}
void
monster_gargantua::Respawn(void)
{
CBaseMonster::Respawn();
SetFrame(GARG_IDLE);
/* takes damage from explosives only
* takedamage = DAMAGE_NO; */
iBleeds = FALSE;
}
void monster_gargantua::monster_gargantua(void)
{
Sound_Precache("monster_gargantua.alert");
Sound_Precache("monster_gargantua.attack");
Sound_Precache("monster_gargantua.attackflame");
Sound_Precache("monster_gargantua.attackflameon");
Sound_Precache("monster_gargantua.attackflameoff");
Sound_Precache("monster_gargantua.die");
Sound_Precache("monster_gargantua.idle");
Sound_Precache("monster_gargantua.pain");
Sound_Precache("monster_gargantua.step");
netname = "Gargantua";
model = "models/garg.mdl";
base_health = Skill_GetValue("gargantua_health", 800);
base_mins = [-32,-32,0];
base_maxs = [32,32,128];
CBaseMonster::CBaseMonster();
}

View File

@ -0,0 +1,87 @@
/*
* 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 monster_gman (0 0.8 0.8) (-16 -16 0) (16 16 72)
HALF-LIFE (1998) ENTITY
G-Man
*/
enum
{
GMAN_IDLE,
GMAN_IDLETIE,
GMAN_IDLELOOK,
GMAN_IDLE2,
GMAN_OPEN,
GMAN_STAND,
GMAN_WALK,
GMAN_YES,
GMAN_NO,
GMAN_NOBIG,
GMAN_YESBIG,
GMAN_LISTEN,
GMAN_LOOKDOWN,
GMAN_LOOKDOWN2
};
class monster_gman:CBaseMonster
{
void(void) monster_gman;
virtual void(void) Respawn;
virtual int(void) AnimIdle;
virtual int(void) AnimWalk;
virtual int(void) AnimRun;
};
int
monster_gman::AnimIdle(void)
{
return GMAN_IDLE;
}
int
monster_gman::AnimWalk(void)
{
return GMAN_WALK;
}
int
monster_gman::AnimRun(void)
{
return GMAN_WALK;
}
void monster_gman::Respawn(void)
{
/* he can't die, he's the G-Man! */
CBaseMonster::Respawn();
SetFrame(GMAN_IDLE);
takedamage = DAMAGE_NO;
iBleeds = FALSE;
}
void monster_gman::monster_gman(void)
{
netname = "G-Man";
model = "models/gman.mdl";
base_mins = [-16,-16,0];
base_maxs = [16,16,72];
CBaseMonster::CBaseMonster();
}

View File

@ -0,0 +1,181 @@
/*
* 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 monster_headcrab (0 0.8 0.8) (-16 -16 0) (16 16 36)
HALF-LIFE (1998) ENTITY
Headcrab
*/
enum
{
HC_IDLE1,
HC_IDLE2,
HC_IDLE3,
HC_WALK,
HC_RUN,
HC_ANGRY,
HC_FLINCH,
HC_DIE,
HC_180_LEFT,
HC_180_RIGHT,
HC_JUMP,
HC_JUMP_VARIATION1,
HC_JUMP_VARIATION2,
HC_YAW_ADJUSTMENT,
HC_HEADCRABBED1,
HC_HEADCRABBED2,
HC_HEADIDLE,
HC_CRASHIDLE,
HC_CRASH,
HC_STRUGGLEIDLE,
HC_STRUGGLE
};
class monster_headcrab:CBaseMonster
{
float m_flIdleTime;
void(void) monster_headcrab;
virtual void(void) Pain;
virtual void(void) Death;
virtual void(void) IdleNoise;
virtual int(void) AnimIdle;
virtual int(void) AnimWalk;
virtual int(void) AnimRun;
virtual int(void) AttackRanged;
virtual void(void) touch;
};
int
monster_headcrab::AnimIdle(void)
{
return HC_IDLE1;
}
int
monster_headcrab::AnimWalk(void)
{
return HC_WALK;
}
int
monster_headcrab::AnimRun(void)
{
return HC_RUN;
}
int
monster_headcrab::AttackRanged(void)
{
/* visual */
if (random() < 0.5)
AnimPlay(HC_JUMP);
else
AnimPlay(HC_JUMP_VARIATION1);
m_flAttackThink = m_flAnimTime;
Sound_Play(this, CHAN_VOICE, "monster_headcrab.attack");
/* functional */
makevectors(vectoangles(m_eEnemy.origin - origin));
velocity = v_forward * 512 + [0,0,250];
return TRUE;
}
void
monster_headcrab::touch(void)
{
if (other.takedamage == DAMAGE_YES)
if (frame == HC_JUMP || frame == HC_JUMP_VARIATION1)
Damage_Apply(other, this, 500, 0, 0);
}
void
monster_headcrab::Pain(void)
{
CBaseMonster::Pain();
if (m_flAnimTime > time) {
return;
}
if (random() < 0.25f) {
return;
}
Sound_Play(this, CHAN_VOICE, "monster_headcrab.pain");
SetFrame(HC_FLINCH);
m_flAnimTime = time + 0.25f;
}
void
monster_headcrab::Death(void)
{
/* if we're already dead (corpse) don't change animations */
if (style != MONSTER_DEAD) {
SetFrame(HC_DIE);
Sound_Play(this, CHAN_VOICE, "monster_headcrab.die");
}
/* set the functional differences */
CBaseMonster::Death();
}
void
monster_headcrab::IdleNoise(void)
{
/* don't make noise if we're dead (corpse) */
if (style == MONSTER_DEAD) {
return;
}
if (m_flIdleTime > time) {
return;
}
m_flIdleTime = time + random(2,10);
Sound_Play(this, CHAN_VOICE, "monster_headcrab.idle");
}
void
monster_headcrab::monster_headcrab(void)
{
Sound_Precache("monster_headcrab.alert");
Sound_Precache("monster_headcrab.attack");
Sound_Precache("monster_headcrab.attackhit");
Sound_Precache("monster_headcrab.die");
Sound_Precache("monster_headcrab.idle");
Sound_Precache("monster_headcrab.pain");
if (classname == "monster_babycrab") {
netname = "Baby Headcrab";
model = "models/baby_headcrab.mdl";
base_health = Skill_GetValue ("headcrab_health", 10) /4;
} else {
netname = "Headcrab";
model = "models/headcrab.mdl";
base_health = Skill_GetValue("headcrab_health", 10);
}
base_mins = [-16,-16,0];
base_maxs = [16,16,36];
m_iAlliance = MAL_ALIEN;
CBaseMonster::CBaseMonster();
}

View File

@ -0,0 +1,97 @@
/*
* 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 monster_hevsuit_dead (0 0.8 0.8) (-16 -16 0) (16 16 72)
HALF-LIFE (1998) ENTITY
HEV-Suit/Player's corpse
*/
class monster_hevsuit_dead:CBaseMonster
{
int m_iPose;
void(void) monster_hevsuit_dead;
virtual void(void) Hide;
virtual void(void) Respawn;
virtual void(void) Gib;
virtual void(string, string) SpawnKey;
};
void
monster_hevsuit_dead::Gib(void)
{
takedamage = DAMAGE_NO;
FX_GibHuman(this.origin);
Hide();
}
void
monster_hevsuit_dead::Hide(void)
{
SetModel("");
solid = SOLID_NOT;
movetype = MOVETYPE_NONE;
}
void
monster_hevsuit_dead::Respawn(void)
{
v_angle[0] = Math_FixDelta(m_oldAngle[0]);
v_angle[1] = Math_FixDelta(m_oldAngle[1]);
v_angle[2] = Math_FixDelta(m_oldAngle[2]);
SetOrigin(m_oldOrigin);
angles = v_angle;
solid = SOLID_CORPSE;
movetype = MOVETYPE_NONE;
SetModel(m_oldModel);
setsize(this, VEC_HULL_MIN + [0,0,36], VEC_HULL_MAX + [0,0,36]);
takedamage = DAMAGE_YES;
health = 0;
velocity = [0,0,0];
iBleeds = TRUE;
SetFrame(73 + m_iPose);
SendFlags |= NPC_BODY;
}
void
monster_hevsuit_dead::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "pose":
m_iPose = stoi(strValue);
break;
case "body":
SetBody(stoi(strValue) + 1);
break;
case "skin":
SetSkin(stoi(strValue));
break;
default:
CBaseMonster::SpawnKey(strKey, strValue);
}
}
void
monster_hevsuit_dead::monster_hevsuit_dead(void)
{
model = "models/player.mdl";
m_iBody = 2;
CBaseMonster::CBaseMonster();
}

View File

@ -0,0 +1,96 @@
/*
* 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 monster_hgrunt_dead (0 0.8 0.8) (-16 -16 0) (16 16 72)
HALF-LIFE (1998) ENTITY
Human Grunt's corpse
*/
class monster_hgrunt_dead:CBaseMonster
{
int m_iPose;
void(void) monster_hgrunt_dead;
virtual void(void) Hide;
virtual void(void) Respawn;
virtual void(void) Gib;
virtual void(string, string) SpawnKey;
};
void
monster_hgrunt_dead::Gib(void)
{
takedamage = DAMAGE_NO;
FX_GibHuman(this.origin);
Hide();
}
void
monster_hgrunt_dead::Hide(void)
{
SetModel("");
solid = SOLID_NOT;
movetype = MOVETYPE_NONE;
}
void
monster_hgrunt_dead::Respawn(void)
{
v_angle[0] = Math_FixDelta(m_oldAngle[0]);
v_angle[1] = Math_FixDelta(m_oldAngle[1]);
v_angle[2] = Math_FixDelta(m_oldAngle[2]);
SetOrigin(m_oldOrigin);
angles = v_angle;
solid = SOLID_CORPSE;
movetype = MOVETYPE_NONE;
SetModel(m_oldModel);
setsize(this, VEC_HULL_MIN + [0,0,36], VEC_HULL_MAX + [0,0,36]);
takedamage = DAMAGE_YES;
health = 0;
velocity = [0,0,0];
iBleeds = TRUE;
SetFrame(44 + m_iPose);
SendFlags |= NPC_BODY;
}
void
monster_hgrunt_dead::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "pose":
m_iPose = stoi(strValue);
break;
case "body":
m_iBody = stoi(strValue) + 1;
break;
case "skin":
skin = stoi(strValue);
break;
default:
CBaseMonster::SpawnKey(strKey, strValue);
}
}
void
monster_hgrunt_dead::monster_hgrunt_dead(void)
{
model = "models/hgrunt.mdl";
CBaseMonster::CBaseMonster();
}

View File

@ -0,0 +1,202 @@
/*
* 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 monster_houndeye (0 0.8 0.8) (-16 -16 0) (16 16 36)
HALF-LIFE (1998) ENTITY
Houndeye
*/
#define HE_BLAST_RADIUS 384
enum
{
HE_IDLE,
HE_IDLE2,
HE_IDLE3,
HE_RUN,
HE_RUN2,
HE_RUN3,
HE_DIE,
HE_DIE2,
HE_DIE3,
HE_DIE4,
HE_ATTACK,
HE_FLINCH,
HE_FLINCH2,
HE_DIE5,
HE_WALKLIMP,
HE_WALK2,
HE_LEADERLOOK,
HE_SLEEP,
HE_GOTOSLEEP,
HE_WAKE,
HE_IDLEMAD,
HE_IDLEMAD2,
HE_IDLEMAD3,
HE_INSPECT,
HE_EAT,
HE_LEFT,
HE_RIGHT,
HE_JUMPBACK,
HE_WAKEFAST,
HE_WHIMPER,
HE_JUMPWINDOW
};
class monster_houndeye:CBaseMonster
{
float m_flIdleTime;
void(void) monster_houndeye;
virtual void(void) Pain;
virtual void(void) Death;
virtual void(void) IdleNoise;
virtual void(void) Respawn;
virtual int(void) AttackMelee;
virtual void(void) AttackBlast;
};
int
monster_houndeye::AttackMelee(void)
{
AnimPlay(HE_ATTACK);
Sound_Play(this, CHAN_WEAPON, "monster_houndeye.attack");
m_flAttackThink = m_flAnimTime + 0.5f;
think = AttackBlast;
nextthink = m_flAnimTime;
return TRUE;
}
void
monster_houndeye::AttackBlast(void)
{
float new_dmg;
float dist;
float diff;
vector pos;
float dmg = 50; /* TODO: set proper damage */
for (entity e = world; (e = findfloat(e, ::takedamage, DAMAGE_YES));) {
pos[0] = e.absmin[0] + (0.5 * (e.absmax[0] - e.absmin[0]));
pos[1] = e.absmin[1] + (0.5 * (e.absmax[1] - e.absmin[1]));
pos[2] = e.absmin[2] + (0.5 * (e.absmax[2] - e.absmin[2]));
if (e.classname == "monster_houndeye")
continue;
/* don't bother if it's not anywhere near us */
dist = vlen(origin - pos);
if (dist > HE_BLAST_RADIUS) {
continue;
}
/* can we physically hit this thing? */
other = world;
traceline(e.origin, origin, MOVE_OTHERONLY, this);
if (trace_fraction < 1.0f)
dmg *= 0.5f;
/* calculate new damage values */
diff = vlen(origin - pos);
diff = (HE_BLAST_RADIUS - diff) / HE_BLAST_RADIUS;
new_dmg = rint(dmg * diff);
if (diff > 0) {
Damage_Apply(e, this, new_dmg, 0, DMG_EXPLODE);
}
}
Sound_Play(this, CHAN_WEAPON, "monster_houndeye.blast");
}
void
monster_houndeye::Pain(void)
{
CBaseMonster::Pain();
if (m_flAnimTime > time) {
return;
}
if (random() < 0.25f) {
return;
}
Sound_Play(this, CHAN_VOICE, "monster_houndeye.pain");
SetFrame(HE_FLINCH + floor(random(0, 2)));
m_flAnimTime = time + 0.25f;
}
void
monster_houndeye::Death(void)
{
/* if we're already dead (corpse) don't change animations */
if (style != MONSTER_DEAD) {
SetFrame(HE_DIE + floor(random(0, 4)));
Sound_Play(this, CHAN_VOICE, "monster_houndeye.die");
}
/* set the functional differences */
CBaseMonster::Death();
}
void
monster_houndeye::IdleNoise(void)
{
/* don't make noise if we're dead (corpse) */
if (style == MONSTER_DEAD) {
return;
}
if (m_flIdleTime > time) {
return;
}
m_flIdleTime = time + random(2,10);
Sound_Play(this, CHAN_VOICE, "monster_houndeye.idle");
}
void
monster_houndeye::Respawn(void)
{
CBaseMonster::Respawn();
SetFrame(HE_IDLE);
}
void
monster_houndeye::monster_houndeye(void)
{
Sound_Precache("monster_houndeye.alert");
Sound_Precache("monster_houndeye.attack");
Sound_Precache("monster_houndeye.blast");
Sound_Precache("monster_houndeye.die");
Sound_Precache("monster_houndeye.idle");
Sound_Precache("monster_houndeye.pain");
netname = "Houndeye";
model = "models/houndeye.mdl";
base_health = Skill_GetValue("houndeye_health", 20);
base_mins = [-16,-16,0];
base_maxs = [16,16,36];
m_iAlliance = MAL_ALIEN;
CBaseMonster::CBaseMonster();
}

View File

@ -0,0 +1,94 @@
/*
* 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 monster_human_assassin (0 0.8 0.8) (-16 -16 0) (16 16 72)
HALF-LIFE (1998) ENTITY
Black Ops - Assassin
*/
enum
{
HAS_IDLE,
HAS_IDLE3,
HAS_IDLE2,
HAS_RUN,
HAS_WALK,
HAS_SHOOT,
HAS_NADETHROW,
HAS_KICK,
HAS_KICK2,
HAS_DIERUN,
HAS_DIEBACK,
HAS_DIE,
HAS_JUMP,
HAS_UP,
HAS_UNUSED,
HAS_ATTACKDOWN,
HAS_LAND
};
class monster_human_assassin:CBaseMonster
{
float m_flIdleTime;
void(void) monster_human_assassin;
virtual void(void) Death;
virtual void(void) Respawn;
};
void
monster_human_assassin::Death(void)
{
/* if we're already dead (corpse) don't change animations */
if (style != MONSTER_DEAD) {
/* headshots == different animation */
/* this animation may not have been used, but it looks cool */
if (g_dmg_iHitBody == BODY_HEAD) {
if (random() < 0.5) {
SetFrame(HAS_DIERUN);
} else {
SetFrame(HAS_DIEBACK);
}
} else {
SetFrame(HAS_DIE);
}
}
/* set the functional differences */
CBaseMonster::Death();
}
void
monster_human_assassin::Respawn(void)
{
CBaseMonster::Respawn();
frame = HAS_IDLE;
}
void
monster_human_assassin::monster_human_assassin(void)
{
netname = "Assassin";
model = "models/hassassin.mdl";
base_health = Skill_GetValue("hassassin_health", 50);
base_mins = [-16,-16,0];
base_maxs = [16,16,72];
CBaseMonster::CBaseMonster();
}

View File

@ -0,0 +1,319 @@
/*
* 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 monster_human_grunt (0 0.8 0.8) (-16 -16 0) (16 16 72)
HALF-LIFE (1998) ENTITY
HECU - Human Grunt
*/
enum
{
GR_WALK,
GR_RUN,
GR_VICTORYDANCE,
GR_COWER,
GR_FLINCH,
GR_LEFTLEGFLINCH,
GR_RIGHTLEGFLINCH,
GR_RIGHTARMFLINCH,
GR_LEFTARMFLINCH,
GR_LAUNCHNADE,
GR_THROWNADE,
GR_IDLE,
GR_IDLE2,
GR_COMBATIDLE,
GR_FRONTKICK,
GR_CROUCHIDLE,
GR_CROUCHWAIT,
GR_CROUCHSHOOTMP5,
GR_STANDSHOOTMP5,
GR_RELOADMP5,
GR_CROUCHSHOOTSG,
GR_STANDSHOOTSG,
GR_RELOADSG,
GR_SIGNALADV,
GR_SIGNALFLANK,
GR_SIGNALRETREAT,
GR_DROPNADE,
GR_LIMPWALK,
GR_LIMPRUN,
GR_TURNLEFT,
GR_TURNRIGHT,
GR_STRAFELEFT,
GR_STRAFERIGHT,
GR_DIEBACK,
GR_DIEFORWARD,
GR_DIE,
GR_DIEBACK2,
GR_DIEHS,
GR_DIEGUT,
GR_BARNACLE1,
GR_BARNACLE2,
GR_BARNACLE3,
GR_BARNACLE4,
GR_DEADSTOMACH,
GR_DEADSTOMACH2,
GR_DEADSIDE,
GR_DEADSITTING,
GR_REPELJUMP,
GR_REPEL,
GR_REPELSHOOT,
GR_REPELLAND,
GR_REPELDIE,
GR_DRAGHOLEIDLE,
GR_DRAGHOLE,
GR_BUSTWALL,
GR_HOPRAIL,
GR_CONVERSE1,
GR_CONVERSE2,
GR_STARTLELEFT,
GR_STRRTLERIGHT,
GR_DIVE,
GR_DEFUSE,
GR_CORNER1,
GR_CORNER2,
GR_STONETOSS,
GR_CLIFFDIE,
GR_DIVESIDEIDLE,
GR_DIVESIDE,
GR_DIVEKNEELIDLE,
GR_DIVEKNEEL,
GR_WMBUTTON,
GR_WM,
GR_WMJUMP,
GR_BUSTWINDOW,
GR_DRAGLEFT,
GR_DRAGRIGHT,
GR_TRACKWAVE,
GR_TRACKDIVE,
GR_FLYBACK,
GR_IMPALED,
GR_JUMPTRACKS,
GR_THROWPIPE,
GR_PLUNGER
};
class monster_human_grunt:CBaseNPC
{
float m_flIdleTime;
int m_iMP5Burst;
void(void) monster_human_grunt;
virtual void(void) Scream;
virtual void(void) IdleChat;
virtual void(void) Respawn;
virtual void(void) Pain;
virtual void(void) Death;
virtual int(void) AnimIdle;
virtual int(void) AnimWalk;
virtual int(void) AnimRun;
virtual int(void) AttackRanged;
virtual int(void) AttackMelee;
virtual void(void) AttackKick;
};
int
monster_human_grunt::AnimIdle(void)
{
return GR_IDLE;
}
int
monster_human_grunt::AnimWalk(void)
{
return GR_WALK;
}
int
monster_human_grunt::AnimRun(void)
{
return GR_RUN;
}
int
monster_human_grunt::AttackMelee(void)
{
/* visual */
AnimPlay(GR_FRONTKICK);
m_flAttackThink = m_flAnimTime;
Sound_Play(this, CHAN_VOICE, "monster_zombie.attack");
/* functional */
think = AttackKick;
nextthink = 0.25f;
return TRUE;
}
void
monster_human_grunt::AttackKick(void)
{
traceline(origin, m_eEnemy.origin, FALSE, this);
if (trace_fraction >= 1.0 || trace_ent.takedamage != DAMAGE_YES) {
//Sound_Play(this, CHAN_WEAPON, "monster_zombie.attackmiss");
return;
}
Damage_Apply(trace_ent, this, 25, 0, 0);
//Sound_Play(this, CHAN_WEAPON, "monster_zombie.attackhit");
}
int
monster_human_grunt::AttackRanged(void)
{
/* visual */
AnimPlay(GR_STANDSHOOTMP5);
Sound_Play(this, CHAN_WEAPON, "weapon_mp5.shoot");
if (m_iMP5Burst >= 2) {
m_iMP5Burst = 0;
m_flAttackThink = time + 0.4f;
} else {
m_iMP5Burst++;
m_flAttackThink = time + 0.1f;
}
/* functional */
v_angle = vectoangles(m_eEnemy.origin - origin);
TraceAttack_FireBullets(1, origin + [0,0,16], 8, [0.01,0.01], 2);
return TRUE;
}
void monster_human_grunt::Scream(void)
{
if (m_flIdleTime > time) {
return;
}
Sentence(m_talkAllyShot);
m_flIdleTime = time + 5.0f;
}
void monster_human_grunt::IdleChat(void)
{
if (m_flIdleTime > time) {
return;
}
Sentence(m_talkIdle);
/* Sentence(m_talkPlayerIdle); */
/* come up with logic to make them repsone to questions
* Sentence(m_talkAsk);
* Sentence(m_talkAnswer);
*/
m_flIdleTime = time + 5.0f + random(0,20);
}
void
monster_human_grunt::Pain(void)
{
CBaseMonster::Pain();
if (m_flAnimTime > time) {
return;
}
if (random() < 0.25f) {
return;
}
Sound_Play(this, CHAN_VOICE, "monster_human_grunt.pain");
SetFrame(GR_FLINCH);
m_flAnimTime = time + 0.25f;
}
void
monster_human_grunt::Death(void)
{
/* if we're already dead (corpse) don't change animations */
if (style != MONSTER_DEAD) {
/* headshots == different animation */
/* this animation may not have been used, but it looks cool */
if (g_dmg_iHitBody == BODY_HEAD) {
if (random() < 0.5) {
SetFrame(GR_DIEHS);
} else {
SetFrame(GR_DIEBACK);
}
} else {
SetFrame(GR_DIE);
}
}
Sound_Play(this, CHAN_VOICE, "monster_human_grunt.die");
/* set the functional differences */
CBaseMonster::Death();
}
void
monster_human_grunt::Respawn(void)
{
CBaseMonster::Respawn();
SetFrame(GR_IDLE);
}
void monster_human_grunt::monster_human_grunt(void)
{
Sound_Precache("monster_human_grunt.die");
Sound_Precache("monster_human_grunt.pain");
/* Adding some into other slots in hopes it feels right
* listed below are other setences that might need their own:
* !HG_MONST - Monster HG_ALERT
* !HG_GREN - Grenade toss
* !HG_CHECK - Sector check question
* !HG_CLEAR - Sector clear response */
m_talkAnswer = "!HG_ANSWER";
m_talkAsk = "!HG_QUEST";
m_talkAllyShot = "!HG_COVER";
m_talkGreet = "";
m_talkIdle = "!HG_IDLE";
m_talkSmelling = "";
m_talkStare = "";
m_talkSurvived = "!HG_CLEAR";
m_talkWounded = "!HG_CHECK";
m_talkPlayerAsk = "";
m_talkPlayerGreet = "!HG_ALERT";
m_talkPlayerIdle = "!HG_CHARGE";
m_talkPlayerWounded1 = "";
m_talkPlayerWounded2 = "";
m_talkPlayerWounded3 = "";
m_talkUnfollow = "";
m_talkFollow = "";
m_talkStopFollow = "";
netname = "Grunt";
model = "models/hgrunt.mdl";
base_health = Skill_GetValue("hgrunt_health", 50);
base_mins = [-16,-16,0];
base_maxs = [16,16,72];
m_iAlliance = MAL_ENEMY;
CBaseMonster::CBaseMonster();
}

View File

@ -0,0 +1,137 @@
/*
* 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 monster_ichthyosaur (0 0.8 0.8) (-32 -32 0) (32 32 64)
HALF-LIFE (1998) ENTITY
Ichthyosaur
*/
enum
{
ICHY_IDLE,
ICHY_SWIM,
ICHY_THRUST,
ICHY_DIE1,
ICHY_DIE2,
ICHY_FLINCH,
ICHY_FLINCH2,
ICHY_DIE3,
ICHY_BITER,
ICHY_BITEL,
ICHY_ATTACK,
ICHY_RIGHT,
ICHY_LEFT,
ICHY_180,
ICHY_HITCAGE,
ICHY_JUMP
};
class monster_ichthyosaur:CBaseMonster
{
float m_flIdleTime;
void(void) monster_ichthyosaur;
virtual void(void) Pain;
virtual void(void) Death;
virtual void(void) IdleNoise;
virtual void(void) Respawn;
};
void
monster_ichthyosaur::Pain(void)
{
CBaseMonster::Pain();
if (m_flAnimTime > time) {
return;
}
if (random() < 0.25f) {
return;
}
Sound_Play(this, CHAN_VOICE, "monster_ichthyosaur.pain");
SetFrame(ICHY_FLINCH + floor(random(0, 2)));
m_flAnimTime = time + 0.25f;
}
void
monster_ichthyosaur::Death(void)
{
/* if we're already dead (corpse) don't change animations */
if (style != MONSTER_DEAD) {
int r = floor(random(0,3));
switch (r) {
case 1:
SetFrame(ICHY_DIE2);
break;
case 2:
SetFrame(ICHY_DIE3);
break;
default:
SetFrame(ICHY_DIE1);
break;
}
Sound_Play(this, CHAN_VOICE, "monster_ichthyosaur.die");
}
/* set the functional differences */
CBaseMonster::Death();
}
void
monster_ichthyosaur::IdleNoise(void)
{
/* don't make noise if we're dead (corpse) */
if (style == MONSTER_DEAD) {
return;
}
if (m_flIdleTime > time) {
return;
}
m_flIdleTime = time + random(2,10);
Sound_Play(this, CHAN_VOICE, "monster_ichthyosaur.idle");
}
void
monster_ichthyosaur::Respawn(void)
{
CBaseMonster::Respawn();
SetFrame(ICHY_IDLE);
}
void
monster_ichthyosaur::monster_ichthyosaur(void)
{
Sound_Precache("monster_ichthyosaur.alert");
Sound_Precache("monster_ichthyosaur.attack");
Sound_Precache("monster_ichthyosaur.die");
Sound_Precache("monster_ichthyosaur.idle");
Sound_Precache("monster_ichthyosaur.pain");
netname = "Ichthyosaur";
model = "models/icky.mdl";
base_mins = [-32,-32,0];
base_maxs = [32,32,64];
CBaseMonster::CBaseMonster();
}

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 monster_leech (0 0.8 0.8) (-6 -6 0) (6 6 6)
HALF-LIFE (1998) ENTITY
Leech
*/
enum
{
LEECH_SWIM,
LEECH_SWIM2,
LEECH_ATTACK,
LEECH_HOVER,
LEECH_LEFT,
LEECH_RIGHT,
LEECH_DIE,
LEECH_DIEEND
};
class monster_leech:CBaseMonster
{
float m_flIdleTime;
void(void) monster_leech;
virtual void(void) Death;
virtual void(void) DeathEnd;
virtual void(void) Respawn;
};
void
monster_leech::DeathEnd(void)
{
SetFrame(LEECH_DIEEND);
}
void
monster_leech::Death(void)
{
/* if we're already dead (corpse) don't change animations */
if (style != MONSTER_DEAD) {
SetFrame(LEECH_DIE);
think = DeathEnd;
nextthink = time + 1.0f;
}
/* set the functional differences */
CBaseMonster::Death();
}
void
monster_leech::Respawn(void)
{
CBaseMonster::Respawn();
SetFrame(LEECH_SWIM);
}
void monster_leech::monster_leech(void)
{
Sound_Precache("monster_leech.alert");
Sound_Precache("monster_leech.attack");
netname = "Leech";
model = "models/leech.mdl";
base_mins = [-6,-6,0];
base_maxs = [6,6,6];
CBaseMonster::CBaseMonster();
}

View File

@ -0,0 +1,47 @@
/*
* 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 monster_miniturret (0 0.8 0.8) (-16 -16 -32) (16 16 32)
HALF-LIFE (1998) ENTITY
Automatic Turret (small)
*/
enum
{
TUR_IDLE,
TUR_FIRE,
TUR_SPIN,
TUR_DEPLOY,
TUR_RETIRE,
TUR_DIE
};
class monster_miniturret:CBaseMonster
{
void(void) monster_miniturret;
};
void monster_miniturret::monster_miniturret(void)
{
netname = "Mini-Turret";
model = "models/miniturret.mdl";
base_mins = [-16,-16,-32];
base_maxs = [16,16,32];
CBaseMonster::CBaseMonster();
}

View File

@ -0,0 +1,134 @@
/*
* 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 monster_nihilanth (0 0.8 0.8) (-192 -192 0) (192 192 384)
HALF-LIFE (1998) ENTITY
Nihilanth
*/
enum
{
NIL_IDLE,
NIL_ATTACK,
NIL_ATTACK2,
NIL_THROW,
NIL_BLOCK,
NIL_RECHARGE,
NIL_IDLEOPEN,
NIL_ATTACKOPEN,
NIL_ATTACKOPEN2,
NIL_FLINCH,
NIL_FLINCH2,
NIL_FALL,
NIL_DIE,
NIL_FORWARD,
NIL_BACK,
NIL_UP,
NIL_DOWN,
NIL_RIGHT,
NIL_LEFT,
NIL_WALK2,
NIL_SHOOT
};
class monster_nihilanth:CBaseMonster
{
float m_flIdleTime;
void(void) monster_nihilanth;
virtual void(void) Death;
virtual void(void) Pain;
virtual void(void) IdleNoise;
virtual void(void) Respawn;
};
void
monster_nihilanth::IdleNoise(void)
{
/* don't make noise if we're dead (corpse) */
if (style == MONSTER_DEAD) {
return;
}
if (m_flIdleTime > time) {
return;
}
/* timing needs to adjusted as sounds conflict */
m_flIdleTime = time + random(2,10);
Sound_Play(this, CHAN_VOICE, "monster_nihilanth.idle");
}
void
monster_nihilanth::Pain(void)
{
CBaseMonster::Pain();
if (m_flAnimTime > time) {
return;
}
if (random() < 0.25f) {
return;
}
Sound_Play(this, CHAN_VOICE, "monster_nihilanth.pain");
SetFrame((random() < 0.5) ? NIL_FLINCH : NIL_FLINCH2);
m_flAnimTime = time + 0.25f;
}
void
monster_nihilanth::Death(void)
{
/* if we're already dead (corpse) don't change animations */
if (style != MONSTER_DEAD) {
SetFrame(NIL_DIE);
Sound_Play(this, CHAN_VOICE, "monster_nihilanth.die");
}
/* set the functional differences */
CBaseMonster::Death();
}
void
monster_nihilanth::Respawn(void)
{
CBaseMonster::Respawn();
SetFrame(NIL_IDLE);
}
void monster_nihilanth::monster_nihilanth(void)
{
Sound_Precache("monster_nihilanth.attack");
Sound_Precache("monster_nihilanth.attackball");
Sound_Precache("monster_nihilanth.attackballmove");
Sound_Precache("monster_nihilanth.die");
Sound_Precache("monster_nihilanth.idle");
Sound_Precache("monster_nihilanth.pain");
Sound_Precache("monster_nihilanth.recharge");
netname = "Nihilanth";
model = "models/nihilanth.mdl";
base_health = Skill_GetValue("nihilanth_health", 800);
base_mins = [-192,-192,-32];
base_maxs = [192,192,384];
CBaseMonster::CBaseMonster();
}

View File

@ -0,0 +1,45 @@
/*
* 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 monster_osprey (0 0.8 0.8) (-480 -480 -112) (480 480 24)
HALF-LIFE (1998) ENTITY
Bell Boeing VV-22 Osprey
*/
class monster_osprey:CBaseMonster
{
void(void) monster_osprey;
virtual void(void) Respawn;
};
void monster_osprey::Respawn(void)
{
CBaseMonster::Respawn();
takedamage = DAMAGE_NO;
iBleeds = FALSE;
}
void monster_osprey::monster_osprey(void)
{
netname = "Osprey";
model = "models/osprey.mdl";
base_mins = [-480,-480,-112];
base_maxs = [480,480,24];
CBaseMonster::CBaseMonster();
}

37
src/server/monster_rat.qc Normal file
View File

@ -0,0 +1,37 @@
/*
* 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 monster_rat (0 0.8 0.8) (-6 -6 0) (6 6 6)
HALF-LIFE (1998) ENTITY
Rat
*/
class monster_rat:CBaseMonster
{
void(void) monster_rat;
};
void monster_rat::monster_rat(void)
{
netname = "Rat";
model = "models/bigrat.mdl";
base_mins = [-6,-6,-0];
base_maxs = [6,6,6];
CBaseMonster::CBaseMonster();
}

View File

@ -0,0 +1,236 @@
/*
* 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 monster_scientist (0 0.8 0.8) (-16 -16 0) (16 16 72)
HALF-LIFE (1998) ENTITY
Scientist
*/
enum
{
SCIA_WALK,
SCIA_WALKSCARED,
SCIA_RUN,
SCIA_RUNSCARED,
SCIA_RUNLOOK,
SCIA_180LEFT,
SCIA_180RIGHT,
SCIA_FLINCH,
SCIA_PAIN,
SCIA_PAINLEFT,
SCIA_PAINRIGHT,
SCIA_PAINLEGLEFT,
SCIA_PAINLEGRIGHT,
SCIA_IDLE1,
SCIA_IDLE2,
SCIA_IDLE3,
SCIA_IDLE4,
SCIA_IDLE5,
SCIA_IDLE6,
SCIA_SCARED_END,
SCIA_SCARED1,
SCIA_SCARED2,
SCIA_SCARED3,
SCIA_SCARED4,
SCIA_PANIC,
SCIA_FEAR1,
SCIA_FEAR2,
SCIA_CRY,
SCIA_SCI1,
SCIA_SCI2,
SCIA_SCI3,
SCIA_DIE_SIMPLE,
SCIA_DIE_FORWARD1,
SCIA_DIE_FORWARD2,
SCIA_DIE_BACKWARD,
SCIA_DIE_HEADSHOT,
SCIA_DIE_GUTSHOT,
SCIA_LYING1,
SCIA_LYING2,
SCIA_DEADSIT,
SCIA_DEADTABLE1,
SCIA_DEADTABLE2,
SCIA_DEADTABLE3
};
class monster_scientist:CBaseNPC
{
void(void) monster_scientist;
virtual void(void) Respawn;
virtual void(void) OnPlayerUse;
virtual void(void) Pain;
virtual void(void) Death;
virtual int(void) AnimIdle;
virtual int(void) AnimWalk;
virtual int(void) AnimRun;
virtual void(string, string) SpawnKey;
};
int
monster_scientist::AnimIdle(void)
{
return SCIA_IDLE1;
}
int
monster_scientist::AnimWalk(void)
{
return SCIA_WALK;
}
int
monster_scientist::AnimRun(void)
{
return SCIA_RUN;
}
void
monster_scientist::OnPlayerUse(void)
{
if (spawnflags & MSF_PREDISASTER) {
Sentence("!SC_POK");
return;
}
CBaseNPC::OnPlayerUse();
}
void
monster_scientist::Pain(void)
{
WarnAllies();
if (m_flAnimTime > time) {
return;
}
if (random() < 0.25f) {
return;
}
Sound_Speak(this, "monster_scientist.pain");
frame = SCIA_FLINCH + floor(random(0, 6));
m_iFlags |= MONSTER_FEAR;
m_flAnimTime = time + 0.25f;
}
void
monster_scientist::Death(void)
{
WarnAllies();
if (style != MONSTER_DEAD) {
SetFrame(SCIA_DIE_SIMPLE + floor(random(0, 6)));
Sound_Speak(this, "monster_scientist.die");
}
/* now mark our state as 'dead' */
CBaseNPC::Death();
}
void
monster_scientist::Respawn(void)
{
CBaseNPC::Respawn();
m_iFlags |= MONSTER_CANFOLLOW;
PlayerUse = OnPlayerUse;
}
void
monster_scientist::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "body":
SetBody(stoi(strValue) + 1);
break;
default:
CBaseEntity::SpawnKey(strKey, strValue);
}
}
void
monster_scientist::monster_scientist(void)
{
Sound_Precache("monster_scientist.die");
Sound_Precache("monster_scientist.pain");
if (spawnflags & MSF_PREDISASTER) {
m_talkAsk = "";
m_talkPlayerAsk = "!SC_PQUEST";
m_talkPlayerGreet = "!SC_PHELLO";
m_talkPlayerIdle = "!SC_PIDLE";
} else {
m_talkAsk = "!SC_QUESTION";
m_talkPlayerAsk = "!SC_QUESTION";
m_talkPlayerGreet = "!SC_HELLO";
m_talkPlayerIdle = "!SC_PIDLE";
}
m_talkAnswer = "!SC_ANSWER";
m_talkAllyShot = "!SC_PLFEAR";
m_talkGreet = "";
m_talkIdle = "!SC_IDLE";
m_talkHearing = "!SC_HEAR";
m_talkSmelling = "!SC_SMELL";
m_talkStare = "!SC_STARE";
m_talkSurvived = "!SC_WOUND";
m_talkWounded = "!SC_MORTAL";
/* they seem to use predisaster lines regardless of disaster state */
m_talkPlayerWounded1 = "!SC_CUREA";
m_talkPlayerWounded2 = "!SC_CUREB";
m_talkPlayerWounded3 = "!SC_CUREC";
m_talkUnfollow = "!SC_WAIT";
m_talkFollow = "!SC_OK";
m_talkStopFollow = "!SC_STOP";
m_iBody = -1;
model = "models/scientist.mdl";
base_mins = [-16,-16,0];
base_maxs = [16,16,72];
base_health = Skill_GetValue("scientist_health", 20);
CBaseNPC::CBaseNPC();
/* has the body not been overriden, etc. choose a character for us */
if (m_iBody == -1) {
SetBody((int)floor(random(1,5)));
}
switch (m_iBody) {
case 1:
m_flPitch = 105;
netname = "Walter";
break;
case 2:
m_flPitch = 100;
netname = "Einstein";
break;
case 3:
m_flPitch = 95;
netname = "Luther";
SetSkin(1);
break;
default:
m_flPitch = 100;
netname = "Slick";
}
}

View File

@ -0,0 +1,131 @@
/*
* 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 monster_scientist_dead (0 0.8 0.8) (-16 -16 0) (16 16 72)
HALF-LIFE (1998) ENTITY
Scientists' corpse
*/
enum
{
DSCIA_LYING1 = 37,
DSCIA_LYING2,
DSCIA_DEADSIT,
DSCIA_DEADTABLE1,
DSCIA_DEADTABLE2,
DSCIA_DEADTABLE3,
DSCIA_DEADHANG
};
class monster_scientist_dead:CBaseMonster
{
int m_iPose;
void(void) monster_scientist_dead;
virtual void(void) Hide;
virtual void(void) Respawn;
virtual void(void) Gib;
virtual void(string, string) SpawnKey;
};
void
monster_scientist_dead::Gib(void)
{
takedamage = DAMAGE_NO;
FX_GibHuman(this.origin);
Hide();
}
void
monster_scientist_dead::Hide(void)
{
SetModel("");
solid = SOLID_NOT;
movetype = MOVETYPE_NONE;
}
void
monster_scientist_dead::Respawn(void)
{
v_angle[0] = Math_FixDelta(m_oldAngle[0]);
v_angle[1] = Math_FixDelta(m_oldAngle[1]);
v_angle[2] = Math_FixDelta(m_oldAngle[2]);
SetOrigin(m_oldOrigin);
angles = v_angle;
solid = SOLID_CORPSE;
movetype = MOVETYPE_NONE;
SetModel(m_oldModel);
setsize(this, VEC_HULL_MIN + [0,0,36], VEC_HULL_MAX + [0,0,36]);
takedamage = DAMAGE_YES;
health = 0;
velocity = [0,0,0];
iBleeds = TRUE;
SendFlags |= NPC_BODY;
switch (m_iPose) {
case 1:
SetFrame(DSCIA_LYING2);
break;
case 2:
SetFrame(DSCIA_DEADSIT);
break;
case 3:
SetFrame(DSCIA_DEADHANG);
break;
case 4:
SetFrame(DSCIA_DEADTABLE1);
break;
case 5:
SetFrame(DSCIA_DEADTABLE2);
break;
case 6:
SetFrame(DSCIA_DEADTABLE3);
break;
default:
SetFrame(DSCIA_LYING1);
}
droptofloor();
}
void
monster_scientist_dead::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "pose":
m_iPose = stoi(strValue);
break;
case "body":
SetBody(stoi(strValue) + 1);
break;
case "skin":
SetSkin(stoi(strValue));
break;
default:
CBaseMonster::SpawnKey(strKey, strValue);
}
}
void
monster_scientist_dead::monster_scientist_dead(void)
{
model = "models/scientist.mdl";
CBaseMonster::CBaseMonster();
}

View File

@ -0,0 +1,78 @@
/*
* 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 monster_sentry (0 0.8 0.8) (-16 -16 0) (16 16 72)
HALF-LIFE (1998) ENTITY
Sentry Gun
*/
enum
{
SENT_IDLE,
SENT_FIRE,
SENT_SPIN,
SENT_DEPLOY,
SENT_RETIRE,
SENT_DIE
};
class monster_sentry:CBaseMonster
{
void(void) monster_sentry;
virtual void(void) Death;
virtual void(void) Respawn;
};
void
monster_sentry::Death(void)
{
/* if we're already dead (corpse) don't change animations */
if (style != MONSTER_DEAD) {
SetFrame(SENT_DIE);
Sound_Play(this, CHAN_VOICE, "monster_sentry.die");
}
/* set the functional differences */
CBaseMonster::Death();
}
void
monster_sentry::Respawn(void)
{
CBaseMonster::Respawn();
SetFrame(SENT_IDLE);
iBleeds = FALSE;
}
void monster_sentry::monster_sentry(void)
{
Sound_Precache("monster_sentry.alert");
Sound_Precache("monster_sentry.die");
Sound_Precache("monster_sentry.idle");
Sound_Precache("monster_sentry.retract");
netname = "Sentry";
model = "models/sentry.mdl";
base_health = Skill_GetValue("sentry_health", 40);
base_mins = [-16,-16,0];
base_maxs = [16,16,72];
CBaseMonster::CBaseMonster();
}

View File

@ -0,0 +1,142 @@
/*
* 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 monster_sitting_scientist (0 0.8 0.8) (-14 -14 0) (14 14 36)
HALF-LIFE (1998) ENTITY
Sitting scientists
*/
enum
{
DSCIA_LYING1 = 37,
DSCIA_LYING2,
DSCIA_DEADSIT,
DSCIA_DEADTABLE1,
DSCIA_DEADTABLE2,
DSCIA_DEADTABLE3,
DSCIA_DEADHANG
};
class monster_sitting_scientist:CBaseMonster
{
int m_iPose;
void(void) monster_sitting_scientist;
virtual void(void) Hide;
virtual void(void) Respawn;
virtual void(void) Death;
virtual void(void) Gib;
virtual void(string, string) SpawnKey;
};
void
monster_sitting_scientist::Gib(void)
{
takedamage = DAMAGE_NO;
FX_GibHuman(this.origin);
Hide();
}
void
monster_sitting_scientist::Death(void)
{
if (health < -50) {
Gib();
return;
}
}
void
monster_sitting_scientist::Hide(void)
{
SetModel("");
solid = SOLID_NOT;
movetype = MOVETYPE_NONE;
}
void
monster_sitting_scientist::Respawn(void)
{
v_angle[0] = Math_FixDelta(m_oldAngle[0]);
v_angle[1] = Math_FixDelta(m_oldAngle[1]);
v_angle[2] = Math_FixDelta(m_oldAngle[2]);
SetOrigin(m_oldOrigin);
angles = v_angle;
solid = SOLID_BBOX;
movetype = MOVETYPE_NONE;
SetModel(m_oldModel);
setsize(this, [-14,-14,0],[14,14,36]);
takedamage = DAMAGE_YES;
health = 0;
velocity = [0,0,0];
iBleeds = TRUE;
SendFlags |= NPC_BODY;
frame = 74;
droptofloor();
}
void
monster_sitting_scientist::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "pose":
m_iPose = stoi(strValue);
break;
case "body":
SetBody(stoi(strValue) + 1);
break;
case "skin":
SetSkin(stoi(strValue));
break;
default:
CBaseMonster::SpawnKey(strKey, strValue);
}
}
void
monster_sitting_scientist::monster_sitting_scientist(void)
{
model = "models/scientist.mdl";
CBaseMonster::CBaseMonster();
/* has the body not been overriden, etc. choose a character for us */
if (m_iBody == -1) {
SetBody((int)floor(random(1,5)));
}
switch (m_iBody) {
case 1:
m_flPitch = 105;
netname = "Walter";
break;
case 2:
m_flPitch = 100;
netname = "Einstein";
break;
case 3:
m_flPitch = 95;
netname = "Luther";
SetSkin(1);
break;
default:
m_flPitch = 100;
netname = "Slick";
}
}

View File

@ -0,0 +1,132 @@
/*
* 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 monster_tentacle (0 0.8 0.8) (-32 -32 0) (32 32 64)
HALF-LIFE (1998) ENTITY
Tentacle
*/
enum
{
TE_IDLEPIT,
TE_RISE,
TE_TOFLOOR1,
TE_IDLE,
TE_PISSED,
TE_SMALLRISE,
TE_WAVE,
TE_STRIKE,
TE_TAP,
TE_ROTATE,
TE_REAR,
TE_REARIDLE,
TE_TOLEV1,
TE_IDELLEV1,
TE_FIDGETLEV1,
TE_SNAPLEV1,
TE_STRIKELEV1,
TE_TAPLEV1,
TE_ROTATELEV1,
TE_REARLEV1,
TE_REARIDELLEV1,
TE_TOLEV2,
TE_IDLELEV2,
TE_FIDGETLEV2,
TE_SNAPLEV2,
TE_SWINGLEV2,
TE_TUTLEV2,
TE_STRIKELEV2,
TE_TAPLEV2,
TE_ROTATELEV2,
TE_REARLEV2,
TE_FREAKDIE,
TE_REARIDLE2,
TE_TOLEV3,
TE_IDLELEV3,
TE_FIDGETLEV3,
TE_SIDELEV3,
TE_SWIPELEV3,
TE_STRIKELEV3,
TE_TAPLEV3,
TE_ROTATELEV3,
TE_REARLEV3,
TE_REARIDLELEV3,
TE_DOORLEV1,
TE_ENGINELEV3,
TE_ENGINEIDLE,
TE_ENGINESWAY,
TE_ENGINESWAT,
TE_ENGINEBOB,
TE_ENGINEDEATH,
TE_ENGINEDEATH2,
TE_ENGINEDEATH3,
TE_GRABIDLE,
TE_GRAB
};
class monster_tentacle:CBaseMonster
{
float m_flIdleTime;
void(void) monster_tentacle;
virtual void(void) IdleNoise;
virtual void(void) Respawn;
};
void
monster_tentacle::IdleNoise(void)
{
/* don't make noise if we're dead (corpse) */
if (style == MONSTER_DEAD) {
return;
}
if (m_flIdleTime > time) {
return;
}
/* timing needs to adjusted as sounds conflict */
m_flIdleTime = time + random(2,10);
Sound_Play(this, CHAN_VOICE, "monster_tentacle.idle");
}
void
monster_tentacle::Respawn(void)
{
CBaseMonster::Respawn();
/* not entirely true, takes damage then retreats and reheals */
takedamage = DAMAGE_NO;
iBleeds = FALSE;
SetFrame(TE_IDLE);
}
void
monster_tentacle::monster_tentacle(void)
{
Sound_Precache("monster_tentacle.alert");
Sound_Precache("monster_tentacle.attack");
Sound_Precache("monster_tentacle.die");
Sound_Precache("monster_tentacle.idle");
netname = "Tentacle";
model = "models/tentacle2.mdl";
base_mins = [-32,-32,0];
base_maxs = [32,32,64];
CBaseMonster::CBaseMonster();
}

View File

@ -0,0 +1,47 @@
/*
* 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 monster_turret (0 0.8 0.8) (-16 -16 0) (16 16 72)
HALF-LIFE (1998) ENTITY
Automatic Turret (large)
*/
enum
{
TUR_IDLE,
TUR_FIRE,
TUR_SPIN,
TUR_DEPLOY,
TUR_RETIRE,
TUR_DIE
};
class monster_turret:CBaseMonster
{
void(void) monster_turret;
};
void monster_turret::monster_turret(void)
{
netname = "Turret";
model = "models/turret.mdl";
base_mins = [-16,-16,0];
base_maxs = [16,16,72];
CBaseMonster::CBaseMonster();
}

View File

@ -0,0 +1,222 @@
/*
* 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 monster_zombie (0 0.8 0.8) (-16 -16 0) (16 16 72)
HALF-LIFE (1998) ENTITY
Zombie
*/
enum
{
ZO_IDLE,
ZO_TURNLEFT,
ZO_TURNRIGHT,
ZO_FLINCHSM,
ZO_FLINCH,
ZO_FLINCHBIG,
ZO_RISE,
ZO_FALLING,
ZO_ATTACK1,
ZO_ATTACK2,
ZO_WALK,
ZO_FLINCHLA,
ZO_FLINCHRA,
ZO_FLINCHLEFT,
ZO_FLINCHRIGHT,
ZO_DIEHS,
ZO_DIEHS2,
ZO_DIE,
ZO_DIE2,
ZO_DIE3,
ZO_PAUSE,
ZO_WALLBUST,
ZO_WALLKICK,
ZO_WINDOWBUST,
ZO_SODA,
ZO_SLIDEIDLE,
ZO_SLIDE,
ZO_VENTIDLE,
ZO_VENT,
ZO_DEADIDLE,
ZO_DEAD,
ZO_FREAKDIE,
ZO_FREAK,
ZO_EATTABLE,
ZO_EAT,
ZO_EATSTAND,
ZO_DOORIP,
ZO_PULLSCI,
ZO_EAT2,
ZO_EAT2STAND,
ZO_VENT2IDLE,
ZO_VENT2,
ZO_HAUL,
ZO_RISESNACK
};
class monster_zombie:CBaseMonster
{
float m_flIdleTime;
void(void) monster_zombie;
virtual void(void) Pain;
virtual void(void) Death;
virtual void(void) IdleNoise;
virtual void(void) Respawn;
virtual int(void) AnimIdle;
virtual int(void) AnimWalk;
virtual int(void) AnimRun;
virtual int(void) AttackMelee;
virtual void(void) AttackFlail;
};
int
monster_zombie::AnimIdle(void)
{
return ZO_IDLE;
}
int
monster_zombie::AnimWalk(void)
{
return ZO_WALK;
}
int
monster_zombie::AnimRun(void)
{
return ZO_WALK;
}
int
monster_zombie::AttackMelee(void)
{
/* visual */
if (random() < 0.5)
AnimPlay(ZO_ATTACK1);
else
AnimPlay(ZO_ATTACK2);
m_flAttackThink = m_flAnimTime;
Sound_Play(this, CHAN_VOICE, "monster_zombie.attack");
/* functional */
think = AttackFlail;
nextthink = 0.25f;
return TRUE;
}
void
monster_zombie::AttackFlail(void)
{
traceline(origin, m_eEnemy.origin, FALSE, this);
if (trace_fraction >= 1.0 || trace_ent.takedamage != DAMAGE_YES) {
Sound_Play(this, CHAN_WEAPON, "monster_zombie.attackmiss");
return;
}
Damage_Apply(trace_ent, this, 25, 0, 0);
Sound_Play(this, CHAN_WEAPON, "monster_zombie.attackhit");
}
void
monster_zombie::Pain(void)
{
CBaseMonster::Pain();
if (m_flAnimTime > time) {
return;
}
if (random() < 0.25f) {
return;
}
Sound_Play(this, CHAN_VOICE, "monster_zombie.pain");
SetFrame(ZO_FLINCH + floor(random(0, 2)));
m_flAnimTime = time + 0.25f;
}
void
monster_zombie::Death(void)
{
/* if we're already dead (corpse) don't change animations */
if (style != MONSTER_DEAD) {
/* headshots == different animation */
if (g_dmg_iHitBody == BODY_HEAD) {
if (random() < 0.5) {
SetFrame(ZO_DIEHS);
} else {
SetFrame(ZO_DIEHS2);
}
} else {
SetFrame(ZO_DIE + floor(random(0, 3)));
}
Sound_Play(this, CHAN_VOICE, "monster_zombie.pain");
}
/* set the functional differences */
CBaseMonster::Death();
}
void
monster_zombie::IdleNoise(void)
{
/* don't make noise if we're dead (corpse) */
if (style == MONSTER_DEAD) {
return;
}
if (m_flIdleTime > time) {
return;
}
m_flIdleTime = time + random(2,10);
Sound_Play(this, CHAN_VOICE, "monster_zombie.idle");
}
void
monster_zombie::Respawn(void)
{
CBaseMonster::Respawn();
SetFrame(ZO_IDLE);
}
void
monster_zombie::monster_zombie(void)
{
Sound_Precache("monster_zombie.alert");
Sound_Precache("monster_zombie.attack");
Sound_Precache("monster_zombie.attackhit");
Sound_Precache("monster_zombie.attackmiss");
Sound_Precache("monster_zombie.idle");
Sound_Precache("monster_zombie.pain");
netname = "Zombie";
model = "models/zombie.mdl";
base_health = Skill_GetValue("zombie_health", 50);
base_mins = [-16,-16,0];
base_maxs = [16,16,72];
m_iAlliance = MAL_ALIEN;
CBaseMonster::CBaseMonster();
}

96
src/server/player.qc Normal file
View File

@ -0,0 +1,96 @@
/*
* 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.
*/
/*
====================
UseWorkaround
====================
*/
void UseWorkaround(entity eTarget)
{
eActivator = self;
entity eOldSelf = self;
self = eTarget;
self.PlayerUse();
self = eOldSelf;
}
/*
====================
Player_UseDown
====================
*/
void Player_UseDown(void)
{
vector vecSrc;
if (self.health <= 0) {
return;
} else if (!(self.flags & FL_USE_RELEASED)) {
return;
}
makevectors(self.v_angle);
vecSrc = self.origin + self.view_ofs;
self.hitcontentsmaski = CONTENTBITS_POINTSOLID;
traceline(vecSrc, vecSrc + (v_forward * 64), MOVE_HITMODEL, self);
if (trace_ent.PlayerUse) {
self.flags &= ~FL_USE_RELEASED;
UseWorkaround(trace_ent);
/* Some entities want to support Use spamming */
if (!(self.flags & FL_USE_RELEASED)) {
sound(self, CHAN_ITEM, "common/wpn_select.wav", 0.25, ATTN_IDLE);
}
} else {
sound(self, CHAN_ITEM, "common/wpn_denyselect.wav", 0.25, ATTN_IDLE);
self.flags &= ~FL_USE_RELEASED;
}
}
/*
====================
Player_UseUp
====================
*/
void Player_UseUp(void) {
if (!(self.flags & FL_USE_RELEASED)) {
self.flags |= FL_USE_RELEASED;
}
}
void Weapons_Draw(void);
void CSEv_PlayerSwitchWeapon_i(int w)
{
player pl = (player)self;
pl.activeweapon = w;
Weapons_Draw();
}
void
Player_Precache(void)
{
searchhandle pm;
pm = search_begin("models/player/*/*.mdl", TRUE, TRUE);
for (int i = 0; i < search_getsize(pm); i++) {
precache_model(search_getfilename(pm, i));
}
search_end(pm);
}

89
src/server/progs.src Executable file
View File

@ -0,0 +1,89 @@
#pragma target fte
#pragma progs_dat "../../progs.dat"
#define QWSSQC
#define SERVER
#define VALVE
#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
monster_apache.qc
monster_alien_controller.qc
monster_alien_grunt.qc
monster_alien_slave.qc
monster_barnacle.qc
monster_barney.qc
monster_barney_dead.qc
monster_bigmomma.qc
monster_bloater.qc
monster_bullchicken.qc
monster_cockroach.qc
monster_flyer_flock.qc
monster_gargantua.qc
monster_gman.qc
monster_headcrab.qc
monster_babycrab.qc
monster_hevsuit_dead.qc
monster_houndeye.qc
monster_human_grunt.qc
monster_hgrunt_dead.qc
monster_human_assassin.qc
monster_ichthyosaur.qc
monster_leech.qc
monster_miniturret.qc
monster_nihilanth.qc
monster_osprey.qc
monster_rat.qc
monster_scientist_dead.qc
monster_sitting_scientist.qc
monster_scientist.qc
monster_sentry.qc
monster_tentacle.qc
monster_turret.qc
monster_zombie.qc
player.qc
spectator.qc
items.qc
item_longjump.qc
item_suit.qc
item_healthkit.qc
item_battery.qc
item_weaponbox.qc
world_items.qc
xen_spore_small.qc
xen_spore_medium.qc
xen_spore_large.qc
xen_hair.qc
xen_plantlight.qc
ammo.qc
../../../src/botlib/include.src
gamerules.qc
gamerules_singleplayer.qc
gamerules_multiplayer.qc
client.qc
server.qc
damage.qc
rules.qc
flashlight.qc
../../../base/src/server/modelevent.qc
input.qc
spawn.qc
../../../src/server/include.src
../../../src/shared/include.src
#endlist

20
src/server/rules.qc Normal file
View File

@ -0,0 +1,20 @@
/*
* 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 Rules_IsTeamPlay(void)
{
return cvar("teamplay");
}

40
src/server/server.qc Normal file
View File

@ -0,0 +1,40 @@
/*
* 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)
{
if (cvar("sv_playerslots") == 1 || cvar("coop") == 1) {
g_grMode = spawn(HLSingleplayerRules);
} else {
g_grMode = spawn(HLMultiplayerRules);
}
}
void
Game_Worldspawn(void)
{
Sound_Precache("ammo.pickup");
Sound_Precache("ammo.respawn");
Sound_Precache("player.die");
Sound_Precache("player.fall");
Sound_Precache("player.lightfall");
precache_model("models/player.mdl");
precache_model("models/w_weaponbox.mdl");
Weapons_Init();
Player_Precache();
}

41
src/server/spawn.qc Normal file
View File

@ -0,0 +1,41 @@
/*
* 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 info_player_start(void)
{
self.solid = SOLID_TRIGGER;
setsize(self, VEC_HULL_MIN, VEC_HULL_MAX);
self.botinfo = BOTINFO_SPAWNPOINT;
}
void info_player_deathmatch(void)
{
self.solid = SOLID_TRIGGER;
setsize(self, VEC_HULL_MIN, VEC_HULL_MAX);
self.botinfo = BOTINFO_SPAWNPOINT;
}
void info_player_team1(void)
{
self.classname = "info_player_deathmatch";
self.botinfo = BOTINFO_SPAWNPOINT;
}
void info_player_team2(void)
{
self.classname = "info_player_deathmatch";
self.botinfo = BOTINFO_SPAWNPOINT;
}

28
src/server/spectator.qc Normal file
View File

@ -0,0 +1,28 @@
/*
* 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_SpectatorThink(void)
{
}
void Game_SpectatorConnect(void)
{
}
void Game_SpectatorDisconnect(void)
{
}

43
src/server/world_items.qc Normal file
View File

@ -0,0 +1,43 @@
/*
* 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.
*/
/* This is one of those leftovers from trying to get a game out in time */
class world_items:CBaseTrigger
{
void(void) world_items;
};
void world_items::world_items(void)
{
int nfields = tokenize(__fullspawndata);
for (int i = 1; i < (nfields - 1); i += 2) {
switch (argv(i)) {
case "type":
float type = stof(argv(i+1));
switch (type) {
case 44:
spawnfunc_item_battery();
break;
case 45:
spawnfunc_item_suit();
break;
default:
}
default:
break;
}
}
}

37
src/server/xen_hair.qc Normal file
View File

@ -0,0 +1,37 @@
/*
* 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 xen_hair (0 0.8 0.8) (-16 -16 0) (16 16 72)
HALF-LIFE (1998) ENTITY
Xen Hair
*/
class xen_hair:CBaseEntity
{
void(void) xen_hair;
};
void xen_hair::xen_hair(void)
{
CBaseEntity::CBaseEntity();
precache_model("models/hair.mdl");
solid = SOLID_SLIDEBOX;
movetype = MOVETYPE_WALK;
SetModel("models/hair.mdl");
SetOrigin(origin);
}

View File

@ -0,0 +1,37 @@
/*
* 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 xen_plantlight (0 0.8 0.8) (-16 -16 0) (16 16 72)
HALF-LIFE (1998) ENTITY
Xen Plant Light
*/
class xen_plantlight:CBaseEntity
{
void(void) xen_plantlight;
};
void xen_plantlight::xen_plantlight(void)
{
CBaseEntity::CBaseEntity();
precache_model("models/light.mdl");
solid = SOLID_SLIDEBOX;
movetype = MOVETYPE_WALK;
SetModel("models/light.mdl");
SetOrigin(origin);
}

View File

@ -0,0 +1,37 @@
/*
* 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 xen_spore_large (0 0.8 0.8) (-16 -16 0) (16 16 72)
HALF-LIFE (1998) ENTITY
Large Xen Spore
*/
class xen_spore_large:CBaseEntity
{
void(void) xen_spore_large;
};
void xen_spore_large::xen_spore_large(void)
{
CBaseEntity::CBaseEntity();
precache_model("models/fungus(large).mdl");
solid = SOLID_SLIDEBOX;
movetype = MOVETYPE_WALK;
SetModel("models/fungus(large).mdl");
SetOrigin(origin);
}

View File

@ -0,0 +1,37 @@
/*
* 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 xen_spore_medium (0 0.8 0.8) (-16 -16 0) (16 16 72)
HALF-LIFE (1998) ENTITY
Medium Xen Spore
*/
class xen_spore_medium:CBaseEntity
{
void(void) xen_spore_medium;
};
void xen_spore_medium::xen_spore_medium(void)
{
CBaseEntity::CBaseEntity();
precache_model("models/fungus.mdl");
solid = SOLID_SLIDEBOX;
movetype = MOVETYPE_WALK;
SetModel("models/fungus.mdl");
SetOrigin(origin);
}

View File

@ -0,0 +1,37 @@
/*
* 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 xen_spore_small (0 0.8 0.8) (-16 -16 0) (16 16 72)
HALF-LIFE (1998) ENTITY
Small Xen Spore
*/
class xen_spore_small:CBaseEntity
{
void(void) xen_spore_small;
};
void xen_spore_small::xen_spore_small(void)
{
CBaseEntity::CBaseEntity();
precache_model("models/fungus(small).mdl");
solid = SOLID_SLIDEBOX;
movetype = MOVETYPE_WALK;
SetModel("models/fungus(small).mdl");
SetOrigin(origin);
}

95
src/shared/animations.h 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.
*/
enum
{
ANIM_LOOKIDLE,
ANIM_IDLE,
ANIM_DEEPIDLE,
ANIM_RUN2,
ANIM_WALK2HANDED,
ANIM_2HANDSHOT,
ANIM_CRAWL,
ANIM_CROUCHIDLE,
ANIM_JUMP,
ANIM_LONGJUMP,
ANIM_SWIM,
ANIM_TREADWATER,
ANIM_RUN,
ANIM_WALK,
ANIM_AIM2,
ANIM_SHOOT2,
ANIM_AIM1,
ANIM_SHOOT1,
ANIM_DIESIMPLE,
ANIM_DIEBACKWARDS1,
ANIM_DIEBACKWARDS2,
ANIM_DIEFORWARD,
ANIM_DIEHEADSHOT,
ANIM_DIESPIN,
ANIM_DIEGUTSHOT,
ANIM_AIMCROWBAR,
ANIM_SHOOTCROWBAR,
ANIM_CR_AIMCROWBAR,
ANIM_CR_SHOOTCROWBAR,
ANIM_AIMTRIPMINE,
ANIM_SHOOTTRIPMINE,
ANIM_CR_AIMTRIPMINE,
ANIM_CR_SHOOTTRIPMINE,
ANIM_AIM1HAND,
ANIM_SHOOT1HAND,
ANIM_CR_AIM1HAND,
ANIM_CR_SHOOT1HAND,
ANIM_AIMPYTHON,
ANIM_SHOOTPYTHON,
ANIM_CR_AIMPYTHON,
ANIM_CR_SHOOTPYTHON,
ANIM_AIMSHOTGUN,
ANIM_SHOOTSHOTGUN,
ANIM_CR_AIMSHOTGUN,
ANIM_CR_SHOOTSHOTGUN,
ANIM_AIMGAUSS,
ANIM_SHOOTGAUSS,
ANIM_CR_AIMGAUSS,
ANIM_CR_SHOOTGAUSS,
ANIM_AIMMP5,
ANIM_SHOOTMP5,
ANIM_CR_AIMMP5,
ANIM_CR_SHOOTMP5,
ANIM_AIMRPG,
ANIM_SHOOTRPG,
ANIM_CR_AIMRPG,
ANIM_CR_SHOOTRPG,
ANIM_AIMEGON,
ANIM_SHOOTEGON,
ANIM_CR_AIMEGON,
ANIM_CR_SHOOTEGON,
ANIM_AIMSQUEAK,
ANIM_SHOOTSQUEAK,
ANIM_CR_AIMSQUEAK,
ANIM_CR_SHOOTSQUEAK,
ANIM_AIMHIVE,
ANIM_SHOOTHIVE,
ANIM_CR_AIMHIVE,
ANIM_CR_SHOOTHIVE,
ANIM_AIMBOW,
ANIM_SHOOTBOW,
ANIM_CR_AIMBOW,
ANIM_CR_SHOOTBOW
};
void Animation_PlayerTop(float);
void Animation_PlayerTopTemp(float, float);

178
src/shared/animations.qc Executable file
View File

@ -0,0 +1,178 @@
/*
* 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 baselerpfrac;
.float lerpfrac;
.float frame_time;
.float frame_old;
.float fWasCrouching;
.float frame2time;
.float frame2;
.float baseframe2time;
.float baseframe1time;
.float baseframe2;
// For lerping, sigh
.float frame_last;
.float baseframe_last;
.float subblendfrac;
.float subblend2frac;
void Animation_Print(string sWow) {
#ifdef CLIENT
print(sprintf("[DEBUG] %s", sWow));
#else
bprint(PRINT_HIGH, sprintf("SSQC: %s", sWow) );
#endif
}
var int autocvar_bone_spinebone = 0;
var int autocvar_bone_baseframe = 0;
var int autocvar_bone_frame = 0;
/*
=================
Animation_PlayerUpdate
Called every frame to update the animation sequences
depending on what the player is doing
=================
*/
void
Animation_PlayerUpdate(void)
{
self.basebone = gettagindex(self, "Bip01 Spine1");
// TODO: Make this faster
if (self.frame_time < time) {
player pl = (player)self;
self.frame = Weapons_GetAim(pl.activeweapon);
self.frame_old = self.frame;
}
/* in order to appear jumping, we want to not be on ground,
* but also make sure we're not just going down a ramp */
if (!(self.flags & FL_ONGROUND) && (self.velocity[2] > 0 || self.baseframe == ANIM_JUMP)) {
self.baseframe = ANIM_JUMP;
} else if (vlen(self.velocity) == 0) {
if (self.flags & FL_CROUCHING) {
self.baseframe = ANIM_CROUCHIDLE;
} else {
self.baseframe = ANIM_IDLE;
}
} else if (vlen(self.velocity) < 150) {
if (self.flags & FL_CROUCHING) {
self.baseframe = ANIM_CRAWL;
} else {
self.baseframe = ANIM_WALK;
}
} else if (vlen(self.velocity) > 150) {
if (self.flags & FL_CROUCHING) {
self.baseframe = ANIM_CRAWL;
} else {
self.baseframe = ANIM_RUN;
}
}
// Lerp it down!
if (self.lerpfrac > 0) {
self.lerpfrac -= frametime * 5;
if (self.lerpfrac < 0) {
self.lerpfrac = 0;
}
}
if (self.baselerpfrac > 0) {
self.baselerpfrac -= frametime * 5;
if (self.baselerpfrac < 0) {
self.baselerpfrac = 0;
}
}
if (self.frame != self.frame_last) {
//Animation_Print(sprintf("New Frame: %d, Last Frame: %d\n", self.frame, self.frame_last));
// Move everything over to frame 2
self.frame2time = self.frame1time;
self.frame2 = self.frame_last;
// Set frame_last to avoid this being called again
self.frame_last = self.frame;
self.lerpfrac = 1.0f;
self.frame1time = 0.0f;
}
if (self.baseframe != self.baseframe_last) {
//Animation_Print(sprintf("New Baseframe: %d, Last Baseframe: %d\n", self.baseframe, self.baseframe_last));
// Move everything over to frame 2
self.baseframe2time = self.baseframe1time;
self.baseframe2 = self.baseframe_last;
// Set frame_last to avoid this being called again
self.baseframe_last = self.baseframe;
self.baselerpfrac = 1.0f;
self.baseframe1time = 0.0f;
}
self.subblend2frac = self.angles[0];
self.angles[0] = self.angles[2] = 0;
if (!(self.flags & FL_ONGROUND)) {
/*self.frame = ANIM_JUMP;*/
}
// Force the code above to update if we switched positions
if (self.fWasCrouching != (self.flags & FL_CROUCHING)) {
self.frame_old = 0;
self.frame_time = 0;
self.fWasCrouching = (self.flags & FL_CROUCHING);
}
#ifndef CLIENT
// On the CSQC it's done in Player.c
self.subblendfrac =
self.subblend2frac = self.v_angle[0] / 90;
#endif
}
/*
=================
Animation_PlayerTop
Changes the animation sequence for the upper body part
=================
*/
void
Animation_PlayerTop(float fFrame)
{
#ifndef CLIENT
self.frame = fFrame;
self.frame_old = fFrame;
#endif
}
void
Animation_PlayerTopTemp(float fFrame, float fTime)
{
#ifndef CLIENT
self.frame = fFrame;
self.frame_time = time + fTime;
self.SendFlags |= PLAYER_FRAME;
#endif
}

20
src/shared/entities.h Normal file
View File

@ -0,0 +1,20 @@
/*
* 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
{
ENT_TRIPMINE = ENT_SEPARATOR
};

40
src/shared/flags.h Normal file
View File

@ -0,0 +1,40 @@
/*
* 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.
*/
/* game flags */
#define GF_SEMI_TOGGLED (1<<0)
#define GF_FLASHLIGHT (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 GF_UNUSED23 (1<<23)

105
src/shared/fx_blood.qc Normal file
View File

@ -0,0 +1,105 @@
/*
* 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_BLOOD;
var int DECAL_BLOOD;
void
FX_Blood_Init(void)
{
precache_model("sprites/bloodspray.spr");
precache_model("sprites/blood.spr");
PARTICLE_BLOOD = particleeffectnum("part_blood");
DECAL_BLOOD = particleeffectnum("decal_blood.effect");
}
#endif
void
FX_Blood(vector pos, vector color)
{
#ifdef SERVER
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_BLOOD);
WriteCoord(MSG_MULTICAST, pos[0]);
WriteCoord(MSG_MULTICAST, pos[1]);
WriteCoord(MSG_MULTICAST, pos[2]);
WriteByte(MSG_MULTICAST, color[0] * 255);
WriteByte(MSG_MULTICAST, color[1] * 255);
WriteByte(MSG_MULTICAST, color[2] * 255);
msg_entity = self;
multicast(pos, MULTICAST_PVS);
#else
static void Blood_Touch(void)
{
if (serverkeyfloat("*bspversion") == BSPVER_HL)
Decals_Place(self.origin, sprintf("{blood%d", floor(random(1,9))));
else {
decal_pickwall(self, self.origin);
pointparticles(DECAL_BLOOD, g_tracedDecal.endpos, g_tracedDecal.normal, 1);
}
}
if (cvar("violence_hblood") <= 0) {
return;
}
env_sprite eBlood = spawn(env_sprite);
setorigin(eBlood, pos);
setmodel(eBlood, "sprites/bloodspray.spr");
eBlood.drawmask = MASK_ENGINE;
eBlood.maxframe = modelframecount(eBlood.modelindex);
eBlood.loops = 0;
eBlood.scale = 1.0f;
#ifdef GS_RENDERFX
eBlood.m_vecRenderColor = color;
#else
eBlood.colormod = color;
#endif
eBlood.framerate = 20;
eBlood.nextthink = time + 0.05f;
for (int i = 0; i < 3; i++) {
env_sprite ePart = spawn(env_sprite);
setorigin(ePart, pos);
setmodel(ePart, "sprites/blood.spr");
ePart.movetype = MOVETYPE_BOUNCE;
ePart.gravity = 0.5f;
ePart.scale = 0.5f;
ePart.drawmask = MASK_ENGINE;
ePart.maxframe = modelframecount(ePart.modelindex);
ePart.loops = 0;
#ifdef GS_RENDERFX
ePart.m_vecRenderColor = color;
#else
ePart.colormod = color;
#endif
ePart.framerate = 15;
ePart.nextthink = time + 0.1f;
ePart.velocity = randomvec() * 64;
ePart.touch = Blood_Touch;
ePart.solid = SOLID_BBOX;
/* ignore player physics */
ePart.dimension_solid = 1;
ePart.dimension_hit = 1;
setsize(ePart, [0,0,0], [0,0,0]);
}
#endif
}

164
src/shared/fx_breakmodel.qc Normal file
View File

@ -0,0 +1,164 @@
/*
* 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
void
FX_BreakModel_Init(void)
{
precache_model("models/glassgibs.mdl");
precache_model("models/woodgibs.mdl");
precache_model("models/metalplategibs.mdl");
precache_model("models/fleshgibs.mdl");
precache_model("models/ceilinggibs.mdl");
precache_model("models/computergibs.mdl");
precache_model("models/rockgibs.mdl");
precache_model("models/cindergibs.mdl");
precache_sound("debris/bustglass1.wav");
precache_sound("debris/bustglass2.wav");
precache_sound("debris/bustglass3.wav");
precache_sound("debris/bustcrate1.wav");
precache_sound("debris/bustcrate2.wav");
precache_sound("debris/bustcrate3.wav");
precache_sound("debris/bustmetal1.wav");
precache_sound("debris/bustmetal2.wav");
precache_sound("debris/bustflesh1.wav");
precache_sound("debris/bustflesh2.wav");
precache_sound("debris/bustconcrete1.wav");
precache_sound("debris/bustconcrete2.wav");
precache_sound("debris/bustceiling.wav");
}
#endif
void
FX_BreakModel(int count, vector vMins, vector vMaxs, vector vVel, float fStyle)
{
#ifdef SERVER
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_MODELGIB);
WriteCoord(MSG_MULTICAST, vMins[0]);
WriteCoord(MSG_MULTICAST, vMins[1]);
WriteCoord(MSG_MULTICAST, vMins[2]);
WriteCoord(MSG_MULTICAST, vMaxs[0]);
WriteCoord(MSG_MULTICAST, vMaxs[1]);
WriteCoord(MSG_MULTICAST, vMaxs[2]);
WriteByte(MSG_MULTICAST, fStyle);
WriteByte(MSG_MULTICAST, count);
msg_entity = self;
vector vWorldPos;
vWorldPos[0] = vMins[0] + (0.5 * (vMaxs[0] - vMins[0]));
vWorldPos[1] = vMins[1] + (0.5 * (vMaxs[1] - vMins[1]));
vWorldPos[2] = vMins[2] + (0.5 * (vMaxs[2] - vMins[2]));
multicast(vWorldPos, MULTICAST_PVS);
#else
static void FX_BreakModel_Remove(void) { remove(self) ; }
float fModelCount = 0;
vector vecPos;
string sModel = "";
switch (fStyle) {
case GSMATERIAL_GLASS:
case GSMATERIAL_GLASS_UNBREAKABLE:
sModel = "models/glassgibs.mdl";
fModelCount = 8;
break;
case GSMATERIAL_WOOD:
sModel = "models/woodgibs.mdl";
fModelCount = 3;
break;
case GSMATERIAL_METAL:
sModel = "models/metalplategibs.mdl";
fModelCount = 13;
break;
case GSMATERIAL_FLESH:
sModel = "models/fleshgibs.mdl";
fModelCount = 4;
break;
case GSMATERIAL_TILE:
sModel = "models/ceilinggibs.mdl";
fModelCount = 4;
break;
case GSMATERIAL_COMPUTER:
sModel = "models/computergibs.mdl";
fModelCount = 15;
break;
case GSMATERIAL_ROCK:
sModel = "models/rockgibs.mdl";
fModelCount = 3;
break;
default:
case GSMATERIAL_CINDER:
sModel = "models/cindergibs.mdl";
fModelCount = 9;
break;
}
vector vWorldPos;
vWorldPos = vMins + (0.5 * (vMaxs - vMins));
switch (fStyle) {
case GSMATERIAL_GLASS:
pointsound(vWorldPos, sprintf("debris/bustglass%d.wav", random(1, 4)), 1.0f, ATTN_NORM);
break;
case GSMATERIAL_WOOD:
pointsound(vWorldPos, sprintf("debris/bustcrate%d.wav", random(1, 4)), 1.0f, ATTN_NORM);
break;
case GSMATERIAL_METAL:
case GSMATERIAL_COMPUTER:
pointsound(vWorldPos, sprintf("debris/bustmetal%d.wav", random(1, 3)), 1.0f, ATTN_NORM);
break;
case GSMATERIAL_FLESH:
pointsound(vWorldPos, sprintf("debris/bustflesh%d.wav", random(1, 3)), 1.0f, ATTN_NORM);
break;
case GSMATERIAL_CINDER:
case GSMATERIAL_ROCK:
pointsound(vWorldPos, sprintf("debris/bustconcrete%d.wav", random(1, 4)), 1.0f, ATTN_NORM);
break;
case GSMATERIAL_TILE:
pointsound(vWorldPos, "debris/bustceiling.wav", 1.0f, ATTN_NORM);
break;
}
for (int i = 0; i < count; i++) {
entity eGib = spawn();
eGib.classname = "gib";
vecPos[0] = vMins[0] + (random() * (vMaxs[0] - vMins[0]));
vecPos[1] = vMins[1] + (random() * (vMaxs[1] - vMins[1]));
vecPos[2] = vMins[2] + (random() * (vMaxs[2] - vMins[2]));
setorigin(eGib, vecPos);
setmodel(eGib, sModel);
setcustomskin(eGib, "", sprintf("geomset 0 %f\n", random(1, fModelCount + 1)));
eGib.movetype = MOVETYPE_BOUNCE;
eGib.solid = SOLID_NOT;
eGib.avelocity[0] = random()*600;
eGib.avelocity[1] = random()*600;
eGib.avelocity[2] = random()*600;
eGib.think = FX_BreakModel_Remove;
eGib.nextthink = time + 10;
if ((fStyle == GSMATERIAL_GLASS) || (fStyle == GSMATERIAL_GLASS_UNBREAKABLE)) {
eGib.alpha = 0.5f;
}
eGib.drawmask = MASK_ENGINE;
}
#endif
}

62
src/shared/fx_explosion.qc Executable file
View File

@ -0,0 +1,62 @@
/*
* 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 int FX_EXPLOSION_MAIN;
var int FX_EXPLOSION_BS;
void
FX_Explosion_Init(void)
{
Sound_Precache("fx.explosion");
precache_model("sprites/fexplo.spr");
FX_EXPLOSION_MAIN = particleeffectnum("fx_explosion.main");
FX_EXPLOSION_BS = particleeffectnum("fx_explosion.blacksmoke");
}
#endif
void
FX_Explosion(vector vecPos)
{
#ifdef SERVER
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_EXPLOSION);
WriteCoord(MSG_MULTICAST, vecPos[0]);
WriteCoord(MSG_MULTICAST, vecPos[1]);
WriteCoord(MSG_MULTICAST, vecPos[2]);
msg_entity = self;
multicast(vecPos, MULTICAST_PVS);
#else
Decals_Place(vecPos, sprintf("{scorch%d", floor(random(1,4))));
vecPos[2] += 48;
env_sprite eExplosion = spawn(env_sprite);
setorigin(eExplosion, vecPos);
setmodel(eExplosion, "sprites/fexplo.spr");
Sound_Play(eExplosion, CHAN_WEAPON, "fx.explosion");
//eExplosion.think = FX_Explosion_Animate;
eExplosion.effects = EF_ADDITIVE;
eExplosion.drawmask = MASK_ENGINE;
eExplosion.maxframe = modelframecount(eExplosion.modelindex);
eExplosion.loops = 0;
eExplosion.framerate = 20;
eExplosion.nextthink = time + 0.05f;
pointparticles(FX_EXPLOSION_MAIN, vecPos, [0,0,0], 1);
pointparticles(FX_EXPLOSION_BS, vecPos, [0,0,0], 1);
#endif
}

88
src/shared/fx_gibhuman.qc Normal file
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.
*/
#ifdef CLIENT
string g_hgibs[] = {
"models/gib_b_bone.mdl",
"models/gib_legbone.mdl",
"models/gib_lung.mdl",
"models/gib_skull.mdl",
"models/gib_b_gib.mdl"
};
void
FX_GibHuman_Init(void)
{
precache_model("models/gib_b_bone.mdl");
precache_model("models/gib_legbone.mdl");
precache_model("models/gib_lung.mdl");
precache_model("models/gib_skull.mdl");
precache_model("models/gib_b_gib.mdl");
precache_sound("common/bodysplat.wav");
}
#endif
void
FX_GibHuman(vector pos)
{
#ifdef SERVER
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_GIBHUMAN);
WriteCoord(MSG_MULTICAST, pos[0]);
WriteCoord(MSG_MULTICAST, pos[1]);
WriteCoord(MSG_MULTICAST, pos[2]);
msg_entity = __NULL__;
multicast(pos, MULTICAST_PVS);
#else
static void Gib_Remove(void) {
remove(self);
}
static void Gib_Touch(void)
{
if (serverkeyfloat("*bspversion") == BSPVER_HL)
Decals_Place(self.origin, sprintf("{blood%d", floor(random(1,9))));
else {
decal_pickwall(self, self.origin);
pointparticles(DECAL_BLOOD, g_tracedDecal.endpos, g_tracedDecal.normal, 1);
}
}
if (cvar("violence_hgibs") <= 0) {
return;
}
for (int i = 0; i < 5; i++) {
vector vel;
vel[0] = random(-128,128);
vel[1] = random(-128,128);
vel[2] = (300 + random() * 64);
entity gibb = spawn();
setmodel(gibb, g_hgibs[i]);
setorigin(gibb, pos);
gibb.movetype = MOVETYPE_BOUNCE;
gibb.solid = SOLID_BBOX;
setsize(gibb, [0,0,0], [0,0,0]);
gibb.velocity = vel;
gibb.avelocity = vectoangles(gibb.velocity);
gibb.think = Gib_Remove;
gibb.touch = Gib_Touch;
gibb.nextthink = time + 5.0f;
gibb.drawmask = MASK_ENGINE;
}
pointsound(pos, "common/bodysplat.wav", 1, ATTN_NORM);
#endif
}

208
src/shared/fx_impact.qc Normal file
View File

@ -0,0 +1,208 @@
/*
* 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 int FX_IMPACT_BLACKBITS;
var int FX_IMPACT_SMOKE_BROWN;
var int FX_IMPACT_SMOKE_GREY;
var int FX_IMPACT_SPARK;
var int DECAL_IMPACT_DEFAULT;
var int DECAL_IMPACT_ALIEN;
var int DECAL_IMPACT_FLESH;
var int DECAL_IMPACT_FOLIAGE;
var int DECAL_IMPACT_COMPUTER;
var int DECAL_IMPACT_DIRT;
var int DECAL_IMPACT_VENT;
var int DECAL_IMPACT_GRATE;
var int DECAL_IMPACT_METAL;
var int DECAL_IMPACT_GLASS;
var int DECAL_IMPACT_SAND;
var int DECAL_IMPACT_SLOSH;
var int DECAL_IMPACT_SNOW;
var int DECAL_IMPACT_TILE;
var int DECAL_IMPACT_WOOD;
var int DECAL_IMPACT_CONCRETE;
void
FX_Impact_Init(void)
{
Sound_Precache("sfx_impact.default");
Sound_Precache("sfx_impact.alien");
Sound_Precache("sfx_impact.flesh");
Sound_Precache("sfx_impact.foliage");
Sound_Precache("sfx_impact.computer");
Sound_Precache("sfx_impact.dirt");
Sound_Precache("sfx_impact.vent");
Sound_Precache("sfx_impact.grate");
Sound_Precache("sfx_impact.metal");
Sound_Precache("sfx_impact.glass");
Sound_Precache("sfx_impact.sand");
Sound_Precache("sfx_impact.slosh");
Sound_Precache("sfx_impact.snow");
Sound_Precache("sfx_impact.tile");
Sound_Precache("sfx_impact.wood");
Sound_Precache("sfx_impact.concrete");
FX_IMPACT_BLACKBITS = particleeffectnum("fx_impact.blackbits");
FX_IMPACT_SMOKE_GREY = particleeffectnum("fx_impact.smoke_grey");
FX_IMPACT_SMOKE_BROWN = particleeffectnum("fx_impact.smoke_brown");
FX_IMPACT_SPARK = particleeffectnum("fx_impact.spark");
/* engine-side particle system decals for non HL1 BSP */
DECAL_IMPACT_DEFAULT = particleeffectnum("decal_impact.default");
DECAL_IMPACT_ALIEN = particleeffectnum("decal_impact.alien");
DECAL_IMPACT_FLESH = particleeffectnum("decal_impact.flesh");
DECAL_IMPACT_FOLIAGE = particleeffectnum("decal_impact.foliage");
DECAL_IMPACT_COMPUTER = particleeffectnum("decal_impact.computer");
DECAL_IMPACT_DIRT = particleeffectnum("decal_impact.dirt");
DECAL_IMPACT_VENT = particleeffectnum("decal_impact.vent");
DECAL_IMPACT_GRATE = particleeffectnum("decal_impact.grate");
DECAL_IMPACT_METAL = particleeffectnum("decal_impact.metal");
DECAL_IMPACT_GLASS = particleeffectnum("decal_impact.glass");
DECAL_IMPACT_SAND = particleeffectnum("decal_impact.sand");
DECAL_IMPACT_SLOSH = particleeffectnum("decal_impact.slosh");
DECAL_IMPACT_SNOW = particleeffectnum("decal_impact.snow");
DECAL_IMPACT_TILE = particleeffectnum("decal_impact.tile");
DECAL_IMPACT_WOOD = particleeffectnum("decal_impact.wood");
DECAL_IMPACT_CONCRETE = particleeffectnum("decal_impact.concrete");
}
#endif
void
FX_Impact(int iType, vector vecPos, vector vNormal)
{
#ifdef SERVER
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_IMPACT);
WriteByte(MSG_MULTICAST, (float)iType);
WriteCoord(MSG_MULTICAST, vecPos[0]);
WriteCoord(MSG_MULTICAST, vecPos[1]);
WriteCoord(MSG_MULTICAST, vecPos[2]);
WriteCoord(MSG_MULTICAST, vNormal[0]);
WriteCoord(MSG_MULTICAST, vNormal[1]);
WriteCoord(MSG_MULTICAST, vNormal[2]);
msg_entity = self;
multicast(vecPos, MULTICAST_PVS);
#else
/* decals */
if (serverkeyfloat("*bspversion") == BSPVER_HL) {
switch (iType) {
case IMPACT_GLASS:
Decals_Place(vecPos, sprintf("{break%d", floor(random(1,4))));
break;
case IMPACT_MELEE:
Decals_Place(vecPos, sprintf("{shot%d", floor(random(1,6))));
break;
default:
Decals_Place(vecPos, sprintf("{bigshot%d", floor(random(1,6))));
break;
}
} else {
switch (iType) {
case IMPACT_GLASS:
pointparticles(DECAL_IMPACT_GLASS, vecPos, vNormal, 1);
break;
case IMPACT_WOOD:
pointparticles(DECAL_IMPACT_WOOD, vecPos, vNormal, 1);
break;
case IMPACT_METAL:
pointparticles(DECAL_IMPACT_METAL, vecPos, vNormal, 1);
break;
case IMPACT_FLESH:
pointparticles(DECAL_IMPACT_FLESH, vecPos, vNormal, 1);
break;
default:
pointparticles(DECAL_IMPACT_DEFAULT, vecPos, vNormal, 1);
break;
}
}
switch (iType) {
case IMPACT_MELEE:
case IMPACT_EXPLOSION:
break;
case IMPACT_GLASS:
pointparticles(FX_IMPACT_BLACKBITS, vecPos, vNormal, 1);
break;
case IMPACT_WOOD:
pointparticles(FX_IMPACT_SPARK, vecPos, vNormal, 1);
pointparticles(FX_IMPACT_BLACKBITS, vecPos, vNormal, 1);
pointparticles(FX_IMPACT_SMOKE_BROWN, vecPos, vNormal, 1);
break;
case IMPACT_METAL:
pointparticles(FX_IMPACT_SPARK, vecPos, vNormal, 1);
pointparticles(FX_IMPACT_BLACKBITS, vecPos, vNormal, 1);
break;
case IMPACT_FLESH:
FX_Blood(vecPos, vNormal);
break;
default:
pointparticles(FX_IMPACT_SPARK, vecPos, vNormal, 1);
pointparticles(FX_IMPACT_BLACKBITS, vecPos, vNormal, 1);
pointparticles(FX_IMPACT_SMOKE_GREY, vecPos, vNormal, 1);
break;
}
switch (iType) {
case IMPACT_ALIEN:
Sound_PlayAt(vecPos, "sfx_impact.alien");
break;
case IMPACT_COMPUTER:
Sound_PlayAt(vecPos, "sfx_impact.computer");
break;
case IMPACT_CONCRETE:
Sound_PlayAt(vecPos, "sfx_impact.concrete");
break;
case IMPACT_DIRT:
Sound_PlayAt(vecPos, "sfx_impact.dirt");
break;
case IMPACT_FLESH:
Sound_PlayAt(vecPos, "sfx_impact.flesh");
break;
case IMPACT_FOLIAGE:
Sound_PlayAt(vecPos, "sfx_impact.foliage");
break;
case IMPACT_GLASS:
Sound_PlayAt(vecPos, "sfx_impact.glass");
break;
case IMPACT_GRATE:
Sound_PlayAt(vecPos, "sfx_impact.grate");
break;
case IMPACT_METAL:
Sound_PlayAt(vecPos, "sfx_impact.metal");
break;
case IMPACT_SLOSH:
Sound_PlayAt(vecPos, "sfx_impact.slosh");
break;
case IMPACT_SNOW:
Sound_PlayAt(vecPos, "sfx_impact.snow");
break;
case IMPACT_TILE:
Sound_PlayAt(vecPos, "sfx_impact.tile");
break;
case IMPACT_VENT:
Sound_PlayAt(vecPos, "sfx_impact.vent");
break;
case IMPACT_WOOD:
Sound_PlayAt(vecPos, "sfx_impact.wood");
break;
default:
Sound_PlayAt(vecPos, "sfx_impact.default");
break;
}
#endif
}

51
src/shared/fx_spark.qc 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.
*/
#ifdef CLIENT
var float PARTICLE_SPARK;
void
FX_Spark_Init(void)
{
precache_sound("buttons/spark1.wav");
precache_sound("buttons/spark2.wav");
precache_sound("buttons/spark3.wav");
precache_sound("buttons/spark4.wav");
precache_sound("buttons/spark5.wav");
precache_sound("buttons/spark6.wav");
PARTICLE_SPARK = particleeffectnum("fx_spark.effect");
}
#endif
void
FX_Spark(vector pos, vector ang)
{
#ifdef SERVER
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_SPARK);
WriteCoord(MSG_MULTICAST, pos[0]);
WriteCoord(MSG_MULTICAST, pos[1]);
WriteCoord(MSG_MULTICAST, pos[2]);
WriteCoord(MSG_MULTICAST, ang[0]);
WriteCoord(MSG_MULTICAST, ang[1]);
WriteCoord(MSG_MULTICAST, ang[2]);
msg_entity = self;
multicast(pos, MULTICAST_PVS);
#else
pointparticles(PARTICLE_SPARK, pos, ang, 1);
pointsound(pos, sprintf("buttons/spark%d.wav", floor(random() * 6) + 1), 1, ATTN_STATIC);
#endif
}

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

@ -0,0 +1,36 @@
#includelist
entities.h
flags.h
player.qc
weapon_common.h
animations.h
animations.qc
pmove.qc
pmove_water.qc
fx_blood.qc
fx_breakmodel.qc
fx_explosion.qc
fx_gibhuman.qc
fx_spark.qc
fx_impact.qc
items.h
weapons.h
w_crossbow.qc
w_crowbar.qc
w_egon.qc
w_gauss.qc
w_glock.qc
w_handgrenade.qc
w_hornetgun.qc
w_mp5.qc
w_python.qc
w_rpg.qc
w_satchel.qc
w_shotgun.qc
w_snark.qc
w_tripmine.qc
weapons.qc
weapon_common.qc
#endlist

Some files were not shown because too many files have changed in this diff Show More