commit 49189c008d78116550c36bde59d18691326feb0c Author: Marco Cawthorne Date: Mon Sep 25 00:42:05 2023 -0700 Initial commit, first day of work. 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/cmds.qc b/src/client/cmds.qc new file mode 100644 index 0000000..580af92 --- /dev/null +++ b/src/client/cmds.qc @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016-2020 Marco Cawthorne + * + * 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 VGUI_ChooseClass(float); + +int +ClientGame_ConsoleCommand(void) +{ + switch(argv(0)) { + default: + return (0); + } + return (1); +} diff --git a/src/client/defs.h b/src/client/defs.h new file mode 100644 index 0000000..ec1305d --- /dev/null +++ b/src/client/defs.h @@ -0,0 +1,2 @@ + +font_s FONT_HUD_CROSS; \ No newline at end of file diff --git a/src/client/draw.qc b/src/client/draw.qc new file mode 100644 index 0000000..5d6502e --- /dev/null +++ b/src/client/draw.qc @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016-2021 Marco Cawthorne + * + * 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 +ClientGame_PreDraw(void) +{ +} + +void +ClientGame_PostDraw(void) +{ + +} diff --git a/src/client/flashlight.qc b/src/client/flashlight.qc new file mode 100644 index 0000000..e2ae45e --- /dev/null +++ b/src/client/flashlight.qc @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2016-2020 Marco Cawthorne + * + * 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 +Player_Flashlight(NSClientPlayer pl) +{ + +} diff --git a/src/client/hud.qc b/src/client/hud.qc new file mode 100644 index 0000000..9f2fec2 --- /dev/null +++ b/src/client/hud.qc @@ -0,0 +1,612 @@ +/* + * Copyright (c) 2016-2021 Marco Cawthorne + * + * 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 HUD_DrawWeaponSelect(void); + +/* Use first frame for drawing (needs precache) */ +#define NUMSIZE_X 20/256 +#define NUMSIZE_Y 28/64 +#define HUD_ALPHA 0.75 + +float spr_hudnum[10] = { + 2 / 256, + 22 / 256, + 42 / 256, + 62 / 256, + 82 / 256, + 102 / 256, + 122 / 256, + 142 / 256, + 162 / 256, + 182 / 256 +}; + +float spr_hudnum_small[12] = { + 0 / 256, + 10 / 256, + 20 / 256, + 30 / 256, + 40 / 256, + 50 / 256, + 60 / 256, + 70 / 256, + 80 / 256, + 90 / 256, + 100 / 256, + 110 / 256 +}; + +/* pre-calculated sprite definitions */ +float spr_health[4] = { + 163 / 256, // pos x + 29 / 64, // pos u + 48 / 256, // size x + 16 / 64 // size y +}; + +float spr_armor[4] = { + 223 / 256, // pos x + 28 / 64, // pos u + 32 / 256, // size x + 16 / 64 // size y +}; + +float spr_ammo[4] = { + 120 / 256, // pos x + 28 / 64, // pos u + 32 / 256, // size x + 16 / 64 // size y +}; + +float spr_flash1[4] = { + 160 / 256, // pos x + 24 / 128, // pos u + 32 / 256, // size x + 32 / 128 // size y +}; + +float spr_flash2[4] = { + 112 / 256, // pos x + 24 / 128, // pos u + 48 / 256, // size x + 32 / 128 // size y +}; + +/* precaches */ +void +HUD_Init(void) +{ + Font_Load("fonts/hud_cross.font", FONT_HUD_CROSS); + g_cross_spr = spriteframe("sprites/crosshairs.spr", 0, 0.0f); + g_laser_spr = spriteframe("sprites/laserdot.spr", 0, 0.0f); + g_hud1_spr = "materials/Sprites/hud1"; + g_hud2_spr = "materials/Sprites/hud1"; + g_hud3_spr = "materials/Sprites/hud1"; + g_hud4_spr = "materials/Sprites/hud1"; + g_hud5_spr = "materials/Sprites/hud1"; + g_hud6_spr = "materials/Sprites/hud1"; + g_hud7_spr = "materials/Sprites/hud1"; + HUD_AmmoNotify_Init(); + HUD_DamageNotify_Init(); + HUD_ItemNotify_Init(); +} + +/* seperator for mainly ammo */ +void +HUD_DrawSeperator(vector pos) +{ + drawsubpic(pos, + [10,28], + g_hud7_spr, + [240/256, 0.0], + [10/256, 28/64], + g_hud_color, + 1.0, + DRAWFLAG_ADDITIVE + ); +} + +/* handle single/multiple digits */ +void +HUD_DrawNumber(int iNumber, vector vecPos, float fAlpha, vector vColor) +{ + drawsubpic(vecPos, + [20,28], + g_hud7_spr, + [spr_hudnum[iNumber], 0], + [NUMSIZE_X, NUMSIZE_Y], + vColor, + fAlpha, + DRAWFLAG_ADDITIVE + ); +} + +void +HUD_DrawNumberS(int iNumber, vector vecPos, float fAlpha, vector vColor) +{ + drawsubpic(vecPos, + [10,12], + g_hud7_spr, + [spr_hudnum_small[iNumber], 29/64], + [10/256, 12/64], + vColor, + fAlpha, + DRAWFLAG_ADDITIVE + ); +} + +void +HUD_DrawAmmoSeparator(vector vecPos) +{ + drawsubpic(vecPos, + [10,28], + g_hud7_spr, + [240/256, 0.0], + [10/256, 28/256], + g_hud_color, + 1.0, + DRAWFLAG_ADDITIVE + ); +} + +void +HUD_DrawNums(float fNumber, vector vecPos, float fAlpha, vector vColor) +{ + int i = fNumber; + + /* always draw 3 digits */ + for (int x = 0; x < 3; x++) { + int b = (float)i % 10; + + /* don't allow anything below 0 */ + if (b < 0) + b = 0; + + /* if we're a zero, but a leading one... */ + if (b == 0) + if ((fNumber < 100 && x == 2) || (fNumber < 10 && x == 1) || (fNumber == 0)) + fAlpha = 0.25f; + + if (x == 1) { + drawsubpic(vecPos, + [20,28], + g_hud7_spr, + [220/256, 0.0], + [NUMSIZE_X, NUMSIZE_Y], + vColor, + fAlpha, + DRAWFLAG_ADDITIVE + ); + } else if (x == 2) { + drawsubpic(vecPos, + [20,28], + g_hud7_spr, + [200/256, 0.0], + [NUMSIZE_X, NUMSIZE_Y], + vColor, + fAlpha, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic(vecPos, + [20,28], + g_hud7_spr, + [200/256, 0.0], + [NUMSIZE_X, NUMSIZE_Y], + vColor, + fAlpha, + DRAWFLAG_ADDITIVE + ); + } + + HUD_DrawNumber(b, vecPos, fAlpha, vColor); + + i = i / 10; + vecPos[0] -= 20; + } +} + +void +HUD_DrawNumsS(float fNumber, vector vecPos, float fAlpha, vector vColor) +{ + int i = fNumber; + + /* always draw 3 digits */ + for (int x = 0; x < 3; x++) { + int b = (float)i % 10; + + /* don't allow anything below 0 */ + if (b < 0) + b = 0; + + /* if we're a zero, but a leading one... */ + if (b == 0) + if ((fNumber < 100 && x == 2) || (fNumber < 10 && x == 1) || (fNumber == 0)) + fAlpha = 0.25f; + + if (x == 1) { + drawsubpic(vecPos, + [10,12], + g_hud7_spr, + [spr_hudnum_small[11], 29/64], + [10/256, 12/64], + vColor, + fAlpha, + DRAWFLAG_ADDITIVE + ); + } else if (x == 2) { + drawsubpic(vecPos, + [10,12], + g_hud7_spr, + [spr_hudnum_small[10], 29/64], + [10/256, 12/64], + vColor, + fAlpha, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic(vecPos, + [10,12], + g_hud7_spr, + [spr_hudnum_small[10], 29/64], + [10/256, 12/64], + vColor, + fAlpha, + DRAWFLAG_ADDITIVE + ); + } + + HUD_DrawNumberS(b, vecPos, fAlpha, vColor); + + i = i / 10; + vecPos[0] -= 10; + } +} + +/* health */ +void +HUD_DrawHealth(void) +{ + vector pos; + player pl = (player)pSeat->m_ePlayer; + + if (pl.health != pSeatLocal->m_iHealthOld) { + pSeatLocal->m_flHealthAlpha = 1.0; + } + + if (pSeatLocal->m_flHealthAlpha >= HUD_ALPHA) { + pSeatLocal->m_flHealthAlpha -= clframetime * 0.5; + } else { + pSeatLocal->m_flHealthAlpha = HUD_ALPHA; + } + + pos = g_hudmins + [16, g_hudres[1] - 42]; + if (pl.health > 25) { + drawsubpic( + pos + [0,-14], + [48,16], + g_hud7_spr, + [spr_health[0], spr_health[1]], + [spr_health[2], spr_health[3]], + g_hud_color, + pSeatLocal->m_flHealthAlpha, + DRAWFLAG_ADDITIVE + ); + HUD_DrawNums(pl.health, pos + [40, 0], pSeatLocal->m_flHealthAlpha, g_hud_color); + } else { + drawsubpic( + pos + [-72,-14], + [48,16], + g_hud7_spr, + [spr_health[0], spr_health[1]], + [spr_health[2], spr_health[3]], + [1,0,0], + pSeatLocal->m_flHealthAlpha, + DRAWFLAG_ADDITIVE + ); + HUD_DrawNums(pl.health, pos + [40, 0], pSeatLocal->m_flHealthAlpha, [1,0,0]); + } + + pSeatLocal->m_iHealthOld = pl.health; +} + +/* armor/suit charge */ +void +HUD_DrawArmor(void) +{ + vector pos; + player pl = (player)pSeat->m_ePlayer; + + if (pl.armor != pSeatLocal->m_iArmorOld) { + pSeatLocal->m_flArmorAlpha = 1.0; + } + + if (pSeatLocal->m_flArmorAlpha >= HUD_ALPHA) { + pSeatLocal->m_flArmorAlpha -= clframetime * 0.5; + } else { + pSeatLocal->m_flArmorAlpha = HUD_ALPHA; + } + + pos = g_hudmins + [16+96, g_hudres[1] - 42]; + if (pl.armor > 25) { + drawsubpic( + pos + [0,-14], + [32,16], + g_hud7_spr, + [spr_armor[0], spr_armor[1]], + [spr_armor[2], spr_armor[3]], + g_hud_color, + pSeatLocal->m_flArmorAlpha, + DRAWFLAG_ADDITIVE + ); + HUD_DrawNums(pl.armor, pos + [40, 0], pSeatLocal->m_flArmorAlpha, g_hud_color); + } else { + drawsubpic( + pos + [-72,-14], + [32,16], + g_hud7_spr, + [spr_armor[0], spr_armor[1]], + [spr_armor[2], spr_armor[3]], + [1,0,0], + pSeatLocal->m_flArmorAlpha, + DRAWFLAG_ADDITIVE + ); + HUD_DrawNums(pl.armor, pos + [40, 0], pSeatLocal->m_flArmorAlpha, [1,0,0]); + } + + pSeatLocal->m_iArmorOld = pl.armor; +} + +/* magazine/clip ammo */ +void +HUD_DrawAmmo1(void) +{ + player pl = (player)pSeat->m_ePlayer; + vector pos; + + if (pl.a_ammo1 != pSeatLocal->m_iAmmo1Old) { + pSeatLocal->m_flAmmo1Alpha = 1.0; + pSeatLocal->m_iAmmo1Old = pl.a_ammo1; + } + + if (pSeatLocal->m_flAmmo1Alpha >= HUD_ALPHA) { + pSeatLocal->m_flAmmo1Alpha -= clframetime * 0.5; + } else { + pSeatLocal->m_flAmmo1Alpha = HUD_ALPHA; + } + + pos = g_hudmins + [g_hudres[0] - 152, g_hudres[1] - 42]; + + drawsubpic( + pos + [-38,-14], + [32,16], + g_hud7_spr, + [spr_ammo[0], spr_ammo[1]], + [spr_ammo[2], spr_ammo[3]], + g_hud_color, + pSeatLocal->m_flArmorAlpha, + DRAWFLAG_ADDITIVE + ); + + HUD_DrawNums(pl.a_ammo1, pos, pSeatLocal->m_flAmmo1Alpha, g_hud_color); + HUD_DrawSeperator(pos + [30,0]); +} + +/* leftover type ammo */ +void +HUD_DrawAmmo2(void) +{ + player pl = (player)pSeat->m_ePlayer; + vector pos; + + if (pl.a_ammo2 != pSeatLocal->m_iAmmo2Old) { + pSeatLocal->m_flAmmo2Alpha = 1.0; + pSeatLocal->m_iAmmo2Old = pl.a_ammo2; + } + + if (pSeatLocal->m_flAmmo2Alpha >= HUD_ALPHA) { + pSeatLocal->m_flAmmo2Alpha -= clframetime * 0.5; + } else { + pSeatLocal->m_flAmmo2Alpha = HUD_ALPHA; + } + + pos = g_hudmins + [g_hudres[0] - 80, g_hudres[1] - 42 + 5]; + HUD_DrawNumsS(pl.a_ammo2, pos, pSeatLocal->m_flAmmo2Alpha, g_hud_color); +} + +/* special ammo */ +void +HUD_DrawAmmo3(void) +{ + player pl = (player)pSeat->m_ePlayer; + vector pos; + + if (pl.a_ammo3 != pSeatLocal->m_iAmmo3Old) { + pSeatLocal->m_flAmmo3Alpha = 1.0; + pSeatLocal->m_iAmmo3Old = pl.a_ammo3; + } + + if (pSeatLocal->m_flAmmo3Alpha >= HUD_ALPHA) { + pSeatLocal->m_flAmmo3Alpha -= clframetime * 0.5; + } else { + pSeatLocal->m_flAmmo3Alpha = HUD_ALPHA; + } + + pos = g_hudmins + [g_hudres[0] - 42, g_hudres[1] - 42 + 5]; + HUD_DrawNumsS(pl.a_ammo3, pos, pSeatLocal->m_flAmmo3Alpha, g_hud_color); +} + +/* ammo bar */ +void +HUD_DrawAmmoBar(vector pos, float val, float max, float a) +{ + if (val <= 0) + return; + + float perc; + perc = val / max; + //drawfill(pos + [10,0], [20,4], g_hud_color, a, DRAWFLAG_NORMAL); + //drawfill(pos + [10,0], [20 * perc,4], [0,1,0], a, DRAWFLAG_NORMAL); +} + +/* weapon/ammo pickup notifications */ +void +HUD_DrawNotify(void) +{ + player pl = (player)self; + vector pos; + float a; + + pos = g_hudmins + [g_hudres[0] - 150, g_hudres[1] - 128]; + + if (pSeatLocal->m_flPickupAlpha <= 0.0f) { + pos[1] += 48; + //HUD_ItemNotify_Draw(pos); + //HUD_AmmoNotify_Draw(pos); + return; + } + + a = bound(0.0, pSeatLocal->m_flPickupAlpha, 1.0); + pos[1] += 48 * (1.0 - a); + Weapons_HUDPic(pl, pSeatLocal->m_iPickupWeapon, 1, pos, a); + //HUD_ItemNotify_Draw(pos); + //HUD_AmmoNotify_Draw(pos); + pSeatLocal->m_flPickupAlpha -= (clframetime * 0.5); +} + +void +HUD_WeaponPickupNotify(int w) +{ +#if defined (VALVE) || defined (GEARBOX) + switch (w) { + case WEAPON_SNARK: + case WEAPON_SATCHEL: + case WEAPON_HANDGRENADE: + case WEAPON_TRIPMINE: +#if defined(GEARBOX) + case WEAPON_PENGUIN: +#endif + return; + default: + } +#endif + + pSeatLocal->m_iPickupWeapon = w; + pSeatLocal->m_flPickupAlpha = 2.5f; +} + +void +HUD_DrawDamageIndicator(void) +{ + vector cross_pos; + + if (pSeatLocal->m_flDamageIndicator <= 0.0) + return; + + cross_pos = g_hudmins + (g_hudres / 2) + [-12,-12]; + + /*drawsubpic( + cross_pos, + [24,24], + g_cross_spr, + [0.0, 72/128], + [0.1875, 0.1875], + [1,1,1] * pSeatLocal->m_flDamageIndicator, + 1.0f, + DRAWFLAG_ADDITIVE + );*/ + + pSeatLocal->m_flDamageIndicator -= clframetime; +} + +void +HUD_TimeRemaining(void) +{ + vector iconPos = g_hudmins + [16, g_hudres[1] - 64]; + + /* display time if timelimit is being hit */ + if (serverkeyfloat("timelimit")) { + string tempstr = strcat("Time Remaining: ", Util_GetTime()); + Font_DrawText_RGB(iconPos, tempstr, g_hud_color, FONT_20); + } +} + +/* main entry */ +void +HUD_Draw(void) +{ + player pl = (player)pSeat->m_ePlayer; + + g_hud_color = [1, 0.75f, 0.25]; + + /* little point in not drawing these, even if you don't have a suit */ + Weapons_DrawCrosshair(pl); + + { + + } + + HUD_DrawDamageIndicator(); + HUD_DrawWeaponSelect(); + Obituary_Draw(); + Textmenu_Draw(); + + HUD_TimeRemaining(); + + if (!(pl.g_items & ITEM_SUIT)) { + return; + } + + HUD_DamageNotify_Draw(); + HUD_DrawHealth(); + HUD_DrawArmor(); + HUD_DrawNotify(); + Damage_Draw(); +} + +string g_specmodes[] = { + "Free Camera", + "Third Person", + "First Person" +}; + +/* specatator main entry */ +void +HUD_DrawSpectator(void) +{ + Textmenu_Draw(); + + NSClientSpectator spec = (NSClientSpectator)pSeat->m_ePlayer; + + drawfont = Font_GetID(FONT_20); + vector vecPos = [0.0f, 0.0f, 0.0f]; + string strText = __NULL__; + float palpha = 1.0f; + + if (spec.spec_mode == SPECMODE_FREE) { + palpha = 0.5f; + } + + strText = sprintf("Tracking: %s", getplayerkeyvalue(spec.spec_ent - 1, "name")); + vecPos[0] = g_hudmins[0] + (g_hudres[0] / 2) - (stringwidth(strText, TRUE, [20,20]) / 2); + vecPos[1] = g_hudmins[1] + g_hudres[1] - 60; + drawstring(vecPos, strText, [20,20], [1,1,1], palpha, DRAWFLAG_ADDITIVE); + + strText = sprintf("Mode: %s", g_specmodes[spec.spec_mode]); + vecPos[0] = g_hudmins[0] + (g_hudres[0] / 2) - (stringwidth(strText, TRUE, [20,20]) / 2); + vecPos[1] = g_hudmins[1] + g_hudres[1] - 40; + drawstring(vecPos, strText, [20,20], [1,1,1], 1.0f, DRAWFLAG_ADDITIVE); +} diff --git a/src/client/hud_weaponselect.qc b/src/client/hud_weaponselect.qc new file mode 100644 index 0000000..63ed7ef --- /dev/null +++ b/src/client/hud_weaponselect.qc @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2016-2020 Marco Cawthorne + * + * 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] = +{ + [46 / 256,44 / 64], + [66 / 256,44 / 64], + [87 / 256,44 / 64], + [109 / 256,44 / 64], + [131 / 256,44 / 64], + [153 / 256,44 / 64], + [175 / 256,44 / 64], + [197 / 256,44 / 64], +}; + +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_Num2(vector vecPos, float fValue) +{ + drawsubpic(vecPos, [16,16], g_hud7_spr, [24/256, 44/64], [16/256, 16/64], g_hud_color, 1, DRAWFLAG_ADDITIVE); + + drawsubpic(vecPos, [16,16], g_hud7_spr, g_vecHUDNums[fValue], [16/255, 16/64], g_hud_color, 1, DRAWFLAG_ADDITIVE); +} + +void +HUD_DrawWeaponSelect_Num(vector vecPos, float fValue) +{ + drawsubpic(vecPos, [16,16], g_hud7_spr, g_vecHUDNums[fValue], [16/255, 16/64], 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 < 6; i++) { + int slot_selected = 0; + vecPos[1] = g_hudmins[1] + 16; + + + if (i == wantslot) + HUD_DrawWeaponSelect_Num2(vecPos, i); + else + 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(pl, pSeat->m_iHUDWeaponSelected, 1, vecPos, 1.0f); + Weapons_HUDPic(pl, pSeat->m_iHUDWeaponSelected, 1, vecPos, 1.0f); + vecPos[1] += 64; + } else if ((b=HUD_InSlotPos(i, x)) != -1) { + // Unselected Sprite + Weapons_HUDPic(pl, b, 0, vecPos, 1.0f); + vecPos[1] += 64; + } + } else if (HUD_InSlotPos(i, x) != -1) { + HUD_DrawWeaponSelect_Num(vecPos, 7); + vecPos[1] += 25; + } + } + + if (slot_selected == TRUE) { + vecPos[0] += 128; + } else { + vecPos[0] += 25; + } + } +} diff --git a/src/client/init.qc b/src/client/init.qc new file mode 100644 index 0000000..b0ee883 --- /dev/null +++ b/src/client/init.qc @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016-2020 Marco Cawthorne + * + * 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; +void VGUI_ChooseTeam(void); + +/* +================= +ClientGame_Init + +Comparable to worldspawn in SSQC in that it's mostly used for precaches +================= +*/ +void +ClientGame_Init(float apilevel, string enginename, float engineversion) +{ + registercommand("changeteam"); + registercommand("changeclass"); + Obituary_Init(); +} + +void +ClientGame_InitDone(void) +{ +} + +void HLSprite_Init(void); +void +ClientGame_RendererRestart(string rstr) +{ + Obituary_Precache(); + Damage_Precache(); + + FX_Blood_Init(); + + /* there's also muzzleflash.spr, but that's just MUZZLE_SMALL again */ + MUZZLE_RIFLE = (int)getmodelindex("sprites/muzzleflash1.spr"); + MUZZLE_SMALL = (int)getmodelindex("sprites/muzzleflash2.spr"); + MUZZLE_WEIRD = (int)getmodelindex("sprites/muzzleflash3.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..c3b5516 --- /dev/null +++ b/src/client/progs.src @@ -0,0 +1,46 @@ +#pragma target fte_5768 +//#pragma flag enable assumeint +#pragma progs_dat "../../csprogs.dat" + +#define CSQC +#define CLIENT +#define HL2 + +#includelist +../../../src/shared/fteextensions.qc +../../../src/shared/defs.h +../../../valve/src/client/defs.h +../../../src/client/defs.h +defs.h + +../../../src/vgui/include.src + +../../../src/gs-entbase/client.src +../../../src/gs-entbase/shared.src +../shared/include.src + +flashlight.qc +../../../valve/src/client/damage.qc +draw.qc +init.qc +../../../valve/src/client/entities.qc +cmds.qc +../../../valve/src/client/game_event.qc +../../../valve/src/client/camera.qc +viewmodel.qc +../../../valve/src/client/view.qc +../../../valve/src/client/obituary.qc +../../../valve/src/client/hud_sprite.qc +../../../valve/src/client/hud_ammonotify.qc +../../../valve/src/client/hud_dmgnotify.qc +../../../valve/src/client/hud_itemnotify.qc +hud.qc +hud_weaponselect.qc +../../../valve/src/client/scoreboard.qc +../../../valve/src/client/modelevent.qc + +../../../src/client/include.src +vgui_changechar.qc +vgui_chooseteam.qc +../../../src/shared/include.src +#endlist diff --git a/src/client/vgui_changechar.qc b/src/client/vgui_changechar.qc new file mode 100644 index 0000000..746aeb0 --- /dev/null +++ b/src/client/vgui_changechar.qc @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2016-2020 Marco Cawthorne + * + * 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. + */ + +static string g_charDescrAdrian; +static string g_charDescrBarney; +static string g_charDescrCivRandom; +static string g_charDescrCleansuit; +static string g_charDescrDrillsgt; +static string g_charDescrGina; +static string g_charDescrGordon; +static string g_charDescrGrunt; +static string g_charDescrRandom; +static string g_charDescrOtis; +static string g_charDescrTandom; +static string g_charDescrRecruit; +static string g_charDescrScientist; +static string g_charDescrSquadleader; +static string g_charDescrTower; + +static void +OP4Char_Init(void) +{ + g_charDescrAdrian = textfile_to_string("classes/short_adrian.txt"); + g_charDescrBarney = textfile_to_string("classes/short_barney.txt"); + g_charDescrCivRandom = textfile_to_string("classes/short_civ_random.txt"); + g_charDescrCleansuit = textfile_to_string("classes/short_cleansuit.txt"); + g_charDescrDrillsgt = textfile_to_string("classes/short_drillsgt.txt"); + g_charDescrGina = textfile_to_string("classes/short_gina.txt"); + g_charDescrGordon = textfile_to_string("classes/short_gordon.txt"); + g_charDescrGrunt = textfile_to_string("classes/short_grunt.txt"); + g_charDescrRandom = textfile_to_string("classes/short_op4_random.txt"); + g_charDescrOtis = textfile_to_string("classes/short_otis.txt"); + g_charDescrTandom = textfile_to_string("classes/short_random.txt"); + g_charDescrRecruit = textfile_to_string("classes/short_recruit.txt"); + g_charDescrScientist = textfile_to_string("classes/short_scientist.txt"); + g_charDescrSquadleader = textfile_to_string("classes/short_squadleader.txt"); + g_charDescrTower = textfile_to_string("classes/short_tower.txt"); + +} + +static VGUIWindow winCharSelection; +static VGUIPic imgCharPreview; +static VGUILabel lblCharTitle; +static VGUILabel lblCharDescription; +static VGUILabel lblCharCounter; + +class OP4CharButton:VGUIButton +{ + void OP4CharButton(void); + + virtual void OnMouseUp(void); + virtual void OnMouseEntered(void); +}; + +void +OP4CharButton::OP4CharButton(void) +{ +} + +void +OP4CharButton::OnMouseUp(void) +{ + int classSelection = GetTag(); + sendevent("ClassJoin", "f", (float)classSelection); + winCharSelection.Hide(); +} + +void +OP4CharButton::OnMouseEntered(void) +{ + int classSelection = GetTag(); + + switch (classSelection) { + case 1: + lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_Barney")); + imgCharPreview.SetImage("gfx/vgui/640_barney"); + lblCharDescription.SetTitle(g_charDescrBarney); + break; + case 2: + lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_Cleansuit")); + imgCharPreview.SetImage("gfx/vgui/640_cleansuit"); + lblCharDescription.SetTitle(g_charDescrCleansuit); + break; + case 3: + lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_Gina")); + imgCharPreview.SetImage("gfx/vgui/640_gina"); + lblCharDescription.SetTitle(g_charDescrGina); + break; + case 4: + lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_Gordon")); + imgCharPreview.SetImage("gfx/vgui/640_gordon"); + lblCharDescription.SetTitle(g_charDescrGordon); + break; + case 5: + lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_Otis")); + imgCharPreview.SetImage("gfx/vgui/640_otis"); + lblCharDescription.SetTitle(g_charDescrOtis); + break; + case 6: + lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_Scientist")); + imgCharPreview.SetImage("gfx/vgui/640_scientist"); + lblCharDescription.SetTitle(g_charDescrScientist); + break; + case 0: + lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_Civ_Random")); + imgCharPreview.SetImage("gfx/vgui/640_civ_random"); + lblCharDescription.SetTitle(g_charDescrCivRandom); + break; + + case 7: + lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_SquadLeader")); + imgCharPreview.SetImage("gfx/vgui/640_squadleader"); + lblCharDescription.SetTitle(g_charDescrSquadleader); + break; + case 8: + lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_DrillSgt")); + imgCharPreview.SetImage("gfx/vgui/640_drillsgt"); + lblCharDescription.SetTitle(g_charDescrDrillsgt); + break; + case 9: + lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_Grunt")); + imgCharPreview.SetImage("gfx/vgui/640_grunt"); + lblCharDescription.SetTitle(g_charDescrGrunt); + break; + case 10: + lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_Recruit")); + imgCharPreview.SetImage("gfx/vgui/640_recruit"); + lblCharDescription.SetTitle(g_charDescrRecruit); + break; + case 11: + lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_Adrian")); + imgCharPreview.SetImage("gfx/vgui/640_adrian"); + lblCharDescription.SetTitle(g_charDescrAdrian); + break; + case 12: + lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_Tower")); + imgCharPreview.SetImage("gfx/vgui/640_tower"); + lblCharDescription.SetTitle(g_charDescrTower); + break; + case 13: + lblCharTitle.SetTitle(Titles_GetTextBody("CTFTitle_Op4_Random")); + imgCharPreview.SetImage("gfx/vgui/640_op4_random"); + lblCharDescription.SetTitle(g_charDescrTandom); + break; + } +} + + +/* +Char/Char list: + +Barney +CleansuitSci +Gina +Freeman +Otis +Walter(Scientist) +Random + +Squad Leader +Drill Sgt +Grunt +Recruit +Shepard +Tower +OP4Random +*/ + +string g_classnames_blackmesa [] = { + "Barney", + "Cleansuit", + "Gina", + "Gordon", + "Otis", + "Scientist", + "Civ_Random" +}; + +string g_classnames_opfor [] = { + "SquadLeader", + "DrillSgt", + "Grunt", + "Recruit", + "Adrian", + "Tower", + "Op4_Random" +}; + +void +VGUI_ChooseClass(float teamChoice) +{ + static int initialized; + static OP4CharButton *btns; + static VGUILabel lblSelectChar; + static VGUIFrame frmCharInfo; + + if (!teamChoice) + teamChoice = getplayerkeyfloat(player_localnum, "*team"); + + if (!initialized) { + vector btnpos = [40,80]; + initialized = TRUE; + + OP4Char_Init(); + + winCharSelection = spawn(VGUIWindow); + winCharSelection.SetSize([640, 480]); + winCharSelection.SetStyleMask(VGUIWindowBorderless | VGUIWindowFullscreen); + + lblSelectChar = spawn(VGUILabel); + lblSelectChar.SetTitle(Titles_GetTextBody("CTFTitle_SelectYourCharacter")); + lblSelectChar.SetTextSize(19); + lblSelectChar.SetPos([40, 38]); + lblSelectChar.SetSize([400, 24]); + + frmCharInfo = spawn(VGUIFrame); + frmCharInfo.SetPos([176, 80]); + frmCharInfo.SetSize([424, 312]); + + imgCharPreview = spawn(VGUIPic); + imgCharPreview.SetPos([190, 90]); + + lblCharTitle = spawn(VGUILabel); + lblCharTitle.SetPos([338, 90]); + lblCharTitle.SetTextSize(19); + lblCharTitle.SetSize([320, 24]); + + lblCharCounter = spawn(VGUILabel); + lblCharCounter.SetPos([338, 90 + 32]); + lblCharCounter.SetSize([320, 18]); + + lblCharDescription = spawn(VGUILabel); + lblCharDescription.SetPos([338, 90 + 32 + 32]); + lblCharDescription.SetSize([250, 240]); + + g_uiDesktop.Add(winCharSelection); + winCharSelection.Add(lblSelectChar); + winCharSelection.Add(frmCharInfo); + winCharSelection.Add(imgCharPreview); + winCharSelection.Add(lblCharTitle); + winCharSelection.Add(lblCharCounter); + winCharSelection.Add(lblCharDescription); + + btns = memalloc(sizeof(OP4CharButton) * g_classnames_blackmesa.length); + for (int i = 0; i < g_classnames_blackmesa.length; i++) { + btns[i] = spawn(OP4CharButton); + btns[i].SetTitle(Titles_GetTextBody(g_classnames_blackmesa[i])); + btns[i].SetSize([124, 24]); + btns[i].SetPos(btnpos); + + if (i == 7) { + btns[i].SetKeyEquivalent("0"); + btns[i].SetTag(0); + } else { + btns[i].SetKeyEquivalent(ftos((float)i+1)); + btns[i].SetTag(i+1i); + } + + winCharSelection.Add(btns[i]); + btnpos[1] += 32; + } + } + + /* relabel the buttons for the currently selected team. */ + for (int i = 0; i < g_classnames_blackmesa.length; i++) { + if (teamChoice == 1) { + btns[i].SetTitle(Titles_GetTextBody(g_classnames_blackmesa[i])); + + if (i == 6) { + btns[i].SetKeyEquivalent("0"); + btns[i].SetTag(0); + } else { + btns[i].SetKeyEquivalent(ftos((float)i+1)); + btns[i].SetTag(i+1i); + } + } else { + btns[i].SetTitle(Titles_GetTextBody(g_classnames_opfor[i])); + + if (i == 6) { + btns[i].SetTag(13); + btns[i].SetKeyEquivalent("0"); + } else { + btns[i].SetTag(6 + i+1i); + btns[i].SetKeyEquivalent(ftos((float)i+1)); + } + } + } + + winCharSelection.Show(); + winCharSelection.SetPos((video_res / 2) - (winCharSelection.GetSize() / 2)); +} \ No newline at end of file diff --git a/src/client/vgui_chooseteam.qc b/src/client/vgui_chooseteam.qc new file mode 100644 index 0000000..31c0a92 --- /dev/null +++ b/src/client/vgui_chooseteam.qc @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2016-2020 Marco Cawthorne + * + * 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. + */ + +static VGUIWindow winChooseTeam; + +class OP4TeamButton:VGUIButton +{ + void OP4TeamButton(void); + + virtual void OnMouseUp(void); +}; + +void +OP4TeamButton::OP4TeamButton(void) +{ +} + +void +OP4TeamButton::OnMouseUp(void) +{ + int tag = GetTag(); + + VGUI_ChooseClass(tag); + sendevent("TeamJoin", "f", (float)tag); + winChooseTeam.Hide(); +} + + +string +VGUI_ChooseTeam_MapInfo(void) +{ + static string mapinfo = __NULL__; + + if (mapinfo != __NULL__) + return mapinfo; + + filestream fileMap = fopen(strcat("maps/", mapname, ".txt"), FILE_READ); + string temp; + + if (fileMap != -1) { + while ((temp = fgets(fileMap))) { + mapinfo = strcat(mapinfo, temp, "\n"); + } + } else { + mapinfo = Titles_GetTextBody("Map_Description_not_available"); + } + + return mapinfo; +} + +void +VGUI_ChooseTeam(void) +{ + static int initialized; + static VGUIButton btnAutoAssign; + static VGUIButton btnGoSpectator; + static VGUIFrame frmMapInfo; + static VGUILabel lblSelectTeam; + static VGUILabel lblMapName; + static VGUILabel lblMapInfo; + + static void VGUI_AutoAssign(void) { + float tag = (random() < 0.5) ? 1 : 2; + VGUI_ChooseClass(tag); + sendevent("TeamJoin", "f", tag); + winChooseTeam.Hide(); + } + + static void VGUI_GoSpectator(void) { + sendevent("TeamJoin", "f", 0); + winChooseTeam.Hide(); + } + + if (!initialized) { + vector btnpos = [40,80]; + + initialized = TRUE; + winChooseTeam = spawn(VGUIWindow); + winChooseTeam.SetSize('640 480'); + winChooseTeam.SetStyleMask(VGUIWindowBorderless | VGUIWindowFullscreen); + + lblSelectTeam = spawn(VGUILabel); + lblSelectTeam.SetTitle(Titles_GetTextBody("CTFTitle_SelectYourTeam")); + lblSelectTeam.SetTextSize(19); + lblSelectTeam.SetPos([40, 38]); + lblSelectTeam.SetSize('400 24'); + + frmMapInfo = spawn(VGUIFrame); + frmMapInfo.SetPos('176 80'); + frmMapInfo.SetSize('424 312'); + + lblMapName = spawn(VGUILabel); + lblMapName.SetTitle(mapname); + lblMapName.SetTextSize(19); + lblMapName.SetPos('194 105'); + lblMapName.SetSize('250 312'); + + lblMapInfo = spawn(VGUILabel); + lblMapInfo.SetTitle(VGUI_ChooseTeam_MapInfo()); + lblMapInfo.SetPos('194 129'); + lblMapInfo.SetSize('375 250'); + + for (int t = 1; t <= serverkeyfloat("teams"); t++) { + OP4TeamButton btnForTeam; + string team_name = serverkey(sprintf("team_%i", t)); + + btnForTeam = spawn(OP4TeamButton); + btnForTeam.SetTitle(team_name); + btnForTeam.SetPos(btnpos); + btnForTeam.SetKeyEquivalent(ftos((float)t)); + btnForTeam.SetSize('124 24'); + + switch (team_name) { + case "Black Mesa": + btnForTeam.SetTag(1); + break; + case "Opposing Force": + btnForTeam.SetTag(2); + break; + } + + winChooseTeam.Add(btnForTeam); + btnpos[1] += 32; + } + + btnAutoAssign = spawn(VGUIButton); + btnAutoAssign.SetTitle(Titles_GetTextBody("CTFTeam_AutoAssign")); + btnAutoAssign.SetPos(btnpos); + btnAutoAssign.SetSize('124 24'); + btnAutoAssign.SetKeyEquivalent("5"); + btnAutoAssign.SetFunc(VGUI_AutoAssign); + btnpos[1] += 32; + + btnGoSpectator = spawn(VGUIButton); + btnGoSpectator.SetTitle(Titles_GetTextBody("CTFMenu_Spectate")); + btnGoSpectator.SetPos(btnpos); + btnGoSpectator.SetSize('124 24'); + btnGoSpectator.SetKeyEquivalent("6"); + btnGoSpectator.SetFunc(VGUI_GoSpectator); + + g_uiDesktop.Add(winChooseTeam); + winChooseTeam.Add(frmMapInfo); + winChooseTeam.Add(lblSelectTeam); + winChooseTeam.Add(lblMapName); + winChooseTeam.Add(lblMapInfo); + winChooseTeam.Add(btnAutoAssign); + winChooseTeam.Add(btnGoSpectator); + } + + winChooseTeam.Show(); + winChooseTeam.SetPos((video_res / 2) - (winChooseTeam.GetSize() / 2)); +} diff --git a/src/client/viewmodel.qc b/src/client/viewmodel.qc new file mode 100644 index 0000000..3aaedfd --- /dev/null +++ b/src/client/viewmodel.qc @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2016-2021 Marco Cawthorne + * + * 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. + */ + +/* very primitive bobbing code, similar to Quake. Some ideas: + - allow for a second bob that runs at a separate cycle speed + - second bob could be applied to the side, would give a Doom III/HL2/TS + like viewmodel bob that people may like +*/ + +var float autocvar_v_bob = 0.005; +var float autocvar_v_bobcycle = 0.6; +var float autocvar_v_bobup = 0.5; + +var float autocvar_v_bob2 = 0.005; +var float autocvar_v_bob2cycle = 1.4; +var float autocvar_v_bob2up = 0.5; + +struct +{ + float m_flBobTime; + float m_flBob; + float m_flBobCycle; + float m_flSpeed; +} g_viewBobVars[4], *pViewBob; + + +struct +{ + float m_flBobTime; + float m_flBob; + float m_flBobCycle; + float m_flSpeed; +} g_viewBobVars2[4], *pViewBob2; + + +void +Viewmodel_CalcBob2(void) +{ + vector vecVel; + float flBob; + int iCycle; + int s = (float)getproperty(VF_ACTIVESEAT); + pViewBob2 = &g_viewBobVars2[s]; + + float var_bob; + float var_cycle; + float var_up; + + var_bob = autocvar_v_bob; + var_cycle = autocvar_v_bob2cycle; + var_up = autocvar_v_bob2up; + + /* how many cycles have we done in total */ + iCycle = (pViewBob2->m_flBobTime / var_cycle); + + /* increment the input value for our cycle */ + pViewBob2->m_flBobTime += frametime; + + /* calculate the point in the cycle based on the input time */ + pViewBob2->m_flBobCycle = pViewBob2->m_flBobTime - (iCycle * var_cycle); + pViewBob2->m_flBobCycle /= var_cycle; + + /* prepare for our cycle value to be placed into sin() to get the wave motion */ + pViewBob2->m_flBobCycle = MATH_PI * (pViewBob2->m_flBobCycle / var_up); + + /* we based the speed on the clients movement speed, but ignore any height/jump velocity */ + vecVel = pSeat->m_vecPredictedVelocity; + vecVel[2] = 0; + + pViewBob2->m_flSpeed = vlen(vecVel); + + /* bob equals speed times strength times cycle */ + flBob = ((pViewBob2->m_flSpeed * var_bob) * sin(pViewBob2->m_flBobCycle)); + + /* clamp between -8 and 4 units */ + pViewBob2->m_flBob = bound(-8, flBob, 4); + + /* make sure it's adjusted for scale */ + pViewBob2->m_flBob *= autocvar_cg_viewmodelScale; +} + +/* bob vars are calculated separately from application, so that if there's + * more than one viewmodel we won't affect the speed of the bob by running + * the math too many times */ +void +Viewmodel_CalcBob(void) +{ + vector vecVel; + float flBob; + int iCycle; + int s = (float)getproperty(VF_ACTIVESEAT); + pViewBob = &g_viewBobVars[s]; + + float var_bob; + float var_cycle; + float var_up; + + var_bob = autocvar_v_bob; + var_cycle = autocvar_v_bobcycle; + var_up = autocvar_v_bobup; + + /* how many cycles have we done in total */ + iCycle = (pViewBob->m_flBobTime / var_cycle); + + /* increment the input value for our cycle */ + pViewBob->m_flBobTime += frametime; + + /* calculate the point in the cycle based on the input time */ + pViewBob->m_flBobCycle = pViewBob->m_flBobTime - (iCycle * var_cycle); + pViewBob->m_flBobCycle /= var_cycle; + + /* prepare for our cycle value to be placed into sin() to get the wave motion */ + pViewBob->m_flBobCycle = MATH_PI * (pViewBob->m_flBobCycle / var_up); + + /* we based the speed on the clients movement speed, but ignore any height/jump velocity */ + vecVel = pSeat->m_vecPredictedVelocity; + vecVel[2] = 0; + + pViewBob->m_flSpeed = vlen(vecVel); + + /* bob equals speed times strength times cycle */ + flBob = ((pViewBob->m_flSpeed * var_bob) * sin(pViewBob->m_flBobCycle)); + + /* clamp between -8 and 4 units */ + pViewBob->m_flBob = bound(-8, flBob, 4); + + /* make sure it's adjusted for scale */ + pViewBob->m_flBob *= autocvar_cg_viewmodelScale; + + Viewmodel_CalcBob2(); +} + +float +Viewmodel_GetBob(void) +{ + int s = (float)getproperty(VF_ACTIVESEAT); + pViewBob = &g_viewBobVars[s]; + return pViewBob->m_flBob; +} + +void +Viewmodel_ApplyBob(entity gun) +{ + int s = (float)getproperty(VF_ACTIVESEAT); + pViewBob = &g_viewBobVars[s]; + + /* apply the gun offset based on our bob */ + gun.origin += v_up * (pViewBob->m_flBob * 0.2) + v_right * (pViewBob2->m_flBob * 0.4); +} 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/ctfitem.qc b/src/server/ctfitem.qc new file mode 100644 index 0000000..a41c8b2 --- /dev/null +++ b/src/server/ctfitem.qc @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2023 Marco Cawthorne + * + * 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 OP4CTFItem:NSRenderableEntity +{ +public: + void OP4CTFItem(void); + + virtual void Respawn(void); + virtual void Touch(entity); + nonvirtual bool CanPlayerGrabPowerup(entity); + virtual void SpawnKey(string, string); + +private: + int m_iItemID; + float m_iTeamID; + string m_strScoreIcon; + vector m_vecScoreColor; +}; + +void +OP4CTFItem::OP4CTFItem(void) +{ + m_iItemID = 0i; + m_strScoreIcon = __NULL__; + m_iTeamID = 0; + m_vecScoreColor = [1,1,1]; +} + +void +OP4CTFItem::Respawn(void) +{ + SetSolid(SOLID_TRIGGER); + SetMovetype(MOVETYPE_NONE); + SetOrigin(GetSpawnOrigin()); + SetModel(GetSpawnModel()); + SetSize([-16, -16, 0], [16, 16, 72]); + DropToFloor(); +} + +void +OP4CTFItem::SpawnKey(string strKey, string strValue) +{ + switch (strKey) { + case "goal_no": + m_iTeamID = ReadFloat(strValue); + break; + default: + super::SpawnKey(strKey, strValue); + } +} + +void +OP4CTFItem::Touch(entity toucherEntity) +{ + player pl = (player)toucherEntity; + + if (!m_iItemID) + return; + + if (!(toucherEntity.flags & FL_CLIENT)) + return; + + if (CanPlayerGrabPowerup(toucherEntity) == false) + return; + + pl.g_items |= m_iItemID; /* add to inventory */ + + forceinfokey(pl, "*icon2", m_strScoreIcon); + forceinfokey(pl, "*icon2_r", ftos(m_vecScoreColor[0])); + forceinfokey(pl, "*icon2_g", ftos(m_vecScoreColor[1])); + forceinfokey(pl, "*icon2_b", ftos(m_vecScoreColor[2])); + Destroy(); +} + +bool +OP4CTFItem::CanPlayerGrabPowerup(entity playerEntity) +{ + player pl = (player)playerEntity; + + if (pl.g_items & ITEM_CTF_JUMPPACK) + return false; + if (pl.g_items & ITEM_CTF_SHIELD) + return false; + if (pl.g_items & ITEM_CTF_HEALTH) + return false; + if (pl.g_items & ITEM_CTF_DEATH) + return false; + if (pl.g_items & ITEM_CTF_BACKPACK) + return false; + + return true; +} \ No newline at end of file diff --git a/src/server/defs.h b/src/server/defs.h new file mode 100644 index 0000000..f333bd1 --- /dev/null +++ b/src/server/defs.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2016-2023 Marco Cawthorne + * + * 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 "../../../valve/src/server/items.h" +#include "../../../valve/src/server/flashlight.h" diff --git a/src/server/gamerules.qc b/src/server/gamerules.qc new file mode 100644 index 0000000..3700035 --- /dev/null +++ b/src/server/gamerules.qc @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2016-2020 Marco Cawthorne + * + * 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. + */ + +bool +HLGameRules::IsMultiplayer(void) +{ + return 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(NSClientPlayer pp) +{ +} + +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(NSClientPlayer 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(NSClientPlayer 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(NSClientPlayer pl) +{ + if (Plugin_PlayerConnect(pl) == FALSE) + bprint(PRINT_HIGH, sprintf("%s connected\n", pl.netname)); +} + +void +HLGameRules::PlayerDisconnect(NSClientPlayer 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(NSClientPlayer pp) +{ + player pl = (player)pp; + Damage_Apply(pl, pl, pl.health, WEAPON_NONE, DMG_SKIP_ARMOR); +} + + +void +TriggerFlashlight(NSClient target) +{ + entity oldself = self; + self = target; + Flashlight_Toggle(); + self = oldself; +} + +void +DropCTFItem(NSClientPlayer pl) +{ + string item; + + if (pl.classname != "player") + return; + + if (pl.g_items & ITEM_CTF_JUMPPACK) { + item = "item_ctflongjump"; + pl.g_items &= ~ ITEM_CTF_JUMPPACK; + } else if (pl.g_items & ITEM_CTF_SHIELD) { + item = "item_ctfportablehev"; + pl.g_items &= ~ ITEM_CTF_SHIELD; + } else if (pl.g_items & ITEM_CTF_HEALTH) { + item = "item_ctfregeneration"; + pl.g_items &= ~ ITEM_CTF_HEALTH; + } else if (pl.g_items & ITEM_CTF_DEATH) { + item = "item_ctfaccelerator"; + pl.g_items &= ~ ITEM_CTF_DEATH; + } else if (pl.g_items & ITEM_CTF_BACKPACK) { + item = "item_ctfbackpack"; + pl.g_items &= ~ ITEM_CTF_BACKPACK; + } +} + +bool +HLGameRules::ImpulseCommand(NSClient bp, float num) +{ + switch (num) { + case 100: + TriggerFlashlight(bp); + break; + case 205: + DropCTFItem((player)bp); + break; + default: + return super::ImpulseCommand(bp, num); + } + + return true; +} \ No newline at end of file diff --git a/src/server/progs.src b/src/server/progs.src new file mode 100644 index 0000000..9031dc0 --- /dev/null +++ b/src/server/progs.src @@ -0,0 +1,53 @@ + +#pragma target fte_5768 +//#pragma flag enable assumeint +#pragma progs_dat "../../progs.dat" + +#define QWSSQC +#define SERVER +#define HL2 + +#includelist +../../../src/shared/fteextensions.qc +../../../src/shared/defs.h +../../../src/server/defs.h +../../../src/botlib/botinfo.h + +../../../src/gs-entbase/server.src +../../../src/gs-entbase/shared.src + +defs.h + +../shared/include.src + +../../../valve/src/server/player.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 + +../../../src/botlib/include.src + +gamerules.qc +../../../valve/src/server/gamerules_singleplayer.qc +../../../valve/src/server/gamerules_multiplayer.qc +server.qc +../../../valve/src/server/damage.qc +../../../valve/src/server/flashlight.qc +../../../valve/src/server/modelevent.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..bf0636c --- /dev/null +++ b/src/server/server.qc @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2016-2023 Marco Cawthorne + * + * 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) +{ + forceinfokey(world, "ctf", "0"); + + 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(); + FX_Corpse_Init(); +} diff --git a/src/shared/include.src b/src/shared/include.src new file mode 100644 index 0000000..4db7935 --- /dev/null +++ b/src/shared/include.src @@ -0,0 +1,31 @@ + #includelist +../../../valve/src/shared/entities.h +../../../valve/src/shared/events.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/fx_blood.qc +../../../valve/src/shared/fx_gaussbeam.qc +../../../valve/src/shared/fx_corpse.qc + +items.h +weapons.h + +w_357.qc +w_ar2.qc +w_bugbait.qc +w_crossbow.qc +w_crowbar.qc +w_frag.qc +w_gravitygun.qc +w_pistol.qc +w_rpg.qc +w_shotgun.qc +w_smg1.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..d46c435 --- /dev/null +++ b/src/shared/items.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2016-2023 Marco Cawthorne + * + * 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_CTF_JUMPPACK 0x04000000i +#define ITEM_CTF_SHIELD 0x08000000i +#define ITEM_CTF_HEALTH 0x10000000i +#define ITEM_CTF_DEATH 0x20000000i +#define ITEM_CTF_BACKPACK 0x40000000i +#define ITEM_GOALITEM 0x80000000i + + +typedef enum +{ + CTFFLAG_IDLE = 0, + CTFFLAG_TAKEN, + CTFFlAG_MISSING +} ctfflag_state; \ No newline at end of file diff --git a/src/shared/player.qc b/src/shared/player.qc new file mode 100644 index 0000000..b36f90c --- /dev/null +++ b/src/shared/player.qc @@ -0,0 +1,612 @@ +/* + * Copyright (c) 2016-2021 Marco Cawthorne + * + * 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/shared/skeleton.h" + +/* all potential SendFlags bits we can possibly send */ +enumflags +{ + PLAYER_TOPFRAME = PLAYER_CUSTOMFIELDSTART, + PLAYER_BOTTOMFRAME, + PLAYER_AMMO1, + PLAYER_AMMO2, + PLAYER_AMMO3, + PLAYER_FLAG, + PLAYER_UNUSED6, + PLAYER_UNUSED7 +}; + +class player:NSClientPlayer +{ + /* animation */ + PREDICTED_INT(anim_top) + PREDICTED_FLOAT(anim_top_time) + PREDICTED_FLOAT(anim_top_delay) + PREDICTED_INT(anim_bottom) + PREDICTED_FLOAT(anim_bottom_time) + + /* ammo 1 */ + PREDICTED_INT(glock_mag) + PREDICTED_INT(mp5_mag) + PREDICTED_INT(python_mag) + PREDICTED_INT(shotgun_mag) + PREDICTED_INT(crossbow_mag) + PREDICTED_INT(rpg_mag) + PREDICTED_INT(satchel_chg) + + /* ammo 2 */ + PREDICTED_INT(ammo_9mm) + PREDICTED_INT(ammo_357) + PREDICTED_INT(ammo_buckshot) + PREDICTED_INT(ammo_bolt) + PREDICTED_INT(ammo_rocket) + PREDICTED_INT(ammo_uranium) + PREDICTED_INT(ammo_handgrenade) + PREDICTED_INT(ammo_satchel) + PREDICTED_INT(ammo_tripmine) + PREDICTED_INT(ammo_snark) + PREDICTED_INT(ammo_hornet) + + /* ammo 3 */ + PREDICTED_INT(ammo_m203_grenade) + PREDICTED_INT(ammo_gauss_volume) + PREDICTED_INT(ammo_rpg_state) + PREDICTED_INT(mode_tempstate) + + /* gearbox */ + PREDICTED_INT(eagle_mag) + PREDICTED_INT(sniper_mag) + PREDICTED_INT(m249_mag) + PREDICTED_INT(sporelauncher_mag) + PREDICTED_INT(ammo_556) + PREDICTED_INT(ammo_762) + PREDICTED_INT(ammo_spore) + PREDICTED_INT(ammo_shock) + PREDICTED_INT(ammo_penguin) + PREDICTED_INT(mode_displacer) + PREDICTED_INT(mode_eagle) + PREDICTED_INT(mode_wrench) + PREDICTED_INT(mode_sporelauncher) + PREDICTED_INT(mode_m249) + + PREDICTED_FLOAT(flagmodel) + PREDICTED_FLOAT(flagskin) + + virtual void(void) Physics_Jump; + virtual void UpdatePlayerAnimation(float); + +#ifdef CLIENT + NSRenderableEntity m_eFlag; + virtual void UpdatePlayerAttachments(bool); + virtual void(float,float) ReceiveEntity; + virtual void(void) PredictPreFrame; + virtual void(void) PredictPostFrame; + virtual void UpdateAliveCam(void); + virtual void OnRemoveEntity(void); +#else + entity hook; + float m_flPickUpTime; + virtual void(void) EvaluateEntity; + virtual float(entity, float) SendEntity; +#endif +}; + + + +void Animation_PlayerUpdate(player); +void Animation_TimerUpdate(player, float); + +void +player::UpdatePlayerAnimation(float timelength) +{ + /* calculate our skeletal progression */ + Animation_PlayerUpdate(this); + /* advance animation timers */ + Animation_TimerUpdate(this, timelength); +} + +#ifdef CLIENT +void Camera_RunPosBob(vector angles, __inout vector camera_pos); +void Camera_StrafeRoll(__inout vector camera_angle); +void Shake_Update(NSClientPlayer); + +void +player::UpdateAliveCam(void) +{ + vector cam_pos = GetEyePos(); + Camera_RunPosBob(view_angles, cam_pos); + + g_view.SetCameraOrigin(cam_pos); + Camera_StrafeRoll(view_angles); + g_view.SetCameraAngle(view_angles); + + if (vehicle) { + NSVehicle veh = (NSVehicle)vehicle; + + if (veh.UpdateView) + veh.UpdateView(); + } else if (health) { + if (autocvar_pm_thirdPerson == TRUE) { + makevectors(view_angles); + vector vStart = [pSeat->m_vecPredictedOrigin[0], pSeat->m_vecPredictedOrigin[1], pSeat->m_vecPredictedOrigin[2] + 16] + (v_right * 4); + vector vEnd = vStart + (v_forward * -48) + [0,0,16] + (v_right * 4); + traceline(vStart, vEnd, FALSE, this); + g_view.SetCameraOrigin(trace_endpos + (v_forward * 5)); + } + } + + Shake_Update(this); + g_view.AddPunchAngle(punchangle); +} + +.string oldmodel; +string Weapons_GetPlayermodel(player, int); + +void +player::UpdatePlayerAttachments(bool visible) +{ + if (gflags & GF_FLASHLIGHT) { + vector src; + vector ang; + + if (entnum != player_localentnum) { + src = origin + view_ofs; + ang = v_angle; + } else { + src = pSeat->m_vecPredictedOrigin + view_ofs; + ang = view_angles; + } + + makevectors(ang); + traceline(src, src + (v_forward * 8096), MOVE_NORMAL, this); + + if (serverkeyfloat("*bspversion") == BSPVER_HL) { + dynamiclight_add(trace_endpos + (trace_plane_normal * 4), 128, [1,1,1]); + } else { + float p = dynamiclight_add(src, 512, [1,1,1], 0, "textures/flashlight"); + dynamiclight_set(p, LFIELD_ANGLES, ang); + dynamiclight_set(p, LFIELD_FLAGS, 3); + } + effects |= EF_NOSHADOW; + } + + if (m_eFlag != world) { + m_eFlag.SetOrigin(origin); + m_eFlag.SetAngles([0, angles[1], 0]); + } + + /* FIXME: this needs to be incorporated and simplified, now that we can handle it all in-class */ + if (!visible) + return; + + /* what's the current weapon model supposed to be anyway? */ + p_model.oldmodel = Weapons_GetPlayermodel(this, activeweapon); + + /* we changed weapons, update skeletonindex */ + if (p_model.model != p_model.oldmodel) { + /* free memory */ + if (p_model.skeletonindex) + skel_delete(p_model.skeletonindex); + + /* set the new model and mark us updated */ + setmodel(p_model, p_model.oldmodel); + p_model.model = p_model.oldmodel; + + /* set the new skeletonindex */ + p_model.skeletonindex = skel_create(p_model.modelindex); + + /* hack this thing in here FIXME: this should be done when popping in/out of a pvs */ + if (autocvar(cl_himodels, 1, "Use high-quality thisayer models over lower-definition ones")) + setcustomskin(this, "", "geomset 0 2\n"); + else + setcustomskin(this, "", "geomset 0 1\n"); + } + + /* follow thisayer at all times */ + setorigin(p_model, origin); + p_model.angles = angles; + skel_build(p_model.skeletonindex, p_model, p_model.modelindex,0, 0, -1); + + /* we have to loop through all valid bones of the weapon model and match them + * to the thisayer one */ + for (float i = 0; i < g_pbones.length; i++) { + vector bpos; + float pbone = gettagindex(this, g_pbones[i]); + float wbone = gettagindex(p_model, g_pbones[i]); + + /* if the bone doesn't ignore in either skeletal mesh, ignore */ + if (wbone <= 0 || pbone <= 0) + continue; + + bpos = gettaginfo(this, pbone); + + /* the most expensive bit */ + skel_set_bone_world(p_model, wbone, bpos, v_forward, v_right, v_up); + } +} + +void Weapons_AmmoUpdate(entity); +void HUD_AmmoNotify_Check(player pl); +void HUD_ItemNotify_Check(player pl); + +void +player::OnRemoveEntity(void) +{ + super::OnRemoveEntity(); + + if (m_eFlag) { + m_eFlag.Destroy(); + } +} +/* +================= +player::ReceiveEntity +================= +*/ +void +player::ReceiveEntity(float new, float flChanged) +{ + /* the generic client attributes */ + NSClientPlayer::ReceiveEntity(new, flChanged); + + /* animation */ + READENTITY_BYTE(anim_top, PLAYER_TOPFRAME) + READENTITY_FLOAT(anim_top_time, PLAYER_TOPFRAME) + READENTITY_FLOAT(anim_top_delay, PLAYER_TOPFRAME) + READENTITY_BYTE(anim_bottom, PLAYER_BOTTOMFRAME) + READENTITY_FLOAT(anim_bottom_time, PLAYER_BOTTOMFRAME) + + READENTITY_BYTE(glock_mag, PLAYER_AMMO1) + READENTITY_BYTE(mp5_mag, PLAYER_AMMO1) + READENTITY_BYTE(python_mag, PLAYER_AMMO1) + READENTITY_BYTE(shotgun_mag, PLAYER_AMMO1) + READENTITY_BYTE(crossbow_mag, PLAYER_AMMO1) + READENTITY_BYTE(rpg_mag, PLAYER_AMMO1) + READENTITY_BYTE(satchel_chg, PLAYER_AMMO1) + + READENTITY_BYTE(ammo_9mm, PLAYER_AMMO2) + READENTITY_BYTE(ammo_357, PLAYER_AMMO2) + READENTITY_BYTE(ammo_buckshot, PLAYER_AMMO2) + READENTITY_BYTE(ammo_bolt, PLAYER_AMMO2) + READENTITY_BYTE(ammo_rocket, PLAYER_AMMO2) + READENTITY_BYTE(ammo_uranium, PLAYER_AMMO2) + READENTITY_BYTE(ammo_handgrenade, PLAYER_AMMO2) + READENTITY_BYTE(ammo_satchel, PLAYER_AMMO2) + READENTITY_BYTE(ammo_tripmine, PLAYER_AMMO2) + READENTITY_BYTE(ammo_snark, PLAYER_AMMO2) + READENTITY_BYTE(ammo_hornet, PLAYER_AMMO2) + + READENTITY_BYTE(ammo_m203_grenade, PLAYER_AMMO3) + READENTITY_BYTE(ammo_gauss_volume, PLAYER_AMMO3) + READENTITY_BYTE(ammo_rpg_state, PLAYER_AMMO3) + READENTITY_BYTE(mode_tempstate, PLAYER_AMMO3) + + /* gearbox */ + READENTITY_BYTE(eagle_mag, PLAYER_AMMO1) + READENTITY_BYTE(sniper_mag, PLAYER_AMMO1) + READENTITY_BYTE(m249_mag, PLAYER_AMMO1) + READENTITY_BYTE(sporelauncher_mag, PLAYER_AMMO1) + + READENTITY_BYTE(ammo_556, PLAYER_AMMO2) + READENTITY_BYTE(ammo_762, PLAYER_AMMO2) + READENTITY_BYTE(ammo_spore, PLAYER_AMMO2) + READENTITY_BYTE(ammo_shock, PLAYER_AMMO2) + READENTITY_BYTE(ammo_penguin, PLAYER_AMMO2) + + READENTITY_BYTE(mode_displacer, PLAYER_AMMO3) + READENTITY_BYTE(mode_eagle, PLAYER_AMMO3) + READENTITY_BYTE(mode_wrench, PLAYER_AMMO3) + READENTITY_BYTE(mode_sporelauncher, PLAYER_AMMO3) + READENTITY_BYTE(mode_m249, PLAYER_AMMO3) + + READENTITY_FLOAT(flagmodel, PLAYER_FLAG) + READENTITY_BYTE(flagskin, PLAYER_FLAG) + + setorigin(this, origin); + + /* add/remove flag model */ + if (flagmodel != 0) { + if (!m_eFlag) + m_eFlag = spawn(NSRenderableEntity); + + m_eFlag.SetModelindex(flagmodel); + m_eFlag.SetSkin(flagskin); + m_eFlag.SetFrame(2); + } else if (m_eFlag) { + m_eFlag.Destroy(); + remove(m_eFlag); + m_eFlag = 0; + } + + /* these only concern the current player */ + CSQC_UpdateSeat(); + if (this != pSeat->m_ePlayer) + return; + + /* do not notify us of updates when spawning initially */ + if (flChanged == UPDATE_ALL) + PredictPreFrame(); + + if (flChanged & PLAYER_AMMO1 || flChanged & PLAYER_AMMO2 || flChanged & PLAYER_AMMO3) { + Weapons_AmmoUpdate(this); + HUD_AmmoNotify_Check(this); + } + + if (flChanged & PLAYER_ITEMS || flChanged & PLAYER_HEALTH) + HUD_ItemNotify_Check(this); +} + +/* +================= +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) +{ + NSClientPlayer::PredictPreFrame(); + + SAVE_STATE(anim_top) + SAVE_STATE(anim_top_delay) + SAVE_STATE(anim_top_time) + SAVE_STATE(anim_bottom) + SAVE_STATE(anim_bottom_time) + + SAVE_STATE(glock_mag) + SAVE_STATE(mp5_mag) + SAVE_STATE(python_mag) + SAVE_STATE(shotgun_mag) + SAVE_STATE(crossbow_mag) + SAVE_STATE(rpg_mag) + SAVE_STATE(satchel_chg) + + SAVE_STATE(ammo_9mm) + SAVE_STATE(ammo_357) + SAVE_STATE(ammo_buckshot) + SAVE_STATE(ammo_bolt) + SAVE_STATE(ammo_rocket) + SAVE_STATE(ammo_uranium) + SAVE_STATE(ammo_handgrenade) + SAVE_STATE(ammo_satchel) + SAVE_STATE(ammo_tripmine) + SAVE_STATE(ammo_snark) + SAVE_STATE(ammo_hornet) + + SAVE_STATE(ammo_m203_grenade) + SAVE_STATE(ammo_gauss_volume) + SAVE_STATE(ammo_rpg_state) + SAVE_STATE(mode_tempstate) + + /* gearbox */ + SAVE_STATE(eagle_mag) + SAVE_STATE(sniper_mag) + SAVE_STATE(m249_mag) + SAVE_STATE(sporelauncher_mag) + SAVE_STATE(ammo_556) + SAVE_STATE(ammo_762) + SAVE_STATE(ammo_spore) + SAVE_STATE(ammo_shock) + SAVE_STATE(ammo_penguin) + SAVE_STATE(mode_displacer) + SAVE_STATE(mode_eagle) + SAVE_STATE(mode_wrench) + SAVE_STATE(mode_sporelauncher) + SAVE_STATE(mode_m249) + SAVE_STATE(flagmodel) + SAVE_STATE(flagskin) +} + +/* +================= +player::PredictPostFrame + +Where we roll back our values to the ones last sent/verified by the server. +================= +*/ +void +player::PredictPostFrame(void) +{ + NSClientPlayer::PredictPostFrame(); + + ROLL_BACK(anim_top) + ROLL_BACK(anim_top_delay) + ROLL_BACK(anim_top_time) + ROLL_BACK(anim_bottom) + ROLL_BACK(anim_bottom_time) + + ROLL_BACK(glock_mag) + ROLL_BACK(mp5_mag) + ROLL_BACK(python_mag) + ROLL_BACK(shotgun_mag) + ROLL_BACK(crossbow_mag) + ROLL_BACK(rpg_mag) + ROLL_BACK(satchel_chg) + + ROLL_BACK(ammo_9mm) + ROLL_BACK(ammo_357) + ROLL_BACK(ammo_buckshot) + ROLL_BACK(ammo_bolt) + ROLL_BACK(ammo_rocket) + ROLL_BACK(ammo_uranium) + ROLL_BACK(ammo_handgrenade) + ROLL_BACK(ammo_satchel) + ROLL_BACK(ammo_tripmine) + ROLL_BACK(ammo_snark) + ROLL_BACK(ammo_hornet) + + ROLL_BACK(ammo_m203_grenade) + ROLL_BACK(ammo_gauss_volume) + ROLL_BACK(ammo_rpg_state) + ROLL_BACK(mode_tempstate) + + /* gearbox */ + ROLL_BACK(eagle_mag) + ROLL_BACK(sniper_mag) + ROLL_BACK(m249_mag) + ROLL_BACK(sporelauncher_mag) + ROLL_BACK(ammo_556) + ROLL_BACK(ammo_762) + ROLL_BACK(ammo_spore) + ROLL_BACK(ammo_shock) + ROLL_BACK(ammo_penguin) + ROLL_BACK(mode_displacer) + ROLL_BACK(mode_eagle) + ROLL_BACK(mode_wrench) + ROLL_BACK(mode_sporelauncher) + ROLL_BACK(mode_m249) + ROLL_BACK(flagmodel) + ROLL_BACK(flagskin) +} + +#else + +void +player::EvaluateEntity(void) +{ + /* the generic client attributes */ + NSClientPlayer::EvaluateEntity(); + + EVALUATE_FIELD(anim_top, PLAYER_TOPFRAME) + EVALUATE_FIELD(anim_top_time, PLAYER_TOPFRAME) + EVALUATE_FIELD(anim_top_delay, PLAYER_TOPFRAME) + EVALUATE_FIELD(anim_bottom, PLAYER_BOTTOMFRAME) + EVALUATE_FIELD(anim_bottom_time, PLAYER_BOTTOMFRAME) + + EVALUATE_FIELD(glock_mag, PLAYER_AMMO1) + EVALUATE_FIELD(mp5_mag, PLAYER_AMMO1) + EVALUATE_FIELD(python_mag, PLAYER_AMMO1) + EVALUATE_FIELD(shotgun_mag, PLAYER_AMMO1) + EVALUATE_FIELD(crossbow_mag, PLAYER_AMMO1) + EVALUATE_FIELD(rpg_mag, PLAYER_AMMO1) + EVALUATE_FIELD(satchel_chg, PLAYER_AMMO1) + + EVALUATE_FIELD(ammo_9mm, PLAYER_AMMO2) + EVALUATE_FIELD(ammo_357, PLAYER_AMMO2) + EVALUATE_FIELD(ammo_buckshot, PLAYER_AMMO2) + EVALUATE_FIELD(ammo_bolt, PLAYER_AMMO2) + EVALUATE_FIELD(ammo_rocket, PLAYER_AMMO2) + EVALUATE_FIELD(ammo_uranium, PLAYER_AMMO2) + EVALUATE_FIELD(ammo_handgrenade, PLAYER_AMMO2) + EVALUATE_FIELD(ammo_satchel, PLAYER_AMMO2) + EVALUATE_FIELD(ammo_tripmine, PLAYER_AMMO2) + EVALUATE_FIELD(ammo_snark, PLAYER_AMMO2) + EVALUATE_FIELD(ammo_hornet, PLAYER_AMMO2) + + EVALUATE_FIELD(ammo_m203_grenade, PLAYER_AMMO3) + EVALUATE_FIELD(ammo_gauss_volume, PLAYER_AMMO3) + EVALUATE_FIELD(ammo_rpg_state, PLAYER_AMMO3) + EVALUATE_FIELD(mode_tempstate, PLAYER_AMMO3) + + /* gearbox */ + EVALUATE_FIELD(eagle_mag, PLAYER_AMMO1) + EVALUATE_FIELD(sniper_mag, PLAYER_AMMO1) + EVALUATE_FIELD(m249_mag, PLAYER_AMMO1) + EVALUATE_FIELD(sporelauncher_mag, PLAYER_AMMO1) + + EVALUATE_FIELD(ammo_556, PLAYER_AMMO2) + EVALUATE_FIELD(ammo_762, PLAYER_AMMO2) + EVALUATE_FIELD(ammo_spore, PLAYER_AMMO2) + EVALUATE_FIELD(ammo_shock, PLAYER_AMMO2) + EVALUATE_FIELD(ammo_penguin, PLAYER_AMMO2) + + EVALUATE_FIELD(mode_displacer, PLAYER_AMMO3) + EVALUATE_FIELD(mode_eagle, PLAYER_AMMO3) + EVALUATE_FIELD(mode_wrench, PLAYER_AMMO3) + EVALUATE_FIELD(mode_sporelauncher, PLAYER_AMMO3) + EVALUATE_FIELD(mode_m249, PLAYER_AMMO3) + EVALUATE_FIELD(flagmodel, PLAYER_FLAG) + EVALUATE_FIELD(flagskin, PLAYER_FLAG) +} + +/* +================= +player::SendEntity +================= +*/ +float +player::SendEntity(entity ePEnt, float flChanged) +{ + /* don't broadcast invisible players */ + if (IsFakeSpectator() && ePEnt != this) + return (0); + if (!GetModelindex() && ePEnt != this) + return (0); + + flChanged = OptimiseChangedFlags(ePEnt, flChanged); + + WriteByte(MSG_ENTITY, ENT_PLAYER); + WriteFloat(MSG_ENTITY, flChanged); + + /* the generic client attributes */ + NSClientPlayer::SendEntity(ePEnt, flChanged); + + SENDENTITY_BYTE(anim_top, PLAYER_TOPFRAME) + SENDENTITY_FLOAT(anim_top_time, PLAYER_TOPFRAME) + SENDENTITY_FLOAT(anim_top_delay, PLAYER_TOPFRAME) + SENDENTITY_BYTE(anim_bottom, PLAYER_BOTTOMFRAME) + SENDENTITY_FLOAT(anim_bottom_time, PLAYER_BOTTOMFRAME) + + SENDENTITY_BYTE(glock_mag, PLAYER_AMMO1) + SENDENTITY_BYTE(mp5_mag, PLAYER_AMMO1) + SENDENTITY_BYTE(python_mag, PLAYER_AMMO1) + SENDENTITY_BYTE(shotgun_mag, PLAYER_AMMO1) + SENDENTITY_BYTE(crossbow_mag, PLAYER_AMMO1) + SENDENTITY_BYTE(rpg_mag, PLAYER_AMMO1) + SENDENTITY_BYTE(satchel_chg, PLAYER_AMMO1) + + SENDENTITY_BYTE(ammo_9mm, PLAYER_AMMO2) + SENDENTITY_BYTE(ammo_357, PLAYER_AMMO2) + SENDENTITY_BYTE(ammo_buckshot, PLAYER_AMMO2) + SENDENTITY_BYTE(ammo_bolt, PLAYER_AMMO2) + SENDENTITY_BYTE(ammo_rocket, PLAYER_AMMO2) + SENDENTITY_BYTE(ammo_uranium, PLAYER_AMMO2) + SENDENTITY_BYTE(ammo_handgrenade, PLAYER_AMMO2) + SENDENTITY_BYTE(ammo_satchel, PLAYER_AMMO2) + SENDENTITY_BYTE(ammo_tripmine, PLAYER_AMMO2) + SENDENTITY_BYTE(ammo_snark, PLAYER_AMMO2) + SENDENTITY_BYTE(ammo_hornet, PLAYER_AMMO2) + + SENDENTITY_BYTE(ammo_m203_grenade, PLAYER_AMMO3) + SENDENTITY_BYTE(ammo_gauss_volume, PLAYER_AMMO3) + SENDENTITY_BYTE(ammo_rpg_state, PLAYER_AMMO3) + SENDENTITY_BYTE(mode_tempstate, PLAYER_AMMO3) + + /* gearbox */ + SENDENTITY_BYTE(eagle_mag, PLAYER_AMMO1) + SENDENTITY_BYTE(sniper_mag, PLAYER_AMMO1) + SENDENTITY_BYTE(m249_mag, PLAYER_AMMO1) + SENDENTITY_BYTE(sporelauncher_mag, PLAYER_AMMO1) + + SENDENTITY_BYTE(ammo_556, PLAYER_AMMO2) + SENDENTITY_BYTE(ammo_762, PLAYER_AMMO2) + SENDENTITY_BYTE(ammo_spore, PLAYER_AMMO2) + SENDENTITY_BYTE(ammo_shock, PLAYER_AMMO2) + SENDENTITY_BYTE(ammo_penguin, PLAYER_AMMO2) + + SENDENTITY_BYTE(mode_displacer, PLAYER_AMMO3) + SENDENTITY_BYTE(mode_eagle, PLAYER_AMMO3) + SENDENTITY_BYTE(mode_wrench, PLAYER_AMMO3) + SENDENTITY_BYTE(mode_sporelauncher, PLAYER_AMMO3) + SENDENTITY_BYTE(mode_m249, PLAYER_AMMO3) + SENDENTITY_FLOAT(flagmodel, PLAYER_FLAG) + SENDENTITY_BYTE(flagskin, PLAYER_FLAG) + return (1); +} +#endif + diff --git a/src/shared/w_357.qc b/src/shared/w_357.qc new file mode 100644 index 0000000..4577a8e --- /dev/null +++ b/src/shared/w_357.qc @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2016-2021 Marco Cawthorne + * + * 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 +{ + PYTHON_IDLE, + PYTHON_FIRE, + PYTHON_DRAW, + PYTHON_RELOAD, + PYTHON_HOLSTER, + PYTHON_IDLE_TO_LOW, + PYTHON_LOW_TO_IDLE, + PYTHON_LOW_IDLE +}; + +void +w_357_precache(void) +{ +#ifdef SERVER + precache_model("models/w_357.mdl"); +#else + precache_model("models/weapons/v_357.mdl"); + precache_model("models/p_357.mdl"); +#endif +} + +int +w_357_pickup(player pl, int new, int startammo) +{ +#ifdef SERVER + int addAmmo = (startammo == -1) ? 6 : startammo; + + if (new) { + pl.python_mag = addAmmo; + return (1); + } + + if (pl.ammo_357 < MAX_A_357) { + pl.ammo_357 = bound(0, pl.ammo_357 + addAmmo, MAX_A_357); + } else { + if (!new) + return (0); + } +#endif + return (1); +} + +void +w_357_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, pl.python_mag, pl.ammo_357, -1); +} + +string +w_357_wmodel(void) +{ + return "models/w_357.mdl"; +} + +string +w_357_pmodel(player pl) +{ + return "models/p_357.mdl"; +} + +string +w_357_deathmsg(void) +{ + return ""; +} + +void +w_357_draw(player pl) +{ + Weapons_SetModel("models/weapons/v_357.mdl"); + + /* singleplayer doesn't do scope */ + if (serverkeyfloat("sv_playerslots") == 1) { + Weapons_SetGeomset("geomset 4 1\n"); + } else { + Weapons_SetGeomset("geomset 4 2\n"); + } + + Weapons_ViewAnimation(pl, PYTHON_DRAW); + pl.w_idle_next = 1.0f; +} + +void +w_357_holster(player pl) +{ + Weapons_ViewAnimation(pl, PYTHON_HOLSTER); + pl.w_idle_next = 0.3660f; +} + +void +w_357_primary(player pl) +{ + if (pl.w_attack_next > 0.0) + return; + if (pl.gflags & GF_SEMI_TOGGLED) + return; + + /* Ammo check */ + if ((pl.python_mag <= 0) || (pl.WaterLevel() >= WATERLEVEL_SUBMERGED)) { +#ifdef SERVER + Sound_Play(pl, CHAN_AUTO, "weapon_357.empty"); +#endif + pl.gflags |= GF_SEMI_TOGGLED; + return; + } + + pl.python_mag--; + + /* Actual firing */ +#ifdef CLIENT + View_SetMuzzleflash(MUZZLE_SMALL); +#else + TraceAttack_FireBullets(1, pl.origin + pl.view_ofs, Skill_GetValue("plr_357_bullet", 40), [0.008, 0.008], WEAPON_357); + Sound_Play(pl, CHAN_WEAPON, "Weapon_357.Single"); +#endif + + Weapons_ViewPunchAngle(pl, [-10,0,0]); + Weapons_ViewAnimation(pl, PYTHON_FIRE); + + if (pl.flags & FL_CROUCHING) + Animation_PlayerTop(pl, ANIM_CR_SHOOTPYTHON, 0.43f); + else + Animation_PlayerTop(pl, ANIM_SHOOTPYTHON, 0.43f); + + pl.w_attack_next = 0.833f; + pl.w_idle_next = 0.833f; +} + +void +w_357_secondary(player pl) +{ + + if (pl.w_attack_next > 0.0) { + return; + } + + /* singleplayer doesn't do scope */ + if (serverkeyfloat("sv_playerslots") == 1) { + return; + } + + /* Simple toggle of fovs */ + if (pl.viewzoom == 1.0f) { + pl.viewzoom = 0.5f; + } else { + pl.viewzoom = 1.0f; + } + + pl.w_attack_next = 0.25f; +} + +void +w_357_reload(player pl) +{ + + if (pl.w_attack_next > 0.0) { + return; + } + + /* Ammo check */ + if (pl.python_mag >= 6) { + return; + } + if (pl.ammo_357 <= 0) { + return; + } + + /* undo our zoom */ + pl.viewzoom = 1.0f; + + /* Audio-Visual bit */ + Weapons_ViewAnimation(pl, PYTHON_RELOAD); + +#ifdef SERVER + static void w_357_reload_done(void) { + player pl = (player)self; + Weapons_ReloadWeapon(pl, player::python_mag, player::ammo_357, 6); + } + + pl.think = w_357_reload_done; + pl.nextthink = time + 3.15f; + Sound_Play(pl, CHAN_WEAPON, "Weapon_357.Reload"); +#endif + + pl.w_attack_next = 3.7f; + pl.w_idle_next = 3.7f; +} + +void +w_357_release(player pl) +{ + /* auto-reload if need be */ + if (pl.w_attack_next <= 0.0) + if (pl.python_mag == 0 && pl.ammo_357 > 0) { + Weapons_Reload(pl); + return; + } + + if (pl.w_idle_next > 0.0) { + return; + } + + Weapons_ViewAnimation(pl, PYTHON_IDLE); + pl.w_idle_next = 4.0f; +} + +void +w_357_crosshair(player pl) +{ +#ifdef CLIENT + HUD_DrawAmmo1(); + HUD_DrawAmmo2(); + vector pos = g_hudmins + [g_hudres[0] / 2, g_hudres[1] / 2]; + Font_DrawText_RGBA(pos + [-7, -14], "Q", g_hud_color, 1.0, FONT_HUD_CROSS); +#endif +} + +float +w_357_aimanim(player pl) +{ + return pl.flags & FL_CROUCHING ? ANIM_CR_AIMPYTHON : ANIM_AIMPYTHON; +} + +void +w_357_hudpic(player pl, int selected, vector pos, float a) +{ +#ifdef CLIENT + vector hud_col; + + if (pl.python_mag == 0 && pl.ammo_357 == 0) + hud_col = [1,0,0]; + else + hud_col = g_hud_color; + + if (selected) { + drawsubpic( + pos, + [128,64], + "materials/Sprites/w_icons1", + [0.5, 0.25], + [128/256,64/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [128,64], + "materials/Sprites/w_icons1", + [0.5, 0.25], + [128/256,64/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } + + HUD_DrawAmmoBar(pos, pl.ammo_357, MAX_A_357, a); +#endif +} + +int +w_357_isempty(player pl) +{ + + if (pl.python_mag <= 0 && pl.ammo_357 <= 0) + return 1; + + return 0; +} + +weapontype_t +w_357_type(player pl) +{ + return WPNTYPE_RANGED; +} + +weapon_t w_357 = +{ + .name = "357", + .id = ITEM_PYTHON, + .slot = 1, + .slot_pos = 1, + .weight = 15, + .draw = w_357_draw, + .holster = w_357_holster, + .primary = w_357_primary, + .secondary = w_357_secondary, + .reload = w_357_reload, + .release = w_357_release, + .postdraw = w_357_crosshair, + .precache = w_357_precache, + .pickup = w_357_pickup, + .updateammo = w_357_updateammo, + .wmodel = w_357_wmodel, + .pmodel = w_357_pmodel, + .deathmsg = w_357_deathmsg, + .aimanim = w_357_aimanim, + .isempty = w_357_isempty, + .type = w_357_type, + .hudpic = w_357_hudpic +}; \ No newline at end of file diff --git a/src/shared/w_ar2.qc b/src/shared/w_ar2.qc new file mode 100644 index 0000000..9f35d4e --- /dev/null +++ b/src/shared/w_ar2.qc @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2016-2021 Marco Cawthorne + * + * 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 +{ + AR2_IDLE, + AR2_FIRE1, + AR2_FIRE2, + AR2_FIRE3, + AR2_FIRE4, + AR2_ALTFIRE, + AR2_RELOAD, + AR2_DRAW, + AR2_HOLSTER, + AR2_IDLE_TO_LOW, + AR2_LOW_TO_IDLE, + AR2_SHAKE, + AR2_VENT_NEUTRAL, + AR2_VENT_OPEN, + AR2_VENT_CLOSED +}; + +void +w_ar2_precache(void) +{ +#ifdef SERVER + precache_model("models/w_hgun.mdl"); + precache_model("models/hornet.mdl"); +#else + precache_model("models/weapons/v_irifle.mdl"); + precache_model("models/p_hgun.mdl"); +#endif +} + +int +w_ar2_pickup(player pl, int new, int startammo) +{ +#ifdef SERVER + + /* only pick it up once */ + if (new) { + pl.ammo_hornet = MAX_A_HORNET; + return (1); + } +#endif + return (0); +} + +void +w_ar2_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, -1, pl.ammo_hornet, -1); +} +string w_ar2_wmodel(void) +{ + return "models/w_hgun.mdl"; +} +string w_ar2_pmodel(player pl) +{ + return "models/p_hgun.mdl"; +} +string w_ar2_deathmsg(void) +{ + return ""; +} + +void +w_ar2_draw(player pl) +{ + Weapons_SetModel("models/weapons/v_irifle.mdl"); + Weapons_ViewAnimation(pl, AR2_DRAW); + pl.w_idle_next = 0.8f; +} + +void +w_ar2_holster(player pl) +{ + Weapons_ViewAnimation(pl, AR2_HOLSTER); + +} + +#ifdef SERVER +void +w_ar2_shoothornet(player pl) +{ + +} +#endif + +void +w_ar2_release(player pl) +{ + if (pl.w_idle_next > 0.0) { + return; + } + + if (pl.w_idle_next > 0.0) { + return; + } + + Weapons_ViewAnimation(pl, AR2_IDLE); + pl.w_idle_next = 1.0f; +} + +void +w_ar2_primary(player pl) +{ + if (pl.w_attack_next > 0.0) { + return; + } + + /* Ammo check */ + if (pl.ammo_hornet <= 0) { + // w_ar2_release(pl); + //return; + } + +#ifdef SERVER + w_ar2_shoothornet(pl); + Sound_Play(pl, CHAN_WEAPON, "Weapon_AR2.Single"); +#endif + +// pl.ammo_hornet--; + int r = floor(pseudorandom() * 4.0); + Weapons_ViewAnimation(pl, AR2_FIRE1 + r); + + if (pl.flags & FL_CROUCHING) + Animation_PlayerTop(pl, ANIM_CR_SHOOTHIVE, 0.43f); + else + Animation_PlayerTop(pl, ANIM_SHOOTHIVE, 0.43f); + + pl.w_attack_next = 0.1f; + pl.w_idle_next = 0.2f; +} + +void +w_ar2_secondary(player pl) +{ + if (pl.w_attack_next) { + return; + } + + /* Ammo check */ + if (pl.ammo_hornet <= 0) { + w_ar2_release(pl); + return; + } + +#ifdef SERVER +// w_ar2_shoothornet(pl); + Sound_Play(pl, CHAN_WEAPON, "Weapon_AR2.Double"); +#endif + + pl.ammo_hornet--; + Weapons_ViewAnimation(pl, AR2_ALTFIRE); + + if (pl.flags & FL_CROUCHING) + Animation_PlayerTop(pl, ANIM_CR_SHOOTHIVE, 0.43f); + else + Animation_PlayerTop(pl, ANIM_SHOOTHIVE, 0.43f); + + pl.w_attack_next = 0.7f; + pl.w_idle_next = 0.7f; +} + +void +w_ar2_reload(player pl) +{ + if (pl.w_attack_next) { + return; + } + +#ifdef SERVER +// w_ar2_shoothornet(pl); + Sound_Play(pl, CHAN_WEAPON, "Weapon_AR2.Reload"); +#endif + + Weapons_ViewAnimation(pl, AR2_RELOAD); + + pl.w_attack_next = 1f; + pl.w_idle_next = 1f; +} + +void +w_ar2_crosshair(player pl) +{ +#ifdef CLIENT + HUD_DrawAmmo2(); + + vector pos = g_hudmins + [g_hudres[0] / 2, g_hudres[1] / 2]; + Font_DrawText_RGBA(pos + [-7, -14], "Q", g_hud_color, 1.0, FONT_HUD_CROSS); +#endif +} + +float +w_ar2_aimanim(player pl) +{ + return pl.flags & FL_CROUCHING ? ANIM_CR_AIMHIVE : ANIM_AIMHIVE; +} + +void +w_ar2_hudpic(player pl, int selected, vector pos, float a) +{ +#ifdef CLIENT + vector hud_col = g_hud_color; + + if (selected) { + drawsubpic( + pos, + [128,64], + "materials/Sprites/w_icons2", + [0.0, 0.25], + [128/256,64/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [128,64], + "materials/Sprites/w_icons2", + [0.0, 0.25], + [128/256,64/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } + + HUD_DrawAmmoBar(pos, pl.ammo_hornet, MAX_A_HORNET, a); +#endif +} + +int +w_ar2_isempty(player pl) +{ + return 0; +} + +weapontype_t +w_ar2_type(player pl) +{ + return WPNTYPE_RANGED; +} + +weapon_t w_ar2 = +{ + .name = "hornet", + .id = ITEM_HORNETGUN, + .slot = 2, + .slot_pos = 1, + .weight = 10, + .draw = w_ar2_draw, + .holster = w_ar2_holster, + .primary = w_ar2_primary, + .secondary = w_ar2_secondary, + .reload = w_ar2_reload, + .release = w_ar2_release, + .postdraw = w_ar2_crosshair, + .precache = w_ar2_precache, + .pickup = w_ar2_pickup, + .updateammo = w_ar2_updateammo, + .wmodel = w_ar2_wmodel, + .pmodel = w_ar2_pmodel, + .deathmsg = w_ar2_deathmsg, + .aimanim = w_ar2_aimanim, + .isempty = w_ar2_isempty, + .type = w_ar2_type, + .hudpic = w_ar2_hudpic +}; + +#ifdef CLIENT +void w_tripmine_parse(void) +{ + +} +#endif \ No newline at end of file diff --git a/src/shared/w_bugbait.qc b/src/shared/w_bugbait.qc new file mode 100644 index 0000000..2acd985 --- /dev/null +++ b/src/shared/w_bugbait.qc @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2016-2021 Marco Cawthorne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef SERVER +.float nadeCookingTime; +#endif + +enum +{ + BUGBAIT_DRAWBACK, + BUGBAIT_THROW, + BUGBAIT_IDLE, + BUGBAIT_DRAW, + BUGBAIT_HOLSTER, + BUGBAIT_SQUEEZE +}; + +void w_bugbait_precache(void) +{ +#ifdef SERVER + Sound_Precache("weapon_frag.bounce"); + precache_model("models/w_grenade.mdl"); + particleeffectnum("fx_explosion.main"); + precache_model("sprites/fexplo.spr"); +#else + precache_model("models/weapons/v_bugbait.mdl"); + precache_model("models/p_grenade.mdl"); +#endif +} + +void w_bugbait_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, -1, pl.ammo_handgrenade, -1); +} + +string w_bugbait_wmodel(void) +{ + return "models/w_grenade.mdl"; +} + +string w_bugbait_pmodel(player pl) +{ + return "models/p_grenade.mdl"; +} + +string w_bugbait_deathmsg(void) +{ + return ""; +} + +int w_bugbait_pickup(player pl, int new, int startammo) +{ +#ifdef SERVER + int addAmmo = (startammo == -1) ? 1 : startammo; + + if (pl.ammo_handgrenade < MAX_A_HANDGRENADE) { + pl.ammo_handgrenade = bound(0, pl.ammo_handgrenade + addAmmo, MAX_A_HANDGRENADE); + } else { + if (!new) + return (0); + } +#endif + return (1); +} + +void w_bugbait_draw(player pl) +{ + pl.mode_tempstate = 0; + + Weapons_SetModel("models/weapons/v_bugbait.mdl"); + Weapons_ViewAnimation(pl, BUGBAIT_DRAW); + pl.w_idle_next = 0.9f; +} + +void w_bugbait_holster(player pl) +{ + +} +void w_bugbait_primary(player pl) +{ + if (pl.w_attack_next > 0.0) { + return; + } + + /* We're abusing this network variable for the holding check */ + if (pl.mode_tempstate > 0) { + return; + } + + /* Ammo check */ + if (pl.ammo_handgrenade <= 0) { + return; + } + + Weapons_ViewAnimation(pl, BUGBAIT_DRAWBACK); + + pl.mode_tempstate = 1; + pl.w_attack_next = 0.5f; + pl.w_idle_next = 0.5f; + +#ifdef SERVER + pl.nadeCookingTime = time; +#endif +} +void w_bugbait_secondary(player pl) +{ + if (pl.w_attack_next > 0.0) { + return; + } + + /* Ammo check */ + if (pl.ammo_handgrenade <= 0) { + return; + } + +#ifdef SERVER + Sound_Play(pl, CHAN_WEAPON, "Weapon_Bugbait.Splat"); +#endif + Weapons_ViewAnimation(pl, BUGBAIT_SQUEEZE); + pl.w_attack_next = 0.5f; + pl.w_idle_next = 0.6f; +} + +void w_bugbait_hud(player pl) +{ +#ifdef CLIENT + HUD_DrawAmmo2(); + + vector pos = g_hudmins + [g_hudres[0] / 2, g_hudres[1] / 2]; + Font_DrawText_RGBA(pos + [-7, -14], "Q", g_hud_color, 1.0, FONT_HUD_CROSS); +#endif +} + +void w_bugbait_release(player pl) +{ + if (pl.w_idle_next > 0.0) { + return; + } + + if (pl.mode_tempstate == 1) { + Weapons_ViewAnimation(pl, BUGBAIT_THROW); +#ifdef SERVER + vector throwDirection; + float throwingStrength; + + NSProjectile nade = (NSProjectile )EntityDef_CreateClassname("projectile_frag"); + nade.SetOwner(pl); + + throwDirection = pl.v_angle; + throwDirection[0] = -10.0f; /* always aim a bit up */ + + /* diminish when aiming up */ + if (pl.v_angle[0] < 0) { + throwDirection[0] += (pl.v_angle[0] * 0.9f); + } else { /* increase when aiming down */ + throwDirection[0] += (pl.v_angle[0] * 1.1f); + } + + throwingStrength = bound(0, (90 - throwDirection[0]) * 5.0f, 1000); + + nade.Launch(pl.GetEyePos(), pl.v_angle, time - pl.nadeCookingTime, 0.0f, 0.0f); + makevectors(throwDirection); + nade.SetVelocity((v_forward * throwingStrength) + pl.GetVelocity()); +#endif + pl.ammo_handgrenade--; + pl.mode_tempstate = 2; + pl.w_attack_next = 1.0f; + pl.w_idle_next = 0.5f; + + if (pl.flags & FL_CROUCHING) + Animation_PlayerTop(pl, ANIM_CR_SHOOTCROWBAR, 0.41f); + else + Animation_PlayerTop(pl, ANIM_SHOOTCROWBAR, 0.5f); + } else if (pl.mode_tempstate == 2) { + Weapons_ViewAnimation(pl, BUGBAIT_DRAW); +#ifdef SERVER + if (!pl.ammo_handgrenade) { + Weapons_RemoveItem(pl, WEAPON_BUGBAIT); + } +#endif + pl.w_attack_next = 0.5f; + pl.w_idle_next = 0.5f; + pl.mode_tempstate = 0; + } else { + Weapons_ViewAnimation(pl, BUGBAIT_IDLE); + pl.w_idle_next = 3.0f; + } +} + +float +w_bugbait_aimanim(player pl) +{ + return pl.flags & FL_CROUCHING ? ANIM_CR_AIMCROWBAR : ANIM_AIMCROWBAR; +} + +void +w_bugbait_hudpic(player pl, int selected, vector pos, float a) +{ +#ifdef CLIENT + vector hud_col = g_hud_color; + + if (selected) { + drawsubpic( + pos, + [128,64], + "materials/Sprites/w_icons3", + [0, 0.5], + [128/256,64/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [128,64], + "materials/Sprites/w_icons3", + [0, 0.5], + [128/256,64/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } + + HUD_DrawAmmoBar(pos, pl.ammo_handgrenade, MAX_A_HANDGRENADE, a); +#endif +} + +int +w_bugbait_isempty(player pl) +{ + + if (pl.ammo_handgrenade <= 0) + return 1; + + return 0; +} + +weapontype_t +w_bugbait_type(player pl) +{ + return WPNTYPE_THROW; +} + +weapon_t w_bugbait = +{ + .name = "grenade", + .id = ITEM_HANDGRENADE, + .slot = 5, + .slot_pos = 0, + .weight = 5, + .draw = w_bugbait_draw, + .holster = w_bugbait_holster, + .primary = w_bugbait_primary, + .secondary = w_bugbait_secondary, + .reload = __NULL__, + .release = w_bugbait_release, + .postdraw = w_bugbait_hud, + .precache = w_bugbait_precache, + .pickup = w_bugbait_pickup, + .updateammo = w_bugbait_updateammo, + .wmodel = w_bugbait_wmodel, + .pmodel = w_bugbait_pmodel, + .deathmsg = w_bugbait_deathmsg, + .aimanim = w_bugbait_aimanim, + .isempty = w_bugbait_isempty, + .type = w_bugbait_type, + .hudpic = w_bugbait_hudpic +}; \ No newline at end of file diff --git a/src/shared/w_crossbow.qc b/src/shared/w_crossbow.qc new file mode 100644 index 0000000..6614fd5 --- /dev/null +++ b/src/shared/w_crossbow.qc @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2016-2021 Marco Cawthorne + * + * 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 +{ + CROSSBOW_IDLE, + CROSSBOW_IDLE_EMPTY, + CROSSBOW_DRAW, + CROSSBOW_FIRE, + CROSSBOW_RELOAD, + CROSSBOW_HOLSTER, + CROSSBOW_IDLE_TO_LOW, + CROSSBOW_LOW_TO_IDLE, + CROSSBOW_LOW_IDLE +}; + +void +w_crossbow_precache(void) +{ +#ifdef SERVER + Sound_Precache("weapon_crossbow.fire"); + Sound_Precache("weapon_crossbow.empty"); + Sound_Precache("weapon_crossbow.hit"); + Sound_Precache("weapon_crossbow.hitbody"); + Sound_Precache("weapon_crossbow.reload"); + precache_model("models/crossbow_bolt.mdl"); + precache_model("models/w_crossbow.mdl"); +#else + precache_model("models/weapons/v_crossbow_dx7.mdl"); + precache_model("models/p_crossbow.mdl"); +#endif +} + +void +w_crossbow_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, pl.crossbow_mag, pl.ammo_bolt, -1); +} + +string +w_crossbow_wmodel(void) +{ + return "models/w_crossbow.mdl"; +} + +string +w_crossbow_pmodel(player pl) +{ + return "models/p_crossbow.mdl"; +} + +string +w_crossbow_deathmsg(void) +{ + return ""; +} + +int +w_crossbow_pickup(player pl, int new, int startammo) +{ +#ifdef SERVER + int addAmmo = (startammo == -1) ? 1 : startammo; + + if (new) { + pl.crossbow_mag = addAmmo; + return (1); + } + + if (pl.ammo_bolt < MAX_A_BOLT) { + pl.ammo_bolt = bound(0, pl.ammo_bolt + addAmmo, MAX_A_BOLT); + } else { + if (!new) + return (0); + } + +#endif + return (1); +} + +void +w_crossbow_draw(player pl) +{ + Weapons_SetModel("models/weapons/v_crossbow_dx7.mdl"); + + Weapons_ViewAnimation(pl, CROSSBOW_DRAW); + pl.w_idle_next = 1.0f; +} + +void +w_crossbow_holster(player pl) +{ + Weapons_ViewAnimation(pl, CROSSBOW_HOLSTER); +} + +void +w_crossbow_primary(player pl) +{ + if (pl.w_attack_next > 0.0) + return; + if (pl.gflags & GF_SEMI_TOGGLED) + return; + + /* ammo check */ + if ((pl.crossbow_mag <= 0i) ? true : false) { +#ifdef SERVER + Sound_Play(pl, CHAN_AUTO, "weapon_crossbow.empty"); +#endif + pl.gflags |= GF_SEMI_TOGGLED; + return; + } + + pl.crossbow_mag--; + +#ifndef CLIENT + HLGameRules rules = (HLGameRules) g_grMode; + + /* multiplayer uses hitscan when zoomed in */ + if (rules.IsMultiplayer() == true && pl.viewzoom < 1.0) { + vector src, dest; + src = pl.origin + pl.view_ofs; + Weapons_MakeVectors(pl); + dest = src + v_forward * 4096; + traceline(src, dest, MOVE_LAGGED, pl); + + if (trace_ent.takedamage == DAMAGE_YES) + Damage_Apply(trace_ent, pl, Skill_GetValue("plr_xbow_bolt_monster", 50), WEAPON_CROSSBOW, DMG_BLUNT); + + if (other.iBleeds == FALSE) + pointparticles(particleeffectnum("platform.spark"), self.origin, trace_plane_normal, 1); + else + FX_Blood(trace_endpos, [1,0,0]); + + /* fake bolt */ + if (trace_ent == world) { + NSRenderableEntity bolt_used = spawn(NSRenderableEntity); + bolt_used.SetSolid(SOLID_NOT); + bolt_used.SetMovetype(MOVETYPE_NONE); + bolt_used.SetModel("models/crossbow_bolt.mdl"); + bolt_used.SetSize([0,0,0], [0,0,0]); + bolt_used.SetAngles(pl.v_angle); + bolt_used.SetOrigin(trace_endpos + v_forward * -16); + bolt_used.think = Util_Destroy; + bolt_used.nextthink = time + 10.0f; + } + } else { + /* zoomed out = explosive */ + if (rules.IsMultiplayer() == true) { + NSProjectile_SpawnDef("projectile_arrowExplosive", pl); + } else { + NSProjectile_SpawnDef("projectile_arrow", pl); + } + } + + if (pl.crossbow_mag > 0) { + Sound_Play(pl, 8, "weapon_crossbow.hitbody"); + } + + Sound_Play(pl, CHAN_WEAPON, "weapon_crossbow.fire"); +#endif + + Weapons_ViewAnimation(pl, CROSSBOW_FIRE); + + if (pl.flags & FL_CROUCHING) + Animation_PlayerTop(pl, ANIM_CR_SHOOTBOW, 0.25f); + else + Animation_PlayerTop(pl, ANIM_SHOOTBOW, 0.25f); + + Weapons_ViewPunchAngle(pl, [-2,0,0]); + + pl.w_attack_next = + pl.w_idle_next = 0.65f; +} + +void +w_crossbow_secondary(player pl) +{ + if (pl.w_attack_next) { + return; + } + /* Simple toggle of fovs */ + if (pl.viewzoom == 1.0f) { + pl.viewzoom = 0.2f; + } else { + pl.viewzoom = 1.0f; + } + pl.w_attack_next = 0.5f; +} + +void +w_crossbow_reload(player pl) +{ + NSTimer reload = __NULL__; + + if (pl.w_attack_next > 0.0) { + return; + } + + if (pl.ammo_bolt <= 0) { + return; + } + if (pl.crossbow_mag >= 1) { + return; + } + + /* undo our zoom */ + pl.viewzoom = 1.0f; + +#ifdef SERVER + static void w_crossbow_reload_done(void) { + player pl = (player)self; + Weapons_ReloadWeapon(pl, player::crossbow_mag, player::ammo_bolt, 1); + Weapons_ViewAnimation(pl, CROSSBOW_IDLE); + } + + reload.TemporaryTimer(pl, w_crossbow_reload_done, 4.4f, false); + Sound_Play(pl, CHAN_ITEM, "weapon_crossbow.reload"); +#endif + + Weapons_ViewAnimation(pl, CROSSBOW_RELOAD); + + pl.w_attack_next = + pl.w_idle_next = 1.8f; +} + +void +w_crossbow_release(player pl) +{ + /* auto-reload if need be */ + if (pl.w_attack_next <= 0.0) + if (pl.crossbow_mag == 0 && pl.ammo_bolt > 0) { + Weapons_ViewAnimation(pl, CROSSBOW_IDLE); + Weapons_Reload(pl); + return; + } + + if (pl.w_idle_next > 0.0) { + return; + } + + if (pl.crossbow_mag) { + Weapons_ViewAnimation(pl, CROSSBOW_IDLE); + } else { + Weapons_ViewAnimation(pl, CROSSBOW_IDLE_EMPTY); + } + + pl.w_idle_next = 0.0f; +} + +void +w_crossbow_crosshair(player pl) +{ +#ifdef CLIENT + vector pos = g_hudmins + [g_hudres[0] / 2, g_hudres[1] / 2]; + Font_DrawText_RGBA(pos + [-7, -14], "Q", g_hud_color, 1.0, FONT_HUD_CROSS); + + HUD_DrawAmmo1(); + HUD_DrawAmmo2(); +#endif +} + +float +w_crossbow_aimanim(player pl) +{ + return pl.flags & FL_CROUCHING ? ANIM_CR_AIMBOW : ANIM_AIMBOW; +} + +void +w_crossbow_hudpic(player pl, int selected, vector pos, float a) +{ +#ifdef CLIENT + vector hud_col; + + if (pl.crossbow_mag == 0 && pl.ammo_bolt == 0) + hud_col = [1,0,0]; + else + hud_col = g_hud_color; + + if (selected) { + drawsubpic( + pos, + [128,64], + "materials/Sprites/w_icons2", + [0, 0.75], + [128/256,64/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [128,64], + "materials/Sprites/w_icons2", + [0, 0.75], + [128/256,64/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } + + HUD_DrawAmmoBar(pos, pl.ammo_bolt, MAX_A_BOLT, a); +#endif +} + +int +w_crossbow_isempty(player pl) +{ + if (pl.crossbow_mag <= 0 && pl.ammo_bolt <= 0) + return 1; + + return 0; +} + +weapontype_t w_crossbow_type(player pl) +{ + return WPNTYPE_RANGED; +} + +weapon_t w_crossbow = +{ + .name = "crossbow", + .id = ITEM_CROSSBOW, + .slot = 3, + .slot_pos = 1, + .weight = 10, + .draw = w_crossbow_draw, + .holster = w_crossbow_holster, + .primary = w_crossbow_primary, + .secondary = w_crossbow_secondary, + .reload = w_crossbow_reload, + .release = w_crossbow_release, + .postdraw = w_crossbow_crosshair, + .precache = w_crossbow_precache, + .pickup = w_crossbow_pickup, + .updateammo = w_crossbow_updateammo, + .wmodel = w_crossbow_wmodel, + .pmodel = w_crossbow_pmodel, + .deathmsg = w_crossbow_deathmsg, + .aimanim = w_crossbow_aimanim, + .isempty = w_crossbow_isempty, + .type = w_crossbow_type, + .hudpic = w_crossbow_hudpic +}; \ No newline at end of file diff --git a/src/shared/w_crowbar.qc b/src/shared/w_crowbar.qc new file mode 100644 index 0000000..b14ea7c --- /dev/null +++ b/src/shared/w_crowbar.qc @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2016-2020 Marco Cawthorne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +enum +{ + CBAR_IDLE, + CBAR_DRAW, + CBAR_ATTACK1MISS, + CBAR_ATTACK2MISS, + CBAR_ATTACK1HIT, + CBAR_ATTACK2HIT, + CBAR_ATTACK3HIT, + CBAR_ATTACK3MISS, + CBAR_HOLSTER +}; + +void +w_crowbar_precache(void) +{ +#ifdef SERVER + Sound_Precache("weapon_crowbar.hit"); + Sound_Precache("weapon_crowbar.miss"); + Sound_Precache("weapon_crowbar.hitbody"); + precache_model("models/w_crowbar.mdl"); +#else + precache_model("models/weapons/v_crowbar.mdl"); + precache_model("models/p_crowbar.mdl"); +#endif +} + +void +w_crowbar_updateammo(player pl) +{ + +} + +string +w_crowbar_wmodel(void) +{ + return "models/w_crowbar.mdl"; +} +string +w_crowbar_pmodel(player pl) +{ + return "models/p_crowbar.mdl"; +} + +string +w_crowbar_deathmsg(void) +{ + return "%s was assaulted by %s's Crowbar."; +} + +void +w_crowbar_draw(player pl) +{ + Weapons_SetModel("models/weapons/v_crowbar.mdl"); + Weapons_ViewAnimation(pl, CBAR_DRAW); + pl.w_idle_next = 0.8f; +} + +void +w_crowbar_holster(player pl) +{ + Weapons_ViewAnimation(pl, CBAR_HOLSTER); +} + +void +w_crowbar_primary(player pl) +{ + int anim = 0; + vector src; + + if (pl.w_attack_next) { + return; + } + + Weapons_MakeVectors(pl); + src = pl.origin + pl.view_ofs; + + /* make sure we can gib corpses */ + int oldhitcontents = pl.hitcontentsmaski; + pl.hitcontentsmaski = CONTENTBITS_POINTSOLID | CONTENTBIT_CORPSE; + traceline(src, src + (v_forward * 64), FALSE, pl); + pl.hitcontentsmaski = oldhitcontents; + + if (trace_fraction >= 1.0) { + pl.w_attack_next = 0.5f; + pl.w_idle_next = 0.65f; + } else { + pl.w_attack_next = 0.45f; + pl.w_idle_next = 0.5f; + } + + int r = (float)input_sequence % 3.0f; + switch (r) { + case 0: + Weapons_ViewAnimation(pl, trace_fraction >= 1 ? CBAR_ATTACK1MISS:CBAR_ATTACK1HIT); + break; + case 1: + Weapons_ViewAnimation(pl, trace_fraction >= 1 ? CBAR_ATTACK2MISS:CBAR_ATTACK2HIT); + break; + default: + Weapons_ViewAnimation(pl, trace_fraction >= 1 ? CBAR_ATTACK2MISS:CBAR_ATTACK3HIT); + } + + if (pl.flags & FL_CROUCHING) + Animation_PlayerTop(pl, ANIM_CR_SHOOTCROWBAR, 0.41f); + else + Animation_PlayerTop(pl, ANIM_SHOOTCROWBAR, 0.5f); + +#ifdef SERVER + Sound_Play(pl, CHAN_WEAPON, "Weapon_Crowbar.Single"); + + 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 { + SurfData_Impact(trace_ent, trace_endpos, trace_plane_normal); + } + + if (trace_ent.takedamage) { + Damage_Apply(trace_ent, pl, Skill_GetValue("plr_crowbar", 10), WEAPON_CROWBAR, DMG_BLUNT); + if (trace_ent.iBleeds) { + Sound_Play(pl, CHAN_WEAPON, "Weapon_Crowbar.Melee_Hit"); + } + } else { + //Sound_Play(pl, CHAN_WEAPON, "Weapon_Crowbar.Melee_HitWorld"); + } +#endif +} + +void +w_crowbar_release(player pl) +{ + if (pl.w_idle_next > 0.0) { + return; + } + + Weapons_ViewAnimation(pl, CBAR_IDLE); + pl.w_idle_next = 15.0f; +} + +float +w_crowbar_aimanim(player pl) +{ + return pl.flags & FL_CROUCHING ? ANIM_CR_AIMCROWBAR : ANIM_AIMCROWBAR; +} + +void +w_crowbar_hudpic(player pl, int selected, vector pos, float a) +{ +#ifdef CLIENT + vector hud_col = g_hud_color; + + if (selected) { + drawsubpic( + pos, + [128,64], + "materials/Sprites/w_icons1", + [0, 0], + [128/256,64/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [128,64], + "materials/Sprites/w_icons1", + [0, 0], + [128/256,64/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } +#endif +} + +int +w_crowbar_isempty(player pl) +{ + return 0; +} + +weapontype_t w_crowbar_type(player pl) +{ + return WPNTYPE_CLOSE; +} + +weapon_t w_crowbar = +{ + .name = "crowbar", + .id = ITEM_CROWBAR, + .slot = 0, + .slot_pos = 0, + .weight = 0, + .draw = w_crowbar_draw, + .holster = w_crowbar_holster, + .primary = w_crowbar_primary, + .secondary = __NULL__, + .reload = __NULL__, + .release = w_crowbar_release, + .postdraw = __NULL__, + .precache = w_crowbar_precache, + .pickup = __NULL__, + .updateammo = w_crowbar_updateammo, + .wmodel = w_crowbar_wmodel, + .pmodel = w_crowbar_pmodel, + .deathmsg = w_crowbar_deathmsg, + .aimanim = w_crowbar_aimanim, + .isempty = w_crowbar_isempty, + .type = w_crowbar_type, + .hudpic = w_crowbar_hudpic +}; diff --git a/src/shared/w_frag.qc b/src/shared/w_frag.qc new file mode 100644 index 0000000..74411ec --- /dev/null +++ b/src/shared/w_frag.qc @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2016-2021 Marco Cawthorne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef SERVER +.float nadeCookingTime; +#endif + +enum +{ + HANDGRENADE_IDLE, + HANDGRENADE_DRAWBACKHIGH, + HANDGRENADE_DRAWBACKLOW, + HANDGRENADE_THROW, + HANDGRENADE_ROLL, + HANDGRENADE_LOB, + HANDGRENADE_DRAW, +}; + +void w_frag_precache(void) +{ +#ifdef SERVER + Sound_Precache("weapon_frag.bounce"); + precache_model("models/w_grenade.mdl"); + particleeffectnum("fx_explosion.main"); + precache_model("sprites/fexplo.spr"); +#else + precache_model("models/weapons/v_grenade.mdl"); + precache_model("models/p_grenade.mdl"); +#endif +} + +void w_frag_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, -1, pl.ammo_handgrenade, -1); +} + +string w_frag_wmodel(void) +{ + return "models/w_grenade.mdl"; +} + +string w_frag_pmodel(player pl) +{ + return "models/p_grenade.mdl"; +} + +string w_frag_deathmsg(void) +{ + return ""; +} + +int w_frag_pickup(player pl, int new, int startammo) +{ +#ifdef SERVER + int addAmmo = (startammo == -1) ? 1 : startammo; + + if (pl.ammo_handgrenade < MAX_A_HANDGRENADE) { + pl.ammo_handgrenade = bound(0, pl.ammo_handgrenade + addAmmo, MAX_A_HANDGRENADE); + } else { + if (!new) + return (0); + } +#endif + return (1); +} + +void w_frag_draw(player pl) +{ + pl.mode_tempstate = 0; + + Weapons_SetModel("models/weapons/v_grenade.mdl"); + Weapons_ViewAnimation(pl, HANDGRENADE_DRAW); + pl.w_idle_next = 0.95f; +} + +void w_frag_holster(player pl) +{ + +} +void w_frag_primary(player pl) +{ + if (pl.w_attack_next > 0.0) { + return; + } + + /* We're abusing this network variable for the holding check */ + if (pl.mode_tempstate > 0) { + return; + } + + /* Ammo check */ + if (pl.ammo_handgrenade <= 0) { + return; + } + + Weapons_ViewAnimation(pl, HANDGRENADE_DRAWBACKHIGH); + + pl.mode_tempstate = 1; + pl.w_attack_next = 0.3f; + pl.w_idle_next = 0.2f; + +#ifdef SERVER + pl.nadeCookingTime = time; +#endif +} + +void w_frag_hud(player pl) +{ +#ifdef CLIENT + HUD_DrawAmmo2(); +#endif +} + +void w_frag_release(player pl) +{ + if (pl.w_idle_next > 0.0) { + return; + } + + if (pl.mode_tempstate == 1) { + Weapons_ViewAnimation(pl, HANDGRENADE_THROW); +#ifdef SERVER + vector throwDirection; + float throwingStrength; + + NSProjectile nade = (NSProjectile )EntityDef_CreateClassname("projectile_frag"); + nade.SetOwner(pl); + + throwDirection = pl.v_angle; + throwDirection[0] = -10.0f; /* always aim a bit up */ + + /* diminish when aiming up */ + if (pl.v_angle[0] < 0) { + throwDirection[0] += (pl.v_angle[0] * 0.9f); + } else { /* increase when aiming down */ + throwDirection[0] += (pl.v_angle[0] * 1.1f); + } + + throwingStrength = bound(0, (90 - throwDirection[0]) * 5.0f, 1000); + + nade.Launch(pl.GetEyePos(), pl.v_angle, time - pl.nadeCookingTime, 0.0f, 0.0f); + makevectors(throwDirection); + nade.SetVelocity((v_forward * throwingStrength) + pl.GetVelocity()); +#endif + pl.ammo_handgrenade--; + pl.mode_tempstate = 2; + pl.w_attack_next = 1.0f; + pl.w_idle_next = 0.5f; + + if (pl.flags & FL_CROUCHING) + Animation_PlayerTop(pl, ANIM_CR_SHOOTCROWBAR, 0.41f); + else + Animation_PlayerTop(pl, ANIM_SHOOTCROWBAR, 0.5f); + } else if (pl.mode_tempstate == 2) { + Weapons_ViewAnimation(pl, HANDGRENADE_DRAW); +#ifdef SERVER + if (!pl.ammo_handgrenade) { + Weapons_RemoveItem(pl, WEAPON_FRAG); + } +#endif + pl.w_attack_next = 1.2f; + pl.w_idle_next = 1.2f; + pl.mode_tempstate = 0; + } else { + + Weapons_ViewAnimation(pl, HANDGRENADE_IDLE); + pl.w_idle_next = 3.0f; + } +} + +float +w_frag_aimanim(player pl) +{ + return pl.flags & FL_CROUCHING ? ANIM_CR_AIMCROWBAR : ANIM_AIMCROWBAR; +} + +void +w_frag_hudpic(player pl, int selected, vector pos, float a) +{ +#ifdef CLIENT + vector hud_col = g_hud_color; + + if (selected) { + drawsubpic( + pos, + [128,64], + "materials/Sprites/w_icons2", + [0.5, 0.5], + [128/256,64/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [128,64], + "materials/Sprites/w_icons2", + [0.5, 0.5], + [128/256,64/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } + + HUD_DrawAmmoBar(pos, pl.ammo_handgrenade, MAX_A_HANDGRENADE, a); +#endif +} + +int +w_frag_isempty(player pl) +{ + + if (pl.ammo_handgrenade <= 0) + return 1; + + return 0; +} + +weapontype_t +w_frag_type(player pl) +{ + return WPNTYPE_THROW; +} + +weapon_t w_frag = +{ + .name = "grenade", + .id = ITEM_HANDGRENADE, + .slot = 4, + .slot_pos = 0, + .weight = 5, + .draw = w_frag_draw, + .holster = w_frag_holster, + .primary = w_frag_primary, + .secondary = __NULL__, + .reload = __NULL__, + .release = w_frag_release, + .postdraw = w_frag_hud, + .precache = w_frag_precache, + .pickup = w_frag_pickup, + .updateammo = w_frag_updateammo, + .wmodel = w_frag_wmodel, + .pmodel = w_frag_pmodel, + .deathmsg = w_frag_deathmsg, + .aimanim = w_frag_aimanim, + .isempty = w_frag_isempty, + .type = w_frag_type, + .hudpic = w_frag_hudpic +}; \ No newline at end of file diff --git a/src/shared/w_gravitygun.qc b/src/shared/w_gravitygun.qc new file mode 100644 index 0000000..461f0cc --- /dev/null +++ b/src/shared/w_gravitygun.qc @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2016-2021 Marco Cawthorne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef CLIENT +var float TRAIL_EGONBEAM; + +string w_gravitygun_sparkframes[11]; + +void +w_gravitygun_beamfx(vector vecPos, vector vecEndPos, entity eOwner) +{ + trailparticles(TRAIL_EGONBEAM, eOwner, vecPos, vecEndPos); +} +#endif + +enum +{ + GRAVGUN_PADDING1, + GRAVGUN_PADDING2, + GRAVGUN_IDLE, + GRAVGUN_HOLD_IDLE, + GRAVGUN_DRAW, + GRAVGUN_HOLSTER, + GRAVGUN_FIRE, + GRAVGUN_ALTFIRE, +}; + +void w_gravitygun_precache(void) +{ +#ifdef SERVER + precache_sound("weapons/egon_windup2.wav"); + precache_sound("weapons/egon_run3.wav"); + precache_sound("weapons/egon_off1.wav"); + precache_model("models/w_gravitygun.mdl"); + Sound_Precache("weapon_egon.empty"); +#else + TRAIL_EGONBEAM = particleeffectnum("weapon_egon.beam"); + precache_model("models/weapons/v_physcannon.mdl"); + precache_model("models/p_egon.mdl"); + precache_model("sprites/xspark1.spr"); + + for (int i = 0; i < 11; i++) + w_gravitygun_sparkframes[i] = spriteframe("sprites/xspark1.spr", i, 0.0f); +#endif +} + +void w_gravitygun_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, -1, pl.ammo_uranium, -1); +} + +string w_gravitygun_wmodel(void) +{ + return "models/w_gravitygun.mdl"; +} + +string w_gravitygun_pmodel(player pl) +{ + return "models/p_egon.mdl"; +} + +string w_gravitygun_deathmsg(void) +{ + return ""; +} + +int w_gravitygun_pickup(player pl, int new, int startammo) +{ +#ifdef SERVER + int addAmmo = (startammo == -1) ? 20 : startammo; + + if (pl.ammo_uranium < MAX_A_URANIUM) { + pl.ammo_uranium = bound(0, pl.ammo_uranium + addAmmo, MAX_A_URANIUM); + } else { + if (!new) + return (0); + } +#endif + return (1); +} + +void w_gravitygun_draw(player pl) +{ + pl.mode_tempstate = 0; + + Weapons_SetModel("models/weapons/v_physcannon.mdl"); + Weapons_ViewAnimation(pl, GRAVGUN_DRAW); + pl.w_idle_next = 0.95f; +} + +void w_gravitygun_holster(player pl) +{ + Weapons_ViewAnimation(pl, GRAVGUN_HOLSTER); +} + +void w_gravitygun_release(player pl); + +void w_gravitygun_primary(player pl) +{ + if (pl.w_attack_next > 0.0f) { + return; + } + + Weapons_ViewAnimation(pl, GRAVGUN_FIRE); + pl.w_attack_next = 0.6f; + pl.w_idle_next = 0.6f; +} +void w_gravitygun_secondary(player pl) +{ + if (pl.w_attack_next > 0.0f) { + return; + } + + + Weapons_ViewAnimation(pl, GRAVGUN_FIRE); + pl.w_attack_next = 0.4f; + pl.w_idle_next = 0.4f; +} + +void w_gravitygun_reload(player pl) +{ + +} + +void w_gravitygun_release(player pl) +{ + if (pl.w_idle_next > 0.0) + return; + + Weapons_ViewAnimation(pl, GRAVGUN_IDLE); + pl.w_idle_next = 2.0f; +} + +void +w_gravitygun_postdraw(player pl, int thirdperson) +{ +#ifdef CLIENT + if (!(pl.gflags & GF_EGONBEAM)) + return; + + vector src; + vector endpos; + + if (thirdperson) { + makevectors(pl.v_angle); + src = pl.origin; + endpos = pl.origin + (v_forward * 1024); + traceline(src, endpos, MOVE_NORMAL, pl); + w_gravitygun_beamfx(gettaginfo(pl.p_model, 10), trace_endpos, pl); + } else { + vector gunpos = gettaginfo(pSeat->m_eViewModel, 33); + src = gettaginfo(pSeat->m_eViewModel, 0); + makevectors(view_angles); + endpos = src + v_forward * 1024; + traceline(src, endpos, FALSE, pl); + w_gravitygun_beamfx(gunpos, endpos, pl); + } + + int i = (cltime*10.0f) % 11.0f; + vector fsize = [32,32]; + makevectors(view_angles); + trace_endpos += v_forward * -16; /* nudge towards our camera */ + dynamiclight_add(trace_endpos, 128, [0.5, 0.5, 1.0]); + + R_BeginPolygon(w_gravitygun_sparkframes[i], 1, 0); + R_PolygonVertex(trace_endpos + v_right * fsize[0] - v_up * fsize[1], + [1,1], [1,1,1], 1.0f); + R_PolygonVertex(trace_endpos - v_right * fsize[0] - v_up * fsize[1], + [0,1], [1,1,1], 1.0f); + R_PolygonVertex(trace_endpos - v_right * fsize[0] + v_up * fsize[1], + [0,0], [1,1,1], 1.0f); + R_PolygonVertex(trace_endpos + v_right * fsize[0] + v_up * fsize[1], + [1,0], [1,1,1], 1.0f); + R_EndPolygon(); +#endif +} + +void w_gravitygun_crosshair(player pl) +{ +#ifdef CLIENT + vector pos = g_hudmins + [g_hudres[0] / 2, g_hudres[1] / 2]; + Font_DrawText_RGBA(pos + [-7, -14], "Q", g_hud_color, 1.0, FONT_HUD_CROSS); + HUD_DrawAmmo2(); +#endif +} + +float w_gravitygun_aimanim(player pl) +{ + return pl.flags & FL_CROUCHING ? ANIM_CR_AIMEGON : ANIM_AIMEGON; +} + +void w_gravitygun_hudpic(player pl, int selected, vector pos, float a) +{ +#ifdef CLIENT + vector hud_col; + + if (pl.ammo_uranium == 0) + hud_col = [1,0,0]; + else + hud_col = g_hud_color; + + if (selected) { + drawsubpic( + pos, + [128,64], + "materials/Sprites/w_icons2", + [0.5, 0.75], + [128/256,64/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [128,64], + "materials/Sprites/w_icons2", + [0.5, 0.75], + [128/256,64/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } + + HUD_DrawAmmoBar(pos, pl.ammo_uranium, MAX_A_URANIUM, a); +#endif +} + +int +w_gravitygun_isempty(player pl) +{ + if (pl.ammo_uranium <= 0) + return 1; + + return 0; +} + +weapontype_t +w_gravitygun_type(player pl) +{ + return WPNTYPE_FULLAUTO; +} + +weapon_t w_gravitygun = +{ + .name = "egon", + .id = ITEM_EGON, + .slot = 0, + .slot_pos = 1, + .weight = 15, + .draw = w_gravitygun_draw, + .holster = w_gravitygun_holster, + .primary = w_gravitygun_primary, + .secondary = w_gravitygun_secondary, + .reload = w_gravitygun_reload, + .release = w_gravitygun_release, + .postdraw = w_gravitygun_crosshair, + .precache = w_gravitygun_precache, + .pickup = w_gravitygun_pickup, + .updateammo = w_gravitygun_updateammo, + .wmodel = w_gravitygun_wmodel, + .pmodel = w_gravitygun_pmodel, + .deathmsg = w_gravitygun_deathmsg, + .aimanim = w_gravitygun_aimanim, + .hudpic = w_gravitygun_hudpic, + .isempty = w_gravitygun_isempty, + .type = w_gravitygun_type, + .predraw = w_gravitygun_postdraw +}; \ No newline at end of file diff --git a/src/shared/w_pistol.qc b/src/shared/w_pistol.qc new file mode 100644 index 0000000..4a4247f --- /dev/null +++ b/src/shared/w_pistol.qc @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2016-2021 Marco Cawthorne + * + * 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 +{ + PISTOL_IDLE, // 0 + PISTOL_IDLE_EMPTY, // 1 + PISTOL_FIRE1, // 2 + PISTOL_FIRE2, // 3 + PISTOL_FIRE3, // 4 + PISTOL_FIRE4, // 5 + PISTOL_FIRE_EMPTY, // 6 + PISTOL_DRAW, //7 + PISTOL_DRAW_EMPTY, // 8 + PISTOL_RELOAD, // 9 + PISTOL_HOLSTER, + PISTOL_HOLSTER_EMPTY, + PISTOL_IDLE_TO_LOW, + PISTOL_LOW_TO_IDLE, + PISTOL_LOW_IDLE +}; + +#ifdef CLIENT +void w_pistol_ejectshell(void) +{ + static void w_pistol_ejectshell_death(void) { + remove(self); + } + static void w_pistol_ejectshell_touch(void) { + if (other == world) + Sound_Play(self, CHAN_BODY, "Bounce.Shell"); + } + entity eShell = spawn(); + setmodel(eShell, "models/weapons/shell.mdl"); + eShell.solid = SOLID_BBOX; + eShell.movetype = MOVETYPE_BOUNCE; + eShell.drawmask = MASK_ENGINE; + eShell.angles = [pSeat->m_eViewModel.angles[0], pSeat->m_eViewModel.angles[1], 0]; + eShell.velocity = pSeat->m_vecPredictedVelocity; + + makevectors(pSeat->m_eViewModel.angles); + eShell.velocity += (v_forward * 0); + eShell.velocity += (v_right * 80); + eShell.velocity += (v_up * 100); + eShell.touch = w_pistol_ejectshell_touch; + + eShell.avelocity = [0,45,900]; + eShell.think = w_pistol_ejectshell_death; + eShell.nextthink = time + 2.5f; + setsize(eShell, [0,0,0], [0,0,0]); + setorigin(eShell, pSeat->m_eViewModel.origin + (v_forward * 26) + (v_right * 8) + (v_up * -4)); +} +#endif + +void +w_pistol_precache(void) +{ +#ifdef SERVER + precache_model("models/w_9mmhandgun.mdl"); + precache_model("models/weapons/shell.mdl"); +#else + precache_model("models/weapons/v_pistol.mdl"); + precache_model("models/p_9mmhandgun.mdl"); + precache_model("models/weapons/shell.mdl"); +#endif +} + +void +w_pistol_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, pl.glock_mag, pl.ammo_9mm, -1); +} + +string +w_pistol_wmodel(void) +{ + return "models/w_9mmhandgun.mdl"; +} + +string +w_pistol_pmodel(player pl) +{ + return "models/p_9mmhandgun.mdl"; +} + +string +w_pistol_deathmsg(void) +{ + return ""; +} + +int +w_pistol_pickup(player pl, int new, int startammo) +{ +#ifdef SERVER + int addAmmo = (startammo == -1) ? 18 : startammo; + + if (new) { + pl.glock_mag = addAmmo; + return (1); + } + + if (pl.ammo_9mm < MAX_A_9MM) { + pl.ammo_9mm = bound(0, pl.ammo_9mm + addAmmo, MAX_A_9MM); + } else { + if (!new) + return (0); + } +#endif + return (1); +} + +void +w_pistol_draw(player pl) +{ + Weapons_SetModel("models/weapons/v_pistol.mdl"); + + if (pl.glock_mag) + Weapons_ViewAnimation(pl, PISTOL_DRAW); + else + Weapons_ViewAnimation(pl, PISTOL_DRAW_EMPTY); + + pl.w_idle_next = 0.8f; +} + +void +w_pistol_holster(player pl) +{ + if (pl.glock_mag) + Weapons_ViewAnimation(pl, PISTOL_HOLSTER); + else + Weapons_ViewAnimation(pl, PISTOL_HOLSTER_EMPTY); +} + +int +w_pistol_isempty(player pl) +{ + if (pl.glock_mag <= 0 && pl.ammo_9mm <= 0) + return 1; + + return 0; +} + +void +w_pistol_primary(player pl) +{ + if (pl.w_attack_next > 0.0) + return; + if (pl.gflags & GF_SEMI_TOGGLED) + return; + + /* ammo check */ + if ((pl.glock_mag <= 0i) ? true : false) { +#ifdef SERVER + Sound_Play(pl, CHAN_AUTO, "Weapon_Pistol.Empty"); +#endif + pl.gflags |= GF_SEMI_TOGGLED; + return; + } + + /* actual firing */ + pl.glock_mag--; + +#ifdef CLIENT + View_SetMuzzleflash(MUZZLE_SMALL); + View_AddEvent(w_pistol_ejectshell, 0.0f); +#else + TraceAttack_FireBullets(1, pl.origin + pl.view_ofs, Skill_GetValue("plr_9mm_bullet", 8), [0.01,0.01], WEAPON_PISTOL); + Sound_Play(pl, CHAN_WEAPON, "Weapon_Pistol.Single"); +#endif + + Weapons_ViewPunchAngle(pl, [-2,0,0]); + + if (pl.glock_mag) { + int r = floor(pseudorandom() * 3.0f); + Weapons_ViewAnimation(pl, PISTOL_FIRE2 + r); + } else { + Weapons_ViewAnimation(pl, PISTOL_FIRE_EMPTY); + } + + if (pl.flags & FL_CROUCHING) + Animation_PlayerTop(pl, ANIM_CR_SHOOT1HAND, 0.2f); + else + Animation_PlayerTop(pl, ANIM_SHOOT1HAND, 0.2f); + + pl.w_attack_next = 0.1f; + pl.w_idle_next = 0.4f; + pl.gflags |= GF_SEMI_TOGGLED; +} + +void +w_pistol_secondary(player pl) +{ + +} + +void +w_pistol_reload(player pl) +{ + if (pl.w_attack_next > 0.0) { + return; + } + + if (pl.glock_mag >= 18) { + return; + } + if (pl.ammo_9mm <= 0) { + return; + } + + Weapons_ViewAnimation(pl, PISTOL_RELOAD); + +#ifdef SERVER + static void w_pistol_reload_done(void) { + player pl = (player)self; + Weapons_ReloadWeapon(pl, player::glock_mag, player::ammo_9mm, 18); + } + + pl.think = w_pistol_reload_done; + pl.nextthink = time + 1.38f; + Sound_Play(pl, CHAN_WEAPON, "Weapon_Pistol.Reload"); +#endif + + pl.w_attack_next = 1.40f; + pl.w_idle_next = 1.40f; +} + +void +w_pistol_release(player pl) +{ + int r; + + /* auto-reload if need be */ + if (pl.w_attack_next <= 0.0) + if (pl.glock_mag == 0 && pl.ammo_9mm > 0) { + Weapons_ViewAnimation(pl, PISTOL_IDLE); + Weapons_Reload(pl); + return; + } + + if (pl.w_idle_next > 0.0) + return; + + if (pl.glock_mag) + Weapons_ViewAnimation(pl, PISTOL_IDLE); + else + Weapons_ViewAnimation(pl, PISTOL_IDLE_EMPTY); +} + +float +w_pistol_aimanim(player pl) +{ + return pl.flags & FL_CROUCHING ? ANIM_CR_AIM1HAND : ANIM_AIM1HAND; +} + +void +w_pistol_hud(player pl) +{ +#ifdef CLIENT + vector pos = g_hudmins + [g_hudres[0] / 2, g_hudres[1] / 2]; + Font_DrawText_RGBA(pos + [-7, -14], "Q", g_hud_color, 1.0, FONT_HUD_CROSS); + +#if 0 + drawsubpic( + pos + [-28, -28], + [56,56], + "materials/Sprites/qi_center", + [0,36/128], + [56/128, 56/128], + g_hud_color, + 1.0f, + DRAWFLAG_ADDITIVE + ); +#endif + + + HUD_DrawAmmo1(); + HUD_DrawAmmo2(); +#endif +} + +void +w_pistol_hudpic(player pl, int selected, vector pos, float a) +{ +#ifdef CLIENT + vector hud_col; + + if (pl.glock_mag == 0 && pl.ammo_9mm == 0) + hud_col = [1,0,0]; + else + hud_col = g_hud_color; + + if (selected) { + drawsubpic( + pos, + [128,64], + "materials/Sprites/w_icons1", + [0.5, 0.0], + [128/256,64/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [128,64], + "materials/Sprites/w_icons1", + [0.5, 0.0], + [128/256,64/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } + + HUD_DrawAmmoBar(pos, pl.ammo_9mm, MAX_A_9MM, a); +#endif +} + +weapontype_t +w_pistol_type(player pl) +{ + return WPNTYPE_RANGED; +} + +weapon_t w_pistol = +{ + .name = "9mmhandgun", + .id = ITEM_GLOCK, + .slot = 1, + .slot_pos = 0, + .weight = 10, + .draw = w_pistol_draw, + .holster = w_pistol_holster, + .primary = w_pistol_primary, + .secondary = w_pistol_secondary, + .reload = w_pistol_reload, + .release = w_pistol_release, + .postdraw = w_pistol_hud, + .precache = w_pistol_precache, + .pickup = w_pistol_pickup, + .updateammo = w_pistol_updateammo, + .wmodel = w_pistol_wmodel, + .pmodel = w_pistol_pmodel, + .deathmsg = w_pistol_deathmsg, + .aimanim = w_pistol_aimanim, + .isempty = w_pistol_isempty, + .type = w_pistol_type, + .hudpic = w_pistol_hudpic +}; diff --git a/src/shared/w_rpg.qc b/src/shared/w_rpg.qc new file mode 100644 index 0000000..be31928 --- /dev/null +++ b/src/shared/w_rpg.qc @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2016-2021 Marco Cawthorne + * + * 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 +{ + RPG_IDLE, + RPG_DRAW, + RPG_FIRE, + RPG_RELOAD, + RPG_UP_TO_DOWN, + RPG_DOWN_TO_UP, + RPG_DOWN_IDLE +}; + +void w_rpg_precache(void) +{ +#ifdef SERVER + Sound_Precache("weapon_rpg.shoot"); + Sound_Precache("weapon_rpg.empty"); + precache_model("models/w_rpg.mdl"); + precache_model("models/rpgrocket.mdl"); + Sound_Precache("fx.explosion"); +#else + precache_model("models/weapons/v_rpg.mdl"); + precache_model("models/p_rpg.mdl"); + precache_model("sprites/laserdot.spr"); +#endif +} + +void w_rpg_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, pl.rpg_mag, pl.ammo_rocket, -1); +} +string w_rpg_wmodel(void) +{ + return "models/w_rpg.mdl"; +} +string w_rpg_pmodel(player pl) +{ + return "models/p_rpg.mdl"; +} +string w_rpg_deathmsg(void) +{ + return ""; +} + +int w_rpg_pickup(player pl, int new, int startammo) +{ +#ifdef SERVER + int addAmmo = (startammo == -1) ? 2 : startammo; + + if (new) { + if (addAmmo > 1) { + pl.rpg_mag = 1; + pl.ammo_rocket = bound(0, pl.ammo_rocket + 1, MAX_A_ROCKET); + } else { + pl.rpg_mag = addAmmo; + } + return (1); + } + + if (pl.ammo_rocket < MAX_A_ROCKET) { + pl.ammo_rocket = bound(0, pl.ammo_rocket + 2, MAX_A_ROCKET); + } else { + if (!new) + return (0); + } +#endif + return (1); +} + +void w_rpg_draw(player pl) +{ + Weapons_SetModel("models/weapons/v_rpg.mdl"); + Weapons_ViewAnimation(pl, RPG_DRAW); + pl.ammo_rpg_state = 1; + pl.w_idle_next = 1.13f;; +} + +void w_rpg_holster(player pl) +{ + +} + +void w_rpg_primary(player pl) +{ + if (pl.w_attack_next > 0.0) + return; + if (pl.gflags & GF_SEMI_TOGGLED) + return; + + /* ammo check */ + if ((pl.rpg_mag <= 0i) ? true : false) { +#ifdef SERVER + Sound_Play(pl, CHAN_AUTO, "weapon_rpg.empty"); +#endif + pl.gflags |= GF_SEMI_TOGGLED; + return; + } + + pl.rpg_mag--; + +#ifdef SERVER + if (pl.ammo_rpg_state > 0) { + NSProjectile_SpawnDef("projectile_rocket_homing", pl); + } else { + NSProjectile_SpawnDef("projectile_rocket", pl); + } + + Sound_Play(pl, CHAN_WEAPON, "weapon_rpg.shoot"); +#endif + + Weapons_ViewAnimation(pl, RPG_FIRE); + Weapons_ViewPunchAngle(pl, [-10,0,0]); + + if (pl.flags & FL_CROUCHING) + Animation_PlayerTop(pl, ANIM_CR_SHOOTRPG, 0.43f); + else + Animation_PlayerTop(pl, ANIM_SHOOTRPG, 0.43f); + + pl.w_attack_next = + pl.w_idle_next = 1.16f; +} + +void w_rpg_reload(player pl) +{ + if (pl.w_attack_next > 0) { + return; + } + + /* Ammo check */ + if (pl.rpg_mag >= 1) { + return; + } + if (pl.ammo_rocket <= 0) { + return; + } + + Weapons_ViewAnimation(pl, RPG_RELOAD); + + /* Audio-Visual Bit */ +#ifdef SERVER + static void w_rpg_reload_done(void) { + player pl = (player)self; + Weapons_ReloadWeapon(pl, player::rpg_mag, player::ammo_rocket, 1); + } + + pl.think = w_rpg_reload_done; + pl.nextthink = time + 2.15f; +#endif + + pl.w_attack_next = 1.70f; + pl.w_idle_next = 1.70f; +} + +void w_rpg_release(player pl) +{ + /* auto-reload if need be */ + if (pl.w_attack_next <= 0.0) + if (pl.rpg_mag == 0 && pl.ammo_rocket > 0) { + Weapons_Reload(pl); + return; + } + + if (pl.w_idle_next > 0.0) { + return; + } + + Weapons_ViewAnimation(pl, RPG_IDLE); +} + +void w_rpg_secondary(player pl) +{ + + if (pl.w_attack_next > 0.0) { + return; + } + + /* toggle laser */ + pl.ammo_rpg_state = 1 - pl.ammo_rpg_state; + + pl.w_attack_next = 0.25f; + w_rpg_release(pl); +} + +float w_rpg_aimanim(player pl) +{ + return pl.flags & FL_CROUCHING ? ANIM_CR_AIMRPG : ANIM_AIMRPG; +} + +void w_rpg_hudpic(player pl, int selected, vector pos, float a) +{ +#ifdef CLIENT + vector hud_col; + + if (pl.rpg_mag == 0 && pl.ammo_rocket == 0) + hud_col = [1,0,0]; + else + hud_col = g_hud_color; + + if (selected) { + drawsubpic( + pos, + [128,64], + "materials/Sprites/w_icons3", + [0, 0.25], + [128/256,64/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [128,64], + "materials/Sprites/w_icons3", + [0, 0.25], + [128/256,64/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } + + HUD_DrawAmmoBar(pos, pl.ammo_rocket, MAX_A_ROCKET, a); +#endif +} + +void w_rpg_hud(player pl) +{ +#ifdef CLIENT + vector laser_pos; + vector aicon_pos; + + /* crosshair/laser */ + if (pl.ammo_rpg_state == 1) { + float lerp; + vector jitter = [0.0f, 0.0f, 0.0f]; + Weapons_MakeVectors(pl); + 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); + laser_pos = g_hudmins + (g_hudres / 2) + ([-lerp,-lerp] / 2); + + drawsubpic( + laser_pos + jitter, + [lerp,lerp], + g_laser_spr, + [0,0], + [1.0, 1.0], + [1,1,1], + 1.0f, + DRAWFLAG_ADDITIVE + ); + } + + vector pos = g_hudmins + [g_hudres[0] / 2, g_hudres[1] / 2]; + Font_DrawText_RGBA(pos + [-7, -14], "Q", g_hud_color, 1.0, FONT_HUD_CROSS); + + /* ammo counters */ + HUD_DrawAmmo1(); + HUD_DrawAmmo2(); +#endif +} + +int +w_rpg_isempty(player pl) +{ + + if (pl.rpg_mag <= 0 && pl.ammo_rocket <= 0) + return 1; + + return 0; +} + +weapontype_t +w_rpg_type(player pl) +{ + return WPNTYPE_RANGED; +} + +weapon_t w_rpg = +{ + .name = "rpg_rocket", + .id = ITEM_RPG, + .slot = 4, + .slot_pos = 1, + .weight = 20, + .draw = w_rpg_draw, + .holster = w_rpg_holster, + .primary = w_rpg_primary, + .secondary = w_rpg_secondary, + .reload = w_rpg_reload, + .release = w_rpg_release, + .postdraw = w_rpg_hud, + .precache = w_rpg_precache, + .pickup = w_rpg_pickup, + .updateammo = w_rpg_updateammo, + .wmodel = w_rpg_wmodel, + .pmodel = w_rpg_pmodel, + .deathmsg = w_rpg_deathmsg, + .aimanim = w_rpg_aimanim, + .isempty = w_rpg_isempty, + .type = w_rpg_type, + .hudpic = w_rpg_hudpic +}; diff --git a/src/shared/w_shotgun.qc b/src/shared/w_shotgun.qc new file mode 100644 index 0000000..7cbf547 --- /dev/null +++ b/src/shared/w_shotgun.qc @@ -0,0 +1,452 @@ +/* + * Copyright (c) 2016-2021 Marco Cawthorne + * + * 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_IDLE, + SHOTGUN_FIRE, + SHOTGUN_ALTFIRE, + SHOTGUN_DRAW, + SHOTGUN_HOLSTER, + SHOTGUN_START_RELOAD, + SHOTGUN_INSERT_SHELL, + SHOTGUN_END_RELOAD, + SHOTGUN_PUMP, + SHOTGUN_DRYFIRE, + SHOTGUN_LOW, + SHOTGUN_LOW_TO_IDLE, + SHOTGUN_IDLE_TO_LOW +}; + +enum +{ + SHOTTY_IDLE, + SHOTTY_RELOAD_START, + SHOTTY_RELOAD, + SHOTTY_MOVEDOWN, + SHOTTY_RELOAD_END, + SHOTTY_COCKSOUND +}; + +#ifdef CLIENT +void w_shotgun_ejectshell(void) +{ + static void w_shotgun_ejectshell_death(void) { + remove(self); + } + static void w_shotgun_ejectshell_touch(void) { + if (other == world) + Sound_Play(self, CHAN_BODY, "Bounce.ShotgunShell"); + } + entity eShell = spawn(); + setmodel(eShell, "models/weapons/shotgun_shell.mdl"); + eShell.solid = SOLID_BBOX; + eShell.movetype = MOVETYPE_BOUNCE; + eShell.drawmask = MASK_ENGINE; + eShell.angles = [pSeat->m_eViewModel.angles[0], pSeat->m_eViewModel.angles[1], 0]; + eShell.velocity = pSeat->m_vecPredictedVelocity; + + makevectors(pSeat->m_eViewModel.angles); + eShell.velocity += (v_forward * 0); + eShell.velocity += (v_right * 80); + eShell.velocity += (v_up * 100); + eShell.touch = w_shotgun_ejectshell_touch; + + eShell.avelocity = [0,45,900]; + eShell.think = w_shotgun_ejectshell_death; + eShell.nextthink = time + 2.5f; + setsize(eShell, [0,0,0], [0,0,0]); + setorigin(eShell, pSeat->m_eViewModel.origin + (v_forward * 26) + (v_right * 8) + (v_up * -8)); +} +#endif + +void w_shotgun_precache(void) +{ +#ifdef SERVER + precache_model("models/w_shotgun.mdl"); + precache_model("models/shotgunshell.mdl"); +#else + precache_model("models/weapons/v_shotgun.mdl"); + precache_model("models/p_shotgun.mdl"); + precache_model("models/shotgunshell.mdl"); +#endif +} + +void +w_shotgun_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, pl.shotgun_mag, pl.ammo_buckshot, -1); +} + +string +w_shotgun_wmodel(void) +{ + return "models/w_shotgun.mdl"; +} + +string +w_shotgun_pmodel(player pl) +{ + return "models/p_shotgun.mdl"; +} + +string +w_shotgun_deathmsg(void) +{ + return ""; +} + +int +w_shotgun_pickup(player pl, int new, int startammo) +{ +#ifdef SERVER + int addAmmo = (startammo == -1) ? 8 : startammo; + + if (new) { + pl.shotgun_mag = addAmmo; + return (1); + } + + if (pl.ammo_buckshot < MAX_A_BUCKSHOT) { + pl.ammo_buckshot = bound(0, pl.ammo_buckshot + addAmmo, MAX_A_BUCKSHOT); + } else { + if (!new) + return (0); + } +#endif + return (1); +} + +void +w_shotgun_draw(player pl) +{ + pl.mode_tempstate = 0; + + Weapons_SetModel("models/weapons/v_shotgun.mdl"); + Weapons_ViewAnimation(pl, SHOTGUN_DRAW); + pl.w_idle_next = 0.7f; +} + +void +w_shotgun_holster(player pl) +{ + Weapons_ViewAnimation(pl, SHOTGUN_HOLSTER); + pl.w_idle_next = 0.3f; +} + +void w_shotgun_release(player pl); + +void +w_shotgun_reload(player pl) +{ + if (pl.shotgun_mag >= 8) { + return; + } + if (pl.ammo_buckshot <= 0) { + return; + } + + if (pl.mode_tempstate > SHOTTY_IDLE) { + return; + } + pl.mode_tempstate = SHOTTY_RELOAD_START; + pl.w_idle_next = 0.0f; +} + +void +w_shotgun_primary(player pl) +{ + if (pl.gflags & GF_SEMI_TOGGLED) + return; + + /* Ammo check */ + if ((pl.shotgun_mag <= 0) || (pl.WaterLevel() >= WATERLEVEL_SUBMERGED)) { +#ifdef SERVER + Sound_Play(pl, CHAN_AUTO, "Weapon_Shotgun.Empty"); +#endif + pl.gflags |= GF_SEMI_TOGGLED; + return; + } + + if (pl.w_attack_next) { + w_shotgun_release(pl); + return; + } + + /* interrupt reloading if no longer empty */ + if (pl.mode_tempstate == SHOTTY_RELOAD && pl.shotgun_mag >= 1) { + pl.mode_tempstate = SHOTTY_RELOAD_END; + w_shotgun_release(pl); + return; + } else if (pl.mode_tempstate > SHOTTY_IDLE) { + w_shotgun_release(pl); + return; + } + + /* Ammo check */ + if (pl.shotgun_mag <= 0) { + w_shotgun_release(pl); + return; + } + +#ifdef SERVER + /* Singleplayer is more accurate */ + if (serverkeyfloat("sv_playerslots") == 1) { + TraceAttack_FireBullets(6, pl.origin + pl.view_ofs, Skill_GetValue("plr_buckshot", 5), [0.08716,0.08716], WEAPON_SHOTGUN); + } else { + TraceAttack_FireBullets(4, pl.origin + pl.view_ofs, Skill_GetValue("plr_buckshot", 5), [0.08716,0.04362], WEAPON_SHOTGUN); + } + Sound_Play(pl, CHAN_WEAPON, "Weapon_Shotgun.Single"); +#else + View_SetMuzzleflash(MUZZLE_WEIRD); + View_AddEvent(w_shotgun_ejectshell, 0.5f); +#endif + + Weapons_ViewAnimation(pl, SHOTGUN_FIRE); + Weapons_ViewPunchAngle(pl, [-5,0,0]); + + if (pl.flags & FL_CROUCHING) + Animation_PlayerTop(pl, ANIM_CR_SHOOTSHOTGUN, 0.41f); + else + Animation_PlayerTop(pl, ANIM_SHOOTSHOTGUN, 0.5f); + + pl.shotgun_mag--; + + /* after 1/2 a second, play the cocksound and eject shell */ + pl.mode_tempstate = SHOTTY_RELOAD_END; + pl.w_idle_next = 0.3f; + pl.w_attack_next = 0.3f; +} + +void +w_shotgun_secondary(player pl) +{ + if (pl.gflags & GF_SEMI_TOGGLED) + return; + + /* Ammo check */ + if ((pl.shotgun_mag <= 1) || (pl.WaterLevel() >= WATERLEVEL_SUBMERGED)) { +#ifdef SERVER + Sound_Play(pl, CHAN_AUTO, "Weapon_Shotgun.Empty"); +#endif + pl.gflags |= GF_SEMI_TOGGLED; + return; + } + + if (pl.w_attack_next) { + w_shotgun_release(pl); + return; + } + + /* interrupt reloading if no longer empty */ + if (pl.mode_tempstate == SHOTTY_RELOAD && pl.shotgun_mag >= 2) { + pl.mode_tempstate = SHOTTY_RELOAD_END; + w_shotgun_release(pl); + return; + } else if (pl.mode_tempstate > SHOTTY_IDLE) { + w_shotgun_release(pl); + return; + } + + /* Ammo check */ + if (pl.shotgun_mag <= 1) { + w_shotgun_reload(pl); + return; + } + + Weapons_ViewAnimation(pl, SHOTGUN_ALTFIRE); + Weapons_ViewPunchAngle(pl, [-10,0,0]); + + if (pl.flags & FL_CROUCHING) + Animation_PlayerTop(pl, ANIM_CR_SHOOTSHOTGUN, 0.41f); + else + Animation_PlayerTop(pl, ANIM_SHOOTSHOTGUN, 0.5f); + +#ifdef SERVER + /* Singleplayer is more accurate */ + if (serverkeyfloat("sv_playerslots") == 1) { + TraceAttack_FireBullets(12, pl.origin + pl.view_ofs, 5, [0.08716,0.08716], WEAPON_SHOTGUN); + } else { + TraceAttack_FireBullets(8, pl.origin + pl.view_ofs, 5, [0.17365,0.04362], WEAPON_SHOTGUN); + } + Sound_Play(pl, CHAN_WEAPON, "Weapon_Shotgun.Double"); +#else + View_SetMuzzleflash(MUZZLE_WEIRD); + View_AddEvent(w_shotgun_ejectshell, 1.0f); +#endif + /* after 1 second, play the cocksound and eject shell */ + pl.mode_tempstate = SHOTTY_RELOAD_END; + + pl.shotgun_mag -= 2; + pl.w_attack_next = 0.5f; + pl.w_idle_next = 0.5f; +} + +void +w_shotgun_release(player pl) +{ + /* auto-reload if need be */ + if (pl.w_attack_next <= 0.0) + if (pl.mode_tempstate == SHOTTY_IDLE && pl.shotgun_mag == 0 && pl.ammo_buckshot > 0) { + Weapons_Reload(pl); + return; + } + + if (pl.w_idle_next > 0.0) { + return; + } + + if (pl.mode_tempstate == SHOTTY_IDLE) { + Weapons_ViewAnimation(pl, SHOTGUN_IDLE); + pl.w_idle_next = 5.00f; + } else if (pl.mode_tempstate == SHOTTY_RELOAD_START) { + Weapons_ViewAnimation(pl, SHOTGUN_START_RELOAD); + pl.mode_tempstate = SHOTTY_RELOAD; + pl.w_idle_next = 0.5f; + } else if (pl.mode_tempstate == SHOTTY_RELOAD) { + Weapons_ViewAnimation(pl, SHOTGUN_INSERT_SHELL); + pl.shotgun_mag++; + pl.ammo_buckshot--; +#ifdef SERVER + Sound_Play(pl, CHAN_WEAPON, "Weapon_Shotgun.Reload"); +#endif + if (pl.ammo_buckshot <= 0 || pl.shotgun_mag >= 8) { + pl.mode_tempstate = SHOTTY_MOVEDOWN; + } + Weapons_UpdateAmmo(pl, pl.shotgun_mag, pl.ammo_buckshot, pl.mode_tempstate); + pl.w_idle_next = 0.4f; + } else if (pl.mode_tempstate == SHOTTY_MOVEDOWN) { + Weapons_ViewAnimation(pl, SHOTGUN_END_RELOAD); + pl.mode_tempstate = SHOTTY_RELOAD_END; + pl.w_idle_next = 0.4f; + pl.w_attack_next = 0.4f; + } else if (pl.mode_tempstate == SHOTTY_RELOAD_END) { + Weapons_ViewAnimation(pl, SHOTGUN_PUMP); +#ifdef SERVER + Sound_Play(pl, CHAN_AUTO, "Weapon_Shotgun.Special1"); +#endif + pl.mode_tempstate = SHOTTY_IDLE; + pl.w_idle_next = 0.5f; + pl.w_attack_next = 0.5f; + } else if (pl.mode_tempstate == SHOTTY_COCKSOUND) { +#ifdef CLIENT + +#else + //Sound_Play(pl, CHAN_WEAPON, "Weapon_Shotgun.Special1"); +#endif + pl.mode_tempstate = SHOTTY_IDLE; + pl.w_idle_next = 0.55f; + pl.w_attack_next = 0.55f; + } +} + +void +w_shotgun_crosshair(player pl) +{ +#ifdef CLIENT + vector pos = g_hudmins + [g_hudres[0] / 2, g_hudres[1] / 2]; + Font_DrawText_RGBA(pos + [-7, -14], "Q", g_hud_color, 1.0, FONT_HUD_CROSS); + + HUD_DrawAmmo1(); + HUD_DrawAmmo2(); +#endif +} + +float +w_shotgun_aimanim(player pl) +{ + return pl.flags & FL_CROUCHING ? ANIM_CR_AIMSHOTGUN : ANIM_AIMSHOTGUN; +} + +void +w_shotgun_hudpic(player pl, int selected, vector pos, float a) +{ +#ifdef CLIENT + vector hud_col; + + if (pl.shotgun_mag == 0 && pl.ammo_buckshot == 0) + hud_col = [1,0,0]; + else + hud_col = g_hud_color; + + if (selected) { + drawsubpic( + pos, + [128,64], + "materials/Sprites/w_icons2", + [0, 0.5], + [128/256,64/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [128,64], + "materials/Sprites/w_icons2", + [0, 0.5], + [128/256,64/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } + + HUD_DrawAmmoBar(pos, pl.ammo_buckshot, MAX_A_BUCKSHOT, a); +#endif +} + +int +w_shotgun_isempty(player pl) +{ + if (pl.shotgun_mag <= 0 && pl.ammo_buckshot <= 0) + return 1; + + return 0; +} + +weapontype_t +w_shotgun_type(player pl) +{ + return WPNTYPE_RANGED; +} + +weapon_t w_shotgun = +{ + .name = "shotgun", + .id = ITEM_SHOTGUN, + .slot = 3, + .slot_pos = 0, + .weight = 15, + .draw = w_shotgun_draw, + .holster = w_shotgun_holster, + .primary = w_shotgun_primary, + .secondary = w_shotgun_secondary, + .reload = w_shotgun_reload, + .release = w_shotgun_release, + .postdraw = w_shotgun_crosshair, + .precache = w_shotgun_precache, + .pickup = w_shotgun_pickup, + .updateammo = w_shotgun_updateammo, + .wmodel = w_shotgun_wmodel, + .pmodel = w_shotgun_pmodel, + .deathmsg = w_shotgun_deathmsg, + .aimanim = w_shotgun_aimanim, + .isempty = w_shotgun_isempty, + .type = w_shotgun_type, + .hudpic = w_shotgun_hudpic +}; \ No newline at end of file diff --git a/src/shared/w_smg1.qc b/src/shared/w_smg1.qc new file mode 100644 index 0000000..de868db --- /dev/null +++ b/src/shared/w_smg1.qc @@ -0,0 +1,388 @@ +/* + * Copyright (c) 2016-2021 Marco Cawthorne + * + * 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 +{ + SMG1_IDLE, + SMG1_FIRE1, + SMG1_FIRE2, + SMG1_FIRE3, + SMG1_FIRE4, + SMG1_ALTFIRE, + SMG1_DRAW, + SMG1_RELOAD, + SMG1_DRYFIRE, + SMG1_IDLE_TO_LOW, + SMG1_LOW_TO_IDLE, + SMG1_LOW +}; + +#ifdef CLIENT +void w_smg1_ejectshell(void) +{ + static void w_smg1_ejectshell_death(void) { + remove(self); + } + static void w_smg1_ejectshell_touch(void) { + if (other == world) + Sound_Play(self, CHAN_BODY, "Bounce.Shell"); + } + entity eShell = spawn(); + setmodel(eShell, "models/weapons/rifleshell.mdl"); + eShell.solid = SOLID_BBOX; + eShell.movetype = MOVETYPE_BOUNCE; + eShell.drawmask = MASK_ENGINE; + eShell.angles = [pSeat->m_eViewModel.angles[0], pSeat->m_eViewModel.angles[1], 0]; + eShell.velocity = pSeat->m_vecPredictedVelocity; + + float r = random(0.0, 50.0); + makevectors(pSeat->m_eViewModel.angles); + eShell.velocity += (v_forward * 0); + eShell.velocity += (v_right * 45); + eShell.velocity += (v_up * (145 + r)); + eShell.touch = w_smg1_ejectshell_touch; + + eShell.avelocity = [0,45,900]; + eShell.think = w_smg1_ejectshell_death; + eShell.nextthink = time + 2.5f; + setsize(eShell, [0,0,0], [0,0,0]); + setorigin(eShell, pSeat->m_eViewModel.origin + (v_forward * 30) + (v_right * 8) + (v_up * -15)); +} +#endif + +void +w_smg1_precache(void) +{ +#ifdef SERVER + precache_model("models/w_9mmar.mdl"); + precache_model("models/grenade.mdl"); +#else + precache_model("models/weapons/v_smg1.mdl"); + precache_model("models/p_9mmar.mdl"); +#endif +} + +int +w_smg1_pickup(player pl, int new, int startammo) +{ +#ifdef SERVER +#ifdef GEARBOX + int addAmmo = (startammo == -1) ? 50 : startammo; +#else + int addAmmo = (startammo == -1) ? 25 : startammo; +#endif + + if (new) { + pl.mp5_mag = addAmmo; + return (1); + } + + if (pl.ammo_9mm < MAX_A_9MM) { + pl.ammo_9mm = bound(0, pl.ammo_9mm + addAmmo, MAX_A_9MM); + } else { + if (!new) + return (0); + } +#endif + return (1); +} + +void +w_smg1_updateammo(player pl) +{ + Weapons_UpdateAmmo(pl, pl.mp5_mag, pl.ammo_9mm, pl.ammo_m203_grenade); +} + +string +w_smg1_wmodel(void) +{ + return "models/w_9mmar.mdl"; +} + +string +w_smg1_pmodel(player pl) +{ + return "models/p_9mmar.mdl"; +} + +string +w_smg1_deathmsg(void) +{ + return ""; +} + +void +w_smg1_draw(player pl) +{ + Weapons_SetModel("models/weapons/v_smg1.mdl"); + Weapons_ViewAnimation(pl, SMG1_DRAW); + pl.w_idle_next = 0.8f; +} + +void +w_smg1_holster(player pl) +{ + Weapons_ViewAnimation(pl, SMG1_LOW); +} + +void +w_smg1_primary(player pl) +{ + if (pl.w_attack_next > 0.0f) + return; + if (pl.gflags & GF_SEMI_TOGGLED) + return; + + /* Ammo check */ + bool out_of_ammo = (pl.mp5_mag <= 0i) ? true : false; + if (out_of_ammo || (pl.WaterLevel() >= WATERLEVEL_SUBMERGED)) { +#ifdef SERVER + Sound_Play(pl, CHAN_AUTO, "Weapon_SMG1.Empty"); +#endif + pl.gflags |= GF_SEMI_TOGGLED; + return; + } + + pl.mp5_mag--; + + /* Actual firing */ + int r = floor(pseudorandom() * 4.0f); + switch (r) { + case 1: + Weapons_ViewAnimation(pl, SMG1_FIRE1); + break; + case 2: + Weapons_ViewAnimation(pl, SMG1_FIRE2); + break; + case 3: + Weapons_ViewAnimation(pl, SMG1_FIRE2); + break; + default: + Weapons_ViewAnimation(pl, SMG1_FIRE3); + break; + } + + Weapons_ViewPunchAngle(pl, [-2,0,0]); + +#ifdef CLIENT + View_SetMuzzleflash(MUZZLE_RIFLE); + View_AddEvent(w_smg1_ejectshell, 0.0f); +#else + /* singleplayer is more accurate */ + if (cvar("sv_playerslots") == 1) { + TraceAttack_FireBullets(1, Weapons_GetCameraPos(pl), Skill_GetValue("plr_9mmAR_bullet", 5), [0.025,0.025], WEAPON_SMG1); + } else { + TraceAttack_FireBullets(1, Weapons_GetCameraPos(pl), Skill_GetValue("plr_9mmAR_bullet", 5), [0.05,0.05], WEAPON_SMG1); + } + + Sound_Play(pl, CHAN_WEAPON, "Weapon_SMG1.Single"); +#endif + + if (pl.flags & FL_CROUCHING) + Animation_PlayerTop(pl, ANIM_CR_SHOOTMP5, 0.1f); + else + Animation_PlayerTop(pl, ANIM_SHOOTMP5, 0.1f); + + pl.w_attack_next = 0.085f; + pl.w_idle_next = 0.233f; +} + +void +w_smg1_secondary(player pl) +{ + if (pl.w_attack_next > 0.0f) + return; + if (pl.gflags & GF_SEMI_TOGGLED) + return; + + /* Ammo check */ + bool out_of_ammo = (pl.ammo_m203_grenade <= 0i) ? true : false; + if (out_of_ammo || pl.WaterLevel() >= WATERLEVEL_SUBMERGED) { +#ifdef SERVER + Sound_Play(pl, CHAN_AUTO, "Weapon_SMG1.Empty"); +#endif + pl.gflags |= GF_SEMI_TOGGLED; + return; + } + + pl.ammo_m203_grenade--; + +#ifdef SERVER + NSProjectile_SpawnDef("projectile_ARgrenade", pl); + Sound_Play(pl, CHAN_WEAPON, "Weapon_SMG1.Double"); +#endif + + Weapons_ViewPunchAngle(pl, [-10.0f, 0.0f, 0.0f]); + Weapons_ViewAnimation(pl, SMG1_ALTFIRE); + + if (pl.flags & FL_CROUCHING) + Animation_PlayerTop(pl, ANIM_CR_SHOOTMP5, 0.45f); + else + Animation_PlayerTop(pl, ANIM_SHOOTMP5, 0.45f); + + pl.w_attack_next = 0.5f; + pl.w_idle_next = 0.5f; +} + +void +w_smg1_reload(player pl) +{ + if (pl.w_attack_next) { + return; + } + + /* Ammo check */ + if (pl.mp5_mag >= 50) { + return; + } + if (pl.ammo_9mm <= 0) { + return; + } + + Weapons_ViewAnimation(pl, SMG1_RELOAD); + +#ifdef SERVER + static void w_smg1_reload_done(void) { + player pl = (player)self; + Weapons_ReloadWeapon(pl, player::mp5_mag, player::ammo_9mm, 50); + } + + pl.think = w_smg1_reload_done; + pl.nextthink = time + 1.4f; +#endif + + pl.w_attack_next = 1.5f; + pl.w_idle_next = 1.5f; +} + +void +w_smg1_release(player pl) +{ + /* auto-reload if need be */ + if (pl.w_attack_next <= 0.0) + if (pl.mp5_mag == 0 && pl.ammo_9mm > 0) { + Weapons_Reload(pl); + return; + } + if (pl.w_idle_next > 0.0) { + return; + } + + Weapons_ViewAnimation(pl, SMG1_IDLE); + pl.w_idle_next = 15.0f; +} + +void +w_smg1_crosshair(player pl) +{ +#ifdef CLIENT + vector pos = g_hudmins + [g_hudres[0] / 2, g_hudres[1] / 2]; + Font_DrawText_RGBA(pos + [-7, -14], "Q", g_hud_color, 1.0, FONT_HUD_CROSS); + + HUD_DrawAmmo1(); + HUD_DrawAmmo2(); + HUD_DrawAmmo3(); + +#endif +} + +float +w_smg1_aimanim(player pl) +{ + return pl.flags & ANIM_CR_AIMMP5 ? ANIM_CR_AIMCROWBAR : ANIM_AIMMP5; +} + +void +w_smg1_hudpic(player pl, int selected, vector pos, float a) +{ +#ifdef CLIENT + vector hud_col; + + if (pl.mp5_mag == 0 && pl.ammo_9mm == 0 && pl.ammo_m203_grenade == 0) + hud_col = [1,0,0]; + else + hud_col = g_hud_color; + + if (selected) { + drawsubpic( + pos, + [128,64], + "materials/Sprites/w_icons1", + [0.5, 0.5], + [128/256,64/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } else { + drawsubpic( + pos, + [128,64], + "materials/Sprites/w_icons1", + [0.5, 0.5], + [128/256,64/256], + hud_col, + a, + DRAWFLAG_ADDITIVE + ); + } + + HUD_DrawAmmoBar(pos, pl.ammo_9mm, MAX_A_9MM, a); + HUD_DrawAmmoBar(pos + [25, 0], pl.ammo_m203_grenade, MAX_A_M203_GRENADE, a); +#endif +} + +int +w_smg1_isempty(player pl) +{ + + if (pl.mp5_mag <= 0 && pl.ammo_9mm <= 0 && pl.ammo_m203_grenade <= 0) + return 1; + + return 0; +} + +weapontype_t +w_smg1_type(player pl) +{ + return WPNTYPE_RANGED; +} + +weapon_t w_smg1 = +{ + .name = "9mmAR", + .id = ITEM_MP5, + .slot = 2, + .slot_pos = 0, + .weight = 15, + .draw = w_smg1_draw, + .holster = w_smg1_holster, + .primary = w_smg1_primary, + .secondary = w_smg1_secondary, + .reload = w_smg1_reload, + .release = w_smg1_release, + .postdraw = w_smg1_crosshair, + .precache = w_smg1_precache, + .pickup = w_smg1_pickup, + .updateammo = w_smg1_updateammo, + .wmodel = w_smg1_wmodel, + .pmodel = w_smg1_pmodel, + .deathmsg = w_smg1_deathmsg, + .aimanim = w_smg1_aimanim, + .isempty = w_smg1_isempty, + .type = w_smg1_type, + .hudpic = w_smg1_hudpic +}; \ No newline at end of file diff --git a/src/shared/weapons.h b/src/shared/weapons.h new file mode 100644 index 0000000..fbec4db --- /dev/null +++ b/src/shared/weapons.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2016-2021 Marco Cawthorne + * + * 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_GRAVITYGUN, + WEAPON_PISTOL, + WEAPON_357, + WEAPON_SMG1, + WEAPON_AR2, + WEAPON_SHOTGUN, + WEAPON_CROSSBOW, + WEAPON_FRAG, + WEAPON_RPG, + WEAPON_BUGBAIT +}; + +#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..ad68cb3 --- /dev/null +++ b/src/shared/weapons.qc @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016-2020 Marco Cawthorne + * + * 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_gravitygun, + w_pistol, + w_357, + w_smg1, + w_ar2, + w_shotgun, + w_crossbow, + w_frag, + w_rpg, + w_bugbait, +}; diff --git a/zpak001.pk3dir/def/9mmAR.def b/zpak001.pk3dir/def/9mmAR.def new file mode 100644 index 0000000..e26b697 --- /dev/null +++ b/zpak001.pk3dir/def/9mmAR.def @@ -0,0 +1,33 @@ +entityDef projectile_ARgrenade +{ + "spawnclass" "NSProjectile" + "model" "models/weapons/ar2_grenade.mdl" + "offset" "16 0 0" + "velocity" "800 0 0" + "angular_velocity" "-300 0 0" + "gravity" "0.5" + "bounce" "1" + "mins" "0 0 0" + "maxs" "0 0 0" + "detonate_on_fuse" "0" + "detonate_on_death" "1" + "detonate_on_world" "1" + "detonate_on_actor" "1" + "snd_explode" "BaseExplosionEffect.Sound" + "model_detonate" "fx_explosion.main" + + "def_damage" "damage_ARgrneadeDirect" + "def_splash_damage" "damage_ARgrneadeSplash" +} + + +entityDef damage_ARgrneadeDirect +{ + "damage" "50" +} + +entityDef damage_ARgrneadeSplash +{ + "damage" "skill:plr_9mmAR_grenade" + "radius" "160" +} \ No newline at end of file diff --git a/zpak001.pk3dir/def/handgrenade.def b/zpak001.pk3dir/def/handgrenade.def new file mode 100644 index 0000000..41164fd --- /dev/null +++ b/zpak001.pk3dir/def/handgrenade.def @@ -0,0 +1,27 @@ +entityDef projectile_frag +{ + "spawnclass" "NSProjectile" + "model" "models/weapons/w_grenade.mdl" + "frame" "1" + "fuse" "4" + "detonate_on_fuse" "1" + "bounce" "1" + "angular_velocity" "-350 0 0" + "model_detonate" "fx_explosion.main" + "snd_explode" "fx.explosion" + "snd_bounce" "weapon_handgrenade.bounce" + + "def_damage" "damage_handgrenadeDirect" + "def_splash_damage" "damage_handgrenadeSplash" +} + +entityDef damage_handgrenadeDirect +{ + "damage" "1" +} + +entityDef damage_handgrenadeSplash +{ + "damage" "skill:plr_hand_grenade" + "radius" "250" +} \ No newline at end of file diff --git a/zpak001.pk3dir/def/rpg.def b/zpak001.pk3dir/def/rpg.def new file mode 100644 index 0000000..8775423 --- /dev/null +++ b/zpak001.pk3dir/def/rpg.def @@ -0,0 +1,53 @@ +entityDef projectile_rocket +{ + "spawnclass" "NSProjectile" + "model" "models/weapons/w_missile.mdl" + + "def_damage" "damage_rocketDirect" + "def_splash_damage" "damage_rocketSplash" + + "health" "0" + "velocity" "250" + "angular_velocity" "0 0 200" + "fuse" "10" + "detonate_on_fuse" "0" + "detonate_on_death" "1" + "detonate_on_world" "1" + "detonate_on_actor" "1" + "impact_damage_effect" "1" + "impact_gib" "1" + + "thrust" "2000" + "thrust_start" "0.1" + "thrust_end" "2" + + "smoke_fly" "weapon_rpg.trail" + "model_detonate" "fx_explosion.main" + "light_color" "1 0.8 0.4" + "light_radius" "160" + "light_offset" "0 0 0" + + "explode_light_color" "2 1.6 0.8" + "explode_light_radius" "320" + "explode_light_fadetime" "0.5" + + "snd_explode" "fx.explosion" +} + +entityDef projectile_rocket_homing +{ + "inherit" "projectile_rocket" + "thrust_homing" "1" +} + +entityDef damage_rocketDirect +{ + "damage" "skill:plr_rocketlauncher_impact" + "damage_random" "skill:plr_rocketlauncher_impact_rand" +} + +entityDef damage_rocketSplash +{ + "damage" "skill:plr_rpg" + "radius" "250" +} \ No newline at end of file diff --git a/zpak001.pk3dir/default.cfg b/zpak001.pk3dir/default.cfg new file mode 100644 index 0000000..1a319fe --- /dev/null +++ b/zpak001.pk3dir/default.cfg @@ -0,0 +1,66 @@ +// 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" "FreeHL2 Server" +seta "maxplayers" "8" + +// 2D/HUD Variables +seta "con_color" "255 150 0" +seta "vgui_color" "255 170 0" +seta "cross_color" "0 255 0" + +// disable some nuclide niceties +seta cg_muzzleDLight 01 + +// config compat +alias mp_timelimit timelimit +alias mp_fraglimit fraglimit + +// video settings +seta gl_overbright 2 +seta gl_ldr 0 +seta r_lightmap_format rgb9e5 +seta rate 30000 // some HL configs set this to 2500 by default! + +exec skill_hl2.cfg + +seta cl_forwardspeed 190 +seta cl_sidespeed 190 +seta cl_backspeed 190 +seta cl_movespeedkey 1.684 +seta pm_maxspeed 320 \ No newline at end of file diff --git a/zpak001.pk3dir/fonts/hud_cross.font b/zpak001.pk3dir/fonts/hud_cross.font new file mode 100644 index 0000000..c8cdd0c --- /dev/null +++ b/zpak001.pk3dir/fonts/hud_cross.font @@ -0,0 +1,3 @@ +path "resource/HALFLIFE2.ttf" +size_x "32" +size_y "32" diff --git a/zpak001.pk3dir/particles/decal_impact.cfg b/zpak001.pk3dir/particles/decal_impact.cfg new file mode 100644 index 0000000..ee05f9d --- /dev/null +++ b/zpak001.pk3dir/particles/decal_impact.cfg @@ -0,0 +1,46 @@ +// Copyright (c) 2000-2019, Vera Visions. All rights reserved. + +r_part default +{ + texture "textures/particles/smoke" + tcoords 0 0 0.125 1 1 8 0.125 + count 1 + scale 32 + die 1 + rgb 25 25 25 + spawnmode ball + blend add + veladd 64 + randomvel 8 8 8 + spawnorg 0.25 + scalefactor 5 +} +r_part +default +{ + type cdecal + texture "textures/decals/impact_default" + tcoords 0 0 0.125 1 1 8 0.125 + rgbf 1 1 1 + scale 12 12 + die 30 60 + orgwrand 6 6 6 + rotationstart -180 180 +} +r_part +default +{ + type normal + blend add + texture "textures/particles/smoke" + tcoords 0 0 0.125 1 1 8 0.125 + rgbf 0 0 0 + alpha 1 + scale 8 + scalefactor 1 + scaledelta 128 + cliptype bounce + die 2 + veladd 25 + orgwrand 6 6 6 + randomvel 0 -8 8 + rotationstart -180 180 +} diff --git a/zpak001.pk3dir/particles/fx_explosion.cfg b/zpak001.pk3dir/particles/fx_explosion.cfg new file mode 100644 index 0000000..86e7af3 --- /dev/null +++ b/zpak001.pk3dir/particles/fx_explosion.cfg @@ -0,0 +1,97 @@ +r_part main +{ + texture "particles/fteparticlefont.tga" + tcoords 97 97 191 191 256 + count 1 + scale 200 + scalefactor 1 + die 1 + rgb 255 128 76 + rgbdelta 0 -32 -32 + friction 1 + blend add +} + +r_part +ember +{ + count 1 + texture "particles/fteparticlefont.tga" + tcoords 97 97 191 191 256 + rgb 255 128 76 + alpha 0 + scale 20 + scalefactor 1 + die 1 + friction 2.5 + blend add + randomvel 15 + veladd 2 + rampmode delta + ramp 0 0 0 -0.5 0 + ramp 0 0 0 0.1 0 + ramp 0 0 0 0.1 0 + ramp 0 0 0 0.1 0 + ramp 0 0 0 0.1 0 + ramp 0 0 0 0.1 0 +} + +r_part +main +{ + lighttime 1 + lightradius 350 + lightradiusfade 300 + lightrgb 1.0 0.5 0.4 + lightrgbfade 0.36 0.19 0.19 + count 0 0 1 + model "sprites/fexplo.spr" framestart=0 framecount=29 framerate=20 additive +} + +r_part +main +{ + cliptype expgib + texture "particles/fteparticlefont.tga" + tcoords 97 97 191 191 256 + alpha 0 + count 16 + die 1 + randomvel 128 + gravity 50 + friction 2 + emit ember + emitinterval 0.01 + spawnmode circle +} + +r_part +main +{ + texture "particles/fteparticlefont.tga" + tcoords 97 97 191 191 256 + count 1 + scale 324 + scalefactor 1 + die 3 + alpha 1 + rgb 0 0 0 + spawnmode ball + gravity -25 +} + +r_part +main +{ + type texturedspark + texture ball + tcoords 1 65 31 95 256 8 32 + scale 1 + count 8 + scalefactor 1 + alpha 0.5 + die 0.8 + rgb 255 115 0 + blend add + spawnmode ball + spawnvel 100 + veladd 100 + friction 0.5 + gravity 800 +} +