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

This commit is contained in:
Marco Cawthorne 2021-03-08 11:11:06 +01:00
commit a3ef032823
36 changed files with 2963 additions and 0 deletions

15
LICENSE Normal file
View File

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

46
README.md Normal file
View File

@ -0,0 +1,46 @@
# FreeSci
Clean-room reimplementation of Scientist Hunt in QuakeC.
Scientist Hunt was a Half-Life mod in which you had to contain the spread
of lab-coat wearing beings that populate like crazy.
The original mod was created by Rich Whitehouse.
I'm just nostalgic for it, so I recoded the important bits to use with
FreeHL and Nuclide.
It's not complete (yet).
![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 scihunt
then either run Nuclide's ./build_game.sh shell script, or issue 'make' inside
./scihunt/src!
Obviously make sure that Nuclide has fteqw and fteqcc set-up for building.
## Community
Join us on #halflife or #scihunt 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: 47 KiB

BIN
img/preview2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

BIN
img/preview3.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

BIN
img/preview4.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

5
src/.kdev4/src.kdev4 Normal file
View File

@ -0,0 +1,5 @@
[Buildset]
BuildItems=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x01\x00\x00\x00\x0b\x00\x00\x00\x00\x01\x00\x00\x00\x1c\x00S\x00c\x00i\x00e\x00n\x00t\x00i\x00s\x00t\x00 \x00H\x00u\x00n\x00t)
[Project]
VersionControlSupport=kdevgit

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

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

@ -0,0 +1,38 @@
#pragma target fte
#pragma progs_dat "../../csprogs.dat"
#define CSQC
#define CLIENT
#define VALVE
#define CLASSIC_VGUI
#define GS_RENDERFX
#includelist
../../../src/shared/fteextensions.qc
../../../src/shared/defs.h
../../../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
../../../valve/src/client/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
../../../valve/src/client/hud_weaponselect.qc
../../../valve/src/client/scoreboard.qc
../../../valve/src/client/input.qc
../../../base/src/client/modelevent.qc
../../../src/client/include.src
../../../src/shared/include.src
#endlist

2
src/progs.src Executable file
View File

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

4
src/server/Makefile Normal file
View File

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

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

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

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

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

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

@ -0,0 +1,399 @@
/*
* 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_sh_insanity = 10;
var int autocvar_sv_playerkeepalive = TRUE;
void
SHMultiplayerRules::PlayerDeath(base_player pl)
{
/* obituary networking */
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_OBITUARY);
if (g_dmg_eAttacker.netname)
WriteString(MSG_MULTICAST, g_dmg_eAttacker.netname);
else
WriteString(MSG_MULTICAST, g_dmg_eAttacker.classname);
WriteString(MSG_MULTICAST, pl.netname);
WriteByte(MSG_MULTICAST, g_dmg_iWeapon);
WriteByte(MSG_MULTICAST, 0);
msg_entity = world;
multicast([0,0,0], MULTICAST_ALL);
/* death-counter */
pl.deaths++;
forceinfokey(pl, "*deaths", ftos(pl.deaths));
/* update score-counter */
if (pl.flags & FL_CLIENT || pl.flags & FL_MONSTER)
if (g_dmg_eAttacker.flags & FL_CLIENT) {
if (pl == g_dmg_eAttacker)
g_dmg_eAttacker.frags--;
else
g_dmg_eAttacker.frags++;
}
pl.movetype = MOVETYPE_NONE;
pl.solid = SOLID_NOT;
pl.takedamage = DAMAGE_NO;
pl.gflags &= ~GF_FLASHLIGHT;
pl.armor = pl.activeweapon = pl.g_items = 0;
pl.think = PutClientInServer;
pl.nextthink = time + 4.0f;
Sound_Play(pl, CHAN_AUTO, "player.die");
if (pl.health < -50) {
pl.health = 0;
FX_GibHuman(pl.origin);
return;
}
pl.health = 0;
/* Let's handle corpses on the clientside */
entity corpse = spawn();
setorigin(corpse, pl.origin + [0,0,32]);
setmodel(corpse, pl.model);
setsize(corpse, VEC_HULL_MIN, VEC_HULL_MAX);
corpse.movetype = MOVETYPE_TOSS;
corpse.solid = SOLID_TRIGGER;
corpse.modelindex = pl.modelindex;
corpse.frame = ANIM_DIESIMPLE;
corpse.angles = pl.angles;
corpse.velocity = pl.velocity;
}
void
SHMultiplayerRules::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));
spot = Spawn_SelectRandom("info_player_deathmatch");
setorigin(pl, spot.origin);
pl.angles = spot.angles;
pl.g_items = ITEM_CROWBAR | ITEM_GLOCK | ITEM_SUIT;
pl.activeweapon = WEAPON_GLOCK;
pl.glock_mag = 18;
pl.ammo_9mm = 44;
Weapons_RefreshAmmo(pl);
SHData_GetItems(pl);
Client_FixAngle(pl, pl.angles);
}
void
SHMultiplayerRules::LevelDecodeParms(base_player pp)
{
player pl = (player)pp;
g_landmarkpos[0] = parm1;
g_landmarkpos[1] = parm2;
g_landmarkpos[2] = parm3;
pl.angles[0] = parm4;
pl.angles[1] = parm5;
pl.angles[2] = parm6;
pl.velocity[0] = parm7;
pl.velocity[1] = parm8;
pl.velocity[2] = parm9;
pl.g_items = parm10;
pl.activeweapon = parm11;
pl.flags = parm64;
pl.ammo_9mm = parm12;
pl.ammo_357 = parm13;
pl.ammo_buckshot = parm14;
pl.ammo_m203_grenade = parm15;
pl.ammo_bolt = parm16;
pl.ammo_rocket = parm17;
pl.ammo_uranium = parm18;
pl.ammo_handgrenade = parm19;
pl.ammo_satchel = parm20;
pl.ammo_tripmine = parm21;
pl.ammo_snark = parm22;
pl.ammo_hornet = parm23;
pl.glock_mag = parm24;
pl.mp5_mag = parm25;
pl.python_mag = parm26;
pl.shotgun_mag = parm27;
pl.crossbow_mag = parm28;
pl.rpg_mag = parm29;
pl.satchel_chg = parm30;
if (pl.flags & FL_CROUCHING) {
setsize(pl, VEC_CHULL_MIN, VEC_CHULL_MAX);
} else {
setsize(pl, VEC_HULL_MIN, VEC_HULL_MAX);
}
}
void
SHMultiplayerRules::LevelChangeParms(base_player pp)
{
player pl = (player)pp;
parm1 = g_landmarkpos[0];
parm2 = g_landmarkpos[1];
parm3 = g_landmarkpos[2];
parm4 = pl.angles[0];
parm5 = pl.angles[1];
parm6 = pl.angles[2];
parm7 = pl.velocity[0];
parm8 = pl.velocity[1];
parm9 = pl.velocity[2];
parm64 = pl.flags;
parm10 = pl.g_items;
parm11 = pl.activeweapon;
parm12 = pl.ammo_9mm;
parm13 = pl.ammo_357;
parm14 = pl.ammo_buckshot;
parm15 = pl.ammo_m203_grenade;
parm16 = pl.ammo_bolt;
parm17 = pl.ammo_rocket;
parm18 = pl.ammo_uranium;
parm19 = pl.ammo_handgrenade;
parm20 = pl.ammo_satchel;
parm21 = pl.ammo_tripmine;
parm22 = pl.ammo_snark;
parm23 = pl.ammo_hornet;
parm24 = pl.glock_mag;
parm25 = pl.mp5_mag;
parm26 = pl.python_mag;
parm27 = pl.shotgun_mag;
parm28 = pl.crossbow_mag;
parm29 = pl.rpg_mag;
parm30 = pl.satchel_chg;
}
void
SHMultiplayerRules::LevelNewParms(void)
{
parm1 = parm2 = parm3 = parm4 = parm5 = parm6 = parm7 =
parm8 = parm9 = parm10 = parm11 = parm12 = parm13 = parm14 =
parm15 = parm16 = parm17 = parm18 = parm19 = parm20 = parm21 =
parm22 = parm23 = parm24 = parm25 = parm26 = parm27 = parm28 =
parm29 = parm30 = 0;
parm64 = FL_CLIENT;
}
/* we check what fields have changed over the course of the frame and network
* only the ones that have actually changed */
void
SHMultiplayerRules::PlayerPostFrame(base_player pp)
{
player pl = (player)pp;
Animation_PlayerUpdate();
if (autocvar_sv_playerkeepalive)
pl.SendFlags |= PLAYER_KEEPALIVE;
if (pl.old_modelindex != pl.modelindex)
pl.SendFlags |= PLAYER_MODELINDEX;
if (pl.old_origin[0] != pl.origin[0])
pl.SendFlags |= PLAYER_ORIGIN;
if (pl.old_origin[1] != pl.origin[1])
pl.SendFlags |= PLAYER_ORIGIN;
if (pl.old_origin[2] != pl.origin[2])
pl.SendFlags |= PLAYER_ORIGIN_Z;
if (pl.old_angles[0] != pl.v_angle[0])
pl.SendFlags |= PLAYER_ANGLES_X;
if (pl.old_angles[1] != pl.angles[1])
pl.SendFlags |= PLAYER_ANGLES_Y;
if (pl.old_angles[2] != pl.angles[2])
pl.SendFlags |= PLAYER_ANGLES_Z;
if (pl.old_velocity[0] != pl.velocity[0])
pl.SendFlags |= PLAYER_VELOCITY;
if (pl.old_velocity[1] != pl.velocity[1])
pl.SendFlags |= PLAYER_VELOCITY;
if (pl.old_velocity[2] != pl.velocity[2])
pl.SendFlags |= PLAYER_VELOCITY_Z;
if (pl.old_flags != pl.flags)
pl.SendFlags |= PLAYER_FLAGS;
if (pl.old_gflags != pl.gflags)
pl.SendFlags |= PLAYER_FLAGS;
if (pl.old_activeweapon != pl.activeweapon)
pl.SendFlags |= PLAYER_WEAPON;
if (pl.old_items != pl.g_items)
pl.SendFlags |= PLAYER_ITEMS;
if (pl.old_health != pl.health)
pl.SendFlags |= PLAYER_HEALTH;
if (pl.old_armor != pl.armor)
pl.SendFlags |= PLAYER_ARMOR;
if (pl.old_movetype != pl.movetype)
pl.SendFlags |= PLAYER_MOVETYPE;
if (pl.old_viewofs != pl.view_ofs[2])
pl.SendFlags |= PLAYER_VIEWOFS;
if (pl.old_baseframe != pl.baseframe)
pl.SendFlags |= PLAYER_BASEFRAME;
if (pl.old_frame != pl.frame)
pl.SendFlags |= PLAYER_FRAME;
if (pl.old_a_ammo1 != pl.a_ammo1)
pl.SendFlags |= PLAYER_AMMO1;
if (pl.old_a_ammo2 != pl.a_ammo2)
pl.SendFlags |= PLAYER_AMMO2;
if (pl.old_a_ammo3 != pl.a_ammo3)
pl.SendFlags |= PLAYER_AMMO3;
pl.old_modelindex = pl.modelindex;
pl.old_origin = pl.origin;
pl.old_angles = pl.angles;
pl.old_angles[0] = pl.v_angle[0];
pl.old_velocity = pl.velocity;
pl.old_flags = pl.flags;
pl.old_gflags = pl.gflags;
pl.old_activeweapon = pl.activeweapon;
pl.old_items = pl.g_items;
pl.old_health = pl.health;
pl.old_armor = pl.armor;
pl.old_movetype = pl.movetype;
pl.old_viewofs = pl.view_ofs[2];
pl.old_baseframe = pl.baseframe;
pl.old_frame = pl.frame;
pl.old_a_ammo1 = pl.a_ammo1;
pl.old_a_ammo2 = pl.a_ammo2;
pl.old_a_ammo3 = pl.a_ammo3;
pl.sh_insaneactive = bound(0.0f, pl.sh_insaneactive - frametime, pl.sh_insaneactive);
if (pl.sh_insaneactive > 0.0f)
pl.flags |= FL_RESERVED1;
else {
if (pl.flags & FL_RESERVED1) {
bprint(PRINT_CHAT, sprintf("%s is no longer insane!\n", pl.netname));
}
pl.flags &= ~FL_RESERVED1;
}
}
void
SHMultiplayerRules::PlayerConnect(base_player pl)
{
if (Plugin_PlayerConnect(pl) == FALSE)
bprint(PRINT_HIGH, sprintf("%s connected\n", pl.netname));
}
void
SHMultiplayerRules::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
SHMultiplayerRules::PlayerKill(base_player pp)
{
player pl = (player)pp;
Damage_Apply(pl, pl, pl.health, WEAPON_NONE, DMG_SKIP_ARMOR);
}
void
SHMultiplayerRules::ScientistKill(base_player pp, entity sci)
{
player pl = (player)pp;
/* obituary networking */
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_OBITUARY);
WriteString(MSG_MULTICAST, pl.netname);
WriteString(MSG_MULTICAST, sci.netname);
WriteByte(MSG_MULTICAST, g_dmg_iWeapon);
WriteByte(MSG_MULTICAST, 0);
msg_entity = world;
multicast([0,0,0], MULTICAST_ALL);
pl.frags++;
/*if (g_weapons[g_dmg_iWeapon].slot != 0)
return;*/
/* if this is our first kill in a while, or in the timer... */
if (pl.sh_insanecount == 0 || pl.sh_insanetime > time) {
pl.sh_insanecount++;
} else {
pl.sh_insanecount = 0;
}
if (pl.sh_insanecount >= autocvar_sh_insanity) {
if (pl.sh_insaneactive <= 0.0f)
bprint(PRINT_CHAT, sprintf("%s is going insane!\n", pl.netname));
pl.sh_insaneactive += 3.0f;
if (pl.sh_insaneactive > 60)
pl.sh_insaneactive = 60;
}
/* timer gets touched every time */
pl.sh_insanetime = time + 2.0f;
}

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

@ -0,0 +1,68 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
=================
Input_Handle
Handles impulse and whatnot
=================
*/
void Game_Input(void)
{
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 == 102) {
// Respawn all the entities
for (entity a = world; (a = findfloat(a, ::identity, 1));) {
CBaseEntity caw = (CBaseEntity)a;
caw.Respawn();
}
bprint(PRINT_HIGH, "Respawning all map entities...\n");
}
if (self.impulse == 103) {
for (entity a = world; (a = find(a, classname, "func_breakable"));) {
func_breakable caw = (func_breakable)a;
caw.Death();
}
bprint(PRINT_HIGH, "BREAK EVERYTHING!\n");
}
}
self.impulse = 0;
}

View File

@ -0,0 +1,337 @@
/*
* 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_sh_scialert = FALSE;
var int autocvar_sh_scispeed = 40;
var int autocvar_sh_sciattack = TRUE;
enum
{
SCIA_WALK,
SCIA_WALKSCARED,
SCIA_RUN,
SCIA_RUNSCARED,
SCIA_RUNLOOK,
SCIA_180LEFT,
SCIA_180RIGHT,
SCIA_FLINCH,
SCIA_PAIN,
SCIA_PAINLEFT,
SCIA_PAINRIGHT,
SCIA_PAINLEGLEFT,
SCIA_PAINLEGRIGHT,
SCIA_IDLE1,
SCIA_IDLE2,
SCIA_IDLE3,
SCIA_IDLE4,
SCIA_IDLE5,
SCIA_IDLE6,
SCIA_SCARED_END,
SCIA_SCARED1,
SCIA_SCARED2,
SCIA_SCARED3,
SCIA_SCARED4,
SCIA_PANIC,
SCIA_FEAR1,
SCIA_FEAR2,
SCIA_CRY,
SCIA_SCI1,
SCIA_SCI2,
SCIA_SCI3,
SCIA_DIE_SIMPLE,
SCIA_DIE_FORWARD1,
SCIA_DIE_FORWARD2,
SCIA_DIE_BACKWARD,
SCIA_DIE_HEADSHOT,
SCIA_DIE_GUTSHOT,
SCIA_LYING1,
SCIA_LYING2,
SCIA_DEADSIT,
SCIA_DEADTABLE1,
SCIA_DEADTABLE2,
SCIA_DEADTABLE3
};
class monster_scientist:CBaseNPC
{
void(void) monster_scientist;
virtual void(void) Respawn;
virtual void(void) Pain;
virtual void(void) Death;
virtual void(void) OnPlayerUse;
virtual void(void) TalkPanic;
virtual int(void) AnimIdle;
virtual int(void) AnimWalk;
virtual int(void) AnimRun;
virtual int(void) AttackMelee;
virtual void(void) AttackNeedle;
};
int
monster_scientist::AttackMelee(void)
{
/* visual */
AnimPlay(28);
m_flAttackThink = m_flAnimTime;
float r = random();
if (r < 0.33)
Sentence("!SC_CUREA");
else if (r < 0.66)
Sentence("!SC_CUREB");
else
Sentence("!SC_CUREC");
/* functional */
think = AttackNeedle;
nextthink = 0.25f;
return TRUE;
}
void
monster_scientist::AttackNeedle(void)
{
traceline(origin, m_eEnemy.origin, FALSE, this);
if (trace_fraction >= 1.0 || trace_ent.takedamage != DAMAGE_YES) {
return;
}
Damage_Apply(trace_ent, this, 25, 0, 0);
AnimPlay(30);
}
int
monster_scientist::AnimIdle(void)
{
return SCIA_IDLE1;
}
int
monster_scientist::AnimWalk(void)
{
return SCIA_WALK;
}
int
monster_scientist::AnimRun(void)
{
return SCIA_RUN;
}
void
monster_scientist::TalkPanic(void)
{
int r = floor(random(0,30));
switch (r) {
case 1:
Sentence("!SC_SCARED1"); //scientist/stopattacking
break;
case 2:
Sentence("!SC_SCARED2"); //scientist/youinsane
break;
case 3:
Sentence("!SC_PLFEAR0"); //scientist/whatyoudoing
break;
case 4:
Sentence("!SC_PLFEAR2"); //scientist/madness
break;
case 5:
Sentence("!SC_PLFEAR3"); //scientist/noplease
break;
case 6:
Sentence("!SC_PLFEAR4"); //scientist/getoutofhere
break;
case 7:
Sentence("!SC_FEAR3"); //scientist/dontwantdie
break;
case 8:
Sentence("!SC_FEAR4"); //scientist/getoutalive
break;
case 9:
Sentence("!SC_FEAR5"); //scientist/startle3
break;
case 10:
Sentence("!SC_FEAR6"); //scientist/startle4
break;
case 11:
Sentence("!SC_FEAR7"); //scientist/startle5
break;
case 12:
Sentence("!SC_FEAR8"); //scientist/startle6
break;
case 13:
Sentence("!SC_FEAR9"); //scientist/startle7
break;
case 14:
Sentence("!SC_FEAR10"); //scientist/startle8
break;
case 15:
Sentence("!SC_FEAR11"); //scientist/startle9
break;
case 16:
Sentence("!SC_FEAR12"); //scientist/startle1
break;
default:
Sentence("!SC_SCREAM"); //scientist/sci_fear15
}
m_flNextSentence = time + 2.0 + random(0,3);
}
void
monster_scientist::Pain(void)
{
if (autocvar_sh_sciattack)
CBaseMonster::Pain();
StartleAllies();
if (m_flAnimTime > time) {
return;
}
if (random() < 0.25f) {
return;
}
Sound_Speak(this, "monster_scientist.pain");
frame = SCIA_FLINCH + floor(random(0, 6));
m_flAnimTime = time + 0.25f;
m_iFlags |= MONSTER_FEAR;
}
void
monster_scientist::Death(void)
{
WarnAllies();
if (style != MONSTER_DEAD) {
SHMultiplayerRules rules = (SHMultiplayerRules)g_grMode;
if (g_dmg_eAttacker.flags & FL_CLIENT)
rules.ScientistKill((player)g_dmg_eAttacker, (entity)this);
Plugin_PlayerObituary(g_dmg_eAttacker, this, g_dmg_iWeapon, g_dmg_iHitBody, g_dmg_iDamage);
SetFrame(SCIA_DIE_SIMPLE + floor(random(0, 6)));
Sound_Speak(this, "monster_scientist.die");
}
/* now mark our state as 'dead' */
CBaseNPC::Death();
}
void
monster_scientist::OnPlayerUse(void)
{
if (m_iFlags & MONSTER_FEAR)
return;
CBaseNPC::OnPlayerUse();
}
void
monster_scientist::Respawn(void)
{
CBaseNPC::Respawn();
m_iFlags |= MONSTER_CANFOLLOW;
PlayerUse = OnPlayerUse;
if (autocvar_sh_scialert) {
m_iFlags |= MONSTER_FEAR;
}
}
void
monster_scientist::monster_scientist(void)
{
spawnflags |= MSF_MULTIPLAYER;
Sound_Precache("monster_scientist.die");
Sound_Precache("monster_scientist.pain");
m_iBody = -1;
for (int i = 1; i < (tokenize(__fullspawndata)-1); i += 2) {
switch (argv(i)) {
case "body":
m_iBody = stoi(argv(i+1)) + 1;
break;
default:
break;
}
}
m_talkAsk = "!SC_QUESTION";
m_talkPlayerAsk = "!SC_PQUEST";
m_talkPlayerGreet = "!SC_PHELLO";
m_talkPlayerIdle = "!SC_PIDLE";
m_talkAnswer = "!SC_ANSWER";
m_talkAllyShot = "!SC_PLFEAR";
m_talkGreet = "";
m_talkIdle = "!SC_IDLE";
m_talkHearing = "!SC_HEAR";
m_talkSmelling = "!SC_SMELL";
m_talkStare = "!SC_STARE";
m_talkSurvived = "!SC_WOUND";
m_talkWounded = "!SC_MORTAL";
m_talkUnfollow = "!SC_WAIT";
m_talkFollow = "!SC_OK";
m_talkStopFollow = "!SC_STOP";
m_iBody = -1;
if (autocvar_sh_sciattack)
m_iAlliance = MAL_ALIEN;
model = "models/scientist.mdl";
base_mins = [-16,-16,0];
base_maxs = [16,16,72];
CBaseNPC::CBaseNPC();
precache_model(m_oldModel);
base_health = Skill_GetValue("scientist_health", 20);
if (m_iBody == -1) {
/* This stuff needs to be persistent because we can't guarantee that
* the client-side geomset refresh happens. Don't shove this into Respawn */
m_iBody = floor(random(1,5));
}
switch (m_iBody) {
case 1:
m_flPitch = 105;
netname = "Walter";
break;
case 2:
m_flPitch = 100;
netname = "Einstein";
break;
case 3:
m_flPitch = 95;
netname = "Luther";
skin = 1;
break;
default:
m_flPitch = 100;
netname = "Slick";
}
}

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

@ -0,0 +1,89 @@
#pragma target fte
#pragma progs_dat "../../progs.dat"
#define QWSSQC
#define SERVER
#define VALVE
#define SCIHUNT
#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_sentry.qc
../../../valve/src/server/monster_tentacle.qc
../../../valve/src/server/monster_turret.qc
../../../valve/src/server/monster_zombie.qc
monster_scientist.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
shdata_parse.qc
gamerules.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
../../../src/botlib/include.src
input.qc
../../../valve/src/server/spawn.qc
../../../src/server/include.src
../../../src/shared/include.src
#endlist

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

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

138
src/server/shdata_parse.qc Normal file
View File

@ -0,0 +1,138 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* If only origin parameters are applied, make something up */
var int autocvar_sh_sciyaw = TRUE;
/* Limit the amount of scientists spawned */
var int autocvar_sh_scimax = 30;
void SHData_SpawnScientist(void)
{
static int slimit = 0;
if (autocvar_sh_scimax) {
if (slimit >= autocvar_sh_scimax) {
dprint("shdata: scientist limit hit. ignored\n");
remove(self);
return;
}
slimit++;
}
spawnfunc_monster_scientist();
}
void SHData_New(void)
{
entity new = spawn();
new.origin[0] = stof(argv(1));
new.origin[1] = stof(argv(2));
new.origin[2] = stof(argv(3));
if (autocvar_sh_sciyaw) {
new.angles[1] = Math_FixDelta(random(0,360));
}
setorigin(new, new.origin);
entity oldself = self;
self = new;
if (argv(0) == "monster_scientist") {
SHData_SpawnScientist();
} else if (argv(0) == "info_player_team1") {
self.classname = "info_player_deathmatch";
} else if (argv(0) == "info_player_team2") {
self.classname = "info_player_deathmatch";
}
self = oldself;
}
void SHData_NewAngles(void)
{
entity new = spawn();
new.origin[0] = stof(argv(1));
new.origin[1] = stof(argv(2));
new.origin[2] = stof(argv(3));
new.angles[0] = stof(argv(4));
new.angles[1] = stof(argv(5));
new.angles[2] = stof(argv(6));
setorigin(new, new.origin);
entity oldself = self;
self = new;
if (argv(0) == "monster_scientist") {
SHData_SpawnScientist();
} else if (argv(0) == "info_player_team1") {
self.classname = "info_player_deathmatch";
} else if (argv(0) == "info_player_team2") {
self.classname = "info_player_deathmatch";
}
self = oldself;
}
void SHData_GetItems(player pl)
{
/* TODO: Parse the config files */
pl.ammo_9mm = 68;
pl.ammo_buckshot = 34;
pl.ammo_bolt = 50;
pl.ammo_357 = 36;
pl.ammo_m203_grenade = 3;
pl.ammo_rocket = 5;
pl.ammo_snark = 10;
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_CANNON, -1);
Weapons_AddItem(pl, WEAPON_CHAINSAW, -1);
Weapons_AddItem(pl, WEAPON_HAMMER, -1);
}
void SHData_Parse(string map)
{
int c;
string temp;
filestream shdfile = fopen(sprintf("SH_Data/%s.shd", map), FILE_READ);
if (shdfile < 0) {
dprint(sprintf("^1WARNING^7: Could not load SH_Data/%s.shd\n", map));
return;
}
if (shdfile >= 0) {
while ((temp = fgets(shdfile))) {
c = tokenize(temp);
if (c == 4) {
SHData_New();
} else if (c == 7) {
SHData_NewAngles();
}
}
}
}

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

@ -0,0 +1,39 @@
#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
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_cannon.qc
w_chainsaw.qc
w_hammer.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 0x00000001
#define ITEM_GLOCK 0x00000002
#define ITEM_PYTHON 0x00000004
#define ITEM_MP5 0x00000008
#define ITEM_CROSSBOW 0x00000010
#define ITEM_SHOTGUN 0x00000020
#define ITEM_RPG 0x00000040
#define ITEM_GAUSS 0x00000080
#define ITEM_EGON 0x00000100
#define ITEM_HORNETGUN 0x00000200
#define ITEM_HANDGRENADE 0x00000400
#define ITEM_TRIPMINE 0x00000800
#define ITEM_SATCHEL 0x00001000
#define ITEM_SNARK 0x00002000
#define ITEM_SUIT 0x00004000
#define ITEM_LONGJUMP 0x00008000
#define ITEM_HEALTHKIT 0x00010000
#define ITEM_BATTERY 0x00020000
#define ITEM_CANNON 0x00040000
#define ITEM_CHAINSAW 0x00080000
#define ITEM_HAMMER 0x00100000
#define ITEM_UNUSED22 0x00200000
#define ITEM_UNUSED23 0x00400000
#define ITEM_UNUSED24 0x00800000
#define ITEM_UNUSED25 0x01000000
#define ITEM_UNUSED26 0x02000000
#define ITEM_UNUSED27 0x04000000
#define ITEM_UNUSED28 0x08000000
#define ITEM_UNUSED29 0x10000000
#define ITEM_UNUSED30 0x20000000
#define ITEM_UNUSED31 0x40000000
#define ITEM_UNUSED32 0x80000000

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

@ -0,0 +1,710 @@
/*
* 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,
AMMO1_CANNON
};
/* 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,
AMMO3_CHAINSAW_STATE,
AMMO3_HAMMER_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 cannon_mag;
int cannon_mag_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;
int ammo_chainsaw_state;
int ammo_chainsaw_state_net;
int ammo_hammer_state;
int ammo_hammer_state_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;
int sh_insanecount;
float sh_insanetime;
float sh_insaneactive;
#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();
cannon_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();
}
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();
ammo_chainsaw_state = readbyte();
ammo_hammer_state = 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;
cannon_mag_net = cannon_mag;
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;
ammo_chainsaw_state_net = ammo_chainsaw_state;
ammo_hammer_state_net = ammo_hammer_state;
}
/*
=================
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;
cannon_mag = cannon_mag_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;
ammo_chainsaw_state = ammo_chainsaw_state_net;
ammo_hammer_state = ammo_hammer_state_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;
}
if (cannon_mag != cannon_mag_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;
}
if (ammo_chainsaw_state != ammo_chainsaw_state_net) {
SendFlags |= PLAYER_AMMO3;
}
if (ammo_hammer_state != ammo_hammer_state_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;
cannon_mag_net = cannon_mag;
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;
ammo_chainsaw_state_net = ammo_chainsaw_state;
ammo_hammer_state_net = ammo_hammer_state;
}
/*
=================
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);
WriteByte(MSG_ENTITY, cannon_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);
}
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);
WriteByte(MSG_ENTITY, ammo_chainsaw_state);
WriteByte(MSG_ENTITY, ammo_hammer_state);
}
return TRUE;
}
#endif

73
src/shared/pmove.qc Normal file
View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define PHY_JUMP_CHAINWINDOW 0.5
#define PHY_JUMP_CHAIN 100
#define PHY_JUMP_CHAINDECAY 50
.float waterlevel;
.float watertype;
float GamePMove_Maxspeed(player target)
{
if (target.flags & FL_RESERVED1)
return (target.flags & FL_CROUCHING) ? 135 : 500;
else
return (target.flags & FL_CROUCHING) ? 135 : 270;
}
void GamePMove_Fall(player target, float impactspeed)
{
if (impactspeed > 580) {
#ifdef SERVER
float fFallDamage = (impactspeed - 580) * (100 / (1024 - 580));
Damage_Apply(self, world, fFallDamage, 0, DMG_FALL);
Sound_Play(self, CHAN_AUTO, "player.fall");
#endif
}
}
void GamePMove_Jump(player target)
{
float flJumptimeDelta;
float flChainBonus;
if (target.waterlevel >= 2) {
if (target.watertype == CONTENT_WATER) {
target.velocity[2] = 100;
} else if (target.watertype == CONTENT_SLIME) {
target.velocity[2] = 80;
} else {
target.velocity[2] = 50;
}
} else {
/* Half-Life: Longjump module */
#ifdef VALVE
if (target.flags & FL_CROUCHING && target.g_items & 0x00008000i) {
target.velocity = v_forward * 512;
target.velocity[2] += 100;
}
#endif
target.velocity[2] += 240;
}
if (target.jumptime > 0) {
flJumptimeDelta = 0 - (target.jumptime - PHY_JUMP_CHAINWINDOW);
flChainBonus = PHY_JUMP_CHAIN - (((PHY_JUMP_CHAINWINDOW - (PHY_JUMP_CHAINWINDOW - flJumptimeDelta)) * 2) * PHY_JUMP_CHAINDECAY);
target.velocity[2] += flChainBonus;
}
target.jumptime = PHY_JUMP_CHAINWINDOW;
}

279
src/shared/w_cannon.qc Normal file
View File

@ -0,0 +1,279 @@
/*
* 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.
*/
#ifdef CLIENT
var string g_cannon_spr;
#endif
typedef enum
{
CANNON_FIREBOTH,
CANNON_FIRELEFT,
CANNON_FIRERIGHT,
CANNON_RELOAD,
CANNON_DEPLOY,
CANNON_PUTAWAY,
CANNON_IDLE1,
CANNON_IDLE2
} cannonAnims_t;
void
w_cannon_precache(void)
{
#ifdef SERVER
precache_sound("cannon/cin.wav");
precache_sound("cannon/close.wav");
precache_sound("cannon/cout.wav");
precache_sound("cannon/fire.wav");
precache_sound("cannon/open.wav");
#else
precache_model("models/v_cannon.mdl");
precache_model("models/p_cannon.mdl");
g_cannon_spr = spriteframe("sprites/w_cannon.spr", 0, 0.0f);
#endif
}
void
w_cannon_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, pl.cannon_mag, pl.ammo_buckshot, -1);
}
string
w_cannon_pmodel(void)
{
return "models/p_cannon.mdl";
}
string
w_cannon_deathmsg(void)
{
return "%s killed %s with handcannon.";
}
void
w_cannon_reload(void)
{
player pl = (player)self;
if (pl.w_attack_next > 0) {
return;
}
if (pl.cannon_mag >= 2) {
return;
}
if (!pl.ammo_buckshot) {
return;
}
#ifdef CLIENT
Weapons_ViewAnimation(CANNON_RELOAD);
#else
Weapons_ReloadWeapon(pl, player::cannon_mag, player::ammo_buckshot, 2);
#endif
pl.w_attack_next = 3.0f;
pl.w_idle_next = 3.0f;
}
int
w_cannon_pickup(int new, int startammo)
{
#ifdef SERVER
player pl = (player)self;
if (new) {
pl.cannon_mag = 2;
} else {
if (pl.ammo_buckshot < 125) {
pl.ammo_buckshot = bound(0, pl.ammo_buckshot + 2, 125);
} else {
return FALSE;
}
}
#endif
return TRUE;
}
void
w_cannon_draw(void)
{
Weapons_SetModel("models/v_cannon.mdl");
Weapons_ViewAnimation(CANNON_DEPLOY);
}
void
w_cannon_holster(void)
{
Weapons_ViewAnimation(CANNON_PUTAWAY);
}
void
w_cannon_primary(void)
{
player pl = (player)self;
if (pl.w_attack_next > 0.0) {
return;
}
if (pl.cannon_mag != 2) {
w_cannon_reload();
return;
}
#ifdef CLIENT
View_SetMuzzleflash(MUZZLE_SMALL);
#else
int dmg;
dmg = Skill_GetValue("plr_cannon", 5);
TraceAttack_FireBullets(20, pl.origin + pl.view_ofs, dmg, [0.08716,0.04362], WEAPON_CANNON);
pl.cannon_mag -= 2;
Weapons_PlaySound(pl, CHAN_WEAPON, "cannon/fire.wav", 1, ATTN_NORM);
Weapons_UpdateAmmo(pl, pl.cannon_mag, pl.ammo_buckshot, __NULL__);
#endif
Weapons_ViewPunchAngle([-5,0,0]);
Weapons_ViewAnimation(CANNON_FIREBOTH);
pl.w_attack_next = 1.5f;
pl.w_idle_next = 2.5f;
}
void
w_cannon_secondary(void)
{
player pl = (player)self;
if (pl.w_attack_next > 0.0) {
return;
}
if (!pl.cannon_mag) {
w_cannon_reload();
return;
}
#ifdef CLIENT
Weapons_ViewPunchAngle([-5,0,0]);
#else
int dmg;
dmg = Skill_GetValue("plr_cannon", 5);
TraceAttack_FireBullets(10, pl.origin + pl.view_ofs, dmg, [0.08716,0.04362], WEAPON_CANNON);
pl.cannon_mag--;
Weapons_PlaySound(pl, CHAN_WEAPON, "cannon/fire.wav", 1, ATTN_NORM);
#endif
if (pl.cannon_mag == 2) {
Weapons_ViewAnimation(CANNON_FIRELEFT);
} else {
Weapons_ViewAnimation(CANNON_FIRERIGHT);
}
pl.w_attack_next = 1.5f;
pl.w_idle_next = 2.5f;
}
void
w_cannon_release(void)
{
player pl = (player)self;
/* auto-reload if need be */
if (pl.w_attack_next <= 0.0)
if (pl.cannon_mag == 0 && pl.ammo_buckshot > 0) {
Weapons_Reload();
return;
}
if (pl.w_idle_next > 0.0) {
return;
}
int r = floor(random(0,2));
switch (r) {
case 0:
Weapons_ViewAnimation(CANNON_IDLE1);
break;
case 1:
Weapons_ViewAnimation(CANNON_IDLE2);
break;
}
pl.w_idle_next = 8.0f;
}
void
w_cannon_crosshair(void)
{
#ifdef CLIENT
static vector cross_pos;
cross_pos = g_hudmins + (g_hudres / 2) + [-12,-12];
drawsubpic(cross_pos, [24,24], g_cross_spr, [48/128,24/128], [0.1875, 0.1875], [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], g_hud7_spr, [72/256,72/128], [24/256, 24/128], g_hud_color, pSeat->m_flAmmo2Alpha, DRAWFLAG_ADDITIVE);
#endif
}
float
w_cannon_aimanim(void)
{
return self.flags & FL_CROUCHING ? ANIM_CR_AIMSHOTGUN : ANIM_AIMSHOTGUN;
}
void
w_cannon_hudpic(int s, vector pos, float a)
{
#ifdef CLIENT
player pl = (player)self;
vector hud_col;
if (pl.cannon_mag == 0 && pl.ammo_buckshot == 0)
hud_col = [1,0,0];
else
hud_col = g_hud_color;
if (s) {
drawsubpic(pos, [170,45], g_cannon_spr, [0,48/256], [170/256,45/256], g_hud_color, a, DRAWFLAG_ADDITIVE);
} else {
drawsubpic(pos, [170,45], g_cannon_spr, [0,0], [170/256,45/256], g_hud_color, a, DRAWFLAG_ADDITIVE);
}
HUD_DrawAmmoBar(pos, pl.ammo_buckshot, MAX_A_BUCKSHOT, a);
#endif
}
weapon_t
w_cannon =
{
.name = "handcannon",
.id = ITEM_CANNON,
.slot = 2,
.slot_pos = 3,
.draw = w_cannon_draw,
.holster = w_cannon_holster,
.primary = w_cannon_primary,
.secondary = w_cannon_secondary,
.reload = w_cannon_reload,
.release = w_cannon_release,
.crosshair = w_cannon_crosshair,
.precache = w_cannon_precache,
.pickup = w_cannon_pickup,
.updateammo = w_cannon_updateammo,
.wmodel = __NULL__,
.pmodel = w_cannon_pmodel,
.deathmsg = w_cannon_deathmsg,
.aimanim = w_cannon_aimanim,
.hudpic = w_cannon_hudpic
};

178
src/shared/w_chainsaw.qc Normal file
View File

@ -0,0 +1,178 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef CLIENT
var string g_chainsaw_spr;
#endif
enum
{
CHAINSAW_STARTFIRE,
CHAINSAW_CONTINUEFIRE,
CHAINSAW_STOPFIRE,
CHAINSAW_DEPLOY,
CHAINSAW_HOLSTER,
CHAINSAW_IDLE1,
CHAINSAW_IDLE2,
};
void w_chainsaw_precache(void)
{
#ifdef SERVER
precache_sound("sh/chainsaw_cutinto.wav");
precache_sound("sh/chainsaw_cutintoflesh.wav");
precache_sound("sh/chainsaw_idle.wav");
precache_sound("sh/chainsaw_idle2.wav");
precache_sound("sh/chainsaw_pullout.wav");
precache_sound("sh/chainsaw_startup.wav");
#else
precache_model("models/v_chainsaw.mdl");
precache_model("models/p_saw.mdl");
g_chainsaw_spr = spriteframe("sprites/chainsaw.spr", 0, 0.0f);
#endif
}
void w_chainsaw_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, -1, -1, -1);
}
string w_chainsaw_pmodel(void)
{
return "models/p_saw.mdl";
}
string w_chainsaw_deathmsg(void)
{
return "%s killed %s with chainsaw.";
}
void w_chainsaw_draw(void)
{
Weapons_SetModel("models/v_chainsaw.mdl");
Weapons_ViewAnimation(CHAINSAW_DEPLOY);
}
void w_chainsaw_holster(void)
{
Weapons_ViewAnimation(CHAINSAW_HOLSTER);
}
void w_chainsaw_primary(void)
{
player pl = (player)self;
if (pl.w_attack_next) {
return;
}
pl.ammo_chainsaw_state = 1;
Weapons_ViewAnimation(CHAINSAW_CONTINUEFIRE);
#ifdef SERVER
Weapons_MakeVectors();
vector src = pl.origin + pl.view_ofs;
traceline(src, src + (v_forward * 32), FALSE, pl);
if (trace_fraction >= 1.0) {
Weapons_PlaySound(pl, CHAN_WEAPON, "sh/chainsaw_idle2.wav", 1, ATTN_NORM);
pl.w_attack_next = 0.2f;
} else {
int dmg;
FX_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal);
if (trace_ent.takedamage) {
if (trace_ent.iBleeds) {
/* Push the player towards the victim */
pl.velocity = normalize(trace_ent.origin - pl.origin) * 240;
}
dmg = Skill_GetValue("plr_chainsaw", 10);
Damage_Apply(trace_ent, self, dmg, WEAPON_CHAINSAW, DMG_BLUNT);
Weapons_PlaySound(pl, CHAN_WEAPON, "sh/chainsaw_cutintoflesh.wav", 1, ATTN_NORM);
} else {
FX_Spark(trace_endpos, trace_plane_normal);
Weapons_PlaySound(pl, CHAN_WEAPON, "sh/chainsaw_cutinto.wav", 1, ATTN_NORM);
}
pl.w_attack_next = 0.1f;
}
#endif
pl.w_idle_next = 0.0f;
}
void w_chainsaw_release(void)
{
player pl = (player)self;
if (pl.w_idle_next) {
return;
}
if (pl.ammo_chainsaw_state == 1) {
pl.ammo_chainsaw_state = 0;
pl.w_idle_next = 1.0f;
Weapons_ViewAnimation(CHAINSAW_STOPFIRE);
return;
} else {
pl.w_idle_next = 10.0f;
}
if (random() < 0.5) {
Weapons_ViewAnimation(CHAINSAW_IDLE1);
} else {
Weapons_ViewAnimation(CHAINSAW_IDLE2);
}
}
float w_chainsaw_aimanim(void)
{
return self.flags & FL_CROUCHING ? ANIM_CR_AIMSQUEAK : ANIM_AIMSQUEAK;
}
void w_chainsaw_hudpic(int s, vector pos, float a)
{
#ifdef CLIENT
if (s) {
drawsubpic(pos, [170,45], g_chainsaw_spr,
[0,48/256], [170/256,45/256],
g_hud_color, a, DRAWFLAG_ADDITIVE);
} else {
drawsubpic(pos, [170,45], g_chainsaw_spr,
[0,0], [170/256,45/256],
g_hud_color, a, DRAWFLAG_ADDITIVE);
}
#endif
}
weapon_t w_chainsaw =
{
.name = "chainsaw",
.id = ITEM_CHAINSAW,
.slot = 0,
.slot_pos = 2,
.draw = w_chainsaw_draw,
.holster = w_chainsaw_holster,
.primary = w_chainsaw_primary,
.secondary = w_chainsaw_release,
.reload = w_chainsaw_release,
.release = w_chainsaw_release,
.crosshair = __NULL__,
.precache = w_chainsaw_precache,
.pickup = __NULL__,
.updateammo = w_chainsaw_updateammo,
.wmodel = __NULL__,
.pmodel = w_chainsaw_pmodel,
.deathmsg = w_chainsaw_deathmsg,
.aimanim = w_chainsaw_aimanim,
.hudpic = w_chainsaw_hudpic
};

244
src/shared/w_hammer.qc Normal file
View File

@ -0,0 +1,244 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef CLIENT
var string g_hammer_spr;
#endif
enum
{
HAMMER_IDLE1,
HAMMER_DRAW,
HAMMER_HOLSTER,
HAMMER_ATTACK1,
HAMMER_ATTACK2,
HAMMER_IDLE2,
HAMMER_IDLE3,
HAMMER_HOLSTER2,
HAMMER_HOLSTER3
};
void w_hammer_precache(void)
{
#ifdef SERVER
precache_sound("sh/ham_hitbod1.wav");
precache_sound("sh/ham_hitbod2.wav");
precache_sound("sh/ham_hitbod3.wav");
precache_sound("sh/ham_hitw.wav");
precache_sound("sh/ham_swing.wav");
#else
precache_model("models/p_hammer.mdl");
precache_model("models/v_hammer.mdl");
g_hammer_spr = spriteframe("sprites/hammer.spr", 0, 0.0f);
#endif
}
void w_hammer_updateammo(player pl)
{
Weapons_UpdateAmmo(pl, -1, -1, -1);
}
string w_hammer_pmodel(void)
{
return "models/p_hammer.mdl";
}
string w_hammer_deathmsg(void)
{
return "%s killed %s with hammer.";
}
void w_hammer_draw(void)
{
Weapons_SetModel("models/v_hammer.mdl");
Weapons_ViewAnimation(HAMMER_DRAW);
}
void w_hammer_holster(void)
{
Weapons_ViewAnimation(HAMMER_HOLSTER);
}
void w_hammer_primary(void)
{
player pl = (player)self;
if (!pl.w_attack_next) {
/* Hack */
if (pl.ammo_hammer_state != 1) {
Weapons_ViewAnimation(HAMMER_HOLSTER2);
pl.ammo_hammer_state = 1;
pl.w_attack_next = 0.5f;
}
}
pl.w_idle_next = 2.5f;
}
void w_hammer_secondary(void)
{
player pl = (player)self;
if (!pl.w_attack_next) {
/* Hack */
if (pl.ammo_hammer_state != 2) {
Weapons_ViewAnimation(HAMMER_HOLSTER3);
pl.ammo_hammer_state = 2;
pl.w_attack_next = 0.5f;
}
}
pl.w_idle_next = 2.5f;
}
void w_hammer_reload(void)
{
}
void w_hammer_release(void)
{
player pl = (player)self;
if (pl.w_attack_next) {
return;
}
#ifdef SERVER
int hdmg;
int hitsound = 0;
vector src = pl.origin + pl.view_ofs;
makevectors(pl.v_angle);
traceline(src, src + v_forward * 64, FALSE, self);
#endif
if (pl.ammo_hammer_state == 1) {
#ifdef SERVER
if (trace_ent.takedamage) {
hitsound = floor(random(1, 4));
/* players only take half damage */
if (trace_ent.classname == "player")
hdmg = Skill_GetValue("plr_hammer", 100) / 2;
else
hdmg = Skill_GetValue("plr_hammer", 100);
Damage_Apply(trace_ent, self, hdmg, WEAPON_HAMMER, DMG_BLUNT);
if (trace_ent.classname == "monster_scientist") {
trace_ent.movetype = MOVETYPE_TOSS;
trace_ent.velocity = v_forward * 768 + v_up * 256;
} else if (trace_ent.classname == "player") {
trace_ent.velocity = v_forward * 768 + v_up * 256;
}
} else {
if (trace_fraction < 1.0) {
hitsound = 4;
}
}
#endif
Weapons_ViewAnimation(HAMMER_ATTACK1);
pl.w_attack_next = 1.0f;
} else if (pl.ammo_hammer_state == 2) {
#ifdef SERVER
if (trace_ent.takedamage) {
hitsound = floor(random(1, 4));
hdmg = Skill_GetValue("plr_hammeralt", 200);
Damage_Apply(trace_ent, self, hdmg, WEAPON_HAMMER, DMG_BLUNT);
} else {
if (trace_fraction < 1.0) {
hitsound = 4;
}
}
#endif
Weapons_ViewAnimation(HAMMER_ATTACK2);
pl.w_attack_next = 0.75f;
}
#ifdef SERVER
if (pl.ammo_hammer_state > 0) {
string snd = "sh/ham_swing.wav";
switch (hitsound) {
case 1:
snd = "sh/ham_hitbod1.wav";
break;
case 2:
snd = "sh/ham_hitbod2.wav";
break;
case 3:
snd = "sh/ham_hitbod3.wav";
break;
case 4:
snd = "sh/ham_hitw.wav";
break;
}
Weapons_PlaySound(pl, CHAN_WEAPON, snd, 1.0f, ATTN_NORM);
}
#endif
/* Reset the hack */
pl.ammo_hammer_state = 0;
/* Pure cosmetics start here */
if (pl.w_idle_next) {
return;
}
int r = floor(random(0,3));
switch (r) {
case 0:
Weapons_ViewAnimation(HAMMER_IDLE1);
break;
case 1:
Weapons_ViewAnimation(HAMMER_IDLE2);
break;
case 2:
Weapons_ViewAnimation(HAMMER_IDLE3);
break;
}
pl.w_idle_next = 10.0f;
}
float w_hammer_aimanim(void)
{
return self.flags & FL_CROUCHING ? ANIM_CR_AIMCROWBAR : ANIM_AIMCROWBAR;
}
void w_hammer_hudpic(int s, vector pos, float a)
{
#ifdef CLIENT
if (s) {
drawsubpic(pos, [170,45], g_hammer_spr, [0,48/256], [170/256,45/256], g_hud_color, a, DRAWFLAG_ADDITIVE);
} else {
drawsubpic(pos, [170,45], g_hammer_spr, [0,0], [170/256,45/256], g_hud_color, a, DRAWFLAG_ADDITIVE);
}
#endif
}
weapon_t w_hammer =
{
.name = "hammer",
.id = ITEM_HAMMER,
.slot = 0,
.slot_pos = 1,
.draw = w_hammer_draw,
.holster = w_hammer_holster,
.primary = w_hammer_primary,
.secondary = w_hammer_secondary,
.reload = w_hammer_reload,
.release = w_hammer_release,
.crosshair = __NULL__,
.precache = w_hammer_precache,
.pickup = __NULL__,
.updateammo = w_hammer_updateammo,
.wmodel = __NULL__,
.pmodel = w_hammer_pmodel,
.deathmsg = w_hammer_deathmsg,
.aimanim = w_hammer_aimanim,
.hudpic = w_hammer_hudpic
};

51
src/shared/weapons.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.
*/
/* weapon Indices for the weapon table */
enum
{
WEAPON_NONE,
WEAPON_CROWBAR,
WEAPON_HAMMER,
WEAPON_CHAINSAW,
WEAPON_GLOCK,
WEAPON_PYTHON,
WEAPON_MP5,
WEAPON_SHOTGUN,
WEAPON_CROSSBOW,
WEAPON_CANNON,
WEAPON_RPG,
WEAPON_GAUSS,
WEAPON_EGON,
WEAPON_HORNETGUN,
WEAPON_HANDGRENADE,
WEAPON_SATCHEL,
WEAPON_TRIPMINE,
WEAPON_SNARK
};
#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

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

@ -0,0 +1,37 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
weapon_t w_null = {};
weapon_t g_weapons[] = {
w_null,
w_crowbar,
w_hammer,
w_chainsaw,
w_glock,
w_python,
w_mp5,
w_shotgun,
w_crossbow,
w_cannon,
w_rpg,
w_gauss,
w_egon,
w_hornetgun,
w_handgrenade,
w_satchel,
w_tripmine,
w_snark
};

4
src/src.kdev4 Normal file
View File

@ -0,0 +1,4 @@
[Project]
CreatedFrom=Makefile
Manager=KDevCustomMakeManager
Name=Scientist Hunt

BIN
zpak001.pk3dir/csprogs.dat Normal file

Binary file not shown.

BIN
zpak001.pk3dir/csprogs.lno Normal file

Binary file not shown.

View File

@ -0,0 +1,45 @@
// 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" "FreeSH Server"
seta "maxplayers" "8"
// 2D/HUD Variables
seta "con_color" "255 255 215"
seta "vgui_color" "255 255 215"
seta "cross_color" "0 255 0"

BIN
zpak001.pk3dir/progs.dat Normal file

Binary file not shown.

BIN
zpak001.pk3dir/progs.lno Normal file

Binary file not shown.

View File

@ -0,0 +1,17 @@
exec skill_valve.cfg
set sk_plr_hammer1 "100"
set sk_plr_hammer2 "100"
set sk_plr_hammer3 "100"
set sk_plr_hammeralt1 "200"
set sk_plr_hammeralt2 "200"
set sk_plr_hammeralt3 "200"
set sk_plr_chainsaw1 "10"
set sk_plr_chainsaw2 "10"
set sk_plr_chainsaw3 "10"
set sk_plr_cannon1 "5"
set sk_plr_cannon2 "5"
set sk_plr_cannon3 "5"