commit 1ec97ee7321a46fe3cbe4e3b3ee91b96c0e1ae7c Author: Marco Hladik Date: Mon Mar 8 11:40:33 2021 +0100 Initial commit, carried over from Nuclide's Git on March 8th 2021 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..73679b8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,15 @@ +ISC License + +Copyright (c) 2016-2021, Marco "eukara" Hladik + +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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..63e6c32 --- /dev/null +++ b/README.md @@ -0,0 +1,38 @@ +# FreeSci +Clean-room reimplementation of They Hunger 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 hunger + +then either run Nuclide's ./build_game.sh shell script, or issue 'make' inside +./hunger/src! + +Obviously make sure that Nuclide has fteqw and fteqcc set-up for building. + +## Community +Join us on #halflife or #hunger via irc.frag-net.com and chat. + +## License +ISC License + +Copyright (c) 2016-2021 Marco Hladik +Copyright (c) 2019-2020 Gethyn ThomasQuail + +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. diff --git a/img/preview1.jpg b/img/preview1.jpg new file mode 100644 index 0000000..0f5d817 Binary files /dev/null and b/img/preview1.jpg differ diff --git a/img/preview2.jpg b/img/preview2.jpg new file mode 100644 index 0000000..68d7418 Binary files /dev/null and b/img/preview2.jpg differ diff --git a/img/preview3.jpg b/img/preview3.jpg new file mode 100644 index 0000000..a7cf97b Binary files /dev/null and b/img/preview3.jpg differ diff --git a/img/preview4.jpg b/img/preview4.jpg new file mode 100644 index 0000000..0b5b0e3 Binary files /dev/null and b/img/preview4.jpg differ diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..cc3f82d --- /dev/null +++ b/src/Makefile @@ -0,0 +1,5 @@ +CC=fteqcc + +all: + cd client && $(MAKE) + cd server && $(MAKE) diff --git a/src/client/Makefile b/src/client/Makefile new file mode 100644 index 0000000..627019a --- /dev/null +++ b/src/client/Makefile @@ -0,0 +1,4 @@ +CC=fteqcc + +all: + $(CC) progs.src diff --git a/src/client/init.qc b/src/client/init.qc new file mode 100644 index 0000000..9b545ff --- /dev/null +++ b/src/client/init.qc @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2016-2020 Marco Hladik + * + * 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/tfchud01.spr"); + precache_model("sprites/tfchud02.spr"); + precache_model("sprites/tfchud03.spr"); + precache_model("sprites/tfchud04.spr"); + precache_model("sprites/tfchud05.spr"); + precache_model("sprites/tfchud06.spr"); + precache_model("sprites/tfc_dmsg.spr"); + precache_model("sprites/nmxhair2.spr"); + BEAM_TRIPMINE = particleeffectnum("weapon_tripmine.beam"); +} diff --git a/src/client/progs.src b/src/client/progs.src new file mode 100644 index 0000000..a964717 --- /dev/null +++ b/src/client/progs.src @@ -0,0 +1,39 @@ +#pragma target fte +#pragma progs_dat "../../csprogs.dat" + +#define CSQC +#define CLIENT +#define VALVE +#define HUNGER +#define CLASSIC_VGUI +#define GS_RENDERFX + +#includelist +../../../src/shared/fteextensions.qc +../../../src/shared/defs.h +../../../valve/src/client/defs.h +../../../src/client/defs.h + +../../../src/vgui/include.src + +../../../src/gs-entbase/client.src +../../../src/gs-entbase/shared.src +../shared/include.src + +../../../valve/src/client/predict.qc +init.qc +../../../valve/src/client/player.qc +../../../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 diff --git a/src/progs.src b/src/progs.src new file mode 100755 index 0000000..2c2a868 --- /dev/null +++ b/src/progs.src @@ -0,0 +1,2 @@ +#pragma sourcefile client/progs.src +#pragma sourcefile server/progs.src diff --git a/src/server/Makefile b/src/server/Makefile new file mode 100644 index 0000000..627019a --- /dev/null +++ b/src/server/Makefile @@ -0,0 +1,4 @@ +CC=fteqcc + +all: + $(CC) progs.src diff --git a/src/server/ammo_th.qc b/src/server/ammo_th.qc new file mode 100644 index 0000000..18eec99 --- /dev/null +++ b/src/server/ammo_th.qc @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2016-2020 Marco Hladik + * Copyright (c) 2019 Gethyn ThomasQuail + * + * 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_th_ap9 (0 0 0.8) (-16 -16 0) (16 16 32) + +THEY HUNGER (1999) ENTITY + +Ammo for the Flamethrower. +A single ammo_egonclip will provide 25, er, gas. + + */ +class ammo_egonclip:item_ammo +{ + void(void) ammo_egonclip; + virtual void(void) touch; +}; + +void ammo_egonclip::ammo_egonclip(void) +{ + model = "models/w_gas.mdl"; + item_ammo::item_ammo(); +} +void ammo_egonclip::touch(void) +{ + if not (other.flags & FL_CLIENT) { + return; + } + if (other.classname == "player") { + player pl = (player)other; + if (pl.ammo_gas < MAX_A_GAS) { + pl.ammo_gas = bound(0, pl.ammo_gas + 25, MAX_A_GAS); + Sound_Play(other, CHAN_ITEM, "ammo_gas.pickup"); + item_ammo::touch(); + } + } +} + +/*QUAKED ammo_th_ap9 (0 0 0.8) (-16 -16 0) (16 16 32) + +THEY HUNGER (1999) ENTITY + +Ammo for the AP9. +A single ammo_th_ap9 will provide 40 bullets. + +*/ +class ammo_th_ap9:item_ammo +{ + void(void) ammo_th_ap9; + virtual void(void) touch; +}; + +void ammo_th_ap9::ammo_th_ap9(void) +{ + model = "models/w_ap9clip.mdl"; + item_ammo::item_ammo(); +} +void ammo_th_ap9::touch(void) +{ + if not (other.flags & FL_CLIENT) { + return; + } + if (other.classname == "player") { + player pl = (player)other; + if (pl.ammo_ap9 < MAX_A_AP9) { + pl.ammo_ap9 = bound(0, pl.ammo_ap9 + 40, MAX_A_AP9); + item_ammo::touch(); + } + } +} + + +/*QUAKED ammo_einar1 (0 0 0.8) (-16 -16 0) (16 16 32) + +THEY HUNGER (1999) ENTITY + +Ammo for the Snipers. +A single ammo_th_sniper will provide 5 bullets. + +Same as ammo_th_sniper + +*/ +/*QUAKED ammo_th_sniper (0 0 0.8) (-16 -16 0) (16 16 32) + +THEY HUNGER (1999) ENTITY + +Ammo for the Snipers. +A single ammo_th_sniper will provide 5 bullets. + +Same as ammo_einar1 + +*/ + +class ammo_th_sniper:item_ammo +{ + void(void) ammo_th_sniper; + virtual void(void) touch; +}; + +void ammo_th_sniper::ammo_th_sniper(void) +{ + model = "models/w_antidote.mdl"; + item_ammo::item_ammo(); +} +void ammo_th_sniper::touch(void) +{ + if not (other.flags & FL_CLIENT) { + return; + } + if (other.classname == "player") { + player pl = (player)other; + if (pl.ammo_sniper < MAX_A_SNIPER) { + pl.ammo_sniper = bound(0, pl.ammo_sniper + 5, MAX_A_SNIPER); + item_ammo::touch(); + } + } +} + +CLASSEXPORT(ammo_einar1, ammo_th_sniper) diff --git a/src/server/input.qc b/src/server/input.qc new file mode 100644 index 0000000..6b56e1d --- /dev/null +++ b/src/server/input.qc @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2016-2020 Marco Hladik + * + * 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 == 101) { + pl.health = 100; + pl.armor = 100; + pl.g_items |= ITEM_SUIT; + Weapons_AddItem(pl, WEAPON_CROWBAR, -1); + Weapons_AddItem(pl, WEAPON_SHOVEL, -1); + Weapons_AddItem(pl, WEAPON_SPANNER, -1); + Weapons_AddItem(pl, WEAPON_GLOCK, -1); + Weapons_AddItem(pl, WEAPON_PYTHON, -1); + Weapons_AddItem(pl, WEAPON_AP9, -1); + Weapons_AddItem(pl, WEAPON_TAURUS, -1); + Weapons_AddItem(pl, WEAPON_MP5, -1); + Weapons_AddItem(pl, WEAPON_SHOTGUN, -1); + Weapons_AddItem(pl, WEAPON_CROSSBOW, -1); + Weapons_AddItem(pl, WEAPON_SNIPER, -1); + Weapons_AddItem(pl, WEAPON_SNIPER2, -1); + Weapons_AddItem(pl, WEAPON_RPG, -1); + Weapons_AddItem(pl, WEAPON_GAUSS, -1); + Weapons_AddItem(pl, WEAPON_EGON, -1); + Weapons_AddItem(pl, WEAPON_CHAINGUN, -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_MEDKIT, -1); + } + + 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"); + } + } + + self.impulse = 0; +} diff --git a/src/server/progs.src b/src/server/progs.src new file mode 100755 index 0000000..ef7de19 --- /dev/null +++ b/src/server/progs.src @@ -0,0 +1,91 @@ +#pragma target fte +#pragma progs_dat "../../progs.dat" + +#define QWSSQC +#define SERVER +#define VALVE +#define HUNGER +#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 + +../../../valve/src/server/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 + +../../../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_th.qc + +../../../src/botlib/include.src + +../../../valve/src/server/gamerules.qc +../../../valve/src/server/gamerules_singleplayer.qc +../../../valve/src/server/gamerules_multiplayer.qc +../../../valve/src/server/client.qc +../../../valve/src/server/server.qc +../../../valve/src/server/damage.qc +../../../valve/src/server/rules.qc +../../../valve/src/server/flashlight.qc +../../../base/src/server/modelevent.qc + +input.qc +../../../valve/src/server/spawn.qc + +../../../src/server/include.src +../../../src/shared/include.src +#endlist diff --git a/src/shared/include.src b/src/shared/include.src new file mode 100644 index 0000000..b539bbb --- /dev/null +++ b/src/shared/include.src @@ -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_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_ap9.qc +w_chaingun.qc +w_flame.qc +w_silencer.qc +w_medkit.qc +w_shovel.qc +w_sniper.qc +w_sniper2.qc +w_spanner.qc +w_taurus.qc +w_tnt.qc +weapons.qc +../../../valve/src/shared/weapon_common.qc +#endlist diff --git a/src/shared/items.h b/src/shared/items.h new file mode 100644 index 0000000..b1c2ba1 --- /dev/null +++ b/src/shared/items.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016-2020 Marco Hladik + * + * 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_CHAINGUN 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_SHOVEL 0x00010000 +#define ITEM_SPANNER 0x00020000 +#define ITEM_AP9 0x00040000 +#define ITEM_TAURUS 0x00080000 +#define ITEM_SNIPER 0x00100000 +#define ITEM_SNIPER2 0x00200000 +#define ITEM_MEDKIT2 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 diff --git a/src/shared/player.qc b/src/shared/player.qc new file mode 100644 index 0000000..292277e --- /dev/null +++ b/src/shared/player.qc @@ -0,0 +1,785 @@ +/* + * Copyright (c) 2016-2021 Marco Hladik + * + * 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; + + /* hunger */ + int sniper_mag; int sniper_mag_net; + int chaingun_mag; int chaingun_mag_net; + int ap9_mag; int ap9_mag_net; + int taurus_mag; int taurus_mag_net; + + int ammo_ap9; int ammo_ap9_net; + int ammo_taurus; int ammo_taurus_net; + int ammo_bolt; int ammo_bolt_net; + int ammo_sniper; int ammo_sniper_net; + int ammo_medkit; int ammo_medkit_net; + int ammo_gas; int ammo_gas_net; + int mode_silencer; int mode_silencer_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(); + + /* hunger */ + sniper_mag = readbyte(); + chaingun_mag = readbyte(); + ap9_mag = readbyte(); + taurus_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(); + + /* hunger */ + ammo_ap9 = readbyte(); + ammo_taurus = readbyte(); + ammo_bolt = readbyte(); + ammo_sniper = readbyte(); + ammo_medkit = readbyte(); + ammo_gas = 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(); + mode_silencer = 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 */ + sniper_mag_net = sniper_mag; + chaingun_mag_net = chaingun_mag; + ap9_mag_net = ap9_mag; + taurus_mag_net = taurus_mag; + + ammo_ap9_net = ammo_ap9; + ammo_taurus_net = ammo_taurus; + ammo_bolt_net = ammo_bolt; + ammo_sniper_net = ammo_sniper; + ammo_medkit_net = ammo_medkit; + ammo_gas_net = ammo_gas; + + mode_silencer_net = mode_silencer; +} + +/* +================= +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; + + /* hunger */ + sniper_mag = sniper_mag_net; + chaingun_mag = chaingun_mag_net; + ap9_mag = ap9_mag_net; + taurus_mag = taurus_mag_net; + + ammo_ap9 = ammo_ap9_net; + ammo_taurus = ammo_taurus_net; + ammo_bolt = ammo_bolt_net; + ammo_sniper = ammo_sniper_net; + ammo_medkit = ammo_medkit_net; + ammo_gas = ammo_gas_net; + + mode_silencer = mode_silencer_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; + + /* hunger */ + if (sniper_mag != sniper_mag_net) + SendFlags |= PLAYER_AMMO1; + if (chaingun_mag != chaingun_mag_net) + SendFlags |= PLAYER_AMMO1; + if (ap9_mag != ap9_mag_net) + SendFlags |= PLAYER_AMMO1; + if (taurus_mag != taurus_mag_net) + SendFlags |= PLAYER_AMMO1; + + if (ammo_ap9 != ammo_ap9_net) + SendFlags |= PLAYER_AMMO2; + if (ammo_taurus != ammo_taurus_net) + SendFlags |= PLAYER_AMMO2; + if (ammo_bolt != ammo_bolt_net) + SendFlags |= PLAYER_AMMO2; + if (ammo_sniper != ammo_sniper_net) + SendFlags |= PLAYER_AMMO2; + if (ammo_medkit != ammo_medkit_net) + SendFlags |= PLAYER_AMMO2; + if (ammo_gas != ammo_gas_net) + SendFlags |= PLAYER_AMMO2; + + if (mode_silencer != mode_silencer_net) + SendFlags |= PLAYER_AMMO3; + + sniper_mag_net = sniper_mag; + chaingun_mag_net = chaingun_mag; + ap9_mag_net = ap9_mag; + taurus_mag_net = taurus_mag; + + ammo_ap9_net = ammo_ap9; + ammo_taurus_net = ammo_taurus; + ammo_bolt_net = ammo_bolt; + ammo_sniper_net = ammo_sniper; + ammo_medkit_net = ammo_medkit; + ammo_gas_net = ammo_gas; + mode_silencer_net= mode_silencer; +} + +/* +================= +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); + + /* hunger */ + WriteByte(MSG_ENTITY, sniper_mag); + WriteByte(MSG_ENTITY, chaingun_mag); + WriteByte(MSG_ENTITY, ap9_mag); + WriteByte(MSG_ENTITY, taurus_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); + + /* hunger */ + WriteByte(MSG_ENTITY, ammo_ap9); + WriteByte(MSG_ENTITY, ammo_taurus); + WriteByte(MSG_ENTITY, ammo_bolt); + WriteByte(MSG_ENTITY, ammo_sniper); + WriteByte(MSG_ENTITY, ammo_medkit); + WriteByte(MSG_ENTITY, ammo_gas); + } + + 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, mode_silencer); + } + + return TRUE; +} +#endif diff --git a/src/shared/w_ap9.qc b/src/shared/w_ap9.qc new file mode 100644 index 0000000..5f217ac --- /dev/null +++ b/src/shared/w_ap9.qc @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2016-2021 Marco Hladik + * Copyright (c) 2019-2020 Gethyn ThomasQuail + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +enum +{ + AP9_IDLE, + AP9_RELOAD, + AP9_DRAW, + AP9_SHOOT1, + AP9_SHOOT2, + AP9_SHOOT3 +}; + +void +w_ap9_precache(void) +{ +#ifdef SERVER + Sound_Precache("weapon_ap9.fire"); +#endif + precache_model("models/v_ap9.mdl"); + precache_model("models/w_ap9.mdl"); + precache_model("models/p_ap9.mdl"); + precache_sound("weapons/ap9_bolt.wav"); + precache_sound("weapons/ap9_clipin.wav"); + precache_sound("weapons/ap9_clipout.wav"); +} + +void +w_ap9_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, pl.ap9_mag, pl.ammo_ap9, -1); +} + +string +w_ap9_wmodel(void) +{ + return "models/w_ap9.mdl"; +} + +string +w_ap9_pmodel(void) +{ + return "models/p_ap9.mdl"; +} + +string +w_ap9_deathmsg(void) +{ + return "%s was unloaded into from %s's AP9."; +} + +int +w_ap9_pickup(int new, int startammo) +{ +#ifdef SERVER + player pl = (player)self; + + if (new) { + pl.ap9_mag = 40; + } else { + if (pl.ammo_ap9 < MAX_A_AP9) { + pl.ammo_ap9 = bound(0, pl.ammo_ap9 + 40, MAX_A_AP9); + } else { + return FALSE; + } + } +#endif + return TRUE; +} + +void +w_ap9_draw(void) +{ +#ifdef CLIENT + Weapons_SetModel("models/v_ap9.mdl"); + Weapons_ViewAnimation(AP9_DRAW); +#endif +} + +void +w_ap9_holster(void) +{ + +} + +void +w_ap9_primary(void) +{ + player pl = (player)self; + + if (pl.w_attack_next > 0.0) { + return; + } + + /* ammo check */ + if (!pl.ap9_mag) { + return; + } + + pl.ap9_mag--; + + /* actual firing */ +#ifdef CLIENT + pl.ap9_mag--; + View_SetMuzzleflash(MUZZLE_SMALL); + Weapons_ViewPunchAngle([-2,0,0]); + + int r = (float)input_sequence % 3; + switch (r) { + case 0: + Weapons_ViewAnimation(AP9_SHOOT1); + break; + case 1: + Weapons_ViewAnimation(AP9_SHOOT2); + break; + case 2: + Weapons_ViewAnimation(AP9_SHOOT3); + break; + } + +#else + TraceAttack_FireBullets(1, pl.origin + pl.view_ofs, 8, [0.1,0.1], WEAPON_AP9); + Sound_Play(pl, CHAN_WEAPON, "weapon_ap9.fire"); + + if (self.flags & FL_CROUCHING) + Animation_PlayerTopTemp(ANIM_SHOOT1HAND, 0.45f); + else + Animation_PlayerTopTemp(ANIM_CR_SHOOT1HAND, 0.45f); +#endif + + pl.w_attack_next = 0.15f; + pl.w_idle_next = 5.0f; +} + +void +w_ap9_secondary(void) +{ + player pl = (player)self; + + if (pl.w_attack_next > 0) { + return; + } + + /* ammo check */ + if ((pl.ap9_mag - 3) < 0) { + return; + } + pl.ap9_mag -= 3; + +#ifdef CLIENT + View_SetMuzzleflash(MUZZLE_SMALL); + Weapons_ViewPunchAngle([-2,0,0]); + + int r = floor(random(0,2)); + switch (r) { + case 0: + Weapons_ViewAnimation(AP9_SHOOT1); + break; + case 1: + Weapons_ViewAnimation(AP9_SHOOT2); + break; + case 2: + Weapons_ViewAnimation(AP9_SHOOT3); + break; + } +#else + TraceAttack_FireBullets(3, pl.origin + pl.view_ofs, 8, [0.02,0.02], WEAPON_AP9); + Sound_Play(pl, CHAN_WEAPON, "weapon_ap9.fire"); + + if (self.flags & FL_CROUCHING) + Animation_PlayerTopTemp(ANIM_SHOOT1HAND, 0.45f); + else + Animation_PlayerTopTemp(ANIM_CR_SHOOT1HAND, 0.45f); +#endif + + pl.w_attack_next = 1.0f; + pl.w_idle_next = 5.0f; +} + +void +w_ap9_reload(void) +{ + player pl = (player)self; + + if (pl.w_attack_next > 0.0) { + return; + } + if (pl.ap9_mag >= 40) { + return; + } + if (pl.a_ammo2 <= 0) { + return; + } + +#ifdef CLIENT + Weapons_ViewAnimation(AP9_RELOAD); +#else + Weapons_ReloadWeapon(pl, player::ap9_mag, player::ammo_ap9, 40); +#endif + + pl.w_attack_next = 2.0f; + pl.w_idle_next = 10.0f; +} + +void +w_ap9_release(void) +{ + player pl = (player)self; + + /* auto-reload if need be */ + if (pl.w_attack_next <= 0.0) + if (pl.ap9_mag == 0 && pl.ammo_ap9 > 0) { + Weapons_Reload(); + return; + } + + if (pl.w_idle_next > 0.0) { + return; + } + + Weapons_ViewAnimation(AP9_IDLE); +} + +float +w_ap9_aimanim(void) +{ + return w_glock_aimanim(); +} + +void +w_ap9_hud(void) +{ + w_glock_hud(); +} + +void +w_ap9_hudpic(int selected, vector pos, float a) +{ +#ifdef CLIENT + player pl = (player)self; + vector hud_col; + + if (pl.ap9_mag == 0 && pl.ammo_ap9 == 0) + hud_col = [1,0,0]; + else + hud_col = g_hud_color; + + HUD_DrawAmmoBar(pos, pl.ammo_ap9, MAX_A_AP9, a); + + if (selected) { + drawsubpic( + pos, + [170,45], + "sprites/tfchud05.spr_0.tga", + [0,0], + [170/256,45/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [170,45], + "sprites/tfchud05.spr_0.tga", + [0,0], + [170/256,45/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } +#endif +} + +weapon_t w_ap9 = +{ + .name = "ap9", + .id = ITEM_AP9, + .slot = 1, + .slot_pos = 2, + .draw = w_ap9_draw, + .holster = w_ap9_holster, + .primary = w_ap9_primary, + .secondary = w_ap9_secondary, + .reload = w_ap9_reload, + .release = w_ap9_release, + .crosshair = w_ap9_hud, + .precache = w_ap9_precache, + .pickup = w_ap9_pickup, + .updateammo = w_ap9_updateammo, + .wmodel = w_ap9_wmodel, + .pmodel = w_ap9_pmodel, + .deathmsg = w_ap9_deathmsg, + .aimanim = w_ap9_aimanim, + .hudpic = w_ap9_hudpic +}; + +/* pickups */ +#ifdef SERVER +void +weapon_th_ap9(void) +{ + Weapons_InitItem(WEAPON_AP9); +} +#endif diff --git a/src/shared/w_chaingun.qc b/src/shared/w_chaingun.qc new file mode 100644 index 0000000..d32109c --- /dev/null +++ b/src/shared/w_chaingun.qc @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2016-2021 Marco Hladik + * Copyright (c) 2019-2020 Gethyn ThomasQuail + * + * 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. + */ + +/* Animations */ +enum +{ + CHAINGUN_IDLE1, + CHAINGUN_IDLE2, + CHAINGUN_SPINUP, + CHAINGUN_SPINDOWN, + CHAINGUN_FIRE, + CHAINGUN_DRAW, + CHAINGUN_HOLSTER +}; + +void +w_chaingun_precache(void) +{ +#ifdef SERVER + Sound_Precache("weapon_chaingun.fire"); + Sound_Precache("weapon_chaingun.reload"); + Sound_Precache("weapon_chaingun.spindown"); + Sound_Precache("weapon_chaingun.spinup"); +#endif + precache_model("models/v_tfac.mdl"); + precache_model("models/w_tfac.mdl"); + precache_model("models/p_tfac.mdl"); +} + +int +w_chaingun_pickup(int new, int startammo) +{ +#ifdef SERVER + player pl = (player)self; + + if (new) { + pl.chaingun_mag = 100; + } else { + if (pl.ammo_9mm < MAX_A_9MM) { + pl.ammo_9mm = bound(0, pl.ammo_9mm + 100, MAX_A_9MM); + } else { + return FALSE; + } + } +#endif + return TRUE; +} + +void +w_chaingun_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, pl.chaingun_mag, pl.ammo_9mm, -1); +} + +string +w_chaingun_wmodel(void) +{ + return "models/w_tfac.mdl"; +} + +string +w_chaingun_pmodel(void) +{ + return "models/p_tfac.mdl"; +} + +string +w_chaingun_deathmsg(void) +{ + return "%s was rolled over by %s' Chaingun."; +} + +void +w_chaingun_draw(void) +{ + player pl = (player)self; + pl.mode_tempstate = 0; + +#ifdef CLIENT + Weapons_SetModel("models/v_tfac.mdl"); + Weapons_ViewAnimation(CHAINGUN_DRAW); +#endif +} + +void +w_chaingun_holster(void) +{ + Weapons_ViewAnimation(CHAINGUN_HOLSTER); +} + +void +w_chaingun_release(void) +{ + player pl = (player)self; + + /* auto-reload if need be */ + if (pl.w_attack_next <= 0.0) + if (pl.chaingun_mag == 0 && pl.ammo_9mm > 0) { + Weapons_Reload(); + return; + } + + if (pl.w_idle_next > 0.0) { + return; + } + + /* end firing */ + if (pl.mode_tempstate == 1) { + pl.mode_tempstate = 0; +#ifdef SERVER + Sound_Play(pl, CHAN_WEAPON, "weapon_chaingun.spindown"); +#endif + Weapons_ViewAnimation(CHAINGUN_SPINDOWN); + pl.w_attack_next = 1.0f; + pl.w_idle_next = pl.w_attack_next; + return; + } + + /* end reload */ + if (pl.mode_tempstate == 2) { + pl.mode_tempstate = 0; + Weapons_ViewAnimation(CHAINGUN_DRAW); + pl.w_attack_next = 1.0f; + pl.w_idle_next = pl.w_attack_next; + return; + } + + int r = (float)input_sequence % 2; + if (r) { + Weapons_ViewAnimation(CHAINGUN_IDLE1); + } else { + Weapons_ViewAnimation(CHAINGUN_IDLE2); + } + + pl.w_idle_next = 15.0f; +} + +void +w_chaingun_primary(void) +{ + player pl = (player)self; + + /* in case we're spamming primary while reloading */ + if (pl.mode_tempstate == 2) { + w_chaingun_release(); + return; + } + + if (pl.w_attack_next > 0.0) { + return; + } + + /* ammo check */ + if (pl.chaingun_mag <= 0) { + return; + } + + /* spin up first */ + if (pl.mode_tempstate == 0) { + pl.mode_tempstate = 1; + Weapons_ViewAnimation(CHAINGUN_SPINUP); +#ifdef SERVER + Sound_Play(pl, CHAN_WEAPON, "weapon_chaingun.spinup"); +#endif + pl.w_attack_next = 0.5f; + pl.w_idle_next = pl.w_attack_next; + return; + } + pl.chaingun_mag--; + + /* actual firing */ +#ifdef CLIENT + View_SetMuzzleflash(MUZZLE_RIFLE); + Weapons_ViewAnimation(CHAINGUN_FIRE); + Weapons_ViewPunchAngle([random(-2, 2),0,0]); +#else + TraceAttack_FireBullets(1, Weapons_GetCameraPos(), 8, [0.15,0.15], WEAPON_CHAINGUN); + Sound_Play(pl, CHAN_WEAPON, "weapon_chaingun.fire"); +#endif + + pl.w_attack_next = 0.1f; + pl.w_idle_next = 0.0f; +} + +void +w_chaingun_reload(void) +{ + player pl = (player)self; + if (pl.w_attack_next) { + w_chaingun_release(); + return; + } + + /* ammo check */ + if (pl.chaingun_mag >= 100) { + return; + } + if (pl.ammo_9mm <= 0) { + return; + } + +#ifdef CLIENT + Weapons_ViewAnimation(CHAINGUN_HOLSTER); +#else + Sound_Play(pl, CHAN_WEAPON, "weapon_chaingun.reload"); + Weapons_ReloadWeapon(pl, player::chaingun_mag, player::ammo_9mm, 100); +#endif + + pl.mode_tempstate = 2; + pl.w_attack_next = 10.0f; + pl.w_idle_next = 1.5f; +} + +void +w_chaingun_hud(void) +{ + w_glock_hud(); +} + +float +w_chaingun_aimanim(void) +{ + return w_mp5_aimanim(); +} + +void +w_chaingun_hudpic(int selected, vector pos, float a) +{ +#ifdef CLIENT + player pl = (player)self; + vector hud_col; + + if (pl.chaingun_mag == 0 && pl.ammo_9mm == 0) + hud_col = [1,0,0]; + else + hud_col = g_hud_color; + + HUD_DrawAmmoBar(pos, pl.ammo_9mm, MAX_A_9MM, a); + + if (selected) { + drawsubpic( + pos, + [170,45], + "sprites/tfchud04.spr_0.tga", + [0,90/256], + [170/256,45/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [170,45], + "sprites/tfchud03.spr_0.tga", + [0,45/256], + [170/256,45/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } +#endif +} + +weapon_t w_chaingun = +{ + .name = "chaingun", + .id = ITEM_CHAINGUN, + .slot = 3, + .slot_pos = 3, + .draw = w_chaingun_draw, + .holster = w_chaingun_holster, + .primary = w_chaingun_primary, + .secondary = w_chaingun_release, + .reload = w_chaingun_reload, + .release = w_chaingun_release, + .crosshair = w_chaingun_hud, + .precache = w_chaingun_precache, + .pickup = w_chaingun_pickup, + .updateammo = w_chaingun_updateammo, + .wmodel = w_chaingun_wmodel, + .pmodel = w_chaingun_pmodel, + .deathmsg = w_chaingun_deathmsg, + .aimanim = w_chaingun_aimanim, + .hudpic = w_chaingun_hudpic +}; + +/* pickups */ +#ifdef SERVER +void +weapon_th_chaingun(void) +{ + Weapons_InitItem(WEAPON_CHAINGUN); +} +#endif diff --git a/src/shared/w_flame.qc b/src/shared/w_flame.qc new file mode 100644 index 0000000..78b5d23 --- /dev/null +++ b/src/shared/w_flame.qc @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2016-2021 Marco Hladik + * Copyright (c) 2019-2020 Gethyn ThomasQuail + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +enum +{ + EGON_IDLE1, + EGON_FIDGET1, + EGON_ALTFIREON, + EGON_ALTFIRECYCLE, + EGON_ALTFIREOFF, + EGON_FIRE1, + EGON_FIRE2, + EGON_FIRE3, + EGON_FIRE4, + EGON_DRAW, + EGON_HOLSTER +}; + +void +w_flame_precache(void) +{ +#ifdef SERVER + Sound_Precache("weapon_flame.fire"); +#endif + precache_model("sprites/fthrow.spr"); + precache_model("models/v_egon.mdl"); + precache_model("models/w_egon.mdl"); + precache_model("models/p_egon.mdl"); +} + +void +w_flame_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, -1, pl.ammo_gas, -1); +} + +string +w_flame_wmodel(void) +{ + return w_egon_wmodel(); +} + +string +w_flame_pmodel(void) +{ + return w_egon_pmodel(); +} + +string +w_flame_deathmsg(void) +{ + return "%s burned to a crisp by %s's Flamethrower."; +} + +int +w_flame_pickup(int new, int startammo) +{ +#ifdef SERVER + player pl = (player)self; + if (pl.ammo_gas < MAX_A_GAS) { + pl.ammo_gas = bound(0, pl.ammo_gas + 20, MAX_A_GAS); + } else { + return FALSE; + } +#endif + return TRUE; +} + +void +w_flame_draw(void) +{ + w_egon_draw(); +} + +void +w_flame_holster(void) +{ + w_egon_holster(); +} + + +#ifdef SERVER +void +Flame_Touch(void) +{ + if (other.takedamage != DAMAGE_YES) { + remove(self); + return; + } + + /* anything else that can take damage */ + Damage_Apply(other, self.owner, 40, WEAPON_EGON, DMG_BURN); + remove(self); +} +#endif + + +void +w_flame_primary(void) +{ + player pl = (player)self; + if (pl.w_attack_next > 0.0) { + return; + } + + /* Ammo check */ + if (pl.ammo_gas <= 0) { + return; + } + + pl.ammo_gas--; + +#ifdef CLIENT + if (Weapons_GetAnimation() == EGON_IDLE1) + Weapons_ViewAnimation(EGON_ALTFIREON); + else if (Weapons_GetAnimation() == EGON_ALTFIREON) + Weapons_ViewAnimation(EGON_ALTFIRECYCLE); +#else + + Sound_Play(pl, CHAN_WEAPON, "weapon_flame.fire"); + Weapons_MakeVectors(); + entity flame = spawn(); + setmodel(flame, "sprites/fthrow.spr"); + setorigin(flame, Weapons_GetCameraPos() + (v_forward * 16)); + flame.owner = self; + flame.velocity = v_forward * 300; + flame.movetype = MOVETYPE_FLYMISSILE; + flame.solid = SOLID_BBOX; + //flame.flags |= FL_LAGGEDMOVE; + flame.angles = vectoangles(flame.velocity); + flame.avelocity[2] = 10; + flame.touch = Flame_Touch; + /*frame.think = Flame_Touch; + flame.nextthink = time + 2.0f;*/ + flame.effects |= EF_BRIGHTLIGHT; + setsize(flame, [0,0,0], [0,0,0]); +#endif + + pl.w_attack_next = 0.2f; + pl.w_idle_next = 2.5f; +} + +void +w_flame_reload(void) +{ +} + +void +w_flame_release(void) +{ + w_egon_release(); +} + +void +w_flame_crosshair(void) +{ +#ifdef CLIENT + static vector cross_pos; + cross_pos = g_hudmins + (g_hudres / 2) + [-12,-12]; + drawsubpic(cross_pos, [24,24], "sprites/crosshairs.spr_0.tga", [72/128,48/128], [0.1875, 0.1875], [1,1,1], 1, DRAWFLAG_NORMAL); + HUD_DrawAmmo2(); + vector aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42]; + drawsubpic(aicon_pos, [24,24], "sprites/640hud7.spr_0.tga", [0,96/128], [24/256, 24/128], g_hud_color, pSeat->m_flAmmo2Alpha, DRAWFLAG_ADDITIVE); +#endif +} + +float +w_flame_aimanim(void) +{ + return w_egon_aimanim(); +} + +void +w_flame_hudpic(int selected, vector pos, float a) +{ +#ifdef CLIENT + player pl = (player)self; + vector hud_col; + + if (pl.ammo_gas == 0) + hud_col = [1,0,0]; + else + hud_col = g_hud_color; + + HUD_DrawAmmoBar(pos, pl.ammo_gas, MAX_A_GAS, a); + + if (selected) { + drawsubpic( + pos, + [170,45], + "sprites/tfchud04.spr_0.tga", + [0,45/256], + [170/256,45/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [170,45], + "sprites/tfchud03.spr_0.tga", + [0,0/256], + [170/256,45/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } +#endif +} + +weapon_t w_flame = +{ + .name = "flame", + .id = ITEM_EGON, + .slot = 3, + .slot_pos = 2, + .draw = w_flame_draw, + .holster = w_egon_holster, + .primary = w_flame_primary, + .secondary = w_flame_release, + .reload = __NULL__, + .release = w_flame_release, + .crosshair = w_flame_crosshair, + .precache = w_flame_precache, + .pickup = w_flame_pickup, + .updateammo = w_flame_updateammo, + .wmodel = w_flame_wmodel, + .pmodel = w_flame_pmodel, + .deathmsg = w_flame_deathmsg, + .aimanim = w_flame_aimanim, + .hudpic = w_flame_hudpic +}; diff --git a/src/shared/w_medkit.qc b/src/shared/w_medkit.qc new file mode 100644 index 0000000..b7d33f8 --- /dev/null +++ b/src/shared/w_medkit.qc @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2016-2021 Marco Hladik + * Copyright (c) 2019-2020 Gethyn ThomasQuail + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +enum +{ + MEDKIT_IDLE1, + MEDKIT_IDLE2, + MEDKIT_USE, + MEDKIT_UNUSED, + MEDKIT_HOLSTER, + MEDKIT_DRAW +}; + +void +w_medkit_precache(void) +{ +#ifdef SERVER + Sound_Precache("weapon_medkit.heal"); +#endif + precache_model("models/v_tfc_medkit.mdl"); + precache_model("models/w_tfc_medkit.mdl"); + precache_model("models/p_tfc_medkit.mdl"); +} + +void +w_medkit_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, -1, pl.ammo_medkit, -1); +} + +string +w_medkit_wmodel(void) +{ + return "models/w_tfc_medkit.mdl"; +} + +string +w_medkit_pmodel(void) +{ + return "models/p_tfc_medkit.mdl"; +} + +string +w_medkit_deathmsg(void) +{ + return "%s was somehow healed to death by %s's Medkit."; +} + +int +w_medkit_pickup(int new, int startammo) +{ +#ifdef SERVER + player pl = (player)self; + + if (new) { + pl.ammo_medkit = 8; + } else { + if (pl.ammo_medkit < MAX_A_MEDKIT) { + pl.ammo_medkit = bound(0, pl.ammo_medkit + 8, MAX_A_MEDKIT); + } else { + return FALSE; + } + } +#endif + return TRUE; +} + + +void +w_medkit_draw(void) +{ + Weapons_SetModel("models/v_tfc_medkit.mdl"); + Weapons_ViewAnimation(MEDKIT_DRAW); +} + +void +w_medkit_primary(void) +{ + player pl = (player)self; + + if (pl.w_attack_next > 0.0) { + return; + } + if (!pl.ammo_medkit) { + return; + } + + /* Don't give the player more than 100 health */ + if (pl.health >= 100) { + return; + } else { + Weapons_ViewAnimation(MEDKIT_USE); + } + + pl.ammo_medkit--; + +#ifdef SERVER + /* We want to only give health to the player & skip armor */ + Damage_Apply(pl, pl, -15, WEAPON_MEDKIT, DMG_GENERIC); + + if (self.flags & FL_CROUCHING) + Animation_PlayerTopTemp(ANIM_SHOOT1HAND, 0.45f); + else + Animation_PlayerTopTemp(ANIM_CR_SHOOT1HAND, 0.45f); + + Sound_Play(pl, CHAN_WEAPON, "weapon_medkit.heal"); +#endif + + pl.w_attack_next = 2.4f; + pl.w_idle_next = 5.0f; +} + +void +w_medkit_release(void) +{ + player pl = (player)self; + + if (pl.w_idle_next > 0.0) { + return; + } + + int r = (float)input_sequence % 2; + switch (r) { + case 0: + Weapons_ViewAnimation(MEDKIT_IDLE1); + pl.w_idle_next = 1.16f; + break; + default: + Weapons_ViewAnimation(MEDKIT_IDLE2); + pl.w_idle_next = 2.36f; + break; + } +} + +float +w_medkit_aimanim(void) +{ + return w_snark_aimanim(); +} + +void +w_medkit_crosshair(void) +{ +#ifdef CLIENT + vector aicon_pos; + aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42]; + + HUD_DrawAmmo2(); + + drawsubpic( + aicon_pos, + [24,24], + "sprites/640hud7.spr_0.tga", + [24/256,96/128], + [24/256, 24/128], + g_hud_color, + pSeat->m_flAmmo2Alpha, + DRAWFLAG_ADDITIVE + ); +#endif +} + +void +w_medkit_hudpic(int selected, vector pos, float a) +{ +#ifdef CLIENT + player pl = (player)self; + vector hud_col; + + if (pl.ammo_medkit == 0) + hud_col = [1,0,0]; + else + hud_col = g_hud_color; + + HUD_DrawAmmoBar(pos, pl.ammo_medkit, MAX_A_MEDKIT, a); + + if (selected) { + drawsubpic( + pos, + [170,45], + "sprites/tfchud05.spr_0.tga", + [0,180/256], + [170/256,45/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [170,45], + "sprites/tfchud06.spr_0.tga", + [0,90/256], + [170/256,45/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } +#endif +} + +weapon_t w_medkit = +{ + .name = "medkit", + .id = ITEM_MEDKIT2, + .slot = 4, + .slot_pos = 4, + .draw = w_medkit_draw, + .holster = __NULL__, + .primary = w_medkit_primary, + .secondary = __NULL__, + .reload = __NULL__, + .release = w_medkit_release, + .crosshair = w_medkit_crosshair, + .precache = w_medkit_precache, + .pickup = w_medkit_pickup, + .updateammo = w_medkit_updateammo, + .wmodel = w_medkit_wmodel, + .pmodel = w_medkit_pmodel, + .deathmsg = w_medkit_deathmsg, + .aimanim = w_medkit_aimanim, + .hudpic = w_medkit_hudpic +}; + +#ifdef SERVER +void +weapon_th_medkit(void) +{ + Weapons_InitItem(WEAPON_MEDKIT); +} +#endif diff --git a/src/shared/w_shovel.qc b/src/shared/w_shovel.qc new file mode 100644 index 0000000..9f7fe82 --- /dev/null +++ b/src/shared/w_shovel.qc @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2016-2021 Marco Hladik + * Copyright (c) 2019-2020 Gethyn ThomasQuail + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +enum +{ + CBAR_IDLE, + CBAR_DRAW, + CBAR_HOLSTER, + CBAR_ATTACK1HIT, + CBAR_ATTACK1MISS, + CBAR_ATTACK2MISS, + CBAR_ATTACK2HIT, + CBAR_ATTACK3MISS, + CBAR_ATTACK3HIT +}; + +void +w_shovel_precache(void) +{ +#ifdef SERVER + Sound_Precache("weapon_crowbar.hit"); + Sound_Precache("weapon_crowbar.miss"); + Sound_Precache("weapon_crowbar.hitbody"); +#endif + precache_model("models/v_shovel.mdl"); + precache_model("models/w_shovel.mdl"); + precache_model("models/p_shovel.mdl"); +} + +void +w_shovel_updateammo(player pl) +{ + w_crowbar_updateammo(pl); +} + +string +w_shovel_wmodel(void) +{ + return "models/w_shovel.mdl"; +} +string +w_shovel_pmodel(void) +{ + return "models/p_shovel.mdl"; +} + +string +w_shovel_deathmsg(void) +{ + return "%s was buried by %s's Shovel."; +} + +void +w_shovel_draw(void) +{ + Weapons_SetModel("models/v_shovel.mdl"); + Weapons_ViewAnimation(CBAR_DRAW); +} + +void +w_shovel_holster(void) +{ + w_crowbar_holster(); +} + +void +w_shovel_primary(void) +{ + w_crowbar_primary(); +} + +void +w_shovel_release(void) +{ + w_crowbar_release(); +} + +float +w_shovel_aimanim(void) +{ + return w_crowbar_aimanim(); +} + +void +w_shovel_hudpic(int selected, vector pos, float a) +{ +#ifdef CLIENT + if (selected) { + drawsubpic( + pos, + [170,45], + "sprites/tfchud04.spr_0.tga", + [0,135/256], + [170/256,45/256], + g_hud_color, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [170,45], + "sprites/tfchud03.spr_0.tga", + [0,90/256], + [170/256,45/256], + g_hud_color, + a, + DRAWFLAG_ADDITIVE + ); + } +#endif +} + +weapon_t w_shovel = +{ + .name = "shovel", + .id = ITEM_SHOVEL, + .slot = 0, + .slot_pos = 1, + .draw = w_shovel_draw, + .holster = w_shovel_holster, + .primary = w_shovel_primary, + .secondary = __NULL__, + .reload = __NULL__, + .release = w_shovel_release, + .crosshair = __NULL__, + .precache = w_shovel_precache, + .pickup = __NULL__, + .updateammo = w_shovel_updateammo, + .wmodel = w_shovel_wmodel, + .pmodel = w_shovel_pmodel, + .deathmsg = w_shovel_deathmsg, + .aimanim = w_shovel_aimanim, + .hudpic = w_shovel_hudpic +}; + +/* entity definitions for pickups */ +#ifdef SERVER +void +weapon_th_shovel(void) +{ + Weapons_InitItem(WEAPON_SHOVEL); +} +#endif diff --git a/src/shared/w_silencer.qc b/src/shared/w_silencer.qc new file mode 100644 index 0000000..35a5333 --- /dev/null +++ b/src/shared/w_silencer.qc @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2016-2021 Marco Hladik + * Copyright (c) 2019-2020 Gethyn ThomasQuail + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +enum +{ + GLOCK_IDLE1, + GLOCK_IDLE2, + GLOCK_IDLE3, + GLOCK_SHOOT, + GLOCK_SHOOT_EMPTY, + GLOCK_RELOAD_EMPTY, + GLOCK_RELOAD, + GLOCK_DRAW, + GLOCK_HOLSTER, + GLOCK_SILENCER +}; + +void +w_silencer_precache(void) +{ +#ifdef SERVER + Sound_Precache("weapon_glock.fire"); + Sound_Precache("weapon_silencer.fire"); +#endif + + precache_model("models/v_9mmhandgun.mdl"); + precache_model("models/w_9mmhandgun.mdl"); + precache_model("models/p_9mmhandgun.mdl"); +} + +void +w_silencer_updateammo(player pl) +{ + w_glock_updateammo(pl); +} + +string +w_silencer_wmodel(void) +{ + return "models/w_silencer.mdl"; +} + +string +w_silencer_pmodel(void) +{ + return w_glock_pmodel(); +} + +string +w_silencer_deathmsg(void) +{ + return "%s was silenced by %s's Beretta."; +} + +int +w_silencer_pickup(int new, int startammo) +{ + return w_glock_pickup(new, startammo); +} + +void +w_silencer_draw(void) +{ + w_glock_draw(); + +#ifdef CLIENT + player pl = (player)self; + if (pl.mode_silencer) { + Weapons_SetGeomset("geomset 2 2\n"); + } else { + Weapons_SetGeomset("geomset 2 0\n"); + } +#endif +} +void +w_silencer_holster(void) +{ + w_glock_holster(); +} + +void +w_silencer_primary(void) +{ + player pl = (player)self; + + if (pl.w_attack_next > 0.0) { + return; + } + + /* ammo check */ + if (!pl.glock_mag) { + return; + } + + pl.glock_mag--; + + /* actual firing */ + Weapons_ViewPunchAngle([-2,0,0]); + +#ifdef CLIENT + if (pl.mode_silencer == 1) { + View_SetMuzzleflash(0); + } else { + View_SetMuzzleflash(MUZZLE_SMALL); + } + + if (pl.glock_mag) { + Weapons_ViewAnimation(GLOCK_SHOOT); + } else { + Weapons_ViewAnimation(GLOCK_SHOOT_EMPTY); + } +#else + /* Different sound & accuracy without silencer */ + if (pl.mode_silencer == 1) { + TraceAttack_FireBullets(1, pl.origin + pl.view_ofs, Skill_GetValue("plr_9mm_bullet", 8), [0.01, 0.01], WEAPON_GLOCK); + Sound_Play(pl, CHAN_WEAPON, "weapon_silencer.fire"); + + } else { + TraceAttack_FireBullets(1, pl.origin + pl.view_ofs, Skill_GetValue("plr_9mm_bullet", 8), [0.1,0.1], WEAPON_GLOCK); + Sound_Play(pl, CHAN_WEAPON, "weapon_glock.fire"); + } + + if (self.flags & FL_CROUCHING) + Animation_PlayerTopTemp(ANIM_SHOOT1HAND, 0.45f); + else + Animation_PlayerTopTemp(ANIM_CR_SHOOT1HAND, 0.45f); +#endif + + /* Fires faster without silencer */ + if (pl.mode_silencer == 1) { + pl.w_attack_next = 0.3f; + } else { + pl.w_attack_next = 0.2f; + } + + pl.w_idle_next = 5.0f; +} + +void +w_silencer_secondary(void) +{ + player pl = (player)self; + + if (pl.w_attack_next > 0) { + return; + } + + /* toggle silencer */ + pl.mode_silencer = 1 - pl.mode_silencer; + + /* the sub model isn't setting right, need the right values */ +#ifdef CLIENT + if (pl.mode_silencer) { + Weapons_SetGeomset("geomset 2 2\n"); + Weapons_ViewAnimation(GLOCK_SILENCER); + } else { + Weapons_SetGeomset("geomset 2 0\n"); + Weapons_ViewAnimation(GLOCK_HOLSTER); + } +#endif + if (pl.mode_silencer) { + pl.w_attack_next = 3.3f; + pl.w_idle_next = pl.w_attack_next; + } else { + + pl.w_attack_next = 0.94f; + pl.w_idle_next = pl.w_attack_next; + } +} + +void +w_silencer_reload(void) +{ + w_glock_reload(); +} + +void +w_silencer_release(void) +{ + w_glock_release(); +} + +float +w_silencer_aimanim(void) +{ + return w_glock_aimanim(); +} + +void +w_silencer_hud(void) +{ + w_glock_hud(); +} + +void +w_silencer_hudpic(int selected, vector pos, float a) +{ +#ifdef CLIENT + player pl = (player)self; + vector hud_col; + + if (pl.glock_mag == 0 && pl.ammo_9mm == 0) + hud_col = [1,0,0]; + else + hud_col = g_hud_color; + + HUD_DrawAmmoBar(pos, pl.ammo_9mm, MAX_A_9MM, a); + + if (selected) { + drawsubpic( + pos, + [170,45], + "sprites/tfchud05.spr_0.tga", + [0,135/256], + [170/256,45/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [170,45], + "sprites/tfchud06.spr_0.tga", + [0,45/256], + [170/256,45/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } +#endif +} + +weapon_t w_silencer = +{ + .name = "silencer", + .id = ITEM_GLOCK, + .slot = 1, + .slot_pos = 0, + .draw = w_silencer_draw, + .holster = w_silencer_holster, + .primary = w_silencer_primary, + .secondary = w_silencer_secondary, + .reload = w_silencer_reload, + .release = w_silencer_release, + .crosshair = w_silencer_hud, + .precache = w_silencer_precache, + .pickup = w_silencer_pickup, + .updateammo = w_silencer_updateammo, + .wmodel = w_silencer_wmodel, + .pmodel = w_silencer_pmodel, + .deathmsg = w_silencer_deathmsg, + .aimanim = w_silencer_aimanim, + .hudpic = w_silencer_hudpic +}; diff --git a/src/shared/w_sniper.qc b/src/shared/w_sniper.qc new file mode 100644 index 0000000..e2c09f5 --- /dev/null +++ b/src/shared/w_sniper.qc @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2016-2021 Marco Hladik + * Copyright (c) 2019-2020 Gethyn ThomasQuail + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +enum +{ + SNIPER_IDLE1, + SNIPER_UNUSED1, + SNIPER_FIRE1, + SNIPER_DRAW, + SNIPER_HOLSTER, + SNIPER_IDLE2 +}; + +void +w_sniper_precache(void) +{ +#ifdef SERVER + Sound_Precache("weapon_sniper.fire"); + Sound_Precache("weapon_sniper.reload"); +#endif + precache_model("models/v_tfc_sniper.mdl"); + precache_model("models/w_isotopebox.mdl"); + precache_model("models/p_sniper.mdl"); +} + +int +w_sniper_pickup(int new, int startammo) +{ +#ifdef SERVER + player pl = (player)self; + + if (new) { + pl.sniper_mag = 5; + } else { + if (pl.ammo_sniper < MAX_A_SNIPER) { + pl.ammo_sniper = bound(0, pl.ammo_sniper + 5, MAX_A_SNIPER); + } else { + return FALSE; + } + } +#endif + return TRUE; +} + +void +w_sniper_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, pl.sniper_mag, pl.ammo_sniper, -1); +} + +string +w_sniper_wmodel(void) +{ + return "models/w_isotopebox.mdl"; +} + +string +w_sniper_pmodel(void) +{ + return "models/p_sniper.mdl"; +} + +string +w_sniper_deathmsg(void) +{ + return "%s was taken out by %s's Sniper."; +} + +void +w_sniper_draw(void) +{ + player pl = (player)self; + pl.mode_tempstate = 0; + +#ifdef CLIENT + Weapons_SetModel("models/v_tfc_sniper.mdl"); + Weapons_ViewAnimation(SNIPER_DRAW); +#endif +} + +void +w_sniper_holster(void) +{ +#ifdef CLIENT + Weapons_ViewAnimation(SNIPER_HOLSTER); +#endif +} + +void +w_sniper_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_sniper > 0) { + Weapons_Reload(); + return; + } + + if (pl.w_idle_next > 0.0) { + return; + } + + if (pl.mode_tempstate == 1) { + Weapons_ViewAnimation(SNIPER_DRAW); + pl.mode_tempstate = 0; + pl.w_attack_next = 0.0f; + pl.w_idle_next = 15.0f; + return; + } + + int r = floor(random(0,2)); + switch (r) { + case 0: + Weapons_ViewAnimation(SNIPER_IDLE1); + pl.w_idle_next = 3.0f; + break; + case 1: + Weapons_ViewAnimation(SNIPER_IDLE2); + pl.w_idle_next = 2.0f; + break; + } + + pl.w_idle_next = 15.0f; +} + +void +w_sniper_primary(void) +{ + player pl = (player)self; + + if (pl.w_attack_next > 0.0) { + return; + } + + /* Ammo check */ + if (pl.sniper_mag <= 0) { + return; + } + + pl.sniper_mag--; + + /* Actual firing */ +#ifdef CLIENT + View_SetMuzzleflash(MUZZLE_SMALL); + Weapons_ViewPunchAngle([-20,0,0]); + Weapons_ViewAnimation(SNIPER_FIRE1); +#else + TraceAttack_FireBullets(1, pl.origin + pl.view_ofs, 40, [0.008, 0.008], WEAPON_SNIPER); + Sound_Play(pl, CHAN_WEAPON, "weapon_sniper.fire"); +#endif + + /* Simple toggle of fovs */ + if (pl.viewzoom == 1.0f) { + pl.w_attack_next = 0.1f; + } else { + pl.w_attack_next = 1.0f; + } + + pl.w_idle_next = 10.0f; +} + +void +w_sniper_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_sniper_reload(void) +{ + player pl = (player)self; + if (pl.w_attack_next) { + w_sniper_release(); + return; + } + if (pl.sniper_mag >= 5) { + return; + } + if (pl.ammo_sniper <= 0) { + return; + } + +#ifdef CLIENT + Weapons_ViewAnimation(SNIPER_HOLSTER); +#else + Sound_Play(pl, CHAN_WEAPON, "weapon_sniper.reload"); + Weapons_ReloadWeapon(pl, player::sniper_mag, player::ammo_sniper, 5); +#endif + + pl.mode_tempstate = 1; + pl.w_attack_next = 2.5f; + pl.w_idle_next = 2.0f; +} + +void +w_sniper_crosshair(void) +{ +#ifdef CLIENT + player pl = (player)self; + static vector cross_pos; + vector aicon_pos; + + if (pl.viewzoom < 1.0f) { + drawfill( + g_hudmins, + g_hudres, + [0,0.2,0], + 1.0f, + DRAWFLAG_ADDITIVE + ); + cross_pos = g_hudmins + (g_hudres / 2) + [-128,-104]; + drawpic( + cross_pos, + "sprites/nmxhair2.spr_0.tga", + [256,208], + [1,1,1], + 1.0f, + DRAWFLAG_NORMAL + ); + } else { + + cross_pos = g_hudmins + (g_hudres / 2) + [-12,-12]; + drawsubpic( + cross_pos, + [24,24], + "sprites/crosshairs.spr_0.tga", + [48/128,0], + [24/128,24/128], + [1,1,1], + 1.0f, + DRAWFLAG_NORMAL + ); + } + + HUD_DrawAmmo1(); + HUD_DrawAmmo2(); + + 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_sniper_aimanim(void) +{ + return w_crossbow_aimanim(); +} + +void +w_sniper_hudpic(int selected, vector pos, float a) +{ +#ifdef CLIENT + player pl = (player)self; + vector hud_col; + + if (pl.sniper_mag == 0 && pl.ammo_sniper == 0) + hud_col = [1,0,0]; + else + hud_col = g_hud_color; + + HUD_DrawAmmoBar(pos, pl.ammo_sniper, MAX_A_SNIPER, a); + + if (selected) { + drawsubpic( + pos, + [170,45], + "sprites/tfchud02.spr_0.tga", + [0,45/256], + [170/256,45/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [170,45], + "sprites/tfchud01.spr_0.tga", + [0,45/256], + [170/256,45/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } +#endif +} + +weapon_t w_sniper = +{ + .name = "sniper", + .id = ITEM_SNIPER, + .slot = 2, + .slot_pos = 3, + .draw = w_sniper_draw, + .holster = w_sniper_holster, + .primary = w_sniper_primary, + .secondary = w_sniper_secondary, + .reload = w_sniper_reload, + .release = w_sniper_release, + .crosshair = w_sniper_crosshair, + .precache = w_sniper_precache, + .pickup = w_sniper_pickup, + .updateammo = w_sniper_updateammo, + .wmodel = w_sniper_wmodel, + .pmodel = w_sniper_pmodel, + .deathmsg = w_sniper_deathmsg, + .aimanim = w_sniper_aimanim, + .hudpic = w_sniper_hudpic +}; + +/* pickups */ +#ifdef SERVER +void +weapon_einar1(void) +{ + Weapons_InitItem(WEAPON_SNIPER); +} +#endif diff --git a/src/shared/w_sniper2.qc b/src/shared/w_sniper2.qc new file mode 100644 index 0000000..773aecb --- /dev/null +++ b/src/shared/w_sniper2.qc @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2016-2021 Marco Hladik + * Copyright (c) 2019-2020 Gethyn ThomasQuail + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +enum +{ + SNIPER_IDLE, + SNIPER_RELOAD, + SNIPER_DRAW, + SNIPER_FIRE +}; + +void +w_sniper2_precache(void) +{ +#ifdef SERVER + Sound_Precache("weapon_sniper.fire"); +#endif + precache_model("models/v_hkg36.mdl"); + precache_model("models/w_hkg36.mdl"); + precache_model("models/p_hkg36.mdl"); +} + +int +w_sniper2_pickup(int new, int startammo) +{ +#ifdef SERVER + player pl = (player)self; + + if (new) { + pl.sniper_mag = 5; + } else { + if (pl.ammo_sniper < MAX_A_SNIPER) { + pl.ammo_sniper = bound(0, pl.ammo_sniper + 5, MAX_A_SNIPER); + } else { + return FALSE; + } + } +#endif + return TRUE; +} + +void +w_sniper2_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, pl.sniper_mag, pl.ammo_sniper, -1); +} + +string +w_sniper2_wmodel(void) +{ + return "models/w_hkg36.mdl"; +} + +string +w_sniper2_pmodel(void) +{ + return "models/p_hkg36.mdl"; +} + +string +w_sniper2_deathmsg(void) +{ + return "%s was taken out by %s's Sniper."; +} + +void +w_sniper2_draw(void) +{ +#ifdef CLIENT + Weapons_SetModel("models/v_hkg36.mdl"); + Weapons_ViewAnimation(SNIPER_DRAW); +#endif +} + +void +w_sniper2_holster(void) +{ +} + +void +w_sniper2_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_sniper > 0) { + Weapons_Reload(); + return; + } + + if (pl.w_idle_next > 0.0) { + return; + } + + int r = floor(random(0,2)); + switch (r) { + case 0: + Weapons_ViewAnimation(SNIPER_IDLE1); + pl.w_idle_next = 3.0f; + break; + case 1: + Weapons_ViewAnimation(SNIPER_IDLE2); + pl.w_idle_next = 2.0f; + break; + } + + pl.w_idle_next = 15.0f; +} + +void +w_sniper2_primary(void) +{ + player pl = (player)self; + + if (pl.w_attack_next > 0.0) { + return; + } + + /* Ammo check */ + if (pl.sniper_mag <= 0) { + return; + } + + pl.sniper_mag--; + + /* Actual firing */ +#ifdef CLIENT + View_SetMuzzleflash(MUZZLE_SMALL); + Weapons_ViewPunchAngle([-20,0,0]); + Weapons_ViewAnimation(SNIPER_FIRE); +#else + TraceAttack_FireBullets(1, pl.origin + pl.view_ofs, 40, [0.008, 0.008], WEAPON_SNIPER); + Sound_Play(pl, CHAN_WEAPON, "weapon_sniper.fire"); +#endif + + /* Simple toggle of fovs */ + if (pl.viewzoom == 1.0f) { + pl.w_attack_next = 0.1f; + } else { + pl.w_attack_next = 1.0f; + } + + pl.w_idle_next = 10.0f; +} + +void +w_sniper2_secondary(void) +{ + w_sniper_secondary(); +} + +void +w_sniper2_reload(void) +{ + player pl = (player)self; + + if (pl.w_attack_next > 0.0) { + return; + } + if (pl.sniper_mag >= 5) { + return; + } + if (pl.ammo_sniper <= 0) { + return; + } + +#ifdef CLIENT + Weapons_ViewAnimation(SNIPER_RELOAD); +#else + Weapons_ReloadWeapon(pl, player::sniper_mag, player::ammo_sniper, 5); +#endif + + pl.w_attack_next = 3.82f; + pl.w_idle_next = 5.0f; +} + +void +w_sniper2_crosshair(void) +{ +#ifdef CLIENT + w_sniper_crosshair(); +#endif +} + +float +w_sniper2_aimanim(void) +{ + return w_crossbow_aimanim(); +} + +void +w_sniper2_hudpic(int selected, vector pos, float a) +{ + w_sniper_hudpic(selected, pos, a); +} + +weapon_t w_sniper2 = +{ + .name = "sniper2", + .id = ITEM_SNIPER2, + .slot = 2, + .slot_pos = 4, + .draw = w_sniper2_draw, + .holster = w_sniper2_holster, + .primary = w_sniper2_primary, + .secondary = w_sniper2_secondary, + .reload = w_sniper2_reload, + .release = w_sniper2_release, + .crosshair = w_sniper2_crosshair, + .precache = w_sniper2_precache, + .pickup = w_sniper2_pickup, + .updateammo = w_sniper2_updateammo, + .wmodel = w_sniper2_wmodel, + .pmodel = w_sniper2_pmodel, + .deathmsg = w_sniper2_deathmsg, + .aimanim = w_sniper2_aimanim, + .hudpic = w_sniper2_hudpic +}; + +/* pickups */ +#ifdef SERVER +void +weapon_th_sniper(void) +{ + Weapons_InitItem(WEAPON_SNIPER2); +} +#endif diff --git a/src/shared/w_spanner.qc b/src/shared/w_spanner.qc new file mode 100644 index 0000000..fd85326 --- /dev/null +++ b/src/shared/w_spanner.qc @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2016-2021 Marco Hladik + * Copyright (c) 2019-2020 Gethyn ThomasQuail + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +enum +{ + CBAR_IDLE, + CBAR_ATTACK1, + CBAR_ATTACK2, + CBAR_UNUSED, + CBAR_DRAW, + CBAR_HOLSTER +}; + +void +w_spanner_precache(void) +{ +#ifdef SERVER + Sound_Precache("weapon_crowbar.hit"); + Sound_Precache("weapon_crowbar.miss"); + Sound_Precache("weapon_crowbar.hitbody"); +#endif + precache_model("models/v_tfc_spanner.mdl"); + precache_model("models/backpack.mdl"); + precache_model("models/p_spanner.mdl"); +} + +void +w_spanner_updateammo(player pl) +{ + w_crowbar_updateammo(pl); +} + +string +w_spanner_wmodel(void) +{ + return "models/backpack.mdl"; +} +string +w_spanner_pmodel(void) +{ + return "models/p_spanner.mdl"; +} + +string +w_spanner_deathmsg(void) +{ + return "%s was retooled by %'s Wrench."; +} + +void +w_spanner_draw(void) +{ + Weapons_SetModel("models/v_tfc_spanner.mdl"); + Weapons_ViewAnimation(CBAR_DRAW); +} + +void +w_spanner_holster(void) +{ + w_crowbar_holster(); +} + +void +w_spanner_primary(void) +{ + int anim = 0; + vector src; + player pl = (player)self; + + if (pl.w_attack_next) { + return; + } + + Weapons_MakeVectors(); + src = pl.origin + pl.view_ofs; + traceline(src, src + (v_forward * 32), FALSE, pl); + + if (trace_fraction >= 1.0) { + pl.w_attack_next = 0.375f; + } else { + pl.w_attack_next = 0.20f; + } + pl.w_idle_next = 2.5f; + +#ifdef CLIENT + if (random() < 0.5) { + Weapons_ViewAnimation(CBAR_ATTACK1); + } else { + Weapons_ViewAnimation(CBAR_ATTACK2); + } +#else + if (pl.flags & FL_CROUCHING) { + Animation_PlayerTopTemp(ANIM_SHOOTCROWBAR, 0.5f); + } else { + Animation_PlayerTopTemp(ANIM_CR_SHOOTCROWBAR, 0.42f); + } + + Sound_Play(self, CHAN_WEAPON, "weapon_crowbar.miss"); + + if (trace_fraction >= 1.0) { + return; + } + + /* don't bother with decals, we got squibs */ + if (trace_ent.iBleeds) { + FX_Blood(trace_endpos, [1,0,0]); + } else { + FX_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal); + } + + if (trace_ent.takedamage) { + Damage_Apply(trace_ent, pl, Skill_GetValue("plr_crowbar", 10), WEAPON_CROWBAR, DMG_BLUNT); + + if (!trace_ent.iBleeds) { + return; + } + + Sound_Play(self, CHAN_WEAPON, "weapon_crowbar.hitbody"); + } else { + Sound_Play(self, CHAN_WEAPON, "weapon_crowbar.hit"); + } +#endif +} + +void +w_spanner_release(void) +{ + w_crowbar_release(); +} + +float +w_spanner_aimanim(void) +{ + return w_crowbar_aimanim(); +} + +void +w_spanner_hudpic(int selected, vector pos, float a) +{ +#ifdef CLIENT + if (selected) { + drawsubpic( + pos, + [170,45], + "sprites/tfchud04.spr_0.tga", + [0,180/256], + [170/256,45/256], + g_hud_color, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [170,45], + "sprites/tfchud03.spr_0.tga", + [0,135/256], + [170/256,45/256], + g_hud_color, + a, + DRAWFLAG_ADDITIVE + ); + } +#endif +} + +weapon_t w_spanner = +{ + .name = "spanner", + .id = ITEM_SPANNER, + .slot = 0, + .slot_pos = 2, + .draw = w_spanner_draw, + .holster = w_spanner_holster, + .primary = w_spanner_primary, + .secondary = __NULL__, + .reload = __NULL__, + .release = w_spanner_release, + .crosshair = __NULL__, + .precache = w_spanner_precache, + .pickup = __NULL__, + .updateammo = w_spanner_updateammo, + .wmodel = w_spanner_wmodel, + .pmodel = w_spanner_pmodel, + .deathmsg = w_spanner_deathmsg, + .aimanim = w_spanner_aimanim, + .hudpic = w_spanner_hudpic +}; + +/* entity definitions for pickups */ +#ifdef SERVER +void +weapon_th_spanner(void) +{ + Weapons_InitItem(WEAPON_SPANNER); +} +#endif diff --git a/src/shared/w_taurus.qc b/src/shared/w_taurus.qc new file mode 100644 index 0000000..58e50cb --- /dev/null +++ b/src/shared/w_taurus.qc @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2016-2021 Marco Hladik + * Copyright (c) 2019-2020 Gethyn ThomasQuail + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +enum +{ + TAURUS_IDLE1, + TAURUS_IDLE2, + TAURUS_IDLE3, + TAURUS_SHOOT, + TAURUS_SHOOT2, + TAURUS_SHOOT3, + TAURUS_SHOOT_EMPTY, + TAURUS_RELOAD, + TAURUS_RELOAD2, + TAURUS_DRAW, + TAURUS_HOLSTER +}; + +void +w_taurus_precache(void) +{ +#ifdef SERVER + Sound_Precache("weapon_taurus.fire"); +#endif + precache_model("models/v_taurus.mdl"); + precache_model("models/w_taurus.mdl"); + precache_model("models/p_taurus.mdl"); +} + +void +w_taurus_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, pl.taurus_mag, pl.ammo_taurus, -1); +} + +string +w_taurus_wmodel(void) +{ + return "models/w_taurus.mdl"; +} + +string +w_taurus_pmodel(void) +{ + return "models/p_taurus.mdl"; +} + +string +w_taurus_deathmsg(void) +{ + return "%s is seeing blue from %s's Taurus."; +} + +int +w_taurus_pickup(int new, int startammo) +{ +#ifdef SERVER + player pl = (player)self; + + if (new) { + pl.taurus_mag = 10; + } else { + if (pl.ammo_taurus < MAX_A_TAURUS) { + pl.ammo_taurus = bound(0, pl.ammo_taurus + 10, MAX_A_TAURUS); + } else { + return FALSE; + } + } +#endif + return TRUE; +} + +void +w_taurus_draw(void) +{ +#ifdef CLIENT + Weapons_SetModel("models/v_taurus.mdl"); + Weapons_ViewAnimation(TAURUS_DRAW); +#endif +} + +void +w_taurus_holster(void) +{ +#ifdef CLIENT + Weapons_ViewAnimation(TAURUS_HOLSTER); +#endif +} + +void +w_taurus_primary(void) +{ + player pl = (player)self; + + if (pl.w_attack_next > 0.0) { + return; + } + + /* ammo check */ + if (!pl.taurus_mag) { + return; + } + + pl.taurus_mag--; + + /* actual firing */ +#ifdef CLIENT + View_SetMuzzleflash(MUZZLE_SMALL); + Weapons_ViewPunchAngle([-2,0,0]); + + if (pl.taurus_mag) { + Weapons_ViewAnimation(TAURUS_SHOOT); + } else { + Weapons_ViewAnimation(TAURUS_SHOOT_EMPTY); + } +#else + TraceAttack_FireBullets(1, pl.origin + pl.view_ofs, 12, [0.01,0.01], WEAPON_TAURUS); + Sound_Play(pl, CHAN_WEAPON, "weapon_taurus.fire"); + + if (self.flags & FL_CROUCHING) + Animation_PlayerTopTemp(ANIM_SHOOT1HAND, 0.45f); + else + Animation_PlayerTopTemp(ANIM_CR_SHOOT1HAND, 0.45f); +#endif + + pl.w_attack_next = 0.25f; + pl.w_idle_next = 5.0f; +} + +void +w_taurus_secondary(void) +{ + +} + +void +w_taurus_reload(void) +{ + player pl = (player)self; + + if (pl.w_attack_next > 0.0) { + return; + } + if (pl.taurus_mag >= 10) { + return; + } + if (pl.ammo_taurus <= 0) { + return; + } + +#ifdef CLIENT + if (pl.taurus_mag) { + Weapons_ViewAnimation(TAURUS_RELOAD); + } else { + Weapons_ViewAnimation(TAURUS_RELOAD2); + } +#else + Weapons_ReloadWeapon(pl, player::taurus_mag, player::ammo_taurus, 10); +#endif + + pl.w_attack_next = 2.0f; + pl.w_idle_next = 10.0f; +} + +void +w_taurus_release(void) +{ + player pl = (player)self; + int r; + + /* auto-reload if need be */ + if (pl.w_attack_next <= 0.0) + if (pl.taurus_mag == 0 && pl.ammo_taurus > 0) { + Weapons_Reload(); + return; + } + + if (pl.w_idle_next > 0.0) { + return; + } + + r = floor(random(0,3)); + switch (r) { + case 1: + Weapons_ViewAnimation(TAURUS_IDLE2); + pl.w_idle_next = 2.25f; + break; + case 2: + Weapons_ViewAnimation(TAURUS_IDLE3); + pl.w_idle_next = 2.5f; + break; + default: + Weapons_ViewAnimation(TAURUS_IDLE1); + pl.w_idle_next = 2.81f; + break; + } +} + +float +w_taurus_aimanim(void) +{ + return w_glock_aimanim(); +} + +void +w_taurus_hud(void) +{ + w_glock_hud(); +} + +void +w_taurus_hudpic(int selected, vector pos, float a) +{ + w_glock_hudpic(selected, pos, a); +} + +weapon_t w_taurus = +{ + .name = "taurus", + .id = ITEM_TAURUS, + .slot = 1, + .slot_pos = 3, + .draw = w_taurus_draw, + .holster = w_taurus_holster, + .primary = w_taurus_primary, + .secondary = w_taurus_secondary, + .reload = w_taurus_reload, + .release = w_taurus_release, + .crosshair = w_taurus_hud, + .precache = w_taurus_precache, + .pickup = w_taurus_pickup, + .updateammo = w_taurus_updateammo, + .wmodel = w_taurus_wmodel, + .pmodel = w_taurus_pmodel, + .deathmsg = w_taurus_deathmsg, + .aimanim = w_taurus_aimanim, + .hudpic = w_taurus_hudpic +}; + + +/* pickups */ +#ifdef SERVER +void +weapon_th_taurus(void) +{ + Weapons_InitItem(WEAPON_TAURUS); +} +#endif diff --git a/src/shared/w_tnt.qc b/src/shared/w_tnt.qc new file mode 100644 index 0000000..bf41ed0 --- /dev/null +++ b/src/shared/w_tnt.qc @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2016-2021 Marco Hladik + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +enum +{ + HANDGRENADE_IDLE, + HANDGRENADE_FIDGET, + HANDGRENADE_PULLPIN, + HANDGRENADE_THROW1, + HANDGRENADE_THROW2, + HANDGRENADE_THROW3, + HANDGRENADE_HOLSTER, + HANDGRENADE_DRAW +}; + +void w_tnt_precache(void) +{ +#ifdef SERVER + Sound_Precache("weapon_handgrenade.bounce"); +#endif + + precache_model("models/v_tnt.mdl"); + precache_model("models/w_tnt.mdl"); + precache_model("models/p_tnt.mdl"); +} + +void w_tnt_updateammo(player pl) +{ + w_handgrenade_updateammo(pl); +} + +string w_tnt_wmodel(void) +{ + return "models/w_tnt.mdl"; +} + +string w_tnt_pmodel(void) +{ + return "models/p_tnt.mdl"; +} + +string w_tnt_deathmsg(void) +{ + return w_handgrenade_deathmsg(); +} + +int w_tnt_pickup(int new, int startammo) +{ + return w_handgrenade_pickup(new, startammo); +} + +#ifdef SERVER +void w_tnt_throw(void) +{ + static void WeaponFrag_Throw_Explode(void) + { + float dmg = Skill_GetValue("plr_hand_grenade", 100); + FX_Explosion(self.origin); + Damage_Radius(self.origin, self.owner, dmg, dmg * 2.5f, TRUE, WEAPON_HANDGRENADE); + sound(self, CHAN_WEAPON, sprintf("weapons/explode%d.wav", floor(random() * 2) + 3), 1, ATTN_NORM); + remove(self); + } + + static void WeaponFrag_Throw_Touch(void) + { + if (other.takedamage == DAMAGE_YES) { + Damage_Apply(other, self.owner, 15, WEAPON_HANDGRENADE, DMG_BLUNT); + } else { + Sound_Play(self, CHAN_BODY, "weapon_handgrenade.bounce"); + } + self.frame = 0; + } + + player pl = (player)self; + vector vPLAngle = pl.v_angle; + if (vPLAngle[0] < 0) { + vPLAngle[0] = -10 + vPLAngle[0] * ((90 - 10) / 90.0); + } else { + vPLAngle[0] = -10 + vPLAngle[0] * ((90 + 10) / 90.0); + } + + float flVel = (90 - vPLAngle[0]) * 5; + if (flVel > 1000) { + flVel = 1000; + } + + makevectors(vPLAngle); + vector vecSrc = pl.origin + pl.view_ofs + v_forward * 16; + vector vecThrow = v_forward * flVel + pl.velocity; + + entity eGrenade = spawn(); + eGrenade.owner = pl; + eGrenade.classname = "remove_me"; + eGrenade.solid = SOLID_BBOX; + eGrenade.frame = 1; + eGrenade.velocity = vecThrow; + eGrenade.movetype = MOVETYPE_BOUNCE; + eGrenade.think = WeaponFrag_Throw_Explode; + eGrenade.touch = WeaponFrag_Throw_Touch; + eGrenade.nextthink = time + 4.0f; + setmodel(eGrenade, "models/w_tnt.mdl"); + setsize(eGrenade, [0,0,0], [0,0,0]); + setorigin(eGrenade, vecSrc); +} +#endif + +void w_tnt_draw(void) +{ + player pl = (player)self; + pl.mode_tempstate = 0; + +#ifdef CLIENT + Weapons_SetModel("models/v_tnt.mdl"); + Weapons_ViewAnimation(HANDGRENADE_DRAW); +#endif +} + +void w_tnt_holster(void) +{ + +} +void w_tnt_primary(void) +{ + w_handgrenade_primary(); +} + +void w_tnt_hud(void) +{ +#ifdef CLIENT + HUD_DrawAmmo2(); + vector aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42]; + drawsubpic(aicon_pos, [16,24], "sprites/640hud7.spr_0.tga", [48/256,96/128], [24/256, 24/128], g_hud_color, pSeat->m_flAmmo2Alpha, DRAWFLAG_ADDITIVE); +#endif +} + + +void w_tnt_release(void) +{ + player pl = (player)self; + + if (pl.w_idle_next > 0.0) { + return; + } + + if (pl.mode_tempstate == 1) { +#ifdef CLIENT + pl.ammo_handgrenade--; + Weapons_ViewAnimation(HANDGRENADE_THROW1); +#else + pl.ammo_handgrenade--; + w_tnt_throw(); +#endif + pl.mode_tempstate = 2; + pl.w_attack_next = 1.0f; + pl.w_idle_next = 0.5f; + } else if (pl.mode_tempstate == 2) { +#ifdef CLIENT + Weapons_ViewAnimation(HANDGRENADE_DRAW); +#else + if (!pl.ammo_handgrenade) { + Weapons_RemoveItem(pl, WEAPON_HANDGRENADE); + } +#endif + pl.w_attack_next = 0.5f; + pl.w_idle_next = 0.5f; + pl.mode_tempstate = 0; + } else { + int r = (float)input_sequence % 8; + if (r == 1) { + Weapons_ViewAnimation(HANDGRENADE_FIDGET); + pl.w_idle_next = 2.5f; + } else { + Weapons_ViewAnimation(HANDGRENADE_IDLE); + pl.w_idle_next = 3.0f; + } + } +} + +float +w_tnt_aimanim(void) +{ + return w_handgrenade_aimanim(); +} + +void +w_tnt_hudpic(int selected, vector pos, float a) +{ + w_handgrenade_hudpic(selected, pos, a); +} + +weapon_t w_tnt = +{ + .name = "tnt", + .id = ITEM_HANDGRENADE, + .slot = 4, + .slot_pos = 0, + .draw = w_tnt_draw, + .holster = w_tnt_holster, + .primary = w_tnt_primary, + .secondary = w_tnt_release, + .reload = w_tnt_release, + .release = w_tnt_release, + .crosshair = w_tnt_hud, + .precache = w_tnt_precache, + .pickup = w_tnt_pickup, + .updateammo = w_tnt_updateammo, + .wmodel = w_tnt_wmodel, + .pmodel = w_tnt_pmodel, + .deathmsg = w_tnt_deathmsg, + .aimanim = w_tnt_aimanim, + .hudpic = w_tnt_hudpic +}; diff --git a/src/shared/weapons.h b/src/shared/weapons.h new file mode 100644 index 0000000..5f78276 --- /dev/null +++ b/src/shared/weapons.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2016-2020 Marco Hladik + * + * 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_SHOVEL, + WEAPON_SPANNER, + WEAPON_GLOCK, + WEAPON_PYTHON, + WEAPON_AP9, + WEAPON_TAURUS, + WEAPON_MP5, + WEAPON_SHOTGUN, + WEAPON_CROSSBOW, + WEAPON_SNIPER, + WEAPON_SNIPER2, + WEAPON_RPG, + WEAPON_GAUSS, + WEAPON_EGON, + WEAPON_CHAINGUN, + WEAPON_HANDGRENADE, + WEAPON_SATCHEL, + WEAPON_TRIPMINE, + WEAPON_SNARK, + WEAPON_MEDKIT +}; + +#define MAX_A_9MM 250 +#define MAX_A_357 36 +#define MAX_A_AP9 200 +#define MAX_A_TAURUS 80 +#define MAX_A_BUCKSHOT 125 +#define MAX_A_M203_GRENADE 10 +#define MAX_A_BOLT 50 +#define MAX_A_SNIPER 50 +#define MAX_A_ROCKET 5 +#define MAX_A_URANIUM 100 +#define MAX_A_GAS 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 +#define MAX_A_MEDKIT 12 diff --git a/src/shared/weapons.qc b/src/shared/weapons.qc new file mode 100644 index 0000000..c737b07 --- /dev/null +++ b/src/shared/weapons.qc @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016-2020 Marco Hladik + * + * 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_shovel, + w_spanner, + w_silencer, + w_python, + w_ap9, + w_taurus, + w_mp5, + w_shotgun, + w_crossbow, + w_sniper, + w_sniper2, + w_rpg, + w_gauss, + w_flame, + w_chaingun, + w_tnt, + w_satchel, + w_tripmine, + w_snark, + w_medkit +}; diff --git a/zpak001.pk3dir/default.cfg b/zpak001.pk3dir/default.cfg new file mode 100755 index 0000000..02b7877 --- /dev/null +++ b/zpak001.pk3dir/default.cfg @@ -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" "They Hunger Server" +name "Einar" +model nypdcop +seta "maxplayers" "8" + +// 2D/HUD Variables +seta "con_color" "255 0 0" +seta "vgui_color" "255 0 0" +seta "cross_color" "255 0 0" diff --git a/zpak001.pk3dir/scripts/map_blacklist b/zpak001.pk3dir/scripts/map_blacklist new file mode 100644 index 0000000..eb885e5 --- /dev/null +++ b/zpak001.pk3dir/scripts/map_blacklist @@ -0,0 +1,58 @@ +thintro.bsp +they1.bsp +they2.bsp +they3.bsp +they4.bsp +they5.bsp +they6.bsp +they7.bsp +they8.bsp +they9.bsp +they10.bsp +they11.bsp +they12.bsp +they13.bsp +they14.bsp +they15.bsp +they16.bsp +they17.bsp +they18.bsp +they19.bsp +they20.bsp +they21.bsp +they22.bsp +they23.bsp +they24.bsp +they25.bsp +they26.bsp +they27.bsp +they28.bsp +they29.bsp +they30.bsp +they30a.bsp +they31.bsp +they32.bsp +they33.bsp +they34.bsp +they35.bsp +they36.bsp +they37.bsp +they38.bsp +they39.bsp +they40.bsp +they41.bsp +they42.bsp +they43.bsp +they44.bsp +they45.bsp +they46.bsp +they47.bsp +they48.bsp +they49.bsp +they50.bsp +they51.bsp +they52.bsp +they53.bsp +they54.bsp +they55.bsp +they56.bsp diff --git a/zpak001.pk3dir/sound/items_hunger.sndshd b/zpak001.pk3dir/sound/items_hunger.sndshd new file mode 100644 index 0000000..9b4d78b --- /dev/null +++ b/zpak001.pk3dir/sound/items_hunger.sndshd @@ -0,0 +1,4 @@ +ammo_gas.pickup +{ + sample player/pl_slosh1.wav +} diff --git a/zpak001.pk3dir/sound/weapons_hunger.sndshd b/zpak001.pk3dir/sound/weapons_hunger.sndshd new file mode 100644 index 0000000..eebc03c --- /dev/null +++ b/zpak001.pk3dir/sound/weapons_hunger.sndshd @@ -0,0 +1,55 @@ +weapon_ap9.fire +{ + sample weapons/ap9_fire.wav +} + +weapon_chaingun.fire +{ + sample weapons/asscan2.wav +} + +weapon_chaingun.reload +{ + sample weapons/reload3.wav +} + +weapon_chaingun.spindown +{ + sample weapons/asscan3.wav +} + +weapon_chaingun.spinup +{ + sample weapons/asscan1.wav +} + +weapon_medkit.heal +{ + sample items/smallmedkit1.wav +} + +weapon_flame.fire +{ + sample weapons/flmfire2.wav +} + +weapon_silencer.fire +{ + sample weapons/pl_gun1.wav + sample weapons/pl_gun2.wav +} + +weapon_sniper.fire +{ + sample weapons/sniper.wav +} + +weapon_sniper.reload +{ + sample weapons/reload3.wav +} + +weapon_taurus.fire +{ + sample weapons/tau_fire.wav +}