commit e26c38718a81fa604d550b610d8f8711781ed5ec Author: Marco Hladik Date: Mon Mar 8 11:58:43 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..0c52dbf --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +# FreePoke646 +Clean-room reimplementation of Poke646 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 poke646 + +then either run Nuclide's ./build_game.sh shell script, or issue 'make' inside +./poke646/src! + +Obviously make sure that Nuclide has fteqw and fteqcc set-up for building. + +## Community +Join us on #halflife or #poke646 via irc.frag-net.com and chat. + +## License +ISC License + +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. diff --git a/data.pk3dir/default.cfg b/data.pk3dir/default.cfg new file mode 100755 index 0000000..43ea9b2 --- /dev/null +++ b/data.pk3dir/default.cfg @@ -0,0 +1,41 @@ +// 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" + +// 2D/HUD Variables +seta "con_color" "193 207 204" +seta "vgui_color" "0 255 0" +seta "cross_color" "0 255 0" diff --git a/data.pk3dir/sound/weapons_poke646.sndshd b/data.pk3dir/sound/weapons_poke646.sndshd new file mode 100644 index 0000000..96aee2a --- /dev/null +++ b/data.pk3dir/sound/weapons_poke646.sndshd @@ -0,0 +1,10 @@ +weapon_bradnailer.fire +{ + sample weapons/bradnailer.wav +} + +weapon_bradnailer.hitbody +{ + sample weapons/brad_hit1.wav + sample weapons/brad_hit2.wav +} diff --git a/img/preview1.jpg b/img/preview1.jpg new file mode 100644 index 0000000..56edb30 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..79bb5f5 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..debd541 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..c83ced2 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/entities.qc b/src/client/entities.qc new file mode 100644 index 0000000..3e4da72 --- /dev/null +++ b/src/client/entities.qc @@ -0,0 +1,26 @@ +/* + * 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. + */ + +int +ClientGame_EntityUpdate(float id, float new) +{ + switch (id) { + default: + return FALSE; + } + + return TRUE; +} diff --git a/src/client/init.qc b/src/client/init.qc new file mode 100644 index 0000000..8bce813 --- /dev/null +++ b/src/client/init.qc @@ -0,0 +1,61 @@ +/* + * 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/hud640_01.spr"); + precache_model("sprites/hud640_02.spr"); + precache_model("sprites/hud640_04.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..a1420e5 --- /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 POKE646 +#define CLASSIC_VGUI +#define GS_RENDERFX + +#includelist +../../../src/shared/fteextensions.qc +../../../src/shared/defs.h +../../../valve/src/client/defs.h +../../../src/client/defs.h + +../../../src/vgui/include.src + +../../../src/gs-entbase/client.src +../../../src/gs-entbase/shared.src +../shared/include.src + +../../../valve/src/client/predict.qc +init.qc +../../../valve/src/client/player.qc +entities.qc +../../../valve/src/client/cmds.qc +../../../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_p646.qc b/src/server/ammo_p646.qc new file mode 100644 index 0000000..329e834 --- /dev/null +++ b/src/server/ammo_p646.qc @@ -0,0 +1,184 @@ +/* + * 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. + */ + +class item_ammo:CBaseEntity +{ + void(void) item_ammo; + virtual void(void) Respawn; + virtual void(void) touch; +}; + +void item_ammo::touch(void) +{ + if not (other.flags & FL_CLIENT) { + return; + } + + player pl = (player)other; + Sound_Play(other, CHAN_ITEM, "ammo.pickup"); + Weapons_RefreshAmmo(pl); + Logging_Pickup(other, this, __NULL__); + + if (cvar("sv_playerslots") == 1) { + remove(self); + } else { + Hide(); + think = Respawn; + nextthink = time + 20.0f; + } +} + +void item_ammo::Respawn(void) +{ + solid = SOLID_TRIGGER; + movetype = MOVETYPE_TOSS; + + if (m_oldModel) { + SetModel(m_oldModel); + } + + setsize(this, [-16,-16,0], [16,16,16]); + SetOrigin(origin); + + think = __NULL__; + nextthink = -1; + Sound_Play(this, CHAN_ITEM, "ammo.respawn"); + droptofloor(); +} + +void item_ammo::item_ammo(void) +{ + m_oldModel = model; + SetModel(m_oldModel); + CBaseEntity::CBaseEntity(); +} + +/* + * Ammo for the Crossbow. + * A single ammo_bolts will provide 5 bolts. + */ + +class +ammo_bolts:item_ammo +{ + void(void) ammo_bolts; +}; + +void +ammo_bolts::ammo_bolts(void) +{ + model = "models/w_crossbow_clip.mdl"; +} + +/*QUAKED ammo_nailclip (0 0 0.8) (-16 -16 0) (16 16 32) + +Poke646 (2001) ENTITY + +Ammo for the nailguns. +A single ammo_nailclip will provide 25 nails. + +*/ +class ammo_nailclip:item_ammo +{ + void(void) ammo_nailclip; + virtual void(void) touch; +}; + +void ammo_nailclip::ammo_nailclip(void) +{ + model = "models/w_nailclip.mdl"; + item_ammo::item_ammo(); +} +void ammo_nailclip::touch(void) +{ + if not (other.flags & FL_CLIENT) { + return; + } + if (other.classname == "player") { + player pl = (player)other; + if (pl.ammo_nail < MAX_A_NAIL) { + pl.ammo_nail = bound(0, pl.ammo_nail + 25, MAX_A_NAIL); + item_ammo::touch(); + } + } +} + +/*QUAKED ammo_nailround (0 0 0.8) (-16 -16 0) (16 16 32) + +Poke646 (2001) ENTITY + +Ammo for the nailguns. +A single ammo_nailround will provide 50 nails. + +*/ +class ammo_nailround:item_ammo +{ + void(void) ammo_nailround; + virtual void(void) touch; +}; + +void ammo_nailround::ammo_nailround(void) +{ + model = "models/w_nailround.mdl"; + item_ammo::item_ammo(); +} +void ammo_nailround::touch(void) +{ + if not (other.flags & FL_CLIENT) { + return; + } + if (other.classname == "player") { + player pl = (player)other; + if (pl.ammo_nail < MAX_A_NAIL) { + pl.ammo_nail = bound(0, pl.ammo_nail + 50, MAX_A_NAIL); + item_ammo::touch(); + } + } +} + +/*QUAKED ammo_xencandy (0 0 0.8) (-16 -16 0) (16 16 32) + +Poke646 (2001) ENTITY + +Ammo for the alien. +A single ammo_xencandy will provide 20 snacks. + +*/ + +class ammo_xencandy:item_ammo +{ + void(void) ammo_xencandy; + virtual void(void) touch; +}; + +void ammo_xencandy::ammo_xencandy(void) +{ + model = "models/w_xencandy.mdl"; + item_ammo::item_ammo(); +} +void ammo_xencandy::touch(void) +{ + if not (other.flags & FL_CLIENT) { + return; + } + if (other.classname == "player") { + player pl = (player)other; + if (pl.ammo_xencandy < MAX_A_XENCANDY) { + pl.ammo_xencandy = bound(0, pl.ammo_xencandy + 20, MAX_A_XENCANDY); + item_ammo::touch(); + } + } +} diff --git a/src/server/gamerules.qc b/src/server/gamerules.qc new file mode 100644 index 0000000..33f8a82 --- /dev/null +++ b/src/server/gamerules.qc @@ -0,0 +1,127 @@ +/* + * 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. + */ + +/* we check what fields have changed over the course of the frame and network + * only the ones that have actually changed */ +void +HLGameRules::PlayerPostFrame(base_player pp) +{ + Animation_PlayerUpdate(); +} + +void +HLGameRules::LevelNewParms(void) +{ + parm1 = parm2 = parm3 = parm4 = parm5 = parm6 = parm7 = + parm8 = parm9 = parm10 = parm11 = parm12 = parm13 = parm14 = + parm15 = parm16 = parm17 = parm18 = parm19 = parm20 = parm21 = + parm22 = parm23 = parm24 = parm25 = parm26 = parm27 = parm28 = + parm29 = parm30 = 0; + parm64 = FL_CLIENT; +} + +void +HLGameRules::LevelDecodeParms(base_player pp) +{ + player pl = (player)pp; + g_landmarkpos[0] = parm1; + g_landmarkpos[1] = parm2; + g_landmarkpos[2] = parm3; + pl.angles[0] = parm4; + pl.angles[1] = parm5; + pl.angles[2] = parm6; + pl.velocity[0] = parm7; + pl.velocity[1] = parm8; + pl.velocity[2] = parm9; + pl.g_items = parm10; + pl.activeweapon = parm11; + pl.flags = parm64; + + pl.ammo_nail = parm12; + pl.ammo_buckshot = parm13; + pl.ammo_bolts = parm14; + pl.ammo_xencandy = parm15; + pl.ammo_satchel = parm16; + + pl.bradnailer_mag = parm17; + pl.nailgun_mag = parm18; + pl.shotgun_mag = parm19; + pl.cmlwbr_mag = parm20; + pl.xs_mag = parm21; + pl.satchel_chg = parm22; + + if (pl.flags & FL_CROUCHING) { + setsize(pl, VEC_CHULL_MIN, VEC_CHULL_MAX); + } else { + setsize(pl, VEC_HULL_MIN, VEC_HULL_MAX); + } +} + +void +HLGameRules::LevelChangeParms(base_player pp) +{ + player pl = (player)pp; + parm1 = g_landmarkpos[0]; + parm2 = g_landmarkpos[1]; + parm3 = g_landmarkpos[2]; + parm4 = pl.angles[0]; + parm5 = pl.angles[1]; + parm6 = pl.angles[2]; + parm7 = pl.velocity[0]; + parm8 = pl.velocity[1]; + parm9 = pl.velocity[2]; + parm64 = pl.flags; + parm10 = pl.g_items; + parm11 = pl.activeweapon; + parm12 = pl.ammo_nail; + parm13 = pl.ammo_buckshot; + parm14 = pl.ammo_bolts; + parm15 = pl.ammo_xencandy; + parm16 = pl.ammo_satchel; + parm17 = pl.bradnailer_mag; + parm18 = pl.nailgun_mag; + parm19 = pl.shotgun_mag; + parm20 = pl.cmlwbr_mag; + parm21 = pl.xs_mag; + parm22 = pl.satchel_chg; +} + +void +HLGameRules::PlayerConnect(base_player pl) +{ + bprint(PRINT_HIGH, sprintf("%s connected\n", pl.netname)); +} + +void +HLGameRules::PlayerDisconnect(base_player pl) +{ + bprint(PRINT_HIGH, sprintf("%s disconnected\n", pl.netname)); + + /* Make this unusable */ + pl.solid = SOLID_NOT; + pl.movetype = MOVETYPE_NONE; + pl.modelindex = 0; + pl.health = 0; + pl.takedamage = 0; + pl.SendFlags = PLAYER_MODELINDEX; +} + +void +HLGameRules::PlayerKill(base_player pp) +{ + player pl = (player)pp; + Damage_Apply(pl, pl, pl.health, WEAPON_NONE, DMG_SKIP_ARMOR); +} diff --git a/src/server/gamerules_multiplayer.qc b/src/server/gamerules_multiplayer.qc new file mode 100644 index 0000000..2e5848b --- /dev/null +++ b/src/server/gamerules_multiplayer.qc @@ -0,0 +1,120 @@ +/* + * 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. + */ + +void +HLMultiplayerRules::FrameStart(void) +{ + if (cvar("mp_timelimit") != 0) + if (time >= (cvar("mp_timelimit") * 60)) { + IntermissionStart(); + } +} + +void +HLMultiplayerRules::PlayerDeath(base_player pp) +{ + player pl = (player)pp; + pl.movetype = MOVETYPE_NONE; + pl.solid = SOLID_NOT; + pl.takedamage = DAMAGE_NO; + pl.gflags &= ~GF_FLASHLIGHT; + pl.armor = pl.activeweapon = pl.g_items = 0; + + pl.think = PutClientInServer; + pl.nextthink = time + 4.0f; + + if (pl.health < -50) { + pl.health = 0; + FX_GibHuman(pl.origin); + return; + } + + pl.health = 0; + + /* Let's handle corpses on the clientside */ + entity corpse = spawn(); + setorigin(corpse, pl.origin + [0,0,32]); + setmodel(corpse, pl.model); + setsize(corpse, VEC_HULL_MIN, VEC_HULL_MAX); + corpse.movetype = MOVETYPE_TOSS; + corpse.solid = SOLID_TRIGGER; + corpse.modelindex = pl.modelindex; + corpse.frame = ANIM_DIESIMPLE; + corpse.angles = pl.angles; + corpse.velocity = pl.velocity; +} + +void +HLMultiplayerRules::PlayerSpawn(base_player pp) +{ + player pl = (player)pp; + /* this is where the mods want to deviate */ + entity spot; + + pl.classname = "player"; + pl.health = pl.max_health = 100; + pl.takedamage = DAMAGE_YES; + pl.solid = SOLID_SLIDEBOX; + pl.movetype = MOVETYPE_WALK; + pl.flags = FL_CLIENT; + pl.viewzoom = 1.0; + pl.model = "models/player.mdl"; + string mymodel = infokey(pl, "model"); + + if (mymodel) { + mymodel = sprintf("models/player/%s/%s.mdl", mymodel, mymodel); + if (whichpack(mymodel)) { + pl.model = mymodel; + } + } + setmodel(pl, pl.model); + + setsize(pl, VEC_HULL_MIN, VEC_HULL_MAX); + pl.view_ofs = VEC_PLAYER_VIEWPOS; + pl.velocity = [0,0,0]; + pl.gravity = __NULL__; + pl.frame = 1; + pl.SendFlags = UPDATE_ALL; + pl.customphysics = Empty; + pl.iBleeds = TRUE; + forceinfokey(pl, "*spec", "0"); + forceinfokey(pl, "*deaths", ftos(pl.deaths)); + + LevelNewParms(); + LevelDecodeParms(pl); + spot = Spawn_SelectRandom("info_player_deathmatch"); + setorigin(pl, spot.origin); + pl.angles = spot.angles; + Weapons_RefreshAmmo(pl); + + Client_FixAngle(pl, pl.angles); +} + +float +HLMultiplayerRules::ConsoleCommand(base_player pp, string cmd) +{ + tokenize(cmd); + + switch (argv(0)) { + case "bot_add": + Bot_AddQuick(); + break; + default: + return FALSE; + } + + return TRUE; +} diff --git a/src/server/input.qc b/src/server/input.qc new file mode 100644 index 0000000..c52ec79 --- /dev/null +++ b/src/server/input.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. + */ + +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; + Weapons_AddItem(pl, WEAPON_HEATERPIPE, -1); + Weapons_AddItem(pl, WEAPON_BRADNAILER, -1); + Weapons_AddItem(pl, WEAPON_NAILGUN, -1); + Weapons_AddItem(pl, WEAPON_SHOTGUN, -1); + Weapons_AddItem(pl, WEAPON_CMLWBR, -1); + Weapons_AddItem(pl, WEAPON_XS, -1); + Weapons_AddItem(pl, WEAPON_SATCHEL, -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..8b7e6ed --- /dev/null +++ b/src/server/progs.src @@ -0,0 +1,89 @@ +#pragma target fte +#pragma progs_dat "../../progs.dat" + +#define QWSSQC +#define SERVER +#define VALVE +#define POKE646 +#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/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 +ammo_p646.qc + +../../../src/botlib/include.src + +gamerules.qc +../../../valve/src/server/gamerules_singleplayer.qc +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..cc0449e --- /dev/null +++ b/src/shared/include.src @@ -0,0 +1,29 @@ + #includelist +../../../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_satchel.qc +w_bradnailer.qc +w_cmlwbr.qc +w_heaterpipe.qc +w_nailgun.qc +w_pipebomb.qc +w_shotgun.qc +w_xs.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..f733a1d --- /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_HEATERPIPE 0x00000001i +#define ITEM_BRADNAILER 0x00000002i +#define ITEM_NAILGUN 0x00000004i +#define ITEM_SHOTGUN 0x00000008i +#define ITEM_CMLWBR 0x00000010i +#define ITEM_XS 0x00000020i +#define ITEM_SATCHEL 0x00000040i +#define ITEM_UNUSED8 0x00000080i + +#define ITEM_UNUSED9 0x00000100i +#define ITEM_UNUSED10 0x00000200i +#define ITEM_UNUSED11 0x00000400i +#define ITEM_UNUSED12 0x00000800i +#define ITEM_UNUSED13 0x00001000i +#define ITEM_UNUSED14 0x00002000i +#define ITEM_SUIT 0x00004000i +#define ITEM_LONGJUMP 0x00008000i + +#define ITEM_UNUSED17 0x00010000i +#define ITEM_UNUSED18 0x00020000i +#define ITEM_UNUSED19 0x00040000i +#define ITEM_UNUSED20 0x00080000i +#define ITEM_UNUSED21 0x00100000i +#define ITEM_UNUSED22 0x00200000i +#define ITEM_UNUSED23 0x00400000i +#define ITEM_UNUSED24 0x00800000i + +#define ITEM_UNUSED25 0x01000000i +#define ITEM_UNUSED26 0x02000000i +#define ITEM_UNUSED27 0x04000000i +#define ITEM_UNUSED28 0x08000000i +#define ITEM_UNUSED29 0x10000000i +#define ITEM_UNUSED30 0x20000000i +#define ITEM_UNUSED31 0x40000000i +#define ITEM_UNUSED32 0x80000000i diff --git a/src/shared/player.qc b/src/shared/player.qc new file mode 100644 index 0000000..e3b1ae8 --- /dev/null +++ b/src/shared/player.qc @@ -0,0 +1,464 @@ +/* + * 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 +}; + +noref int input_sequence; +class player:base_player +{ + /* Weapon specific */ + int bradnailer_mag; int bradnailer_mag_net; + int nailgun_mag; int nailgun_mag_net; + int shotgun_mag; int shotgun_mag_net; + int cmlwbr_mag; int cmlwbr_mag_net; + int xs_mag; int xs_mag_net; + int satchel_chg; int satchel_chg_net; + + int ammo_nail; int ammo_nail_net; + int ammo_buckshot; int ammo_buckshot_net; + int ammo_bolts; int ammo_bolts_net; + int ammo_xencandy; int ammo_xencandy_net; + int ammo_satchel; int ammo_satchel_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) { + bradnailer_mag = readbyte(); + nailgun_mag = readbyte(); + shotgun_mag = readbyte(); + cmlwbr_mag = readbyte(); + xs_mag = readbyte(); + satchel_chg = readbyte(); + } + + if (fl & PLAYER_AMMO2) { + ammo_nail = readbyte(); + ammo_buckshot = readbyte(); + ammo_bolts = readbyte(); + ammo_xencandy = readbyte(); + ammo_satchel = readbyte(); + } + + if (fl & PLAYER_AMMO3) { + } + + 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) +{ + bradnailer_mag_net = bradnailer_mag; + nailgun_mag_net = nailgun_mag; + shotgun_mag_net = shotgun_mag; + cmlwbr_mag_net = cmlwbr_mag; + xs_mag_net = xs_mag; + satchel_chg_net = satchel_chg; + + ammo_nail_net = ammo_nail; + ammo_buckshot_net = ammo_buckshot; + ammo_bolts_net = ammo_bolts; + ammo_xencandy_net = ammo_xencandy; + ammo_satchel_net = ammo_satchel; +} + +/* +================= +player::PredictPostFrame + +Where we roll back our values to the ones last sent/verified by the server. +================= +*/ +void +player::PredictPostFrame(void) +{ + bradnailer_mag = bradnailer_mag_net; + nailgun_mag = nailgun_mag_net; + shotgun_mag = shotgun_mag_net; + cmlwbr_mag = cmlwbr_mag_net; + xs_mag = xs_mag_net; + satchel_chg = satchel_chg_net; + + ammo_nail = ammo_nail_net; + ammo_buckshot = ammo_buckshot_net; + ammo_bolts = ammo_bolts_net; + ammo_xencandy = ammo_xencandy_net; + ammo_satchel = ammo_satchel_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; + + 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; + + if (bradnailer_mag_net != bradnailer_mag) + SendFlags |= PLAYER_AMMO1; + if (nailgun_mag_net != nailgun_mag) + SendFlags |= PLAYER_AMMO1; + if (shotgun_mag_net != shotgun_mag) + SendFlags |= PLAYER_AMMO1; + if (cmlwbr_mag_net != cmlwbr_mag) + SendFlags |= PLAYER_AMMO1; + if (xs_mag_net != xs_mag) + SendFlags |= PLAYER_AMMO1; + if (satchel_chg_net != satchel_chg) + SendFlags |= PLAYER_AMMO1; + + if (ammo_nail_net != ammo_nail) + SendFlags |= PLAYER_AMMO2; + if (ammo_buckshot_net != ammo_buckshot) + SendFlags |= PLAYER_AMMO2; + if (ammo_bolts_net != ammo_bolts) + SendFlags |= PLAYER_AMMO2; + if (ammo_xencandy_net != ammo_xencandy) + SendFlags |= PLAYER_AMMO2; + if (ammo_satchel_net != ammo_satchel) + SendFlags |= PLAYER_AMMO2; + + bradnailer_mag_net = bradnailer_mag; + nailgun_mag_net = nailgun_mag; + shotgun_mag_net = shotgun_mag; + cmlwbr_mag_net = cmlwbr_mag; + xs_mag_net = xs_mag; + satchel_chg_net = satchel_chg; + + ammo_nail_net = ammo_nail; + ammo_buckshot_net = ammo_buckshot; + ammo_bolts_net = ammo_bolts; + ammo_xencandy_net = ammo_xencandy; + ammo_satchel_net = ammo_satchel; +} + +/* +================= +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, bradnailer_mag); + WriteByte(MSG_ENTITY, nailgun_mag); + WriteByte(MSG_ENTITY, shotgun_mag); + WriteByte(MSG_ENTITY, cmlwbr_mag); + WriteByte(MSG_ENTITY, xs_mag); + WriteByte(MSG_ENTITY, satchel_chg); + } + + if (fChanged & PLAYER_AMMO2) { + WriteByte(MSG_ENTITY, ammo_nail); + WriteByte(MSG_ENTITY, ammo_buckshot); + WriteByte(MSG_ENTITY, ammo_bolts); + WriteByte(MSG_ENTITY, ammo_xencandy); + WriteByte(MSG_ENTITY, ammo_satchel); + } + + if (fChanged & PLAYER_AMMO3) { + } + + return TRUE; +} +#endif diff --git a/src/shared/w_bradnailer.qc b/src/shared/w_bradnailer.qc new file mode 100644 index 0000000..20060ef --- /dev/null +++ b/src/shared/w_bradnailer.qc @@ -0,0 +1,268 @@ +/* + * 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. + */ + +/*QUAKED weapon_bradnailer (0 0 1) (-16 -16 0) (16 16 32) +"model" "models/w_bradnailer.mdl" + +Poke646 (2001) ENTITY + +Handheld Nailgun that kills like a pistol + +*/ + +enum +{ + BNAIL_IDLE1, + BNAIL_IDLE2, + BNAIL_IDLE3, + BNAIL_SHOOT, + BNAIL_UNUSED1, + BNAIL_RELOAD, + BNAIL_UNUSED2, + BNAIL_DRAW, + BNAIL_HOLSTER, + BNAIL_UNUSED3, + BNAIL_TILT, + BNAIL_TILTBACK, + BNAIL_SHOOT2 +}; + +void +w_bradnailer_precache(void) +{ +#ifdef SERVER + Sound_Precache("weapon_bradnailer.fire"); + Sound_Precache("weapon_bradnailer.hitbody"); +#endif + + precache_model("models/nail.mdl"); + precache_model("models/v_bradnailer.mdl"); + precache_model("models/w_bradnailer.mdl"); +} + +void +w_bradnailer_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, pl.bradnailer_mag, pl.ammo_nail, -1); +} + +string +w_bradnailer_wmodel(void) +{ + return "models/w_bradnailer.mdl"; +} + +int +w_bradnailer_pickup(int new, int startammo) +{ +/* TODO */ + return TRUE; +} + +void +w_bradnailer_draw(void) +{ + Weapons_SetModel("models/v_bradnailer.mdl"); + Weapons_ViewAnimation(BNAIL_DRAW); +} + +void +w_bradnailer_holster(void) +{ + Weapons_ViewAnimation(BNAIL_HOLSTER); +} + +#ifdef SERVER +void +w_bradnailer_shootnail(void) +{ + player pl = (player)self; + static void Nail_Touch(void) { + FX_Spark(self.origin, trace_plane_normal); + if (other.takedamage == DAMAGE_YES) { + Damage_Apply(other, self.owner, 15, WEAPON_BRADNAILER, DMG_GENERIC); + Sound_Play(self, CHAN_WEAPON, "weapon_bradnailer.hitbody"); + } else { + Sound_Play(self, CHAN_WEAPON, "weapon_crossbow.hit"); + } + remove(self); + } + + Weapons_MakeVectors(); + entity nail = spawn(); + setmodel(nail, "models/nail.mdl"); + setorigin(nail, Weapons_GetCameraPos() + (v_forward * 16)); + nail.owner = self; + nail.velocity = v_forward * 2000; + nail.movetype = MOVETYPE_FLY; + nail.solid = SOLID_BBOX; + nail.angles = vectoangles(nail.velocity); + nail.avelocity[2] = 10; + nail.touch = Nail_Touch; + setsize(nail, [0,0,0], [0,0,0]); + + if (self.flags & FL_CROUCHING) + Animation_PlayerTopTemp(ANIM_SHOOT1HAND, 0.45f); + else + Animation_PlayerTopTemp(ANIM_CR_SHOOT1HAND, 0.45f); + + Sound_Play(pl, CHAN_WEAPON, "weapon_bradnailer.fire"); +} +#endif + +void +w_bradnailer_primary(void) +{ + player pl = (player)self; + + if (pl.w_attack_next > 0.0) { + return; + } + +#ifdef SERVER + w_bradnailer_shootnail(); +#else + Weapons_ViewPunchAngle([-2,0,0]); + Weapons_ViewAnimation(BNAIL_SHOOT); +#endif + + pl.w_attack_next = 0.3f; + pl.w_idle_next = 5.0f; +} + +void +w_bradnailer_secondary(void) +{ + player pl = (player)self; + + if (pl.w_attack_next > 0.0) { + return; + } + + /* Hack */ + if (pl.a_ammo3 == 0) { + pl.a_ammo3 = 1; + Weapons_ViewAnimation(BNAIL_TILT); + pl.w_attack_next = 0.4f; + pl.w_idle_next = pl.w_attack_next; + return; + } + +#ifdef SERVER + w_bradnailer_shootnail(); +#else + Weapons_ViewPunchAngle([-2,0,0]); + Weapons_ViewAnimation(BNAIL_SHOOT2); +#endif + + pl.w_attack_next = 0.2f; + pl.w_idle_next = pl.w_attack_next; +} + + +void +w_bradnailer_release(void) +{ + player pl = (player)self; + + if (pl.w_idle_next > 0.0) { + return; + } + + if (pl.a_ammo3 == 1) { + pl.a_ammo3 = 0; + Weapons_ViewAnimation(BNAIL_TILTBACK); + pl.w_attack_next = 0.4f; + pl.w_idle_next = pl.w_attack_next; + return; + } + + int r = (float)input_sequence % 3; + switch (r) { + case 0: + Weapons_ViewAnimation(BNAIL_IDLE1); + break; + case 1: + Weapons_ViewAnimation(BNAIL_IDLE2); + break; + case 2: + Weapons_ViewAnimation(BNAIL_IDLE3); + break; + } + pl.w_idle_next = 10.0f; +} + +void +w_bradnailer_hudpic(int selected, vector pos, float a) +{ +#ifdef CLIENT + if (selected) { + drawsubpic( + pos, + [170,45], + "sprites/hud640_01.spr_0.tga", + [0,45/256], + [170/256,45/256], + g_hud_color, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [170,45], + "sprites/hud640_01.spr_0.tga", + [0,45/256], + [170/256,45/256], + g_hud_color, + a, + DRAWFLAG_ADDITIVE + ); + } +#endif +} + +weapon_t w_bradnailer = +{ + .name = "bradnailer", + .id = ITEM_BRADNAILER, + .slot = 1, + .slot_pos = 0, + .draw = w_bradnailer_draw, + .holster = w_bradnailer_holster, + .primary = w_bradnailer_primary, + .secondary = w_bradnailer_secondary, + .reload = __NULL__, + .release = w_bradnailer_release, + .crosshair = __NULL__, + .precache = w_bradnailer_precache, + .pickup = w_bradnailer_pickup, + .updateammo = w_bradnailer_updateammo, + .wmodel = w_bradnailer_wmodel, + .pmodel = __NULL__, + .deathmsg = __NULL__, + .aimanim = __NULL__, + .hudpic = w_bradnailer_hudpic +}; + +/* entity definitions for pickups */ +#ifdef SERVER +void +weapon_bradnailer(void) +{ + Weapons_InitItem(WEAPON_BRADNAILER); +} +#endif diff --git a/src/shared/w_cmlwbr.qc b/src/shared/w_cmlwbr.qc new file mode 100644 index 0000000..f9dfda3 --- /dev/null +++ b/src/shared/w_cmlwbr.qc @@ -0,0 +1,151 @@ +/* + * 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 +{ + CML_IDLE1, + CML_IDLE2, + CML_IDLE3, + CML_IDLE4, + CML_FIRE1, + CML_RELOAD, + CML_DRAWBACK, + CML_UNDRAW, + CML_DRAW, + CML_UNUSED, + CML_HOLSTER +}; + +void +w_cmlwbr_precache(void) +{ + precache_sound("weapons/cmlwbr_drawback.wav"); + precache_sound("weapons/cmlwbr_fire.wav"); + precache_sound("weapons/cmlwbr_reload.wav"); + precache_sound("weapons/cmlwbr_undraw.wav"); + precache_sound("weapons/cmlwbr_zoom.wav"); + + precache_model("models/v_cmlwbr.mdl"); + precache_model("models/w_crossbow.mdl"); +} + +void +w_cmlwbr_updateammo(player pl) +{ +#ifdef SERVER + Weapons_UpdateAmmo(pl, __NULL__, __NULL__, __NULL__); +#endif +} + +string +w_cmlwbr_wmodel(void) +{ + return "models/w_crossbow.mdl"; +} + +void +w_cmlwbr_draw(void) +{ + Weapons_SetModel("models/v_cmlwbr.mdl"); + Weapons_ViewAnimation(CML_DRAW); +} + +void +w_cmlwbr_holster(void) +{ + Weapons_ViewAnimation(CML_HOLSTER); +} + +void +w_cmlwbr_primary(void) +{ +/* TODO, attack slows to crawl & player breathes */ +} + +void +w_cmlwbr_secondary(void) +{ + +} + + +void +w_cmlwbr_release(void) +{ + +} + +void +w_cmlwbr_hudpic(int selected, vector pos, float a) +{ +#ifdef CLIENT + if (selected) { + drawsubpic( + pos, + [170,45], + "sprites/hud640_03.spr_0.tga", + [0,45/256], + [170/256,45/256], + g_hud_color, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [170,45], + "sprites/hud640_03.spr_0.tga", + [0,45/256], + [170/256,45/256], + g_hud_color, + a, + DRAWFLAG_ADDITIVE + ); + } +#endif +} + +weapon_t w_cmlwbr = +{ + .name = "cmlwbr", + .id = ITEM_CMLWBR, + .slot = 2, + .slot_pos = 1, + .draw = w_cmlwbr_draw, + .holster = w_cmlwbr_holster, + .primary = w_cmlwbr_primary, + .secondary = w_cmlwbr_secondary, + .reload = __NULL__, + .release = w_cmlwbr_release, + .crosshair = __NULL__, + .precache = w_cmlwbr_precache, + .pickup = __NULL__, + .updateammo = w_cmlwbr_updateammo, + .wmodel = w_cmlwbr_wmodel, + .pmodel = __NULL__, + .deathmsg = __NULL__, + .aimanim = __NULL__, + .hudpic = w_cmlwbr_hudpic +}; + +/* entity definitions for pickups */ +#ifdef SERVER +void +weapon_cmlwbr(void) +{ + Weapons_InitItem(WEAPON_CMLWBR); +} +#endif diff --git a/src/shared/w_heaterpipe.qc b/src/shared/w_heaterpipe.qc new file mode 100644 index 0000000..ff9557e --- /dev/null +++ b/src/shared/w_heaterpipe.qc @@ -0,0 +1,140 @@ +/* + * 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 +{ + HPIPE_IDLE1, + HPIPE_DRAW, + HPIPE_HOLSTER, + HPIPE_ATTACK1, + HPIPE_ATTACK1MISS, + HPIPE_ATTACK2MISS, + HPIPE_ATTACK2, + HPIPE_ATTACK3MISS, + HPIPE_ATTACK3 +}; + +void +w_heaterpipe_precache(void) +{ + precache_sound("weapons/pipe_hit1.wav"); + precache_sound("weapons/pipe_hit2.wav"); + precache_sound("weapons/pipe_miss.wav"); + + precache_model("models/v_heaterpipe.mdl"); + precache_model("models/w_heaterpipe.mdl"); +} + +void +w_heaterpipe_updateammo(player pl) +{ +#ifdef SERVER + Weapons_UpdateAmmo(pl, __NULL__, __NULL__, __NULL__); +#endif +} + +string +w_heaterpipe_wmodel(void) +{ + return "models/w_heaterpipe.mdl"; +} + +void +w_heaterpipe_draw(void) +{ + Weapons_SetModel("models/v_heaterpipe.mdl"); + Weapons_ViewAnimation(HPIPE_DRAW); +} + +void +w_heaterpipe_holster(void) +{ + Weapons_ViewAnimation(HPIPE_HOLSTER); +} + +void +w_heaterpipe_primary(void) +{ +/* TODO, attack slows to crawl & player breathes */ +} + +void +w_heaterpipe_release(void) +{ + +} + +void +w_heaterpipe_hudpic(int selected, vector pos, float a) +{ +#ifdef CLIENT + if (selected) { + drawsubpic( + pos, + [170,45], + "sprites/hud640_01.spr_0.tga", + [0,45/256], + [170/256,45/256], + g_hud_color, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [170,45], + "sprites/hud640_01.spr_0.tga", + [0,45/256], + [170/256,45/256], + g_hud_color, + a, + DRAWFLAG_ADDITIVE + ); + } +#endif +} + +weapon_t w_heaterpipe = +{ + .name = "heaterpipe", + .id = ITEM_HEATERPIPE, + .slot = 0, + .slot_pos = 0, + .draw = w_heaterpipe_draw, + .holster = w_heaterpipe_holster, + .primary = w_heaterpipe_primary, + .secondary = __NULL__, + .reload = __NULL__, + .release = w_heaterpipe_release, + .crosshair = __NULL__, + .precache = w_heaterpipe_precache, + .pickup = __NULL__, + .updateammo = w_heaterpipe_updateammo, + .wmodel = w_heaterpipe_wmodel, + .pmodel = __NULL__, + .deathmsg = __NULL__, + .aimanim = __NULL__, + .hudpic = w_heaterpipe_hudpic +}; + +/* entity definitions for pickups */ +#ifdef SERVER +void +weapon_heaterpipe(void) +{ + Weapons_InitItem(WEAPON_HEATERPIPE); +} +#endif diff --git a/src/shared/w_nailgun.qc b/src/shared/w_nailgun.qc new file mode 100644 index 0000000..bbe6d47 --- /dev/null +++ b/src/shared/w_nailgun.qc @@ -0,0 +1,196 @@ +/* + * 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 +{ + NAIL_IDLE1, + NAIL_IDLE2, + NAIL_UNUSED1, + NAIL_RELOAD, + NAIL_DRAW, + NAIL_SHOOT +}; + +void +w_nailgun_precache(void) +{ + precache_sound("weapons/brad_hit1.wav"); + precache_sound("weapons/brad_hit2.wav"); + precache_sound("weapons/nailgun.wav"); + + precache_model("models/nail.mdl"); + precache_model("models/v_nailgun.mdl"); + precache_model("models/w_nailgun.mdl"); +} + +void +w_nailgun_updateammo(player pl) +{ +#ifdef SERVER + Weapons_UpdateAmmo(pl, __NULL__, __NULL__, __NULL__); +#endif +} + +string +w_nailgun_wmodel(void) +{ + return "models/w_nailgun.mdl"; +} + +void +w_nailgun_draw(void) +{ + Weapons_SetModel("models/v_nailgun.mdl"); + Weapons_ViewAnimation(NAIL_DRAW); +} + +void +w_nailgun_primary(void) +{ + player pl = (player)self; + + if (pl.w_attack_next > 0.0) { + return; + } + +#ifdef SERVER + static void Nail_Touch(void) { + FX_Spark(self.origin, trace_plane_normal); + if (other.takedamage == DAMAGE_YES) { + Damage_Apply(other, self.owner, 15, WEAPON_NAILGUN, DMG_GENERIC); + if (random() < 0.5) { + Weapons_PlaySound(self, CHAN_WEAPON, "weapons/brad_hit1.wav", 1, ATTN_NORM); + } else { + Weapons_PlaySound(self, CHAN_WEAPON, "weapons/brad_hit2.wav", 1, ATTN_NORM); + } + } else { + Weapons_PlaySound(self, CHAN_WEAPON, "weapons/xbow_hit1.wav", 1, ATTN_NORM); + } + remove(self); + } + + Weapons_MakeVectors(); + entity nail = spawn(); + setmodel(nail, "models/nail.mdl"); + setorigin(nail, Weapons_GetCameraPos() + (v_forward * 16)); + nail.owner = self; + nail.velocity = v_forward * 2000; + nail.movetype = MOVETYPE_FLY; + nail.solid = SOLID_BBOX; + nail.angles = vectoangles(nail.velocity); + nail.avelocity[2] = 10; + nail.touch = Nail_Touch; + setsize(nail, [0,0,0], [0,0,0]); + + if (self.flags & FL_CROUCHING) + Animation_PlayerTopTemp(ANIM_SHOOT1HAND, 0.45f); + else + Animation_PlayerTopTemp(ANIM_CR_SHOOT1HAND, 0.45f); + + Weapons_PlaySound(pl, CHAN_WEAPON, "weapons/nailgun.wav", 1, ATTN_NORM); + +#else + + Weapons_ViewPunchAngle([-2,0,0]); + Weapons_ViewAnimation(NAIL_SHOOT); + + +#endif + + pl.w_attack_next = 0.1f; + pl.w_idle_next = 5.0f; +} + +void +w_nailgun_release(void) +{ + + player pl = (player)self; + if (pl.w_idle_next > 0) { + return; + } + + if (random() < 0.5) { + Weapons_ViewAnimation(NAIL_IDLE1); + } else { + Weapons_ViewAnimation(NAIL_IDLE2); + } + pl.w_idle_next = 10.0f; + +} + + +void +w_nailgun_hudpic(int selected, vector pos, float a) +{ +#ifdef CLIENT + if (selected) { + drawsubpic( + pos, + [170,45], + "sprites/hud640_01.spr_0.tga", + [0,45/256], + [170/256,45/256], + g_hud_color, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [170,45], + "sprites/hud640_01.spr_0.tga", + [0,45/256], + [170/256,45/256], + g_hud_color, + a, + DRAWFLAG_ADDITIVE + ); + } +#endif +} + +weapon_t w_nailgun = +{ + .name = "nailgun", + .id = ITEM_NAILGUN, + .slot = 1, + .slot_pos = 1, + .draw = w_nailgun_draw, + .holster = __NULL__, + .primary = w_nailgun_primary, + .secondary = __NULL__, + .reload = __NULL__, + .release = w_nailgun_release, + .crosshair = __NULL__, + .precache = w_nailgun_precache, + .pickup = __NULL__, + .updateammo = w_nailgun_updateammo, + .wmodel = w_nailgun_wmodel, + .pmodel = __NULL__, + .deathmsg = __NULL__, + .aimanim = __NULL__, + .hudpic = w_nailgun_hudpic +}; + +/* entity definitions for pickups */ +#ifdef SERVER +void +weapon_nailgun(void) +{ + Weapons_InitItem(WEAPON_NAILGUN); +} +#endif diff --git a/src/shared/w_pipebomb.qc b/src/shared/w_pipebomb.qc new file mode 100644 index 0000000..0057631 --- /dev/null +++ b/src/shared/w_pipebomb.qc @@ -0,0 +1,276 @@ +/* + * 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. + */ + +/*QUAKED weapon_pipebomb (0 0 1) (-16 -16 0) (16 16 32) +"model" "models/w_pipebomb.mdl" + +Poke646 (2001) ENTITY + +Pipebomb Weapon, literal copy of Half-Life's Satchel Weapon + +*/ + +enum +{ + SATCHEL_IDLE, + SATCHEL_FIDGET, + SATCHEL_DRAW, + SATCHEL_THROW +}; + +enum +{ + RADIO_IDLE, + RADIO_FIDGET, + RADIO_DRAW, + RADIO_USE, + RADIO_HOLSTER +}; + +void w_pipebomb_updateammo(player pl) +{ + w_satchel_updateammo(pl); +} +string w_pipebomb_wmodel(void) +{ + return "models/w_pipebomb.mdl"; +} +string w_pipebomb_pmodel(void) +{ + return "models/p_pipebomb.mdl"; +} +string w_pipebomb_deathmsg(void) +{ + return "%s blew up %s with a pipebomb."; +} +void w_pipebomb_precache(void) +{ +#ifdef SERVER + Sound_Precache("weapon_satchel.bounce"); +#endif + precache_model("models/w_pipebomb.mdl"); + precache_model("models/v_pipebomb.mdl"); + precache_model("models/v_pipebomb_watch.mdl"); + precache_model("models/p_pipebomb.mdl"); +} + +int w_pipebomb_pickup(int new, int startammo) +{ + return w_satchel_pickup(new, startammo); +} + +void w_pipebomb_draw(void) +{ + Weapons_SetModel("models/v_pipebomb.mdl"); + Weapons_ViewAnimation(SATCHEL_DRAW); +#ifdef SERVER + player pl = (player)self; + Weapons_UpdateAmmo(pl, pl.satchel_chg, pl.ammo_satchel, __NULL__); +#endif +} + +void w_pipebomb_holster(void) +{ + +} + +#ifdef SERVER +void s_pipebomb_drop(entity master, vector src, vector vel) +{ + static void s_pipebomb_touch(void) + { + if (other == world) + Sound_Play(self, CHAN_BODY, "weapon_satchel.bounce"); + } + entity satch; + satch = spawn(); + satch.owner = master; + satch.classname = "satchel"; + satch.movetype = MOVETYPE_BOUNCE; + satch.solid = SOLID_BBOX; + satch.frame = 1; + satch.gravity = 0.5f; + satch.friction = 0.8f; + satch.velocity = vel; + satch.avelocity = [0,400,0]; + satch.touch = s_pipebomb_touch; + setmodel(satch, "models/w_satchel.mdl"); + setsize(satch, [-4,-4,-4], [4,4,4]); + setorigin(satch, src); +} +void s_pipebomb_detonate(entity master) +{ + for (entity b = world; (b = find(b, ::classname, "satchel"));) { + if (b.owner == master) { + float dmg = Skill_GetValue("plr_satchel", 150); + FX_Explosion(b.origin); + Damage_Radius(b.origin, master, dmg, dmg * 2.5f, TRUE, WEAPON_SATCHEL); + sound(b, CHAN_WEAPON, sprintf("weapons/explode%d.wav", floor(random() * 2) + 3), 1, ATTN_NORM); + remove(b); + } + } +} +#endif + +void w_pipebomb_primary(void) +{ + player pl = (player)self; + + if (pl.w_attack_next) { + return; + } + + /* Ammo check */ +#ifdef CLIENT + if (pl.satchel_chg <= 0 && pl.ammo_satchel <= 0) { + return; + } +#else + if (pl.satchel_chg <= 0 && pl.ammo_satchel <= 0) { + return; + } +#endif + + if (pl.satchel_chg <= 0) { + Weapons_ViewAnimation(RADIO_DRAW); + } else { + Weapons_ViewAnimation(RADIO_USE); + } + +#ifdef SERVER + if (!pl.satchel_chg) { + vector throw; + + Weapons_MakeVectors(); + throw = pl.velocity + (v_forward * 274); + s_pipebomb_drop(self, pl.origin, throw); + pl.satchel_chg++; + pl.ammo_satchel--; + } else { + s_pipebomb_detonate(pl); + pl.satchel_chg = 0; + + if (pl.ammo_satchel <= 0) { + Weapons_RemoveItem(pl, WEAPON_SATCHEL); + } + } + Weapons_UpdateAmmo(pl, pl.satchel_chg, pl.ammo_satchel, __NULL__); +#else + setmodel(pSeat->m_eViewModel, "models/v_pipebomb_watch.mdl"); + pl.satchel_chg++; + pl.ammo_satchel--; +#endif + + pl.w_attack_next = 1.0f; + pl.w_idle_next = 1.0f; +} +void w_pipebomb_secondary(void) +{ + player pl = (player)self; + + if (pl.w_attack_next) { + return; + } + + /* Ammo check */ +#ifdef CLIENT + if (pl.ammo_satchel <= 0) { + return; + } +#else + if (pl.ammo_satchel <= 0) { + return; + } +#endif + +#ifdef SERVER + vector throw; + Weapons_MakeVectors(); + throw = pl.velocity + (v_forward * 274); + s_pipebomb_drop(self, pl.origin, throw); + pl.satchel_chg++; + pl.ammo_satchel--; + Weapons_UpdateAmmo(pl, pl.satchel_chg, pl.ammo_satchel, __NULL__); +#else + pl.satchel_chg++; + pl.ammo_satchel--; + setmodel(pSeat->m_eViewModel, "models/v_pipebomb_watch.mdl"); +#endif + + Weapons_ViewAnimation(RADIO_DRAW); + + pl.w_attack_next = 1.0f; + pl.w_idle_next = 2.5f; +} +void w_pipebomb_reload(void) +{ + +} +void w_pipebomb_release(void) +{ + w_satchel_release(); +} + +float w_pipebomb_aimanim(void) +{ + return w_satchel_aimanim(); +} + +void w_pipebomb_hud(void) +{ + w_satchel_holster(); +} + +void w_pipebomb_hudpic(int selected, vector pos, float a) +{ +#ifdef CLIENT + if (selected) { + drawsubpic(pos, [170,45], "sprites/640hud6.spr_0.tga", [0,45/256], [170/256,45/256], g_hud_color, a, DRAWFLAG_ADDITIVE); + } else { + drawsubpic(pos, [170,45], "sprites/640hud3.spr_0.tga", [0,45/256], [170/256,45/256], g_hud_color, a, DRAWFLAG_ADDITIVE); + } +#endif +} + +weapon_t w_pipebomb = +{ + .name = "pipebomb", + .id = ITEM_SATCHEL, + .slot = 4, + .slot_pos = 1, + .draw = w_pipebomb_draw, + .holster = w_pipebomb_holster, + .primary = w_pipebomb_primary, + .secondary = w_pipebomb_secondary, + .reload = __NULL__, + .release = w_pipebomb_release, + .crosshair = w_pipebomb_hud, + .precache = w_pipebomb_precache, + .pickup = w_pipebomb_pickup, + .updateammo = w_pipebomb_updateammo, + .wmodel = w_pipebomb_wmodel, + .pmodel = __NULL__, + .deathmsg = __NULL__, + .aimanim = w_pipebomb_aimanim, + .hudpic = w_pipebomb_hudpic +}; + +#ifdef SERVER +void weapon_pipebomb(void) { + Weapons_InitItem(WEAPON_SATCHEL); +} +#endif diff --git a/src/shared/w_shotgun.qc b/src/shared/w_shotgun.qc new file mode 100644 index 0000000..5d4e6af --- /dev/null +++ b/src/shared/w_shotgun.qc @@ -0,0 +1,280 @@ +/* + * 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 +{ + SHOTGUN_IDLE1, + SHOTGUN_FIRE1, + SHOTGUN_RELOAD, + SHOTGUN_PUMP, + SHOTGUN_START_RELOAD, + SHOTGUN_DRAW, + SHOTGUN_HOLSTER, + SHOTGUN_IDLE2 +}; + +enum +{ + SHOTTY_IDLE, + SHOTTY_RELOAD_START, + SHOTTY_RELOAD, + SHOTTY_RELOAD_END +}; + +void w_shotgun_precache(void) +{ + precache_model("models/v_shotgun.mdl"); + precache_model("models/w_shotgun.mdl"); + precache_model("models/p_shotgun.mdl"); + precache_sound("weapons/sbarrel1.wav"); + precache_sound("weapons/dbarrel1.wav"); + precache_sound("weapons/reload3.wav"); + precache_sound("weapons/scock1.wav"); +} +void w_shotgun_updateammo(player pl) +{ +#ifdef SERVER + Weapons_UpdateAmmo(pl, pl.shotgun_mag, pl.ammo_buckshot, __NULL__); +#endif +} +string w_shotgun_wmodel(void) +{ + return "models/w_shotgun.mdl"; +} +string w_shotgun_pmodel(void) +{ + return "models/p_shotgun.mdl"; +} +string w_shotgun_deathmsg(void) +{ + return ""; +} + +int w_shotgun_pickup(int new, int startammo) +{ +#ifdef SERVER + player pl = (player)self; + + if (new) { + pl.shotgun_mag = 8; + } else { + if (pl.ammo_buckshot < 125) { + pl.ammo_buckshot = bound(0, pl.ammo_buckshot + 8, 125); + } else { + return FALSE; + } + } +#endif + return TRUE; +} + +void w_shotgun_draw(void) +{ + Weapons_SetModel("models/v_shotgun.mdl"); + Weapons_ViewAnimation(SHOTGUN_DRAW); +#ifdef SERVER + player pl = (player)self; + Weapons_UpdateAmmo(pl, pl.shotgun_mag, pl.ammo_buckshot, __NULL__); +#endif +} + +void w_shotgun_holster(void) +{ + Weapons_ViewAnimation(SHOTGUN_HOLSTER); +} +void w_shotgun_primary(void) +{ + player pl = (player)self; + if (pl.w_attack_next) { + return; + } + + if (pl.a_ammo3 > SHOTTY_IDLE) { + return; + } + + /* Ammo check */ +#ifdef SERVER + if (pl.shotgun_mag <= 0) { + return; + } +#else + if (pl.a_ammo1 <= 0) { + return; + } +#endif + +#ifdef SERVER + /* Singleplayer is more accurate */ + if (cvar("sv_playerslots") == 1) { + TraceAttack_FireBullets(6, pl.origin + pl.view_ofs, 5, [0.08716,0.08716], WEAPON_SHOTGUN); + } else { + TraceAttack_FireBullets(4, pl.origin + pl.view_ofs, 5, [0.08716,0.04362], WEAPON_SHOTGUN); + } + Weapons_PlaySound(pl, CHAN_WEAPON, "weapons/dbarrel1.wav", 1, ATTN_NORM); + pl.shotgun_mag--; + Weapons_UpdateAmmo(pl, pl.shotgun_mag, pl.ammo_buckshot, __NULL__); +#else + View_SetMuzzleflash(MUZZLE_WEIRD); + Weapons_ViewPunchAngle([-5,0,0]); + pl.a_ammo1--; +#endif + Weapons_ViewAnimation(SHOTGUN_FIRE1); + + pl.w_attack_next = 1.1f; + pl.w_idle_next = 2.5f; +} +void w_shotgun_reload(void) +{ + player pl = (player)self; +#ifdef CLIENT + if (pl.a_ammo1 >= 8) { + return; + } + if (pl.a_ammo2 <= 0) { + return; + } +#else + if (pl.shotgun_mag >= 8) { + return; + } + if (pl.ammo_buckshot <= 0) { + return; + } +#endif + + if (pl.a_ammo3 > SHOTTY_IDLE) { + return; + } + pl.a_ammo3 = SHOTTY_RELOAD_START; + pl.w_idle_next = 0.0f; +} +void w_shotgun_release(void) +{ + player pl = (player)self; + + /* auto-reload if need be */ + if (pl.w_attack_next <= 0.0) + if (pl.a_ammo3 == SHOTTY_IDLE && pl.a_ammo1 == 0 && pl.a_ammo2 > 0) { + Weapons_Reload(); + return; + } + + if (pl.w_idle_next > 0.0) { + return; + } + + if (pl.a_ammo3 == SHOTTY_IDLE) { + int r = floor(random(0,2)); + switch (r) { + case 0: + Weapons_ViewAnimation(SHOTGUN_IDLE1); + break; + case 1: + Weapons_ViewAnimation(SHOTGUN_IDLE2); + break; + } + pl.w_idle_next = 15.0f; + } else if (pl.a_ammo3 == SHOTTY_RELOAD_START) { + Weapons_ViewAnimation(SHOTGUN_START_RELOAD); + pl.a_ammo3 = SHOTTY_RELOAD; + pl.w_idle_next = 0.65f; + } else if (pl.a_ammo3 == SHOTTY_RELOAD) { + Weapons_ViewAnimation(SHOTGUN_RELOAD); +#ifdef CLIENT + pl.a_ammo1++; + pl.a_ammo2--; + + if (pl.a_ammo2 <= 0 || pl.a_ammo1 >= 8) { + pl.a_ammo3 = SHOTTY_RELOAD_END; + } +#else + pl.shotgun_mag++; + pl.ammo_buckshot--; + Weapons_UpdateAmmo(pl, pl.shotgun_mag, pl.ammo_buckshot, pl.a_ammo3); + sound(pl, CHAN_WEAPON, "weapons/reload3.wav", 1.0, ATTN_NORM); + if (pl.ammo_buckshot <= 0 || pl.shotgun_mag >= 8) { + pl.a_ammo3 = SHOTTY_RELOAD_END; + } +#endif + pl.w_idle_next = 0.5f; + } else if (pl.a_ammo3 == SHOTTY_RELOAD_END) { + Weapons_ViewAnimation(SHOTGUN_PUMP); +#ifdef SERVER + sound(pl, CHAN_WEAPON, "weapons/scock1.wav", 1.0, ATTN_NORM); +#endif + pl.a_ammo3 = SHOTTY_IDLE; + pl.w_idle_next = 10.0f; + pl.w_attack_next = 0.5f; + } +} +void w_shotgun_crosshair(void) +{ +#ifdef CLIENT + static vector cross_pos; + cross_pos = (g_hudres / 2) + [-12,-12]; + drawsubpic(cross_pos, [24,24], "sprites/crosshairs.spr_0.tga", [48/128,24/128], [0.1875, 0.1875], [1,1,1], 1, DRAWFLAG_NORMAL); + HUD_DrawAmmo1(); + HUD_DrawAmmo2(); + vector aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42]; + drawsubpic(aicon_pos, [24,24], "sprites/640hud7.spr_0.tga", [72/256,72/128], [24/256, 24/128], g_hud_color, pSeat->m_flAmmo2Alpha, DRAWFLAG_ADDITIVE); +#endif +} + +float w_shotgun_aimanim(void) +{ + return self.flags & FL_CROUCHING ? ANIM_CR_AIMSHOTGUN : ANIM_AIMSHOTGUN; +} + +void w_shotgun_hudpic(int s, vector pos, float a) +{ +#ifdef CLIENT + if (s) { + drawsubpic(pos, [170,45], "sprites/640hud4.spr_0.tga", [0,180/256], [170/256,45/256], g_hud_color, a, DRAWFLAG_ADDITIVE); + } else { + drawsubpic(pos, [170,45], "sprites/640hud1.spr_0.tga", [0,180/256], [170/256,45/256], g_hud_color, a, DRAWFLAG_ADDITIVE); + } +#endif +} + +weapon_t w_shotgun = +{ + .name = "shotgun", + .id = ITEM_SHOTGUN, + .slot = 2, + .slot_pos = 1, + .draw = w_shotgun_draw, + .holster = w_shotgun_holster, + .primary = w_shotgun_primary, + .secondary = __NULL__, + .reload = w_shotgun_reload, + .release = w_shotgun_release, + .crosshair = __NULL__, + .precache = w_shotgun_precache, + .pickup = w_shotgun_pickup, + .updateammo = w_shotgun_updateammo, + .wmodel = w_shotgun_wmodel, + .pmodel = __NULL__, + .deathmsg = __NULL__, + .aimanim = __NULL__, + .hudpic = w_shotgun_hudpic +}; + +#ifdef SERVER +void weapon_shotgun(void) { + Weapons_InitItem(WEAPON_SHOTGUN); +} +#endif diff --git a/src/shared/w_xs.qc b/src/shared/w_xs.qc new file mode 100644 index 0000000..a8dacdc --- /dev/null +++ b/src/shared/w_xs.qc @@ -0,0 +1,153 @@ +/* + * 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 +{ + XS_IDLE1, + XS_IDLE2, + XS_IDLE3, + XS_SPINUP, + XS_SPIN, + XS_FIRE1, + XS_FIRE2, + XS_HOLSTER, + XS_DRAW, + XS_RELOAD +}; + +void +w_xs_precache(void) +{ + precache_sound("weapons/xs_moan1.wav"); + precache_sound("weapons/xs_moan2.wav"); + precache_sound("weapons/xs_moan3.wav"); + precache_sound("weapons/xs_reload.wav"); + precache_sound("weapons/xs_shot.wav"); + precache_sound("weapons/xs_windup.wav"); + + precache_model("models/v_xs.mdl"); + precache_model("models/w_xs.mdl"); +} + +void +w_xs_updateammo(player pl) +{ +#ifdef SERVER + Weapons_UpdateAmmo(pl, __NULL__, __NULL__, __NULL__); +#endif +} + +string +w_xs_wmodel(void) +{ + return "models/w_xs.mdl"; +} + +void +w_xs_draw(void) +{ + Weapons_SetModel("models/v_xs.mdl"); + Weapons_ViewAnimation(XS_DRAW); +} + +void +w_xs_holster(void) +{ + Weapons_ViewAnimation(XS_HOLSTER); +} + +void +w_xs_primary(void) +{ +/* TODO */ +} + +void +w_xs_secondary(void) +{ + +/* TODO Charge up, uses ammo similar to gauss */ + +} + + +void +w_xs_release(void) +{ + +} + +void +w_xs_hudpic(int selected, vector pos, float a) +{ +#ifdef CLIENT + if (selected) { + drawsubpic( + pos, + [170,45], + "sprites/hud640_01.spr_0.tga", + [0,45/256], + [170/256,45/256], + g_hud_color, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [170,45], + "sprites/hud640_01.spr_0.tga", + [0,45/256], + [170/256,45/256], + g_hud_color, + a, + DRAWFLAG_ADDITIVE + ); + } +#endif +} + +weapon_t w_xs = +{ + .name = "xs", + .id = ITEM_XS, + .slot = 3, + .slot_pos = 0, + .draw = w_xs_draw, + .holster = w_xs_holster, + .primary = w_xs_primary, + .secondary = w_xs_secondary, + .reload = __NULL__, + .release = w_xs_release, + .crosshair = __NULL__, + .precache = w_xs_precache, + .pickup = __NULL__, + .updateammo = w_xs_updateammo, + .wmodel = w_xs_wmodel, + .pmodel = __NULL__, + .deathmsg = __NULL__, + .aimanim = __NULL__, + .hudpic = w_xs_hudpic +}; + +/* entity definitions for pickups */ +#ifdef SERVER +void +weapon_xs(void) +{ + Weapons_InitItem(WEAPON_XS); +} +#endif diff --git a/src/shared/weapons.h b/src/shared/weapons.h new file mode 100644 index 0000000..a61bcc6 --- /dev/null +++ b/src/shared/weapons.h @@ -0,0 +1,34 @@ +/* + * 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_HEATERPIPE, + WEAPON_BRADNAILER, + WEAPON_NAILGUN, + WEAPON_SHOTGUN, + WEAPON_CMLWBR, + WEAPON_XS, + WEAPON_SATCHEL +}; + +#define MAX_A_NAIL 250 +#define MAX_A_BUCKSHOT 125 +#define MAX_A_BOLT 50 +#define MAX_A_XENCANDY 15 +#define MAX_A_SATCHEL 5 diff --git a/src/shared/weapons.qc b/src/shared/weapons.qc new file mode 100644 index 0000000..df5ea85 --- /dev/null +++ b/src/shared/weapons.qc @@ -0,0 +1,27 @@ +/* + * 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_heaterpipe, + w_bradnailer, + w_nailgun, + w_shotgun, + w_cmlwbr, + w_xs, + w_pipebomb +};