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

This commit is contained in:
Marco Cawthorne 2021-03-08 11:47:30 +01:00
commit 5a93a6e9e7
41 changed files with 6053 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.

37
README.md Normal file
View File

@ -0,0 +1,37 @@
# FreeSci
Clean-room reimplementation of Gunman Chronicles in QuakeC.
![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 rewolf
then either run Nuclide's ./build_game.sh shell script, or issue 'make' inside
./rewolf/src!
Obviously make sure that Nuclide has fteqw and fteqcc set-up for building.
## Community
Join us on #halflife or #gunman 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: 80 KiB

BIN
img/preview2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

BIN
img/preview3.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

BIN
img/preview4.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 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

View File

@ -0,0 +1,235 @@
/*
* 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[8] =
{
[168 / 255,72 / 128],
[188 / 255,72 / 128],
[208 / 255,72 / 128],
[168 / 255,92 / 128],
[188 / 255,92 / 128],
[228 / 255,72 / 128],
[228 / 255,92 / 128],
[208 / 255,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;
/* compiler bug */
if (pl.g_items & g_weapons[pSeat->m_iHUDWeaponSelected].id) {
} else {
HUD_DrawWeaponSelect_Forward();
}
}
void
HUD_DrawWeaponSelect_Back(void)
{
player pl = (player)pSeat->m_ePlayer;
if (!pl.activeweapon) {
return;
}
if (pSeat->m_flHUDWeaponSelectTime < time) {
pSeat->m_iHUDWeaponSelected = pl.activeweapon;
sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_hudon.wav", 0.5, ATTN_NONE);
} else {
sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_moveselect.wav", 0.5, ATTN_NONE);
pSeat->m_iHUDWeaponSelected++;
if (pSeat->m_iHUDWeaponSelected >= g_weapons.length) {
pSeat->m_iHUDWeaponSelected = 1;
}
}
pSeat->m_flHUDWeaponSelectTime = time + 3;
/* compiler bug */
if (pl.g_items & g_weapons[pSeat->m_iHUDWeaponSelected].id) {
} else {
HUD_DrawWeaponSelect_Back();
}
}
void
HUD_DrawWeaponSelect_Trigger(void)
{
player pl = (player)pSeat->m_ePlayer;
pl.activeweapon = pSeat->m_iHUDWeaponSelected;
sendevent("PlayerSwitchWeapon", "i", pSeat->m_iHUDWeaponSelected);
sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_select.wav", 0.5f, ATTN_NONE);
pSeat->m_iHUDWeaponSelected = pSeat->m_flHUDWeaponSelectTime = 0;
}
void
HUD_DrawWeaponSelect_Last(void)
{
player pl = (player)pSeat->m_ePlayer;
if (pl.g_items & g_weapons[pSeat->m_iOldWeapon].id) {
pl.activeweapon = pSeat->m_iOldWeapon;
sendevent("PlayerSwitchWeapon", "i", pSeat->m_iOldWeapon);
}
}
void
HUD_DrawWeaponSelect_Num(vector vecPos, float fValue)
{
drawsubpic(vecPos, [20,20], "sprites/640hud7.spr_0.tga", g_vecHUDNums[fValue], [20/255, 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 < 7; 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], "sprites/640hud3.spr_0.tga",
[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, 7);
vecPos[1] += 25;
}
}
if (slot_selected == TRUE) {
vecPos[0] += 175;
} else {
vecPos[0] += 25;
}
}
}

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

@ -0,0 +1,67 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
float(entity foo, float chanid) getchannellevel = #0;
/*
=================
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();
precache_model("sprites/640hud1.spr");
precache_model("sprites/640hud2.spr");
precache_model("sprites/640hud3.spr");
precache_model("sprites/640hud4.spr");
precache_model("sprites/640hud5.spr");
precache_model("sprites/640hud6.spr");
precache_model("sprites/640hudof01.spr");
precache_model("sprites/640hudof02.spr");
precache_model("sprites/640hudof03.spr");
precache_model("sprites/640hudof04.spr");
precache_model("sprites/640hudof05.spr");
precache_model("sprites/640hudof06.spr");
precache_model("sprites/ofch1.spr");
precache_model("sprites/ofch2.spr");
precache_model("sprites/320hudof01.spr");
BEAM_TRIPMINE = particleeffectnum("weapon_tripmine.beam");
}

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

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

2
src/progs.src Executable file
View File

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

4
src/server/Makefile Normal file
View File

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

176
src/server/ammo_op4.qc Normal file
View File

@ -0,0 +1,176 @@
/*
* 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 ammo_556 (0 0 0.8) (-16 -16 0) (16 16 32)
HALF-LIFE: OPPOSING FORCE (1999) ENTITY
Ammo for the M249.
A single ammo_556 will provide 50 bullets.
*/
class ammo_556:item_ammo
{
void(void) ammo_556;
virtual void(void) touch;
};
void
ammo_556::ammo_556(void)
{
model = "models/w_saw_clip.mdl";
item_ammo::item_ammo();
}
void
ammo_556::touch(void)
{
if (other.classname == "player") {
player pl = (player)other;
if (pl.ammo_556 < 200) {
pl.ammo_556 = bound(0, pl.ammo_556 + 50, 200);
item_ammo::touch();
}
}
}
/*QUAKED ammo_762 (0 0 0.8) (-16 -16 0) (16 16 32)
HALF-LIFE: OPPOSING FORCE (1999) ENTITY
Ammo for the M-40A1 Sniper.
A single ammo_762 will provide 5 bullets.
*/
class ammo_762:item_ammo
{
void(void) ammo_762;
virtual void(void) touch;
};
void
ammo_762::ammo_762(void)
{
model = "models/w_m40a1clip.mdl";
item_ammo::item_ammo();
}
void
ammo_762::touch(void)
{
if (other.classname == "player") {
player pl = (player)other;
if (pl.ammo_762 < 15) {
pl.ammo_762 = bound(0, pl.ammo_762 + 5, 15);
item_ammo::touch();
}
}
}
/*QUAKED ammo_spore (0 0 0.8) (-16 -16 0) (16 16 32)
HALF-LIFE: OPPOSING FORCE (1999) ENTITY
Ammo for the Spore Launcher.
A single ammo_spore will provide 1 spore.
The angle key refers to the direction the entity will fire (?)
when shot. The model itself uses decal-like logic to determine
the direction the model is aiming.
*/
class ammo_spore:item_ammo
{
void(void) ammo_spore;
virtual void(void) touch;
virtual void(void) Respawn;
virtual void(void) Death;
};
void
ammo_spore::ammo_spore(void)
{
movetype = MOVETYPE_NONE;
model = "models/spore_ammo.mdl";
item_ammo::item_ammo();
}
void
ammo_spore::Death(void)
{
makevectors(m_oldAngle);
Sporelauncher_AltFire(this, origin, v_forward);
frame = 2;
m_iBody = 0;
solid = SOLID_NOT;
think = Respawn;
nextthink = time + 10.0f;
}
void ammo_spore::Respawn(void)
{
frame = 1;
m_iBody = 2;
movetype = MOVETYPE_NONE;
takedamage = DAMAGE_YES;
health = 1;
if (m_oldModel) {
SetModel(m_oldModel);
}
solid = SOLID_NOT;
setsize(this, [0,0,0], [0,0,0]);
SetOrigin(m_oldOrigin);
decal_pickwall(this, m_oldOrigin);
/* we never hit any wall. */
if (g_tracedDecal.fraction == 1.0f) {
print(sprintf("^xFA0Warning^7: ammo_spore tracing failed at %v\n", origin));
return;
}
origin = g_tracedDecal.endpos;
makevectors(vectoangles(g_tracedDecal.endpos - origin));
vector cpl = v_forward - (v_forward * g_tracedDecal.normal) * g_tracedDecal.normal;
if (g_tracedDecal.normal[2] == 0) {
cpl = [0, 0, 1];
}
angles = vectoangles(cpl, g_tracedDecal.normal);
solid = SOLID_BBOX;
setsize(this, [-16,-16,-16], [16,16,16]);
think = __NULL__;
nextthink = -1;
}
void
ammo_spore::touch(void)
{
if not (other.flags & FL_CLIENT) {
return;
}
player pl = (player)other;
if (pl.ammo_spore < 20) {
pl.ammo_spore = bound(0, pl.ammo_spore + 1, 20);
Weapons_RefreshAmmo(pl);
Logging_Pickup(other, this, __NULL__);
frame = 2;
m_iBody = 0;
think = Respawn;
nextthink = time + 10.0f;
}
}

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

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

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

@ -0,0 +1,168 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
var int autocvar_sv_playerkeepalive = TRUE;
/* 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 pp)
{
Animation_PlayerUpdate();
}
void
HLGameRules::LevelNewParms(void)
{
parm1 = parm2 = parm3 = parm4 = parm5 = parm6 = parm7 =
parm8 = parm9 = parm10 = parm11 = parm12 = parm13 = parm14 =
parm15 = parm16 = parm17 = parm18 = parm19 = parm20 = parm21 =
parm22 = parm23 = parm24 = parm25 = parm26 = parm27 = parm28 =
parm29 = parm30 = 0;
parm64 = FL_CLIENT;
}
void
HLGameRules::LevelDecodeParms(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;
/* near gearbox additions */
pl.ammo_556 = parm31;
pl.ammo_762 = parm32;
pl.ammo_spore = parm33;
pl.ammo_shock = parm34;
pl.ammo_penguin = parm35;
pl.eagle_mag = parm36;
pl.sniper_mag = parm37;
pl.m249_mag = parm38;
pl.sporelauncher_mag = parm39;
if (pl.flags & FL_CROUCHING) {
setsize(pl, VEC_CHULL_MIN, VEC_CHULL_MAX);
} else {
setsize(pl, VEC_HULL_MIN, VEC_HULL_MAX);
}
}
void
HLGameRules::LevelChangeParms(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;
/* near gearbox additions */
parm31 = pl.ammo_556;
parm32 = pl.ammo_762;
parm33 = pl.ammo_spore;
parm34 = pl.ammo_shock;
parm35 = pl.ammo_penguin;
parm36 = pl.eagle_mag;
parm37 = pl.sniper_mag;
parm38 = pl.m249_mag;
parm39 = pl.sporelauncher_mag;
}
void
HLGameRules::PlayerConnect(base_player pl)
{
if (Plugin_PlayerConnect(pl) == FALSE)
bprint(PRINT_HIGH, sprintf("%s connected\n", pl.netname));
}
void
HLGameRules::PlayerDisconnect(base_player pl)
{
bprint(PRINT_HIGH, sprintf("%s disconnected\n", pl.netname));
/* Make this unusable */
pl.solid = SOLID_NOT;
pl.movetype = MOVETYPE_NONE;
pl.modelindex = 0;
pl.health = 0;
pl.takedamage = 0;
pl.SendFlags = PLAYER_MODELINDEX;
}
void
HLGameRules::PlayerKill(base_player pp)
{
player pl = (player)pp;
Damage_Apply(pl, pl, pl.health, WEAPON_NONE, DMG_SKIP_ARMOR);
}

View File

@ -0,0 +1,27 @@
/*
* 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 OP4CTFRules:HLGameRules
{
int m_iIntermission;
int m_iIntermissionTime;
virtual void(void) FrameStart;
/* client */
virtual void(base_player) PlayerSpawn;
virtual void(base_player) PlayerDeath;
};

145
src/server/gamerules_ctf.qc Normal file
View File

@ -0,0 +1,145 @@
/*
* 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
OP4CTFRules::FrameStart(void)
{
if (cvar("mp_timelimit"))
if (time >= (cvar("mp_timelimit") * 60)) {
IntermissionStart();
}
}
void
OP4CTFRules::PlayerDeath(base_player pp)
{
player pl = (player)pp;
/* obituary networking */
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_OBITUARY);
if (g_dmg_eAttacker.netname)
WriteString(MSG_MULTICAST, g_dmg_eAttacker.netname);
else
WriteString(MSG_MULTICAST, g_dmg_eAttacker.classname);
WriteString(MSG_MULTICAST, pl.netname);
WriteByte(MSG_MULTICAST, g_dmg_iWeapon);
WriteByte(MSG_MULTICAST, 0);
msg_entity = world;
multicast([0,0,0], MULTICAST_ALL);
/* death-counter */
pl.deaths++;
forceinfokey(pl, "*deaths", ftos(pl.deaths));
/* update score-counter */
if (pl.flags & FL_CLIENT || pl.flags & FL_MONSTER)
if (g_dmg_eAttacker.flags & FL_CLIENT) {
if (pl == g_dmg_eAttacker)
g_dmg_eAttacker.frags--;
else
g_dmg_eAttacker.frags++;
}
/* in DM we only care about the frags */
if (cvar("mp_fraglimit"))
if (g_dmg_eAttacker.frags >= cvar("mp_fraglimit")) {
IntermissionStart();
}
weaponbox_spawn(pl);
pl.movetype = MOVETYPE_NONE;
pl.solid = SOLID_NOT;
pl.takedamage = DAMAGE_NO;
pl.gflags &= ~GF_FLASHLIGHT;
pl.armor = pl.activeweapon = pl.g_items = 0;
pl.think = PutClientInServer;
pl.nextthink = time + 4.0f;
Sound_Play(pl, CHAN_AUTO, "player.die");
if (pl.health < -50) {
pl.health = 0;
FX_GibHuman(pl.origin);
return;
}
pl.health = 0;
/* Let's handle corpses on the clientside */
entity corpse = spawn();
setorigin(corpse, pl.origin + [0,0,32]);
setmodel(corpse, pl.model);
setsize(corpse, VEC_HULL_MIN, VEC_HULL_MAX);
corpse.movetype = MOVETYPE_TOSS;
corpse.solid = SOLID_TRIGGER;
corpse.modelindex = pl.modelindex;
corpse.frame = ANIM_DIESIMPLE;
corpse.angles = pl.angles;
corpse.velocity = pl.velocity;
}
void
OP4CTFRules::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.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);
}

83
src/server/input.qc Normal file
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.
*/
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();
}
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);
Weapons_AddItem(pl, WEAPON_PENGUIN, -1);
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_M249, -1);
Weapons_AddItem(pl, WEAPON_SHOCKRIFLE, -1);
Weapons_AddItem(pl, WEAPON_SPORELAUNCHER, -1);
Weapons_AddItem(pl, WEAPON_SNIPERRIFLE, -1);
Weapons_AddItem(pl, WEAPON_DISPLACER, -1);
}
if (self.impulse == 102) {
// Respawn all the entities
for (entity a = world; (a = findfloat(a, g::identity, 1));) {
CBaseEntity caw = (CBaseEntity)a;
caw.Respawn();
}
bprint(PRINT_HIGH, "Respawning all map entities...\n");
}
}
self.impulse = 0;
}

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_drillsergeant (0 0.8 0.8) (-16 -16 0) (16 16 72)
HALF-LIFE: OPPOSING FORCE (1999) ENTITY
Drill Sergeant
...from the Opposing Force Boot-Camp Training
*/
enum
{
DRILL_IDLE1,
DRILL_IDLE2,
DRILL_IDLE3,
DRILL_WALK,
DRILL_RUN,
DRILL_TURNLEFT,
DRILL_TURNRIGHT,
DRILL_FLINCH,
DRILL_DIESIMPLE,
DRILL_DIEBACKWARD,
DRILL_DIEFORWARD,
DRILL_DEADONSIDE,
DRILL_DEADONSTOMACH,
DRILL_HANDSONHIPS,
DRILL_POINT1,
DRILL_POINT2,
DRILL_BARK,
DRILL_YELLHARD,
DRILL_BARKHARD,
DRILL_WHISTLE,
DRILL_BINOCULARS
};
class monster_drillsergeant:CBaseNPC
{
void(void) monster_drillsergeant;
virtual void(void) Respawn;
virtual int(void) AnimIdle;
virtual int(void) AnimWalk;
virtual int(void) AnimRun;
};
int
monster_drillsergeant::AnimIdle(void)
{
return DRILL_IDLE1;
}
int
monster_drillsergeant::AnimWalk(void)
{
return DRILL_WALK;
}
int
monster_drillsergeant::AnimRun(void)
{
return DRILL_RUN;
}
void
monster_drillsergeant::Respawn(void)
{
CBaseNPC::Respawn();
takedamage = DAMAGE_NO;
iBleeds = FALSE;
}
void
monster_drillsergeant::monster_drillsergeant(void)
{
netname = "Drill Sergeant";
model = "models/drill.mdl";
base_mins = [-16,-16,0];
base_maxs = [16,16,72];
CBaseNPC::CBaseNPC();
}

View File

@ -0,0 +1,81 @@
/*
* 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_recruit (0 0.8 0.8) (-16 -16 0) (16 16 72)
HALF-LIFE: OPPOSING FORCE (1999) ENTITY
Recruit
...from the Opposing Force Boot-Camp Training
*/
enum
{
RECRUIT_IDLE,
RECRUIT_WALK,
RECRUIT_RUN,
RECRUIT_TURNLEFT,
RECRUIT_TURNRIGHT,
RECRUIT_PUSHUPS,
RECRUIT_JUMPINJACK,
RECRUIT_SALUTE
};
class monster_recruit:CBaseNPC
{
void(void) monster_recruit;
virtual void(void) Respawn;
virtual int(void) AnimIdle;
virtual int(void) AnimWalk;
virtual int(void) AnimRun;
};
int
monster_recruit::AnimIdle(void)
{
return RECRUIT_IDLE;
}
int
monster_recruit::AnimWalk(void)
{
return RECRUIT_WALK;
}
int
monster_recruit::AnimRun(void)
{
return RECRUIT_RUN;
}
void
monster_recruit::Respawn(void)
{
CBaseNPC::Respawn();
takedamage = DAMAGE_NO;
iBleeds = FALSE;
}
void
monster_recruit::monster_recruit(void)
{
netname = "Recruit";
model = "models/recruit.mdl";
base_mins = [-16,-16,0];
base_maxs = [16,16,72];
CBaseNPC::CBaseNPC();
}

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

@ -0,0 +1,95 @@
#pragma target fte
#pragma progs_dat "../../progs.dat"
#define QWSSQC
#define SERVER
#define VALVE
#define GEARBOX
#define GS_RENDERFX
#includelist
../../../src/shared/fteextensions.qc
../../../src/gs-entbase/server/defs.h
../../../src/shared/defs.h
../../../src/server/defs.h
../../../src/gs-entbase/server.src
../../../src/gs-entbase/shared.src
../shared/include.src
defs.h
../../../valve/src/server/monster_apache.qc
../../../valve/src/server/monster_alien_controller.qc
../../../valve/src/server/monster_alien_grunt.qc
../../../valve/src/server/monster_alien_slave.qc
../../../valve/src/server/monster_barnacle.qc
../../../valve/src/server/monster_barney.qc
../../../valve/src/server/monster_barney_dead.qc
../../../valve/src/server/monster_bigmomma.qc
../../../valve/src/server/monster_bloater.qc
../../../valve/src/server/monster_bullchicken.qc
../../../valve/src/server/monster_cockroach.qc
../../../valve/src/server/monster_flyer_flock.qc
../../../valve/src/server/monster_gargantua.qc
../../../valve/src/server/monster_gman.qc
../../../valve/src/server/monster_headcrab.qc
../../../valve/src/server/monster_babycrab.qc
../../../valve/src/server/monster_hevsuit_dead.qc
../../../valve/src/server/monster_houndeye.qc
../../../valve/src/server/monster_human_grunt.qc
../../../valve/src/server/monster_hgrunt_dead.qc
../../../valve/src/server/monster_human_assassin.qc
../../../valve/src/server/monster_ichthyosaur.qc
../../../valve/src/server/monster_leech.qc
../../../valve/src/server/monster_miniturret.qc
../../../valve/src/server/monster_nihilanth.qc
../../../valve/src/server/monster_osprey.qc
../../../valve/src/server/monster_rat.qc
../../../valve/src/server/monster_scientist_dead.qc
../../../valve/src/server/monster_sitting_scientist.qc
../../../valve/src/server/monster_scientist.qc
../../../valve/src/server/monster_sentry.qc
../../../valve/src/server/monster_tentacle.qc
../../../valve/src/server/monster_turret.qc
../../../valve/src/server/monster_zombie.qc
monster_drillsergeant.qc
monster_recruit.qc
../../../valve/src/server/player.qc
../../../valve/src/server/spectator.qc
../../../valve/src/server/items.qc
../../../valve/src/server/item_longjump.qc
../../../valve/src/server/item_suit.qc
../../../valve/src/server/item_healthkit.qc
../../../valve/src/server/item_battery.qc
../../../valve/src/server/item_weaponbox.qc
../../../valve/src/server/world_items.qc
../../../valve/src/server/xen_spore_small.qc
../../../valve/src/server/xen_spore_medium.qc
../../../valve/src/server/xen_spore_large.qc
../../../valve/src/server/xen_hair.qc
../../../valve/src/server/xen_plantlight.qc
../../../valve/src/server/ammo.qc
ammo_op4.qc
../../../src/botlib/include.src
gamerules.qc
../../../valve/src/server/gamerules_singleplayer.qc
../../../valve/src/server/gamerules_multiplayer.qc
gamerules_ctf.qc
../../../valve/src/server/client.qc
server.qc
../../../valve/src/server/damage.qc
../../../valve/src/server/rules.qc
../../../valve/src/server/flashlight.qc
../../../base/src/server/modelevent.qc
../../../valve/src/server/input.qc
../../../valve/src/server/spawn.qc
../../../src/server/include.src
../../../src/shared/include.src
#endlist

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

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

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

@ -0,0 +1,46 @@
#includelist
../../../valve/src/shared/entities.h
../../../valve/src/shared/flags.h
player.qc
../../../valve/src/shared/weapon_common.h
../../../valve/src/shared/animations.h
../../../valve/src/shared/animations.qc
../../../valve/src/shared/pmove.qc
../../../valve/src/shared/pmove_water.qc
../../../valve/src/shared/fx_blood.qc
../../../valve/src/shared/fx_breakmodel.qc
../../../valve/src/shared/fx_explosion.qc
../../../valve/src/shared/fx_gibhuman.qc
../../../valve/src/shared/fx_spark.qc
../../../valve/src/shared/fx_impact.qc
items.h
weapons.h
../../../valve/src/shared/w_crossbow.qc
../../../valve/src/shared/w_crowbar.qc
../../../valve/src/shared/w_egon.qc
../../../valve/src/shared/w_gauss.qc
../../../valve/src/shared/w_glock.qc
../../../valve/src/shared/w_handgrenade.qc
../../../valve/src/shared/w_hornetgun.qc
../../../valve/src/shared/w_mp5.qc
../../../valve/src/shared/w_python.qc
../../../valve/src/shared/w_rpg.qc
../../../valve/src/shared/w_satchel.qc
../../../valve/src/shared/w_shotgun.qc
../../../valve/src/shared/w_snark.qc
../../../valve/src/shared/w_tripmine.qc
w_pipewrench.qc
w_knife.qc
w_grapple.qc
w_eagle.qc
w_m249.qc
w_displacer.qc
w_sniperrifle.qc
w_sporelauncher.qc
w_penguin.qc
w_shockrifle.qc
weapons.qc
../../../valve/src/shared/weapon_common.qc
#endlist

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

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

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

@ -0,0 +1,806 @@
/*
* 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.
*/
/* all potential SendFlags bits we can possibly send */
enumflags
{
PLAYER_KEEPALIVE,
PLAYER_MODELINDEX,
PLAYER_ORIGIN,
PLAYER_ORIGIN_Z,
PLAYER_ANGLES_X,
PLAYER_ANGLES_Y,
PLAYER_ANGLES_Z,
PLAYER_VELOCITY,
PLAYER_VELOCITY_Z,
PLAYER_FLAGS,
PLAYER_WEAPON,
PLAYER_ITEMS,
PLAYER_HEALTH,
PLAYER_ARMOR,
PLAYER_MOVETYPE,
PLAYER_VIEWOFS,
PLAYER_BASEFRAME,
PLAYER_FRAME,
PLAYER_AMMO1,
PLAYER_AMMO2,
PLAYER_AMMO3,
PLAYER_UNUSED1,
PLAYER_UNUSED2
};
/* ammo 1 type updates */
enumflags
{
AMMO1_GLOCK,
AMMO1_MP5,
AMMO1_PYTHON,
AMMO1_SHOTGUN,
AMMO1_CROSSBOW,
AMMO1_RPG,
AMMO1_SATCHEL
};
/* ammo 2 type updates */
enumflags
{
AMMO2_9MM,
AMMO2_357,
AMMO2_BUCKSHOT,
AMMO2_BOLT,
AMMO2_ROCKET,
AMMO2_URANIUM,
AMMO2_HANDGRENADE,
AMMO2_SATCHEL,
AMMO2_TRIPMINE,
AMMO2_SNARK,
AMMO2_HORNET,
};
enumflags
{
AMMO3_M203_GRENADE,
AMMO3_SHOTGUN_STATE,
AMMO3_GAUSS_STATE,
AMMO3_GAUSS_VOLUME,
AMMO3_EGON_STATE,
AMMO3_RPG_STATE,
AMMO3_HANDGRENADE_STATE
};
noref int input_sequence;
class player:base_player
{
/* Weapon specific */
int glock_mag;
int glock_mag_net;
int mp5_mag;
int mp5_mag_net;
int python_mag;
int python_mag_net;
int shotgun_mag;
int shotgun_mag_net;
int crossbow_mag;
int crossbow_mag_net;
int rpg_mag;
int rpg_mag_net;
int satchel_chg;
int satchel_chg_net;
int ammo_9mm;
int ammo_9mm_net;
int ammo_357;
int ammo_357_net;
int ammo_buckshot;
int ammo_buckshot_net;
int ammo_bolt;
int ammo_bolt_net;
int ammo_rocket;
int ammo_rocket_net;
int ammo_uranium;
int ammo_uranium_net;
int ammo_handgrenade;
int ammo_handgrenade_net;
int ammo_satchel;
int ammo_satchel_net;
int ammo_tripmine;
int ammo_tripmine_net;
int ammo_snark;
int ammo_snark_net;
int ammo_hornet;
int ammo_hornet_net;
int ammo_m203_grenade;
int ammo_m203_grenade_net;
int ammo_shotgun_state;
int ammo_shotgun_state_net;
int ammo_gauss_state;
int ammo_gauss_state_net;
int ammo_gauss_volume;
int ammo_gauss_volume_net;
int ammo_egon_state;
int ammo_egon_state_net;
int ammo_rpg_state;
int ammo_rpg_state_net;
int mode_tempstate;
int mode_tempstate_net;
/* gearbox */
int eagle_mag; int eagle_mag_net;
int sniper_mag; int sniper_mag_net;
int m249_mag; int m249_mag_net;
int sporelauncher_mag; int sporelauncher_mag_net;
int ammo_556; int ammo_556_net;
int ammo_762; int ammo_762_net;
int ammo_spore; int ammo_spore_net;
int ammo_shock; int ammo_shock_net;
int ammo_penguin; int ammo_penguin_net;
int mode_displacer; int mode_displacer_net;
int mode_eagle; int mode_eagle_net;
int mode_wrench; int mode_wrench_net;
int mode_sporelauncher; int mode_sporelauncher_net;
int mode_m249; int mode_m249_net;
#ifdef CLIENT
/* External model */
entity p_model;
int p_hand_bone;
int p_model_bone;
float lastweapon;
virtual void(void) gun_offset;
virtual void(void) draw;
virtual float() predraw;
virtual void(void) postdraw;
virtual void(float) ReceiveEntity;
virtual void(void) PredictPreFrame;
virtual void(void) PredictPostFrame;
#else
virtual void(void) EvaluateEntity;
virtual float(entity, float) SendEntity;
#endif
};
#ifdef CLIENT
void Weapons_AmmoUpdate(entity);
/*
=================
player::ReceiveEntity
=================
*/
void
player::ReceiveEntity(float new)
{
float fl;
if (new == FALSE) {
/* Go through all the physics code between the last received frame
* and the newest frame and keep the changes this time around instead
* of rolling back, because we'll apply the new server-verified values
* right after anyway. */
/* FIXME: splitscreen */
if (entnum == player_localentnum) {
/* FIXME: splitscreen */
pSeat = &g_seats[0];
for (int i = sequence+1; i <= servercommandframe; i++) {
/* ...maybe the input state is too old? */
if (!getinputstate(i)) {
break;
}
input_sequence = i;
PMove_Run();
}
/* any differences in things that are read below are now
* officially from prediction misses. */
}
}
/* seed for our prediction table */
sequence = servercommandframe;
fl = readfloat();
/* HACK: we need to make this more reliable */
if (fl == UPDATE_ALL) {
/* we respawned */
gravity = __NULL__;
}
if (fl & PLAYER_MODELINDEX)
modelindex = readshort();
if (fl & PLAYER_ORIGIN) {
origin[0] = readcoord();
origin[1] = readcoord();
}
if (fl & PLAYER_ORIGIN_Z)
origin[2] = readcoord();
if (fl & PLAYER_ANGLES_X)
pitch = readfloat();
if (fl & PLAYER_ANGLES_Y)
angles[1] = readfloat();
if (fl & PLAYER_ANGLES_Z)
angles[2] = readfloat();
if (fl & PLAYER_VELOCITY) {
velocity[0] = readcoord();
velocity[1] = readcoord();
}
if (fl & PLAYER_VELOCITY_Z)
velocity[2] = readcoord();
if (fl & PLAYER_FLAGS) {
flags = readfloat();
gflags = readfloat();
}
if (fl & PLAYER_WEAPON)
activeweapon = readbyte();
if (fl & PLAYER_ITEMS)
g_items = (__variant)readfloat();
if (fl & PLAYER_HEALTH)
health = readbyte();
if (fl & PLAYER_ARMOR)
armor = readbyte();
if (fl & PLAYER_MOVETYPE)
movetype = readbyte();
if (fl & PLAYER_VIEWOFS)
view_ofs[2] = readfloat();
if (fl & PLAYER_BASEFRAME)
baseframe = readbyte();
if (fl & PLAYER_FRAME) {
frame = readbyte();
frame1time = 0.0f;
frame2time = 0.0f;
}
if (fl & PLAYER_AMMO1) {
glock_mag = readbyte();
mp5_mag = readbyte();
python_mag = readbyte();
shotgun_mag = readbyte();
crossbow_mag = readbyte();
rpg_mag = readbyte();
satchel_chg = readbyte();
/* gearbox */
eagle_mag = readbyte();
sniper_mag = readbyte();
m249_mag = readbyte();
sporelauncher_mag = readbyte();
}
if (fl & PLAYER_AMMO2) {
ammo_9mm = readbyte();
ammo_357 = readbyte();
ammo_buckshot = readbyte();
ammo_bolt = readbyte();
ammo_rocket = readbyte();
ammo_uranium = readbyte();
ammo_handgrenade = readbyte();
ammo_satchel = readbyte();
ammo_tripmine = readbyte();
ammo_snark = readbyte();
ammo_hornet = readbyte();
/* gearbox */
ammo_556 = readbyte();
ammo_762 = readbyte();
ammo_spore = readbyte();
ammo_shock = readbyte();
ammo_penguin = readbyte();
}
if (fl & PLAYER_AMMO3) {
ammo_m203_grenade = readbyte();
ammo_shotgun_state = readbyte();
ammo_gauss_state = readbyte();
ammo_gauss_volume = readbyte();
ammo_egon_state = readbyte();
ammo_rpg_state = readbyte();
mode_tempstate = readbyte();
/* gearbox */
mode_displacer = readbyte();
mode_eagle = readbyte();
mode_wrench = readbyte();
mode_sporelauncher = readbyte();
mode_m249 = readbyte();
}
if (fl & PLAYER_AMMO1 || fl & PLAYER_AMMO2 || fl & PLAYER_AMMO3)
Weapons_AmmoUpdate(this);
setorigin(this, origin);
}
/*
=================
player::PredictPostFrame
Save the last valid server values away in the _net variants of each field
so we can roll them back later.
=================
*/
void
player::PredictPreFrame(void)
{
glock_mag_net = glock_mag;
mp5_mag_net = mp5_mag;
python_mag_net = python_mag;
shotgun_mag_net = shotgun_mag;
crossbow_mag_net = crossbow_mag;
rpg_mag_net = rpg_mag;
satchel_chg_net = satchel_chg;
ammo_9mm_net = ammo_9mm;
ammo_357_net = ammo_357;
ammo_buckshot_net = ammo_buckshot;
ammo_bolt_net = ammo_bolt;
ammo_rocket_net = ammo_rocket;
ammo_uranium_net = ammo_uranium;
ammo_handgrenade_net = ammo_handgrenade;
ammo_satchel_net = ammo_satchel;
ammo_tripmine_net = ammo_tripmine;
ammo_snark_net = ammo_snark;
ammo_hornet_net = ammo_hornet;
ammo_m203_grenade_net = ammo_m203_grenade;
ammo_shotgun_state_net = ammo_shotgun_state;
ammo_gauss_state_net = ammo_gauss_state;
ammo_gauss_volume_net = ammo_gauss_volume;
ammo_egon_state_net = ammo_egon_state;
ammo_rpg_state_net = ammo_rpg_state;
mode_tempstate_net = mode_tempstate;
/* gearbox */
eagle_mag_net = eagle_mag;
sniper_mag_net = sniper_mag;
m249_mag_net = m249_mag;
sporelauncher_mag_net = sporelauncher_mag;
ammo_556_net = ammo_556;
ammo_762_net = ammo_762;
ammo_spore_net = ammo_spore;
ammo_shock_net = ammo_shock;
ammo_penguin_net = ammo_penguin;
mode_displacer_net = mode_displacer;
mode_eagle_net = mode_eagle;
mode_wrench_net = mode_wrench;
mode_sporelauncher_net = mode_sporelauncher;
mode_m249_net = mode_m249;
}
/*
=================
player::PredictPostFrame
Where we roll back our values to the ones last sent/verified by the server.
=================
*/
void
player::PredictPostFrame(void)
{
glock_mag = glock_mag_net;
mp5_mag = mp5_mag_net;
python_mag = python_mag_net;
shotgun_mag = shotgun_mag_net;
crossbow_mag = crossbow_mag_net;
rpg_mag = rpg_mag_net;
satchel_chg = satchel_chg_net;
ammo_9mm = ammo_9mm_net;
ammo_357 = ammo_357_net;
ammo_buckshot = ammo_buckshot_net;
ammo_m203_grenade = ammo_m203_grenade_net;
ammo_bolt = ammo_bolt_net;
ammo_rocket = ammo_rocket_net;
ammo_uranium = ammo_uranium_net;
ammo_handgrenade = ammo_handgrenade_net;
ammo_satchel = ammo_satchel_net;
ammo_tripmine = ammo_tripmine_net;
ammo_snark = ammo_snark_net;
ammo_hornet = ammo_hornet_net;
ammo_m203_grenade = ammo_m203_grenade_net;
ammo_shotgun_state = ammo_shotgun_state_net;
ammo_gauss_state = ammo_gauss_state_net;
ammo_gauss_volume = ammo_gauss_volume_net;
ammo_egon_state = ammo_egon_state_net;
ammo_rpg_state = ammo_rpg_state_net;
mode_tempstate = mode_tempstate_net;
/* gearbox */
eagle_mag = eagle_mag_net;
sniper_mag = sniper_mag_net;
m249_mag = m249_mag_net;
sporelauncher_mag = sporelauncher_mag_net;
ammo_556 = ammo_556_net;
ammo_762 = ammo_762_net;
ammo_spore = ammo_spore_net;
ammo_shock = ammo_shock_net;
ammo_penguin = ammo_penguin_net;
mode_displacer = mode_displacer_net;
mode_eagle = mode_eagle_net;
mode_wrench = mode_wrench_net;
mode_sporelauncher = mode_sporelauncher_net;
mode_m249 = mode_m249_net;
}
#else
void
player::EvaluateEntity(void)
{
SendFlags |= PLAYER_KEEPALIVE;
if (old_modelindex != modelindex)
SendFlags |= PLAYER_MODELINDEX;
if (old_origin[0] != origin[0])
SendFlags |= PLAYER_ORIGIN;
if (old_origin[1] != origin[1])
SendFlags |= PLAYER_ORIGIN;
if (old_origin[2] != origin[2])
SendFlags |= PLAYER_ORIGIN_Z;
if (old_angles[0] != v_angle[0])
SendFlags |= PLAYER_ANGLES_X;
if (old_angles[1] != angles[1])
SendFlags |= PLAYER_ANGLES_Y;
if (old_angles[2] != angles[2])
SendFlags |= PLAYER_ANGLES_Z;
if (old_velocity[0] != velocity[0])
SendFlags |= PLAYER_VELOCITY;
if (old_velocity[1] != velocity[1])
SendFlags |= PLAYER_VELOCITY;
if (old_velocity[2] != velocity[2])
SendFlags |= PLAYER_VELOCITY_Z;
if (old_flags != flags)
SendFlags |= PLAYER_FLAGS;
if (old_gflags != gflags)
SendFlags |= PLAYER_FLAGS;
if (old_activeweapon != activeweapon)
SendFlags |= PLAYER_WEAPON;
if (old_items != g_items)
SendFlags |= PLAYER_ITEMS;
if (old_health != health)
SendFlags |= PLAYER_HEALTH;
if (old_armor != armor)
SendFlags |= PLAYER_ARMOR;
if (old_movetype != movetype)
SendFlags |= PLAYER_MOVETYPE;
if (old_viewofs != view_ofs[2])
SendFlags |= PLAYER_VIEWOFS;
if (old_baseframe != baseframe)
SendFlags |= PLAYER_BASEFRAME;
if (old_frame != frame)
SendFlags |= PLAYER_FRAME;
/* ammo 1 type updates */
if (glock_mag != glock_mag_net) {
SendFlags |= PLAYER_AMMO1;
}
if (mp5_mag != mp5_mag_net) {
SendFlags |= PLAYER_AMMO1;
}
if (python_mag != python_mag_net) {
SendFlags |= PLAYER_AMMO1;
}
if (shotgun_mag != shotgun_mag_net) {
SendFlags |= PLAYER_AMMO1;
}
if (crossbow_mag != crossbow_mag_net) {
SendFlags |= PLAYER_AMMO1;
}
if (rpg_mag != rpg_mag_net) {
SendFlags |= PLAYER_AMMO1;
}
if (satchel_chg != satchel_chg_net) {
SendFlags |= PLAYER_AMMO1;
}
/* ammo 2 type updates */
if (ammo_9mm != ammo_9mm_net) {
SendFlags |= PLAYER_AMMO2;
}
if (ammo_357 != ammo_357_net) {
SendFlags |= PLAYER_AMMO2;
}
if (ammo_buckshot != ammo_buckshot_net) {
SendFlags |= PLAYER_AMMO2;
}
if (ammo_bolt != ammo_bolt_net) {
SendFlags |= PLAYER_AMMO2;
}
if (ammo_rocket != ammo_rocket_net) {
SendFlags |= PLAYER_AMMO2;
}
if (ammo_uranium != ammo_uranium_net) {
SendFlags |= PLAYER_AMMO2;
}
if (ammo_handgrenade != ammo_handgrenade_net) {
SendFlags |= PLAYER_AMMO2;
}
if (ammo_satchel != ammo_satchel_net) {
SendFlags |= PLAYER_AMMO2;
}
if (ammo_tripmine != ammo_tripmine_net) {
SendFlags |= PLAYER_AMMO2;
}
if (ammo_snark != ammo_snark_net) {
SendFlags |= PLAYER_AMMO2;
}
if (ammo_hornet != ammo_hornet_net) {
SendFlags |= PLAYER_AMMO2;
}
if (ammo_m203_grenade != ammo_m203_grenade_net) {
SendFlags |= PLAYER_AMMO3;
}
if (ammo_shotgun_state != ammo_shotgun_state_net) {
SendFlags |= PLAYER_AMMO3;
}
if (ammo_gauss_state != ammo_gauss_state_net) {
SendFlags |= PLAYER_AMMO3;
}
if (ammo_gauss_volume != ammo_gauss_volume_net) {
SendFlags |= PLAYER_AMMO3;
}
if (ammo_egon_state != ammo_egon_state_net) {
SendFlags |= PLAYER_AMMO3;
}
if (ammo_rpg_state != ammo_rpg_state_net) {
SendFlags |= PLAYER_AMMO3;
}
if (mode_tempstate != mode_tempstate_net) {
SendFlags |= PLAYER_AMMO3;
}
old_modelindex = modelindex;
old_origin = origin;
old_angles = angles;
old_angles[0] = v_angle[0];
old_velocity = velocity;
old_flags = flags;
old_gflags = gflags;
old_activeweapon = activeweapon;
old_items = g_items;
old_health = health;
old_armor = armor;
old_movetype = movetype;
old_viewofs = view_ofs[2];
old_baseframe = baseframe;
old_frame = frame;
glock_mag_net = glock_mag;
mp5_mag_net = mp5_mag;
python_mag_net = python_mag;
shotgun_mag_net = shotgun_mag;
crossbow_mag_net = crossbow_mag;
rpg_mag_net = rpg_mag;
satchel_chg_net = satchel_chg;
ammo_9mm_net = ammo_9mm;
ammo_357_net = ammo_357;
ammo_buckshot_net = ammo_buckshot;
ammo_m203_grenade_net = ammo_m203_grenade;
ammo_bolt_net = ammo_bolt;
ammo_rocket_net = ammo_rocket;
ammo_uranium_net = ammo_uranium;
ammo_handgrenade_net = ammo_handgrenade;
ammo_satchel_net = ammo_satchel;
ammo_tripmine_net = ammo_tripmine;
ammo_snark_net = ammo_snark;
ammo_hornet_net = ammo_hornet;
ammo_m203_grenade_net = ammo_m203_grenade;
ammo_shotgun_state_net = ammo_shotgun_state;
ammo_gauss_state_net = ammo_gauss_state;
ammo_gauss_volume_net = ammo_gauss_volume;
ammo_egon_state_net = ammo_egon_state;
ammo_rpg_state_net = ammo_rpg_state;
mode_tempstate_net = mode_tempstate;
/* gearbox */
if (eagle_mag_net != eagle_mag)
SendFlags |= PLAYER_AMMO1;
if (sniper_mag_net != sniper_mag)
SendFlags |= PLAYER_AMMO1;
if (m249_mag_net != m249_mag)
SendFlags |= PLAYER_AMMO1;
if (sporelauncher_mag_net != sporelauncher_mag)
SendFlags |= PLAYER_AMMO1;
if (ammo_556_net != ammo_556)
SendFlags |= PLAYER_AMMO2;
if (ammo_762_net != ammo_762)
SendFlags |= PLAYER_AMMO2;
if (ammo_spore_net != ammo_spore)
SendFlags |= PLAYER_AMMO2;
if (ammo_shock_net != ammo_shock)
SendFlags |= PLAYER_AMMO2;
if (ammo_penguin_net != ammo_penguin)
SendFlags |= PLAYER_AMMO2;
if (mode_displacer_net != mode_displacer)
SendFlags |= PLAYER_AMMO3;
if (mode_eagle_net != mode_eagle)
SendFlags |= PLAYER_AMMO3;
if (mode_wrench_net != mode_wrench)
SendFlags |= PLAYER_AMMO3;
if (mode_sporelauncher_net != mode_sporelauncher)
SendFlags |= PLAYER_AMMO3;
eagle_mag_net = eagle_mag;
sniper_mag_net = sniper_mag;
m249_mag_net = m249_mag;
sporelauncher_mag_net = sporelauncher_mag;
ammo_556_net = ammo_556;
ammo_762_net = ammo_762;
ammo_spore_net = ammo_spore;
ammo_shock_net = ammo_shock;
ammo_penguin_net = ammo_penguin;
mode_displacer_net = mode_displacer;
mode_eagle_net = mode_eagle;
mode_wrench_net = mode_wrench;
mode_sporelauncher_net = mode_sporelauncher;
mode_m249_net = mode_m249;
}
/*
=================
player::SendEntity
=================
*/
float
player::SendEntity(entity ePEnt, float fChanged)
{
if (health <= 0 && ePEnt != this) {
return FALSE;
}
if (clienttype(ePEnt) != CLIENTTYPE_REAL) {
return FALSE;
}
if (ePEnt != self) {
fChanged &= ~PLAYER_ITEMS;
fChanged &= ~PLAYER_HEALTH;
fChanged &= ~PLAYER_ARMOR;
fChanged &= ~PLAYER_VIEWOFS;
fChanged &= ~PLAYER_AMMO1;
fChanged &= ~PLAYER_AMMO2;
fChanged &= ~PLAYER_AMMO3;
}
WriteByte(MSG_ENTITY, ENT_PLAYER);
WriteFloat(MSG_ENTITY, fChanged);
/* really trying to get our moneys worth with 23 bits of mantissa */
if (fChanged & PLAYER_MODELINDEX)
WriteShort(MSG_ENTITY, modelindex);
if (fChanged & PLAYER_ORIGIN) {
WriteCoord(MSG_ENTITY, origin[0]);
WriteCoord(MSG_ENTITY, origin[1]);
}
if (fChanged & PLAYER_ORIGIN_Z)
WriteCoord(MSG_ENTITY, origin[2]);
if (fChanged & PLAYER_ANGLES_X)
WriteFloat(MSG_ENTITY, v_angle[0]);
if (fChanged & PLAYER_ANGLES_Y)
WriteFloat(MSG_ENTITY, angles[1]);
if (fChanged & PLAYER_ANGLES_Z)
WriteFloat(MSG_ENTITY, angles[2]);
if (fChanged & PLAYER_VELOCITY) {
WriteCoord(MSG_ENTITY, velocity[0]);
WriteCoord(MSG_ENTITY, velocity[1]);
}
if (fChanged & PLAYER_VELOCITY_Z)
WriteCoord(MSG_ENTITY, velocity[2]);
if (fChanged & PLAYER_FLAGS) {
WriteFloat(MSG_ENTITY, flags);
WriteFloat(MSG_ENTITY, gflags);
}
if (fChanged & PLAYER_WEAPON)
WriteByte(MSG_ENTITY, activeweapon);
if (fChanged & PLAYER_ITEMS)
WriteFloat(MSG_ENTITY, (__variant)g_items);
if (fChanged & PLAYER_HEALTH)
WriteByte(MSG_ENTITY, bound(0, health, 255));
if (fChanged & PLAYER_ARMOR)
WriteByte(MSG_ENTITY, armor);
if (fChanged & PLAYER_MOVETYPE)
WriteByte(MSG_ENTITY, movetype);
if (fChanged & PLAYER_VIEWOFS)
WriteFloat(MSG_ENTITY, view_ofs[2]);
if (fChanged & PLAYER_BASEFRAME)
WriteByte(MSG_ENTITY, baseframe);
if (fChanged & PLAYER_FRAME)
WriteByte(MSG_ENTITY, frame);
if (fChanged & PLAYER_AMMO1) {
WriteByte(MSG_ENTITY, glock_mag);
WriteByte(MSG_ENTITY, mp5_mag);
WriteByte(MSG_ENTITY, python_mag);
WriteByte(MSG_ENTITY, shotgun_mag);
WriteByte(MSG_ENTITY, crossbow_mag);
WriteByte(MSG_ENTITY, rpg_mag);
WriteByte(MSG_ENTITY, satchel_chg);
/* gearbox */
WriteByte(MSG_ENTITY, eagle_mag);
WriteByte(MSG_ENTITY, sniper_mag);
WriteByte(MSG_ENTITY, m249_mag);
WriteByte(MSG_ENTITY, sporelauncher_mag);
}
if (fChanged & PLAYER_AMMO2) {
WriteByte(MSG_ENTITY, ammo_9mm);
WriteByte(MSG_ENTITY, ammo_357);
WriteByte(MSG_ENTITY, ammo_buckshot);
WriteByte(MSG_ENTITY, ammo_bolt);
WriteByte(MSG_ENTITY, ammo_rocket);
WriteByte(MSG_ENTITY, ammo_uranium);
WriteByte(MSG_ENTITY, ammo_handgrenade);
WriteByte(MSG_ENTITY, ammo_satchel);
WriteByte(MSG_ENTITY, ammo_tripmine);
WriteByte(MSG_ENTITY, ammo_snark);
WriteByte(MSG_ENTITY, ammo_hornet);
/* gearbox */
WriteByte(MSG_ENTITY, ammo_556);
WriteByte(MSG_ENTITY, ammo_762);
WriteByte(MSG_ENTITY, ammo_spore);
WriteByte(MSG_ENTITY, ammo_shock);
WriteByte(MSG_ENTITY, ammo_penguin);
}
if (fChanged & PLAYER_AMMO3) {
WriteByte(MSG_ENTITY, ammo_m203_grenade);
WriteByte(MSG_ENTITY, ammo_shotgun_state);
WriteByte(MSG_ENTITY, ammo_gauss_state);
WriteByte(MSG_ENTITY, ammo_gauss_volume);
WriteByte(MSG_ENTITY, ammo_egon_state);
WriteByte(MSG_ENTITY, ammo_rpg_state);
WriteByte(MSG_ENTITY, mode_tempstate);
/* gearbox */
WriteByte(MSG_ENTITY, mode_displacer);
WriteByte(MSG_ENTITY, mode_eagle);
WriteByte(MSG_ENTITY, mode_wrench);
WriteByte(MSG_ENTITY, mode_sporelauncher);
WriteByte(MSG_ENTITY, mode_m249);
}
return TRUE;
}
#endif

384
src/shared/w_displacer.qc Normal file
View File

@ -0,0 +1,384 @@
/*
* 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.
*/
/*QUAKED weapon_displacer (0 0 1) (-16 -16 0) (16 16 32)
"model" "models/w_displacer.mdl"
HALF-LIFE: OPPOSING FORCE (1999) ENTITY
Displacer Weapon
*/
enum
{
DISP_IDLE1,
DISP_IDLE2,
DISP_SPINUP,
DISP_SPIN,
DISP_FIRE,
DISP_DRAW,
DISP_HOLSTER
};
#ifdef SERVER
entity Spawn_SelectRandom(string);
#endif
void
w_displacer_precache(void)
{
#ifdef SERVER
precache_sound("weapons/displacer_impact.wav");
precache_sound("weapons/displacer_fire.wav");
precache_sound("weapons/displacer_self.wav");
precache_sound("weapons/displacer_spin.wav");
precache_sound("weapons/displacer_spin2.wav");
precache_sound("weapons/displacer_start.wav");
precache_sound("weapons/displacer_teleport.wav");
precache_sound("weapons/displacer_teleport_player.wav");
precache_model("models/w_displacer.mdl");
precache_model("sprites/exit1.spr");
#else
precache_model("models/v_displacer.mdl");
precache_model("models/p_displacer.mdl");
#endif
}
void
w_displacer_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, -1, pl.ammo_uranium, -1);
}
string
w_displacer_wmodel(void)
{
return "models/w_displacer.mdl";
}
string
w_displacer_pmodel(void)
{
return "models/p_displacer.mdl";
}
string
w_displacer_deathmsg(void)
{
return "%s was assaulted by %s's Displacer.";
}
int
w_displacer_pickup(int new, int startammo)
{
#ifdef SERVER
player pl = (player)self;
if (pl.ammo_uranium < MAX_A_URANIUM) {
pl.ammo_uranium = bound(0, pl.ammo_uranium + 40, MAX_A_URANIUM);
} else {
return FALSE;
}
#endif
return TRUE;
}
void
w_displacer_draw(void)
{
#ifdef CLIENT
Weapons_SetModel("models/v_displacer.mdl");
Weapons_ViewAnimation(DISP_DRAW);
#endif
}
void
w_displacer_holster(void)
{
#ifdef CLIENT
Weapons_ViewAnimation(DISP_HOLSTER);
#endif
}
void
w_displacer_teleport(entity target)
{
#ifdef SERVER
player pl = (player)target;
/* TODO, 250 damage */
Weapons_PlaySound(pl, CHAN_WEAPON, "weapons/displacer_teleport.wav", 1, ATTN_NORM);
/* FIXME: This will teleport upon your standard spawn positions
* in other game modes, such as CTF (your team spawns), no clue
* about singleplayer */
entity spot = Spawn_SelectRandom("info_player_deathmatch");
setorigin(pl, spot.origin);
#endif
}
void
w_displacer_fireball(void)
{
#ifdef SERVER
player pl = (player)self;
static void displacerball_touch(void)
{
if (other.flags & FL_CLIENT) {
w_displacer_teleport(other);
}
Damage_Radius(self.origin, self.owner, 250, 250 * 2.5f, TRUE, WEAPON_DISPLACER);
sound(self, 1, "weapons/displacer_impact.wav", 1, ATTN_NORM);
remove(self);
}
static void displacerball_animate(void)
{
self.frame++;
if (self.frame > 25)
self.frame = 0;
self.nextthink = time + 0.1f;
}
Weapons_MakeVectors();
entity ball = spawn();
setmodel(ball, "sprites/exit1.spr");
setorigin(ball, Weapons_GetCameraPos() + (v_forward * 16));
ball.owner = self;
ball.velocity = v_forward * 500;
ball.movetype = MOVETYPE_FLYMISSILE;
ball.solid = SOLID_BBOX;
ball.angles = vectoangles(ball.velocity);
ball.touch = displacerball_touch;
ball.effects = EF_ADDITIVE;
ball.think = displacerball_animate;
ball.nextthink = time + 0.1f;
setsize(ball, [0,0,0], [0,0,0]);
sound(pl, CHAN_WEAPON, "weapons/displacer_fire.wav", 1, ATTN_NORM);
#endif
}
void
w_displacer_release(void)
{
player pl = (player)self;
if (pl.w_idle_next > 0.0) {
return;
}
if (pl.mode_displacer == 1) {
Weapons_ViewAnimation(DISP_FIRE);
w_displacer_fireball();
pl.mode_displacer = 0;
pl.w_idle_next = pl.w_attack_next = 1.0f;
pl.ammo_uranium -= 20;
return;
} else if (pl.mode_displacer == 2) {
Weapons_ViewAnimation(DISP_FIRE);
w_displacer_teleport(pl);
pl.mode_displacer = 0;
pl.w_idle_next = pl.w_attack_next = 1.0f;
pl.ammo_uranium -= 60;
return;
}
int r = (float)input_sequence % 3;
if (r == 1) {
Weapons_ViewAnimation(DISP_IDLE1);
} else {
Weapons_ViewAnimation(DISP_IDLE2);
}
pl.w_idle_next = 3.0f;
}
void
w_displacer_primary(void)
{
player pl = (player)self;
if (pl.w_attack_next > 0.0) {
return;
}
/* ammo check */
if (pl.ammo_uranium < 20) {
return;
}
/* we're already in spinning mode */
if (pl.mode_displacer > 0) {
w_displacer_release();
return;
}
pl.mode_displacer = 1;
#ifdef CLIENT
Weapons_ViewAnimation(DISP_SPINUP);
#else
Weapons_PlaySound(pl, CHAN_WEAPON, "weapons/displacer_spin.wav", 1, ATTN_NORM);
#endif
pl.w_idle_next = pl.w_attack_next = 1.0f;
}
void
w_displacer_secondary(void)
{
player pl = (player)self;
if (pl.w_attack_next > 0.0) {
return;
}
if (pl.ammo_uranium < 60) {
return;
}
/* we're already in spinning mode */
if (pl.mode_displacer > 0) {
w_displacer_release();
return;
}
pl.mode_displacer = 2;
#ifdef CLIENT
Weapons_ViewAnimation(DISP_SPINUP);
#else
Weapons_PlaySound(pl, CHAN_WEAPON, "weapons/displacer_spin2.wav", 1, ATTN_NORM);
#endif
pl.w_idle_next = pl.w_attack_next = 1.0f;
}
float
w_displacer_aimanim(void)
{
return self.flags & FL_CROUCHING ? ANIM_CR_AIMSQUEAK : ANIM_AIMSQUEAK;
}
void
w_displacer_hud(void)
{
#ifdef CLIENT
vector cross_pos;
vector aicon_pos;
cross_pos = g_hudmins + (g_hudres / 2) + [-12,-12];
aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42];
drawsubpic(
cross_pos,
[24,24],
"sprites/ofch1.spr_0.tga",
[48/72,0],
[24/72,24/72],
[1,1,1],
1,
DRAWFLAG_NORMAL
);
drawsubpic(
aicon_pos,
[24,24],
"sprites/640hud7.spr_0.tga",
[0,96/128], // was [24/256,72/128]... which makes 0 sense
[24/256, 24/128],
g_hud_color,
pSeat->m_flAmmo2Alpha,
DRAWFLAG_ADDITIVE
);
HUD_DrawAmmo2();
#endif
}
void
w_displacer_hudpic(int selected, vector pos, float a)
{
#ifdef CLIENT
player pl = (player)self;
vector hud_col;
if (pl.ammo_uranium == 0)
hud_col = [1,0,0];
else
hud_col = g_hud_color;
HUD_DrawAmmoBar(pos, pl.ammo_uranium, MAX_A_URANIUM, a);
if (selected) {
drawsubpic(
pos,
[170,45],
"sprites/640hudof02.spr_0.tga",
[0,180/256],
[170/256,45/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[170,45],
"sprites/640hudof01.spr_0.tga",
[0,180/256],
[170/256,45/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
}
#endif
}
weapon_t w_displacer =
{
.name = "displacer",
.id = ITEM_DISPLACER,
.slot = 5,
.slot_pos = 1,
.draw = w_displacer_draw,
.holster = w_displacer_holster,
.primary = w_displacer_primary,
.secondary = w_displacer_secondary,
.reload = __NULL__,
.release = w_displacer_release,
.crosshair = w_displacer_hud,
.precache = w_displacer_precache,
.pickup = w_displacer_pickup,
.updateammo = w_displacer_updateammo,
.wmodel = w_displacer_wmodel,
.pmodel = w_displacer_pmodel,
.deathmsg = w_displacer_deathmsg,
.aimanim = w_displacer_aimanim,
.hudpic = w_displacer_hudpic
};
/* entity definitions for pickups */
#ifdef SERVER
void
weapon_displacer(void)
{
Weapons_InitItem(WEAPON_DISPLACER);
}
#endif

412
src/shared/w_eagle.qc Normal file
View File

@ -0,0 +1,412 @@
/*
* 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.
*/
/*QUAKED weapon_eagle (0 0 1) (-16 -16 0) (16 16 32)
"model" "models/w_desert_eagle.mdl"
HALF-LIFE: OPPOSING FORCE (1999) ENTITY
Desert Eagle Weapon
*/
enum
{
EAGLE_IDLE1,
EAGLE_IDLE2,
EAGLE_IDLE3,
EAGLE_IDLE4,
EAGLE_IDLE5,
EAGLE_SHOOT,
EAGLE_SHOOT_EMPTY,
EAGLE_RELOAD,
EAGLE_RELOAD_NOSHOT,
EAGLE_DRAW,
EAGLE_HOLSTER
};
void
w_eagle_precache(void)
{
#ifdef SERVER
precache_model("models/w_desert_eagle.mdl");
precache_sound("weapons/desert_eagle_fire.wav");
precache_sound("weapons/desert_eagle_sight.wav");
precache_sound("weapons/desert_eagle_sight2.wav");
#else
precache_model("models/v_desert_eagle.mdl");
precache_model("models/p_desert_eagle.mdl");
#endif
}
int
w_eagle_pickup(int new, int startammo)
{
#ifdef SERVER
player pl = (player)self;
if (new) {
pl.eagle_mag = 7;
} else {
if (pl.ammo_357 < MAX_A_357) {
pl.ammo_357 = bound(0, pl.ammo_357 + 7, MAX_A_357);
} else {
return FALSE;
}
}
#endif
return TRUE;
}
void
w_eagle_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, pl.eagle_mag, pl.ammo_357, -1);
}
string
w_eagle_wmodel(void)
{
return "models/w_desert_eagle.mdl";
}
string
w_eagle_pmodel(void)
{
return "models/p_desert_eagle.mdl";
}
string
w_eagle_deathmsg(void)
{
return "";
}
void
w_eagle_draw(void)
{
#ifdef CLIENT
Weapons_SetModel("models/v_desert_eagle.mdl");
Weapons_ViewAnimation(EAGLE_DRAW);
#else
player pl = (player)self;
Weapons_UpdateAmmo(pl, pl.eagle_mag, pl.ammo_357, -1);
#endif
}
void
w_eagle_holster(void)
{
Weapons_ViewAnimation(EAGLE_HOLSTER);
}
void
w_eagle_release(void)
{
player pl = (player)self;
/* auto-reload if need be */
if (pl.w_attack_next <= 0.0)
if (pl.eagle_mag == 0 && pl.ammo_357 > 0) {
Weapons_Reload();
return;
}
if (pl.w_idle_next) {
return;
}
/* these idles don't support the 'empty' animation style */
#ifdef CLIENT
if (pl.eagle_mag <= 0) {
return;
}
#else
if (pl.eagle_mag <= 0) {
return;
}
#endif
int r = (float)input_sequence % 4;
switch (r) {
case 0:
Weapons_ViewAnimation(EAGLE_IDLE1);
pl.w_idle_next = 2.5f;
break;
case 1:
Weapons_ViewAnimation(EAGLE_IDLE2);
pl.w_idle_next = 2.5f;
break;
case 2:
Weapons_ViewAnimation(EAGLE_IDLE3);
pl.w_idle_next = 1.633333f;
break;
default:
Weapons_ViewAnimation(EAGLE_IDLE4);
pl.w_idle_next = 2.5f;
}
}
void
w_eagle_primary(void)
{
player pl = (player)self;
if (pl.w_attack_next > 0.0) {
return;
}
/* Ammo check */
#ifdef CLIENT
if (pl.eagle_mag <= 0) {
return;
}
#else
if (pl.eagle_mag <= 0) {
return;
}
#endif
/* Actual firing */
if (pl.mode_eagle == 1) {
#ifdef SERVER
TraceAttack_FireBullets(1, pl.origin + pl.view_ofs, 34, [0, 0], WEAPON_EAGLE);
#endif
pl.w_attack_next = 0.5f;
} else {
#ifdef SERVER
TraceAttack_FireBullets(1, pl.origin + pl.view_ofs, 34, [0.1,0.1], WEAPON_EAGLE);
#endif
pl.w_attack_next = 0.2f;
}
#ifdef SERVER
sound(pl, CHAN_WEAPON, "weapons/desert_eagle_fire.wav", 1, ATTN_NORM);
pl.eagle_mag--;
Weapons_UpdateAmmo(pl, pl.eagle_mag, pl.ammo_357, -1);
#else
pl.eagle_mag--;
View_SetMuzzleflash(MUZZLE_SMALL);
Weapons_ViewPunchAngle([-10,0,0]);
if (pl.eagle_mag <= 0) {
Weapons_ViewAnimation(EAGLE_SHOOT_EMPTY);
} else {
Weapons_ViewAnimation(EAGLE_SHOOT);
}
#endif
}
void
w_eagle_secondary(void)
{
player pl = (player)self;
if (pl.w_attack_next > 0.0) {
return;
}
/* toggle laser */
pl.mode_eagle = 1 - pl.mode_eagle;
#ifdef SERVER
if (pl.mode_eagle) {
sound(pl, 8, "weapons/desert_eagle_sight.wav", 1, ATTN_NORM);
} else {
sound(pl, 8, "weapons/desert_eagle_sight2.wav", 1, ATTN_NORM);
}
#endif
pl.w_attack_next = 1.0f;
w_eagle_release();
}
void
w_eagle_reload(void)
{
player pl = (player)self;
if (pl.w_attack_next > 0.0) {
return;
}
/* Ammo check */
#ifdef CLIENT
if (pl.eagle_mag >= 7) {
return;
}
if (pl.ammo_357 <= 0) {
return;
}
#else
if (pl.eagle_mag >= 7) {
return;
}
if (pl.ammo_357 <= 0) {
return;
}
#endif
/* Audio-Visual bit */
#ifdef CLIENT
if (pl.eagle_mag <= 0) {
Weapons_ViewAnimation(EAGLE_RELOAD);
} else {
Weapons_ViewAnimation(EAGLE_RELOAD_NOSHOT);
}
#else
Weapons_ReloadWeapon(pl, player::eagle_mag, player::ammo_357, 7);
Weapons_UpdateAmmo(pl, pl.eagle_mag, pl.ammo_357, -1);
#endif
pl.w_attack_next = 1.64f;
pl.w_idle_next = 10.0f;
}
void
w_eagle_crosshair(void)
{
#ifdef CLIENT
player pl = (player)self;
vector cross_pos;
vector aicon_pos;
/* crosshair/laser */
if (pl.mode_eagle == 1) {
float lerp;
vector jitter;
Weapons_MakeVectors();
vector src = pl.origin + pl.view_ofs;
traceline(src, src + (v_forward * 256), FALSE, pl);
lerp = Math_Lerp(18,6, trace_fraction);
jitter[0] = (random(0,2) - 2) * (1 - trace_fraction);
jitter[1] = (random(0,2) - 2) * (1 - trace_fraction);
cross_pos = g_hudmins + (g_hudres / 2) + ([-lerp,-lerp] / 2);
drawsubpic(
cross_pos + jitter,
[lerp,lerp],
"sprites/laserdot.spr_0.tga",
[0,0],
[1.0, 1.0],
[1,1,1],
1.0f,
DRAWFLAG_ADDITIVE
);
} else {
cross_pos = g_hudmins + (g_hudres / 2) + [-12,-12];
drawsubpic(
cross_pos,
[24,24],
"sprites/ofch1.spr_0.tga",
[0,0],
[24/72, 24/72],
[1,1,1],
1,
DRAWFLAG_NORMAL
);
}
/* ammo counters */
HUD_DrawAmmo1();
HUD_DrawAmmo2();
/* ammo icon */
aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42];
drawsubpic(
aicon_pos,
[24,24],
"sprites/640hud7.spr_0.tga",
[24/256,72/128],
[24/256, 24/128],
g_hud_color,
pSeat->m_flAmmo2Alpha,
DRAWFLAG_ADDITIVE
);
#endif
}
float
w_eagle_aimanim(void)
{
return self.flags & FL_CROUCHING ? ANIM_CR_AIMPYTHON : ANIM_AIMPYTHON;
}
void
w_eagle_hudpic(int selected, vector pos, float a)
{
#ifdef CLIENT
player pl = (player)self;
vector hud_col;
if (pl.eagle_mag == 0 && pl.ammo_357 == 0)
hud_col = [1,0,0];
else
hud_col = g_hud_color;
if (selected) {
drawsubpic(
pos,
[170,45],
"sprites/640hudof02.spr_0.tga",
[0,90/256],
[170/256,45/256],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[170,45],
"sprites/640hudof01.spr_0.tga",
[0,90/256],
[170/256,45/256],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
}
HUD_DrawAmmoBar(pos, pl.ammo_357, MAX_A_357, a);
#endif
}
weapon_t w_eagle =
{
.name = "eagle",
.id = ITEM_EAGLE,
.slot = 1,
.slot_pos = 2,
.draw = w_eagle_draw,
.holster = w_eagle_holster,
.primary = w_eagle_primary,
.secondary = w_eagle_secondary,
.reload = w_eagle_reload,
.release = w_eagle_release,
.crosshair = w_eagle_crosshair,
.precache = w_eagle_precache,
.pickup = w_eagle_pickup,
.updateammo = w_eagle_updateammo,
.wmodel = w_eagle_wmodel,
.pmodel = w_eagle_pmodel,
.deathmsg = w_eagle_deathmsg,
.aimanim = w_eagle_aimanim,
.hudpic = w_eagle_hudpic
};
#ifdef SERVER
void
weapon_eagle(void)
{
Weapons_InitItem(WEAPON_EAGLE);
}
#endif

314
src/shared/w_grapple.qc Normal file
View File

@ -0,0 +1,314 @@
/*
* 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.
*/
/*QUAKED weapon_grapple (0 0 1) (-16 -16 0) (16 16 32)
"model" "models/w_bgrap.mdl"
HALF-LIFE: OPPOSING FORCE (1999) ENTITY
Barnacle Grappling-Hook Weapon
*/
#ifdef CLIENT
/* because some people apparently prefer the worse quality one */
var int autocvar_cl_tonguemode = 0;
#endif
enum
{
BARN_IDLE1,
BARN_IDLE2,
BARN_IDLE3,
BARN_COUGH,
BARN_HOLSTER,
BARN_DRAW,
BARN_FIRE,
BARN_FIREWAIT,
BARN_FIREREACH,
BARN_FIRETRAVEL,
BARN_FIRERELEASE
};
void
w_grapple_precache(void)
{
#ifdef SERVER
precache_sound("weapons/bgrapple_cough.wav");
precache_sound("weapons/bgrapple_fire.wav");
precache_sound("weapons/bgrapple_impact.wav");
precache_sound("weapons/bgrapple_pull.wav");
precache_sound("weapons/bgrapple_release.wav");
precache_sound("weapons/bgrapple_wait.wav");
precache_model("sprites/_tongue.spr");
precache_model("sprites/tongue.spr");
precache_model("models/w_bgrap.mdl");
#else
precache_model("models/v_bgrap.mdl");
precache_model("models/v_bgrap_tonguetip.mdl");
precache_model("models/p_bgrap.mdl");
#endif
}
void
w_grapple_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, -1, -1, -1);
}
string
w_grapple_wmodel(void)
{
return "models/w_bgrap.mdl";
}
string
w_grapple_pmodel(void)
{
return "models/p_bgrap.mdl";
}
string
w_grapple_deathmsg(void)
{
return "%s was assaulted by %s's Barnacle.";
}
void
w_grapple_draw(void)
{
Weapons_SetModel("models/v_bgrap.mdl");
Weapons_ViewAnimation(BARN_DRAW);
}
void
w_grapple_holster(void)
{
Weapons_ViewAnimation(BARN_HOLSTER);
}
/* called once the tongue hits a wall */
void Grapple_Touch(void)
{
player pl = (player)self.owner;
pl.hook.movetype = MOVETYPE_NONE;
pl.hook.touch = __NULL__;
pl.hook.velocity = [0,0,0];
pl.hook.solid = SOLID_NOT;
pl.a_ammo1 = 1;
}
#ifdef CLIENT
/* draw the tongue from a to b */
float
grapple_predraw(void)
{
vector forg = gettaginfo(pSeat->m_eViewModel, pSeat->m_iVMBones);
vector morg = self.origin;
vector fsize = [3,3];
vector col1 = getlight(forg) / 255;
vector col2 = getlight(morg) / 255;
makevectors(view_angles);
R_BeginPolygon(autocvar_cl_tonguemode == 1 ? "sprites/_tongue.spr_0.tga" : "sprites/tongue.spr_0.tga", 0, 0);
R_PolygonVertex(forg + v_right * fsize[0] - v_up * fsize[1],
[1,1], col1, 1.0f);
R_PolygonVertex(forg - v_right * fsize[0] - v_up * fsize[1],
[0,1], col1, 1.0f);
R_PolygonVertex(morg - v_right * fsize[0] + v_up * fsize[1],
[0,0], col2, 1.0f);
R_PolygonVertex(morg + v_right * fsize[0] + v_up * fsize[1],
[1,0], col2, 1.0f);
R_EndPolygon();
addentity(self);
return PREDRAW_NEXT;
}
#endif
/* spawn and pull */
void
w_grapple_primary(void)
{
player pl = (player)self;
if (pl.hook != __NULL__) {
/* play the looping reel anim once */
if (pl.a_ammo1 == 1) {
pl.a_ammo1 = 2;
Weapons_ViewAnimation(BARN_FIRETRAVEL);
} else if (pl.a_ammo1 == 2) {
pl.hook.skin = 1; /* grappled */
}
if (pl.w_attack_next > 0.0) {
return;
}
#ifdef SERVER
Weapons_MakeVectors();
vector src = Weapons_GetCameraPos();
traceline(src, src + (v_forward * 32), FALSE, pl);
if (trace_ent.takedamage == DAMAGE_YES && trace_ent.iBleeds) {
Damage_Apply(trace_ent, pl, 25, WEAPON_GRAPPLE, DMG_GENERIC);
}
#endif
pl.w_attack_next = 0.5f;
return;
}
Weapons_MakeVectors();
pl.hook = spawn();
#ifdef CLIENT
/*setmodel(pl.hook, "models/v_bgrap_tonguetip.mdl");*/
pl.hook.drawmask = MASK_ENGINE;
pl.hook.predraw = grapple_predraw;
#else
sound(pl, CHAN_WEAPON, "weapons/bgrapple_fire.wav", 1.0, ATTN_NORM);
sound(pl, CHAN_VOICE, "weapons/bgrapple_pull.wav", 1.0, ATTN_NORM);
#endif
setorigin(pl.hook, Weapons_GetCameraPos() + (v_forward * 16));
pl.hook.owner = self;
pl.hook.velocity = v_forward * 1500;
pl.hook.movetype = MOVETYPE_FLYMISSILE;
pl.hook.solid = SOLID_BBOX;
pl.hook.angles = vectoangles(pl.hook.velocity);
pl.hook.touch = Grapple_Touch;
setsize(pl.hook, [0,0,0], [0,0,0]);
Weapons_ViewAnimation(BARN_FIRE);
}
/* let go, hang */
void
w_grapple_secondary(void)
{
player pl = (player)self;
if (pl.hook == __NULL__) {
return;
}
pl.hook.skin = 0; /* ungrappled */
}
/* de-spawn and play idle anims */
void
w_grapple_release(void)
{
player pl = (player)self;
if (pl.hook != __NULL__) {
pl.a_ammo1 = 0; /* cache */
pl.hook.skin = 0; /* ungrappled */
remove(pl.hook);
#ifdef CLIENT
Weapons_ViewAnimation(BARN_FIRERELEASE);
#else
sound(pl, CHAN_VOICE, "weapons/bgrapple_release.wav", 1.0, ATTN_NORM);
#endif
pl.w_idle_next = 1.0f;
pl.hook = __NULL__;
}
if (pl.w_idle_next > 0.0) {
return;
}
int r = (float)input_sequence % 3;
switch (r) {
case 1:
Weapons_ViewAnimation(BARN_IDLE1);
pl.w_idle_next = 2.566667f;
break;
case 2:
Weapons_ViewAnimation(BARN_IDLE2);
pl.w_idle_next = 10.0f;
break;
default:
Weapons_ViewAnimation(BARN_IDLE3);
pl.w_idle_next = 1.35f;
break;
}
}
float
w_grapple_aimanim(void)
{
return self.flags & FL_CROUCHING ? ANIM_CR_AIMSQUEAK : ANIM_AIMSQUEAK;
}
void
w_grapple_hudpic(int selected, vector pos, float a)
{
#ifdef CLIENT
if (selected) {
drawsubpic(
pos,
[170,45],
"sprites/640hudof02.spr_0.tga",
[0,45/256],
[170/256,45/256],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[170,45],
"sprites/640hudof01.spr_0.tga",
[0,45/256],
[170/256,45/256],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
}
#endif
}
weapon_t w_grapple =
{
.name = "grapple",
.id = ITEM_GRAPPLE,
.slot = 0,
.slot_pos = 3,
.draw = w_grapple_draw,
.holster = w_grapple_holster,
.primary = w_grapple_primary,
.secondary = w_grapple_secondary,
.reload = __NULL__,
.release = w_grapple_release,
.crosshair = __NULL__,
.precache = w_grapple_precache,
.pickup = __NULL__,
.updateammo = w_grapple_updateammo,
.wmodel = w_grapple_wmodel,
.pmodel = w_grapple_pmodel,
.deathmsg = w_grapple_deathmsg,
.aimanim = w_grapple_aimanim,
.hudpic = w_grapple_hudpic
};
/* entity definitions for pickups */
#ifdef SERVER
void
weapon_grapple(void)
{
Weapons_InitItem(WEAPON_GRAPPLE);
}
#endif

275
src/shared/w_knife.qc Normal file
View File

@ -0,0 +1,275 @@
/*
* 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.
*/
/*QUAKED weapon_knife (0 0 1) (-16 -16 0) (16 16 32)
"model" "models/w_knife.mdl"
HALF-LIFE: OPPOSING FORCE (1999) ENTITY
Knife Weapon
*/
enum
{
KNIFE_IDLE1,
KNIFE_DRAW,
KNIFE_HOLSTER,
KNIFE_ATTACK1HIT,
KNIFE_ATTACK1MISS,
KNIFE_ATTACK2MISS,
KNIFE_ATTACK2HIT,
KNIFE_ATTACK3MISS,
KNIFE_ATTACK3HIT,
KNIFE_IDLE2,
KNIFE_IDLE3
};
void
w_knife_precache(void)
{
#ifdef SERVER
precache_model("models/w_knife.mdl");
precache_sound("weapons/knife1.wav");
precache_sound("weapons/knife2.wav");
precache_sound("weapons/knife3.wav");
precache_sound("weapons/knife_hit_wall1.wav");
precache_sound("weapons/knife_hit_wall2.wav");
precache_sound("weapons/knife_hit_flesh1.wav");
precache_sound("weapons/knife_hit_flesh2.wav");
#else
precache_model("models/v_knife.mdl");
precache_model("models/p_knife.mdl");
#endif
}
void
w_knife_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, -1, -1, -1);
}
string
w_knife_wmodel(void)
{
return "models/w_knife.mdl";
}
string
w_knife_pmodel(void)
{
return "models/p_knife.mdl";
}
string
w_knife_deathmsg(void)
{
return "%s was assaulted by %s's Knife.";
}
void
w_knife_draw(void)
{
Weapons_SetModel("models/v_knife.mdl");
Weapons_ViewAnimation(KNIFE_DRAW);
}
void
w_knife_holster(void)
{
Weapons_ViewAnimation(KNIFE_HOLSTER);
}
void
w_knife_primary(void)
{
int anim = 0;
int r;
vector src;
player pl = (player)self;
if (pl.w_attack_next) {
return;
}
Weapons_MakeVectors();
src = pl.origin + pl.view_ofs;
traceline(src, src + (v_forward * 32), FALSE, pl);
if (trace_fraction >= 1.0) {
pl.w_attack_next = 0.5f;
} else {
pl.w_attack_next = 0.25f;
}
pl.w_idle_next = 2.5f;
#ifdef CLIENT
r = (float)input_sequence % 3;
switch (r) {
case 0:
anim = trace_fraction >= 1 ? KNIFE_ATTACK1MISS:KNIFE_ATTACK1HIT;
break;
case 1:
anim = trace_fraction >= 1 ? KNIFE_ATTACK2MISS:KNIFE_ATTACK2HIT;
break;
default:
anim = trace_fraction >= 1 ? KNIFE_ATTACK3MISS:KNIFE_ATTACK3HIT;
}
Weapons_ViewAnimation(anim);
#else
if (pl.flags & FL_CROUCHING) {
Animation_PlayerTopTemp(ANIM_SHOOTCROWBAR, 0.5f);
} else {
Animation_PlayerTopTemp(ANIM_CR_SHOOTCROWBAR, 0.42f);
}
r = (float)input_sequence % 3;
switch (r) {
case 0:
sound(pl, CHAN_WEAPON, "weapons/knife1.wav", 1, ATTN_NORM);
break;
case 1:
sound(pl, CHAN_WEAPON, "weapons/knife2.wav", 1, ATTN_NORM);
break;
default:
sound(pl, CHAN_WEAPON, "weapons/knife3.wav", 1, ATTN_NORM);
}
if (trace_fraction >= 1.0) {
return;
}
/* don't bother with decals, we got squibs */
if (trace_ent.iBleeds) {
FX_Blood(trace_endpos, [1,0,0]);
} else {
FX_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal);
}
if (trace_ent.takedamage) {
Damage_Apply(trace_ent, self, 10, WEAPON_KNIFE, DMG_SLASH);
if (!trace_ent.iBleeds) {
return;
}
if (random() < 0.5) {
sound(pl, 8, "weapons/knife_hit_flesh1.wav", 1, ATTN_NORM);
} else {
sound(pl, 8, "weapons/knife_hit_flesh2.wav", 1, ATTN_NORM);
}
} else {
if (random() < 0.5) {
sound(pl, 8, "weapons/knife_hit_wall1.wav", 1, ATTN_NORM);
} else {
sound(pl, 8, "weapons/knife_hit_wall2.wav", 1, ATTN_NORM);
}
}
#endif
}
void
w_knife_release(void)
{
int r;
player pl = (player)self;
if (pl.w_idle_next) {
return;
}
r = (float)input_sequence % 3;
switch (r) {
case 0:
Weapons_ViewAnimation(KNIFE_IDLE1);
pl.w_idle_next = 2.7f;
break;
case 1:
Weapons_ViewAnimation(KNIFE_IDLE2);
pl.w_idle_next = 5.3f;
break;
default:
Weapons_ViewAnimation(KNIFE_IDLE3);
pl.w_idle_next = 5.3f;
}
}
float
w_knife_aimanim(void)
{
return self.flags & FL_CROUCHING ? ANIM_CR_AIMCROWBAR : ANIM_AIMCROWBAR;
}
void
w_knife_hudpic(int selected, vector pos, float a)
{
#ifdef CLIENT
if (selected) {
drawsubpic(
pos,
[170,45],
"sprites/640hudof04.spr_0.tga",
[0,90/256],
[170/256,45/256],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[170,45],
"sprites/640hudof03.spr_0.tga",
[0,90/256],
[170/256,45/256],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
}
#endif
}
weapon_t w_knife =
{
.name = "knife",
.id = ITEM_KNIFE,
.slot = 0,
.slot_pos = 2,
.draw = w_knife_draw,
.holster = w_knife_holster,
.primary = w_knife_primary,
.secondary = __NULL__,
.reload = __NULL__,
.release = w_knife_release,
.crosshair = __NULL__,
.precache = w_knife_precache,
.pickup = __NULL__,
.updateammo = w_knife_updateammo,
.wmodel = w_knife_wmodel,
.pmodel = w_knife_pmodel,
.deathmsg = w_knife_deathmsg,
.aimanim = w_knife_aimanim,
.hudpic = w_knife_hudpic
};
/* entity definitions for pickups */
#ifdef SERVER
void weapon_knife(void)
{
Weapons_InitItem(WEAPON_KNIFE);
}
#endif

352
src/shared/w_m249.qc Normal file
View File

@ -0,0 +1,352 @@
/*
* 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.
*/
/*QUAKED weapon_m249 (0 0 1) (-16 -16 0) (16 16 32)
"model" "models/w_saw.mdl"
HALF-LIFE: OPPOSING FORCE (1999) ENTITY
M249 Weapon
*/
/* Animations */
enum
{
M249_IDLE1,
M249_IDLE2,
M249_RELOAD1,
M249_RELOAD2,
M249_HOLSTER,
M249_DRAW,
M249_FIRE
};
void
w_m249_precache(void)
{
#ifdef SERVER
precache_model("models/w_saw.mdl");
precache_sound("weapons/saw_fire1.wav");
precache_sound("weapons/saw_fire2.wav");
precache_sound("weapons/saw_fire3.wav");
precache_sound("weapons/saw_reload.wav");
precache_sound("weapons/saw_reload2.wav");
#else
precache_model("models/v_saw.mdl");
precache_model("models/p_saw.mdl");
#endif
}
int
w_m249_pickup(int new, int startammo)
{
#ifdef SERVER
player pl = (player)self;
if (new) {
pl.m249_mag = 50;
} else {
if (pl.ammo_556 < MAX_A_556) {
pl.ammo_556 = bound(0, pl.ammo_556 + 50, MAX_A_556);
} else {
return FALSE;
}
}
#endif
return TRUE;
}
void
w_m249_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, pl.m249_mag, pl.ammo_556, -1);
}
string
w_m249_wmodel(void)
{
return "models/w_saw.mdl";
}
string
w_m249_pmodel(void)
{
return "models/p_saw.mdl";
}
string
w_m249_deathmsg(void)
{
return "";
}
void
w_m249_draw(void)
{
#ifdef CLIENT
Weapons_SetModel("models/v_saw.mdl");
Weapons_ViewAnimation(M249_DRAW);
#endif
}
void
w_m249_holster(void)
{
Weapons_ViewAnimation(M249_DRAW);
}
void
w_m249_release(void)
{
player pl = (player)self;
/* auto-reload if need be */
if (pl.w_attack_next <= 0.0)
if (pl.m249_mag == 0 && pl.ammo_556 > 0) {
Weapons_Reload();
return;
}
if (pl.w_idle_next > 0.0) {
return;
}
if (pl.mode_m249 == 1) {
Weapons_ViewAnimation(M249_RELOAD2);
pl.mode_m249 = 0;
pl.w_attack_next = 2.45f;
pl.w_idle_next = 15.0f;
return;
}
if (random() < 0.5) {
Weapons_ViewAnimation(M249_IDLE1);
} else {
Weapons_ViewAnimation(M249_IDLE2);
}
pl.w_idle_next = 15.0f;
}
void
w_m249_primary(void)
{
player pl = (player)self;
vector push;
if (pl.mode_m249 == 1) {
w_m249_release();
return;
}
if (pl.w_attack_next > 0.0) {
return;
}
/* ammo check */
#ifdef CLIENT
if (pl.m249_mag <= 0) {
return;
}
#else
if (pl.m249_mag <= 0) {
return;
}
#endif
Weapons_ViewAnimation(M249_FIRE);
push = v_forward * -64;
push[2] *= 0.25f; /* gravity duh */
pl.velocity += push;
/* actual firing */
#ifdef CLIENT
pl.m249_mag--;
View_SetMuzzleflash(MUZZLE_RIFLE);
Weapons_ViewPunchAngle([-5,0,0]);
#else
TraceAttack_FireBullets(1, pl.origin + pl.view_ofs, 8, [0.052,0.052], WEAPON_M249);
int r = (float)input_sequence % 3;
switch (r) {
case 0:
Weapons_PlaySound(pl, CHAN_WEAPON, "weapons/saw_fire1.wav", 1, ATTN_NORM);
break;
case 1:
Weapons_PlaySound(pl, CHAN_WEAPON, "weapons/saw_fire2.wav", 1, ATTN_NORM);
break;
default:
Weapons_PlaySound(pl, CHAN_WEAPON, "weapons/saw_fire3.wav", 1, ATTN_NORM);
}
pl.m249_mag--;
#endif
pl.w_attack_next = 0.075f;
pl.w_idle_next = 10.0f;
}
void
w_m249_reload(void)
{
player pl = (player)self;
if (pl.w_attack_next > 0.0) {
w_m249_release();
return;
}
#ifdef CLIENT
if (pl.m249_mag >= 50) {
return;
}
if (pl.ammo_556 <= 0) {
return;
}
Weapons_ViewAnimation(M249_RELOAD1);
#else
if (pl.m249_mag >= 50) {
return;
}
if (pl.ammo_556 <= 0) {
return;
}
Weapons_ReloadWeapon(pl, player::m249_mag, player::ammo_556, 50);
Weapons_UpdateAmmo(pl, pl.m249_mag, pl.ammo_556, __NULL__);
#endif
pl.mode_m249 = 1;
pl.w_attack_next = pl.w_idle_next = 1.5f;
}
void
w_m249_crosshair(void)
{
#ifdef CLIENT
vector cross_pos;
vector aicon_pos;
/* crosshair */
cross_pos = g_hudmins + (g_hudres / 2) + [-12,-12];
drawsubpic(
cross_pos,
[24,24],
"sprites/ofch1.spr_0.tga",
[24/72,0],
[24/72, 24/72],
[1,1,1],
1.0,
DRAWFLAG_NORMAL
);
/* ammo counters */
HUD_DrawAmmo1();
HUD_DrawAmmo2();
/* ammo icon */
aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42];
drawsubpic(
aicon_pos,
[24,24],
"sprites/640hud7.spr_0.tga",
[24/128,72/128],
[24/256, 24/128],
g_hud_color,
pSeat->m_flAmmo2Alpha,
DRAWFLAG_ADDITIVE
);
#endif
}
float
w_m249_aimanim(void)
{
return self.flags & ANIM_CR_AIMMP5 ? ANIM_CR_AIMCROWBAR : ANIM_AIMMP5;
}
void
w_m249_hudpic(int selected, vector pos, float a)
{
#ifdef CLIENT
player pl = (player)self;
vector hud_col;
if (pl.m249_mag == 0 && pl.ammo_556 == 0)
hud_col = [1,0,0];
else
hud_col = g_hud_color;
HUD_DrawAmmoBar(pos, pl.ammo_556, MAX_A_556, a);
if (selected) {
drawsubpic(
pos,
[170,45],
"sprites/640hudof02.spr_0.tga",
[0,135/256],
[170/256,45/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[170,45],
"sprites/640hudof01.spr_0.tga",
[0,135/256],
[170/256,45/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
}
#endif
}
weapon_t w_m249 =
{
.name = "m249",
.id = ITEM_M249,
.slot = 5,
.slot_pos = 0,
.draw = w_m249_draw,
.holster = w_m249_holster,
.primary = w_m249_primary,
.secondary = __NULL__,
.reload = w_m249_reload,
.release = w_m249_release,
.crosshair = w_m249_crosshair,
.precache = w_m249_precache,
.pickup = w_m249_pickup,
.updateammo = w_m249_updateammo,
.wmodel = w_m249_wmodel,
.pmodel = w_m249_pmodel,
.deathmsg = w_m249_deathmsg,
.aimanim = w_m249_aimanim,
.hudpic = w_m249_hudpic
};
#ifdef SERVER
void
weapon_m249(void)
{
Weapons_InitItem(WEAPON_M249);
}
#endif

375
src/shared/w_penguin.qc Normal file
View File

@ -0,0 +1,375 @@
/*
* 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.
*/
/*QUAKED weapon_penguin (0 0 1) (-16 -16 0) (16 16 32)
"model" "models/w_penguin.mdl"
HALF-LIFE: OPPOSING FORCE (1999) ENTITY
Penguin Weapon
*/
enum
{
PENGUIN_IDLE,
PENGUIN_FIDGET1,
PENGUIN_FIDGET2,
PENGUIN_HOLSTER,
PENGUIN_DRAW,
PENGUIN_THROW
};
int
w_penguin_pickup(int new, int startammo)
{
#ifdef SERVER
player pl = (player)self;
if (pl.ammo_penguin < MAX_A_PENGUIN) {
pl.ammo_penguin = bound(0, pl.ammo_penguin + 3, MAX_A_PENGUIN);
} else {
return FALSE;
}
#endif
return TRUE;
}
void
w_penguin_draw(void)
{
Weapons_SetModel("models/v_penguin.mdl");
Weapons_ViewAnimation(PENGUIN_DRAW);
}
void
w_penguin_holster(void)
{
}
#ifdef SERVER
void penguin_squeak(entity p)
{
int r = floor(random(1,4));
switch (r) {
case 1:
sound(p, CHAN_VOICE, "squeek/sqk_hunt1.wav", 1.0, ATTN_NORM);
break;
case 2:
sound(p, CHAN_VOICE, "squeek/sqk_hunt2.wav", 1.0, ATTN_NORM);
break;
default:
sound(p, CHAN_VOICE, "squeek/sqk_hunt3.wav", 1.0, ATTN_NORM);
}
}
void
penguin_ai(void)
{
input_movevalues = [250,0,0];
input_buttons = 0;
input_impulse = 0;
input_angles = self.angles;
input_timelength = frametime;
if (self.health <= 0) {
return;
}
if (self.weapon <= 0.0 && self.aiment == __NULL__) {
entity ef;
float shortest = 999999;
for (ef = world; (ef = findfloat(ef, movetype, MOVETYPE_WALK));) {
float len = vlen(ef.origin - self.origin);
if (ef.classname != "snark" && len < shortest && ef.health > 0) {
self.owner = __NULL__;
self.aiment = ef;
shortest = len;
}
}
}
if (self.aiment) {
self.angles = input_angles = vectoangles(self.aiment.origin - self.origin);
}
if (self.aiment && self.weapon <= 0.0) {
self.weapon = 0.5f + random();
penguin_squeak(self);
input_buttons = 2;
Damage_Apply(self, world, 1, 0, DMG_GENERIC);
makevectors(self.angles);
traceline(self.origin, self.origin + (v_forward * 128), 0, self);
if (trace_ent.takedamage == DAMAGE_YES) {
float pit = 100 + random(0,10);
sound(self, CHAN_BODY, "squeek/sqk_deploy1.wav", 1.0, ATTN_NORM, pit);
Damage_Apply(trace_ent, self.goalentity, 10, WEAPON_PENGUIN, DMG_GENERIC);
}
if (self.aiment.health <= 0) {
self.aiment = __NULL__;
}
}
self.weapon -= frametime;
runstandardplayerphysics(self);
}
void
penguin_die(void)
{
/* clear this first to avoid infinite recursion */
self.health = 0;
/* now we can explodededededed */
FX_Explosion(self.origin);
Damage_Radius(self.origin, self.owner, 150, 150 * 2.5f, TRUE, WEAPON_PENGUIN);
if (random() < 0.5) {
sound(self, 1, "weapons/explode3.wav", 1.0f, ATTN_NORM);
} else {
sound(self, 1, "weapons/explode4.wav", 1.0f, ATTN_NORM);
}
remove(self);
}
void
penguin_pain(void)
{
/* add stuff? */
}
void
w_penguin_deploy(void)
{
CBaseEntity pingu = spawn(CBaseEntity);
pingu.owner = self;
pingu.goalentity = self;
pingu.netname = "Penguin";
pingu.classname = "snark"; /* so snarks and pingus don't attack e/o */
setmodel(pingu, "models/w_penguin.mdl");
makevectors(self.v_angle);
setorigin(pingu, self.origin + v_forward * 32);
pingu.solid = SOLID_BBOX;
pingu.movetype = MOVETYPE_WALK;
pingu.frame = 3; /* running like crazy. */
pingu.customphysics = penguin_ai;
pingu.angles = self.angles;
pingu.health = 20;
pingu.Pain = penguin_pain;
pingu.takedamage = DAMAGE_YES;
pingu.aiment = __NULL__;
pingu.Death = penguin_die;
pingu.weapon = 3.0f;
penguin_squeak(pingu);
}
#endif
void
w_penguin_primary(void)
{
player pl = (player)self;
if (pl.w_attack_next > 0.0) {
return;
}
/* Ammo check */
#ifdef CLIENT
if (pl.ammo_penguin <= 0) {
return;
}
#else
if (pl.ammo_penguin <= 0) {
return;
}
#endif
Weapons_ViewAnimation(PENGUIN_THROW);
/* Audio-Visual Bit */
#ifdef CLIENT
pl.ammo_penguin--;
#else
w_penguin_deploy();
pl.ammo_penguin--;
Weapons_UpdateAmmo(pl, __NULL__, pl.ammo_penguin, __NULL__);
if (pl.ammo_penguin <= 0) {
Weapons_RemoveItem(pl, WEAPON_SNARK);
}
#endif
pl.w_idle_next = 2.0f;
pl.w_attack_next = 2.0f;
}
void
w_penguin_secondary(void)
{
}
void
w_penguin_reload(void)
{
}
void
w_penguin_release(void)
{
int r;
player pl = (player)self;
if (pl.w_idle_next > 0.0) {
return;
}
r = (float)input_sequence % 3;
switch (r) {
case 0:
Weapons_ViewAnimation(PENGUIN_IDLE);
pl.w_idle_next = 1.875f;
break;
case 1:
Weapons_ViewAnimation(PENGUIN_FIDGET1);
pl.w_idle_next = 4.375f;
break;
default:
Weapons_ViewAnimation(PENGUIN_FIDGET2);
pl.w_idle_next = 5.0f;
break;
}
}
void
w_penguin_precache(void)
{
#ifdef SERVER
precache_model("models/w_penguin.mdl");
precache_sound("squeek/sqk_deploy1.wav");
precache_sound("squeek/sqk_die1.wav");
precache_sound("squeek/sqk_blast1.wav");
precache_sound("squeek/sqk_hunt1.wav");
precache_sound("squeek/sqk_hunt2.wav");
precache_sound("squeek/sqk_hunt3.wav");
#else
precache_model("models/p_penguin.mdl");
precache_model("models/v_penguin.mdl");
#endif
}
void
w_penguin_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, -1, pl.ammo_penguin, -1);
}
string
w_penguin_wmodel(void)
{
return "models/w_penguinnest.mdl";
}
string
w_penguin_pmodel(void)
{
return "models/p_penguin.mdl";
}
string
w_penguin_deathmsg(void)
{
return "";
}
float
w_penguin_aimanim(void)
{
return self.flags & FL_CROUCHING ? ANIM_CR_AIMSQUEAK : ANIM_AIMSQUEAK;
}
void
w_penguin_hud(void)
{
#ifdef CLIENT
HUD_DrawAmmo2();
vector aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42];
drawsubpic(aicon_pos, [24,24], "sprites/640hud7.spr_0.tga", [144/256,72/128], [24/256, 24/128], g_hud_color, pSeat->m_flAmmo2Alpha, DRAWFLAG_ADDITIVE);
#endif
}
void
w_penguin_hudpic(int s, vector pos, float a)
{
#ifdef CLIENT
player pl = (player)self;
vector hud_col;
if (pl.ammo_penguin == 0)
hud_col = [1,0,0];
else
hud_col = g_hud_color;
HUD_DrawAmmoBar(pos, pl.ammo_penguin, MAX_A_PENGUIN, a);
if (s) {
drawsubpic(pos, [170,45], "sprites/640hudof04.spr_0.tga",
[0,180/256], [170/256,45/256],
hud_col, a, DRAWFLAG_ADDITIVE);
} else {
drawsubpic(pos, [170,45], "sprites/640hudof03.spr_0.tga",
[0,180/256], [170/256,45/256],
hud_col, a, DRAWFLAG_ADDITIVE);
}
#endif
}
weapon_t w_penguin =
{
.name = "penguin",
.id = ITEM_PENGUIN,
.slot = 4,
.slot_pos = 4,
.draw = w_penguin_draw,
.holster = w_penguin_holster,
.primary = w_penguin_primary,
.secondary = w_penguin_secondary,
.reload = w_penguin_reload,
.release = w_penguin_release,
.crosshair = w_penguin_hud,
.precache = w_penguin_precache,
.pickup = w_penguin_pickup,
.updateammo = w_penguin_updateammo,
.wmodel = w_penguin_wmodel,
.pmodel = w_penguin_pmodel,
.deathmsg = w_penguin_deathmsg,
.aimanim = w_penguin_aimanim,
.hudpic = w_penguin_hudpic
};
#ifdef SERVER
void
weapon_penguin(void)
{
Weapons_InitItem(WEAPON_PENGUIN);
}
#endif

350
src/shared/w_pipewrench.qc Normal file
View File

@ -0,0 +1,350 @@
/*
* 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.
*/
/*QUAKED weapon_pipewrench (0 0 1) (-16 -16 0) (16 16 32)
"model" "models/w_pipe_wrench.mdl"
HALF-LIFE: OPPOSING FORCE (1999) ENTITY
Pipe-Wrench Weapon
*/
enum
{
PIPE_IDLE1,
PIPE_IDLE2,
PIPE_IDLE3,
PIPE_DRAW,
PIPE_HOLSTER,
PIPE_ATTACK1HIT,
PIPE_ATTACK1MISS,
PIPE_ATTACK2HIT,
PIPE_ATTACK2MISS,
PIPE_ATTACK3HIT,
PIPE_ATTACK3MISS,
PIPE_ATTACKBIGWIND,
PIPE_ATTACKBIGHIT,
PIPE_ATTACKBIGMISS,
PIPE_ATTACKBIGLOOP
};
void
w_pipewrench_precache(void)
{
#ifdef SERVER
precache_sound("weapons/pwrench_big_miss.wav");
precache_sound("weapons/pwrench_big_hit1.wav");
precache_sound("weapons/pwrench_big_hit2.wav");
precache_sound("weapons/pwrench_big_hitbod1.wav");
precache_sound("weapons/pwrench_big_hitbod2.wav");
precache_sound("weapons/pwrench_miss1.wav");
precache_sound("weapons/pwrench_miss2.wav");
precache_sound("weapons/pwrench_hit1.wav");
precache_sound("weapons/pwrench_hit2.wav");
precache_sound("weapons/pwrench_hitbod1.wav");
precache_sound("weapons/pwrench_hitbod2.wav");
precache_sound("weapons/pwrench_hitbod3.wav");
precache_model("models/w_pipe_wrench.mdl");
#else
precache_model("models/p_pipe_wrench.mdl");
precache_model("models/v_pipe_wrench.mdl");
#endif
}
void
w_pipewrench_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, -1, -1, -1);
}
string
w_pipewrench_wmodel(void)
{
return "models/w_pipe_wrench.mdl";
}
string
w_pipewrench_pmodel(void)
{
return "models/p_pipe_wrench.mdl";
}
string
w_pipewrench_deathmsg(void)
{
return "%s was assaulted by %s's Pipewrench.";
}
void
w_pipewrench_draw(void)
{
Weapons_SetModel("models/v_pipe_wrench.mdl");
Weapons_ViewAnimation(PIPE_DRAW);
}
void
w_pipewrench_holster(void)
{
Weapons_ViewAnimation(PIPE_HOLSTER);
}
void
w_pipewrench_primary(void)
{
int anim = 0;
vector src;
player pl = (player)self;
if (pl.w_attack_next) {
return;
}
Weapons_MakeVectors();
src = Weapons_GetCameraPos();
traceline(src, src + (v_forward * 32), FALSE, pl);
if (trace_fraction >= 1.0) {
pl.w_attack_next = 0.7f;
} else {
pl.w_attack_next = 0.53f;
}
pl.w_idle_next = 2.5f;
#ifdef CLIENT
int r = (float)input_sequence % 3;
switch (r) {
case 0:
anim = trace_fraction >= 1 ? PIPE_ATTACK1MISS:PIPE_ATTACK1HIT;
break;
case 1:
anim = trace_fraction >= 1 ? PIPE_ATTACK2MISS:PIPE_ATTACK2HIT;
break;
default:
anim = trace_fraction >= 1 ? PIPE_ATTACK3MISS:PIPE_ATTACK3HIT;
}
Weapons_ViewAnimation(anim);
#else
if (pl.flags & FL_CROUCHING) {
Animation_PlayerTopTemp(ANIM_SHOOTCROWBAR, 0.5f);
} else {
Animation_PlayerTopTemp(ANIM_CR_SHOOTCROWBAR, 0.42f);
}
sound(pl, CHAN_WEAPON, "weapons/pwrench_miss1.wav", 1, ATTN_NORM);
if (trace_fraction >= 1.0) {
return;
}
/* don't bother with decals, we got squibs */
if (trace_ent.iBleeds) {
FX_Blood(trace_endpos, [1,0,0]);
} else {
FX_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal);
}
if (trace_ent.takedamage) {
Damage_Apply(trace_ent, self, 10, WEAPON_PIPEWRENCH, DMG_BLUNT);
if (!trace_ent.iBleeds) {
return;
}
if (random() < 0.33) {
sound(pl, 8, "weapons/pwrench_hitbod1.wav", 1, ATTN_NORM);
} else if (random() < 0.66) {
sound(pl, 8, "weapons/pwrench_hitbod2.wav", 1, ATTN_NORM);
} else {
sound(pl, 8, "weapons/pwrench_hitbod3.wav", 1, ATTN_NORM);
}
} else {
if (random() < 0.5) {
sound(pl, 8, "weapons/pwrench_hit1.wav", 1, ATTN_NORM);
} else {
sound(pl, 8, "weapons/pwrench_hit2.wav", 1, ATTN_NORM);
}
}
#endif
}
void
w_pipewrench_secondary(void)
{
player pl = (player)self;
if (!pl.w_attack_next) {
/* Hack */
if (pl.mode_wrench != 1) {
Weapons_ViewAnimation(PIPE_ATTACKBIGWIND);
pl.mode_wrench = 1;
pl.w_attack_next = 0.75f;
}
}
pl.w_idle_next = 2.5f;
}
void
w_pipewrench_release(void)
{
vector src;
player pl = (player)self;
if (pl.w_attack_next > 0.0) {
return;
}
if (pl.mode_wrench == 1) {
#ifdef SERVER
int hitsound = 0;
string snd;
#endif
/* attack! */
Weapons_MakeVectors();
src = Weapons_GetCameraPos();
traceline(src, src + (v_forward * 64), FALSE, pl);
if (trace_fraction < 1.0) {
#ifdef SERVER
if (trace_ent.takedamage == DAMAGE_YES) {
hitsound = floor(random(1, 2));
/* TODO Damage is 45 - 200+ (?) */
Damage_Apply(trace_ent, pl, 200, WEAPON_PIPEWRENCH, DMG_BLUNT);
} else {
hitsound = 3;
}
/* don't bother with decals, we got squibs */
if (trace_ent.iBleeds) {
FX_Blood(trace_endpos, [1,0,0]);
} else {
FX_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal);
}
#endif
Weapons_ViewAnimation(PIPE_ATTACKBIGHIT);
Weapons_ViewPunchAngle([-10,0,0]);
} else {
Weapons_ViewAnimation(PIPE_ATTACKBIGMISS);
}
#ifdef SERVER
snd = "weapons/pwrench_big_miss.wav";
switch (hitsound) {
case 1:
snd = "weapons/pwrench_big_hitbod1.wav";
break;
case 2:
snd = "weapons/pwrench_big_hitbod2.wav";
break;
case 3:
snd = "weapons/pwrench_big_hit1.wav";
break;
}
Weapons_PlaySound(pl, CHAN_WEAPON, snd, 1.0f, ATTN_NORM);
#endif
pl.w_attack_next = 1.0f;
pl.w_idle_next = 10.0f;
pl.mode_wrench = 0;
}
/* Pure cosmetics start here */
if (pl.w_idle_next > 0.0) {
return;
}
int r = floor(random(0,3));
switch (r) {
case 0:
Weapons_ViewAnimation(PIPE_IDLE1);
pl.w_idle_next = 2.0f;
break;
case 1:
Weapons_ViewAnimation(PIPE_IDLE2);
pl.w_idle_next = 3.0f;
break;
case 2:
Weapons_ViewAnimation(PIPE_IDLE3);
pl.w_idle_next = 3.0f;
break;
}
}
float
w_pipewrench_aimanim(void)
{
return self.flags & FL_CROUCHING ? ANIM_CR_AIMCROWBAR : ANIM_AIMCROWBAR;
}
void
w_pipewrench_hudpic(int selected, vector pos, float a)
{
#ifdef CLIENT
if (selected) {
drawsubpic(
pos,
[170,45],
"sprites/640hudof02.spr_0.tga",
[0,0],
[170/256,45/256],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[170,45],
"sprites/640hudof01.spr_0.tga",
[0,0],
[170/256,45/256],
g_hud_color,
a,
DRAWFLAG_ADDITIVE
);
}
#endif
}
weapon_t w_pipewrench =
{
.name = "pipewrench",
.id = ITEM_PIPEWRENCH,
.slot = 0,
.slot_pos = 1,
.draw = w_pipewrench_draw,
.holster = w_pipewrench_holster,
.primary = w_pipewrench_primary,
.secondary = w_pipewrench_secondary,
.reload = w_pipewrench_release,
.release = w_pipewrench_release,
.crosshair = __NULL__,
.precache = w_pipewrench_precache,
.pickup = __NULL__,
.updateammo = w_pipewrench_updateammo,
.wmodel = w_pipewrench_wmodel,
.pmodel = w_pipewrench_pmodel,
.deathmsg = w_pipewrench_deathmsg,
.aimanim = w_pipewrench_aimanim,
.hudpic = w_pipewrench_hudpic
};
/* entity definitions for pickups */
#ifdef SERVER
void
weapon_pipewrench(void)
{
Weapons_InitItem(WEAPON_PIPEWRENCH);
}
#endif

317
src/shared/w_shockrifle.qc Normal file
View File

@ -0,0 +1,317 @@
/*
* 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.
*/
/*QUAKED weapon_shockrifle (0 0 1) (-16 -16 0) (16 16 32)
"model" "models/w_shock.mdl"
HALF-LIFE: OPPOSING FORCE (1999) ENTITY
Shockrifle Weapon
*/
#ifdef CLIENT
var int PART_SHOCKPIECE;
#endif
enum
{
SHOCKRIFLE_IDLE1,
SHOCKRIFLE_SHOOT,
SHOCKRIFLE_DRAW,
SHOCKRIFLE_HOLSTER,
SHOCKRIFLE_IDLE2
};
void
w_shockrifle_precache(void)
{
#ifdef SERVER
precache_model("models/w_shock.mdl");
precache_sound("weapons/shock_discharge.wav");
precache_sound("weapons/shock_draw.wav");
precache_sound("weapons/shock_fire.wav");
precache_sound("weapons/shock_impact.wav");
precache_sound("weapons/shock_recharge.wav");
#else
PART_SHOCKPIECE = particleeffectnum("shockrifle.shockrifle_piece");
precache_model("models/v_shock.mdl");
precache_model("models/p_shock.mdl");
#endif
}
int
w_shockrifle_pickup(int new, int startammo)
{
#ifdef SERVER
player pl = (player)self;
/* only pick it up once */
if (new) {
pl.ammo_shock = MAX_A_SHOCK;
return TRUE;
}
#endif
return FALSE;
}
void
w_shockrifle_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, -1, pl.ammo_shock, -1);
}
string
w_shockrifle_wmodel(void)
{
return "models/w_shock.mdl";
}
string
w_shockrifle_pmodel(void)
{
return "models/p_shock.mdl";
}
string
w_shockrifle_deathmsg(void)
{
return "";
}
void
w_shockrifle_draw(void)
{
Weapons_SetModel("models/v_shock.mdl");
Weapons_ViewAnimation(SHOCKRIFLE_DRAW);
#ifdef SERVER
player pl = (player)self;
Weapons_UpdateAmmo(pl, -1, pl.ammo_shock, -1);
#endif
}
void
w_shockrifle_holster(void)
{
}
#ifdef SERVER
void
w_shockrifle_shoothornet(void)
{
static void Hornet_Touch(void) {
if (other.takedamage == DAMAGE_YES) {
Damage_Apply(other, self.owner, 10, WEAPON_SHOCKRIFLE, DMG_ELECTRO);
}
if (other.iBleeds) {
FX_Blood(trace_endpos, [1,0,0]);
} else {
FX_Spark(self.origin, trace_plane_normal);
}
remove(self);
}
Weapons_MakeVectors();
entity bolt = spawn();
//setmodel(bolt, "models/hornet.mdl");
setorigin(bolt, Weapons_GetCameraPos() + (v_forward * 16) + (v_up * -8));
bolt.owner = self;
bolt.velocity = v_forward * 1000;
bolt.movetype = MOVETYPE_FLY;
bolt.solid = SOLID_BBOX;
//bolt.flags |= FL_LAGGEDMOVE;
bolt.gravity = 0.5f;
bolt.angles = vectoangles(bolt.velocity);
bolt.touch = Hornet_Touch;
setsize(bolt, [0,0,0], [0,0,0]);
}
#endif
void
w_shockrifle_release(void)
{
player pl = (player)self;
if (pl.w_idle_next > 0.0) {
return;
}
if (pl.ammo_shock < MAX_A_SHOCK) {
pl.ammo_shock = bound(0, pl.ammo_shock + 1, MAX_A_SHOCK);
pl.w_idle_next = 0.35f;
}
if (pl.w_idle_next > 0.0) {
return;
}
if (random() < 0.5) {
Weapons_ViewAnimation(SHOCKRIFLE_IDLE1);
} else {
Weapons_ViewAnimation(SHOCKRIFLE_IDLE2);
}
pl.w_idle_next = 3.333333f;
}
void
w_shockrifle_primary(void)
{
player pl = (player)self;
if (pl.w_attack_next > 0.0) {
return;
}
/* Ammo check */
if (pl.ammo_shock <= 0) {
w_shockrifle_release();
return;
}
#ifdef SERVER
w_shockrifle_shoothornet();
Weapons_PlaySound(pl, CHAN_WEAPON, "weapons/shock_fire.wav", 1, ATTN_NORM);
pl.ammo_shock--;
Weapons_UpdateAmmo(pl, -1, pl.ammo_shock, -1);
#else
Weapons_MakeVectors();
vector src = Weapons_GetCameraPos() + (v_forward * 16) + (v_up * -8);
pointparticles(PART_SHOCKPIECE, src, v_forward * 1000, 1);
pl.ammo_shock--;
#endif
Weapons_ViewAnimation(SHOCKRIFLE_SHOOT);
pl.w_attack_next = 0.1f;
pl.w_idle_next = 0.5f;
}
void
w_shockrifle_crosshair(void)
{
#ifdef CLIENT
vector cross_pos;
vector aicon_pos;
/* crosshair */
cross_pos = g_hudmins + (g_hudres / 2) + [-12,-12];
drawsubpic(
cross_pos,
[24,24],
"sprites/ofch1.spr_0.tga",
[0,24/72],
[24/72, 24/72],
[1,1,1],
1.0,
DRAWFLAG_NORMAL
);
/* ammo counter */
HUD_DrawAmmo2();
/* ammo icon */
aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42];
drawsubpic(
aicon_pos,
[24,24],
"sprites/640hud7.spr_0.tga",
[224/256,48/128],
[24/256, 24/128],
g_hud_color,
pSeat->m_flAmmo2Alpha,
DRAWFLAG_ADDITIVE
);
#endif
}
float
w_shockrifle_aimanim(void)
{
return self.flags & FL_CROUCHING ? ANIM_CR_AIMHIVE : ANIM_AIMHIVE;
}
void
w_shockrifle_hudpic(int selected, vector pos, float a)
{
#ifdef CLIENT
player pl = (player)self;
vector hud_col;
if (pl.ammo_shock == 0)
hud_col = [1,0,0];
else
hud_col = g_hud_color;
HUD_DrawAmmoBar(pos, pl.ammo_shock, MAX_A_SHOCK, a);
if (selected) {
drawsubpic(
pos,
[170,45],
"sprites/640hudof04.spr_0.tga",
[0,45/256],
[170/256,45/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[170,45],
"sprites/640hudof03.spr_0.tga",
[0,45/256],
[170/256,45/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
}
#endif
}
weapon_t w_shockrifle =
{
.name = "shockrifle",
.id = ITEM_SHOCKRIFLE,
.slot = 6,
.slot_pos = 1,
.draw = w_shockrifle_draw,
.holster = w_shockrifle_holster,
.primary = w_shockrifle_primary,
.secondary = w_shockrifle_release,
.reload = w_shockrifle_release,
.release = w_shockrifle_release,
.crosshair = w_shockrifle_crosshair,
.precache = w_shockrifle_precache,
.pickup = w_shockrifle_pickup,
.updateammo = w_shockrifle_updateammo,
.wmodel = w_shockrifle_wmodel,
.pmodel = w_shockrifle_pmodel,
.deathmsg = w_shockrifle_deathmsg,
.aimanim = w_shockrifle_aimanim,
.hudpic = w_shockrifle_hudpic
};
#ifdef SERVER
void
weapon_shockrifle(void)
{
Weapons_InitItem(WEAPON_SHOCKRIFLE);
}
#endif

327
src/shared/w_sniperrifle.qc Normal file
View File

@ -0,0 +1,327 @@
/*
* 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.
*/
/*QUAKED weapon_sniperrifle (0 0 1) (-16 -16 0) (16 16 32)
"model" "models/w_m40a1.mdl"
HALF-LIFE: OPPOSING FORCE (1999) ENTITY
Sniper-Rifle Weapon
*/
enum
{
SNIPER_DRAW,
SNIPER_IDLE1,
SNIPER_FIRE1,
SNIPER_FIRE2,
SNIPER_RELOAD1,
SNIPER_RELOAD2,
SNIPER_RELOAD3,
SNIPER_IDLE2,
SNIPER_HOLSTER,
SNIPER_DRAW
};
void
w_sniperrifle_precache(void)
{
#ifdef SERVER
precache_model("models/w_m40a1.mdl");
precache_sound("weapons/sniper_fire.wav");
#else
precache_model("models/v_m40a1.mdl");
precache_model("models/p_m40a1.mdl");
#endif
}
int
w_sniperrifle_pickup(int new, int startammo)
{
#ifdef SERVER
player pl = (player)self;
if (new) {
pl.sniper_mag = 5;
} else {
if (pl.ammo_762 < MAX_A_762) {
pl.ammo_762 = bound(0, pl.ammo_762 + 5, MAX_A_762);
} else {
return FALSE;
}
}
#endif
return TRUE;
}
void
w_sniperrifle_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, pl.sniper_mag, pl.ammo_762, -1);
}
string
w_sniperrifle_wmodel(void)
{
return "models/w_m40a1.mdl";
}
string
w_sniperrifle_pmodel(void)
{
return "models/p_m40a1.mdl";
}
string
w_sniperrifle_deathmsg(void)
{
return "";
}
void
w_sniperrifle_draw(void)
{
Weapons_SetModel("models/v_m40a1.mdl");
Weapons_ViewAnimation(SNIPER_DRAW);
#ifdef SERVER
player pl = (player)self;
Weapons_UpdateAmmo(pl, pl.sniper_mag, pl.ammo_762, -1);
#endif
}
void
w_sniperrifle_holster(void)
{
Weapons_ViewAnimation(SNIPER_HOLSTER);
}
void
w_sniperrifle_primary(void)
{
player pl = (player)self;
if (pl.w_attack_next > 0.0) {
return;
}
/* Ammo check */
#ifdef CLIENT
if (pl.sniper_mag <= 0) {
return;
}
#else
if (pl.sniper_mag <= 0) {
return;
}
#endif
/* Actual firing */
#ifdef SERVER
TraceAttack_FireBullets(1, pl.origin + pl.view_ofs, 40, [0.00873, 0.00873], WEAPON_SNIPERRIFLE);
Weapons_PlaySound(pl, CHAN_WEAPON, "weapons/sniper_fire.wav", 1, ATTN_NORM);
pl.sniper_mag--;
Weapons_UpdateAmmo(pl, pl.sniper_mag, pl.ammo_762, __NULL__);
#else
pl.sniper_mag--;
View_SetMuzzleflash(MUZZLE_SMALL);
Weapons_ViewPunchAngle([-10,0,0]);
if (pl.sniper_mag) {
Weapons_ViewAnimation(SNIPER_FIRE1);
} else {
Weapons_ViewAnimation(SNIPER_FIRE2);
}
#endif
pl.w_attack_next = 1.75f;
pl.w_idle_next = 10.0f;
}
void
w_sniperrifle_secondary(void)
{
player pl = (player)self;
if (pl.w_attack_next > 0.0) {
return;
}
/* Simple toggle of fovs */
if (pl.viewzoom == 1.0f) {
pl.viewzoom = 0.25f;
} else {
pl.viewzoom = 1.0f;
}
pl.w_attack_next = 0.5f;
}
void
w_sniperrifle_reload(void)
{
player pl = (player)self;
if (pl.w_attack_next > 0.0) {
return;
}
/* Ammo check */
#ifdef CLIENT
if (pl.sniper_mag >= 5) {
return;
}
if (pl.ammo_762 <= 0) {
return;
}
#else
if (pl.sniper_mag >= 5) {
return;
}
if (pl.ammo_762 <= 0) {
return;
}
#endif
/* Audio-Visual bit */
/* TODO has a couple reloading states */
Weapons_ViewAnimation(SNIPER_RELOAD1);
#ifdef SERVER
Weapons_ReloadWeapon(pl, player::sniper_mag, player::ammo_762, 5);
Weapons_UpdateAmmo(pl, pl.sniper_mag, pl.ammo_762, __NULL__);
#endif
pl.w_attack_next = 2.3f;
pl.w_idle_next = 10.0f;
}
void
w_sniperrifle_release(void)
{
player pl = (player)self;
/* auto-reload if need be */
if (pl.w_attack_next <= 0.0)
if (pl.sniper_mag == 0 && pl.ammo_762 > 0) {
Weapons_Reload();
return;
}
if (pl.w_idle_next > 0.0) {
return;
}
int r = (float)input_sequence % 2;
if (r == 1) {
Weapons_ViewAnimation(SNIPER_IDLE1);
} else {
Weapons_ViewAnimation(SNIPER_IDLE2);
}
pl.w_idle_next = 15.0f;
}
void
w_sniperrifle_crosshair(void)
{
#ifdef CLIENT
player pl = (player)self;
static vector cross_pos;
if (pl.viewzoom == 1.0f) {
cross_pos = g_hudmins + (g_hudres / 2) + [-12,-12];
drawsubpic(
cross_pos,
[24,24],
"sprites/ofch1.spr_0.tga",
[0,48/72],
[24/72, 24/72],
[1,1,1],
1,
DRAWFLAG_NORMAL
);
} else {
cross_pos = g_hudmins + (g_hudres / 2) + [-128,-128];
drawsubpic(
cross_pos,
[256,256],
"sprites/ofch2.spr_0.tga",
[0,0],
[1, 1],
[1,1,1],
1,
DRAWFLAG_NORMAL
);
}
HUD_DrawAmmo1();
HUD_DrawAmmo2();
vector aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42];
drawsubpic(aicon_pos, [24,24], "sprites/640hud7.spr_0.tga", [24/256,72/128], [24/256, 24/128], g_hud_color, pSeat->m_flAmmo2Alpha, DRAWFLAG_ADDITIVE);
#endif
}
float
w_sniperrifle_aimanim(void)
{
return self.flags & FL_CROUCHING ? ANIM_CR_AIMPYTHON : ANIM_AIMPYTHON;
}
void
w_sniperrifle_hudpic(int s, vector pos, float a)
{
#ifdef CLIENT
player pl = (player)self;
vector hud_col;
if (pl.sniper_mag == 0 && pl.ammo_762 == 0)
hud_col = [1,0,0];
else
hud_col = g_hud_color;
HUD_DrawAmmoBar(pos, pl.ammo_762, MAX_A_762, a);
if (s) {
drawsubpic(pos, [170,45], "sprites/640hudof04.spr_0.tga", [0,135/256], [170/256,45/256], hud_col, a, DRAWFLAG_ADDITIVE);
} else {
drawsubpic(pos, [170,45], "sprites/640hudof03.spr_0.tga", [0,135/256], [170/256,45/256], hud_col, a, DRAWFLAG_ADDITIVE);
}
#endif
}
weapon_t w_sniperrifle =
{
.name = "sniperrifle",
.id = ITEM_SNIPERRIFLE,
.slot = 5,
.slot_pos = 2,
.draw = w_sniperrifle_draw,
.holster = w_sniperrifle_holster,
.primary = w_sniperrifle_primary,
.secondary = w_sniperrifle_secondary,
.reload = w_sniperrifle_reload,
.release = w_sniperrifle_release,
.crosshair = w_sniperrifle_crosshair,
.precache = w_sniperrifle_precache,
.pickup = w_sniperrifle_pickup,
.updateammo = w_sniperrifle_updateammo,
.wmodel = w_sniperrifle_wmodel,
.pmodel = w_sniperrifle_pmodel,
.deathmsg = w_sniperrifle_deathmsg,
.aimanim = w_sniperrifle_aimanim,
.hudpic = w_sniperrifle_hudpic
};
#ifdef SERVER
void
weapon_sniperrifle(void)
{
Weapons_InitItem(WEAPON_SNIPERRIFLE);
}
#endif

View File

@ -0,0 +1,491 @@
/*
* 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.
*/
/*QUAKED weapon_sporelauncher (0 0 1) (-16 -16 0) (16 16 32)
"model" "models/w_spore_launcher.mdl"
HALF-LIFE: OPPOSING FORCE (1999) ENTITY
Sporelauncher Weapon
*/
enum
{
SPORE_IDLE1,
SPORE_FIDGET,
SPORE_RELOAD1,
SPORE_RELOAD2,
SPORE_RELOAD3,
SPORE_FIRE,
SPORE_HOLSTER,
SPORE_DRAW,
SPORE_IDLE2
};
enum
{
SLSTATE_IDLE,
SLSTATE_RELOAD_START,
SLSTATE_RELOAD,
SLSTATE_RELOAD_END
};
#ifdef SERVER
void Sporelauncher_Fire(entity spawner, vector org, vector dir)
{
static void Spore_Touch(void) {
int r;
string hitsnd;
if (other.takedamage == DAMAGE_YES) {
Damage_Apply(other, self.owner, 50, WEAPON_SPORELAUNCHER, DMG_GENERIC);
} else {
Decals_Place(self.origin, sprintf("{yblood%d", floor(random(1,7))));
}
r = floor(random(0,3));
hitsnd = "weapons/spore_hit1.wav";
switch (r) {
case 0:
hitsnd = "weapons/spore_hit2.wav";
break;
case 1:
hitsnd = "weapons/spore_hit3.wav";
break;
}
sound(self, CHAN_BODY, hitsnd, 1.0f, ATTN_NORM);
remove(self);
}
entity blob = spawn();
setmodel(blob, "models/spore.mdl");
blob.owner = spawner;
blob.velocity = dir * 2000;
blob.movetype = MOVETYPE_BOUNCE;
blob.solid = SOLID_BBOX;
//bolt.flags |= FL_LAGGEDMOVE;
blob.gravity = 0.5f;
blob.angles = vectoangles(blob.velocity);
blob.avelocity[2] = 10;
blob.touch = Spore_Touch;
setsize(blob, [0,0,0], [0,0,0]);
setorigin(blob, org);
sound(spawner, CHAN_WEAPON, "weapons/splauncher_fire.wav", 1, ATTN_NORM);
}
void Sporelauncher_AltFire(entity spawner, vector org, vector dir)
{
static void Spore_Explode(void) {
int r;
string hitsnd;
Damage_Radius(self.origin, self.owner, 100, 256, 1, WEAPON_SPORELAUNCHER);
r = floor(random(0,3));
hitsnd = "weapons/spore_hit1.wav";
switch (r) {
case 0:
hitsnd = "weapons/spore_hit2.wav";
break;
case 1:
hitsnd = "weapons/spore_hit3.wav";
break;
}
sound(self, CHAN_BODY, hitsnd, 1.0f, ATTN_NORM);
remove(self);
}
static void Spore_Touch(void) {
Decals_Place(self.origin, sprintf("{yblood%d", floor(random(1,7))));
if (other.takedamage == DAMAGE_YES) {
Spore_Explode();
} else if (self.think == __NULL__) {
self.think = Spore_Explode;
self.nextthink = time + 2.0f;
}
self.velocity *= 0.5f;
}
entity blob = spawn();
setmodel(blob, "models/spore.mdl");
blob.owner = spawner;
blob.velocity = dir * 2000;
blob.movetype = MOVETYPE_BOUNCE;
blob.solid = SOLID_BBOX;
//bolt.flags |= FL_LAGGEDMOVE;
blob.gravity = 0.5f;
blob.angles = vectoangles(blob.velocity);
blob.avelocity[2] = 10;
blob.touch = Spore_Touch;
setsize(blob, [0,0,0], [0,0,0]);
setorigin(blob, org);
sound(spawner, CHAN_WEAPON, "weapons/splauncher_fire.wav", 1, ATTN_NORM);
}
#endif
void
w_sporelauncher_precache(void)
{
#ifdef SERVER
precache_model("models/spore.mdl");
precache_model("models/w_spore_launcher.mdl");
precache_sound("weapons/splauncher_altfire.wav");
precache_sound("weapons/splauncher_bounce.wav");
precache_sound("weapons/splauncher_fire.wav");
precache_sound("weapons/splauncher_impact.wav");
precache_sound("weapons/splauncher_pet.wav");
precache_sound("weapons/splauncher_reload.wav");
precache_sound("weapons/spore_ammo.wav");
precache_sound("weapons/spore_hit1.wav");
precache_sound("weapons/spore_hit2.wav");
precache_sound("weapons/spore_hit3.wav");
#else
precache_model("models/v_spore_launcher.mdl");
precache_model("models/p_spore_launcher.mdl");
#endif
}
void
w_sporelauncher_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, pl.sporelauncher_mag, pl.ammo_spore, -1);
}
string
w_sporelauncher_wmodel(void)
{
return "models/w_spore_launcher.mdl";
}
string
w_sporelauncher_pmodel(void)
{
return "models/p_spore_launcher.mdl";
}
string
w_sporelauncher_deathmsg(void)
{
return "";
}
int
w_sporelauncher_pickup(int new, int startammo)
{
#ifdef SERVER
player pl = (player)self;
if (new) {
pl.sporelauncher_mag = 5;
} else {
if (pl.ammo_spore < MAX_A_SPORE) {
pl.ammo_spore = bound(0, pl.ammo_spore + 5, MAX_A_SPORE);
} else {
return FALSE;
}
}
#endif
return TRUE;
}
void
w_sporelauncher_draw(void)
{
#ifdef CLIENT
Weapons_SetModel("models/v_spore_launcher.mdl");
Weapons_ViewAnimation(SPORE_DRAW);
#else
player pl = (player)self;
Weapons_UpdateAmmo(pl, pl.sporelauncher_mag, pl.ammo_spore, -1);
#endif
}
void
w_sporelauncher_holster(void)
{
Weapons_ViewAnimation(SPORE_HOLSTER);
}
void
w_sporelauncher_primary(void)
{
player pl = (player)self;
if (pl.w_attack_next > 0.0) {
return;
}
#ifdef SERVER
if (pl.sporelauncher_mag <= 0) {
return;
}
Weapons_MakeVectors();
Sporelauncher_Fire(self, Weapons_GetCameraPos() + (v_forward * 16), v_forward);
pl.sporelauncher_mag--;
Weapons_UpdateAmmo(pl, pl.sporelauncher_mag, pl.ammo_spore, -1);
#else
if (pl.sporelauncher_mag <= 0) {
return;
}
Weapons_ViewPunchAngle([-2,0,0]);
Weapons_ViewAnimation(SPORE_FIRE);
#endif
pl.w_attack_next = 0.75f;
pl.w_idle_next = 10.0f;
}
void
w_sporelauncher_secondary(void)
{
player pl = (player)self;
if (pl.w_attack_next > 0.0) {
return;
}
#ifdef SERVER
if (pl.sporelauncher_mag <= 0) {
return;
}
Weapons_MakeVectors();
Sporelauncher_AltFire(self, Weapons_GetCameraPos() + (v_forward * 16), v_forward);
pl.sporelauncher_mag--;
Weapons_UpdateAmmo(pl, pl.sporelauncher_mag, pl.ammo_spore, -1);
#else
if (pl.sporelauncher_mag <= 0) {
return;
}
Weapons_ViewPunchAngle([-2,0,0]);
Weapons_ViewAnimation(SPORE_FIRE);
#endif
pl.w_attack_next = 0.75f;
pl.w_idle_next = 10.0f;
}
void w_sporelauncher_release(void)
{
player pl = (player)self;
/* auto-reload if need be */
if (pl.w_attack_next <= 0.0)
if (pl.mode_sporelauncher == SLSTATE_IDLE && pl.sporelauncher_mag == 0 && pl.ammo_spore > 0) {
Weapons_Reload();
return;
}
if (pl.w_idle_next > 0.0) {
return;
}
if (pl.mode_sporelauncher == SLSTATE_IDLE) {
int r = (float)input_sequence % 3;
switch (r) {
case 0:
Weapons_ViewAnimation(SPORE_IDLE1);
pl.w_idle_next = 2.0f;
break;
case 1:
Weapons_ViewAnimation(SPORE_FIDGET);
pl.w_idle_next = 4.0f;
break;
case 2:
Weapons_ViewAnimation(SPORE_IDLE2);
pl.w_idle_next = 4.0f;
break;
}
} else if (pl.mode_sporelauncher == SLSTATE_RELOAD_START) {
Weapons_ViewAnimation(SPORE_RELOAD1);
pl.mode_sporelauncher = SLSTATE_RELOAD;
pl.w_idle_next = 0.65f;
} else if (pl.mode_sporelauncher == SLSTATE_RELOAD) {
Weapons_ViewAnimation(SPORE_RELOAD2);
#ifdef CLIENT
pl.sporelauncher_mag++;
pl.ammo_spore--;
if (pl.ammo_spore <= 0 || pl.sporelauncher_mag >= 5) {
pl.mode_sporelauncher = SLSTATE_RELOAD_END;
}
#else
pl.sporelauncher_mag++;
pl.ammo_spore--;
if (pl.ammo_spore <= 0 || pl.sporelauncher_mag >= 5) {
pl.mode_sporelauncher = SLSTATE_RELOAD_END;
}
#endif
pl.w_idle_next = 1.0f;
} else if (pl.mode_sporelauncher == SLSTATE_RELOAD_END) {
Weapons_ViewAnimation(SPORE_RELOAD3);
pl.mode_sporelauncher = SLSTATE_IDLE;
pl.w_idle_next = 10.0f;
pl.w_attack_next = 0.5f;
}
}
void
w_sporelauncher_reload(void)
{
player pl = (player)self;
#ifdef CLIENT
if (pl.sporelauncher_mag >= 5) {
return;
}
if (pl.ammo_spore <= 0) {
return;
}
#else
if (pl.sporelauncher_mag >= 5) {
return;
}
if (pl.ammo_spore <= 0) {
return;
}
#endif
if (pl.mode_sporelauncher > SLSTATE_IDLE) {
return;
}
pl.mode_sporelauncher = SLSTATE_RELOAD_START;
pl.w_idle_next = 0.0f;
}
void
w_sporelauncher_crosshair(void)
{
#ifdef CLIENT
vector cross_pos;
vector aicon_pos;
/* crosshair */
cross_pos = g_hudmins + (g_hudres / 2) + [-12,-12];
drawsubpic(
cross_pos,
[24,24],
"sprites/ofch1.spr_0.tga",
[24/72,24/72],
[24/72,24/72],
[1,1,1],
1.0,
DRAWFLAG_NORMAL
);
/* ammo counters */
HUD_DrawAmmo1();
HUD_DrawAmmo2();
/* ammo icon */
aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42];
drawsubpic(
aicon_pos,
[24,24],
"sprites/640hud7.spr_0.tga",
[200/256,48/128],
[24/256, 24/128],
g_hud_color,
pSeat->m_flAmmo2Alpha,
DRAWFLAG_ADDITIVE
);
#endif
}
float
w_sporelauncher_aimanim(void)
{
return self.flags & FL_CROUCHING ? ANIM_CR_AIMBOW : ANIM_AIMBOW;
}
void
w_sporelauncher_hudpic(int selected, vector pos, float a)
{
#ifdef CLIENT
player pl = (player)self;
vector hud_col;
if (pl.sporelauncher_mag == 0 && pl.ammo_spore == 0)
hud_col = [1,0,0];
else
hud_col = g_hud_color;
HUD_DrawAmmoBar(pos, pl.ammo_spore, MAX_A_SPORE, a);
if (selected) {
drawsubpic(
pos,
[170,45],
"sprites/640hudof04.spr_0.tga",
[0,0],
[170/256,45/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(
pos,
[170,45],
"sprites/640hudof03.spr_0.tga",
[0,0],
[170/256,45/256],
hud_col,
a,
DRAWFLAG_ADDITIVE
);
}
#endif
}
weapon_t w_sporelauncher =
{
.name = "sporelauncher",
.id = ITEM_SPORELAUNCHER,
.slot = 6,
.slot_pos = 0,
.draw = w_sporelauncher_draw,
.holster = w_sporelauncher_holster,
.primary = w_sporelauncher_primary,
.secondary = w_sporelauncher_secondary,
.reload = w_sporelauncher_reload,
.release = w_sporelauncher_release,
.crosshair = w_sporelauncher_crosshair,
.precache = w_sporelauncher_precache,
.pickup = w_sporelauncher_pickup,
.updateammo = w_sporelauncher_updateammo,
.wmodel = w_sporelauncher_wmodel,
.pmodel = w_sporelauncher_pmodel,
.deathmsg = w_sporelauncher_deathmsg,
.aimanim = w_sporelauncher_aimanim,
.hudpic = w_sporelauncher_hudpic
};
#ifdef SERVER
void
weapon_sporelauncher(void)
{
Weapons_InitItem(WEAPON_SPORELAUNCHER);
}
#endif

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

@ -0,0 +1,65 @@
/*
* 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.
*/
/* Weapon Indices for the weapon table */
enum
{
WEAPON_NONE,
WEAPON_CROWBAR,
WEAPON_PIPEWRENCH,
WEAPON_KNIFE,
WEAPON_GRAPPLE,
WEAPON_GLOCK,
WEAPON_PYTHON,
WEAPON_EAGLE,
WEAPON_MP5,
WEAPON_SHOTGUN,
WEAPON_CROSSBOW,
WEAPON_RPG,
WEAPON_GAUSS,
WEAPON_EGON,
WEAPON_HORNETGUN,
WEAPON_HANDGRENADE,
WEAPON_SATCHEL,
WEAPON_TRIPMINE,
WEAPON_SNARK,
WEAPON_PENGUIN,
WEAPON_M249,
WEAPON_DISPLACER,
WEAPON_SNIPERRIFLE,
WEAPON_SPORELAUNCHER,
WEAPON_SHOCKRIFLE
};
#define MAX_A_9MM 250
#define MAX_A_357 36
#define MAX_A_BUCKSHOT 125
#define MAX_A_M203_GRENADE 10
#define MAX_A_BOLT 50
#define MAX_A_ROCKET 5
#define MAX_A_URANIUM 100
#define MAX_A_HANDGRENADE 10
#define MAX_A_SATCHEL 5
#define MAX_A_TRIPMINE 10
#define MAX_A_SNARK 10
#define MAX_A_HORNET 8
/* gearbox */
#define MAX_A_556 200
#define MAX_A_PENGUIN 9
#define MAX_A_SHOCK 10
#define MAX_A_762 15
#define MAX_A_SPORE 20

44
src/shared/weapons.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.
*/
weapon_t w_null = {};
weapon_t g_weapons[] = {
w_null,
w_crowbar,
w_pipewrench,
w_knife,
w_grapple,
w_glock,
w_python,
w_eagle,
w_mp5,
w_shotgun,
w_crossbow,
w_rpg,
w_gauss,
w_egon,
w_hornetgun,
w_handgrenade,
w_satchel,
w_tripmine,
w_snark,
w_penguin,
w_m249,
w_displacer,
w_sniperrifle,
w_sporelauncher,
w_shockrifle
};

47
zpak001.pk3dir/default.cfg Executable file
View File

@ -0,0 +1,47 @@
// Generic Binds
bind "ESC" "togglemenu"
bind "w" "+forward"
bind "s" "+back"
bind "a" "+moveleft"
bind "d" "+moveright"
bind "SPACE" "+jump"
bind "CTRL" "+duck"
bind "SHIFT" "+speed"
bind "0" "slot10"
bind "1" "slot1"
bind "2" "slot2"
bind "3" "slot3"
bind "4" "slot4"
bind "5" "slot5"
bind "6" "slot6"
bind "7" "slot7"
bind "8" "slot8"
bind "9" "slot9"
bind "UPARROW" "+forward"
bind "DOWNARROW" "+back"
bind "LEFTARROW" "+left"
bind "RIGHTARROW" "+right"
bind "MOUSE1" "+attack"
bind "MOUSE2" "+attack2"
bind "MWHEELDOWN" "invnext"
bind "MWHEELUP" "invprev"
bind "r" "+reload"
bind "e" "+use"
bind "TAB" "+showscores"
bind "y" "messagemode"
bind "u" "messagemode2"
bind "t" "impulse 201"
bind "f" "impulse 100"
bind "f1" "vote yes"
bind "f2" "vote no"
// Game Variables
seta "hostname" "Opposing Force Server"
name "Shephard"
model shephard
seta "maxplayers" "8"
// 2D/HUD Variables
seta "con_color" "0 255 0"
seta "vgui_color" "0 255 0"
seta "cross_color" "0 255 0"

View File

@ -0,0 +1,17 @@
r_part shockrifle_piece
{
type texturedspark
texture ball
tcoords 1 65 31 95 256 8 32
scale 1
count 8
scalefactor 1
alpha 0.5
die 25
rgb 0 255 255
blend add
spawnmode ball
spawnorg 1
friction 0.5
gravity 0
}

View File

@ -0,0 +1,45 @@
of0a0.bsp
of1a1.bsp
of1a2.bsp
of1a3.bsp
of1a4b.bsp
of1a4.bsp
of1a5b.bsp
of1a5.bsp
of1a6.bsp
of2a1b.bsp
of2a1.bsp
of2a2.bsp
of2a3.bsp
of2a4.bsp
of2a5.bsp
of2a6.bsp
of3a1b.bsp
of3a1.bsp
of3a2.bsp
of3a4.bsp
of3a5.bsp
of3a6.bsp
of4a1.bsp
of4a2.bsp
of4a3.bsp
of4a4.bsp
of4a5.bsp
of5a1.bsp
of5a2.bsp
of5a3.bsp
of5a4.bsp
of6a1.bsp
of6a2.bsp
of6a3.bsp
of6a4b.bsp
of6a4.bsp
of6a5.bsp
of7a0.bsp
ofboot0.bsp
ofboot1.bsp
ofboot2.bsp
ofboot3.bsp
ofboot4.bsp
of2a5dmo.bsp
of5a3dmo.bsp