diff --git a/base/src/shared/include.src b/base/src/shared/include.src index 4e84be95..e553d040 100644 --- a/base/src/shared/include.src +++ b/base/src/shared/include.src @@ -16,6 +16,11 @@ fx_impact.qc items.h weapons.h + +weapon_basesemi.qc +weapon_baseshotgun.qc +weapon_baseautomatic.qc + weapons.qc weapon_common.qc input.qc diff --git a/base/src/shared/player.qc b/base/src/shared/player.qc index 1979e33f..65788325 100644 --- a/base/src/shared/player.qc +++ b/base/src/shared/player.qc @@ -45,6 +45,8 @@ enumflags noref int input_sequence; class player:base_player { + PREDICTED_INT(mode_tempstate); + #ifdef CLIENT /* External model */ entity p_model; diff --git a/base/src/shared/weapon_baseautomatic.qc b/base/src/shared/weapon_baseautomatic.qc new file mode 100644 index 00000000..81d95844 --- /dev/null +++ b/base/src/shared/weapon_baseautomatic.qc @@ -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. + */ + +enum +{ + AUTO_FIRE_FAILED, + AUTO_FIRED, + AUTO_LAST, + AUTO_EMPTY +}; + +int +w_baseauto_fire(int w, .int mag, int d) +{ + player pl = (player)self; + + if (pl.w_attack_next > 0.0) { + return (AUTO_FIRE_FAILED); + } + if (pl.gflags & GF_SEMI_TOGGLED) { + return (AUTO_FIRE_FAILED); + } + if (pl.(mag) <= 0) { + pl.gflags |= GF_SEMI_TOGGLED; + return (AUTO_EMPTY); + } + + pl.(mag)--; + +#ifdef SERVER + TraceAttack_FireBullets(1, pl.origin + pl.view_ofs, d, [0.1,0.1], w); +#endif + + if (pl.(mag) == 0) + return (AUTO_LAST); + else + return (AUTO_FIRED); +} diff --git a/base/src/shared/weapon_basemelee.qc b/base/src/shared/weapon_basemelee.qc new file mode 100644 index 00000000..282ada75 --- /dev/null +++ b/base/src/shared/weapon_basemelee.qc @@ -0,0 +1,43 @@ +enum +{ + MELEE_FAILED, + MELEE_MISS, + MELEE_HIT, + MELEE_HITBODY +}; + +int +w_basemelee_fire(int d, int w) +{ + int anim = 0; + vector src; + player pl = (player)self; + + if (pl.w_attack_next > 0.0) { + return (MELEE_FAILED); + } + + Weapons_MakeVectors(); + src = pl.origin + pl.view_ofs; + + /* make sure we can gib corpses */ + int oldhitcontents = self.hitcontentsmaski; + self.hitcontentsmaski = CONTENTBITS_POINTSOLID | CONTENTBIT_CORPSE; + traceline(src, src + (v_forward * 32), FALSE, pl); + self.hitcontentsmaski = oldhitcontents; + + pl.w_attack_next = 0.5f; + pl.w_idle_next = 2.5f; + + if (trace_fraction >= 1.0) { + return (MELEE_MISS); + } + +#ifdef SERVER + if (trace_ent.takedamage) { + Damage_Apply(trace_ent, pl, d, w, DMG_BLUNT); + } +#endif + + return (MELEE_HIT); +} diff --git a/base/src/shared/weapon_baseprojectile.qc b/base/src/shared/weapon_baseprojectile.qc new file mode 100644 index 00000000..e715ccd8 --- /dev/null +++ b/base/src/shared/weapon_baseprojectile.qc @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016-2021 Marco Hladik + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +enum +{ + SEMI_FIRE_FAILED, + SEMI_FIRED, + SEMI_LAST, + SEMI_EMPTY +}; + +int +w_baseprojectile_fire(int w, .int mag, void() spawnfunc) +{ + player pl = (player)self; + + if (pl.w_attack_next > 0.0) { + return (SEMI_FIRE_FAILED); + } + if (pl.gflags & GF_SEMI_TOGGLED) { + return (SEMI_FIRE_FAILED); + } + if (pl.(mag) <= 0) { + return (SEMI_EMPTY); + } + + pl.(mag)--; + +#ifdef SERVER + spawnfunc(); +#endif + + if (pl.(mag) == 0) + return (SEMI_LAST); + else + return (SEMI_FIRED); +} diff --git a/base/src/shared/weapon_basesemi.qc b/base/src/shared/weapon_basesemi.qc new file mode 100644 index 00000000..94c955f5 --- /dev/null +++ b/base/src/shared/weapon_basesemi.qc @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2016-2021 Marco Hladik + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +enum +{ + SEMI_FIRE_FAILED, + SEMI_FIRED, + SEMI_LAST, + SEMI_EMPTY +}; + +int +w_basesemi_fire(int w, .int mag, int d) +{ + player pl = (player)self; + + if (pl.w_attack_next > 0.0) { + return (SEMI_FIRE_FAILED); + } + if (pl.gflags & GF_SEMI_TOGGLED) { + return (SEMI_FIRE_FAILED); + } + if (pl.(mag) <= 0) { + pl.gflags |= GF_SEMI_TOGGLED; + return (SEMI_EMPTY); + } + + pl.(mag)--; + +#ifdef SERVER + TraceAttack_FireBullets(1, pl.origin + pl.view_ofs, d, [0,0,0], w); +#endif + + pl.gflags |= GF_SEMI_TOGGLED; + + if (pl.(mag) == 0) + return (SEMI_LAST); + else + return (SEMI_FIRED); +} diff --git a/base/src/shared/weapon_baseshotgun.qc b/base/src/shared/weapon_baseshotgun.qc new file mode 100644 index 00000000..1ce1fa41 --- /dev/null +++ b/base/src/shared/weapon_baseshotgun.qc @@ -0,0 +1,123 @@ +/* + * 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. + */ + +enum +{ + SHOTGUN_FIRE_FAILED, + SHOTGUN_FIRED, + SHOTGUN_LAST, + SHOTGUN_EMPTY +}; + +int +w_baseshotgun_fire(int w, .int mag, int c, int d, vector bs) +{ + player pl = (player)self; + + if (pl.w_attack_next > 0.0) { + return (SHOTGUN_FIRE_FAILED); + } + if (pl.gflags & GF_SEMI_TOGGLED) { + return (SHOTGUN_FIRE_FAILED); + } + if (pl.(mag) <= 0) { + pl.gflags |= GF_SEMI_TOGGLED; + return (SHOTGUN_EMPTY); + } + + pl.(mag)--; + +#ifdef SERVER + TraceAttack_FireBullets(c, pl.origin + pl.view_ofs, d, bs, w); +#endif + + pl.gflags |= GF_SEMI_TOGGLED; + + if (pl.(mag) == 0) + return (SHOTGUN_LAST); + else + return (SHOTGUN_FIRED); +} + +enum +{ + SHOTTY_IDLE, + SHOTTY_RELOAD_START, + SHOTTY_RELOAD, + SHOTTY_RELOAD_END, + SHOTTY_COCKSOUND +}; + +void +w_baseshotgun_reload(.int mag, .int ammo, int max) +{ + player pl = (player)self; + + if (pl.(mag) >= max) { + return; + } + if (pl.(ammo) <= 0) { + return; + } + if (pl.mode_tempstate > SHOTTY_IDLE) { + return; + } + + pl.mode_tempstate = SHOTTY_RELOAD_START; + pl.w_idle_next = 0.0f; +} + +enum +{ + SHOTGUN_IDLE, + SHOTGUN_BUSY, + SHOTGUN_START_RELOAD, + SHOTGUN_RELOAD, + SHOTGUN_END_RELOAD +}; + +int +w_baseshotgun_release(.int mag, .int ammo, int max) +{ + player pl = (player)self; + + if (pl.w_idle_next > 0.0) { + return (SHOTGUN_BUSY); + } + + if (pl.mode_tempstate == SHOTTY_RELOAD_START) { + pl.mode_tempstate = SHOTTY_RELOAD; + pl.w_idle_next = 0.65f; + return (SHOTGUN_START_RELOAD); + } else if (pl.mode_tempstate == SHOTTY_RELOAD) { + pl.(mag)++; + pl.(ammo)--; + + if (pl.(ammo) <= 0 || pl.(mag) >= max) { + pl.mode_tempstate = SHOTTY_RELOAD_END; + } + Weapons_UpdateAmmo(pl, pl.(mag), pl.(ammo), pl.mode_tempstate); + pl.w_idle_next = 0.5f; + return (SHOTGUN_RELOAD); + } else if (pl.mode_tempstate == SHOTTY_RELOAD_END) { + pl.mode_tempstate = SHOTTY_IDLE; + pl.w_idle_next = 10.0f; + pl.w_attack_next = 0.5f; + return (SHOTGUN_END_RELOAD); + } + + return (SHOTGUN_IDLE); +}