commit 5a93a6e9e71485346e098214147b5c271f4c9f77 Author: Marco Hladik Date: Mon Mar 8 11:47:30 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..515791a --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +# FreeSci +Clean-room reimplementation of Gunman Chronicles in QuakeC. + +![Preview 1](img/preview1.jpg) +![Preview 2](img/preview2.jpg) +![Preview 3](img/preview3.jpg) +![Preview 4](img/preview4.jpg) + +## Building +Clone the repository into the Nuclide-SDK: + +> git clone REPOURL rewolf + +then either run Nuclide's ./build_game.sh shell script, or issue 'make' inside +./rewolf/src! + +Obviously make sure that Nuclide has fteqw and fteqcc set-up for building. + +## Community +Join us on #halflife or #gunman via irc.frag-net.com and chat. + +## License +ISC License + +Copyright (c) 2016-2021 Marco Hladik + +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..e6ecf7e 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..f1e6361 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..3503ac0 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..fe27ede 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/hud_weaponselect.qc b/src/client/hud_weaponselect.qc new file mode 100644 index 0000000..403e04e --- /dev/null +++ b/src/client/hud_weaponselect.qc @@ -0,0 +1,235 @@ +/* + * 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. + */ + +vector g_vecHUDNums[8] = +{ + [168 / 255,72 / 128], + [188 / 255,72 / 128], + [208 / 255,72 / 128], + [168 / 255,92 / 128], + [188 / 255,92 / 128], + [228 / 255,72 / 128], + [228 / 255,92 / 128], + [208 / 255,92 / 128], +}; + +void +HUD_DrawWeaponSelect_Forward(void) +{ + player pl = (player)pSeat->m_ePlayer; + + if (!pl.activeweapon) { + return; + } + + if (pSeat->m_flHUDWeaponSelectTime < time) { + pSeat->m_iHUDWeaponSelected = pl.activeweapon; + sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_hudon.wav", 0.5, ATTN_NONE); + } else { + sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_moveselect.wav", 0.5, ATTN_NONE); + pSeat->m_iHUDWeaponSelected--; + if (pSeat->m_iHUDWeaponSelected <= 0) { + pSeat->m_iHUDWeaponSelected = g_weapons.length - 1; + } + } + + pSeat->m_flHUDWeaponSelectTime = time + 3; + + /* compiler bug */ + if (pl.g_items & g_weapons[pSeat->m_iHUDWeaponSelected].id) { + } else { + HUD_DrawWeaponSelect_Forward(); + } +} + +void +HUD_DrawWeaponSelect_Back(void) +{ + player pl = (player)pSeat->m_ePlayer; + + if (!pl.activeweapon) { + return; + } + + if (pSeat->m_flHUDWeaponSelectTime < time) { + pSeat->m_iHUDWeaponSelected = pl.activeweapon; + sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_hudon.wav", 0.5, ATTN_NONE); + } else { + sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_moveselect.wav", 0.5, ATTN_NONE); + pSeat->m_iHUDWeaponSelected++; + if (pSeat->m_iHUDWeaponSelected >= g_weapons.length) { + pSeat->m_iHUDWeaponSelected = 1; + } + } + + pSeat->m_flHUDWeaponSelectTime = time + 3; + + /* compiler bug */ + if (pl.g_items & g_weapons[pSeat->m_iHUDWeaponSelected].id) { + } else { + HUD_DrawWeaponSelect_Back(); + } +} + +void +HUD_DrawWeaponSelect_Trigger(void) +{ + player pl = (player)pSeat->m_ePlayer; + pl.activeweapon = pSeat->m_iHUDWeaponSelected; + sendevent("PlayerSwitchWeapon", "i", pSeat->m_iHUDWeaponSelected); + sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_select.wav", 0.5f, ATTN_NONE); + pSeat->m_iHUDWeaponSelected = pSeat->m_flHUDWeaponSelectTime = 0; +} + +void +HUD_DrawWeaponSelect_Last(void) +{ + player pl = (player)pSeat->m_ePlayer; + if (pl.g_items & g_weapons[pSeat->m_iOldWeapon].id) { + pl.activeweapon = pSeat->m_iOldWeapon; + sendevent("PlayerSwitchWeapon", "i", pSeat->m_iOldWeapon); + } +} + +void +HUD_DrawWeaponSelect_Num(vector vecPos, float fValue) +{ + drawsubpic(vecPos, [20,20], "sprites/640hud7.spr_0.tga", g_vecHUDNums[fValue], [20/255, 20/128], g_hud_color, 1, DRAWFLAG_ADDITIVE); +} + +int +HUD_InSlotPos(int slot, int pos) +{ + player pl = (player)pSeat->m_ePlayer; + for (int i = 1; i < g_weapons.length; i++) { + if (g_weapons[i].slot == slot && g_weapons[i].slot_pos == pos) { + if (pl.g_items & g_weapons[i].id) { + return i; + } else { + return -1; + } + } + } + return -1; +} + +void +HUD_SlotSelect(int slot) +{ + player pl = (player)pSeat->m_ePlayer; + int curslot = g_weapons[pSeat->m_iHUDWeaponSelected].slot; + int i; + + if (g_textmenu != "") { + Textmenu_Input(slot); + return; + } + + /* hack to see if we have ANY weapons at all. */ + if (!pl.activeweapon) { + return; + } + + if (pSeat->m_flHUDWeaponSelectTime < time) { + sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_hudon.wav", 0.5, ATTN_NONE); + } else { + sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_moveselect.wav", 0.5, ATTN_NONE); + } + + /* weren't in that slot? select the first one then */ + if (curslot != slot) { + for (i = 1; i < g_weapons.length; i++) { + if (g_weapons[i].slot == slot && pl.g_items & g_weapons[i].id) { + pSeat->m_iHUDWeaponSelected = i; + pSeat->m_flHUDWeaponSelectTime = time + 3; + break; + } + } + } else { + int first = -1; + for (i = 1; i < g_weapons.length; i++) { + if (g_weapons[i].slot == slot && pl.g_items & g_weapons[i].id) { + if (i < pSeat->m_iHUDWeaponSelected && first == -1) { + first = i; + } else if (i > pSeat->m_iHUDWeaponSelected) { + first = -1; + pSeat->m_iHUDWeaponSelected = i; + pSeat->m_flHUDWeaponSelectTime = time + 3; + break; + } + } + } + + if (first > 0) { + pSeat->m_iHUDWeaponSelected = first; + pSeat->m_flHUDWeaponSelectTime = time + 3; + } + } +} + +void +HUD_DrawWeaponSelect(void) +{ + player pl = (player)pSeat->m_ePlayer; + if (!pl.activeweapon) { + return; + } + if (pSeat->m_flHUDWeaponSelectTime < time) { + if (pSeat->m_iHUDWeaponSelected) { + sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_hudoff.wav", 0.5, ATTN_NONE); + pSeat->m_iHUDWeaponSelected = 0; + } + return; + } + + vector vecPos = g_hudmins + [16,16]; + + int b; + int wantslot = g_weapons[pSeat->m_iHUDWeaponSelected].slot; + int wantpos = g_weapons[pSeat->m_iHUDWeaponSelected].slot_pos; + for (int i = 0; i < 7; i++) { + int slot_selected = 0; + vecPos[1] = g_hudmins[1] + 16; + HUD_DrawWeaponSelect_Num(vecPos, i); + vecPos[1] += 20; + for (int x = 0; x < 32; x++) { + if (i == wantslot) { + slot_selected = TRUE; + if (x == wantpos) { + // Selected Sprite + Weapons_HUDPic(pSeat->m_iHUDWeaponSelected, 1, vecPos, 1.0f); + drawsubpic(vecPos, [170,45], "sprites/640hud3.spr_0.tga", + [0,180/256], [170/256,45/256], + g_hud_color, 1, DRAWFLAG_ADDITIVE); + vecPos[1] += 50; + } else if ((b=HUD_InSlotPos(i, x)) != -1) { + // Unselected Sprite + Weapons_HUDPic(b, 0, vecPos, 1.0f); + vecPos[1] += 50; + } + } else if (HUD_InSlotPos(i, x) != -1) { + HUD_DrawWeaponSelect_Num(vecPos, 7); + vecPos[1] += 25; + } + } + + if (slot_selected == TRUE) { + vecPos[0] += 175; + } else { + vecPos[0] += 25; + } + } +} diff --git a/src/client/init.qc b/src/client/init.qc new file mode 100644 index 0000000..f5838b5 --- /dev/null +++ b/src/client/init.qc @@ -0,0 +1,67 @@ +/* + * 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/640hudof01.spr"); + precache_model("sprites/640hudof02.spr"); + precache_model("sprites/640hudof03.spr"); + precache_model("sprites/640hudof04.spr"); + precache_model("sprites/640hudof05.spr"); + precache_model("sprites/640hudof06.spr"); + precache_model("sprites/ofch1.spr"); + precache_model("sprites/ofch2.spr"); + precache_model("sprites/320hudof01.spr"); + + BEAM_TRIPMINE = particleeffectnum("weapon_tripmine.beam"); +} diff --git a/src/client/progs.src b/src/client/progs.src new file mode 100644 index 0000000..eccfc07 --- /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 GEARBOX +#define GS_RENDERFX +#define CLASSIC_VGUI + +#includelist +../../../src/shared/fteextensions.qc +../../../src/shared/defs.h +../../../valve/src/client/defs.h +../../../src/client/defs.h + +../../../src/vgui/include.src + +../../../src/gs-entbase/client.src +../../../src/gs-entbase/shared.src +../shared/include.src + +../../../valve/src/client/predict.qc +init.qc +../../../valve/src/client/player.qc +../../../valve/src/client/entities.qc +../../../valve/src/client/cmds.qc +../../../valve/src/client/game_event.qc +../../../valve/src/client/view.qc +../../../valve/src/client/obituary.qc +../../../valve/src/client/hud.qc +hud_weaponselect.qc +../../../valve/src/client/scoreboard.qc +../../../valve/src/client/input.qc +../../../base/src/client/modelevent.qc + +../../../src/client/include.src +../../../src/shared/include.src +#endlist 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_op4.qc b/src/server/ammo_op4.qc new file mode 100644 index 0000000..0829deb --- /dev/null +++ b/src/server/ammo_op4.qc @@ -0,0 +1,176 @@ +/* + * 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. + */ + +/*QUAKED ammo_556 (0 0 0.8) (-16 -16 0) (16 16 32) + +HALF-LIFE: OPPOSING FORCE (1999) ENTITY + +Ammo for the M249. +A single ammo_556 will provide 50 bullets. + +*/ +class ammo_556:item_ammo +{ + void(void) ammo_556; + virtual void(void) touch; +}; + +void +ammo_556::ammo_556(void) +{ + model = "models/w_saw_clip.mdl"; + item_ammo::item_ammo(); +} +void +ammo_556::touch(void) +{ + if (other.classname == "player") { + player pl = (player)other; + if (pl.ammo_556 < 200) { + pl.ammo_556 = bound(0, pl.ammo_556 + 50, 200); + item_ammo::touch(); + } + } +} + +/*QUAKED ammo_762 (0 0 0.8) (-16 -16 0) (16 16 32) + +HALF-LIFE: OPPOSING FORCE (1999) ENTITY + +Ammo for the M-40A1 Sniper. +A single ammo_762 will provide 5 bullets. + +*/ +class ammo_762:item_ammo +{ + void(void) ammo_762; + virtual void(void) touch; +}; + +void +ammo_762::ammo_762(void) +{ + model = "models/w_m40a1clip.mdl"; + item_ammo::item_ammo(); +} +void +ammo_762::touch(void) +{ + if (other.classname == "player") { + player pl = (player)other; + if (pl.ammo_762 < 15) { + pl.ammo_762 = bound(0, pl.ammo_762 + 5, 15); + item_ammo::touch(); + } + } +} + +/*QUAKED ammo_spore (0 0 0.8) (-16 -16 0) (16 16 32) + +HALF-LIFE: OPPOSING FORCE (1999) ENTITY + +Ammo for the Spore Launcher. +A single ammo_spore will provide 1 spore. +The angle key refers to the direction the entity will fire (?) +when shot. The model itself uses decal-like logic to determine +the direction the model is aiming. + +*/ +class ammo_spore:item_ammo +{ + void(void) ammo_spore; + virtual void(void) touch; + virtual void(void) Respawn; + virtual void(void) Death; +}; + +void +ammo_spore::ammo_spore(void) +{ + movetype = MOVETYPE_NONE; + model = "models/spore_ammo.mdl"; + item_ammo::item_ammo(); +} + +void +ammo_spore::Death(void) +{ + makevectors(m_oldAngle); + Sporelauncher_AltFire(this, origin, v_forward); + frame = 2; + m_iBody = 0; + solid = SOLID_NOT; + think = Respawn; + nextthink = time + 10.0f; +} + +void ammo_spore::Respawn(void) +{ + frame = 1; + m_iBody = 2; + movetype = MOVETYPE_NONE; + takedamage = DAMAGE_YES; + health = 1; + + if (m_oldModel) { + SetModel(m_oldModel); + } + + solid = SOLID_NOT; + setsize(this, [0,0,0], [0,0,0]); + SetOrigin(m_oldOrigin); + + decal_pickwall(this, m_oldOrigin); + + /* we never hit any wall. */ + if (g_tracedDecal.fraction == 1.0f) { + print(sprintf("^xFA0Warning^7: ammo_spore tracing failed at %v\n", origin)); + return; + } + + origin = g_tracedDecal.endpos; + makevectors(vectoangles(g_tracedDecal.endpos - origin)); + vector cpl = v_forward - (v_forward * g_tracedDecal.normal) * g_tracedDecal.normal; + + if (g_tracedDecal.normal[2] == 0) { + cpl = [0, 0, 1]; + } + angles = vectoangles(cpl, g_tracedDecal.normal); + + solid = SOLID_BBOX; + setsize(this, [-16,-16,-16], [16,16,16]); + think = __NULL__; + nextthink = -1; +} + +void +ammo_spore::touch(void) +{ + if not (other.flags & FL_CLIENT) { + return; + } + + player pl = (player)other; + if (pl.ammo_spore < 20) { + pl.ammo_spore = bound(0, pl.ammo_spore + 1, 20); + Weapons_RefreshAmmo(pl); + Logging_Pickup(other, this, __NULL__); + frame = 2; + m_iBody = 0; + think = Respawn; + nextthink = time + 10.0f; + } +} diff --git a/src/server/defs.h b/src/server/defs.h new file mode 100644 index 0000000..3a04a3b --- /dev/null +++ b/src/server/defs.h @@ -0,0 +1,19 @@ +/* + * 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. + */ + +#include "../../../valve/src/server/gamerules.h" +#include "gamerules_ctf.h" +#include "../../../valve/src/server/items.h" diff --git a/src/server/gamerules.qc b/src/server/gamerules.qc new file mode 100644 index 0000000..30ae7cd --- /dev/null +++ b/src/server/gamerules.qc @@ -0,0 +1,168 @@ +/* + * 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. + */ + +var int autocvar_sv_playerkeepalive = TRUE; + +/* we check what fields have changed over the course of the frame and network + * only the ones that have actually changed */ +void +HLGameRules::PlayerPostFrame(base_player pp) +{ + Animation_PlayerUpdate(); +} + +void +HLGameRules::LevelNewParms(void) +{ + parm1 = parm2 = parm3 = parm4 = parm5 = parm6 = parm7 = + parm8 = parm9 = parm10 = parm11 = parm12 = parm13 = parm14 = + parm15 = parm16 = parm17 = parm18 = parm19 = parm20 = parm21 = + parm22 = parm23 = parm24 = parm25 = parm26 = parm27 = parm28 = + parm29 = parm30 = 0; + parm64 = FL_CLIENT; +} + +void +HLGameRules::LevelDecodeParms(base_player pp) +{ + player pl = (player)pp; + g_landmarkpos[0] = parm1; + g_landmarkpos[1] = parm2; + g_landmarkpos[2] = parm3; + pl.angles[0] = parm4; + pl.angles[1] = parm5; + pl.angles[2] = parm6; + pl.velocity[0] = parm7; + pl.velocity[1] = parm8; + pl.velocity[2] = parm9; + pl.g_items = parm10; + pl.activeweapon = parm11; + pl.flags = parm64; + + pl.ammo_9mm = parm12; + pl.ammo_357 = parm13; + pl.ammo_buckshot = parm14; + pl.ammo_m203_grenade = parm15; + pl.ammo_bolt = parm16; + pl.ammo_rocket = parm17; + pl.ammo_uranium = parm18; + pl.ammo_handgrenade = parm19; + pl.ammo_satchel = parm20; + pl.ammo_tripmine = parm21; + pl.ammo_snark = parm22; + pl.ammo_hornet = parm23; + + pl.glock_mag = parm24; + pl.mp5_mag = parm25; + pl.python_mag = parm26; + pl.shotgun_mag = parm27; + pl.crossbow_mag = parm28; + pl.rpg_mag = parm29; + pl.satchel_chg = parm30; + + /* near gearbox additions */ + pl.ammo_556 = parm31; + pl.ammo_762 = parm32; + pl.ammo_spore = parm33; + pl.ammo_shock = parm34; + pl.ammo_penguin = parm35; + pl.eagle_mag = parm36; + pl.sniper_mag = parm37; + pl.m249_mag = parm38; + pl.sporelauncher_mag = parm39; + + if (pl.flags & FL_CROUCHING) { + setsize(pl, VEC_CHULL_MIN, VEC_CHULL_MAX); + } else { + setsize(pl, VEC_HULL_MIN, VEC_HULL_MAX); + } +} + +void +HLGameRules::LevelChangeParms(base_player pp) +{ + player pl = (player)pp; + parm1 = g_landmarkpos[0]; + parm2 = g_landmarkpos[1]; + parm3 = g_landmarkpos[2]; + parm4 = pl.angles[0]; + parm5 = pl.angles[1]; + parm6 = pl.angles[2]; + parm7 = pl.velocity[0]; + parm8 = pl.velocity[1]; + parm9 = pl.velocity[2]; + parm64 = pl.flags; + parm10 = pl.g_items; + parm11 = pl.activeweapon; + parm12 = pl.ammo_9mm; + parm13 = pl.ammo_357; + parm14 = pl.ammo_buckshot; + parm15 = pl.ammo_m203_grenade; + parm16 = pl.ammo_bolt; + parm17 = pl.ammo_rocket; + parm18 = pl.ammo_uranium; + parm19 = pl.ammo_handgrenade; + parm20 = pl.ammo_satchel; + parm21 = pl.ammo_tripmine; + parm22 = pl.ammo_snark; + parm23 = pl.ammo_hornet; + parm24 = pl.glock_mag; + parm25 = pl.mp5_mag; + parm26 = pl.python_mag; + parm27 = pl.shotgun_mag; + parm28 = pl.crossbow_mag; + parm29 = pl.rpg_mag; + parm30 = pl.satchel_chg; + + /* near gearbox additions */ + parm31 = pl.ammo_556; + parm32 = pl.ammo_762; + parm33 = pl.ammo_spore; + parm34 = pl.ammo_shock; + parm35 = pl.ammo_penguin; + parm36 = pl.eagle_mag; + parm37 = pl.sniper_mag; + parm38 = pl.m249_mag; + parm39 = pl.sporelauncher_mag; +} + +void +HLGameRules::PlayerConnect(base_player pl) +{ + if (Plugin_PlayerConnect(pl) == FALSE) + bprint(PRINT_HIGH, sprintf("%s connected\n", pl.netname)); +} + +void +HLGameRules::PlayerDisconnect(base_player pl) +{ + bprint(PRINT_HIGH, sprintf("%s disconnected\n", pl.netname)); + + /* Make this unusable */ + pl.solid = SOLID_NOT; + pl.movetype = MOVETYPE_NONE; + pl.modelindex = 0; + pl.health = 0; + pl.takedamage = 0; + pl.SendFlags = PLAYER_MODELINDEX; +} + +void +HLGameRules::PlayerKill(base_player pp) +{ + player pl = (player)pp; + Damage_Apply(pl, pl, pl.health, WEAPON_NONE, DMG_SKIP_ARMOR); +} diff --git a/src/server/gamerules_ctf.h b/src/server/gamerules_ctf.h new file mode 100644 index 0000000..d12c87f --- /dev/null +++ b/src/server/gamerules_ctf.h @@ -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. + */ + +class OP4CTFRules:HLGameRules +{ + int m_iIntermission; + int m_iIntermissionTime; + + virtual void(void) FrameStart; + + /* client */ + virtual void(base_player) PlayerSpawn; + virtual void(base_player) PlayerDeath; +}; diff --git a/src/server/gamerules_ctf.qc b/src/server/gamerules_ctf.qc new file mode 100644 index 0000000..c606cb1 --- /dev/null +++ b/src/server/gamerules_ctf.qc @@ -0,0 +1,145 @@ +/* + * 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 +OP4CTFRules::FrameStart(void) +{ + if (cvar("mp_timelimit")) + if (time >= (cvar("mp_timelimit") * 60)) { + IntermissionStart(); + } +} + +void +OP4CTFRules::PlayerDeath(base_player pp) +{ + player pl = (player)pp; + + /* obituary networking */ + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, EV_OBITUARY); + if (g_dmg_eAttacker.netname) + WriteString(MSG_MULTICAST, g_dmg_eAttacker.netname); + else + WriteString(MSG_MULTICAST, g_dmg_eAttacker.classname); + WriteString(MSG_MULTICAST, pl.netname); + WriteByte(MSG_MULTICAST, g_dmg_iWeapon); + WriteByte(MSG_MULTICAST, 0); + msg_entity = world; + multicast([0,0,0], MULTICAST_ALL); + + /* death-counter */ + pl.deaths++; + forceinfokey(pl, "*deaths", ftos(pl.deaths)); + + /* update score-counter */ + if (pl.flags & FL_CLIENT || pl.flags & FL_MONSTER) + if (g_dmg_eAttacker.flags & FL_CLIENT) { + if (pl == g_dmg_eAttacker) + g_dmg_eAttacker.frags--; + else + g_dmg_eAttacker.frags++; + } + + /* in DM we only care about the frags */ + if (cvar("mp_fraglimit")) + if (g_dmg_eAttacker.frags >= cvar("mp_fraglimit")) { + IntermissionStart(); + } + + weaponbox_spawn(pl); + pl.movetype = MOVETYPE_NONE; + pl.solid = SOLID_NOT; + pl.takedamage = DAMAGE_NO; + pl.gflags &= ~GF_FLASHLIGHT; + pl.armor = pl.activeweapon = pl.g_items = 0; + + pl.think = PutClientInServer; + pl.nextthink = time + 4.0f; + Sound_Play(pl, CHAN_AUTO, "player.die"); + + if (pl.health < -50) { + pl.health = 0; + FX_GibHuman(pl.origin); + return; + } + + pl.health = 0; + + /* Let's handle corpses on the clientside */ + entity corpse = spawn(); + setorigin(corpse, pl.origin + [0,0,32]); + setmodel(corpse, pl.model); + setsize(corpse, VEC_HULL_MIN, VEC_HULL_MAX); + corpse.movetype = MOVETYPE_TOSS; + corpse.solid = SOLID_TRIGGER; + corpse.modelindex = pl.modelindex; + corpse.frame = ANIM_DIESIMPLE; + corpse.angles = pl.angles; + corpse.velocity = pl.velocity; +} + +void +OP4CTFRules::PlayerSpawn(base_player pp) +{ + player pl = (player)pp; + + /* this is where the mods want to deviate */ + entity spot; + + pl.classname = "player"; + pl.health = pl.max_health = 100; + pl.takedamage = DAMAGE_YES; + pl.solid = SOLID_SLIDEBOX; + pl.movetype = MOVETYPE_WALK; + pl.flags = FL_CLIENT; + pl.viewzoom = 1.0; + pl.model = "models/player.mdl"; + string mymodel = infokey(pl, "model"); + + if (mymodel) { + mymodel = sprintf("models/player/%s/%s.mdl", mymodel, mymodel); + if (whichpack(mymodel)) { + pl.model = mymodel; + } + } + setmodel(pl, pl.model); + + setsize(pl, VEC_HULL_MIN, VEC_HULL_MAX); + pl.view_ofs = VEC_PLAYER_VIEWPOS; + pl.velocity = [0,0,0]; + pl.gravity = __NULL__; + pl.frame = 1; + pl.SendFlags = UPDATE_ALL; + pl.customphysics = Empty; + pl.iBleeds = TRUE; + forceinfokey(pl, "*spec", "0"); + forceinfokey(pl, "*deaths", ftos(pl.deaths)); + + LevelNewParms(); + LevelDecodeParms(pl); + pl.g_items = ITEM_CROWBAR | ITEM_GLOCK | ITEM_SUIT; + pl.activeweapon = WEAPON_GLOCK; + pl.glock_mag = 18; + pl.ammo_9mm = 44; + + spot = Spawn_SelectRandom("info_player_deathmatch"); + setorigin(pl, spot.origin); + pl.angles = spot.angles; + Weapons_RefreshAmmo(pl); + + Client_FixAngle(pl, pl.angles); +} diff --git a/src/server/input.qc b/src/server/input.qc new file mode 100644 index 0000000..486d73d --- /dev/null +++ b/src/server/input.qc @@ -0,0 +1,83 @@ +/* + * 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; + pl.g_items |= ITEM_SUIT; + Weapons_AddItem(pl, WEAPON_CROWBAR, -1); + Weapons_AddItem(pl, WEAPON_GLOCK, -1); + Weapons_AddItem(pl, WEAPON_PYTHON, -1); + Weapons_AddItem(pl, WEAPON_MP5, -1); + Weapons_AddItem(pl, WEAPON_SHOTGUN, -1); + Weapons_AddItem(pl, WEAPON_CROSSBOW, -1); + Weapons_AddItem(pl, WEAPON_RPG, -1); + Weapons_AddItem(pl, WEAPON_GAUSS, -1); + Weapons_AddItem(pl, WEAPON_EGON, -1); + Weapons_AddItem(pl, WEAPON_HORNETGUN, -1); + Weapons_AddItem(pl, WEAPON_HANDGRENADE, -1); + Weapons_AddItem(pl, WEAPON_SATCHEL, -1); + Weapons_AddItem(pl, WEAPON_TRIPMINE, -1); + Weapons_AddItem(pl, WEAPON_SNARK, -1); + Weapons_AddItem(pl, WEAPON_PENGUIN, -1); + Weapons_AddItem(pl, WEAPON_PIPEWRENCH, -1); + Weapons_AddItem(pl, WEAPON_KNIFE, -1); + Weapons_AddItem(pl, WEAPON_GRAPPLE, -1); + Weapons_AddItem(pl, WEAPON_EAGLE, -1); + Weapons_AddItem(pl, WEAPON_M249, -1); + Weapons_AddItem(pl, WEAPON_SHOCKRIFLE, -1); + Weapons_AddItem(pl, WEAPON_SPORELAUNCHER, -1); + Weapons_AddItem(pl, WEAPON_SNIPERRIFLE, -1); + Weapons_AddItem(pl, WEAPON_DISPLACER, -1); + } + + if (self.impulse == 102) { + // Respawn all the entities + for (entity a = world; (a = findfloat(a, g::identity, 1));) { + CBaseEntity caw = (CBaseEntity)a; + caw.Respawn(); + } + bprint(PRINT_HIGH, "Respawning all map entities...\n"); + } + } + + self.impulse = 0; +} diff --git a/src/server/monster_drillsergeant.qc b/src/server/monster_drillsergeant.qc new file mode 100644 index 0000000..014b42b --- /dev/null +++ b/src/server/monster_drillsergeant.qc @@ -0,0 +1,94 @@ +/* + * 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. + */ + +/*QUAKED monster_drillsergeant (0 0.8 0.8) (-16 -16 0) (16 16 72) + +HALF-LIFE: OPPOSING FORCE (1999) ENTITY + +Drill Sergeant +...from the Opposing Force Boot-Camp Training + +*/ + +enum +{ + DRILL_IDLE1, + DRILL_IDLE2, + DRILL_IDLE3, + DRILL_WALK, + DRILL_RUN, + DRILL_TURNLEFT, + DRILL_TURNRIGHT, + DRILL_FLINCH, + DRILL_DIESIMPLE, + DRILL_DIEBACKWARD, + DRILL_DIEFORWARD, + DRILL_DEADONSIDE, + DRILL_DEADONSTOMACH, + DRILL_HANDSONHIPS, + DRILL_POINT1, + DRILL_POINT2, + DRILL_BARK, + DRILL_YELLHARD, + DRILL_BARKHARD, + DRILL_WHISTLE, + DRILL_BINOCULARS +}; + +class monster_drillsergeant:CBaseNPC +{ + void(void) monster_drillsergeant; + virtual void(void) Respawn; + virtual int(void) AnimIdle; + virtual int(void) AnimWalk; + virtual int(void) AnimRun; +}; + +int +monster_drillsergeant::AnimIdle(void) +{ + return DRILL_IDLE1; +} + +int +monster_drillsergeant::AnimWalk(void) +{ + return DRILL_WALK; +} + +int +monster_drillsergeant::AnimRun(void) +{ + return DRILL_RUN; +} + +void +monster_drillsergeant::Respawn(void) +{ + CBaseNPC::Respawn(); + takedamage = DAMAGE_NO; + iBleeds = FALSE; +} + +void +monster_drillsergeant::monster_drillsergeant(void) +{ + netname = "Drill Sergeant"; + model = "models/drill.mdl"; + base_mins = [-16,-16,0]; + base_maxs = [16,16,72]; + CBaseNPC::CBaseNPC(); +} diff --git a/src/server/monster_recruit.qc b/src/server/monster_recruit.qc new file mode 100644 index 0000000..e73a460 --- /dev/null +++ b/src/server/monster_recruit.qc @@ -0,0 +1,81 @@ +/* + * 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. + */ + +/*QUAKED monster_recruit (0 0.8 0.8) (-16 -16 0) (16 16 72) + +HALF-LIFE: OPPOSING FORCE (1999) ENTITY + +Recruit +...from the Opposing Force Boot-Camp Training + +*/ + +enum +{ + RECRUIT_IDLE, + RECRUIT_WALK, + RECRUIT_RUN, + RECRUIT_TURNLEFT, + RECRUIT_TURNRIGHT, + RECRUIT_PUSHUPS, + RECRUIT_JUMPINJACK, + RECRUIT_SALUTE +}; + +class monster_recruit:CBaseNPC +{ + void(void) monster_recruit; + virtual void(void) Respawn; + virtual int(void) AnimIdle; + virtual int(void) AnimWalk; + virtual int(void) AnimRun; +}; + +int +monster_recruit::AnimIdle(void) +{ + return RECRUIT_IDLE; +} + +int +monster_recruit::AnimWalk(void) +{ + return RECRUIT_WALK; +} + +int +monster_recruit::AnimRun(void) +{ + return RECRUIT_RUN; +} + +void +monster_recruit::Respawn(void) +{ + CBaseNPC::Respawn(); + takedamage = DAMAGE_NO; + iBleeds = FALSE; +} + +void +monster_recruit::monster_recruit(void) +{ + netname = "Recruit"; + model = "models/recruit.mdl"; + base_mins = [-16,-16,0]; + base_maxs = [16,16,72]; + CBaseNPC::CBaseNPC(); +} diff --git a/src/server/progs.src b/src/server/progs.src new file mode 100755 index 0000000..9d20767 --- /dev/null +++ b/src/server/progs.src @@ -0,0 +1,95 @@ +#pragma target fte +#pragma progs_dat "../../progs.dat" + +#define QWSSQC +#define SERVER +#define VALVE +#define GEARBOX +#define GS_RENDERFX + +#includelist +../../../src/shared/fteextensions.qc +../../../src/gs-entbase/server/defs.h +../../../src/shared/defs.h +../../../src/server/defs.h + +../../../src/gs-entbase/server.src +../../../src/gs-entbase/shared.src +../shared/include.src + +defs.h + +../../../valve/src/server/monster_apache.qc +../../../valve/src/server/monster_alien_controller.qc +../../../valve/src/server/monster_alien_grunt.qc +../../../valve/src/server/monster_alien_slave.qc +../../../valve/src/server/monster_barnacle.qc +../../../valve/src/server/monster_barney.qc +../../../valve/src/server/monster_barney_dead.qc +../../../valve/src/server/monster_bigmomma.qc +../../../valve/src/server/monster_bloater.qc +../../../valve/src/server/monster_bullchicken.qc +../../../valve/src/server/monster_cockroach.qc +../../../valve/src/server/monster_flyer_flock.qc +../../../valve/src/server/monster_gargantua.qc +../../../valve/src/server/monster_gman.qc +../../../valve/src/server/monster_headcrab.qc +../../../valve/src/server/monster_babycrab.qc +../../../valve/src/server/monster_hevsuit_dead.qc +../../../valve/src/server/monster_houndeye.qc +../../../valve/src/server/monster_human_grunt.qc +../../../valve/src/server/monster_hgrunt_dead.qc +../../../valve/src/server/monster_human_assassin.qc +../../../valve/src/server/monster_ichthyosaur.qc +../../../valve/src/server/monster_leech.qc +../../../valve/src/server/monster_miniturret.qc +../../../valve/src/server/monster_nihilanth.qc +../../../valve/src/server/monster_osprey.qc +../../../valve/src/server/monster_rat.qc +../../../valve/src/server/monster_scientist_dead.qc +../../../valve/src/server/monster_sitting_scientist.qc +../../../valve/src/server/monster_scientist.qc +../../../valve/src/server/monster_sentry.qc +../../../valve/src/server/monster_tentacle.qc +../../../valve/src/server/monster_turret.qc +../../../valve/src/server/monster_zombie.qc +monster_drillsergeant.qc +monster_recruit.qc + +../../../valve/src/server/player.qc +../../../valve/src/server/spectator.qc +../../../valve/src/server/items.qc +../../../valve/src/server/item_longjump.qc +../../../valve/src/server/item_suit.qc +../../../valve/src/server/item_healthkit.qc +../../../valve/src/server/item_battery.qc +../../../valve/src/server/item_weaponbox.qc +../../../valve/src/server/world_items.qc +../../../valve/src/server/xen_spore_small.qc +../../../valve/src/server/xen_spore_medium.qc +../../../valve/src/server/xen_spore_large.qc +../../../valve/src/server/xen_hair.qc +../../../valve/src/server/xen_plantlight.qc +../../../valve/src/server/ammo.qc +ammo_op4.qc + +../../../src/botlib/include.src + +gamerules.qc +../../../valve/src/server/gamerules_singleplayer.qc +../../../valve/src/server/gamerules_multiplayer.qc +gamerules_ctf.qc +../../../valve/src/server/client.qc +server.qc +../../../valve/src/server/damage.qc +../../../valve/src/server/rules.qc +../../../valve/src/server/flashlight.qc +../../../base/src/server/modelevent.qc + +../../../valve/src/server/input.qc +../../../valve/src/server/spawn.qc + +../../../src/server/include.src +../../../src/shared/include.src +#endlist + diff --git a/src/server/server.qc b/src/server/server.qc new file mode 100644 index 0000000..fd1c23d --- /dev/null +++ b/src/server/server.qc @@ -0,0 +1,39 @@ +/* + * 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_InitRules(void) +{ + if (cvar("sv_playerslots") == 1 || cvar("coop") == 1) { + g_grMode = spawn(HLSingleplayerRules); + } else { + g_grMode = spawn(HLMultiplayerRules); + } +} + +void +Game_Worldspawn(void) +{ + Sound_Precache("ammo.pickup"); + Sound_Precache("ammo.respawn"); + Sound_Precache("player.die"); + Sound_Precache("player.fall"); + Sound_Precache("player.lightfall"); + precache_model("models/player.mdl"); + precache_model("models/w_weaponbox.mdl"); + Weapons_Init(); + Player_Precache(); +} diff --git a/src/shared/include.src b/src/shared/include.src new file mode 100644 index 0000000..06d2042 --- /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_hornetgun.qc +../../../valve/src/shared/w_mp5.qc +../../../valve/src/shared/w_python.qc +../../../valve/src/shared/w_rpg.qc +../../../valve/src/shared/w_satchel.qc +../../../valve/src/shared/w_shotgun.qc +../../../valve/src/shared/w_snark.qc +../../../valve/src/shared/w_tripmine.qc +w_pipewrench.qc +w_knife.qc +w_grapple.qc +w_eagle.qc +w_m249.qc +w_displacer.qc +w_sniperrifle.qc +w_sporelauncher.qc +w_penguin.qc +w_shockrifle.qc +weapons.qc +../../../valve/src/shared/weapon_common.qc +#endlist diff --git a/src/shared/items.h b/src/shared/items.h new file mode 100644 index 0000000..efe5bd1 --- /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 0x00000001i +#define ITEM_GLOCK 0x00000002i +#define ITEM_PYTHON 0x00000004i +#define ITEM_MP5 0x00000008i +#define ITEM_CROSSBOW 0x00000010i +#define ITEM_SHOTGUN 0x00000020i +#define ITEM_RPG 0x00000040i +#define ITEM_GAUSS 0x00000080i + +#define ITEM_EGON 0x00000100i +#define ITEM_HORNETGUN 0x00000200i +#define ITEM_HANDGRENADE 0x00000400i +#define ITEM_TRIPMINE 0x00000800i +#define ITEM_SATCHEL 0x00001000i +#define ITEM_SNARK 0x00002000i +#define ITEM_SUIT 0x00004000i +#define ITEM_LONGJUMP 0x00008000i + +#define ITEM_PIPEWRENCH 0x00010000i +#define ITEM_KNIFE 0x00020000i +#define ITEM_GRAPPLE 0x00040000i +#define ITEM_EAGLE 0x00080000i +#define ITEM_M249 0x00100000i +#define ITEM_DISPLACER 0x00200000i +#define ITEM_SNIPERRIFLE 0x00400000i +#define ITEM_PENGUIN 0x00800000i + +#define ITEM_SHOCKRIFLE 0x01000000i +#define ITEM_SPORELAUNCHER 0x02000000i +#define ITEM_UNUSED27 0x04000000i +#define ITEM_UNUSED28 0x08000000i +#define ITEM_UNUSED29 0x10000000i +#define ITEM_UNUSED30 0x20000000i +#define ITEM_UNUSED31 0x40000000i +#define ITEM_UNUSED32 0x80000000i diff --git a/src/shared/player.qc b/src/shared/player.qc new file mode 100644 index 0000000..742edce --- /dev/null +++ b/src/shared/player.qc @@ -0,0 +1,806 @@ +/* + * 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; + + /* gearbox */ + int eagle_mag; int eagle_mag_net; + int sniper_mag; int sniper_mag_net; + int m249_mag; int m249_mag_net; + int sporelauncher_mag; int sporelauncher_mag_net; + int ammo_556; int ammo_556_net; + int ammo_762; int ammo_762_net; + int ammo_spore; int ammo_spore_net; + int ammo_shock; int ammo_shock_net; + int ammo_penguin; int ammo_penguin_net; + int mode_displacer; int mode_displacer_net; + int mode_eagle; int mode_eagle_net; + int mode_wrench; int mode_wrench_net; + int mode_sporelauncher; int mode_sporelauncher_net; + int mode_m249; int mode_m249_net; + +#ifdef CLIENT + /* External model */ + entity p_model; + int p_hand_bone; + int p_model_bone; + float lastweapon; + + virtual void(void) gun_offset; + virtual void(void) draw; + virtual float() predraw; + virtual void(void) postdraw; + virtual void(float) ReceiveEntity; + virtual void(void) PredictPreFrame; + virtual void(void) PredictPostFrame; +#else + virtual void(void) EvaluateEntity; + virtual float(entity, float) SendEntity; +#endif +}; + +#ifdef CLIENT +void Weapons_AmmoUpdate(entity); +/* +================= +player::ReceiveEntity +================= +*/ +void +player::ReceiveEntity(float new) +{ + float fl; + if (new == FALSE) { + /* Go through all the physics code between the last received frame + * and the newest frame and keep the changes this time around instead + * of rolling back, because we'll apply the new server-verified values + * right after anyway. */ + /* FIXME: splitscreen */ + if (entnum == player_localentnum) { + /* FIXME: splitscreen */ + pSeat = &g_seats[0]; + + for (int i = sequence+1; i <= servercommandframe; i++) { + /* ...maybe the input state is too old? */ + if (!getinputstate(i)) { + break; + } + input_sequence = i; + PMove_Run(); + } + + /* any differences in things that are read below are now + * officially from prediction misses. */ + } + } + + /* seed for our prediction table */ + sequence = servercommandframe; + + fl = readfloat(); + + /* HACK: we need to make this more reliable */ + if (fl == UPDATE_ALL) { + /* we respawned */ + gravity = __NULL__; + } + + if (fl & PLAYER_MODELINDEX) + modelindex = readshort(); + + if (fl & PLAYER_ORIGIN) { + origin[0] = readcoord(); + origin[1] = readcoord(); + } + + if (fl & PLAYER_ORIGIN_Z) + origin[2] = readcoord(); + if (fl & PLAYER_ANGLES_X) + pitch = readfloat(); + if (fl & PLAYER_ANGLES_Y) + angles[1] = readfloat(); + if (fl & PLAYER_ANGLES_Z) + angles[2] = readfloat(); + + if (fl & PLAYER_VELOCITY) { + velocity[0] = readcoord(); + velocity[1] = readcoord(); + } + + if (fl & PLAYER_VELOCITY_Z) + velocity[2] = readcoord(); + if (fl & PLAYER_FLAGS) { + flags = readfloat(); + gflags = readfloat(); + } + if (fl & PLAYER_WEAPON) + activeweapon = readbyte(); + if (fl & PLAYER_ITEMS) + g_items = (__variant)readfloat(); + if (fl & PLAYER_HEALTH) + health = readbyte(); + if (fl & PLAYER_ARMOR) + armor = readbyte(); + if (fl & PLAYER_MOVETYPE) + movetype = readbyte(); + if (fl & PLAYER_VIEWOFS) + view_ofs[2] = readfloat(); + if (fl & PLAYER_BASEFRAME) + baseframe = readbyte(); + if (fl & PLAYER_FRAME) { + frame = readbyte(); + frame1time = 0.0f; + frame2time = 0.0f; + } + + if (fl & PLAYER_AMMO1) { + glock_mag = readbyte(); + mp5_mag = readbyte(); + python_mag = readbyte(); + shotgun_mag = readbyte(); + crossbow_mag = readbyte(); + rpg_mag = readbyte(); + satchel_chg = readbyte(); + + /* gearbox */ + eagle_mag = readbyte(); + sniper_mag = readbyte(); + m249_mag = readbyte(); + sporelauncher_mag = readbyte(); + } + + if (fl & PLAYER_AMMO2) { + ammo_9mm = readbyte(); + ammo_357 = readbyte(); + ammo_buckshot = readbyte(); + ammo_bolt = readbyte(); + ammo_rocket = readbyte(); + ammo_uranium = readbyte(); + ammo_handgrenade = readbyte(); + ammo_satchel = readbyte(); + ammo_tripmine = readbyte(); + ammo_snark = readbyte(); + ammo_hornet = readbyte(); + + /* gearbox */ + ammo_556 = readbyte(); + ammo_762 = readbyte(); + ammo_spore = readbyte(); + ammo_shock = readbyte(); + ammo_penguin = readbyte(); + } + + if (fl & PLAYER_AMMO3) { + ammo_m203_grenade = readbyte(); + ammo_shotgun_state = readbyte(); + ammo_gauss_state = readbyte(); + ammo_gauss_volume = readbyte(); + ammo_egon_state = readbyte(); + ammo_rpg_state = readbyte(); + mode_tempstate = readbyte(); + + /* gearbox */ + mode_displacer = readbyte(); + mode_eagle = readbyte(); + mode_wrench = readbyte(); + mode_sporelauncher = readbyte(); + mode_m249 = readbyte(); + } + + if (fl & PLAYER_AMMO1 || fl & PLAYER_AMMO2 || fl & PLAYER_AMMO3) + Weapons_AmmoUpdate(this); + + setorigin(this, origin); +} + +/* +================= +player::PredictPostFrame + +Save the last valid server values away in the _net variants of each field +so we can roll them back later. +================= +*/ +void +player::PredictPreFrame(void) +{ + glock_mag_net = glock_mag; + mp5_mag_net = mp5_mag; + python_mag_net = python_mag; + shotgun_mag_net = shotgun_mag; + crossbow_mag_net = crossbow_mag; + rpg_mag_net = rpg_mag; + satchel_chg_net = satchel_chg; + ammo_9mm_net = ammo_9mm; + ammo_357_net = ammo_357; + ammo_buckshot_net = ammo_buckshot; + ammo_bolt_net = ammo_bolt; + ammo_rocket_net = ammo_rocket; + ammo_uranium_net = ammo_uranium; + ammo_handgrenade_net = ammo_handgrenade; + ammo_satchel_net = ammo_satchel; + ammo_tripmine_net = ammo_tripmine; + ammo_snark_net = ammo_snark; + ammo_hornet_net = ammo_hornet; + + ammo_m203_grenade_net = ammo_m203_grenade; + ammo_shotgun_state_net = ammo_shotgun_state; + ammo_gauss_state_net = ammo_gauss_state; + ammo_gauss_volume_net = ammo_gauss_volume; + ammo_egon_state_net = ammo_egon_state; + ammo_rpg_state_net = ammo_rpg_state; + mode_tempstate_net = mode_tempstate; + + /* gearbox */ + eagle_mag_net = eagle_mag; + sniper_mag_net = sniper_mag; + m249_mag_net = m249_mag; + sporelauncher_mag_net = sporelauncher_mag; + ammo_556_net = ammo_556; + ammo_762_net = ammo_762; + ammo_spore_net = ammo_spore; + ammo_shock_net = ammo_shock; + ammo_penguin_net = ammo_penguin; + mode_displacer_net = mode_displacer; + mode_eagle_net = mode_eagle; + mode_wrench_net = mode_wrench; + mode_sporelauncher_net = mode_sporelauncher; + mode_m249_net = mode_m249; +} + +/* +================= +player::PredictPostFrame + +Where we roll back our values to the ones last sent/verified by the server. +================= +*/ +void +player::PredictPostFrame(void) +{ + glock_mag = glock_mag_net; + mp5_mag = mp5_mag_net; + python_mag = python_mag_net; + shotgun_mag = shotgun_mag_net; + crossbow_mag = crossbow_mag_net; + rpg_mag = rpg_mag_net; + satchel_chg = satchel_chg_net; + ammo_9mm = ammo_9mm_net; + ammo_357 = ammo_357_net; + ammo_buckshot = ammo_buckshot_net; + ammo_m203_grenade = ammo_m203_grenade_net; + ammo_bolt = ammo_bolt_net; + ammo_rocket = ammo_rocket_net; + ammo_uranium = ammo_uranium_net; + ammo_handgrenade = ammo_handgrenade_net; + ammo_satchel = ammo_satchel_net; + ammo_tripmine = ammo_tripmine_net; + ammo_snark = ammo_snark_net; + ammo_hornet = ammo_hornet_net; + + ammo_m203_grenade = ammo_m203_grenade_net; + ammo_shotgun_state = ammo_shotgun_state_net; + ammo_gauss_state = ammo_gauss_state_net; + ammo_gauss_volume = ammo_gauss_volume_net; + ammo_egon_state = ammo_egon_state_net; + ammo_rpg_state = ammo_rpg_state_net; + mode_tempstate = mode_tempstate_net; + + /* gearbox */ + eagle_mag = eagle_mag_net; + sniper_mag = sniper_mag_net; + m249_mag = m249_mag_net; + sporelauncher_mag = sporelauncher_mag_net; + ammo_556 = ammo_556_net; + ammo_762 = ammo_762_net; + ammo_spore = ammo_spore_net; + ammo_shock = ammo_shock_net; + ammo_penguin = ammo_penguin_net; + mode_displacer = mode_displacer_net; + mode_eagle = mode_eagle_net; + mode_wrench = mode_wrench_net; + mode_sporelauncher = mode_sporelauncher_net; + mode_m249 = mode_m249_net; +} + +#else +void +player::EvaluateEntity(void) +{ + SendFlags |= PLAYER_KEEPALIVE; + + if (old_modelindex != modelindex) + SendFlags |= PLAYER_MODELINDEX; + + if (old_origin[0] != origin[0]) + SendFlags |= PLAYER_ORIGIN; + + if (old_origin[1] != origin[1]) + SendFlags |= PLAYER_ORIGIN; + + if (old_origin[2] != origin[2]) + SendFlags |= PLAYER_ORIGIN_Z; + + if (old_angles[0] != v_angle[0]) + SendFlags |= PLAYER_ANGLES_X; + + if (old_angles[1] != angles[1]) + SendFlags |= PLAYER_ANGLES_Y; + + if (old_angles[2] != angles[2]) + SendFlags |= PLAYER_ANGLES_Z; + + if (old_velocity[0] != velocity[0]) + SendFlags |= PLAYER_VELOCITY; + + if (old_velocity[1] != velocity[1]) + SendFlags |= PLAYER_VELOCITY; + + if (old_velocity[2] != velocity[2]) + SendFlags |= PLAYER_VELOCITY_Z; + + if (old_flags != flags) + SendFlags |= PLAYER_FLAGS; + + if (old_gflags != gflags) + SendFlags |= PLAYER_FLAGS; + + if (old_activeweapon != activeweapon) + SendFlags |= PLAYER_WEAPON; + + if (old_items != g_items) + SendFlags |= PLAYER_ITEMS; + + if (old_health != health) + SendFlags |= PLAYER_HEALTH; + + if (old_armor != armor) + SendFlags |= PLAYER_ARMOR; + + if (old_movetype != movetype) + SendFlags |= PLAYER_MOVETYPE; + + if (old_viewofs != view_ofs[2]) + SendFlags |= PLAYER_VIEWOFS; + + if (old_baseframe != baseframe) + SendFlags |= PLAYER_BASEFRAME; + + if (old_frame != frame) + SendFlags |= PLAYER_FRAME; + + /* ammo 1 type updates */ + if (glock_mag != glock_mag_net) { + SendFlags |= PLAYER_AMMO1; + } + if (mp5_mag != mp5_mag_net) { + SendFlags |= PLAYER_AMMO1; + } + if (python_mag != python_mag_net) { + SendFlags |= PLAYER_AMMO1; + } + if (shotgun_mag != shotgun_mag_net) { + SendFlags |= PLAYER_AMMO1; + } + if (crossbow_mag != crossbow_mag_net) { + SendFlags |= PLAYER_AMMO1; + } + if (rpg_mag != rpg_mag_net) { + SendFlags |= PLAYER_AMMO1; + } + if (satchel_chg != satchel_chg_net) { + SendFlags |= PLAYER_AMMO1; + } + + /* ammo 2 type updates */ + if (ammo_9mm != ammo_9mm_net) { + SendFlags |= PLAYER_AMMO2; + } + if (ammo_357 != ammo_357_net) { + SendFlags |= PLAYER_AMMO2; + } + if (ammo_buckshot != ammo_buckshot_net) { + SendFlags |= PLAYER_AMMO2; + } + if (ammo_bolt != ammo_bolt_net) { + SendFlags |= PLAYER_AMMO2; + } + if (ammo_rocket != ammo_rocket_net) { + SendFlags |= PLAYER_AMMO2; + } + if (ammo_uranium != ammo_uranium_net) { + SendFlags |= PLAYER_AMMO2; + } + if (ammo_handgrenade != ammo_handgrenade_net) { + SendFlags |= PLAYER_AMMO2; + } + if (ammo_satchel != ammo_satchel_net) { + SendFlags |= PLAYER_AMMO2; + } + if (ammo_tripmine != ammo_tripmine_net) { + SendFlags |= PLAYER_AMMO2; + } + if (ammo_snark != ammo_snark_net) { + SendFlags |= PLAYER_AMMO2; + } + if (ammo_hornet != ammo_hornet_net) { + SendFlags |= PLAYER_AMMO2; + } + + if (ammo_m203_grenade != ammo_m203_grenade_net) { + SendFlags |= PLAYER_AMMO3; + } + if (ammo_shotgun_state != ammo_shotgun_state_net) { + SendFlags |= PLAYER_AMMO3; + } + if (ammo_gauss_state != ammo_gauss_state_net) { + SendFlags |= PLAYER_AMMO3; + } + if (ammo_gauss_volume != ammo_gauss_volume_net) { + SendFlags |= PLAYER_AMMO3; + } + if (ammo_egon_state != ammo_egon_state_net) { + SendFlags |= PLAYER_AMMO3; + } + if (ammo_rpg_state != ammo_rpg_state_net) { + SendFlags |= PLAYER_AMMO3; + } + if (mode_tempstate != mode_tempstate_net) { + SendFlags |= PLAYER_AMMO3; + } + + old_modelindex = modelindex; + old_origin = origin; + old_angles = angles; + old_angles[0] = v_angle[0]; + old_velocity = velocity; + old_flags = flags; + old_gflags = gflags; + old_activeweapon = activeweapon; + old_items = g_items; + old_health = health; + old_armor = armor; + old_movetype = movetype; + old_viewofs = view_ofs[2]; + old_baseframe = baseframe; + old_frame = frame; + + glock_mag_net = glock_mag; + mp5_mag_net = mp5_mag; + python_mag_net = python_mag; + shotgun_mag_net = shotgun_mag; + crossbow_mag_net = crossbow_mag; + rpg_mag_net = rpg_mag; + satchel_chg_net = satchel_chg; + + ammo_9mm_net = ammo_9mm; + ammo_357_net = ammo_357; + ammo_buckshot_net = ammo_buckshot; + ammo_m203_grenade_net = ammo_m203_grenade; + ammo_bolt_net = ammo_bolt; + ammo_rocket_net = ammo_rocket; + ammo_uranium_net = ammo_uranium; + ammo_handgrenade_net = ammo_handgrenade; + ammo_satchel_net = ammo_satchel; + ammo_tripmine_net = ammo_tripmine; + ammo_snark_net = ammo_snark; + ammo_hornet_net = ammo_hornet; + + ammo_m203_grenade_net = ammo_m203_grenade; + ammo_shotgun_state_net = ammo_shotgun_state; + ammo_gauss_state_net = ammo_gauss_state; + ammo_gauss_volume_net = ammo_gauss_volume; + ammo_egon_state_net = ammo_egon_state; + ammo_rpg_state_net = ammo_rpg_state; + mode_tempstate_net = mode_tempstate; + + /* gearbox */ + if (eagle_mag_net != eagle_mag) + SendFlags |= PLAYER_AMMO1; + if (sniper_mag_net != sniper_mag) + SendFlags |= PLAYER_AMMO1; + if (m249_mag_net != m249_mag) + SendFlags |= PLAYER_AMMO1; + if (sporelauncher_mag_net != sporelauncher_mag) + SendFlags |= PLAYER_AMMO1; + + if (ammo_556_net != ammo_556) + SendFlags |= PLAYER_AMMO2; + if (ammo_762_net != ammo_762) + SendFlags |= PLAYER_AMMO2; + if (ammo_spore_net != ammo_spore) + SendFlags |= PLAYER_AMMO2; + if (ammo_shock_net != ammo_shock) + SendFlags |= PLAYER_AMMO2; + if (ammo_penguin_net != ammo_penguin) + SendFlags |= PLAYER_AMMO2; + + if (mode_displacer_net != mode_displacer) + SendFlags |= PLAYER_AMMO3; + if (mode_eagle_net != mode_eagle) + SendFlags |= PLAYER_AMMO3; + if (mode_wrench_net != mode_wrench) + SendFlags |= PLAYER_AMMO3; + if (mode_sporelauncher_net != mode_sporelauncher) + SendFlags |= PLAYER_AMMO3; + + eagle_mag_net = eagle_mag; + sniper_mag_net = sniper_mag; + m249_mag_net = m249_mag; + sporelauncher_mag_net = sporelauncher_mag; + ammo_556_net = ammo_556; + ammo_762_net = ammo_762; + ammo_spore_net = ammo_spore; + ammo_shock_net = ammo_shock; + ammo_penguin_net = ammo_penguin; + mode_displacer_net = mode_displacer; + mode_eagle_net = mode_eagle; + mode_wrench_net = mode_wrench; + mode_sporelauncher_net = mode_sporelauncher; + mode_m249_net = mode_m249; +} + +/* +================= +player::SendEntity +================= +*/ +float +player::SendEntity(entity ePEnt, float fChanged) +{ + if (health <= 0 && ePEnt != this) { + return FALSE; + } + + if (clienttype(ePEnt) != CLIENTTYPE_REAL) { + return FALSE; + } + + if (ePEnt != self) { + fChanged &= ~PLAYER_ITEMS; + fChanged &= ~PLAYER_HEALTH; + fChanged &= ~PLAYER_ARMOR; + fChanged &= ~PLAYER_VIEWOFS; + fChanged &= ~PLAYER_AMMO1; + fChanged &= ~PLAYER_AMMO2; + fChanged &= ~PLAYER_AMMO3; + } + + WriteByte(MSG_ENTITY, ENT_PLAYER); + WriteFloat(MSG_ENTITY, fChanged); + + /* really trying to get our moneys worth with 23 bits of mantissa */ + if (fChanged & PLAYER_MODELINDEX) + WriteShort(MSG_ENTITY, modelindex); + if (fChanged & PLAYER_ORIGIN) { + WriteCoord(MSG_ENTITY, origin[0]); + WriteCoord(MSG_ENTITY, origin[1]); + } + if (fChanged & PLAYER_ORIGIN_Z) + WriteCoord(MSG_ENTITY, origin[2]); + if (fChanged & PLAYER_ANGLES_X) + WriteFloat(MSG_ENTITY, v_angle[0]); + if (fChanged & PLAYER_ANGLES_Y) + WriteFloat(MSG_ENTITY, angles[1]); + if (fChanged & PLAYER_ANGLES_Z) + WriteFloat(MSG_ENTITY, angles[2]); + if (fChanged & PLAYER_VELOCITY) { + WriteCoord(MSG_ENTITY, velocity[0]); + WriteCoord(MSG_ENTITY, velocity[1]); + } + if (fChanged & PLAYER_VELOCITY_Z) + WriteCoord(MSG_ENTITY, velocity[2]); + if (fChanged & PLAYER_FLAGS) { + WriteFloat(MSG_ENTITY, flags); + WriteFloat(MSG_ENTITY, gflags); + } + if (fChanged & PLAYER_WEAPON) + WriteByte(MSG_ENTITY, activeweapon); + if (fChanged & PLAYER_ITEMS) + WriteFloat(MSG_ENTITY, (__variant)g_items); + if (fChanged & PLAYER_HEALTH) + WriteByte(MSG_ENTITY, bound(0, health, 255)); + if (fChanged & PLAYER_ARMOR) + WriteByte(MSG_ENTITY, armor); + if (fChanged & PLAYER_MOVETYPE) + WriteByte(MSG_ENTITY, movetype); + if (fChanged & PLAYER_VIEWOFS) + WriteFloat(MSG_ENTITY, view_ofs[2]); + if (fChanged & PLAYER_BASEFRAME) + WriteByte(MSG_ENTITY, baseframe); + if (fChanged & PLAYER_FRAME) + WriteByte(MSG_ENTITY, frame); + + if (fChanged & PLAYER_AMMO1) { + WriteByte(MSG_ENTITY, glock_mag); + WriteByte(MSG_ENTITY, mp5_mag); + WriteByte(MSG_ENTITY, python_mag); + WriteByte(MSG_ENTITY, shotgun_mag); + WriteByte(MSG_ENTITY, crossbow_mag); + WriteByte(MSG_ENTITY, rpg_mag); + WriteByte(MSG_ENTITY, satchel_chg); + + /* gearbox */ + WriteByte(MSG_ENTITY, eagle_mag); + WriteByte(MSG_ENTITY, sniper_mag); + WriteByte(MSG_ENTITY, m249_mag); + WriteByte(MSG_ENTITY, sporelauncher_mag); + } + + if (fChanged & PLAYER_AMMO2) { + WriteByte(MSG_ENTITY, ammo_9mm); + WriteByte(MSG_ENTITY, ammo_357); + WriteByte(MSG_ENTITY, ammo_buckshot); + WriteByte(MSG_ENTITY, ammo_bolt); + WriteByte(MSG_ENTITY, ammo_rocket); + WriteByte(MSG_ENTITY, ammo_uranium); + WriteByte(MSG_ENTITY, ammo_handgrenade); + WriteByte(MSG_ENTITY, ammo_satchel); + WriteByte(MSG_ENTITY, ammo_tripmine); + WriteByte(MSG_ENTITY, ammo_snark); + WriteByte(MSG_ENTITY, ammo_hornet); + + /* gearbox */ + WriteByte(MSG_ENTITY, ammo_556); + WriteByte(MSG_ENTITY, ammo_762); + WriteByte(MSG_ENTITY, ammo_spore); + WriteByte(MSG_ENTITY, ammo_shock); + WriteByte(MSG_ENTITY, ammo_penguin); + } + + if (fChanged & PLAYER_AMMO3) { + WriteByte(MSG_ENTITY, ammo_m203_grenade); + WriteByte(MSG_ENTITY, ammo_shotgun_state); + WriteByte(MSG_ENTITY, ammo_gauss_state); + WriteByte(MSG_ENTITY, ammo_gauss_volume); + WriteByte(MSG_ENTITY, ammo_egon_state); + WriteByte(MSG_ENTITY, ammo_rpg_state); + WriteByte(MSG_ENTITY, mode_tempstate); + + /* gearbox */ + WriteByte(MSG_ENTITY, mode_displacer); + WriteByte(MSG_ENTITY, mode_eagle); + WriteByte(MSG_ENTITY, mode_wrench); + WriteByte(MSG_ENTITY, mode_sporelauncher); + WriteByte(MSG_ENTITY, mode_m249); + } + + return TRUE; +} +#endif + diff --git a/src/shared/w_displacer.qc b/src/shared/w_displacer.qc new file mode 100644 index 0000000..66225c2 --- /dev/null +++ b/src/shared/w_displacer.qc @@ -0,0 +1,384 @@ +/* + * 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_displacer (0 0 1) (-16 -16 0) (16 16 32) +"model" "models/w_displacer.mdl" + +HALF-LIFE: OPPOSING FORCE (1999) ENTITY + +Displacer Weapon + +*/ + +enum +{ + DISP_IDLE1, + DISP_IDLE2, + DISP_SPINUP, + DISP_SPIN, + DISP_FIRE, + DISP_DRAW, + DISP_HOLSTER +}; + +#ifdef SERVER +entity Spawn_SelectRandom(string); +#endif + +void +w_displacer_precache(void) +{ +#ifdef SERVER + precache_sound("weapons/displacer_impact.wav"); + precache_sound("weapons/displacer_fire.wav"); + precache_sound("weapons/displacer_self.wav"); + precache_sound("weapons/displacer_spin.wav"); + precache_sound("weapons/displacer_spin2.wav"); + precache_sound("weapons/displacer_start.wav"); + precache_sound("weapons/displacer_teleport.wav"); + precache_sound("weapons/displacer_teleport_player.wav"); + precache_model("models/w_displacer.mdl"); + precache_model("sprites/exit1.spr"); +#else + precache_model("models/v_displacer.mdl"); + precache_model("models/p_displacer.mdl"); +#endif +} + +void +w_displacer_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, -1, pl.ammo_uranium, -1); +} + +string +w_displacer_wmodel(void) +{ + return "models/w_displacer.mdl"; +} + +string +w_displacer_pmodel(void) +{ + return "models/p_displacer.mdl"; +} + +string +w_displacer_deathmsg(void) +{ + return "%s was assaulted by %s's Displacer."; +} + +int +w_displacer_pickup(int new, int startammo) +{ +#ifdef SERVER + player pl = (player)self; + + if (pl.ammo_uranium < MAX_A_URANIUM) { + pl.ammo_uranium = bound(0, pl.ammo_uranium + 40, MAX_A_URANIUM); + } else { + return FALSE; + } +#endif + return TRUE; +} + +void +w_displacer_draw(void) +{ +#ifdef CLIENT + Weapons_SetModel("models/v_displacer.mdl"); + Weapons_ViewAnimation(DISP_DRAW); +#endif +} + +void +w_displacer_holster(void) +{ +#ifdef CLIENT + Weapons_ViewAnimation(DISP_HOLSTER); +#endif +} + +void +w_displacer_teleport(entity target) +{ +#ifdef SERVER + player pl = (player)target; + /* TODO, 250 damage */ + Weapons_PlaySound(pl, CHAN_WEAPON, "weapons/displacer_teleport.wav", 1, ATTN_NORM); + + /* FIXME: This will teleport upon your standard spawn positions + * in other game modes, such as CTF (your team spawns), no clue + * about singleplayer */ + entity spot = Spawn_SelectRandom("info_player_deathmatch"); + setorigin(pl, spot.origin); +#endif +} + +void +w_displacer_fireball(void) +{ +#ifdef SERVER + player pl = (player)self; + + static void displacerball_touch(void) + { + if (other.flags & FL_CLIENT) { + w_displacer_teleport(other); + } + Damage_Radius(self.origin, self.owner, 250, 250 * 2.5f, TRUE, WEAPON_DISPLACER); + sound(self, 1, "weapons/displacer_impact.wav", 1, ATTN_NORM); + remove(self); + } + + static void displacerball_animate(void) + { + self.frame++; + + if (self.frame > 25) + self.frame = 0; + + self.nextthink = time + 0.1f; + } + + Weapons_MakeVectors(); + entity ball = spawn(); + + setmodel(ball, "sprites/exit1.spr"); + setorigin(ball, Weapons_GetCameraPos() + (v_forward * 16)); + ball.owner = self; + ball.velocity = v_forward * 500; + ball.movetype = MOVETYPE_FLYMISSILE; + ball.solid = SOLID_BBOX; + ball.angles = vectoangles(ball.velocity); + ball.touch = displacerball_touch; + ball.effects = EF_ADDITIVE; + ball.think = displacerball_animate; + ball.nextthink = time + 0.1f; + setsize(ball, [0,0,0], [0,0,0]); + sound(pl, CHAN_WEAPON, "weapons/displacer_fire.wav", 1, ATTN_NORM); +#endif +} + +void +w_displacer_release(void) +{ + player pl = (player)self; + + if (pl.w_idle_next > 0.0) { + return; + } + + if (pl.mode_displacer == 1) { + Weapons_ViewAnimation(DISP_FIRE); + w_displacer_fireball(); + pl.mode_displacer = 0; + pl.w_idle_next = pl.w_attack_next = 1.0f; + pl.ammo_uranium -= 20; + return; + } else if (pl.mode_displacer == 2) { + Weapons_ViewAnimation(DISP_FIRE); + w_displacer_teleport(pl); + pl.mode_displacer = 0; + pl.w_idle_next = pl.w_attack_next = 1.0f; + pl.ammo_uranium -= 60; + return; + } + + int r = (float)input_sequence % 3; + if (r == 1) { + Weapons_ViewAnimation(DISP_IDLE1); + } else { + Weapons_ViewAnimation(DISP_IDLE2); + } + + pl.w_idle_next = 3.0f; +} + +void +w_displacer_primary(void) +{ + player pl = (player)self; + + if (pl.w_attack_next > 0.0) { + return; + } + + /* ammo check */ + if (pl.ammo_uranium < 20) { + return; + } + + /* we're already in spinning mode */ + if (pl.mode_displacer > 0) { + w_displacer_release(); + return; + } + + pl.mode_displacer = 1; + +#ifdef CLIENT + Weapons_ViewAnimation(DISP_SPINUP); +#else + Weapons_PlaySound(pl, CHAN_WEAPON, "weapons/displacer_spin.wav", 1, ATTN_NORM); +#endif + pl.w_idle_next = pl.w_attack_next = 1.0f; +} + +void +w_displacer_secondary(void) +{ + player pl = (player)self; + + if (pl.w_attack_next > 0.0) { + return; + } + + if (pl.ammo_uranium < 60) { + return; + } + + /* we're already in spinning mode */ + if (pl.mode_displacer > 0) { + w_displacer_release(); + return; + } + + pl.mode_displacer = 2; + +#ifdef CLIENT + Weapons_ViewAnimation(DISP_SPINUP); +#else + Weapons_PlaySound(pl, CHAN_WEAPON, "weapons/displacer_spin2.wav", 1, ATTN_NORM); +#endif + pl.w_idle_next = pl.w_attack_next = 1.0f; +} + +float +w_displacer_aimanim(void) +{ + return self.flags & FL_CROUCHING ? ANIM_CR_AIMSQUEAK : ANIM_AIMSQUEAK; +} + +void +w_displacer_hud(void) +{ +#ifdef CLIENT + vector cross_pos; + vector aicon_pos; + + cross_pos = g_hudmins + (g_hudres / 2) + [-12,-12]; + aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42]; + + drawsubpic( + cross_pos, + [24,24], + "sprites/ofch1.spr_0.tga", + [48/72,0], + [24/72,24/72], + [1,1,1], + 1, + DRAWFLAG_NORMAL + ); + + drawsubpic( + aicon_pos, + [24,24], + "sprites/640hud7.spr_0.tga", + [0,96/128], // was [24/256,72/128]... which makes 0 sense + [24/256, 24/128], + g_hud_color, + pSeat->m_flAmmo2Alpha, + DRAWFLAG_ADDITIVE + ); + + HUD_DrawAmmo2(); +#endif +} + +void +w_displacer_hudpic(int selected, vector pos, float a) +{ +#ifdef CLIENT + player pl = (player)self; + vector hud_col; + + if (pl.ammo_uranium == 0) + hud_col = [1,0,0]; + else + hud_col = g_hud_color; + + HUD_DrawAmmoBar(pos, pl.ammo_uranium, MAX_A_URANIUM, a); + + if (selected) { + drawsubpic( + pos, + [170,45], + "sprites/640hudof02.spr_0.tga", + [0,180/256], + [170/256,45/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [170,45], + "sprites/640hudof01.spr_0.tga", + [0,180/256], + [170/256,45/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } +#endif +} + +weapon_t w_displacer = +{ + .name = "displacer", + .id = ITEM_DISPLACER, + .slot = 5, + .slot_pos = 1, + .draw = w_displacer_draw, + .holster = w_displacer_holster, + .primary = w_displacer_primary, + .secondary = w_displacer_secondary, + .reload = __NULL__, + .release = w_displacer_release, + .crosshair = w_displacer_hud, + .precache = w_displacer_precache, + .pickup = w_displacer_pickup, + .updateammo = w_displacer_updateammo, + .wmodel = w_displacer_wmodel, + .pmodel = w_displacer_pmodel, + .deathmsg = w_displacer_deathmsg, + .aimanim = w_displacer_aimanim, + .hudpic = w_displacer_hudpic +}; + +/* entity definitions for pickups */ +#ifdef SERVER +void +weapon_displacer(void) +{ + Weapons_InitItem(WEAPON_DISPLACER); +} +#endif diff --git a/src/shared/w_eagle.qc b/src/shared/w_eagle.qc new file mode 100644 index 0000000..861b74b --- /dev/null +++ b/src/shared/w_eagle.qc @@ -0,0 +1,412 @@ +/* + * 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_eagle (0 0 1) (-16 -16 0) (16 16 32) +"model" "models/w_desert_eagle.mdl" + +HALF-LIFE: OPPOSING FORCE (1999) ENTITY + +Desert Eagle Weapon + +*/ + +enum +{ + EAGLE_IDLE1, + EAGLE_IDLE2, + EAGLE_IDLE3, + EAGLE_IDLE4, + EAGLE_IDLE5, + EAGLE_SHOOT, + EAGLE_SHOOT_EMPTY, + EAGLE_RELOAD, + EAGLE_RELOAD_NOSHOT, + EAGLE_DRAW, + EAGLE_HOLSTER +}; + +void +w_eagle_precache(void) +{ +#ifdef SERVER + precache_model("models/w_desert_eagle.mdl"); + precache_sound("weapons/desert_eagle_fire.wav"); + precache_sound("weapons/desert_eagle_sight.wav"); + precache_sound("weapons/desert_eagle_sight2.wav"); +#else + precache_model("models/v_desert_eagle.mdl"); + precache_model("models/p_desert_eagle.mdl"); +#endif +} + +int +w_eagle_pickup(int new, int startammo) +{ +#ifdef SERVER + player pl = (player)self; + + if (new) { + pl.eagle_mag = 7; + } else { + if (pl.ammo_357 < MAX_A_357) { + pl.ammo_357 = bound(0, pl.ammo_357 + 7, MAX_A_357); + } else { + return FALSE; + } + } +#endif + return TRUE; +} + +void +w_eagle_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, pl.eagle_mag, pl.ammo_357, -1); +} + +string +w_eagle_wmodel(void) +{ + return "models/w_desert_eagle.mdl"; +} +string +w_eagle_pmodel(void) +{ + return "models/p_desert_eagle.mdl"; +} +string +w_eagle_deathmsg(void) +{ + return ""; +} + +void +w_eagle_draw(void) +{ +#ifdef CLIENT + Weapons_SetModel("models/v_desert_eagle.mdl"); + Weapons_ViewAnimation(EAGLE_DRAW); +#else + player pl = (player)self; + Weapons_UpdateAmmo(pl, pl.eagle_mag, pl.ammo_357, -1); +#endif +} + +void +w_eagle_holster(void) +{ + Weapons_ViewAnimation(EAGLE_HOLSTER); +} + +void +w_eagle_release(void) +{ + player pl = (player)self; + + /* auto-reload if need be */ + if (pl.w_attack_next <= 0.0) + if (pl.eagle_mag == 0 && pl.ammo_357 > 0) { + Weapons_Reload(); + return; + } + + if (pl.w_idle_next) { + return; + } + + /* these idles don't support the 'empty' animation style */ +#ifdef CLIENT + if (pl.eagle_mag <= 0) { + return; + } +#else + if (pl.eagle_mag <= 0) { + return; + } +#endif + + int r = (float)input_sequence % 4; + switch (r) { + case 0: + Weapons_ViewAnimation(EAGLE_IDLE1); + pl.w_idle_next = 2.5f; + break; + case 1: + Weapons_ViewAnimation(EAGLE_IDLE2); + pl.w_idle_next = 2.5f; + break; + case 2: + Weapons_ViewAnimation(EAGLE_IDLE3); + pl.w_idle_next = 1.633333f; + break; + default: + Weapons_ViewAnimation(EAGLE_IDLE4); + pl.w_idle_next = 2.5f; + } +} + +void +w_eagle_primary(void) +{ + player pl = (player)self; + if (pl.w_attack_next > 0.0) { + return; + } + + /* Ammo check */ +#ifdef CLIENT + if (pl.eagle_mag <= 0) { + return; + } +#else + if (pl.eagle_mag <= 0) { + return; + } +#endif + + /* Actual firing */ + if (pl.mode_eagle == 1) { +#ifdef SERVER + TraceAttack_FireBullets(1, pl.origin + pl.view_ofs, 34, [0, 0], WEAPON_EAGLE); +#endif + pl.w_attack_next = 0.5f; + } else { +#ifdef SERVER + TraceAttack_FireBullets(1, pl.origin + pl.view_ofs, 34, [0.1,0.1], WEAPON_EAGLE); +#endif + pl.w_attack_next = 0.2f; + } + +#ifdef SERVER + sound(pl, CHAN_WEAPON, "weapons/desert_eagle_fire.wav", 1, ATTN_NORM); + pl.eagle_mag--; + Weapons_UpdateAmmo(pl, pl.eagle_mag, pl.ammo_357, -1); +#else + pl.eagle_mag--; + View_SetMuzzleflash(MUZZLE_SMALL); + Weapons_ViewPunchAngle([-10,0,0]); + + if (pl.eagle_mag <= 0) { + Weapons_ViewAnimation(EAGLE_SHOOT_EMPTY); + } else { + Weapons_ViewAnimation(EAGLE_SHOOT); + } +#endif +} + +void +w_eagle_secondary(void) +{ + player pl = (player)self; + + if (pl.w_attack_next > 0.0) { + return; + } + + /* toggle laser */ + pl.mode_eagle = 1 - pl.mode_eagle; + +#ifdef SERVER + if (pl.mode_eagle) { + sound(pl, 8, "weapons/desert_eagle_sight.wav", 1, ATTN_NORM); + } else { + sound(pl, 8, "weapons/desert_eagle_sight2.wav", 1, ATTN_NORM); + } +#endif + + pl.w_attack_next = 1.0f; + w_eagle_release(); +} + +void +w_eagle_reload(void) +{ + player pl = (player)self; + if (pl.w_attack_next > 0.0) { + return; + } + + /* Ammo check */ +#ifdef CLIENT + if (pl.eagle_mag >= 7) { + return; + } + if (pl.ammo_357 <= 0) { + return; + } +#else + if (pl.eagle_mag >= 7) { + return; + } + if (pl.ammo_357 <= 0) { + return; + } +#endif + + /* Audio-Visual bit */ +#ifdef CLIENT + if (pl.eagle_mag <= 0) { + Weapons_ViewAnimation(EAGLE_RELOAD); + } else { + Weapons_ViewAnimation(EAGLE_RELOAD_NOSHOT); + } +#else + Weapons_ReloadWeapon(pl, player::eagle_mag, player::ammo_357, 7); + Weapons_UpdateAmmo(pl, pl.eagle_mag, pl.ammo_357, -1); +#endif + + pl.w_attack_next = 1.64f; + pl.w_idle_next = 10.0f; +} + +void +w_eagle_crosshair(void) +{ +#ifdef CLIENT + player pl = (player)self; + vector cross_pos; + vector aicon_pos; + + /* crosshair/laser */ + if (pl.mode_eagle == 1) { + float lerp; + vector jitter; + Weapons_MakeVectors(); + vector src = pl.origin + pl.view_ofs; + traceline(src, src + (v_forward * 256), FALSE, pl); + lerp = Math_Lerp(18,6, trace_fraction); + jitter[0] = (random(0,2) - 2) * (1 - trace_fraction); + jitter[1] = (random(0,2) - 2) * (1 - trace_fraction); + cross_pos = g_hudmins + (g_hudres / 2) + ([-lerp,-lerp] / 2); + drawsubpic( + cross_pos + jitter, + [lerp,lerp], + "sprites/laserdot.spr_0.tga", + [0,0], + [1.0, 1.0], + [1,1,1], + 1.0f, + DRAWFLAG_ADDITIVE + ); + } else { + cross_pos = g_hudmins + (g_hudres / 2) + [-12,-12]; + drawsubpic( + cross_pos, + [24,24], + "sprites/ofch1.spr_0.tga", + [0,0], + [24/72, 24/72], + [1,1,1], + 1, + DRAWFLAG_NORMAL + ); + } + + /* ammo counters */ + HUD_DrawAmmo1(); + HUD_DrawAmmo2(); + + /* ammo icon */ + aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42]; + drawsubpic( + aicon_pos, + [24,24], + "sprites/640hud7.spr_0.tga", + [24/256,72/128], + [24/256, 24/128], + g_hud_color, + pSeat->m_flAmmo2Alpha, + DRAWFLAG_ADDITIVE + ); +#endif +} + +float +w_eagle_aimanim(void) +{ + return self.flags & FL_CROUCHING ? ANIM_CR_AIMPYTHON : ANIM_AIMPYTHON; +} + +void +w_eagle_hudpic(int selected, vector pos, float a) +{ +#ifdef CLIENT + player pl = (player)self; + vector hud_col; + + if (pl.eagle_mag == 0 && pl.ammo_357 == 0) + hud_col = [1,0,0]; + else + hud_col = g_hud_color; + + if (selected) { + drawsubpic( + pos, + [170,45], + "sprites/640hudof02.spr_0.tga", + [0,90/256], + [170/256,45/256], + g_hud_color, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [170,45], + "sprites/640hudof01.spr_0.tga", + [0,90/256], + [170/256,45/256], + g_hud_color, + a, + DRAWFLAG_ADDITIVE + ); + } + + HUD_DrawAmmoBar(pos, pl.ammo_357, MAX_A_357, a); +#endif +} + +weapon_t w_eagle = +{ + .name = "eagle", + .id = ITEM_EAGLE, + .slot = 1, + .slot_pos = 2, + .draw = w_eagle_draw, + .holster = w_eagle_holster, + .primary = w_eagle_primary, + .secondary = w_eagle_secondary, + .reload = w_eagle_reload, + .release = w_eagle_release, + .crosshair = w_eagle_crosshair, + .precache = w_eagle_precache, + .pickup = w_eagle_pickup, + .updateammo = w_eagle_updateammo, + .wmodel = w_eagle_wmodel, + .pmodel = w_eagle_pmodel, + .deathmsg = w_eagle_deathmsg, + .aimanim = w_eagle_aimanim, + .hudpic = w_eagle_hudpic +}; + +#ifdef SERVER +void +weapon_eagle(void) +{ + Weapons_InitItem(WEAPON_EAGLE); +} +#endif diff --git a/src/shared/w_grapple.qc b/src/shared/w_grapple.qc new file mode 100644 index 0000000..eaddf15 --- /dev/null +++ b/src/shared/w_grapple.qc @@ -0,0 +1,314 @@ +/* + * 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_grapple (0 0 1) (-16 -16 0) (16 16 32) +"model" "models/w_bgrap.mdl" + +HALF-LIFE: OPPOSING FORCE (1999) ENTITY + +Barnacle Grappling-Hook Weapon + +*/ + +#ifdef CLIENT +/* because some people apparently prefer the worse quality one */ +var int autocvar_cl_tonguemode = 0; +#endif + +enum +{ + BARN_IDLE1, + BARN_IDLE2, + BARN_IDLE3, + BARN_COUGH, + BARN_HOLSTER, + BARN_DRAW, + BARN_FIRE, + BARN_FIREWAIT, + BARN_FIREREACH, + BARN_FIRETRAVEL, + BARN_FIRERELEASE +}; + +void +w_grapple_precache(void) +{ +#ifdef SERVER + precache_sound("weapons/bgrapple_cough.wav"); + precache_sound("weapons/bgrapple_fire.wav"); + precache_sound("weapons/bgrapple_impact.wav"); + precache_sound("weapons/bgrapple_pull.wav"); + precache_sound("weapons/bgrapple_release.wav"); + precache_sound("weapons/bgrapple_wait.wav"); + precache_model("sprites/_tongue.spr"); + precache_model("sprites/tongue.spr"); + precache_model("models/w_bgrap.mdl"); +#else + precache_model("models/v_bgrap.mdl"); + precache_model("models/v_bgrap_tonguetip.mdl"); + precache_model("models/p_bgrap.mdl"); +#endif +} + +void +w_grapple_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, -1, -1, -1); +} + +string +w_grapple_wmodel(void) +{ + return "models/w_bgrap.mdl"; +} + +string +w_grapple_pmodel(void) +{ + return "models/p_bgrap.mdl"; +} + +string +w_grapple_deathmsg(void) +{ + return "%s was assaulted by %s's Barnacle."; +} + +void +w_grapple_draw(void) +{ + Weapons_SetModel("models/v_bgrap.mdl"); + Weapons_ViewAnimation(BARN_DRAW); +} + +void +w_grapple_holster(void) +{ + Weapons_ViewAnimation(BARN_HOLSTER); +} + +/* called once the tongue hits a wall */ +void Grapple_Touch(void) +{ + player pl = (player)self.owner; + pl.hook.movetype = MOVETYPE_NONE; + pl.hook.touch = __NULL__; + pl.hook.velocity = [0,0,0]; + pl.hook.solid = SOLID_NOT; + pl.a_ammo1 = 1; +} + +#ifdef CLIENT +/* draw the tongue from a to b */ +float +grapple_predraw(void) +{ + vector forg = gettaginfo(pSeat->m_eViewModel, pSeat->m_iVMBones); + vector morg = self.origin; + vector fsize = [3,3]; + + vector col1 = getlight(forg) / 255; + vector col2 = getlight(morg) / 255; + + makevectors(view_angles); + + R_BeginPolygon(autocvar_cl_tonguemode == 1 ? "sprites/_tongue.spr_0.tga" : "sprites/tongue.spr_0.tga", 0, 0); + R_PolygonVertex(forg + v_right * fsize[0] - v_up * fsize[1], + [1,1], col1, 1.0f); + R_PolygonVertex(forg - v_right * fsize[0] - v_up * fsize[1], + [0,1], col1, 1.0f); + R_PolygonVertex(morg - v_right * fsize[0] + v_up * fsize[1], + [0,0], col2, 1.0f); + R_PolygonVertex(morg + v_right * fsize[0] + v_up * fsize[1], + [1,0], col2, 1.0f); + R_EndPolygon(); + addentity(self); + return PREDRAW_NEXT; +} +#endif + +/* spawn and pull */ +void +w_grapple_primary(void) +{ + player pl = (player)self; + + if (pl.hook != __NULL__) { + /* play the looping reel anim once */ + if (pl.a_ammo1 == 1) { + pl.a_ammo1 = 2; + Weapons_ViewAnimation(BARN_FIRETRAVEL); + } else if (pl.a_ammo1 == 2) { + pl.hook.skin = 1; /* grappled */ + } + + if (pl.w_attack_next > 0.0) { + return; + } + +#ifdef SERVER + Weapons_MakeVectors(); + vector src = Weapons_GetCameraPos(); + traceline(src, src + (v_forward * 32), FALSE, pl); + if (trace_ent.takedamage == DAMAGE_YES && trace_ent.iBleeds) { + Damage_Apply(trace_ent, pl, 25, WEAPON_GRAPPLE, DMG_GENERIC); + } +#endif + pl.w_attack_next = 0.5f; + return; + } + + Weapons_MakeVectors(); + pl.hook = spawn(); + +#ifdef CLIENT + /*setmodel(pl.hook, "models/v_bgrap_tonguetip.mdl");*/ + pl.hook.drawmask = MASK_ENGINE; + pl.hook.predraw = grapple_predraw; +#else + sound(pl, CHAN_WEAPON, "weapons/bgrapple_fire.wav", 1.0, ATTN_NORM); + sound(pl, CHAN_VOICE, "weapons/bgrapple_pull.wav", 1.0, ATTN_NORM); +#endif + setorigin(pl.hook, Weapons_GetCameraPos() + (v_forward * 16)); + pl.hook.owner = self; + pl.hook.velocity = v_forward * 1500; + pl.hook.movetype = MOVETYPE_FLYMISSILE; + pl.hook.solid = SOLID_BBOX; + pl.hook.angles = vectoangles(pl.hook.velocity); + pl.hook.touch = Grapple_Touch; + setsize(pl.hook, [0,0,0], [0,0,0]); + Weapons_ViewAnimation(BARN_FIRE); +} + +/* let go, hang */ +void +w_grapple_secondary(void) +{ + player pl = (player)self; + if (pl.hook == __NULL__) { + return; + } + + pl.hook.skin = 0; /* ungrappled */ +} + +/* de-spawn and play idle anims */ +void +w_grapple_release(void) +{ + player pl = (player)self; + + if (pl.hook != __NULL__) { + pl.a_ammo1 = 0; /* cache */ + pl.hook.skin = 0; /* ungrappled */ + remove(pl.hook); +#ifdef CLIENT + Weapons_ViewAnimation(BARN_FIRERELEASE); +#else + sound(pl, CHAN_VOICE, "weapons/bgrapple_release.wav", 1.0, ATTN_NORM); +#endif + pl.w_idle_next = 1.0f; + pl.hook = __NULL__; + } + + if (pl.w_idle_next > 0.0) { + return; + } + + int r = (float)input_sequence % 3; + switch (r) { + case 1: + Weapons_ViewAnimation(BARN_IDLE1); + pl.w_idle_next = 2.566667f; + break; + case 2: + Weapons_ViewAnimation(BARN_IDLE2); + pl.w_idle_next = 10.0f; + break; + default: + Weapons_ViewAnimation(BARN_IDLE3); + pl.w_idle_next = 1.35f; + break; + } +} + +float +w_grapple_aimanim(void) +{ + return self.flags & FL_CROUCHING ? ANIM_CR_AIMSQUEAK : ANIM_AIMSQUEAK; +} + +void +w_grapple_hudpic(int selected, vector pos, float a) +{ +#ifdef CLIENT + if (selected) { + drawsubpic( + pos, + [170,45], + "sprites/640hudof02.spr_0.tga", + [0,45/256], + [170/256,45/256], + g_hud_color, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [170,45], + "sprites/640hudof01.spr_0.tga", + [0,45/256], + [170/256,45/256], + g_hud_color, + a, + DRAWFLAG_ADDITIVE + ); + } +#endif +} + +weapon_t w_grapple = +{ + .name = "grapple", + .id = ITEM_GRAPPLE, + .slot = 0, + .slot_pos = 3, + .draw = w_grapple_draw, + .holster = w_grapple_holster, + .primary = w_grapple_primary, + .secondary = w_grapple_secondary, + .reload = __NULL__, + .release = w_grapple_release, + .crosshair = __NULL__, + .precache = w_grapple_precache, + .pickup = __NULL__, + .updateammo = w_grapple_updateammo, + .wmodel = w_grapple_wmodel, + .pmodel = w_grapple_pmodel, + .deathmsg = w_grapple_deathmsg, + .aimanim = w_grapple_aimanim, + .hudpic = w_grapple_hudpic +}; + +/* entity definitions for pickups */ +#ifdef SERVER +void +weapon_grapple(void) +{ + Weapons_InitItem(WEAPON_GRAPPLE); +} +#endif diff --git a/src/shared/w_knife.qc b/src/shared/w_knife.qc new file mode 100644 index 0000000..ae8faef --- /dev/null +++ b/src/shared/w_knife.qc @@ -0,0 +1,275 @@ +/* + * 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_knife (0 0 1) (-16 -16 0) (16 16 32) +"model" "models/w_knife.mdl" + +HALF-LIFE: OPPOSING FORCE (1999) ENTITY + +Knife Weapon + +*/ + +enum +{ + KNIFE_IDLE1, + KNIFE_DRAW, + KNIFE_HOLSTER, + KNIFE_ATTACK1HIT, + KNIFE_ATTACK1MISS, + KNIFE_ATTACK2MISS, + KNIFE_ATTACK2HIT, + KNIFE_ATTACK3MISS, + KNIFE_ATTACK3HIT, + KNIFE_IDLE2, + KNIFE_IDLE3 +}; + +void +w_knife_precache(void) +{ +#ifdef SERVER + precache_model("models/w_knife.mdl"); + precache_sound("weapons/knife1.wav"); + precache_sound("weapons/knife2.wav"); + precache_sound("weapons/knife3.wav"); + precache_sound("weapons/knife_hit_wall1.wav"); + precache_sound("weapons/knife_hit_wall2.wav"); + precache_sound("weapons/knife_hit_flesh1.wav"); + precache_sound("weapons/knife_hit_flesh2.wav"); +#else + precache_model("models/v_knife.mdl"); + precache_model("models/p_knife.mdl"); +#endif +} + +void +w_knife_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, -1, -1, -1); +} + +string +w_knife_wmodel(void) +{ + return "models/w_knife.mdl"; +} + +string +w_knife_pmodel(void) +{ + return "models/p_knife.mdl"; +} + +string +w_knife_deathmsg(void) +{ + return "%s was assaulted by %s's Knife."; +} + +void +w_knife_draw(void) +{ + Weapons_SetModel("models/v_knife.mdl"); + Weapons_ViewAnimation(KNIFE_DRAW); +} + +void +w_knife_holster(void) +{ + Weapons_ViewAnimation(KNIFE_HOLSTER); +} + +void +w_knife_primary(void) +{ + int anim = 0; + int r; + vector src; + player pl = (player)self; + + if (pl.w_attack_next) { + return; + } + + Weapons_MakeVectors(); + src = pl.origin + pl.view_ofs; + traceline(src, src + (v_forward * 32), FALSE, pl); + + if (trace_fraction >= 1.0) { + pl.w_attack_next = 0.5f; + } else { + pl.w_attack_next = 0.25f; + } + pl.w_idle_next = 2.5f; + +#ifdef CLIENT + r = (float)input_sequence % 3; + switch (r) { + case 0: + anim = trace_fraction >= 1 ? KNIFE_ATTACK1MISS:KNIFE_ATTACK1HIT; + break; + case 1: + anim = trace_fraction >= 1 ? KNIFE_ATTACK2MISS:KNIFE_ATTACK2HIT; + break; + default: + anim = trace_fraction >= 1 ? KNIFE_ATTACK3MISS:KNIFE_ATTACK3HIT; + } + Weapons_ViewAnimation(anim); +#else + if (pl.flags & FL_CROUCHING) { + Animation_PlayerTopTemp(ANIM_SHOOTCROWBAR, 0.5f); + } else { + Animation_PlayerTopTemp(ANIM_CR_SHOOTCROWBAR, 0.42f); + } + + r = (float)input_sequence % 3; + switch (r) { + case 0: + sound(pl, CHAN_WEAPON, "weapons/knife1.wav", 1, ATTN_NORM); + break; + case 1: + sound(pl, CHAN_WEAPON, "weapons/knife2.wav", 1, ATTN_NORM); + break; + default: + sound(pl, CHAN_WEAPON, "weapons/knife3.wav", 1, ATTN_NORM); + } + + if (trace_fraction >= 1.0) { + return; + } + + /* don't bother with decals, we got squibs */ + if (trace_ent.iBleeds) { + FX_Blood(trace_endpos, [1,0,0]); + } else { + FX_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal); + } + + if (trace_ent.takedamage) { + Damage_Apply(trace_ent, self, 10, WEAPON_KNIFE, DMG_SLASH); + + if (!trace_ent.iBleeds) { + return; + } + + if (random() < 0.5) { + sound(pl, 8, "weapons/knife_hit_flesh1.wav", 1, ATTN_NORM); + } else { + sound(pl, 8, "weapons/knife_hit_flesh2.wav", 1, ATTN_NORM); + } + } else { + if (random() < 0.5) { + sound(pl, 8, "weapons/knife_hit_wall1.wav", 1, ATTN_NORM); + } else { + sound(pl, 8, "weapons/knife_hit_wall2.wav", 1, ATTN_NORM); + } + } +#endif +} + +void +w_knife_release(void) +{ + int r; + player pl = (player)self; + + if (pl.w_idle_next) { + return; + } + + r = (float)input_sequence % 3; + switch (r) { + case 0: + Weapons_ViewAnimation(KNIFE_IDLE1); + pl.w_idle_next = 2.7f; + break; + case 1: + Weapons_ViewAnimation(KNIFE_IDLE2); + pl.w_idle_next = 5.3f; + break; + default: + Weapons_ViewAnimation(KNIFE_IDLE3); + pl.w_idle_next = 5.3f; + } +} + +float +w_knife_aimanim(void) +{ + return self.flags & FL_CROUCHING ? ANIM_CR_AIMCROWBAR : ANIM_AIMCROWBAR; +} + +void +w_knife_hudpic(int selected, vector pos, float a) +{ +#ifdef CLIENT + if (selected) { + drawsubpic( + pos, + [170,45], + "sprites/640hudof04.spr_0.tga", + [0,90/256], + [170/256,45/256], + g_hud_color, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [170,45], + "sprites/640hudof03.spr_0.tga", + [0,90/256], + [170/256,45/256], + g_hud_color, + a, + DRAWFLAG_ADDITIVE + ); + } +#endif +} + +weapon_t w_knife = +{ + .name = "knife", + .id = ITEM_KNIFE, + .slot = 0, + .slot_pos = 2, + .draw = w_knife_draw, + .holster = w_knife_holster, + .primary = w_knife_primary, + .secondary = __NULL__, + .reload = __NULL__, + .release = w_knife_release, + .crosshair = __NULL__, + .precache = w_knife_precache, + .pickup = __NULL__, + .updateammo = w_knife_updateammo, + .wmodel = w_knife_wmodel, + .pmodel = w_knife_pmodel, + .deathmsg = w_knife_deathmsg, + .aimanim = w_knife_aimanim, + .hudpic = w_knife_hudpic +}; + +/* entity definitions for pickups */ +#ifdef SERVER +void weapon_knife(void) +{ + Weapons_InitItem(WEAPON_KNIFE); +} +#endif diff --git a/src/shared/w_m249.qc b/src/shared/w_m249.qc new file mode 100644 index 0000000..c4c4832 --- /dev/null +++ b/src/shared/w_m249.qc @@ -0,0 +1,352 @@ +/* + * 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_m249 (0 0 1) (-16 -16 0) (16 16 32) +"model" "models/w_saw.mdl" + +HALF-LIFE: OPPOSING FORCE (1999) ENTITY + +M249 Weapon + +*/ + +/* Animations */ +enum +{ + M249_IDLE1, + M249_IDLE2, + M249_RELOAD1, + M249_RELOAD2, + M249_HOLSTER, + M249_DRAW, + M249_FIRE +}; + +void +w_m249_precache(void) +{ +#ifdef SERVER + precache_model("models/w_saw.mdl"); + precache_sound("weapons/saw_fire1.wav"); + precache_sound("weapons/saw_fire2.wav"); + precache_sound("weapons/saw_fire3.wav"); + precache_sound("weapons/saw_reload.wav"); + precache_sound("weapons/saw_reload2.wav"); +#else + precache_model("models/v_saw.mdl"); + precache_model("models/p_saw.mdl"); +#endif +} + +int +w_m249_pickup(int new, int startammo) +{ +#ifdef SERVER + player pl = (player)self; + + if (new) { + pl.m249_mag = 50; + } else { + if (pl.ammo_556 < MAX_A_556) { + pl.ammo_556 = bound(0, pl.ammo_556 + 50, MAX_A_556); + } else { + return FALSE; + } + } +#endif + return TRUE; +} + +void +w_m249_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, pl.m249_mag, pl.ammo_556, -1); +} + +string +w_m249_wmodel(void) +{ + return "models/w_saw.mdl"; +} + +string +w_m249_pmodel(void) +{ + return "models/p_saw.mdl"; +} + +string +w_m249_deathmsg(void) +{ + return ""; +} + +void +w_m249_draw(void) +{ +#ifdef CLIENT + Weapons_SetModel("models/v_saw.mdl"); + Weapons_ViewAnimation(M249_DRAW); +#endif +} + +void +w_m249_holster(void) +{ + Weapons_ViewAnimation(M249_DRAW); +} + +void +w_m249_release(void) +{ + player pl = (player)self; + + /* auto-reload if need be */ + if (pl.w_attack_next <= 0.0) + if (pl.m249_mag == 0 && pl.ammo_556 > 0) { + Weapons_Reload(); + return; + } + + if (pl.w_idle_next > 0.0) { + return; + } + + if (pl.mode_m249 == 1) { + Weapons_ViewAnimation(M249_RELOAD2); + pl.mode_m249 = 0; + pl.w_attack_next = 2.45f; + pl.w_idle_next = 15.0f; + return; + } + + if (random() < 0.5) { + Weapons_ViewAnimation(M249_IDLE1); + } else { + Weapons_ViewAnimation(M249_IDLE2); + } + + pl.w_idle_next = 15.0f; +} + +void +w_m249_primary(void) +{ + player pl = (player)self; + vector push; + + if (pl.mode_m249 == 1) { + w_m249_release(); + return; + } + + if (pl.w_attack_next > 0.0) { + return; + } + + /* ammo check */ +#ifdef CLIENT + if (pl.m249_mag <= 0) { + return; + } +#else + if (pl.m249_mag <= 0) { + return; + } +#endif + + Weapons_ViewAnimation(M249_FIRE); + + push = v_forward * -64; + push[2] *= 0.25f; /* gravity duh */ + pl.velocity += push; + + /* actual firing */ +#ifdef CLIENT + pl.m249_mag--; + View_SetMuzzleflash(MUZZLE_RIFLE); + Weapons_ViewPunchAngle([-5,0,0]); +#else + TraceAttack_FireBullets(1, pl.origin + pl.view_ofs, 8, [0.052,0.052], WEAPON_M249); + + int r = (float)input_sequence % 3; + switch (r) { + case 0: + Weapons_PlaySound(pl, CHAN_WEAPON, "weapons/saw_fire1.wav", 1, ATTN_NORM); + break; + case 1: + Weapons_PlaySound(pl, CHAN_WEAPON, "weapons/saw_fire2.wav", 1, ATTN_NORM); + break; + default: + Weapons_PlaySound(pl, CHAN_WEAPON, "weapons/saw_fire3.wav", 1, ATTN_NORM); + } + + pl.m249_mag--; +#endif + + pl.w_attack_next = 0.075f; + pl.w_idle_next = 10.0f; +} + +void +w_m249_reload(void) +{ + player pl = (player)self; + + if (pl.w_attack_next > 0.0) { + w_m249_release(); + return; + } + +#ifdef CLIENT + if (pl.m249_mag >= 50) { + return; + } + if (pl.ammo_556 <= 0) { + return; + } + Weapons_ViewAnimation(M249_RELOAD1); +#else + if (pl.m249_mag >= 50) { + return; + } + if (pl.ammo_556 <= 0) { + return; + } + Weapons_ReloadWeapon(pl, player::m249_mag, player::ammo_556, 50); + Weapons_UpdateAmmo(pl, pl.m249_mag, pl.ammo_556, __NULL__); +#endif + + pl.mode_m249 = 1; + pl.w_attack_next = pl.w_idle_next = 1.5f; +} + +void +w_m249_crosshair(void) +{ +#ifdef CLIENT + vector cross_pos; + vector aicon_pos; + + /* crosshair */ + cross_pos = g_hudmins + (g_hudres / 2) + [-12,-12]; + drawsubpic( + cross_pos, + [24,24], + "sprites/ofch1.spr_0.tga", + [24/72,0], + [24/72, 24/72], + [1,1,1], + 1.0, + DRAWFLAG_NORMAL + ); + + /* ammo counters */ + HUD_DrawAmmo1(); + HUD_DrawAmmo2(); + + /* ammo icon */ + aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42]; + drawsubpic( + aicon_pos, + [24,24], + "sprites/640hud7.spr_0.tga", + [24/128,72/128], + [24/256, 24/128], + g_hud_color, + pSeat->m_flAmmo2Alpha, + DRAWFLAG_ADDITIVE + ); +#endif +} + +float +w_m249_aimanim(void) +{ + return self.flags & ANIM_CR_AIMMP5 ? ANIM_CR_AIMCROWBAR : ANIM_AIMMP5; +} + +void +w_m249_hudpic(int selected, vector pos, float a) +{ +#ifdef CLIENT + player pl = (player)self; + vector hud_col; + + if (pl.m249_mag == 0 && pl.ammo_556 == 0) + hud_col = [1,0,0]; + else + hud_col = g_hud_color; + + HUD_DrawAmmoBar(pos, pl.ammo_556, MAX_A_556, a); + + if (selected) { + drawsubpic( + pos, + [170,45], + "sprites/640hudof02.spr_0.tga", + [0,135/256], + [170/256,45/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [170,45], + "sprites/640hudof01.spr_0.tga", + [0,135/256], + [170/256,45/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } +#endif +} + +weapon_t w_m249 = +{ + .name = "m249", + .id = ITEM_M249, + .slot = 5, + .slot_pos = 0, + .draw = w_m249_draw, + .holster = w_m249_holster, + .primary = w_m249_primary, + .secondary = __NULL__, + .reload = w_m249_reload, + .release = w_m249_release, + .crosshair = w_m249_crosshair, + .precache = w_m249_precache, + .pickup = w_m249_pickup, + .updateammo = w_m249_updateammo, + .wmodel = w_m249_wmodel, + .pmodel = w_m249_pmodel, + .deathmsg = w_m249_deathmsg, + .aimanim = w_m249_aimanim, + .hudpic = w_m249_hudpic +}; + +#ifdef SERVER +void +weapon_m249(void) +{ + Weapons_InitItem(WEAPON_M249); +} +#endif + diff --git a/src/shared/w_penguin.qc b/src/shared/w_penguin.qc new file mode 100644 index 0000000..e6a6096 --- /dev/null +++ b/src/shared/w_penguin.qc @@ -0,0 +1,375 @@ +/* + * 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_penguin (0 0 1) (-16 -16 0) (16 16 32) +"model" "models/w_penguin.mdl" + +HALF-LIFE: OPPOSING FORCE (1999) ENTITY + +Penguin Weapon + +*/ + +enum +{ + PENGUIN_IDLE, + PENGUIN_FIDGET1, + PENGUIN_FIDGET2, + PENGUIN_HOLSTER, + PENGUIN_DRAW, + PENGUIN_THROW +}; + +int +w_penguin_pickup(int new, int startammo) +{ +#ifdef SERVER + player pl = (player)self; + + if (pl.ammo_penguin < MAX_A_PENGUIN) { + pl.ammo_penguin = bound(0, pl.ammo_penguin + 3, MAX_A_PENGUIN); + } else { + return FALSE; + } +#endif + return TRUE; +} + +void +w_penguin_draw(void) +{ + Weapons_SetModel("models/v_penguin.mdl"); + Weapons_ViewAnimation(PENGUIN_DRAW); +} + +void +w_penguin_holster(void) +{ + +} + +#ifdef SERVER +void penguin_squeak(entity p) +{ + int r = floor(random(1,4)); + + switch (r) { + case 1: + sound(p, CHAN_VOICE, "squeek/sqk_hunt1.wav", 1.0, ATTN_NORM); + break; + case 2: + sound(p, CHAN_VOICE, "squeek/sqk_hunt2.wav", 1.0, ATTN_NORM); + break; + default: + sound(p, CHAN_VOICE, "squeek/sqk_hunt3.wav", 1.0, ATTN_NORM); + } +} + +void +penguin_ai(void) +{ + input_movevalues = [250,0,0]; + input_buttons = 0; + input_impulse = 0; + input_angles = self.angles; + input_timelength = frametime; + + if (self.health <= 0) { + return; + } + + if (self.weapon <= 0.0 && self.aiment == __NULL__) { + entity ef; + float shortest = 999999; + for (ef = world; (ef = findfloat(ef, movetype, MOVETYPE_WALK));) { + float len = vlen(ef.origin - self.origin); + if (ef.classname != "snark" && len < shortest && ef.health > 0) { + self.owner = __NULL__; + self.aiment = ef; + shortest = len; + } + } + } + + if (self.aiment) { + self.angles = input_angles = vectoangles(self.aiment.origin - self.origin); + } + + if (self.aiment && self.weapon <= 0.0) { + self.weapon = 0.5f + random(); + penguin_squeak(self); + input_buttons = 2; + Damage_Apply(self, world, 1, 0, DMG_GENERIC); + + makevectors(self.angles); + traceline(self.origin, self.origin + (v_forward * 128), 0, self); + + if (trace_ent.takedamage == DAMAGE_YES) { + float pit = 100 + random(0,10); + sound(self, CHAN_BODY, "squeek/sqk_deploy1.wav", 1.0, ATTN_NORM, pit); + Damage_Apply(trace_ent, self.goalentity, 10, WEAPON_PENGUIN, DMG_GENERIC); + } + + if (self.aiment.health <= 0) { + self.aiment = __NULL__; + } + } + self.weapon -= frametime; + runstandardplayerphysics(self); +} + +void +penguin_die(void) +{ + /* clear this first to avoid infinite recursion */ + self.health = 0; + + /* now we can explodededededed */ + FX_Explosion(self.origin); + Damage_Radius(self.origin, self.owner, 150, 150 * 2.5f, TRUE, WEAPON_PENGUIN); + + if (random() < 0.5) { + sound(self, 1, "weapons/explode3.wav", 1.0f, ATTN_NORM); + } else { + sound(self, 1, "weapons/explode4.wav", 1.0f, ATTN_NORM); + } + + remove(self); +} + +void +penguin_pain(void) +{ + /* add stuff? */ +} + +void +w_penguin_deploy(void) +{ + CBaseEntity pingu = spawn(CBaseEntity); + pingu.owner = self; + pingu.goalentity = self; + pingu.netname = "Penguin"; + pingu.classname = "snark"; /* so snarks and pingus don't attack e/o */ + setmodel(pingu, "models/w_penguin.mdl"); + makevectors(self.v_angle); + setorigin(pingu, self.origin + v_forward * 32); + pingu.solid = SOLID_BBOX; + pingu.movetype = MOVETYPE_WALK; + pingu.frame = 3; /* running like crazy. */ + pingu.customphysics = penguin_ai; + pingu.angles = self.angles; + pingu.health = 20; + pingu.Pain = penguin_pain; + pingu.takedamage = DAMAGE_YES; + pingu.aiment = __NULL__; + pingu.Death = penguin_die; + pingu.weapon = 3.0f; + penguin_squeak(pingu); +} +#endif + +void +w_penguin_primary(void) +{ + player pl = (player)self; + if (pl.w_attack_next > 0.0) { + return; + } + + /* Ammo check */ +#ifdef CLIENT + if (pl.ammo_penguin <= 0) { + return; + } +#else + if (pl.ammo_penguin <= 0) { + return; + } +#endif + + Weapons_ViewAnimation(PENGUIN_THROW); + + /* Audio-Visual Bit */ +#ifdef CLIENT + pl.ammo_penguin--; +#else + w_penguin_deploy(); + pl.ammo_penguin--; + Weapons_UpdateAmmo(pl, __NULL__, pl.ammo_penguin, __NULL__); + + if (pl.ammo_penguin <= 0) { + Weapons_RemoveItem(pl, WEAPON_SNARK); + } +#endif + + pl.w_idle_next = 2.0f; + pl.w_attack_next = 2.0f; + +} + +void +w_penguin_secondary(void) +{ + +} + +void +w_penguin_reload(void) +{ + +} + +void +w_penguin_release(void) +{ + int r; + player pl = (player)self; + if (pl.w_idle_next > 0.0) { + return; + } + + r = (float)input_sequence % 3; + switch (r) { + case 0: + Weapons_ViewAnimation(PENGUIN_IDLE); + pl.w_idle_next = 1.875f; + break; + case 1: + Weapons_ViewAnimation(PENGUIN_FIDGET1); + pl.w_idle_next = 4.375f; + break; + default: + Weapons_ViewAnimation(PENGUIN_FIDGET2); + pl.w_idle_next = 5.0f; + break; + } +} + +void +w_penguin_precache(void) +{ +#ifdef SERVER + precache_model("models/w_penguin.mdl"); + precache_sound("squeek/sqk_deploy1.wav"); + precache_sound("squeek/sqk_die1.wav"); + precache_sound("squeek/sqk_blast1.wav"); + precache_sound("squeek/sqk_hunt1.wav"); + precache_sound("squeek/sqk_hunt2.wav"); + precache_sound("squeek/sqk_hunt3.wav"); +#else + precache_model("models/p_penguin.mdl"); + precache_model("models/v_penguin.mdl"); +#endif +} + +void +w_penguin_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, -1, pl.ammo_penguin, -1); +} + +string +w_penguin_wmodel(void) +{ + return "models/w_penguinnest.mdl"; +} + +string +w_penguin_pmodel(void) +{ + return "models/p_penguin.mdl"; +} + +string +w_penguin_deathmsg(void) +{ + return ""; +} + + +float +w_penguin_aimanim(void) +{ + return self.flags & FL_CROUCHING ? ANIM_CR_AIMSQUEAK : ANIM_AIMSQUEAK; +} + +void +w_penguin_hud(void) +{ +#ifdef CLIENT + HUD_DrawAmmo2(); + vector aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42]; + drawsubpic(aicon_pos, [24,24], "sprites/640hud7.spr_0.tga", [144/256,72/128], [24/256, 24/128], g_hud_color, pSeat->m_flAmmo2Alpha, DRAWFLAG_ADDITIVE); +#endif +} + +void +w_penguin_hudpic(int s, vector pos, float a) +{ +#ifdef CLIENT + player pl = (player)self; + vector hud_col; + + if (pl.ammo_penguin == 0) + hud_col = [1,0,0]; + else + hud_col = g_hud_color; + + HUD_DrawAmmoBar(pos, pl.ammo_penguin, MAX_A_PENGUIN, a); + + if (s) { + drawsubpic(pos, [170,45], "sprites/640hudof04.spr_0.tga", + [0,180/256], [170/256,45/256], + hud_col, a, DRAWFLAG_ADDITIVE); + } else { + drawsubpic(pos, [170,45], "sprites/640hudof03.spr_0.tga", + [0,180/256], [170/256,45/256], + hud_col, a, DRAWFLAG_ADDITIVE); + } +#endif +} + +weapon_t w_penguin = +{ + .name = "penguin", + .id = ITEM_PENGUIN, + .slot = 4, + .slot_pos = 4, + .draw = w_penguin_draw, + .holster = w_penguin_holster, + .primary = w_penguin_primary, + .secondary = w_penguin_secondary, + .reload = w_penguin_reload, + .release = w_penguin_release, + .crosshair = w_penguin_hud, + .precache = w_penguin_precache, + .pickup = w_penguin_pickup, + .updateammo = w_penguin_updateammo, + .wmodel = w_penguin_wmodel, + .pmodel = w_penguin_pmodel, + .deathmsg = w_penguin_deathmsg, + .aimanim = w_penguin_aimanim, + .hudpic = w_penguin_hudpic +}; + +#ifdef SERVER +void +weapon_penguin(void) +{ + Weapons_InitItem(WEAPON_PENGUIN); +} +#endif diff --git a/src/shared/w_pipewrench.qc b/src/shared/w_pipewrench.qc new file mode 100644 index 0000000..c0562f0 --- /dev/null +++ b/src/shared/w_pipewrench.qc @@ -0,0 +1,350 @@ +/* + * 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_pipewrench (0 0 1) (-16 -16 0) (16 16 32) +"model" "models/w_pipe_wrench.mdl" + +HALF-LIFE: OPPOSING FORCE (1999) ENTITY + +Pipe-Wrench Weapon + +*/ + +enum +{ + PIPE_IDLE1, + PIPE_IDLE2, + PIPE_IDLE3, + PIPE_DRAW, + PIPE_HOLSTER, + PIPE_ATTACK1HIT, + PIPE_ATTACK1MISS, + PIPE_ATTACK2HIT, + PIPE_ATTACK2MISS, + PIPE_ATTACK3HIT, + PIPE_ATTACK3MISS, + PIPE_ATTACKBIGWIND, + PIPE_ATTACKBIGHIT, + PIPE_ATTACKBIGMISS, + PIPE_ATTACKBIGLOOP +}; + +void +w_pipewrench_precache(void) +{ +#ifdef SERVER + precache_sound("weapons/pwrench_big_miss.wav"); + precache_sound("weapons/pwrench_big_hit1.wav"); + precache_sound("weapons/pwrench_big_hit2.wav"); + precache_sound("weapons/pwrench_big_hitbod1.wav"); + precache_sound("weapons/pwrench_big_hitbod2.wav"); + precache_sound("weapons/pwrench_miss1.wav"); + precache_sound("weapons/pwrench_miss2.wav"); + precache_sound("weapons/pwrench_hit1.wav"); + precache_sound("weapons/pwrench_hit2.wav"); + precache_sound("weapons/pwrench_hitbod1.wav"); + precache_sound("weapons/pwrench_hitbod2.wav"); + precache_sound("weapons/pwrench_hitbod3.wav"); + precache_model("models/w_pipe_wrench.mdl"); +#else + precache_model("models/p_pipe_wrench.mdl"); + precache_model("models/v_pipe_wrench.mdl"); +#endif +} + +void +w_pipewrench_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, -1, -1, -1); +} + +string +w_pipewrench_wmodel(void) +{ + return "models/w_pipe_wrench.mdl"; +} + +string +w_pipewrench_pmodel(void) +{ + return "models/p_pipe_wrench.mdl"; +} + +string +w_pipewrench_deathmsg(void) +{ + return "%s was assaulted by %s's Pipewrench."; +} + +void +w_pipewrench_draw(void) +{ + Weapons_SetModel("models/v_pipe_wrench.mdl"); + Weapons_ViewAnimation(PIPE_DRAW); +} + +void +w_pipewrench_holster(void) +{ + Weapons_ViewAnimation(PIPE_HOLSTER); +} + +void +w_pipewrench_primary(void) +{ + int anim = 0; + vector src; + player pl = (player)self; + + if (pl.w_attack_next) { + return; + } + + Weapons_MakeVectors(); + src = Weapons_GetCameraPos(); + traceline(src, src + (v_forward * 32), FALSE, pl); + + if (trace_fraction >= 1.0) { + pl.w_attack_next = 0.7f; + } else { + pl.w_attack_next = 0.53f; + } + pl.w_idle_next = 2.5f; + +#ifdef CLIENT + int r = (float)input_sequence % 3; + switch (r) { + case 0: + anim = trace_fraction >= 1 ? PIPE_ATTACK1MISS:PIPE_ATTACK1HIT; + break; + case 1: + anim = trace_fraction >= 1 ? PIPE_ATTACK2MISS:PIPE_ATTACK2HIT; + break; + default: + anim = trace_fraction >= 1 ? PIPE_ATTACK3MISS:PIPE_ATTACK3HIT; + } + Weapons_ViewAnimation(anim); +#else + if (pl.flags & FL_CROUCHING) { + Animation_PlayerTopTemp(ANIM_SHOOTCROWBAR, 0.5f); + } else { + Animation_PlayerTopTemp(ANIM_CR_SHOOTCROWBAR, 0.42f); + } + + sound(pl, CHAN_WEAPON, "weapons/pwrench_miss1.wav", 1, ATTN_NORM); + + if (trace_fraction >= 1.0) { + return; + } + + /* don't bother with decals, we got squibs */ + if (trace_ent.iBleeds) { + FX_Blood(trace_endpos, [1,0,0]); + } else { + FX_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal); + } + + if (trace_ent.takedamage) { + Damage_Apply(trace_ent, self, 10, WEAPON_PIPEWRENCH, DMG_BLUNT); + + if (!trace_ent.iBleeds) { + return; + } + + if (random() < 0.33) { + sound(pl, 8, "weapons/pwrench_hitbod1.wav", 1, ATTN_NORM); + } else if (random() < 0.66) { + sound(pl, 8, "weapons/pwrench_hitbod2.wav", 1, ATTN_NORM); + } else { + sound(pl, 8, "weapons/pwrench_hitbod3.wav", 1, ATTN_NORM); + } + } else { + if (random() < 0.5) { + sound(pl, 8, "weapons/pwrench_hit1.wav", 1, ATTN_NORM); + } else { + sound(pl, 8, "weapons/pwrench_hit2.wav", 1, ATTN_NORM); + } + } +#endif +} + +void +w_pipewrench_secondary(void) +{ + player pl = (player)self; + + if (!pl.w_attack_next) { + /* Hack */ + if (pl.mode_wrench != 1) { + Weapons_ViewAnimation(PIPE_ATTACKBIGWIND); + pl.mode_wrench = 1; + pl.w_attack_next = 0.75f; + } + } + pl.w_idle_next = 2.5f; +} + +void +w_pipewrench_release(void) +{ + vector src; + player pl = (player)self; + + if (pl.w_attack_next > 0.0) { + return; + } + + if (pl.mode_wrench == 1) { + #ifdef SERVER + int hitsound = 0; + string snd; + #endif + /* attack! */ + Weapons_MakeVectors(); + src = Weapons_GetCameraPos(); + traceline(src, src + (v_forward * 64), FALSE, pl); + + if (trace_fraction < 1.0) { + #ifdef SERVER + if (trace_ent.takedamage == DAMAGE_YES) { + hitsound = floor(random(1, 2)); + /* TODO Damage is 45 - 200+ (?) */ + Damage_Apply(trace_ent, pl, 200, WEAPON_PIPEWRENCH, DMG_BLUNT); + } else { + hitsound = 3; + } + + /* don't bother with decals, we got squibs */ + if (trace_ent.iBleeds) { + FX_Blood(trace_endpos, [1,0,0]); + } else { + FX_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal); + } + #endif + Weapons_ViewAnimation(PIPE_ATTACKBIGHIT); + Weapons_ViewPunchAngle([-10,0,0]); + } else { + Weapons_ViewAnimation(PIPE_ATTACKBIGMISS); + } +#ifdef SERVER + snd = "weapons/pwrench_big_miss.wav"; + switch (hitsound) { + case 1: + snd = "weapons/pwrench_big_hitbod1.wav"; + break; + case 2: + snd = "weapons/pwrench_big_hitbod2.wav"; + break; + case 3: + snd = "weapons/pwrench_big_hit1.wav"; + break; + } + Weapons_PlaySound(pl, CHAN_WEAPON, snd, 1.0f, ATTN_NORM); +#endif + pl.w_attack_next = 1.0f; + pl.w_idle_next = 10.0f; + pl.mode_wrench = 0; + } + + /* Pure cosmetics start here */ + if (pl.w_idle_next > 0.0) { + return; + } + + int r = floor(random(0,3)); + switch (r) { + case 0: + Weapons_ViewAnimation(PIPE_IDLE1); + pl.w_idle_next = 2.0f; + break; + case 1: + Weapons_ViewAnimation(PIPE_IDLE2); + pl.w_idle_next = 3.0f; + break; + case 2: + Weapons_ViewAnimation(PIPE_IDLE3); + pl.w_idle_next = 3.0f; + break; + } +} + +float +w_pipewrench_aimanim(void) +{ + return self.flags & FL_CROUCHING ? ANIM_CR_AIMCROWBAR : ANIM_AIMCROWBAR; +} + +void +w_pipewrench_hudpic(int selected, vector pos, float a) +{ +#ifdef CLIENT + if (selected) { + drawsubpic( + pos, + [170,45], + "sprites/640hudof02.spr_0.tga", + [0,0], + [170/256,45/256], + g_hud_color, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [170,45], + "sprites/640hudof01.spr_0.tga", + [0,0], + [170/256,45/256], + g_hud_color, + a, + DRAWFLAG_ADDITIVE + ); + } +#endif +} + +weapon_t w_pipewrench = +{ + .name = "pipewrench", + .id = ITEM_PIPEWRENCH, + .slot = 0, + .slot_pos = 1, + .draw = w_pipewrench_draw, + .holster = w_pipewrench_holster, + .primary = w_pipewrench_primary, + .secondary = w_pipewrench_secondary, + .reload = w_pipewrench_release, + .release = w_pipewrench_release, + .crosshair = __NULL__, + .precache = w_pipewrench_precache, + .pickup = __NULL__, + .updateammo = w_pipewrench_updateammo, + .wmodel = w_pipewrench_wmodel, + .pmodel = w_pipewrench_pmodel, + .deathmsg = w_pipewrench_deathmsg, + .aimanim = w_pipewrench_aimanim, + .hudpic = w_pipewrench_hudpic +}; + +/* entity definitions for pickups */ +#ifdef SERVER +void +weapon_pipewrench(void) +{ + Weapons_InitItem(WEAPON_PIPEWRENCH); +} +#endif diff --git a/src/shared/w_shockrifle.qc b/src/shared/w_shockrifle.qc new file mode 100644 index 0000000..3869777 --- /dev/null +++ b/src/shared/w_shockrifle.qc @@ -0,0 +1,317 @@ +/* + * 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_shockrifle (0 0 1) (-16 -16 0) (16 16 32) +"model" "models/w_shock.mdl" + +HALF-LIFE: OPPOSING FORCE (1999) ENTITY + +Shockrifle Weapon + +*/ + +#ifdef CLIENT +var int PART_SHOCKPIECE; +#endif + +enum +{ + SHOCKRIFLE_IDLE1, + SHOCKRIFLE_SHOOT, + SHOCKRIFLE_DRAW, + SHOCKRIFLE_HOLSTER, + SHOCKRIFLE_IDLE2 +}; + +void +w_shockrifle_precache(void) +{ +#ifdef SERVER + precache_model("models/w_shock.mdl"); + precache_sound("weapons/shock_discharge.wav"); + precache_sound("weapons/shock_draw.wav"); + precache_sound("weapons/shock_fire.wav"); + precache_sound("weapons/shock_impact.wav"); + precache_sound("weapons/shock_recharge.wav"); +#else + PART_SHOCKPIECE = particleeffectnum("shockrifle.shockrifle_piece"); + precache_model("models/v_shock.mdl"); + precache_model("models/p_shock.mdl"); +#endif +} + +int +w_shockrifle_pickup(int new, int startammo) +{ +#ifdef SERVER + player pl = (player)self; + + /* only pick it up once */ + if (new) { + pl.ammo_shock = MAX_A_SHOCK; + return TRUE; + } +#endif + return FALSE; +} + +void +w_shockrifle_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, -1, pl.ammo_shock, -1); +} + +string +w_shockrifle_wmodel(void) +{ + return "models/w_shock.mdl"; +} + +string +w_shockrifle_pmodel(void) +{ + return "models/p_shock.mdl"; +} + +string +w_shockrifle_deathmsg(void) +{ + return ""; +} + +void +w_shockrifle_draw(void) +{ + Weapons_SetModel("models/v_shock.mdl"); + Weapons_ViewAnimation(SHOCKRIFLE_DRAW); +#ifdef SERVER + player pl = (player)self; + Weapons_UpdateAmmo(pl, -1, pl.ammo_shock, -1); +#endif +} + +void +w_shockrifle_holster(void) +{ + +} + +#ifdef SERVER +void +w_shockrifle_shoothornet(void) +{ + static void Hornet_Touch(void) { + if (other.takedamage == DAMAGE_YES) { + Damage_Apply(other, self.owner, 10, WEAPON_SHOCKRIFLE, DMG_ELECTRO); + } + + if (other.iBleeds) { + FX_Blood(trace_endpos, [1,0,0]); + } else { + FX_Spark(self.origin, trace_plane_normal); + } + remove(self); + } + Weapons_MakeVectors(); + entity bolt = spawn(); + //setmodel(bolt, "models/hornet.mdl"); + setorigin(bolt, Weapons_GetCameraPos() + (v_forward * 16) + (v_up * -8)); + bolt.owner = self; + bolt.velocity = v_forward * 1000; + bolt.movetype = MOVETYPE_FLY; + bolt.solid = SOLID_BBOX; + //bolt.flags |= FL_LAGGEDMOVE; + bolt.gravity = 0.5f; + bolt.angles = vectoangles(bolt.velocity); + bolt.touch = Hornet_Touch; + setsize(bolt, [0,0,0], [0,0,0]); +} +#endif + +void +w_shockrifle_release(void) +{ + player pl = (player)self; + + if (pl.w_idle_next > 0.0) { + return; + } + + if (pl.ammo_shock < MAX_A_SHOCK) { + pl.ammo_shock = bound(0, pl.ammo_shock + 1, MAX_A_SHOCK); + pl.w_idle_next = 0.35f; + } + + if (pl.w_idle_next > 0.0) { + return; + } + + if (random() < 0.5) { + Weapons_ViewAnimation(SHOCKRIFLE_IDLE1); + } else { + Weapons_ViewAnimation(SHOCKRIFLE_IDLE2); + } + + pl.w_idle_next = 3.333333f; +} + +void +w_shockrifle_primary(void) +{ + player pl = (player)self; + if (pl.w_attack_next > 0.0) { + return; + } + + /* Ammo check */ + if (pl.ammo_shock <= 0) { + w_shockrifle_release(); + return; + } + + +#ifdef SERVER + w_shockrifle_shoothornet(); + Weapons_PlaySound(pl, CHAN_WEAPON, "weapons/shock_fire.wav", 1, ATTN_NORM); + + pl.ammo_shock--; + Weapons_UpdateAmmo(pl, -1, pl.ammo_shock, -1); +#else + Weapons_MakeVectors(); + vector src = Weapons_GetCameraPos() + (v_forward * 16) + (v_up * -8); + pointparticles(PART_SHOCKPIECE, src, v_forward * 1000, 1); + pl.ammo_shock--; +#endif + + Weapons_ViewAnimation(SHOCKRIFLE_SHOOT); + pl.w_attack_next = 0.1f; + pl.w_idle_next = 0.5f; +} + +void +w_shockrifle_crosshair(void) +{ +#ifdef CLIENT + vector cross_pos; + vector aicon_pos; + + /* crosshair */ + cross_pos = g_hudmins + (g_hudres / 2) + [-12,-12]; + drawsubpic( + cross_pos, + [24,24], + "sprites/ofch1.spr_0.tga", + [0,24/72], + [24/72, 24/72], + [1,1,1], + 1.0, + DRAWFLAG_NORMAL + ); + + /* ammo counter */ + HUD_DrawAmmo2(); + + /* ammo icon */ + aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42]; + drawsubpic( + aicon_pos, + [24,24], + "sprites/640hud7.spr_0.tga", + [224/256,48/128], + [24/256, 24/128], + g_hud_color, + pSeat->m_flAmmo2Alpha, + DRAWFLAG_ADDITIVE + ); +#endif +} + +float +w_shockrifle_aimanim(void) +{ + return self.flags & FL_CROUCHING ? ANIM_CR_AIMHIVE : ANIM_AIMHIVE; +} + +void +w_shockrifle_hudpic(int selected, vector pos, float a) +{ +#ifdef CLIENT + player pl = (player)self; + vector hud_col; + + if (pl.ammo_shock == 0) + hud_col = [1,0,0]; + else + hud_col = g_hud_color; + + HUD_DrawAmmoBar(pos, pl.ammo_shock, MAX_A_SHOCK, a); + + if (selected) { + drawsubpic( + pos, + [170,45], + "sprites/640hudof04.spr_0.tga", + [0,45/256], + [170/256,45/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [170,45], + "sprites/640hudof03.spr_0.tga", + [0,45/256], + [170/256,45/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } +#endif +} + +weapon_t w_shockrifle = +{ + .name = "shockrifle", + .id = ITEM_SHOCKRIFLE, + .slot = 6, + .slot_pos = 1, + .draw = w_shockrifle_draw, + .holster = w_shockrifle_holster, + .primary = w_shockrifle_primary, + .secondary = w_shockrifle_release, + .reload = w_shockrifle_release, + .release = w_shockrifle_release, + .crosshair = w_shockrifle_crosshair, + .precache = w_shockrifle_precache, + .pickup = w_shockrifle_pickup, + .updateammo = w_shockrifle_updateammo, + .wmodel = w_shockrifle_wmodel, + .pmodel = w_shockrifle_pmodel, + .deathmsg = w_shockrifle_deathmsg, + .aimanim = w_shockrifle_aimanim, + .hudpic = w_shockrifle_hudpic +}; + +#ifdef SERVER +void +weapon_shockrifle(void) +{ + Weapons_InitItem(WEAPON_SHOCKRIFLE); +} +#endif diff --git a/src/shared/w_sniperrifle.qc b/src/shared/w_sniperrifle.qc new file mode 100644 index 0000000..6c9bf2d --- /dev/null +++ b/src/shared/w_sniperrifle.qc @@ -0,0 +1,327 @@ +/* + * 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_sniperrifle (0 0 1) (-16 -16 0) (16 16 32) +"model" "models/w_m40a1.mdl" + +HALF-LIFE: OPPOSING FORCE (1999) ENTITY + +Sniper-Rifle Weapon + +*/ + +enum +{ + SNIPER_DRAW, + SNIPER_IDLE1, + SNIPER_FIRE1, + SNIPER_FIRE2, + SNIPER_RELOAD1, + SNIPER_RELOAD2, + SNIPER_RELOAD3, + SNIPER_IDLE2, + SNIPER_HOLSTER, + SNIPER_DRAW +}; + +void +w_sniperrifle_precache(void) +{ +#ifdef SERVER + precache_model("models/w_m40a1.mdl"); + precache_sound("weapons/sniper_fire.wav"); +#else + precache_model("models/v_m40a1.mdl"); + precache_model("models/p_m40a1.mdl"); +#endif +} + +int +w_sniperrifle_pickup(int new, int startammo) +{ +#ifdef SERVER + player pl = (player)self; + + if (new) { + pl.sniper_mag = 5; + } else { + if (pl.ammo_762 < MAX_A_762) { + pl.ammo_762 = bound(0, pl.ammo_762 + 5, MAX_A_762); + } else { + return FALSE; + } + } +#endif + return TRUE; +} + +void +w_sniperrifle_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, pl.sniper_mag, pl.ammo_762, -1); +} + +string +w_sniperrifle_wmodel(void) +{ + return "models/w_m40a1.mdl"; +} + +string +w_sniperrifle_pmodel(void) +{ + return "models/p_m40a1.mdl"; +} + +string +w_sniperrifle_deathmsg(void) +{ + return ""; +} + +void +w_sniperrifle_draw(void) +{ + Weapons_SetModel("models/v_m40a1.mdl"); + Weapons_ViewAnimation(SNIPER_DRAW); +#ifdef SERVER + player pl = (player)self; + Weapons_UpdateAmmo(pl, pl.sniper_mag, pl.ammo_762, -1); +#endif +} + +void +w_sniperrifle_holster(void) +{ + Weapons_ViewAnimation(SNIPER_HOLSTER); +} + +void +w_sniperrifle_primary(void) +{ + player pl = (player)self; + if (pl.w_attack_next > 0.0) { + return; + } + + /* Ammo check */ +#ifdef CLIENT + if (pl.sniper_mag <= 0) { + return; + } +#else + if (pl.sniper_mag <= 0) { + return; + } +#endif + + /* Actual firing */ +#ifdef SERVER + TraceAttack_FireBullets(1, pl.origin + pl.view_ofs, 40, [0.00873, 0.00873], WEAPON_SNIPERRIFLE); + Weapons_PlaySound(pl, CHAN_WEAPON, "weapons/sniper_fire.wav", 1, ATTN_NORM); + + pl.sniper_mag--; + Weapons_UpdateAmmo(pl, pl.sniper_mag, pl.ammo_762, __NULL__); +#else + pl.sniper_mag--; + View_SetMuzzleflash(MUZZLE_SMALL); + Weapons_ViewPunchAngle([-10,0,0]); + + if (pl.sniper_mag) { + Weapons_ViewAnimation(SNIPER_FIRE1); + } else { + Weapons_ViewAnimation(SNIPER_FIRE2); + } +#endif + + pl.w_attack_next = 1.75f; + pl.w_idle_next = 10.0f; +} + +void +w_sniperrifle_secondary(void) +{ + player pl = (player)self; + if (pl.w_attack_next > 0.0) { + return; + } + /* Simple toggle of fovs */ + if (pl.viewzoom == 1.0f) { + pl.viewzoom = 0.25f; + } else { + pl.viewzoom = 1.0f; + } + pl.w_attack_next = 0.5f; +} + +void +w_sniperrifle_reload(void) +{ + player pl = (player)self; + if (pl.w_attack_next > 0.0) { + return; + } + + /* Ammo check */ +#ifdef CLIENT + if (pl.sniper_mag >= 5) { + return; + } + if (pl.ammo_762 <= 0) { + return; + } +#else + if (pl.sniper_mag >= 5) { + return; + } + if (pl.ammo_762 <= 0) { + return; + } +#endif + + /* Audio-Visual bit */ + /* TODO has a couple reloading states */ + Weapons_ViewAnimation(SNIPER_RELOAD1); +#ifdef SERVER + Weapons_ReloadWeapon(pl, player::sniper_mag, player::ammo_762, 5); + Weapons_UpdateAmmo(pl, pl.sniper_mag, pl.ammo_762, __NULL__); +#endif + pl.w_attack_next = 2.3f; + pl.w_idle_next = 10.0f; +} +void +w_sniperrifle_release(void) +{ + player pl = (player)self; + + /* auto-reload if need be */ + if (pl.w_attack_next <= 0.0) + if (pl.sniper_mag == 0 && pl.ammo_762 > 0) { + Weapons_Reload(); + return; + } + + if (pl.w_idle_next > 0.0) { + return; + } + + int r = (float)input_sequence % 2; + if (r == 1) { + Weapons_ViewAnimation(SNIPER_IDLE1); + } else { + Weapons_ViewAnimation(SNIPER_IDLE2); + } + pl.w_idle_next = 15.0f; +} +void +w_sniperrifle_crosshair(void) +{ +#ifdef CLIENT + player pl = (player)self; + static vector cross_pos; + + if (pl.viewzoom == 1.0f) { + cross_pos = g_hudmins + (g_hudres / 2) + [-12,-12]; + drawsubpic( + cross_pos, + [24,24], + "sprites/ofch1.spr_0.tga", + [0,48/72], + [24/72, 24/72], + [1,1,1], + 1, + DRAWFLAG_NORMAL + ); + } else { + cross_pos = g_hudmins + (g_hudres / 2) + [-128,-128]; + drawsubpic( + cross_pos, + [256,256], + "sprites/ofch2.spr_0.tga", + [0,0], + [1, 1], + [1,1,1], + 1, + DRAWFLAG_NORMAL + ); + } + + HUD_DrawAmmo1(); + HUD_DrawAmmo2(); + + vector aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42]; + drawsubpic(aicon_pos, [24,24], "sprites/640hud7.spr_0.tga", [24/256,72/128], [24/256, 24/128], g_hud_color, pSeat->m_flAmmo2Alpha, DRAWFLAG_ADDITIVE); +#endif +} + +float +w_sniperrifle_aimanim(void) +{ + return self.flags & FL_CROUCHING ? ANIM_CR_AIMPYTHON : ANIM_AIMPYTHON; +} + +void +w_sniperrifle_hudpic(int s, vector pos, float a) +{ +#ifdef CLIENT + player pl = (player)self; + vector hud_col; + + if (pl.sniper_mag == 0 && pl.ammo_762 == 0) + hud_col = [1,0,0]; + else + hud_col = g_hud_color; + + HUD_DrawAmmoBar(pos, pl.ammo_762, MAX_A_762, a); + + if (s) { + drawsubpic(pos, [170,45], "sprites/640hudof04.spr_0.tga", [0,135/256], [170/256,45/256], hud_col, a, DRAWFLAG_ADDITIVE); + } else { + drawsubpic(pos, [170,45], "sprites/640hudof03.spr_0.tga", [0,135/256], [170/256,45/256], hud_col, a, DRAWFLAG_ADDITIVE); + } +#endif +} + +weapon_t w_sniperrifle = +{ + .name = "sniperrifle", + .id = ITEM_SNIPERRIFLE, + .slot = 5, + .slot_pos = 2, + .draw = w_sniperrifle_draw, + .holster = w_sniperrifle_holster, + .primary = w_sniperrifle_primary, + .secondary = w_sniperrifle_secondary, + .reload = w_sniperrifle_reload, + .release = w_sniperrifle_release, + .crosshair = w_sniperrifle_crosshair, + .precache = w_sniperrifle_precache, + .pickup = w_sniperrifle_pickup, + .updateammo = w_sniperrifle_updateammo, + .wmodel = w_sniperrifle_wmodel, + .pmodel = w_sniperrifle_pmodel, + .deathmsg = w_sniperrifle_deathmsg, + .aimanim = w_sniperrifle_aimanim, + .hudpic = w_sniperrifle_hudpic +}; + +#ifdef SERVER +void +weapon_sniperrifle(void) +{ + Weapons_InitItem(WEAPON_SNIPERRIFLE); +} +#endif diff --git a/src/shared/w_sporelauncher.qc b/src/shared/w_sporelauncher.qc new file mode 100644 index 0000000..ad9acc9 --- /dev/null +++ b/src/shared/w_sporelauncher.qc @@ -0,0 +1,491 @@ +/* + * 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_sporelauncher (0 0 1) (-16 -16 0) (16 16 32) +"model" "models/w_spore_launcher.mdl" + +HALF-LIFE: OPPOSING FORCE (1999) ENTITY + +Sporelauncher Weapon + +*/ + +enum +{ + SPORE_IDLE1, + SPORE_FIDGET, + SPORE_RELOAD1, + SPORE_RELOAD2, + SPORE_RELOAD3, + SPORE_FIRE, + SPORE_HOLSTER, + SPORE_DRAW, + SPORE_IDLE2 +}; + +enum +{ + SLSTATE_IDLE, + SLSTATE_RELOAD_START, + SLSTATE_RELOAD, + SLSTATE_RELOAD_END +}; + +#ifdef SERVER +void Sporelauncher_Fire(entity spawner, vector org, vector dir) +{ + static void Spore_Touch(void) { + int r; + string hitsnd; + + if (other.takedamage == DAMAGE_YES) { + Damage_Apply(other, self.owner, 50, WEAPON_SPORELAUNCHER, DMG_GENERIC); + } else { + Decals_Place(self.origin, sprintf("{yblood%d", floor(random(1,7)))); + } + + r = floor(random(0,3)); + hitsnd = "weapons/spore_hit1.wav"; + switch (r) { + case 0: + hitsnd = "weapons/spore_hit2.wav"; + break; + case 1: + hitsnd = "weapons/spore_hit3.wav"; + break; + } + sound(self, CHAN_BODY, hitsnd, 1.0f, ATTN_NORM); + remove(self); + } + + entity blob = spawn(); + setmodel(blob, "models/spore.mdl"); + blob.owner = spawner; + blob.velocity = dir * 2000; + blob.movetype = MOVETYPE_BOUNCE; + blob.solid = SOLID_BBOX; + //bolt.flags |= FL_LAGGEDMOVE; + blob.gravity = 0.5f; + blob.angles = vectoangles(blob.velocity); + blob.avelocity[2] = 10; + blob.touch = Spore_Touch; + setsize(blob, [0,0,0], [0,0,0]); + setorigin(blob, org); + + sound(spawner, CHAN_WEAPON, "weapons/splauncher_fire.wav", 1, ATTN_NORM); +} +void Sporelauncher_AltFire(entity spawner, vector org, vector dir) +{ + static void Spore_Explode(void) { + int r; + string hitsnd; + + Damage_Radius(self.origin, self.owner, 100, 256, 1, WEAPON_SPORELAUNCHER); + r = floor(random(0,3)); + hitsnd = "weapons/spore_hit1.wav"; + switch (r) { + case 0: + hitsnd = "weapons/spore_hit2.wav"; + break; + case 1: + hitsnd = "weapons/spore_hit3.wav"; + break; + } + sound(self, CHAN_BODY, hitsnd, 1.0f, ATTN_NORM); + remove(self); + } + static void Spore_Touch(void) { + Decals_Place(self.origin, sprintf("{yblood%d", floor(random(1,7)))); + if (other.takedamage == DAMAGE_YES) { + Spore_Explode(); + } else if (self.think == __NULL__) { + self.think = Spore_Explode; + self.nextthink = time + 2.0f; + } + self.velocity *= 0.5f; + } + + entity blob = spawn(); + setmodel(blob, "models/spore.mdl"); + blob.owner = spawner; + blob.velocity = dir * 2000; + blob.movetype = MOVETYPE_BOUNCE; + blob.solid = SOLID_BBOX; + //bolt.flags |= FL_LAGGEDMOVE; + blob.gravity = 0.5f; + blob.angles = vectoangles(blob.velocity); + blob.avelocity[2] = 10; + blob.touch = Spore_Touch; + setsize(blob, [0,0,0], [0,0,0]); + setorigin(blob, org); + + sound(spawner, CHAN_WEAPON, "weapons/splauncher_fire.wav", 1, ATTN_NORM); +} +#endif + +void +w_sporelauncher_precache(void) +{ +#ifdef SERVER + precache_model("models/spore.mdl"); + precache_model("models/w_spore_launcher.mdl"); + precache_sound("weapons/splauncher_altfire.wav"); + precache_sound("weapons/splauncher_bounce.wav"); + precache_sound("weapons/splauncher_fire.wav"); + precache_sound("weapons/splauncher_impact.wav"); + precache_sound("weapons/splauncher_pet.wav"); + precache_sound("weapons/splauncher_reload.wav"); + precache_sound("weapons/spore_ammo.wav"); + precache_sound("weapons/spore_hit1.wav"); + precache_sound("weapons/spore_hit2.wav"); + precache_sound("weapons/spore_hit3.wav"); +#else + precache_model("models/v_spore_launcher.mdl"); + precache_model("models/p_spore_launcher.mdl"); +#endif + +} +void +w_sporelauncher_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, pl.sporelauncher_mag, pl.ammo_spore, -1); +} + +string +w_sporelauncher_wmodel(void) +{ + return "models/w_spore_launcher.mdl"; +} + +string +w_sporelauncher_pmodel(void) +{ + return "models/p_spore_launcher.mdl"; +} +string +w_sporelauncher_deathmsg(void) +{ + return ""; +} + +int +w_sporelauncher_pickup(int new, int startammo) +{ +#ifdef SERVER + player pl = (player)self; + + if (new) { + pl.sporelauncher_mag = 5; + } else { + if (pl.ammo_spore < MAX_A_SPORE) { + pl.ammo_spore = bound(0, pl.ammo_spore + 5, MAX_A_SPORE); + } else { + return FALSE; + } + } +#endif + return TRUE; +} + +void +w_sporelauncher_draw(void) +{ +#ifdef CLIENT + Weapons_SetModel("models/v_spore_launcher.mdl"); + Weapons_ViewAnimation(SPORE_DRAW); +#else + player pl = (player)self; + Weapons_UpdateAmmo(pl, pl.sporelauncher_mag, pl.ammo_spore, -1); +#endif +} + +void +w_sporelauncher_holster(void) +{ + Weapons_ViewAnimation(SPORE_HOLSTER); +} + +void +w_sporelauncher_primary(void) +{ + player pl = (player)self; + + if (pl.w_attack_next > 0.0) { + return; + } + +#ifdef SERVER + if (pl.sporelauncher_mag <= 0) { + return; + } + + Weapons_MakeVectors(); + Sporelauncher_Fire(self, Weapons_GetCameraPos() + (v_forward * 16), v_forward); + + pl.sporelauncher_mag--; + Weapons_UpdateAmmo(pl, pl.sporelauncher_mag, pl.ammo_spore, -1); +#else + if (pl.sporelauncher_mag <= 0) { + return; + } + + Weapons_ViewPunchAngle([-2,0,0]); + Weapons_ViewAnimation(SPORE_FIRE); +#endif + + pl.w_attack_next = 0.75f; + pl.w_idle_next = 10.0f; +} + +void +w_sporelauncher_secondary(void) +{ + player pl = (player)self; + + if (pl.w_attack_next > 0.0) { + return; + } + +#ifdef SERVER + if (pl.sporelauncher_mag <= 0) { + return; + } + + Weapons_MakeVectors(); + Sporelauncher_AltFire(self, Weapons_GetCameraPos() + (v_forward * 16), v_forward); + + pl.sporelauncher_mag--; + Weapons_UpdateAmmo(pl, pl.sporelauncher_mag, pl.ammo_spore, -1); +#else + if (pl.sporelauncher_mag <= 0) { + return; + } + + Weapons_ViewPunchAngle([-2,0,0]); + Weapons_ViewAnimation(SPORE_FIRE); +#endif + + pl.w_attack_next = 0.75f; + pl.w_idle_next = 10.0f; +} + +void w_sporelauncher_release(void) +{ + player pl = (player)self; + + /* auto-reload if need be */ + if (pl.w_attack_next <= 0.0) + if (pl.mode_sporelauncher == SLSTATE_IDLE && pl.sporelauncher_mag == 0 && pl.ammo_spore > 0) { + Weapons_Reload(); + return; + } + + if (pl.w_idle_next > 0.0) { + return; + } + + if (pl.mode_sporelauncher == SLSTATE_IDLE) { + int r = (float)input_sequence % 3; + switch (r) { + case 0: + Weapons_ViewAnimation(SPORE_IDLE1); + pl.w_idle_next = 2.0f; + break; + case 1: + Weapons_ViewAnimation(SPORE_FIDGET); + pl.w_idle_next = 4.0f; + break; + case 2: + Weapons_ViewAnimation(SPORE_IDLE2); + pl.w_idle_next = 4.0f; + break; + } + } else if (pl.mode_sporelauncher == SLSTATE_RELOAD_START) { + Weapons_ViewAnimation(SPORE_RELOAD1); + pl.mode_sporelauncher = SLSTATE_RELOAD; + pl.w_idle_next = 0.65f; + } else if (pl.mode_sporelauncher == SLSTATE_RELOAD) { + Weapons_ViewAnimation(SPORE_RELOAD2); +#ifdef CLIENT + pl.sporelauncher_mag++; + pl.ammo_spore--; + + if (pl.ammo_spore <= 0 || pl.sporelauncher_mag >= 5) { + pl.mode_sporelauncher = SLSTATE_RELOAD_END; + } +#else + pl.sporelauncher_mag++; + pl.ammo_spore--; + + if (pl.ammo_spore <= 0 || pl.sporelauncher_mag >= 5) { + pl.mode_sporelauncher = SLSTATE_RELOAD_END; + } +#endif + pl.w_idle_next = 1.0f; + } else if (pl.mode_sporelauncher == SLSTATE_RELOAD_END) { + Weapons_ViewAnimation(SPORE_RELOAD3); + + pl.mode_sporelauncher = SLSTATE_IDLE; + pl.w_idle_next = 10.0f; + pl.w_attack_next = 0.5f; + } +} + +void +w_sporelauncher_reload(void) +{ + player pl = (player)self; + +#ifdef CLIENT + if (pl.sporelauncher_mag >= 5) { + return; + } + if (pl.ammo_spore <= 0) { + return; + } +#else + if (pl.sporelauncher_mag >= 5) { + return; + } + if (pl.ammo_spore <= 0) { + return; + } +#endif + + if (pl.mode_sporelauncher > SLSTATE_IDLE) { + return; + } + + pl.mode_sporelauncher = SLSTATE_RELOAD_START; + pl.w_idle_next = 0.0f; +} + +void +w_sporelauncher_crosshair(void) +{ +#ifdef CLIENT + vector cross_pos; + vector aicon_pos; + + /* crosshair */ + cross_pos = g_hudmins + (g_hudres / 2) + [-12,-12]; + drawsubpic( + cross_pos, + [24,24], + "sprites/ofch1.spr_0.tga", + [24/72,24/72], + [24/72,24/72], + [1,1,1], + 1.0, + DRAWFLAG_NORMAL + ); + + /* ammo counters */ + HUD_DrawAmmo1(); + HUD_DrawAmmo2(); + + /* ammo icon */ + aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42]; + drawsubpic( + aicon_pos, + [24,24], + "sprites/640hud7.spr_0.tga", + [200/256,48/128], + [24/256, 24/128], + g_hud_color, + pSeat->m_flAmmo2Alpha, + DRAWFLAG_ADDITIVE + ); +#endif +} + +float +w_sporelauncher_aimanim(void) +{ + return self.flags & FL_CROUCHING ? ANIM_CR_AIMBOW : ANIM_AIMBOW; +} + +void +w_sporelauncher_hudpic(int selected, vector pos, float a) +{ +#ifdef CLIENT + player pl = (player)self; + vector hud_col; + + if (pl.sporelauncher_mag == 0 && pl.ammo_spore == 0) + hud_col = [1,0,0]; + else + hud_col = g_hud_color; + + HUD_DrawAmmoBar(pos, pl.ammo_spore, MAX_A_SPORE, a); + + if (selected) { + drawsubpic( + pos, + [170,45], + "sprites/640hudof04.spr_0.tga", + [0,0], + [170/256,45/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [170,45], + "sprites/640hudof03.spr_0.tga", + [0,0], + [170/256,45/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } +#endif +} + +weapon_t w_sporelauncher = +{ + .name = "sporelauncher", + .id = ITEM_SPORELAUNCHER, + .slot = 6, + .slot_pos = 0, + .draw = w_sporelauncher_draw, + .holster = w_sporelauncher_holster, + .primary = w_sporelauncher_primary, + .secondary = w_sporelauncher_secondary, + .reload = w_sporelauncher_reload, + .release = w_sporelauncher_release, + .crosshair = w_sporelauncher_crosshair, + .precache = w_sporelauncher_precache, + .pickup = w_sporelauncher_pickup, + .updateammo = w_sporelauncher_updateammo, + .wmodel = w_sporelauncher_wmodel, + .pmodel = w_sporelauncher_pmodel, + .deathmsg = w_sporelauncher_deathmsg, + .aimanim = w_sporelauncher_aimanim, + .hudpic = w_sporelauncher_hudpic +}; + +#ifdef SERVER +void +weapon_sporelauncher(void) +{ + Weapons_InitItem(WEAPON_SPORELAUNCHER); +} +#endif + diff --git a/src/shared/weapons.h b/src/shared/weapons.h new file mode 100644 index 0000000..5d08d6e --- /dev/null +++ b/src/shared/weapons.h @@ -0,0 +1,65 @@ +/* + * 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. + */ + +/* Weapon Indices for the weapon table */ +enum +{ + WEAPON_NONE, + WEAPON_CROWBAR, + WEAPON_PIPEWRENCH, + WEAPON_KNIFE, + WEAPON_GRAPPLE, + WEAPON_GLOCK, + WEAPON_PYTHON, + WEAPON_EAGLE, + WEAPON_MP5, + WEAPON_SHOTGUN, + WEAPON_CROSSBOW, + WEAPON_RPG, + WEAPON_GAUSS, + WEAPON_EGON, + WEAPON_HORNETGUN, + WEAPON_HANDGRENADE, + WEAPON_SATCHEL, + WEAPON_TRIPMINE, + WEAPON_SNARK, + WEAPON_PENGUIN, + WEAPON_M249, + WEAPON_DISPLACER, + WEAPON_SNIPERRIFLE, + WEAPON_SPORELAUNCHER, + WEAPON_SHOCKRIFLE +}; + +#define MAX_A_9MM 250 +#define MAX_A_357 36 +#define MAX_A_BUCKSHOT 125 +#define MAX_A_M203_GRENADE 10 +#define MAX_A_BOLT 50 +#define MAX_A_ROCKET 5 +#define MAX_A_URANIUM 100 +#define MAX_A_HANDGRENADE 10 +#define MAX_A_SATCHEL 5 +#define MAX_A_TRIPMINE 10 +#define MAX_A_SNARK 10 +#define MAX_A_HORNET 8 + +/* gearbox */ +#define MAX_A_556 200 +#define MAX_A_PENGUIN 9 +#define MAX_A_SHOCK 10 +#define MAX_A_762 15 +#define MAX_A_SPORE 20 diff --git a/src/shared/weapons.qc b/src/shared/weapons.qc new file mode 100644 index 0000000..f7d2a3f --- /dev/null +++ b/src/shared/weapons.qc @@ -0,0 +1,44 @@ +/* + * 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_pipewrench, + w_knife, + w_grapple, + w_glock, + w_python, + w_eagle, + w_mp5, + w_shotgun, + w_crossbow, + w_rpg, + w_gauss, + w_egon, + w_hornetgun, + w_handgrenade, + w_satchel, + w_tripmine, + w_snark, + w_penguin, + w_m249, + w_displacer, + w_sniperrifle, + w_sporelauncher, + w_shockrifle +}; diff --git a/zpak001.pk3dir/default.cfg b/zpak001.pk3dir/default.cfg new file mode 100755 index 0000000..fd2712e --- /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" "Opposing Force Server" +name "Shephard" +model shephard +seta "maxplayers" "8" + +// 2D/HUD Variables +seta "con_color" "0 255 0" +seta "vgui_color" "0 255 0" +seta "cross_color" "0 255 0" diff --git a/zpak001.pk3dir/particles/shockrifle.cfg b/zpak001.pk3dir/particles/shockrifle.cfg new file mode 100755 index 0000000..b8f93f4 --- /dev/null +++ b/zpak001.pk3dir/particles/shockrifle.cfg @@ -0,0 +1,17 @@ +r_part shockrifle_piece +{ + type texturedspark + texture ball + tcoords 1 65 31 95 256 8 32 + scale 1 + count 8 + scalefactor 1 + alpha 0.5 + die 25 + rgb 0 255 255 + blend add + spawnmode ball + spawnorg 1 + friction 0.5 + gravity 0 +} diff --git a/zpak001.pk3dir/scripts/map_blacklist b/zpak001.pk3dir/scripts/map_blacklist new file mode 100644 index 0000000..c25e3c9 --- /dev/null +++ b/zpak001.pk3dir/scripts/map_blacklist @@ -0,0 +1,45 @@ +of0a0.bsp +of1a1.bsp +of1a2.bsp +of1a3.bsp +of1a4b.bsp +of1a4.bsp +of1a5b.bsp +of1a5.bsp +of1a6.bsp +of2a1b.bsp +of2a1.bsp +of2a2.bsp +of2a3.bsp +of2a4.bsp +of2a5.bsp +of2a6.bsp +of3a1b.bsp +of3a1.bsp +of3a2.bsp +of3a4.bsp +of3a5.bsp +of3a6.bsp +of4a1.bsp +of4a2.bsp +of4a3.bsp +of4a4.bsp +of4a5.bsp +of5a1.bsp +of5a2.bsp +of5a3.bsp +of5a4.bsp +of6a1.bsp +of6a2.bsp +of6a3.bsp +of6a4b.bsp +of6a4.bsp +of6a5.bsp +of7a0.bsp +ofboot0.bsp +ofboot1.bsp +ofboot2.bsp +ofboot3.bsp +ofboot4.bsp +of2a5dmo.bsp +of5a3dmo.bsp