├── .github └── FUNDING.yml ├── LICENSE ├── README.md ├── img └── preview1.jpg ├── instructions.txt ├── manifest.fmf ├── src ├── Makefile ├── client │ ├── Makefile │ ├── cmds.qc │ ├── defs.h │ ├── draw.qc │ ├── entities.qc │ ├── game_event.qc │ ├── hallucination.qc │ ├── hud_ammonotify.qc │ ├── hud_itemnotify.qc │ ├── init.qc │ ├── progs.src │ ├── vgui_changeclass.qc │ ├── vgui_chooseteam.qc │ └── vox.qc ├── progs.src ├── server │ ├── Makefile │ ├── bot.qc │ ├── client.qc │ ├── defs.h │ ├── dispenser.qc │ ├── func_nobuild.qc │ ├── func_nogrenades.qc │ ├── gamerules.h │ ├── gamerules.qc │ ├── info_areadef.qc │ ├── info_player_teamspawn.qc │ ├── info_tfdetect.qc │ ├── info_tfgoal.qc │ ├── item_armor.qc │ ├── item_healthkit.qc │ ├── item_tfgoal.qc │ ├── nades.qc │ ├── progs.src │ ├── sentry.h │ ├── sentry.qc │ ├── server.qc │ ├── spawn.qc │ ├── teleporter.qc │ └── vox.qc └── shared │ ├── animations_tfc.h │ ├── defs.h │ ├── events.h │ ├── flags.h │ ├── include.src │ ├── items.h │ ├── player.qc │ ├── pmove.qc │ ├── w_asscan.qc │ ├── w_autorifle.qc │ ├── w_crowbar.qc │ ├── w_dbs.qc │ ├── w_flamer.qc │ ├── w_glauncher.qc │ ├── w_grapple.qc │ ├── w_incendiary.qc │ ├── w_knife.qc │ ├── w_medkit.qc │ ├── w_nailgun.qc │ ├── w_pipebomb.qc │ ├── w_railgun.qc │ ├── w_rpg.qc │ ├── w_sbs.qc │ ├── w_sniper.qc │ ├── w_supernail.qc │ ├── w_tranquil.qc │ ├── w_umbrella.qc │ ├── w_wrench.qc │ ├── weapon_baseautomatic.qc │ ├── weapon_basemelee.qc │ ├── weapon_baseprojectile.qc │ ├── weapon_basesemi.qc │ ├── weapon_baseshotgun.qc │ ├── weapons.h │ └── weapons.qc └── zpak001.pk3dir ├── data ├── avanti.way ├── badlands.way ├── casbah.way ├── crossover2.way ├── cz2.way ├── dustbowl.way ├── epicenter.way ├── flagrun.way ├── hunted.way ├── push.way ├── rock2.way ├── warpath.way └── well.way ├── def ├── armor.def ├── bot.def ├── monsters.def └── spawns.def ├── default.cfg ├── maps ├── 2fort_src.jpg ├── avanti_src.jpg ├── badlands_src.jpg ├── casbah_src.jpg ├── crossover2_src.jpg ├── cz2_src.jpg ├── dustbowl_src.jpg ├── epicenter_src.jpg ├── flagrun_src.jpg ├── hunted_src.jpg ├── push_src.jpg ├── rock2_src.jpg ├── warpath_src.jpg └── well_src.jpg ├── particles └── weapon_railgun.cfg ├── scripts └── constants.txt └── sound ├── items_tfc.sndshd ├── player_tfc.sndshd ├── turret_tfc.sndshd └── weapons_tfc.sndshd /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: eukara 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: ['https://www.paypal.me/eukara'] 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2016-2021, Marco "eukara" Hladik 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FreeTFC 2 | Clean-room reimplementation of Team Fortress Classic in QuakeC. 3 | 4 | ![Preview 1](img/preview1.jpg) 5 | 6 | ## Building 7 | Clone the repository into the Nuclide-SDK: 8 | 9 | > git clone REPOURL tfc 10 | 11 | then either run Nuclide's ./build_game.sh shell script, or issue 'make' inside 12 | ./tfc/src! 13 | 14 | Obviously make sure that Nuclide has fteqw and fteqcc set-up for building. 15 | 16 | ## Community 17 | 18 | ### Matrix 19 | If you're a fellow Matrix user, join the Nuclide Space to see live-updates and more! 20 | https://matrix.to/#/#nuclide:matrix.org 21 | 22 | ### IRC 23 | Join us on #freecs via irc.libera.chat and talk/lurk or discuss bugs, issues 24 | and other such things. It's bridged with the Matrix room of the same name! 25 | 26 | ### Others 27 | We've had people ask in the oddest of places for help, please don't do that. 28 | 29 | ## License 30 | ISC License 31 | 32 | Copyright (c) 2016-2021 Marco Hladik 33 | 34 | Permission to use, copy, modify, and distribute this software for any 35 | purpose with or without fee is hereby granted, provided that the above 36 | copyright notice and this permission notice appear in all copies. 37 | 38 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 39 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 40 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 41 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 42 | WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 43 | IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 44 | OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 45 | -------------------------------------------------------------------------------- /img/preview1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eukara/freetfc/1152939d934726b261b2f3ce74692ffc707c4e36/img/preview1.jpg -------------------------------------------------------------------------------- /instructions.txt: -------------------------------------------------------------------------------- 1 | In order to play this FreeHL addon, please move the folder this file is 2 | in into the same place where 'valve' and 'default.fmf' reside. Thanks! -------------------------------------------------------------------------------- /manifest.fmf: -------------------------------------------------------------------------------- 1 | FTEMANIFEST 1 2 | GAME tfc 3 | NAME "Team Fortress" 4 | BASEGAME platform 5 | BASEGAME valve 6 | BASEGAME tfc 7 | 8 | // you don't really want to change these 9 | RTCBROKER master.frag-net.com:27950 10 | PROTOCOLNAME "Nuclide" 11 | MAINCONFIG game.cfg 12 | DOWNLOADSURL "http://www.frag-net.com/dl/packages" 13 | 14 | -exec platform_default.cfg 15 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | CC=fteqcc 2 | 3 | all: 4 | cd client && $(MAKE) 5 | cd server && $(MAKE) 6 | -------------------------------------------------------------------------------- /src/client/Makefile: -------------------------------------------------------------------------------- 1 | CC=fteqcc 2 | 3 | all: 4 | $(CC) progs.src 5 | -------------------------------------------------------------------------------- /src/client/cmds.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2020 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | void VGUI_ChooseClass(void); 18 | 19 | int 20 | ClientGame_ConsoleCommand(void) 21 | { 22 | switch(argv(0)) { 23 | case "build": 24 | sendevent("TFCBuild", "i", stoi(argv(1))); 25 | break; 26 | case "dismantle": 27 | sendevent("TFCDismantle", "i", stoi(argv(1))); 28 | break; 29 | case "chooseclass": 30 | case "changeclass": 31 | VGUI_ChooseClass(); 32 | break; 33 | case "chooseteam": 34 | case "changeteam": 35 | VGUI_ChooseTeam(); 36 | break; 37 | 38 | case "+gren1": 39 | pSeat->m_iInputExtra1 = TRUE; 40 | break; 41 | case "-gren1": 42 | pSeat->m_iInputExtra1 = FALSE; 43 | break; 44 | case "+gren2": 45 | pSeat->m_iInputExtra2 = TRUE; 46 | break; 47 | case "-gren2": 48 | pSeat->m_iInputExtra2 = FALSE; 49 | break; 50 | default: 51 | return (0); 52 | } 53 | return (1); 54 | } 55 | -------------------------------------------------------------------------------- /src/client/defs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2022 Marco Cawthorne 3 | * Copyright (c) 2022 Gethyn ThomasQuail 4 | * 5 | * Permission to use, copy, modify, and distribute this software for any 6 | * purpose with or without fee is hereby granted, provided that the above 7 | * copyright notice and this permission notice appear in all copies. 8 | * 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 14 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 15 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | */ 17 | 18 | #define MAX_A_CELLS 200 19 | 20 | var string g_dmsg_spr; 21 | var string g_tfchud1_spr; 22 | var string g_tfchud2_spr; 23 | var string g_tfchud3_spr; 24 | var string g_tfchud4_spr; 25 | var string g_tfchud5_spr; 26 | var string g_tfchud6_spr; 27 | var string g_tfchud7_spr; 28 | 29 | var int MUZZLE_ROUND; 30 | 31 | 32 | void TFCHallucination_Insert(vector, vector); -------------------------------------------------------------------------------- /src/client/draw.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2022 Vera Visions LLC. 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #define TFC_HUD_TEAM_COLOR_RED [1, 0.15, 0.15] 18 | #define TFC_HUD_TEAM_COLOR_BLUE [0.15, 0.15, 1.0] 19 | #define TFC_HUD_TEAM_COLOR_GREEN [0.15, 1.0, 0.15] 20 | #define TFC_HUD_TEAM_COLOR_YELLOW [1.0, 1.0, 0.15] 21 | 22 | void 23 | ClientGame_PreDraw(void) 24 | { 25 | /* color the HUD according to the team we're on */ 26 | switch (getplayerkeyfloat(player_localnum, "*team")) { 27 | case 1: 28 | g_hud_color = TFC_HUD_TEAM_COLOR_BLUE; 29 | break; 30 | case 2: 31 | g_hud_color = TFC_HUD_TEAM_COLOR_RED; 32 | break; 33 | case 3: 34 | g_hud_color = TFC_HUD_TEAM_COLOR_GREEN; 35 | break; 36 | case 4: 37 | g_hud_color = TFC_HUD_TEAM_COLOR_YELLOW; 38 | break; 39 | } 40 | } 41 | 42 | void 43 | ClientGame_PostDraw(void) 44 | { 45 | player pl = (player)pSeat->m_ePlayer; 46 | 47 | if (serverkeyfloat("areadefs") == 1) { 48 | string strArea = getplayerkeyvalue(player_localnum, "*areadef"); 49 | float flOffset = Font_StringWidth(strArea, TRUE, FONT_20) / 2; 50 | Font_DrawText_A([g_hudmins[0] + 16, g_hudmins[1] + g_hudres[1] - 70], strArea, 0.75, FONT_20); 51 | } 52 | 53 | if (pl.g_items & ITEM_GOALITEM) { 54 | vector vecGoalItemPos; 55 | int iGoalItemTeam = (int)getplayerkeyfloat(player_localnum, "*goalitem_t"); 56 | 57 | vecGoalItemPos = g_hudmins + [16, (g_hudres[1] / 2) - 32]; 58 | 59 | if (iGoalItemTeam == 1) { /* blue */ 60 | drawsubpic( 61 | vecGoalItemPos, 62 | [64,64], 63 | g_tfchud1_spr, 64 | [192/256,0/256], 65 | [64/256, 64/256], 66 | TFC_HUD_TEAM_COLOR_BLUE, 67 | 1.0f, 68 | DRAWFLAG_ADDITIVE 69 | ); 70 | } else if (iGoalItemTeam == 2) { /* red */ 71 | drawsubpic( 72 | vecGoalItemPos, 73 | [64,64], 74 | g_tfchud1_spr, 75 | [192/256, 62/256], 76 | [64/256, 64/256], 77 | TFC_HUD_TEAM_COLOR_RED, 78 | 1.0f, 79 | DRAWFLAG_ADDITIVE 80 | ); 81 | } else if (iGoalItemTeam == 3) { /* green */ 82 | drawsubpic( 83 | vecGoalItemPos, 84 | [64,64], 85 | g_tfchud6_spr, 86 | [192/256, 62/256], 87 | [64/256, 136/256], 88 | TFC_HUD_TEAM_COLOR_GREEN, 89 | 1.0f, 90 | DRAWFLAG_ADDITIVE 91 | ); 92 | } else { /* yellow */ 93 | drawsubpic( 94 | vecGoalItemPos, 95 | [64,64], 96 | g_tfchud1_spr, 97 | [0/256,136/256], 98 | [64/256, 64/256], 99 | TFC_HUD_TEAM_COLOR_YELLOW, 100 | 1.0f, 101 | DRAWFLAG_ADDITIVE 102 | ); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/client/entities.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2020 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | int 18 | ClientGame_EntityUpdate(float id, float new) 19 | { 20 | switch (id) { 21 | default: 22 | return (0); 23 | } 24 | 25 | return (1); 26 | } 27 | -------------------------------------------------------------------------------- /src/client/game_event.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2022 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | int 18 | ClientGame_EventParse(float fHeader) 19 | { 20 | switch (fHeader) { 21 | case EV_TFC_VOXMSG: 22 | Vox_Parse(); 23 | break; 24 | case EV_OBITUARY: 25 | Obituary_Parse(); 26 | break; 27 | case EV_BLOOD: 28 | vector vBloodPos; 29 | vector vBloodColor; 30 | 31 | vBloodPos[0] = readcoord(); 32 | vBloodPos[1] = readcoord(); 33 | vBloodPos[2] = readcoord(); 34 | 35 | vBloodColor[0] = readbyte() / 255; 36 | vBloodColor[1] = readbyte() / 255; 37 | vBloodColor[2] = readbyte() / 255; 38 | 39 | FX_Blood(vBloodPos, vBloodColor); 40 | break; 41 | case EV_CHAT: 42 | float fSender = readbyte(); 43 | float fTeam = readbyte(); 44 | string sMessage = readstring(); 45 | 46 | CSQC_Parse_Print(sprintf("%s: %s", getplayerkeyvalue(fSender, "name"), sMessage), PRINT_CHAT); 47 | break; 48 | case EV_CHAT_TEAM: 49 | float fSender2 = readbyte(); 50 | float fTeam2 = readbyte(); 51 | string sMessage2 = readstring(); 52 | 53 | CSQC_Parse_Print(sprintf("[TEAM] %s: %s", getplayerkeyvalue(fSender2, "name"), sMessage2), PRINT_CHAT); 54 | break; 55 | case EV_VIEWMODEL: 56 | View_PlayAnimation(readbyte()); 57 | break; 58 | case EV_WEAPON_PICKUP: 59 | int w = readbyte(); 60 | 61 | if (autocvar_cl_autoweaponswitch == 1) { 62 | sendevent("PlayerSwitchWeapon", "i", w); 63 | } 64 | 65 | HUD_WeaponPickupNotify(w); 66 | break; 67 | default: 68 | return (0); 69 | } 70 | 71 | return (1); 72 | } 73 | -------------------------------------------------------------------------------- /src/client/hallucination.qc: -------------------------------------------------------------------------------- 1 | class 2 | TFCHallucination:NSEntity 3 | { 4 | 5 | }; 6 | 7 | void 8 | TFCHallucination_Insert(vector viewPosition, vector viewDirection) 9 | { 10 | int r = 0i; 11 | vector halluPos = viewPosition; 12 | 13 | halluPos += v_forward * random(8, 128); 14 | halluPos += v_up * random(-64, 128); 15 | halluPos += v_right * random(-256, 256); 16 | 17 | traceline(viewPosition, halluPos, MOVE_NORMAL, pSeat->m_ePlayer); 18 | halluPos = trace_endpos; 19 | 20 | makevectors([0, viewDirection[1], 0]); 21 | 22 | r = (int)(floor(random(0, 10))); 23 | 24 | switch (r) { 25 | case 1: /* blood splats */ 26 | for (int i = 0; i < 3; i++) { 27 | halluPos = viewPosition; 28 | halluPos += v_forward * random(8, 64); 29 | halluPos += v_up * random(-64, 64); 30 | halluPos += v_right * random(-64, 64); 31 | FX_Blood(halluPos, [1,0,0]); 32 | } 33 | pointsound(viewPosition, "weapons/cbar_hitbod1.wav", 1, ATTN_NORM); 34 | break; 35 | case 2: /* explosions */ 36 | pointparticles(particleeffectnum("fx_explosion.main"), halluPos, [0,0,0], 1); 37 | pSeat->m_flShakeDuration = 2; 38 | pSeat->m_flShakeAmp = 5.0; 39 | pSeat->m_flShakeFreq = 2; 40 | pSeat->m_flShakeTime = 2; 41 | pointsound(halluPos, sprintf("weapons/explode%d.wav", floor(random() * 2) + 3), 1, ATTN_NORM); 42 | break; 43 | case 3: /* shotgun impact */ 44 | traceline(viewPosition, halluPos + (v_forward * 1024), MOVE_NORMAL, pSeat->m_ePlayer); 45 | SurfData_Impact(world, trace_endpos, [0,0,0]); 46 | DecalGroups_Place("Impact.Shot", trace_endpos); 47 | pointsound(halluPos, "weapons/sbarrel1.wav", 1, ATTN_NORM); 48 | break; 49 | case 4: /* being hit by a crowbar */ 50 | pSeat->m_flShakeDuration = 1; 51 | pSeat->m_flShakeAmp = 1.0; 52 | pSeat->m_flShakeFreq = 2; 53 | pSeat->m_flShakeTime = 2; 54 | pointsound(halluPos, "weapons/cbar_hitbod1.wav", 1, ATTN_NORM); 55 | break; 56 | case 5: /* sniper impact */ 57 | traceline(viewPosition, halluPos + (v_forward * 1024), MOVE_NORMAL, pSeat->m_ePlayer); 58 | SurfData_Impact(world, trace_endpos, [0,0,0]); 59 | DecalGroups_Place("Impact.Shot", trace_endpos); 60 | pointsound(halluPos, "weapons/sniper.wav", 1, ATTN_NORM); 61 | break; 62 | case 6: /* nailgun impact */ 63 | traceline(viewPosition, halluPos + (v_forward * 1024), MOVE_NORMAL, pSeat->m_ePlayer); 64 | SurfData_Impact(world, trace_endpos, [0,0,0]); 65 | DecalGroups_Place("Impact.Shot", trace_endpos); 66 | pointsound(halluPos, "weapons/airgun_1.wav", 1, ATTN_NORM); 67 | break; 68 | case 7: /* nade thrown about */ 69 | int nadeSelection = (int)floor(random(0, 8)); 70 | NSRenderableEntity eNade = spawn(NSRenderableEntity); 71 | 72 | switch (nadeSelection) { 73 | case 1: 74 | eNade.SetModel("models/emp_grenade.mdl"); 75 | break; 76 | case 2: 77 | eNade.SetModel("models/spy_grenade.mdl"); 78 | break; 79 | case 3: 80 | eNade.SetModel("models/napalm.mdl"); 81 | break; 82 | case 4: 83 | eNade.SetModel("models/mirv_grenade.mdl"); 84 | break; 85 | case 5: 86 | eNade.SetModel("models/ngrenade.mdl"); 87 | break; 88 | case 6: 89 | eNade.SetModel("models/conc_grenade.mdl"); 90 | break; 91 | case 7: 92 | eNade.SetModel("models/caltrop.mdl"); 93 | break; 94 | default: 95 | eNade.SetModel("models/w_grenade.mdl"); 96 | } 97 | eNade.SetOrigin(viewPosition + (v_forward * -32) + (v_right * random(-64, 64))); 98 | eNade.SetMovetype(MOVETYPE_BOUNCE); 99 | eNade.SetSolid(SOLID_NOT); 100 | eNade.SetGravity(1.0f); 101 | eNade.SetVelocity(v_forward * 300 + v_right * random(-64, 64) + v_up * 200); 102 | eNade.SetAngularVelocity([300, 300, 300]); 103 | eNade.SetAngles(vectoangles(eNade.GetVelocity())); 104 | eNade.ScheduleThink(eNade.Destroy, 5.0f); 105 | eNade.drawmask = MASK_ENGINE; 106 | pointsound(halluPos, "weapons/grenade_hit3.wav", 1, ATTN_NORM); 107 | break; 108 | case 8: /* nail shot around */ 109 | halluPos = viewPosition + (v_forward * -32) + (v_right * random(-64, 64)); 110 | NSRenderableEntity eNail = spawn(NSRenderableEntity); 111 | eNail.SetModel("models/nail.mdl"); 112 | eNail.SetOrigin(halluPos); 113 | eNail.SetMovetype(MOVETYPE_NOCLIP); 114 | eNail.SetSolid(SOLID_NOT); 115 | eNail.SetGravity(1.0f); 116 | eNail.SetVelocity(v_forward * 800 + v_right * random(-800, 800)); 117 | eNail.SetAngles(vectoangles(eNail.GetVelocity())); 118 | eNail.ScheduleThink(eNail.Destroy, 5.0f); 119 | eNail.drawmask = MASK_ENGINE; 120 | pointsound(halluPos, "weapons/airgun_1.wav", 1, ATTN_NORM); 121 | break; 122 | case 9: /* fire eruption */ 123 | /* get it close to the player than usual */ 124 | halluPos = viewPosition; 125 | halluPos += v_forward * random(8, 64); 126 | halluPos += v_up * random(-16, 16); 127 | halluPos += v_right * random(-64, 64); 128 | 129 | env_sprite eFired = spawn(env_sprite); 130 | eFired.SetOrigin(halluPos); 131 | eFired.SetModel("sprites/fthrow.spr"); 132 | eFired.SetMaxFrame(modelframecount(eFired.modelindex)); 133 | eFired.SetFramerate(20); 134 | eFired.SetLoopFlag(false); 135 | eFired.SetRenderMode(RM_ADDITIVE); 136 | eFired.SetRenderAmt(1.0f); 137 | eFired.nextthink = time + 0.05f; 138 | pointsound(halluPos, "weapons/flmfire2.wav", 1, ATTN_NORM); 139 | break; 140 | default: 141 | /* rocket launcher firing */ 142 | pointsound(halluPos, "weapons/rocketfire1.wav", 1, ATTN_NORM); 143 | break; 144 | } 145 | }; -------------------------------------------------------------------------------- /src/client/hud_ammonotify.qc: -------------------------------------------------------------------------------- 1 | 2 | 3 | #define AMMO_COUNT 4 4 | 5 | string g_ammo_spr; 6 | 7 | typedef struct 8 | { 9 | float alpha; 10 | int count; 11 | } ammonote_t; 12 | ammonote_t g_ammonotify[AMMO_COUNT]; 13 | 14 | vector g_ammotype[AMMO_COUNT] = { 15 | [120/256, 72/128], // rockets (valve's rocket) 16 | [0/256, 72/128], // nails (valve's pistol) 17 | [0/256, 96/128], // cells (valve's uranium) 18 | [72/256, 72/128], // shells 19 | }; 20 | 21 | void 22 | HUD_AmmoNotify_Init(void) 23 | { 24 | g_ammo_spr = spriteframe("sprites/640hud7.spr", 0, 0.0f); 25 | } 26 | 27 | void 28 | HUD_AmmoNotify_Draw(vector startpos) 29 | { 30 | vector pos = startpos; 31 | 32 | for (int i = 0; i < AMMO_COUNT; i++) { 33 | vector srcpos; 34 | float a; 35 | 36 | /* make sure we skip any faded entries, and also null them */ 37 | if (g_ammonotify[i].alpha <= 0.0f) { 38 | g_ammonotify[i].count = 0; 39 | continue; 40 | } 41 | 42 | /* let's get the src img pos for our type */ 43 | srcpos = g_ammotype[i]; 44 | a = bound(0, g_ammonotify[i].alpha, 1.0); 45 | 46 | drawsubpic(pos, 47 | [24,24], 48 | g_ammo_spr, 49 | srcpos, 50 | [24/256, 24/128], 51 | g_hud_color, 52 | a, 53 | DRAWFLAG_ADDITIVE 54 | ); 55 | 56 | drawfont = Font_GetID(FONT_20); 57 | string txt = sprintf("%i", g_ammonotify[i].count); 58 | float offs = stringwidth(txt, FALSE, [20,20]); 59 | drawstring(pos + [-offs - 8,4], sprintf("%i", g_ammonotify[i].count), [20,20], g_hud_color, a, DRAWFLAG_ADDITIVE); 60 | 61 | g_ammonotify[i].alpha -= (clframetime * 0.5); 62 | pos -= [0, 32]; /* go up a notch */ 63 | } 64 | } 65 | 66 | void 67 | HUD_AmmoNotify_Insert(int type, int count) 68 | { 69 | if (count <= 0) 70 | return; 71 | 72 | g_ammonotify[type].count += count; 73 | g_ammonotify[type].alpha = 2.5f; 74 | 75 | } 76 | 77 | /* called whenever we should check for pickup updates */ 78 | void 79 | HUD_AmmoNotify_Check(player pl) 80 | { 81 | HUD_AmmoNotify_Insert(0, pl.m_iAmmoRockets - pl.m_iAmmoRockets_net); 82 | HUD_AmmoNotify_Insert(1, pl.m_iAmmoNails - pl.m_iAmmoNails_net); 83 | HUD_AmmoNotify_Insert(2, pl.m_iAmmoCells - pl.m_iAmmoCells_net); 84 | HUD_AmmoNotify_Insert(3, pl.m_iAmmoShells - pl.m_iAmmoShells_net); 85 | } -------------------------------------------------------------------------------- /src/client/hud_itemnotify.qc: -------------------------------------------------------------------------------- 1 | 2 | #define ITEM_COUNT 3 3 | 4 | string g_item_spr; 5 | 6 | typedef struct 7 | { 8 | float alpha; 9 | int count; 10 | } itemnote_t; 11 | itemnote_t g_itemnotify[ITEM_COUNT]; 12 | 13 | vector g_itemtype[ITEM_COUNT] = { 14 | [176/256, 0/256], // battery 15 | [176/256, 48/256], // medkit 16 | [176/256, 96/256], // longjump 17 | }; 18 | 19 | void 20 | HUD_ItemNotify_Init(void) 21 | { 22 | g_item_spr = spriteframe("sprites/640hud2.spr", 0, 0.0f); 23 | } 24 | 25 | void 26 | HUD_ItemNotify_Draw(__inout vector pos) 27 | { 28 | pos[0] = g_hudmins[0] + g_hudres[0] - 44; 29 | for (int i = 0; i < ITEM_COUNT; i++) { 30 | vector srcpos; 31 | float a; 32 | 33 | /* make sure we skip any faded entries, and also null them */ 34 | if (g_itemnotify[i].alpha <= 0.0f) { 35 | g_itemnotify[i].count = 0; 36 | continue; 37 | } 38 | 39 | /* let's get the src img pos for our type */ 40 | srcpos = g_itemtype[i]; 41 | a = bound(0, g_itemnotify[i].alpha, 1.0); 42 | 43 | /* we'll use the alpha to control the offset so it gently glides down when fading out */ 44 | pos -= [0, 52 * a]; /* go up a notch */ 45 | drawsubpic(pos + [-20,0], 46 | [44,44], 47 | g_item_spr, 48 | srcpos, 49 | [44/256, 44/256], 50 | g_hud_color, 51 | a, 52 | DRAWFLAG_ADDITIVE 53 | ); 54 | 55 | if (g_itemnotify[i].count > 1) { 56 | drawfont = Font_GetID(FONT_20); 57 | string txt = sprintf("%i", g_itemnotify[i].count); 58 | float offs = stringwidth(txt, FALSE, [20,20]) + 16; 59 | drawstring(pos + [-offs - 8,12], sprintf("%i", g_itemnotify[i].count), [20,20], g_hud_color, a, DRAWFLAG_ADDITIVE); 60 | } 61 | 62 | g_itemnotify[i].alpha -= (clframetime * 0.5); 63 | } 64 | } 65 | 66 | void 67 | HUD_ItemNotify_Insert(int type, int count) 68 | { 69 | if (count <= 0) 70 | return; 71 | 72 | g_itemnotify[type].count += count; 73 | g_itemnotify[type].alpha = 2.5f; 74 | 75 | } 76 | 77 | /* called whenever we should check for pickup updates */ 78 | void 79 | HUD_ItemNotify_Check(player pl) 80 | { 81 | int healthdiff = bound(0, pl.health - pl.health_net, 100); 82 | int armordiff = bound(0, pl.armor - pl.armor_net, 100); 83 | 84 | if (healthdiff > 1) 85 | HUD_ItemNotify_Insert(1, 1); 86 | if (armordiff > 1) 87 | HUD_ItemNotify_Insert(0, 1); 88 | } -------------------------------------------------------------------------------- /src/client/init.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2020 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | ================= 19 | ClientGame_Init 20 | 21 | Comparable to worldspawn in SSQC in that it's mostly used for precaches 22 | ================= 23 | */ 24 | void 25 | ClientGame_Init(float apilevel, string enginename, float engineversion) 26 | { 27 | registercommand("build"); 28 | registercommand("dismantle"); 29 | registercommand("+gren1"); 30 | registercommand("-gren1"); 31 | registercommand("+gren2"); 32 | registercommand("-gren2"); 33 | registercommand("chooseclass"); 34 | registercommand("changeclass"); 35 | registercommand("chooseteam"); 36 | registercommand("changeteam"); 37 | Obituary_Init(); 38 | } 39 | 40 | void VGUI_ChooseTeam(void); 41 | void 42 | ClientGame_InitDone(void) 43 | { 44 | VGUI_ChooseTeam(); 45 | } 46 | 47 | void 48 | ClientGame_RendererRestart(string rstr) 49 | { 50 | Obituary_Precache(); 51 | Damage_Precache(); 52 | 53 | FX_Blood_Init(); 54 | 55 | /* HUD selection icons */ 56 | g_dmsg_spr = spriteframe("sprites/tfc_dmsg.spr", 0, 0.0f); 57 | g_tfchud1_spr = spriteframe("sprites/tfchud01.spr", 0, 0.0f); 58 | g_tfchud2_spr = spriteframe("sprites/tfchud02.spr", 0, 0.0f); 59 | g_tfchud3_spr = spriteframe("sprites/tfchud03.spr", 0, 0.0f); 60 | g_tfchud4_spr = spriteframe("sprites/tfchud04.spr", 0, 0.0f); 61 | g_tfchud5_spr = spriteframe("sprites/tfchud05.spr", 0, 0.0f); 62 | g_tfchud6_spr = spriteframe("sprites/tfchud06.spr", 0, 0.0f); 63 | g_tfchud7_spr = spriteframe("sprites/tfchud07.spr", 0, 0.0f); 64 | 65 | /* there's also muzzleflash.spr, but that's just MUZZLE_SMALL again */ 66 | MUZZLE_RIFLE = (int)getmodelindex("sprites/muzzleflash1.spr"); 67 | MUZZLE_SMALL = (int)getmodelindex("sprites/muzzleflash2.spr"); 68 | MUZZLE_WEIRD = (int)getmodelindex("sprites/muzzleflash3.spr"); 69 | MUZZLE_ROUND = (int)getmodelindex("sprites/muzzleflash.spr"); 70 | } 71 | -------------------------------------------------------------------------------- /src/client/progs.src: -------------------------------------------------------------------------------- 1 | #pragma target fte_5768 2 | //#pragma flag enable assumeint 3 | #pragma progs_dat "../../csprogs.dat" 4 | 5 | #define CSQC 6 | #define CLIENT 7 | #define TFC 8 | #define CLASSIC_VGUI 9 | 10 | #includelist 11 | ../../../src/shared/fteextensions.qc 12 | ../../../src/shared/defs.h 13 | ../../../valve/src/client/defs.h 14 | ../../../src/client/defs.h 15 | defs.h 16 | 17 | ../../../src/vgui/include.src 18 | 19 | ../../../src/gs-entbase/client.src 20 | ../../../src/gs-entbase/shared.src 21 | ../shared/include.src 22 | 23 | vox.qc 24 | 25 | ../../../valve/src/client/damage.qc 26 | draw.qc 27 | init.qc 28 | ../../../valve/src/client/flashlight.qc 29 | entities.qc 30 | cmds.qc 31 | game_event.qc 32 | hallucination.qc 33 | ../../../valve/src/client/camera.qc 34 | ../../../valve/src/client/viewmodel.qc 35 | ../../../valve/src/client/obituary.qc 36 | ../../../valve/src/client/hud_dmgnotify.qc 37 | hud_itemnotify.qc 38 | hud_ammonotify.qc 39 | ../../../valve/src/client/hud_sprite.qc 40 | ../../../valve/src/client/hud.qc 41 | ../../../valve/src/client/hud_weaponselect.qc 42 | ../../../valve/src/client/scoreboard.qc 43 | 44 | ../../../src/client/include.src 45 | vgui_chooseteam.qc 46 | vgui_changeclass.qc 47 | ../../../src/shared/include.src 48 | #endlist 49 | -------------------------------------------------------------------------------- /src/client/vgui_chooseteam.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2020 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | static VGUIWindow winChooseTeam; 18 | 19 | class TFTeamButton:VGUIButton 20 | { 21 | void TFTeamButton(void); 22 | 23 | virtual void OnMouseUp(void); 24 | }; 25 | 26 | void 27 | TFTeamButton::TFTeamButton(void) 28 | { 29 | } 30 | 31 | void 32 | TFTeamButton::OnMouseUp(void) 33 | { 34 | int tag = GetTag(); 35 | 36 | localcmd("changeclass\n"); 37 | sendevent("TeamJoin", "f", (float)tag); 38 | winChooseTeam.Hide(); 39 | } 40 | 41 | 42 | string 43 | VGUI_ChooseTeam_MapInfo(void) 44 | { 45 | static string mapinfo = __NULL__; 46 | 47 | if (mapinfo != __NULL__) 48 | return mapinfo; 49 | 50 | filestream fileMap = fopen(strcat("maps/", mapname, ".txt"), FILE_READ); 51 | string temp; 52 | 53 | if (fileMap != -1) { 54 | while ((temp = fgets(fileMap))) { 55 | mapinfo = strcat(mapinfo, temp, "\n"); 56 | } 57 | } else { 58 | mapinfo = Titles_GetTextBody("Map_Description_not_available"); 59 | } 60 | 61 | return mapinfo; 62 | } 63 | 64 | void 65 | VGUI_ChooseTeam(void) 66 | { 67 | static int initialized; 68 | static VGUIButton btnAutoAssign; 69 | static VGUIButton btnGoSpectator; 70 | static VGUIFrame frmMapInfo; 71 | static VGUILabel lblSelectTeam; 72 | static VGUILabel lblMapName; 73 | static VGUILabel lblMapInfo; 74 | 75 | if (!initialized) { 76 | vector btnpos = [40,80]; 77 | 78 | initialized = TRUE; 79 | winChooseTeam = spawn(VGUIWindow); 80 | winChooseTeam.SetSize('640 480'); 81 | winChooseTeam.SetStyleMask(VGUIWindowBorderless | VGUIWindowFullscreen); 82 | 83 | lblSelectTeam = spawn(VGUILabel); 84 | lblSelectTeam.SetTitle(Titles_GetTextBody("Title_SelectYourTeam")); 85 | lblSelectTeam.SetTextSize(19); 86 | lblSelectTeam.SetPos([40, 38]); 87 | lblSelectTeam.SetSize('400 24'); 88 | 89 | frmMapInfo = spawn(VGUIFrame); 90 | frmMapInfo.SetPos('176 80'); 91 | frmMapInfo.SetSize('424 312'); 92 | 93 | lblMapName = spawn(VGUILabel); 94 | lblMapName.SetTitle(mapname); 95 | lblMapName.SetTextSize(19); 96 | lblMapName.SetPos('194 105'); 97 | lblMapName.SetSize('250 312'); 98 | 99 | lblMapInfo = spawn(VGUILabel); 100 | lblMapInfo.SetTitle(VGUI_ChooseTeam_MapInfo()); 101 | lblMapInfo.SetPos('194 129'); 102 | lblMapInfo.SetSize('375 250'); 103 | 104 | for (int t = 1; t <= serverkeyfloat("teams"); t++) { 105 | TFTeamButton btnForTeam; 106 | string team_name = serverkey(sprintf("team_%i", t)); 107 | 108 | btnForTeam = spawn(TFTeamButton); 109 | btnForTeam.SetTitle(strtoupper(team_name)); 110 | btnForTeam.SetPos(btnpos); 111 | btnForTeam.SetKeyEquivalent(ftos((float)t)); 112 | btnForTeam.SetSize('124 24'); 113 | 114 | switch (team_name) { 115 | case "Blue": 116 | btnForTeam.SetTag(1); 117 | break; 118 | case "Red": 119 | btnForTeam.SetTag(2); 120 | break; 121 | case "Green": 122 | btnForTeam.SetTag(3); 123 | break; 124 | case "Yellow": 125 | btnForTeam.SetTag(4); 126 | break; 127 | } 128 | 129 | winChooseTeam.Add(btnForTeam); 130 | btnpos[1] += 32; 131 | } 132 | 133 | btnAutoAssign = spawn(VGUIButton); 134 | btnAutoAssign.SetTitle(Titles_GetTextBody("Team_AutoAssign")); 135 | btnAutoAssign.SetPos(btnpos); 136 | btnAutoAssign.SetSize('124 24'); 137 | btnAutoAssign.SetKeyEquivalent("5"); 138 | //btnAutoAssign.SetFunc(VGUI_AutoAssign); 139 | btnpos[1] += 32; 140 | 141 | btnGoSpectator = spawn(VGUIButton); 142 | btnGoSpectator.SetTitle(Titles_GetTextBody("Menu_Spectate")); 143 | btnGoSpectator.SetPos(btnpos); 144 | btnGoSpectator.SetSize('124 24'); 145 | btnGoSpectator.SetKeyEquivalent("6"); 146 | //btnGoSpectator.SetFunc(VGUI_GoSpectator); 147 | 148 | g_uiDesktop.Add(winChooseTeam); 149 | winChooseTeam.Add(frmMapInfo); 150 | winChooseTeam.Add(lblSelectTeam); 151 | winChooseTeam.Add(lblMapName); 152 | winChooseTeam.Add(lblMapInfo); 153 | winChooseTeam.Add(btnAutoAssign); 154 | winChooseTeam.Add(btnGoSpectator); 155 | } 156 | 157 | winChooseTeam.Show(); 158 | winChooseTeam.SetPos((video_res / 2) - (winChooseTeam.GetSize() / 2)); 159 | } 160 | -------------------------------------------------------------------------------- /src/client/vox.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2020 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | class 18 | TFCVox:NSTalkMonster 19 | { 20 | void(void) TFCVox; 21 | virtual void(string) SentenceSample; 22 | }; 23 | 24 | TFCVox g_vox; 25 | 26 | void 27 | TFCVox::SentenceSample(string sample) 28 | { 29 | sound(this, CHAN_VOICE, sample, 1.0, ATTN_NONE, 100, SOUNDFLAG_FOLLOW | SOUNDFLAG_NOSPACIALISE); 30 | } 31 | 32 | void 33 | TFCVox::TFCVox(void) 34 | { 35 | } 36 | 37 | void 38 | Vox_Parse(void) 39 | { 40 | string msg = readstring(); 41 | 42 | if (!g_vox) 43 | g_vox = spawn(TFCVox); 44 | 45 | print(msg); 46 | print("\n"); 47 | g_vox.Sentence(msg); 48 | } 49 | -------------------------------------------------------------------------------- /src/progs.src: -------------------------------------------------------------------------------- 1 | #pragma sourcefile client/progs.src 2 | #pragma sourcefile server/progs.src 3 | -------------------------------------------------------------------------------- /src/server/Makefile: -------------------------------------------------------------------------------- 1 | CC=fteqcc 2 | 3 | all: 4 | $(CC) progs.src 5 | -------------------------------------------------------------------------------- /src/server/bot.qc: -------------------------------------------------------------------------------- 1 | class 2 | TFCBot:NSBot 3 | { 4 | void TFCBot(void); 5 | 6 | //virtual void CreateObjective(void); 7 | }; 8 | 9 | void CSEv_TeamJoin_f(float f); 10 | void CSEv_ClassJoin_f(float f); 11 | 12 | void 13 | TFCBot::TFCBot(void) 14 | { 15 | CSEv_TeamJoin_f(0); 16 | CSEv_ClassJoin_f(0); 17 | } 18 | 19 | #if 0 20 | void 21 | TFCBot::CreateObjective(void) 22 | { 23 | super:: CreateObjective(); 24 | } 25 | #endif -------------------------------------------------------------------------------- /src/server/client.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2022 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* called every input frame */ 18 | void 19 | Game_RunClientCommand(void) 20 | { 21 | player pl = (player)self; 22 | 23 | /* clear map triggers */ 24 | pl.gflags &= ~GF_NOBUILDZONE; 25 | pl.gflags &= ~GF_NOGRENADEZONE; 26 | 27 | pl.Physics_Run(); 28 | } 29 | 30 | /* client cmd overrides happen here */ 31 | void 32 | Game_ParseClientCommand(string cmd) 33 | { 34 | tokenize(cmd); 35 | 36 | if (argv(1) == "timeleft") { 37 | string msg; 38 | string timestring; 39 | float timeleft; 40 | timeleft = cvar("timelimit") - (time / 60); 41 | timestring = Util_TimeToString(timeleft); 42 | msg = sprintf("we have %s minutes remaining", timestring); 43 | bprint(PRINT_CHAT, msg); 44 | return; 45 | } 46 | 47 | clientcommand(self, cmd); 48 | } 49 | -------------------------------------------------------------------------------- /src/server/defs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2020 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "gamerules.h" 18 | #include "../../../valve/src/server/items.h" 19 | #include "../../../valve/src/server/flashlight.h" 20 | #include "sentry.h" 21 | 22 | var bool g_tfcHasBlueTeam = false; 23 | var bool g_tfcHasRedTeam = false; 24 | var bool g_tfcHasYellowTeam = false; 25 | var bool g_tfcHasGreenTeam = false; 26 | 27 | /* returns if a player already has a teleporter/exit built */ 28 | bool 29 | TFC_ExistsForPlayer(entity pl, string cname) 30 | { 31 | /* loop through all exits */ 32 | for (entity e = world; (e = find(e, ::classname, cname));) { 33 | /* if it's not places by our owner... */ 34 | if (e.real_owner != pl) 35 | continue; 36 | 37 | return true; 38 | } 39 | 40 | return false; 41 | } 42 | 43 | void 44 | TFC_DetonateTypeForPlayer(entity pl, string cname) 45 | { 46 | /* loop through all exits */ 47 | for (entity e = world; (e = find(e, ::classname, cname));) { 48 | /* if it's not places by our owner... */ 49 | if (e.real_owner != pl) 50 | continue; 51 | 52 | NSSurfacePropEntity targ = (NSSurfacePropEntity)e; 53 | targ.Destroy(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/server/func_nobuild.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /*QUAKED func_nobuild (0 .5 .8) ? 18 | 19 | TEAM FORTRESS (1996) ENTITY 20 | 21 | Brush volume that when entered, will not allow you to deploy anything as an engineer. 22 | 23 | -------- KEYS -------- 24 | "targetname" Name 25 | */ 26 | 27 | class 28 | func_nobuild:NSBrushTrigger 29 | { 30 | void(void) func_nobuild; 31 | 32 | virtual void(void) Respawn; 33 | virtual void(entity) Touch; 34 | }; 35 | 36 | void 37 | func_nobuild::Touch(entity eToucher) 38 | { 39 | player pl = (player)eToucher; 40 | if (!(eToucher.flags & FL_CLIENT)) 41 | return; 42 | 43 | pl.gflags |= GF_NOBUILDZONE; 44 | } 45 | 46 | void 47 | func_nobuild::Respawn(void) 48 | { 49 | InitBrushTrigger(); 50 | } 51 | 52 | void 53 | func_nobuild::func_nobuild(void) 54 | { 55 | 56 | } -------------------------------------------------------------------------------- /src/server/func_nogrenades.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /*QUAKED func_nogrenades (0 .5 .8) ? 18 | 19 | TEAM FORTRESS (1996) ENTITY 20 | 21 | Brush volume that when entered, will not allow you to deploy any grenades. 22 | 23 | -------- KEYS -------- 24 | "targetname" Name 25 | */ 26 | 27 | class 28 | func_nogrenades:NSBrushTrigger 29 | { 30 | void(void) func_nogrenades; 31 | 32 | virtual void(void) Respawn; 33 | virtual void(entity) Touch; 34 | }; 35 | 36 | void 37 | func_nogrenades::Touch(entity eToucher) 38 | { 39 | player pl = (player)eToucher; 40 | if (!(eToucher.flags & FL_CLIENT)) 41 | return; 42 | 43 | pl.gflags |= GF_NOGRENADEZONE; 44 | } 45 | 46 | void 47 | func_nogrenades::Respawn(void) 48 | { 49 | InitBrushTrigger(); 50 | } 51 | 52 | void 53 | func_nogrenades::func_nogrenades(void) 54 | { 55 | 56 | } -------------------------------------------------------------------------------- /src/server/gamerules.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2020 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | class TFCGameRules:CGameRules 18 | { 19 | void(void) TFCGameRules; 20 | 21 | virtual bool ConsoleCommand(NSClientPlayer, string); 22 | virtual bool IsTeamplay(void); 23 | 24 | virtual void PlayerConnect(NSClientPlayer); 25 | virtual void PlayerDisconnect(NSClientPlayer); 26 | virtual void PlayerPostFrame(NSClientPlayer); 27 | virtual void PlayerSpawn(NSClientPlayer); 28 | virtual void PlayerKill(NSClientPlayer); 29 | virtual void PlayerRespawn(NSClientPlayer); 30 | virtual void PlayerDeath(NSClientPlayer); 31 | virtual void DropGoalItem(NSClientPlayer); 32 | virtual float ImpulseCommand(NSClient, float); 33 | virtual void LevelNewParms(void); 34 | virtual void InitPostEnts(void); 35 | }; 36 | -------------------------------------------------------------------------------- /src/server/gamerules.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2023 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | void 18 | TFCGameRules::TFCGameRules(void) 19 | { 20 | /* wipe the serverinfo clean */ 21 | forceinfokey(world, "teams", "0"); 22 | forceinfokey(world, "team_1", ""); 23 | forceinfokey(world, "team_2", ""); 24 | forceinfokey(world, "team_3", ""); 25 | forceinfokey(world, "team_4", ""); 26 | forceinfokey(world, "teamscore_1", ""); 27 | forceinfokey(world, "teamscore_2", ""); 28 | forceinfokey(world, "teamscore_3", ""); 29 | forceinfokey(world, "teamscore_4", ""); 30 | } 31 | 32 | bool 33 | TFCGameRules::ConsoleCommand(NSClientPlayer pp, string cmd) 34 | { 35 | tokenize(cmd); 36 | 37 | switch (argv(0)) { 38 | default: 39 | return (false); 40 | } 41 | 42 | return (true); 43 | } 44 | 45 | bool 46 | TFCGameRules::IsTeamplay(void) 47 | { 48 | return TRUE; 49 | } 50 | 51 | void 52 | TFCGameRules::DropGoalItem(NSClientPlayer pp) 53 | { 54 | /* skip normal players */ 55 | if (!(pp.g_items & ITEM_GOALITEM)) 56 | return; 57 | 58 | item_tfgoal target; 59 | 60 | for (entity e = world; (e = find(e, ::classname, "item_tfgoal"));) { 61 | target = (item_tfgoal)e; 62 | 63 | /* item is still pick-upable */ 64 | if (target.solid != SOLID_NOT) { 65 | print("the item is not picked up. \n"); 66 | continue; 67 | } 68 | 69 | /* that's us, yup */ 70 | if (target.m_eActivator == pp) { 71 | target.DropReturnable(pp); 72 | return; 73 | } 74 | } 75 | 76 | print("^1WARNING: ^7Player marked as having impossible goal-item\n"); 77 | } 78 | 79 | /* we check what fields have changed over the course of the frame and network 80 | * only the ones that have actually changed */ 81 | void 82 | TFCGameRules::PlayerPostFrame(NSClientPlayer pp) 83 | { 84 | } 85 | 86 | void 87 | TFCGameRules::LevelNewParms(void) 88 | { 89 | parm1 = parm2 = parm3 = parm4 = parm5 = parm6 = parm7 = 90 | parm8 = parm9 = parm10 = parm11 = parm12 = parm13 = parm14 = 91 | parm15 = parm16 = parm17 = parm18 = parm19 = parm20 = parm21 = 92 | parm22 = parm23 = parm24 = parm25 = parm26 = parm27 = parm28 = 93 | parm29 = parm30 = 0; 94 | parm64 = FL_CLIENT; 95 | } 96 | 97 | void 98 | TFCGameRules::PlayerConnect(NSClientPlayer pl) 99 | { 100 | if (Plugin_PlayerConnect(pl) == FALSE) 101 | bprint(PRINT_HIGH, sprintf("%s connected\n", pl.netname)); 102 | } 103 | 104 | void 105 | TFCGameRules::PlayerDisconnect(NSClientPlayer pl) 106 | { 107 | bprint(PRINT_HIGH, sprintf("%s disconnected\n", pl.netname)); 108 | 109 | /* Make this unusable */ 110 | pl.solid = SOLID_NOT; 111 | pl.movetype = MOVETYPE_NONE; 112 | pl.modelindex = 0; 113 | pl.health = 0; 114 | pl.takedamage = 0; 115 | pl.SendFlags = PLAYER_MODELINDEX; 116 | } 117 | 118 | void 119 | TFCGameRules_PlayerRespawn(void) 120 | { 121 | TFCGameRules rule = (TFCGameRules)g_grMode; 122 | rule.PlayerRespawn((NSClientPlayer)self); 123 | } 124 | 125 | void 126 | TFCGameRules::PlayerDeath(NSClientPlayer pp) 127 | { 128 | player pl = (player)pp; 129 | 130 | DropGoalItem(pp); 131 | pl.SetSolid(SOLID_NOT); 132 | pl.SetMovetype(MOVETYPE_NONE); 133 | 134 | pl.ScheduleThink(TFCGameRules_PlayerRespawn, 4.0f); 135 | 136 | /* play the iconic death sound */ 137 | Sound_Play(pl, CHAN_VOICE, "player_tfc.death"); 138 | } 139 | 140 | void 141 | TFCGameRules::PlayerKill(NSClientPlayer pp) 142 | { 143 | player pl = (player)pp; 144 | Damage_Apply(pl, pl, pl.health, WEAPON_NONE, DMG_SKIP_ARMOR); 145 | } 146 | 147 | void 148 | TFCGameRules::PlayerRespawn(NSClientPlayer pp) 149 | { 150 | player pl = (player)pp; 151 | pl.MakeClass(pl.classtype); 152 | pl.SpawnIntoGame(); 153 | } 154 | 155 | void 156 | TFCGameRules::PlayerSpawn(NSClientPlayer pp) 157 | { 158 | player pl = (player)pp; 159 | pl.MakeTempSpectator(); /* replace this with a non-spectator ghost */ 160 | Spawn_ObserverCam(pl); 161 | } 162 | 163 | bool 164 | TFCGameRules::ImpulseCommand(NSClient bp, float num) 165 | { 166 | switch (num) { 167 | case 101: 168 | player pl = (player)bp; 169 | if (cvar("sv_cheats") > 0) { 170 | Weapons_AddItem(pl, WEAPON_CROWBAR, -1); 171 | Weapons_AddItem(pl, WEAPON_MEDKIT, -1); 172 | Weapons_AddItem(pl, WEAPON_KNIFE, -1); 173 | Weapons_AddItem(pl, WEAPON_WRENCH, -1); 174 | Weapons_AddItem(pl, WEAPON_UMBRELLA, -1); 175 | Weapons_AddItem(pl, WEAPON_SBS, -1); 176 | Weapons_AddItem(pl, WEAPON_SNIPER, -1); 177 | Weapons_AddItem(pl, WEAPON_TRANQUIL, -1); 178 | Weapons_AddItem(pl, WEAPON_RAILGUN, -1); 179 | Weapons_AddItem(pl, WEAPON_AUTORIFLE, -1); 180 | Weapons_AddItem(pl, WEAPON_DBS, -1); 181 | Weapons_AddItem(pl, WEAPON_NAILGUN, -1); 182 | Weapons_AddItem(pl, WEAPON_GLAUNCHER, -1); 183 | Weapons_AddItem(pl, WEAPON_SUPERNAIL, -1); 184 | Weapons_AddItem(pl, WEAPON_FLAMER, -1); 185 | Weapons_AddItem(pl, WEAPON_RPG, -1); 186 | Weapons_AddItem(pl, WEAPON_PIPEBOMB, -1); 187 | Weapons_AddItem(pl, WEAPON_ASSCAN, -1); 188 | Weapons_AddItem(pl, WEAPON_INCENDIARY, -1); 189 | Weapons_AddItem(pl, WEAPON_GRAPPLE, -1); 190 | } 191 | break; 192 | default: 193 | return super::ImpulseCommand(bp, num); 194 | } 195 | 196 | return true; 197 | } 198 | 199 | void 200 | TFCGameRules::InitPostEnts(void) 201 | { 202 | super::InitPostEnts(); 203 | 204 | /* rename the team spawns. */ 205 | info_player_teamspawn::RenameTeamSpawns(); 206 | info_tfdetect::Setup(); 207 | } 208 | -------------------------------------------------------------------------------- /src/server/info_areadef.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /*QUAKED info_areadef (0 0 0.8) (-16 -16 -36) (16 16 36) 18 | 19 | TEAM FORTRESS (1996) ENTITY 20 | 21 | Describes an area's bounds and description/name. 22 | 23 | -------- KEYS -------- 24 | "targetname" : Name 25 | "areaname" : Name of the specified area 26 | "mins" : Mins of the area's bounding box 27 | "maxs" : Maxs of the area's bounding box 28 | */ 29 | 30 | class 31 | info_areadef:NSPointTrigger 32 | { 33 | string m_strDescription; 34 | vector m_vecMins; 35 | vector m_vecMaxs; 36 | 37 | void(void) info_areadef; 38 | 39 | virtual void(void) Respawn; 40 | virtual void(string,string) SpawnKey; 41 | virtual void(entity) Touch; 42 | }; 43 | 44 | void 45 | info_areadef::Touch(entity eToucher) 46 | { 47 | if (!(eToucher.flags & FL_CLIENT)) 48 | return; 49 | 50 | forceinfokey(eToucher, "*areadef", m_strDescription); 51 | } 52 | 53 | void 54 | info_areadef::SpawnKey(string strKey, string strValue) 55 | { 56 | switch (strKey) { 57 | case "areaname": 58 | m_strDescription = strtoupper(strValue); 59 | m_strDescription = strreplace("BLUE", "^x99FBLUE^7", m_strDescription); 60 | m_strDescription = strreplace("RED", "^xF66RED^7", m_strDescription); 61 | m_strDescription = strreplace("GREEN", "^x4F4GREEN^7", m_strDescription); 62 | m_strDescription = strreplace("YELLOW", "^xFF4YELLOW^7", m_strDescription); 63 | break; 64 | case "mins": 65 | m_vecMins = stov(strValue); 66 | break; 67 | case "maxs": 68 | m_vecMaxs = stov(strValue); 69 | break; 70 | default: 71 | super::SpawnKey(strKey, strValue); 72 | } 73 | } 74 | 75 | void 76 | info_areadef::Respawn(void) 77 | { 78 | /* set up our volume */ 79 | SetSolid(SOLID_TRIGGER); 80 | SetMovetype(MOVETYPE_NONE); 81 | SetOrigin(GetSpawnOrigin()); 82 | SetSize(m_vecMins, m_vecMaxs); 83 | } 84 | 85 | void 86 | info_areadef::info_areadef(void) 87 | { 88 | forceinfokey(world, "areadefs", "1"); 89 | } -------------------------------------------------------------------------------- /src/server/info_player_teamspawn.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2020 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | class info_player_teamspawn:NSSpawnPoint 18 | { 19 | void(void) info_player_teamspawn; 20 | 21 | virtual void SpawnKey(string, string); 22 | 23 | nonvirtual void RenameTeamSpawns(void); 24 | }; 25 | 26 | void 27 | info_player_teamspawn::info_player_teamspawn(void) 28 | { 29 | 30 | } 31 | 32 | void 33 | info_player_teamspawn::SpawnKey(string keyName, string setValue) 34 | { 35 | switch (keyName) { 36 | case "team_no": 37 | team = ReadInt(setValue); 38 | break; 39 | default: 40 | super::SpawnKey(keyName, setValue); 41 | } 42 | } 43 | 44 | void 45 | info_player_teamspawn::RenameTeamSpawns(void) 46 | { 47 | for (entity e = world; (e = find(e, ::classname, "info_player_teamspawn"));) { 48 | info_player_teamspawn findSpawn = (info_player_teamspawn)e; 49 | 50 | switch (findSpawn.team) { 51 | case 1: 52 | e.classname = "info_teamspawn_blue"; 53 | break; 54 | case 2: 55 | e.classname = "info_teamspawn_red"; 56 | break; 57 | case 3: 58 | e.classname = "info_teamspawn_yellow"; 59 | break; 60 | case 4: 61 | e.classname = "info_teamspawn_green"; 62 | break; 63 | } 64 | } 65 | 66 | botinfo = BOTINFO_SPAWNPOINT; 67 | } 68 | 69 | CLASSEXPORT(i_p_t, info_player_teamspawn) 70 | -------------------------------------------------------------------------------- /src/server/info_tfdetect.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | typedef enum 18 | { 19 | TFDFL_CIVILIANONLY = -1, 20 | TFDFL_NONE = 0, 21 | TFDFL_NOSCOUNT = 1, 22 | TFDFL_NOSNIPER = 2, 23 | TFDFL_NOSOLDIER = 4, 24 | TFDFL_NODEMOMAN = 8, 25 | TFDFL_NOMEDIC = 16, 26 | TFDFL_NOHEAVY = 32, 27 | TFDFL_NOPYRO = 64, 28 | TFDFL_NORANDOM = 128, 29 | TFDFL_NOSPY = 256, 30 | TFDFL_NOENGINEER = 512, 31 | } tfdetectTeamFlags_t; 32 | 33 | /*QUAKED info_tfdetect (0 0 0.8) (-16 -16 -16) (16 16 16) 34 | # OVERVIEW 35 | 36 | # KEYS 37 | - "broadcast" : ??? 38 | - "number_of_teams" : Number of teams. 39 | - "team1_name" : Name of team blue. 40 | - "team2_name" : Name of team red. 41 | - "team3_name" : Name of team yellow. 42 | - "team4_name" : Name of team green. 43 | - "impulse" : Game settings field. 44 | - "message" : commands to insert into the server console. 45 | - "maxammo_shells" : Blue team flags bitfield. 46 | - "maxammo_nails" : Red team flags bitfield. 47 | - "maxammo_rockets" : Yellow team flags bitfield. 48 | - "maxammo_cells" : Green team flags bitfield. 49 | - "ammo_medikit" : Blue team max player count. 50 | - "ammo_detpack" : Red team max player count. 51 | - "maxammo_medikit" : Yellow team max player count. 52 | - "maxammo_detpack" : Green team max player count. 53 | - "team1_allies" : Blue team ally bitfield. 54 | - "team2_allies" : Red team ally bitfield. 55 | - "team3_allies" : Yellow team ally bitfield. 56 | - "team4_allies" : Green team ally bitfield. 57 | 58 | # NOTES 59 | 60 | 61 | # TRIVIA 62 | This entity was introduced in Team Fortress (1996). 63 | */ 64 | class 65 | info_tfdetect:NSPointTrigger 66 | { 67 | public: 68 | void info_tfdetect(void); 69 | 70 | virtual void SpawnKey(string, string); 71 | virtual void Respawn(void); 72 | 73 | nonvirtual void Setup(void); 74 | 75 | private: 76 | string m_strTeam1Name; 77 | string m_strTeam2Name; 78 | string m_strTeam3Name; 79 | string m_strTeam4Name; 80 | string m_strLocalCommand; 81 | 82 | tfdetectTeamFlags_t m_bfTeam1Flags; 83 | tfdetectTeamFlags_t m_bfTeam2Flags; 84 | tfdetectTeamFlags_t m_bfTeam3Flags; 85 | tfdetectTeamFlags_t m_bfTeam4Flags; 86 | }; 87 | 88 | void 89 | info_tfdetect::info_tfdetect(void) 90 | { 91 | m_strTeam1Name = "Blue"; 92 | m_strTeam2Name = "Red"; 93 | m_strTeam3Name = "Yellow"; 94 | m_strTeam4Name = "Green"; 95 | m_strLocalCommand = ""; 96 | m_bfTeam1Flags = TFDFL_NONE; 97 | m_bfTeam2Flags = TFDFL_NONE; 98 | m_bfTeam3Flags = TFDFL_NONE; 99 | m_bfTeam4Flags = TFDFL_NONE; 100 | } 101 | 102 | void 103 | info_tfdetect::SpawnKey(string keyName, string setValue) 104 | { 105 | switch (keyName) { 106 | case "team1_name": 107 | m_strTeam1Name = ReadString(setValue); 108 | break; 109 | case "team2_name": 110 | m_strTeam2Name = ReadString(setValue); 111 | break; 112 | case "team3_name": 113 | m_strTeam3Name = ReadString(setValue); 114 | break; 115 | case "team4_name": 116 | m_strTeam4Name = ReadString(setValue); 117 | break; 118 | case "message": 119 | m_strLocalCommand = ReadString(setValue); 120 | break; 121 | case "maxammo_shells": 122 | m_bfTeam1Flags = ReadFloat(setValue); 123 | break; 124 | case "maxammo_nails": 125 | m_bfTeam2Flags = ReadFloat(setValue); 126 | break; 127 | case "maxammo_rockets": 128 | m_bfTeam3Flags = ReadFloat(setValue); 129 | break; 130 | case "maxammo_cells": 131 | m_bfTeam4Flags = ReadFloat(setValue); 132 | break; 133 | default: 134 | super::SpawnKey(keyName, setValue); 135 | } 136 | } 137 | 138 | void 139 | info_tfdetect::Respawn(void) 140 | { 141 | 142 | } 143 | 144 | void 145 | info_tfdetect::Setup(void) 146 | { 147 | int team_count = 0i; 148 | entity e = __NULL__; 149 | info_tfdetect globalTFD = (info_tfdetect)find(world, ::classname, "info_tfdetect"); 150 | 151 | /* populate the serverinfo field with the teams we have on the map */ 152 | e = find(world, ::classname, "info_teamspawn_blue"); 153 | if (e) { 154 | team_count += 1; 155 | forceinfokey(world, sprintf("team_%i", team_count), "Blue"); 156 | forceinfokey(world, sprintf("teamscore_%i", team_count), "0"); 157 | g_tfcHasBlueTeam = true; 158 | } 159 | 160 | e = find(world, ::classname, "info_teamspawn_red"); 161 | if (e) { 162 | team_count += 1; 163 | forceinfokey(world, sprintf("team_%i", team_count), "Red"); 164 | forceinfokey(world, sprintf("teamscore_%i", team_count), "0"); 165 | g_tfcHasRedTeam = true; 166 | } 167 | 168 | e = find(world, ::classname, "info_teamspawn_green"); 169 | if (e) { 170 | team_count += 1; 171 | forceinfokey(world, sprintf("team_%i", team_count), "Green"); 172 | forceinfokey(world, sprintf("teamscore_%i", team_count), "0"); 173 | g_tfcHasGreenTeam = true; 174 | } 175 | 176 | e = find(world, ::classname, "info_teamspawn_yellow"); 177 | if (e) { 178 | team_count += 1; 179 | forceinfokey(world, sprintf("team_%i", team_count), "Yellow"); 180 | forceinfokey(world, sprintf("teamscore_%i", team_count), "0"); 181 | g_tfcHasYellowTeam = true; 182 | } 183 | forceinfokey(world, "teams", itos(team_count)); 184 | 185 | if (!globalTFD) { 186 | NSLog("No info_tfdetect in level."); 187 | forceinfokey(world, "teamflags_1", "0"); 188 | forceinfokey(world, "teamflags_2", "0"); 189 | forceinfokey(world, "teamflags_3", "0"); 190 | forceinfokey(world, "teamflags_4", "0"); 191 | return; 192 | } 193 | 194 | forceinfokey(world, "team_1", globalTFD.m_strTeam1Name); 195 | forceinfokey(world, "team_2", globalTFD.m_strTeam2Name); 196 | forceinfokey(world, "team_3", globalTFD.m_strTeam3Name); 197 | forceinfokey(world, "team_4", globalTFD.m_strTeam4Name); 198 | 199 | forceinfokey(world, "teamflags_1", ftos(globalTFD.m_bfTeam1Flags)); 200 | forceinfokey(world, "teamflags_2", ftos(globalTFD.m_bfTeam1Flags)); 201 | forceinfokey(world, "teamflags_3", ftos(globalTFD.m_bfTeam1Flags)); 202 | forceinfokey(world, "teamflags_4", ftos(globalTFD.m_bfTeam1Flags)); 203 | 204 | /* the evil localcmd feature of this entity. */ 205 | if (m_strLocalCommand) { 206 | localcmd(m_strLocalCommand); 207 | localcmd("\n"); 208 | } 209 | } -------------------------------------------------------------------------------- /src/server/item_armor.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022-2024 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | class 18 | TFCArmor:NSRenderableEntity 19 | { 20 | float m_flRespawnDelay; 21 | int m_iTeamUses; 22 | int m_iArmorValue; 23 | 24 | void(void) TFCArmor; 25 | 26 | virtual void(entity) Touch; 27 | virtual void(void) Respawn; 28 | virtual void(void) Spawned; 29 | virtual void(string,string) SpawnKey; 30 | }; 31 | 32 | void 33 | TFCArmor::TFCArmor(void) 34 | { 35 | m_flRespawnDelay = 0.0f; 36 | m_iTeamUses = 0i; 37 | m_iArmorValue = 0i; 38 | } 39 | 40 | void 41 | TFCArmor::SpawnKey(string keyName, string setValue) 42 | { 43 | switch (keyName) { 44 | case "armorvalue": 45 | m_iArmorValue = ReadInt(setValue); 46 | break; 47 | case "team_no": 48 | m_iTeamUses = ReadInt(setValue); 49 | break; 50 | case "respawn_delay": 51 | m_flRespawnDelay = ReadFloat(setValue); 52 | break; 53 | default: 54 | super::SpawnKey(keyName, setValue); 55 | } 56 | } 57 | 58 | void 59 | TFCArmor::Spawned(void) 60 | { 61 | super::Spawned(); 62 | Sound_Precache("item_armor_tfc.pickup"); 63 | } 64 | 65 | void 66 | TFCArmor::Respawn(void) 67 | { 68 | SetModel(GetSpawnModel()); 69 | SetSize([-16,-16,0], [16,16,56]); 70 | SetSolid(SOLID_TRIGGER); 71 | SetOrigin(GetSpawnOrigin()); 72 | DropToFloor(); 73 | botinfo = BOTINFO_ARMOR; 74 | } 75 | 76 | void 77 | TFCArmor::Touch(entity eToucher) 78 | { 79 | if (eToucher.classname != "player") { 80 | return; 81 | } 82 | player pl = (player)eToucher; 83 | 84 | /* check for team eligibility */ 85 | if (m_iTeamUses) 86 | if (pl.team != m_iTeamUses) 87 | return; 88 | 89 | /* if we can't add anything, don't bother */ 90 | if (pl.armor >= pl.m_iMaxArmor && pl.m_iAmmoCells >= pl.m_iMaxCells) 91 | return; 92 | 93 | int ap; 94 | int tp = 0; 95 | 96 | /* get remaining points */ 97 | ap = pl.m_iMaxArmor - pl.armor; 98 | tp = m_iArmorValue; 99 | 100 | /* if that's all we can give... */ 101 | if (ap > tp) { 102 | pl.armor += tp; 103 | } else { 104 | /* give whatever armor points we need */ 105 | pl.armor += ap; 106 | 107 | /* give the remaining as metal... engineers only!*/ 108 | if (pl.classtype == CLASS_ENGINEER) { 109 | pl. m_iAmmoCells = bound(0, pl.m_iAmmoCells + (tp - ap), pl.m_iMaxCells); 110 | } 111 | } 112 | 113 | Sound_Play(this, CHAN_ITEM, "item_armor_tfc.pickup"); 114 | 115 | /* hide and respawn */ 116 | Disappear(); 117 | ScheduleThink(Respawn, m_flRespawnDelay); 118 | } 119 | -------------------------------------------------------------------------------- /src/server/item_healthkit.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /*QUAKED item_healthkit (0 0 0.8) (-16 -16 -36) (16 16 36) 18 | 19 | TEAM FORTRESS CLASSIC (1999) ENTITY 20 | 21 | Health pickup. Unlike Team Fortress, this is the only one and it provides 22 | 25 health at all times. 23 | 24 | -------- KEYS -------- 25 | "targetname" : Name 26 | "areaname" : Name of the specified area 27 | "team_no" : Which team can pick up the armor (0 = all) 28 | "respawn_delay" : Time it takes to respawn after having been picked up 29 | */ 30 | 31 | class 32 | item_healthkit:NSRenderableEntity 33 | { 34 | int m_iTeamUses; 35 | float m_flRespawnDelay; 36 | 37 | void(void) item_healthkit; 38 | 39 | virtual void(void) Respawn; 40 | virtual void(entity) Touch; 41 | virtual void(string,string) SpawnKey; 42 | }; 43 | 44 | void 45 | item_healthkit::Touch(entity eToucher) 46 | { 47 | if (eToucher.classname != "player") { 48 | return; 49 | } 50 | player pl = (player)eToucher; 51 | 52 | /* check for team eligibility */ 53 | if (m_iTeamUses) 54 | if (pl.team != m_iTeamUses) 55 | return; 56 | 57 | /* leave when full */ 58 | if (pl.health >= pl.m_iMaxHealth) 59 | return; 60 | 61 | pl.health = bound(0, pl.health + 25, pl.m_iMaxHealth); 62 | 63 | Sound_Play(this, CHAN_ITEM, "item_healthkit_tfc.pickup"); 64 | 65 | /* hide and respawn */ 66 | Disappear(); 67 | ScheduleThink(Respawn, m_flRespawnDelay); 68 | } 69 | 70 | void 71 | item_healthkit::SpawnKey(string strKey, string strValue) 72 | { 73 | switch (strKey) { 74 | case "team_no": 75 | m_iTeamUses = stoi(strValue); 76 | break; 77 | case "respawn_delay": 78 | m_flRespawnDelay = stof(strValue); 79 | break; 80 | default: 81 | super::SpawnKey(strKey, strValue); 82 | } 83 | } 84 | 85 | void 86 | item_healthkit::Respawn(void) 87 | { 88 | SetModel("models/w_medkit.mdl"); 89 | SetSize([-16,-16,0], [16,16,56]); 90 | SetSolid(SOLID_TRIGGER); 91 | SetOrigin(GetSpawnOrigin()); 92 | DropToFloor(); 93 | botinfo = BOTINFO_HEALTH; 94 | } 95 | 96 | void 97 | item_healthkit::item_healthkit(void) 98 | { 99 | Sound_Precache("item_healthkit_tfc.pickup"); 100 | m_flRespawnDelay = 30.0f; 101 | } -------------------------------------------------------------------------------- /src/server/progs.src: -------------------------------------------------------------------------------- 1 | #pragma target fte_5768 2 | //#pragma flag enable assumeint 3 | #pragma progs_dat "../../progs.dat" 4 | 5 | #define QWSSQC 6 | #define SERVER 7 | #define VALVE 8 | #define TFC 9 | 10 | #includelist 11 | ../../../src/shared/fteextensions.qc 12 | ../../../src/shared/defs.h 13 | ../../../src/server/defs.h 14 | ../../../src/botlib/botinfo.h 15 | 16 | ../../../src/gs-entbase/server.src 17 | ../../../src/gs-entbase/shared.src 18 | 19 | defs.h 20 | 21 | ../shared/include.src 22 | 23 | ../../../valve/src/server/player.qc 24 | 25 | dispenser.qc 26 | sentry.qc 27 | teleporter.qc 28 | 29 | func_nobuild.qc 30 | func_nogrenades.qc 31 | 32 | vox.qc 33 | ../../../valve/src/server/items.qc 34 | ../../../src/botlib/include.src 35 | bot.qc 36 | 37 | info_player_teamspawn.qc 38 | item_tfgoal.qc 39 | info_tfgoal.qc 40 | info_areadef.qc 41 | info_tfdetect.qc 42 | item_armor.qc 43 | item_healthkit.qc 44 | nades.qc 45 | 46 | gamerules.qc 47 | client.qc 48 | server.qc 49 | ../../../valve/src/server/damage.qc 50 | ../../../valve/src/server/flashlight.qc 51 | ../../../valve/src/server/modelevent.qc 52 | 53 | spawn.qc 54 | 55 | ../../../src/server/include.src 56 | ../../../src/shared/include.src 57 | #endlist 58 | 59 | -------------------------------------------------------------------------------- /src/server/sentry.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #define TFC_SENTRY_COST 130 18 | 19 | typedef enum 20 | { 21 | SENTRY_IDLE, 22 | SENTRY_SEARCHING, 23 | SENTRY_ALERTED, 24 | SENTRY_SHOOTING 25 | } sentrystate_e; 26 | 27 | class 28 | TFCSentry:NSSurfacePropEntity 29 | { 30 | NSSurfacePropEntity m_eHead; 31 | sentrystate_e m_state; 32 | float m_flNextIdleSound; 33 | 34 | /* spinny */ 35 | float m_flWantAngle; 36 | float m_flCurrAngle; 37 | 38 | void(void) TFCSentry; 39 | 40 | virtual void(NSClientPlayer) Place; 41 | virtual void(void) FinishPlacing; 42 | virtual void(void) Think; 43 | }; -------------------------------------------------------------------------------- /src/server/sentry.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | void 18 | TFCSentry::Think(void) 19 | { 20 | ScheduleThink(Think, 0.1f); 21 | 22 | /* searching */ 23 | entity t = world; 24 | { 25 | for (entity p = world; (p = find(p, ::classname, "player"));) { 26 | /* out of range */ 27 | if (vlen(origin - p.origin) > 1024) 28 | continue; 29 | 30 | if (team == p.team) 31 | continue; 32 | 33 | if (IsFacing(p) == false) 34 | continue; 35 | 36 | /* find them */ 37 | traceline(origin, p.origin, MOVE_NORMAL, this); 38 | if (trace_ent == p) { 39 | t = p; 40 | break; 41 | } 42 | } 43 | } 44 | 45 | if (m_state == SENTRY_SEARCHING) { 46 | float twist = sin(time); 47 | m_eHead.SetBoneControl1(twist); 48 | m_eHead.SetBoneControl2(0.5f); 49 | 50 | if (m_flNextIdleSound < time) { 51 | Sound_Play(this, CHAN_VOICE, "turret_tfc.idle_noise"); 52 | m_flNextIdleSound = time + 10.0f; 53 | } 54 | 55 | if (t) 56 | m_state = SENTRY_ALERTED; 57 | } else if (m_state == SENTRY_ALERTED) { 58 | Sound_Play(this, CHAN_VOICE, "turret_tfc.target_spotted"); 59 | m_state = SENTRY_SHOOTING; 60 | } else if (m_state == SENTRY_SHOOTING) { 61 | // shoot things 62 | if (!t) 63 | m_state = SENTRY_SEARCHING; 64 | else { 65 | makevectors([0, angles[1], 0]); 66 | m_flWantAngle = dotproduct((origin - t.origin), v_right); 67 | m_flCurrAngle = Math_Lerp(m_flCurrAngle, m_flWantAngle, 0.25f); 68 | m_eHead.SetBoneControl1(m_flCurrAngle); 69 | print(sprintf("head: %f; want: %f\n", m_flCurrAngle, m_flWantAngle)); 70 | 71 | /* fire bullets */ 72 | input_angles = v_angle = vectoangles(origin - t.origin); 73 | TraceAttack_FireBullets(1, origin, 5, [0.025,0.025], WEAPON_NONE); 74 | } 75 | } 76 | } 77 | 78 | void 79 | TFCSentry::Place(NSClientPlayer pl) 80 | { 81 | vector newAngles = pl.GetAngles(); 82 | newAngles[0] = newAngles[2] = 0; 83 | SetAngles(newAngles); 84 | 85 | makevectors([0, pl.v_angle[1], 0]); 86 | SetOrigin(pl.origin + (v_forward * 48)); 87 | DropToFloor(); 88 | 89 | ScheduleThink(FinishPlacing, 5.0f); 90 | real_owner = pl; 91 | colormap = pl.colormap; 92 | team = pl.team; 93 | 94 | env_message_single(real_owner, "#Engineer_building"); 95 | Sound_Play(this, CHAN_BODY, "engineer.build"); 96 | } 97 | 98 | void 99 | TFCSentry::FinishPlacing(void) 100 | { 101 | /* put the top on that spins */ 102 | m_eHead.SetModel("models/sentry1.mdl"); 103 | m_eHead.SetAngles(GetAngles()); 104 | m_eHead.SetSolid(SOLID_BBOX); 105 | m_eHead.SetMovetype(MOVETYPE_NONE); 106 | m_eHead.SetSize([-16,-16,0], [16,16,32]); 107 | m_eHead.SetOrigin(GetOrigin() + [0,0,20]); 108 | m_eHead.colormap = colormap; 109 | 110 | ScheduleThink(Think, 0.1f); 111 | m_state = SENTRY_SEARCHING; 112 | m_flNextIdleSound = time + 5.0f; 113 | 114 | env_message_single(real_owner, "#Sentry_finish"); 115 | Sound_Play(this, CHAN_BODY, "engineer.turret_set"); 116 | } 117 | 118 | void 119 | TFCSentry::TFCSentry(void) 120 | { 121 | m_eHead = spawn(NSSurfacePropEntity); 122 | SetModel("models/base.mdl"); 123 | SetSolid(SOLID_BBOX); 124 | SetMovetype(MOVETYPE_NONE); 125 | SetSize([-16,-16,0], [16,16,20]); 126 | 127 | SetTakedamage(DAMAGE_YES); 128 | SetHealth(100); 129 | m_eHead.SetTakedamage(DAMAGE_YES); 130 | m_eHead.SetHealth(100); 131 | m_state = SENTRY_IDLE; 132 | } 133 | 134 | void 135 | TFCSentry_Build(void) 136 | { 137 | player pl = (player)self; 138 | 139 | /* only engineers can do this */ 140 | if (pl.classtype != CLASS_ENGINEER) 141 | return; 142 | 143 | /* it costs */ 144 | if (pl.m_iAmmoCells < TFC_SENTRY_COST) { 145 | env_message_single(pl, "#Build_nometal"); 146 | return; 147 | } 148 | 149 | /* can't build in the air */ 150 | if (!(pl.flags & FL_ONGROUND)) { 151 | env_message_single(pl, "#Build_air"); 152 | return; 153 | } 154 | 155 | if (TFC_ExistsForPlayer(pl, "TFCSentry")) { 156 | env_message_single(pl, "#Build_onesentry"); 157 | return; 158 | } 159 | 160 | pl.m_iAmmoCells -= TFC_SENTRY_COST; 161 | 162 | /* deploy */ 163 | TFCSentry sentry = spawn(TFCSentry); 164 | sentry.Place(pl); 165 | } 166 | 167 | void 168 | TFCSentry_Dismantle(void) 169 | { 170 | TFC_DetonateTypeForPlayer((player)self, "TFCSentry"); 171 | } 172 | -------------------------------------------------------------------------------- /src/server/server.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2020 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | void 18 | Game_InitRules(void) 19 | { 20 | g_grMode = spawn(TFCGameRules); 21 | } 22 | 23 | void 24 | Game_Worldspawn(void) 25 | { 26 | forceinfokey(world, "areadefs", "0"); 27 | Sound_Precache("turret_tfc.idle_noise"); 28 | Sound_Precache("turret_tfc.target_spotted"); 29 | Sound_Precache("ammo.pickup"); 30 | Sound_Precache("ammo.respawn"); 31 | Sound_Precache("player.fall"); 32 | Sound_Precache("player.lightfall"); 33 | Sound_Precache("player_tfc.death"); 34 | Sound_Precache("player_tfc.jump"); 35 | Sound_Precache("engineer.build"); 36 | Sound_Precache("engineer.turret_set"); 37 | 38 | precache_model("models/base.mdl"); 39 | precache_model("models/dispenser.mdl"); 40 | precache_model("models/sentry1.mdl"); 41 | precache_model("models/sentry2.mdl"); 42 | precache_model("models/sentry3.mdl"); 43 | precache_model("models/player.mdl"); 44 | precache_model("models/w_weaponbox.mdl"); 45 | Weapons_Init(); 46 | Player_Precache(); 47 | FX_Corpse_Init(); 48 | } 49 | 50 | void weaponbox_spawn(player pl) 51 | { 52 | } 53 | 54 | void 55 | CSEv_TFCBuild_i(int type) 56 | { 57 | player pl = (player)self; 58 | 59 | if (pl.gflags & GF_NOBUILDZONE) { 60 | env_message_single(pl, "#Build_nobuild"); 61 | return; 62 | } 63 | 64 | switch (type) { 65 | case 1: 66 | TFCDispenser_Build(); 67 | break; 68 | case 2: 69 | TFCSentry_Build(); 70 | break; 71 | case 4: 72 | TFCTeleporter_Build(); 73 | break; 74 | case 5: 75 | TFCTeleporterExit_Build(); 76 | break; 77 | } 78 | } 79 | 80 | void 81 | CSEv_TFCDismantle_i(int type) 82 | { 83 | switch (type) { 84 | case 1: 85 | TFCDispenser_Dismantle(); 86 | break; 87 | case 2: 88 | TFCSentry_Dismantle(); 89 | break; 90 | case 4: 91 | TFCTeleporter_Dismantle(); 92 | break; 93 | case 5: 94 | TFCTeleporterExit_Dismantle(); 95 | break; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/server/spawn.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2020 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | float 18 | TFCTeamJoin_SmallestTeam(int blue, int red, int yellow, int green) 19 | { 20 | while (blue > 0i || red > 0i || yellow > 0i || green > 0i) { 21 | /* the first team that goes to 0, gets picked. */ 22 | if (blue <= 0i) 23 | return 1; 24 | else if (red <= 0i) 25 | return 2; 26 | else if (yellow <= 0i) 27 | return 3; 28 | else if (green <= 0i) 29 | return 4; 30 | 31 | blue--; 32 | red--; 33 | yellow--; 34 | green--; 35 | } 36 | 37 | /* the first team that goes to 0, gets picked. */ 38 | if (blue == 0i) 39 | return 1; 40 | else if (red == 0i) 41 | return 2; 42 | else if (yellow == 0i) 43 | return 3; 44 | else if (green == 0i) 45 | return 4; 46 | 47 | return 0; 48 | } 49 | 50 | void 51 | CSEv_TeamJoin_f(float f) 52 | { 53 | player pl = (player)self; 54 | 55 | /* random... */ 56 | if (f == 0) { 57 | int bluePlayers = 0i; 58 | int redPlayers = 0i; 59 | int yellowPlayers = 0i; 60 | int greenPlayers = 0i; 61 | 62 | /* hack to get it to never pick this team */ 63 | if (g_tfcHasBlueTeam == false) 64 | bluePlayers = (int)cvar("sv_playerslots"); 65 | if (g_tfcHasRedTeam == false) 66 | redPlayers = (int)cvar("sv_playerslots"); 67 | if (g_tfcHasYellowTeam == false) 68 | yellowPlayers = (int)cvar("sv_playerslots"); 69 | if (g_tfcHasGreenTeam == false) 70 | greenPlayers = (int)cvar("sv_playerslots"); 71 | 72 | /* count all valid players within each team */ 73 | for (entity e = world; (e = find(e, ::classname, "player"));) { 74 | if (e.team == 1) 75 | bluePlayers++; 76 | else if (e.team == 2) 77 | redPlayers++; 78 | else if (e.team == 3) 79 | yellowPlayers++; 80 | else if (e.team == 4) 81 | greenPlayers++; 82 | } 83 | 84 | /* assign us to the team with the lowest amount of players */ 85 | f = TFCTeamJoin_SmallestTeam(bluePlayers, redPlayers, yellowPlayers, greenPlayers); 86 | } 87 | 88 | /* mess, do it better */ 89 | if (f == 1) { 90 | pl.team = 1; /* Blue */ 91 | forceinfokey(pl, "topcolor", "0x9aff"); 92 | forceinfokey(pl, "bottomcolor", "0x9aff"); 93 | } else if (f == 2) { 94 | pl.team = 2; /* Red */ 95 | f -= 10; 96 | forceinfokey(pl, "topcolor", "0xff1800"); 97 | forceinfokey(pl, "bottomcolor", "0xff1800"); 98 | } else if (f == 3) { 99 | pl.team = 3; /* Yellow */ 100 | f -= 20; 101 | forceinfokey(pl, "topcolor", "0xffca00"); 102 | forceinfokey(pl, "bottomcolor", "0xffca00"); 103 | } else if (f == 4) { 104 | pl.team = 4; /* Green */ 105 | f -= 30; 106 | forceinfokey(pl, "topcolor", "0x3bff00"); 107 | forceinfokey(pl, "bottomcolor", "0x3bff00"); 108 | } else { 109 | return; 110 | } 111 | 112 | if (self.health > 0) { 113 | ClientKill(); 114 | return; 115 | } 116 | } 117 | 118 | /** Called by the client-side VGUI menu when we choose a class. */ 119 | void 120 | CSEv_ClassJoin_f(float f) 121 | { 122 | 123 | player pl = (player)self; 124 | 125 | /* choose a random class. */ 126 | if (f == 0) { 127 | float newClass = 0; 128 | 129 | while (newClass == 0 || newClass == pl.classtype) 130 | newClass = floor(random(CLASS_SCOUT, CLASS_ENGINEER + 1)); 131 | 132 | f = newClass; 133 | } 134 | 135 | /* invalid */ 136 | if (pl.team == 0) { 137 | return; 138 | } 139 | 140 | if (self.classname != "player") { 141 | spawnfunc_player(); 142 | } 143 | 144 | /* invalid */ 145 | if (pl.classtype == f) 146 | return; 147 | 148 | /* if we're still alive... */ 149 | if (pl.health > 0) { 150 | pl.classtype = f; 151 | pl.MakeClass(f); 152 | ClientKill(); 153 | } else { 154 | /* insta spawn */ 155 | 156 | /* assign our class type for safe keeping */ 157 | pl.classtype = f; 158 | 159 | /* turn the player into the class of his choice */ 160 | pl.MakeClass(f); 161 | pl.SpawnIntoGame(); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /src/server/teleporter.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #define TFC_TELEPORTER_COST 125 18 | 19 | /* main teleporter */ 20 | class 21 | TFCTeleporter:NSSurfacePropEntity 22 | { 23 | float m_flNextTeleport; 24 | 25 | void(void) TFCTeleporter; 26 | 27 | virtual void(player) Place; 28 | virtual void(void) FinishPlacing; 29 | virtual void(entity) Touch; 30 | }; 31 | 32 | void 33 | TFCTeleporter::Touch(entity eToucher) 34 | { 35 | if (eToucher.team != real_owner.team) 36 | return; 37 | 38 | if (m_flNextTeleport > time) 39 | return; 40 | 41 | TFCTeleporter target = __NULL__; 42 | string exitname; 43 | 44 | if (classname == "TFCTeleporter") 45 | exitname = "TFCTeleporterExit"; 46 | else 47 | return; 48 | 49 | /* loop through all exits */ 50 | for (entity e = world; (e = find(e, ::classname, exitname));) { 51 | /* if it's not places by our owner... */ 52 | if (e.real_owner != real_owner) 53 | continue; 54 | 55 | target = (TFCTeleporter)e; 56 | break; 57 | } 58 | 59 | if (!target) 60 | return; 61 | 62 | /* teleport our player */ 63 | setorigin(eToucher, target.origin + [0,0,32]); 64 | 65 | /* if the teleport was successful, make them unusable for 2.5 secs */ 66 | target.m_flNextTeleport = m_flNextTeleport = time + 2.5f; 67 | 68 | } 69 | 70 | void 71 | TFCTeleporter::Place(player pl) 72 | { 73 | SetAngles(pl.GetAngles()); 74 | 75 | makevectors([0, pl.v_angle[1], 0]); 76 | SetOrigin(pl.origin + (v_forward * 48)); 77 | DropToFloor(); 78 | ScheduleThink(FinishPlacing, 5.0f); 79 | 80 | real_owner = pl; 81 | colormap = pl.colormap; 82 | 83 | env_message_single(real_owner, "#Engineer_building"); 84 | Sound_Play(this, CHAN_BODY, "engineer.build"); 85 | } 86 | 87 | void 88 | TFCTeleporter::FinishPlacing(void) 89 | { 90 | env_message_single(real_owner, "You built the entrance, sonny!"); 91 | Sound_Play(this, CHAN_BODY, "engineer.turret_set"); 92 | } 93 | 94 | void 95 | TFCTeleporter::TFCTeleporter(void) 96 | { 97 | SetModel("models/dispenser.mdl"); 98 | SetSolid(SOLID_TRIGGER); 99 | SetMovetype(MOVETYPE_NONE); 100 | SetSize([-16,-16,0], [16,16,48]); 101 | } 102 | 103 | 104 | /* exit only */ 105 | class 106 | TFCTeleporterExit:TFCTeleporter 107 | { 108 | void(void) TFCTeleporterExit; 109 | virtual void(void) FinishPlacing; 110 | }; 111 | 112 | void 113 | TFCTeleporterExit::FinishPlacing(void) 114 | { 115 | env_message_single(real_owner, "You built the exit, sonny!"); 116 | Sound_Play(this, CHAN_BODY, "engineer.turret_set"); 117 | } 118 | 119 | void 120 | TFCTeleporterExit::TFCTeleporterExit(void) 121 | { 122 | SetModel("models/dispenser.mdl"); 123 | SetSolid(SOLID_TRIGGER); 124 | SetMovetype(MOVETYPE_NONE); 125 | SetSize([-16,-16,0], [16,16,48]); 126 | } 127 | 128 | void 129 | TFCTeleporter_Build(void) 130 | { 131 | player pl = (player)self; 132 | 133 | /* only engineers can do this */ 134 | if (pl.classtype != CLASS_ENGINEER) 135 | return; 136 | 137 | /* it costs */ 138 | if (pl.m_iAmmoCells < TFC_TELEPORTER_COST) { 139 | env_message_single(pl, "#Build_nometal"); 140 | return; 141 | } 142 | 143 | /* can't build in the air */ 144 | if (!(pl.flags & FL_ONGROUND)) { 145 | env_message_single(pl, "#Build_air"); 146 | return; 147 | } 148 | 149 | if (TFC_ExistsForPlayer(pl, "TFCTeleport")) { 150 | env_message_single(pl, "You can only have one teleporter."); 151 | return; 152 | } 153 | 154 | pl.m_iAmmoCells -= TFC_TELEPORTER_COST; 155 | 156 | /* deploy */ 157 | TFCTeleporter start = spawn(TFCTeleporter); 158 | start.Place(pl); 159 | } 160 | 161 | void 162 | TFCTeleporterExit_Build(void) 163 | { 164 | player pl = (player)self; 165 | 166 | /* only engineers can do this */ 167 | if (pl.classtype != CLASS_ENGINEER) 168 | return; 169 | 170 | /* it costs */ 171 | if (pl.m_iAmmoCells < TFC_TELEPORTER_COST) { 172 | env_message_single(pl, "#Build_nometal"); 173 | return; 174 | } 175 | 176 | /* can't build in the air */ 177 | if (!(pl.flags & FL_ONGROUND)) { 178 | env_message_single(pl, "#Build_air"); 179 | return; 180 | } 181 | 182 | if (TFC_ExistsForPlayer(pl, "TFCTeleportExit")) { 183 | env_message_single(pl, "You can only have one teleporter exit."); 184 | return; 185 | } 186 | 187 | pl.m_iAmmoCells -= TFC_TELEPORTER_COST; 188 | 189 | /* deploy */ 190 | TFCTeleporterExit end = spawn(TFCTeleporterExit); 191 | end.Place(pl); 192 | } 193 | 194 | void 195 | TFCTeleporter_Dismantle(void) 196 | { 197 | TFC_DetonateTypeForPlayer((player)self, "TFCTeleporter"); 198 | } 199 | void 200 | TFCTeleporterExit_Dismantle(void) 201 | { 202 | TFC_DetonateTypeForPlayer((player)self, "TFCTeleporterExit"); 203 | } 204 | -------------------------------------------------------------------------------- /src/server/vox.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | void 18 | Vox_Sentence_Broadcast(string msg) 19 | { 20 | if (!msg || msg == "") 21 | return; 22 | 23 | WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); 24 | WriteByte(MSG_MULTICAST, EV_TFC_VOXMSG); 25 | WriteString(MSG_MULTICAST, msg); 26 | multicast([0,0,0], MULTICAST_ALL_R); 27 | } 28 | 29 | void 30 | Vox_Sentence_Single(entity targ, string msg) 31 | { 32 | if (!msg || msg == "") 33 | return; 34 | 35 | WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); 36 | WriteByte(MSG_MULTICAST, EV_TFC_VOXMSG); 37 | WriteString(MSG_MULTICAST, msg); 38 | msg_entity = targ; 39 | multicast([0,0,0], MULTICAST_ONE_R); 40 | } 41 | -------------------------------------------------------------------------------- /src/shared/animations_tfc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2022 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | enum 18 | { 19 | TFCANIM_DIEGUTSHOT = ANIM_DIEGUTSHOT, 20 | TFCANIM_AIMCROWBAR, 21 | TFCANIM_SHOOTCROWBAR, 22 | TFCANIM_CR_AIMCROWBAR, 23 | TFCANIM_CR_SHOOTCROWBAR, 24 | TFCANIM_AIM1HAND, 25 | TFCANIM_SHOOT1HAND, 26 | TFCANIM_CR_AIM1HAND, 27 | TFCANIM_CR_SHOOT1HAND, 28 | TFCANIM_AIMSHOTGUN, 29 | TFCANIM_SHOOTSHOTGUN, 30 | TFCANIM_CR_AIMSHOTGUN, 31 | TFCANIM_CR_SHOOTSHOTGUN, 32 | TFCANIM_AIMGAUSS, 33 | TFCANIM_SHOOTGAUSS, 34 | TFCANIM_CR_AIMGAUSS, 35 | TFCANIM_CR_SHOOTGAUSS, 36 | TFCANIM_AIMMP5, 37 | TFCANIM_SHOOTMP5, 38 | TFCANIM_CR_AIMMP5, 39 | TFCANIM_CR_SHOOTMP5, 40 | TFCANIM_AIMRPG, 41 | TFCANIM_SHOOTRPG, 42 | TFCANIM_CR_AIMRPG, 43 | TFCANIM_CR_SHOOTRPG, 44 | TFCANIM_AIMEGON, 45 | TFCANIM_SHOOTEGON, 46 | TFCANIM_CR_AIMEGON, 47 | TFCANIM_CR_SHOOTEGON, 48 | TFCANIM_AIMSNIPER, 49 | TFCANIM_SHOOTSNIPER, 50 | TFCANIM_CR_AIMSNIPER, 51 | TFCANIM_CR_SHOOTSNIPER, 52 | TFCANIM_AIMAUTOSNIPER, 53 | TFCANIM_SHOOTAUTOSNIPER, 54 | TFCANIM_CR_AIMAUTOSNIPER, 55 | TFCANIM_CR_SHOOTAUTOSNIPER, 56 | TFCANIM_AIMMEDKIT, 57 | TFCANIM_SHOOTMEDKIT, 58 | TFCANIM_CR_AIMMEDKIT, 59 | TFCANIM_CR_SHOOTMEDKIT, 60 | TFCANIM_AIMKNIFE, 61 | TFCANIM_SHOOTKNIFE, 62 | TFCANIM_CR_AIMKNIFE, 63 | TFCANIM_CR_SHOOTKNIFE, 64 | TFCANIM_AIMASSCAN, 65 | TFCANIM_SHOOTASSCAN, 66 | TFCANIM_CR_AIMASSCAN, 67 | TFCANIM_CR_SHOOTASSCAN 68 | }; -------------------------------------------------------------------------------- /src/shared/defs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2022 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | typedef enum 18 | { 19 | CLASS_SCOUT = 1, 20 | CLASS_SNIPER, 21 | CLASS_SOLDIER, 22 | CLASS_DEMO, 23 | CLASS_MEDIC, 24 | CLASS_HVYWEAPON, 25 | CLASS_PYRO, 26 | CLASS_SPY, 27 | CLASS_ENGINEER 28 | } classtype_e; 29 | 30 | string g_teammodels[] = { 31 | "", 32 | "models/player/scout/scout.mdl", 33 | "models/player/sniper/sniper.mdl", 34 | "models/player/soldier/soldier.mdl", 35 | "models/player/demo/demo.mdl", 36 | "models/player/medic/medic.mdl", 37 | "models/player/hvyweapon/hvyweapon.mdl", 38 | "models/player/pyro/pyro.mdl", 39 | "models/player/spy/spy.mdl", 40 | "models/player/engineer/engineer.mdl" 41 | }; 42 | 43 | string g_teammodels_hd[] = { 44 | "", 45 | "models/player/scout/scout2.mdl", 46 | "models/player/sniper/sniper2.mdl", 47 | "models/player/soldier/soldier2.mdl", 48 | "models/player/demo/demo2.mdl", 49 | "models/player/medic/medic2.mdl", 50 | "models/player/hvyweapon/hvyweapon2.mdl", 51 | "models/player/pyro/pyro2.mdl", 52 | "models/player/spy/spy2.mdl", 53 | "models/player/engineer/engineer2.mdl" 54 | }; 55 | 56 | /* are we using a later build of TF? */ 57 | bool 58 | TFC_IsLaterBuild(void) 59 | { 60 | if (whichpack(g_teammodels_hd[1])) 61 | return true; 62 | 63 | return false; 64 | } 65 | 66 | /* stuff */ 67 | string 68 | TFC_GetModelForClasstype(classtype_e type) 69 | { 70 | if (TFC_IsLaterBuild() == true) 71 | if (autocvar(tfc_newmodels, 0) == 1) 72 | return g_teammodels[type]; /* on later versions, the old names are the HD ones */ 73 | else 74 | return g_teammodels_hd[type]; 75 | 76 | return g_teammodels[type]; 77 | } -------------------------------------------------------------------------------- /src/shared/events.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2020 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | enum 18 | { 19 | EV_TFC_VOXMSG = EV_SEPARATOR 20 | }; 21 | -------------------------------------------------------------------------------- /src/shared/flags.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2020 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* game flags */ 18 | #define GF_SEMI_TOGGLED (1<<0) 19 | #define GF_FLASHLIGHT (1<<1) 20 | #define GF_NOBUILDZONE (1<<2) 21 | #define GF_NOGRENADEZONE (1<<3) 22 | #define GF_GREN1COOK (1<<4) 23 | #define GF_GREN2COOK (1<<5) 24 | #define GF_UNUSED7 (1<<6) 25 | #define GF_UNUSED8 (1<<7) 26 | #define GF_UNUSED9 (1<<8) 27 | #define GF_UNUSED10 (1<<9) 28 | #define GF_UNUSED11 (1<<10) 29 | #define GF_UNUSED12 (1<<11) 30 | #define GF_UNUSED13 (1<<12) 31 | #define GF_UNUSED14 (1<<14) 32 | #define GF_UNUSED15 (1<<16) 33 | #define GF_UNUSED16 (1<<13) 34 | #define GF_UNUSED17 (1<<17) 35 | #define GF_UNUSED18 (1<<18) 36 | #define GF_UNUSED19 (1<<19) 37 | #define GF_UNUSED20 (1<<20) 38 | #define GF_UNUSED21 (1<<21) 39 | #define GF_UNUSED22 (1<<22) 40 | #define GF_UNUSED23 (1<<23) 41 | -------------------------------------------------------------------------------- /src/shared/include.src: -------------------------------------------------------------------------------- 1 | #includelist 2 | defs.h 3 | items.h 4 | weapons.h 5 | 6 | flags.h 7 | events.h 8 | player.qc 9 | ../../../valve/src/shared/weapon_common.h 10 | ../../../valve/src/shared/animations.h 11 | animations_tfc.h 12 | ../../../valve/src/shared/animations.qc 13 | pmove.qc 14 | 15 | ../../../valve/src/shared/fx_blood.qc 16 | ../../../valve/src/shared/fx_corpse.qc 17 | 18 | weapon_basesemi.qc 19 | weapon_basemelee.qc 20 | weapon_baseshotgun.qc 21 | weapon_baseprojectile.qc 22 | weapon_baseautomatic.qc 23 | 24 | w_asscan.qc 25 | w_autorifle.qc 26 | w_crowbar.qc 27 | w_dbs.qc 28 | w_flamer.qc 29 | w_glauncher.qc 30 | w_grapple.qc 31 | w_incendiary.qc 32 | w_knife.qc 33 | w_medkit.qc 34 | w_nailgun.qc 35 | w_pipebomb.qc 36 | w_railgun.qc 37 | w_rpg.qc 38 | w_sbs.qc 39 | w_sniper.qc 40 | w_supernail.qc 41 | w_tranquil.qc 42 | w_umbrella.qc 43 | w_wrench.qc 44 | weapons.qc 45 | ../../../valve/src/shared/weapon_common.qc 46 | #endlist 47 | -------------------------------------------------------------------------------- /src/shared/items.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2020 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #define ITEM_CROWBAR 0x00000001 18 | #define ITEM_MEDKIT 0x00000002 19 | #define ITEM_KNIFE 0x00000004 20 | #define ITEM_WRENCH 0x00000008 21 | #define ITEM_UMBRELLA 0x00000010 22 | #define ITEM_SBS 0x00000020 23 | #define ITEM_SNIPER 0x00000040 24 | #define ITEM_TRANQUIL 0x00000080 25 | #define ITEM_RAILGUN 0x00000100 26 | #define ITEM_AUTORIFLE 0x00000200 27 | #define ITEM_DBS 0x00000400 28 | #define ITEM_NAILGUN 0x00000800 29 | #define ITEM_GLAUNCHER 0x00001000 30 | #define ITEM_SUPERNAIL 0x00002000 31 | #define ITEM_FLAMER 0x00004000 32 | #define ITEM_RPG 0x00008000 33 | #define ITEM_PIPEBOMB 0x00010000 34 | #define ITEM_ASSCAN 0x00020000 35 | 36 | #define ITEM_INCENDIARY 0x00040000 37 | 38 | #define ITEM_GRAPPLE 0x00080000 39 | #define ITEM_SUIT 0x00100000 40 | #define ITEM_GOALITEM 0x00200000 41 | #define ITEM_UNUSED23 0x00400000 42 | #define ITEM_UNUSED24 0x00800000 43 | #define ITEM_UNUSED25 0x01000000 44 | #define ITEM_UNUSED26 0x02000000 45 | #define ITEM_UNUSED27 0x04000000 46 | #define ITEM_UNUSED28 0x08000000 47 | #define ITEM_UNUSED29 0x10000000 48 | #define ITEM_UNUSED30 0x20000000 49 | #define ITEM_UNUSED31 0x40000000 50 | #define ITEM_UNUSED32 0x80000000 51 | -------------------------------------------------------------------------------- /src/shared/pmove.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2020 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #define PMOVE_AIRSTEPHEIGHT 0 18 | #define PMOVE_STEPHEIGHT 18 19 | #define PMOVE_FRICTION 4 20 | #define PMOVE_EDGEFRICTION 1 21 | #define PMOVE_STOPSPEED 100 22 | #define PMOVE_GRAVITY 800 23 | #define PMOVE_AIRACCELERATE 10 24 | #define PMOVE_WATERACCELERATE 10 25 | #define PMOVE_ACCELERATE 10 26 | #define PMOVE_MAXSPEED 320 27 | #define PMOVE_STEP_WALKSPEED 135 28 | #define PMOVE_STEP_RUNSPEED 220 29 | #define PHY_VIEWPOS [0,0,28] 30 | #define PHY_VIEWPOS_CROUCHED [0,0,12] 31 | 32 | void 33 | player::Physics_Jump(void) 34 | { 35 | if (waterlevel >= 2) { 36 | if (watertype == CONTENT_WATER) { 37 | velocity[2] = 100; 38 | } else if (watertype == CONTENT_SLIME) { 39 | velocity[2] = 80; 40 | } else { 41 | velocity[2] = 50; 42 | } 43 | } else { 44 | if (flags & FL_ONGROUND) { 45 | #ifdef SERVER 46 | Sound_Play(this, CHAN_VOICE, "player_tfc.jump"); 47 | #endif 48 | velocity[2] += 265; 49 | } 50 | } 51 | } 52 | 53 | float 54 | player::Physics_MaxSpeed(void) 55 | { 56 | float desiredspeed = 300.0f; 57 | 58 | /* values courtesy of https://wiki.teamfortress.com/ */ 59 | switch (classtype) { 60 | case CLASS_SCOUT: 61 | desiredspeed = 400.0f; 62 | break; 63 | case CLASS_SNIPER: 64 | desiredspeed = 300.0f; 65 | break; 66 | case CLASS_SOLDIER: 67 | desiredspeed = 240.0f; 68 | break; 69 | case CLASS_DEMO: 70 | desiredspeed = 280.0f; 71 | break; 72 | case CLASS_MEDIC: 73 | desiredspeed = 320.0f; 74 | break; 75 | case CLASS_HVYWEAPON: 76 | desiredspeed = 228.0f; 77 | break; 78 | case CLASS_PYRO: 79 | desiredspeed = 300.0f; 80 | break; 81 | case CLASS_SPY: 82 | desiredspeed = 300.0f; 83 | break; 84 | case CLASS_ENGINEER: 85 | desiredspeed = 300.0f; 86 | break; 87 | default: 88 | desiredspeed = 300.0f; 89 | } 90 | 91 | if (GetFlags() & FL_CROUCHING) 92 | desiredspeed /= 3; 93 | 94 | return desiredspeed; 95 | } -------------------------------------------------------------------------------- /src/shared/w_autorifle.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2020 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | enum 18 | { 19 | SNIPER_IDLE, 20 | SNIPER_AIM, 21 | SNIPER_FIRE, 22 | SNIPER_DRAW, 23 | SNIPER_HOLSTER, 24 | SNIPER_AUTOIDLE, 25 | SNIPER_AUTOFIRE, 26 | SNIPER_AUTODRAW, 27 | SNIPER_AUTOHOLSTER, 28 | }; 29 | 30 | void 31 | w_autorifle_precache(void) 32 | { 33 | precache_model("models/v_tfc_sniper.mdl"); 34 | precache_model("models/p_sniper2.mdl"); 35 | Sound_Precache("weapon_sniper.fire"); 36 | } 37 | 38 | void 39 | w_autorifle_updateammo(player pl) 40 | { 41 | Weapons_UpdateAmmo(pl, __NULL__, pl.m_iAmmoShells, __NULL__); 42 | } 43 | 44 | string 45 | w_autorifle_wmodel(void) 46 | { 47 | return ""; 48 | } 49 | string 50 | w_autorifle_pmodel(player pl) 51 | { 52 | return "models/p_sniper2.mdl"; 53 | } 54 | 55 | string 56 | w_autorifle_deathmsg(void) 57 | { 58 | return "%s was assaulted by %s's Assault Cannon."; 59 | } 60 | 61 | void 62 | w_autorifle_release(player pl) 63 | { 64 | if (pl.w_idle_next > 0) 65 | return; 66 | 67 | Weapons_ViewAnimation(pl, SNIPER_AUTOIDLE); 68 | } 69 | 70 | void 71 | w_autorifle_draw(player pl) 72 | { 73 | Weapons_SetModel("models/v_tfc_sniper.mdl"); 74 | Weapons_ViewAnimation(pl, SNIPER_AUTODRAW); 75 | pl.w_idle_next = 1.0f; 76 | } 77 | 78 | float 79 | w_autorifle_aimanim(player pl) 80 | { 81 | return pl.flags & FL_CROUCHING ? TFCANIM_CR_AIMAUTOSNIPER : TFCANIM_AIMAUTOSNIPER; 82 | } 83 | 84 | void 85 | w_autorifle_primary(player pl) 86 | { 87 | int s = w_baseauto_fire(WEAPON_AUTORIFLE, player::m_iAmmoShells, 8, [0,0]); 88 | 89 | switch (s) { 90 | case AUTO_FIRE_FAILED: 91 | return; 92 | break; 93 | case AUTO_FIRED: 94 | case AUTO_LAST: 95 | Weapons_ViewAnimation(pl, SNIPER_AUTOFIRE); 96 | 97 | if (pl.flags & FL_CROUCHING) 98 | Animation_PlayerTop(pl, TFCANIM_CR_SHOOTAUTOSNIPER, 0.45f); 99 | else 100 | Animation_PlayerTop(pl, TFCANIM_SHOOTAUTOSNIPER, 0.45f); 101 | 102 | #ifdef CLIENT 103 | View_SetMuzzleflash(MUZZLE_RIFLE); 104 | #endif 105 | Weapons_Sound(pl, CHAN_WEAPON, "weapon_sniper.fire"); 106 | pl.w_attack_next = 0.1f; 107 | break; 108 | case AUTO_EMPTY: 109 | w_autorifle_release(pl); 110 | pl.w_attack_next = 0.2f; 111 | break; 112 | } 113 | 114 | pl.w_idle_next = 0.0f; 115 | } 116 | 117 | void 118 | w_autorifle_postdraw(player pl) 119 | { 120 | #ifdef CLIENT 121 | // crosshair 122 | if (pl.viewzoom == 1) { 123 | Cross_DrawSub(g_cross_spr, [24,24], [72/128,0], [0.1875, 0.1875]); 124 | } else { 125 | Cross_DrawSub(g_cross_spr, [104,16], [24/128,96/128], [104/128, 16/128]); 126 | } 127 | // ammo counter 128 | HUD_DrawAmmo2(); 129 | vector aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42]; 130 | drawsubpic(aicon_pos, [24,24], "sprites/640hud7.spr_0.tga", [72/256,72/128], [24/256, 24/128], g_hud_color, pSeatLocal->m_flAmmo2Alpha, DRAWFLAG_ADDITIVE); 131 | #endif 132 | } 133 | 134 | void 135 | w_autorifle_hudpic(player pl, int selected, vector pos, float a) 136 | { 137 | #ifdef CLIENT 138 | if (selected) { 139 | drawsubpic( 140 | pos, 141 | [170,45], 142 | g_tfchud2_spr, 143 | [0,0], 144 | [170/256,45/256], 145 | g_hud_color, 146 | a, 147 | DRAWFLAG_ADDITIVE 148 | ); 149 | } else { 150 | drawsubpic( 151 | pos, 152 | [170,45], 153 | g_tfchud1_spr, 154 | [0,0], 155 | [170/256,45/256], 156 | g_hud_color, 157 | a, 158 | DRAWFLAG_ADDITIVE 159 | ); 160 | } 161 | #endif 162 | } 163 | 164 | weapon_t w_autorifle = 165 | { 166 | .name = "autorifle", 167 | .id = ITEM_AUTORIFLE, 168 | .slot = 2, 169 | .slot_pos = 0, 170 | .weight = WEIGHT_AUTORIFLE, 171 | .draw = w_autorifle_draw, 172 | .holster = __NULL__, 173 | .primary = w_autorifle_primary, 174 | .secondary = w_autorifle_release, 175 | .reload = __NULL__, 176 | .release = w_autorifle_release, 177 | .postdraw = w_autorifle_postdraw, 178 | .precache = w_autorifle_precache, 179 | .pickup = __NULL__, 180 | .updateammo = w_autorifle_updateammo, 181 | .wmodel = __NULL__, 182 | .pmodel = w_autorifle_pmodel, 183 | .deathmsg = w_autorifle_deathmsg, 184 | .aimanim = w_autorifle_aimanim, 185 | .hudpic = w_autorifle_hudpic, 186 | .isempty = w_asscan_isempty 187 | }; 188 | -------------------------------------------------------------------------------- /src/shared/w_crowbar.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2021 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /*QUAKED weapon_crowbar (0 0 1) (-16 -16 0) (16 16 32) 18 | "model" "models/w_crowbar.mdl" 19 | 20 | HALF-LIFE (1998) ENTITY 21 | 22 | Crowbar Weapon 23 | 24 | */ 25 | 26 | enum 27 | { 28 | CBAR_IDLE, 29 | CBAR_DRAW, 30 | CBAR_HOLSTER, 31 | CBAR_ATTACK1HIT, 32 | CBAR_ATTACK1MISS, 33 | CBAR_ATTACK2MISS, 34 | CBAR_ATTACK2HIT, 35 | CBAR_ATTACK3MISS, 36 | CBAR_ATTACK3HIT 37 | }; 38 | 39 | void 40 | w_crowbar_precache(void) 41 | { 42 | #ifdef SERVER 43 | Sound_Precache("weapon_crowbar.hit"); 44 | Sound_Precache("weapon_crowbar.miss"); 45 | Sound_Precache("weapon_crowbar.hitbody"); 46 | precache_model("models/w_crowbar.mdl"); 47 | #else 48 | precache_model("models/v_tfc_crowbar.mdl"); 49 | precache_model("models/p_crowbar.mdl"); 50 | #endif 51 | } 52 | 53 | void 54 | w_crowbar_updateammo(player pl) 55 | { 56 | 57 | } 58 | 59 | string 60 | w_crowbar_wmodel(void) 61 | { 62 | return "models/w_crowbar.mdl"; 63 | } 64 | string 65 | w_crowbar_pmodel(player pl) 66 | { 67 | return "models/p_crowbar.mdl"; 68 | } 69 | 70 | string 71 | w_crowbar_deathmsg(void) 72 | { 73 | return "%s was assaulted by %s's Crowbar."; 74 | } 75 | 76 | void 77 | w_crowbar_draw(player pl) 78 | { 79 | Weapons_SetModel("models/v_tfc_crowbar.mdl"); 80 | Weapons_ViewAnimation(pl, CBAR_DRAW); 81 | } 82 | 83 | void 84 | w_crowbar_holster(player pl) 85 | { 86 | Weapons_ViewAnimation(pl, CBAR_HOLSTER); 87 | } 88 | 89 | void 90 | w_crowbar_primary(player pl) 91 | { 92 | int anim = 0; 93 | vector src; 94 | 95 | if (pl.w_attack_next) { 96 | return; 97 | } 98 | 99 | Weapons_MakeVectors(pl); 100 | src = pl.origin + pl.view_ofs; 101 | 102 | /* make sure we can gib corpses */ 103 | int oldhitcontents = self.hitcontentsmaski; 104 | self.hitcontentsmaski = CONTENTBITS_POINTSOLID | CONTENTBIT_CORPSE; 105 | traceline(src, src + (v_forward * 32), FALSE, pl); 106 | self.hitcontentsmaski = oldhitcontents; 107 | 108 | if (trace_fraction >= 1.0) { 109 | pl.w_attack_next = 0.5f; 110 | } else { 111 | pl.w_attack_next = 0.25f; 112 | } 113 | pl.w_idle_next = 2.5f; 114 | 115 | int r = (float)input_sequence % 3; 116 | switch (r) { 117 | case 0: 118 | Weapons_ViewAnimation(pl, trace_fraction >= 1 ? CBAR_ATTACK1MISS:CBAR_ATTACK1HIT); 119 | break; 120 | case 1: 121 | Weapons_ViewAnimation(pl, trace_fraction >= 1 ? CBAR_ATTACK2MISS:CBAR_ATTACK2HIT); 122 | break; 123 | default: 124 | Weapons_ViewAnimation(pl, trace_fraction >= 1 ? CBAR_ATTACK3MISS:CBAR_ATTACK3HIT); 125 | } 126 | 127 | if (pl.flags & FL_CROUCHING) 128 | Animation_PlayerTop(pl, ANIM_CR_SHOOTCROWBAR, 0.41f); 129 | else 130 | Animation_PlayerTop(pl, ANIM_SHOOTCROWBAR, 0.5f); 131 | 132 | #ifdef SERVER 133 | Sound_Play(self, CHAN_WEAPON, "weapon_crowbar.miss"); 134 | 135 | if (trace_fraction >= 1.0) { 136 | return; 137 | } 138 | 139 | /* don't bother with decals, we got squibs */ 140 | if (trace_ent.iBleeds) { 141 | FX_Blood(trace_endpos, [1,0,0]); 142 | } else { 143 | SurfData_Impact(trace_ent, trace_endpos, trace_plane_normal); 144 | } 145 | 146 | if (trace_ent.takedamage) { 147 | Damage_Apply(trace_ent, pl, 18, WEAPON_CROWBAR, DMG_BLUNT); 148 | if (trace_ent.iBleeds) { 149 | Sound_Play(self, CHAN_WEAPON, "weapon_crowbar.hitbody"); 150 | } 151 | } else { 152 | Sound_Play(self, CHAN_WEAPON, "weapon_crowbar.hit"); 153 | } 154 | #endif 155 | } 156 | 157 | void 158 | w_crowbar_release(player pl) 159 | { 160 | 161 | if (pl.w_idle_next) { 162 | return; 163 | } 164 | 165 | Weapons_ViewAnimation(pl, CBAR_IDLE); 166 | pl.w_idle_next = 15.0f; 167 | } 168 | 169 | float 170 | w_crowbar_aimanim(player pl) 171 | { 172 | return pl.flags & FL_CROUCHING ? ANIM_CR_AIMCROWBAR : ANIM_AIMCROWBAR; 173 | } 174 | 175 | void 176 | w_crowbar_hudpic(player pl, int selected, vector pos, float a) 177 | { 178 | #ifdef CLIENT 179 | if (selected) { 180 | drawsubpic( 181 | pos, 182 | [170,45], 183 | g_hud4_spr, 184 | [0,0], 185 | [170/256,45/256], 186 | g_hud_color, 187 | a, 188 | DRAWFLAG_ADDITIVE 189 | ); 190 | } else { 191 | drawsubpic( 192 | pos, 193 | [170,45], 194 | g_hud1_spr, 195 | [0,0], 196 | [170/256,45/256], 197 | g_hud_color, 198 | a, 199 | DRAWFLAG_ADDITIVE 200 | ); 201 | } 202 | #endif 203 | } 204 | 205 | weapon_t w_crowbar = 206 | { 207 | .name = "crowbar", 208 | .id = ITEM_CROWBAR, 209 | .slot = 0, 210 | .slot_pos = 0, 211 | .weight = WEIGHT_CROWBAR, 212 | .draw = w_crowbar_draw, 213 | .holster = w_crowbar_holster, 214 | .primary = w_crowbar_primary, 215 | .secondary = __NULL__, 216 | .reload = __NULL__, 217 | .release = w_crowbar_release, 218 | .postdraw = __NULL__, 219 | .precache = w_crowbar_precache, 220 | .pickup = __NULL__, 221 | .updateammo = w_crowbar_updateammo, 222 | .wmodel = w_crowbar_wmodel, 223 | .pmodel = w_crowbar_pmodel, 224 | .deathmsg = w_crowbar_deathmsg, 225 | .aimanim = w_crowbar_aimanim, 226 | .hudpic = w_crowbar_hudpic, 227 | .isempty = w_asscan_isempty 228 | }; 229 | -------------------------------------------------------------------------------- /src/shared/w_dbs.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2020 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | enum 18 | { 19 | DBS_IDLE1, 20 | DBS_FIRE1, 21 | DBS_FIRE2, 22 | DBS_ADDSHELL, 23 | DBS_PUMP, 24 | DBS_START_RELOAD, 25 | DBS_DRAW, 26 | DBS_HOLSTER, 27 | DBS_IDLE2, 28 | DBS_IDLE3 29 | }; 30 | 31 | void 32 | w_dbs_precache(void) 33 | { 34 | precache_model("models/v_tfc_shotgun.mdl"); 35 | precache_model("models/w_shot2.mdl"); 36 | precache_model("models/p_shot2.mdl"); 37 | #ifdef SERVER 38 | Sound_Precache("weapon_dbs.cock"); 39 | Sound_Precache("weapon_dbs.fire"); 40 | Sound_Precache("weapon_dbs.reload"); 41 | #endif 42 | } 43 | 44 | void 45 | w_dbs_updateammo(player pl) 46 | { 47 | Weapons_UpdateAmmo(pl, pl.mag_dbs, pl.m_iAmmoShells, __NULL__); 48 | } 49 | 50 | string 51 | w_dbs_wmodel(void) 52 | { 53 | return "models/w_shot2.mdl"; 54 | } 55 | 56 | string 57 | w_dbs_pmodel(player pl) 58 | { 59 | return "models/p_shotgun2.mdl"; 60 | } 61 | 62 | string 63 | w_dbs_deathmsg(void) 64 | { 65 | return ""; 66 | } 67 | 68 | int 69 | w_dbs_pickup(player pl, int new, int startammo) 70 | { 71 | #ifdef SERVER 72 | pl.mag_dbs = bound(0, pl.mag_dbs + 16, 16); 73 | #endif 74 | return (1); 75 | } 76 | 77 | void 78 | w_dbs_draw(player pl) 79 | { 80 | Weapons_SetModel("models/v_tfc_shotgun.mdl"); 81 | Weapons_ViewAnimation(pl, DBS_DRAW); 82 | } 83 | 84 | void 85 | w_dbs_holster(player pl) 86 | { 87 | Weapons_ViewAnimation(pl, DBS_HOLSTER); 88 | } 89 | 90 | void 91 | w_dbs_primary(player pl) 92 | { 93 | int s; 94 | 95 | if (pl.mag_dbs != 1) 96 | s = w_baseshotgun_fire(WEAPON_DBS, player::mag_dbs, 14, 4, [0.14, 0.08, 0]); 97 | else 98 | s = w_baseshotgun_fire(WEAPON_DBS, player::mag_dbs, 6, 4, [0.14, 0.08, 0]); 99 | 100 | switch (s) { 101 | case AUTO_FIRE_FAILED: 102 | return; 103 | break; 104 | case AUTO_LAST: 105 | case AUTO_FIRED: 106 | pl.mag_dbs--; 107 | Weapons_ViewAnimation(pl, DBS_FIRE1); 108 | Weapons_ViewPunchAngle(pl, [-2,0,0]); 109 | 110 | if (pl.flags & FL_CROUCHING) 111 | Animation_PlayerTop(pl, TFCANIM_CR_SHOOTSHOTGUN, 0.45f); 112 | else 113 | Animation_PlayerTop(pl, TFCANIM_SHOOTSHOTGUN, 0.45f); 114 | 115 | #ifdef CLIENT 116 | View_SetMuzzleflash(MUZZLE_ROUND); 117 | #endif 118 | Weapons_Sound(pl, CHAN_WEAPON, "weapon_dbs.fire"); 119 | pl.w_attack_next = 0.7f; 120 | break; 121 | case AUTO_EMPTY: 122 | Weapons_Sound(pl, CHAN_WEAPON, "weapon_dbs.fire_empty"); 123 | pl.w_attack_next = 0.2f; 124 | break; 125 | } 126 | 127 | pl.w_idle_next = 1.5f; 128 | } 129 | 130 | void 131 | w_dbs_reload(player pl) 132 | { 133 | w_baseshotgun_reload(player::mag_dbs, player::m_iAmmoShells, 16); 134 | } 135 | 136 | void 137 | w_dbs_release(player pl) 138 | { 139 | int s = w_baseshotgun_release(player::mag_dbs, player::m_iAmmoShells, 16); 140 | 141 | switch (s) { 142 | case SHOTGUN_IDLE: 143 | int r = (float)input_sequence % 3; 144 | if (r == 1) { 145 | Weapons_ViewAnimation(pl, DBS_IDLE1); 146 | } else if (r == 2) { 147 | Weapons_ViewAnimation(pl, DBS_IDLE2); 148 | } else { 149 | Weapons_ViewAnimation(pl, DBS_IDLE3); 150 | } 151 | pl.w_idle_next = 5.0f; 152 | break; 153 | case SHOTGUN_BUSY: 154 | break; 155 | case SHOTGUN_START_RELOAD: 156 | Weapons_ViewAnimation(pl, DBS_START_RELOAD); 157 | break; 158 | case SHOTGUN_RELOAD: 159 | Weapons_ViewAnimation(pl, DBS_ADDSHELL); 160 | Weapons_Sound(pl, CHAN_WEAPON, "weapon_dbs.reload"); 161 | break; 162 | case SHOTGUN_END_RELOAD: 163 | Weapons_ViewAnimation(pl, DBS_PUMP); 164 | Weapons_Sound(pl, CHAN_WEAPON, "weapon_dbs.cock"); 165 | break; 166 | } 167 | } 168 | 169 | void 170 | w_dbs_crosshair(player pl) 171 | { 172 | #ifdef CLIENT 173 | Cross_DrawSub(g_cross_spr, [24,24], [48/128,24/128], [0.1875, 0.1875]); 174 | HUD_DrawAmmo1(); 175 | HUD_DrawAmmo2(); 176 | vector aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42]; 177 | drawsubpic(aicon_pos, [24,24], "sprites/640hud7.spr_0.tga", [72/256,72/128], [24/256, 24/128], g_hud_color, pSeatLocal->m_flAmmo2Alpha, DRAWFLAG_ADDITIVE); 178 | #endif 179 | } 180 | 181 | float 182 | w_dbs_aimanim(player pl) 183 | { 184 | return pl.flags & FL_CROUCHING ? ANIM_CR_AIMSHOTGUN : ANIM_AIMSHOTGUN; 185 | } 186 | 187 | void 188 | w_dbs_hudpic(player pl, int s, vector pos, float a) 189 | { 190 | #ifdef CLIENT 191 | if (s) { 192 | drawsubpic(pos, [170,45], g_hud4_spr, [0,180/256], [170/256,45/256], g_hud_color, a, DRAWFLAG_ADDITIVE); 193 | } else { 194 | drawsubpic(pos, [170,45], g_hud1_spr, [0,180/256], [170/256,45/256], g_hud_color, a, DRAWFLAG_ADDITIVE); 195 | } 196 | #endif 197 | } 198 | 199 | weapon_t w_dbs = 200 | { 201 | .name = "sbs", 202 | .id = ITEM_DBS, 203 | .slot = 2, 204 | .slot_pos = 1, 205 | .weight = WEIGHT_DBS, 206 | .draw = w_dbs_draw, 207 | .holster = w_dbs_holster, 208 | .primary = w_dbs_primary, 209 | .secondary = w_dbs_release, 210 | .reload = w_dbs_reload, 211 | .release = w_dbs_release, 212 | .postdraw = w_dbs_crosshair, 213 | .precache = w_dbs_precache, 214 | .pickup = w_dbs_pickup, 215 | .updateammo = w_dbs_updateammo, 216 | .wmodel = w_dbs_wmodel, 217 | .pmodel = w_dbs_pmodel, 218 | .deathmsg = w_dbs_deathmsg, 219 | .aimanim = w_dbs_aimanim, 220 | .hudpic = w_dbs_hudpic, 221 | .isempty = w_asscan_isempty 222 | }; 223 | -------------------------------------------------------------------------------- /src/shared/w_flamer.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2021 Marco Cawthorne 3 | * Copyright (c) 2019-2020 Gethyn ThomasQuail 4 | * 5 | * Permission to use, copy, modify, and distribute this software for any 6 | * purpose with or without fee is hereby granted, provided that the above 7 | * copyright notice and this permission notice appear in all copies. 8 | * 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 14 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 15 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | */ 17 | 18 | enum 19 | { 20 | EGON_IDLE1, 21 | EGON_FIDGET1, 22 | EGON_ALTFIREON, 23 | EGON_ALTFIRECYCLE, 24 | EGON_ALTFIREOFF, 25 | EGON_FIRE1, 26 | EGON_FIRE2, 27 | EGON_FIRE3, 28 | EGON_FIRE4, 29 | EGON_DRAW, 30 | EGON_HOLSTER 31 | }; 32 | 33 | void 34 | w_flamer_precache(void) 35 | { 36 | #ifdef SERVER 37 | Sound_Precache("weapon_flame.fire"); 38 | precache_model("sprites/fthrow.spr"); 39 | #endif 40 | precache_model("models/v_flame.mdl"); 41 | precache_model("models/w_egon.mdl"); 42 | precache_model("models/p_egon.mdl"); 43 | } 44 | 45 | void 46 | w_flamer_updateammo(player pl) 47 | { 48 | Weapons_UpdateAmmo(pl, -1, pl.m_iAmmoCells, -1); 49 | } 50 | 51 | string 52 | w_flamer_wmodel(void) 53 | { 54 | return "models/w_egon.mdl"; 55 | } 56 | 57 | string 58 | w_flamer_pmodel(player pl) 59 | { 60 | return "models/p_egon2.mdl"; 61 | } 62 | 63 | string 64 | w_flamer_deathmsg(void) 65 | { 66 | return "%s burned to a crisp by %s's Flamethrower."; 67 | } 68 | 69 | int 70 | w_flamer_pickup(player pl, int new, int startammo) 71 | { 72 | return (1); 73 | } 74 | 75 | void 76 | w_flamer_draw(player pl) 77 | { 78 | Weapons_SetModel("models/v_flame.mdl"); 79 | Weapons_ViewAnimation(pl, EGON_DRAW); 80 | } 81 | 82 | void 83 | w_flamer_holster(player pl) 84 | { 85 | 86 | } 87 | 88 | void 89 | w_flamer_primary(player pl) 90 | { 91 | if (pl.w_attack_next > 0.0) 92 | return; 93 | 94 | /* Ammo check */ 95 | if (pl.m_iAmmoCells <= 0) 96 | return; 97 | 98 | pl.m_iAmmoCells--; 99 | Weapons_ViewAnimation(pl, EGON_FIRE1); 100 | 101 | #ifdef SERVER 102 | 103 | static void w_flamer_die(void) { 104 | NSEntity::Destroy(); 105 | } 106 | 107 | static void w_flamer_touch(entity target, entity source) { 108 | NSEntity me = (NSEntity)source; 109 | 110 | if (target.takedamage == DAMAGE_YES) { 111 | NSSurfacePropEntity m = (NSSurfacePropEntity)target; 112 | m.Ignite(source, 5.0f, WEAPON_FLAMER); 113 | } 114 | } 115 | 116 | 117 | 118 | Sound_Play(pl, CHAN_WEAPON, "weapon_flame.fire"); 119 | NSProjectile ball = spawn(NSProjectile); 120 | ball.SetModel("sprites/fthrow.spr"); 121 | ball.SetRenderMode(RM_ADDITIVE); 122 | ball.SetOwner(pl); 123 | ball.SetImpact(w_flamer_touch); 124 | ball.AnimateOnce(0, 15, 0.1f); 125 | 126 | // To be added to spec 127 | // ball.Animate(0,15); 128 | // ball.effects |= EF_BRIGHTLIGHT; 129 | 130 | // Also will need check for water contents (so projectile will die underwater) 131 | 132 | Weapons_MakeVectors(pl); 133 | ball.SetOrigin(Weapons_GetCameraPos(pl) + (v_forward * 16)); 134 | ball.SetVelocity(v_forward * 300); 135 | #endif 136 | 137 | pl.w_attack_next = 0.2f; 138 | pl.w_idle_next = 0.2f; 139 | } 140 | 141 | void 142 | w_flamer_reload(player pl) 143 | { 144 | } 145 | 146 | void 147 | w_flamer_release(player pl) 148 | { 149 | if (pl.w_attack_next > 0) 150 | return; 151 | 152 | if (pl.w_idle_next > 0) 153 | return; 154 | 155 | Weapons_ViewAnimation(pl, EGON_IDLE1); 156 | } 157 | 158 | void 159 | w_flamer_crosshair(player pl) 160 | { 161 | #ifdef CLIENT 162 | Cross_DrawSub(g_cross_spr, [24,24], [48/128,24/128], [0.1875, 0.1875]); 163 | //Cross_DrawSub(g_cross_spr, [24,24], [72/128,48/128], [0.1875, 0.1875]); 164 | HUD_DrawAmmo2(); 165 | vector aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42]; 166 | drawsubpic(aicon_pos, [24,24], g_hud7_spr, [0,96/128], [24/256, 24/128], g_hud_color, pSeatLocal->m_flAmmo2Alpha, DRAWFLAG_ADDITIVE); 167 | #endif 168 | } 169 | 170 | float 171 | w_flamer_aimanim(player pl) 172 | { 173 | return pl.flags & FL_CROUCHING ? TFCANIM_CR_AIMEGON : TFCANIM_AIMEGON; 174 | } 175 | 176 | void 177 | w_flamer_hudpic(player pl, int selected, vector pos, float a) 178 | { 179 | #ifdef CLIENT 180 | vector hud_col; 181 | 182 | if (pl.m_iAmmoCells == 0) 183 | hud_col = [1,0,0]; 184 | else 185 | hud_col = g_hud_color; 186 | 187 | HUD_DrawAmmoBar(pos, pl.m_iAmmoCells, 200, a); 188 | 189 | if (selected) { 190 | drawsubpic( 191 | pos, 192 | [170,45], 193 | g_tfchud4_spr, 194 | [0,45/256], 195 | [170/256,45/256], 196 | hud_col, 197 | a, 198 | DRAWFLAG_ADDITIVE 199 | ); 200 | } else { 201 | drawsubpic( 202 | pos, 203 | [170,45], 204 | g_tfchud3_spr, 205 | [0,0/256], 206 | [170/256,45/256], 207 | hud_col, 208 | a, 209 | DRAWFLAG_ADDITIVE 210 | ); 211 | } 212 | #endif 213 | } 214 | 215 | int 216 | w_flamer_isempty(player pl) 217 | { 218 | 219 | if (pl.m_iAmmoCells <= 0) 220 | return 1; 221 | 222 | return 0; 223 | } 224 | 225 | weapontype_t 226 | w_flamer_type(player pl) 227 | { 228 | return WPNTYPE_RANGED; 229 | } 230 | 231 | weapon_t w_flamer = 232 | { 233 | .name = "flamer", 234 | .id = ITEM_FLAMER, 235 | .slot = 3, 236 | .slot_pos = 2, 237 | .weight = WEIGHT_FLAMER, 238 | .draw = w_flamer_draw, 239 | .holster = __NULL__, 240 | .primary = w_flamer_primary, 241 | .secondary = w_flamer_release, 242 | .reload = __NULL__, 243 | .release = w_flamer_release, 244 | .postdraw = w_flamer_crosshair, 245 | .precache = w_flamer_precache, 246 | .pickup = w_flamer_pickup, 247 | .updateammo = w_flamer_updateammo, 248 | .wmodel = w_flamer_wmodel, 249 | .pmodel = w_flamer_pmodel, 250 | .deathmsg = w_flamer_deathmsg, 251 | .aimanim = w_flamer_aimanim, 252 | .isempty = w_flamer_isempty, 253 | .type = w_flamer_type, 254 | .hudpic = w_flamer_hudpic 255 | }; 256 | -------------------------------------------------------------------------------- /src/shared/w_grapple.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2020 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | void 18 | w_grapple_precache(void) 19 | { 20 | precache_model("models/v_grapple.mdl"); 21 | precache_model("models/w_grapple.mdl"); 22 | precache_model("models/p_grapple.mdl"); 23 | } 24 | 25 | void 26 | w_grapple_updateammo(player pl) 27 | { 28 | #ifdef SERVER 29 | Weapons_UpdateAmmo(pl, __NULL__, __NULL__, __NULL__); 30 | #endif 31 | } 32 | 33 | string 34 | w_grapple_wmodel(void) 35 | { 36 | return "models/w_grapple.mdl"; 37 | } 38 | string 39 | w_grapple_pmodel(player pl) 40 | { 41 | return "models/p_grapple.mdl"; 42 | } 43 | 44 | string 45 | w_grapple_deathmsg(void) 46 | { 47 | return "%s was assaulted by %s's Assault Cannon."; 48 | } 49 | 50 | void 51 | w_grapple_draw(player pl) 52 | { 53 | Weapons_SetModel("models/v_grapple.mdl"); 54 | Weapons_ViewAnimation(pl, 0); 55 | } 56 | 57 | float 58 | w_grapple_aimanim(player pl) 59 | { 60 | return pl.flags & FL_CROUCHING ? ANIM_CR_AIMCROWBAR : ANIM_AIMCROWBAR; 61 | } 62 | 63 | void 64 | w_grapple_hudpic(player pl, int selected, vector pos, float a) 65 | { 66 | #ifdef CLIENT 67 | if (selected) { 68 | drawsubpic( 69 | pos, 70 | [170,45], 71 | g_tfchud4_spr, 72 | [0,0], 73 | [170/256,45/256], 74 | g_hud_color, 75 | a, 76 | DRAWFLAG_ADDITIVE 77 | ); 78 | } else { 79 | drawsubpic( 80 | pos, 81 | [170,45], 82 | g_tfchud1_spr, 83 | [0,0], 84 | [170/256,45/256], 85 | g_hud_color, 86 | a, 87 | DRAWFLAG_ADDITIVE 88 | ); 89 | } 90 | #endif 91 | } 92 | 93 | weapon_t w_grapple = 94 | { 95 | .name = "grapple", 96 | .id = ITEM_GRAPPLE, 97 | .slot = 5, 98 | .slot_pos = 0, 99 | .weight = WEIGHT_GRAPPLE, 100 | .draw = w_grapple_draw, 101 | .holster = __NULL__, 102 | .primary = __NULL__, 103 | .secondary = __NULL__, 104 | .reload = __NULL__, 105 | .release = __NULL__, 106 | .postdraw = __NULL__, 107 | .precache = w_grapple_precache, 108 | .pickup = __NULL__, 109 | .updateammo = w_grapple_updateammo, 110 | .wmodel = w_grapple_wmodel, 111 | .pmodel = w_grapple_pmodel, 112 | .deathmsg = w_grapple_deathmsg, 113 | .aimanim = w_grapple_aimanim, 114 | .hudpic = w_grapple_hudpic, 115 | .isempty = w_asscan_isempty 116 | }; 117 | -------------------------------------------------------------------------------- /src/shared/w_incendiary.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2023 Marco Cawthorne 3 | * Copyright (c) 2023 Gethyn ThomasQuail 4 | * 5 | * Permission to use, copy, modify, and distribute this software for any 6 | * purpose with or without fee is hereby granted, provided that the above 7 | * copyright notice and this permission notice appear in all copies. 8 | * 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 14 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 15 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | */ 17 | 18 | #define TFC_RPG_ROCKET_SPEED 900.0f 19 | 20 | enum 21 | { 22 | INC_IDLE1, 23 | INC_FIDGET1, 24 | INC_FIRE, 25 | INC_HOLSTER1, 26 | INC_DRAW1, 27 | INC_HOLSTER2, 28 | INC_DRAW2, 29 | INC_RELOAD_START, 30 | INC_RELOAD, 31 | INC_RELOAD_END, 32 | INC_IDLE2, 33 | INC_FIDGET2 34 | }; 35 | 36 | void 37 | w_incendiary_precache(void) 38 | { 39 | precache_model("models/v_tfc_rpg.mdl"); 40 | precache_model("models/w_incendiary.mdl"); 41 | precache_model("models/p_incendiary.mdl"); 42 | Sound_Precache("weapon_incendiary.fire"); 43 | } 44 | 45 | void 46 | w_incendiary_updateammo(player pl) 47 | { 48 | Weapons_UpdateAmmo(pl, __NULL__, pl.m_iAmmoRockets, __NULL__); 49 | } 50 | 51 | string 52 | w_incendiary_wmodel(void) 53 | { 54 | return "models/w_incendiary.mdl"; 55 | } 56 | string 57 | w_incendiary_pmodel(player pl) 58 | { 59 | return "models/p_rpg2.mdl"; 60 | } 61 | 62 | string 63 | w_incendiary_deathmsg(void) 64 | { 65 | return "%s gets well done by %s's incendiary rocket."; 66 | 67 | // TODO 68 | // Has special birthday and suicide death messages 69 | } 70 | 71 | void 72 | w_incendiary_draw(player pl) 73 | { 74 | Weapons_SetModel("models/v_tfc_rpg.mdl"); 75 | Weapons_ViewAnimation(pl, 0); 76 | } 77 | 78 | void 79 | w_incendiary_shootrocket(player pl) 80 | { 81 | static void w_incendiary_shootrocket_touch(void) { 82 | pointparticles(particleeffectnum("fx_explosion.main"), self.origin, [0,0,0], 1); 83 | remove(self); 84 | } 85 | 86 | Weapons_MakeVectors(pl); 87 | entity p = spawn(); 88 | setmodel(p, "models/rpgrocket.mdl"); 89 | setorigin(p, Weapons_GetCameraPos(pl) + (v_forward * 8)); 90 | p.owner = self; 91 | p.movetype = MOVETYPE_FLYMISSILE; 92 | p.solid = SOLID_BBOX; 93 | p.gravity = 0.5f; 94 | p.velocity = (v_forward * TFC_RPG_ROCKET_SPEED); 95 | p.angles = vectoangles(p.velocity); 96 | p.touch = w_incendiary_shootrocket_touch; 97 | p.think = Util_Destroy; 98 | p.nextthink = time + 5.0f; 99 | } 100 | 101 | void 102 | w_incendiary_primary(player pl) 103 | { 104 | int s = w_baseprojectile_fire(pl, WEAPON_INCENDIARY, player::m_iAmmoRockets, w_incendiary_shootrocket); 105 | 106 | switch (s) { 107 | case AUTO_FIRE_FAILED: 108 | return; 109 | break; 110 | case AUTO_FIRED: 111 | case AUTO_LAST: 112 | Weapons_ViewAnimation(pl, INC_FIRE); 113 | Weapons_Sound(pl, CHAN_WEAPON, "weapon_incendiary.fire"); 114 | Weapons_ViewPunchAngle(pl, [-2,0,0]); 115 | 116 | if (pl.flags & FL_CROUCHING) 117 | Animation_PlayerTop(pl, TFCANIM_CR_SHOOTRPG, 0.45f); 118 | else 119 | Animation_PlayerTop(pl, TFCANIM_SHOOTRPG, 0.45f); 120 | 121 | pl.w_attack_next = 0.8f; 122 | break; 123 | case AUTO_EMPTY: 124 | pl.w_attack_next = 0.2f; 125 | break; 126 | } 127 | 128 | pl.w_idle_next = 1.5f; 129 | } 130 | 131 | float 132 | w_incendiary_aimanim(player pl) 133 | { 134 | return pl.flags & FL_CROUCHING ? TFCANIM_CR_AIMRPG : TFCANIM_AIMRPG; 135 | } 136 | 137 | void 138 | w_incendiary_postdraw(player pl) 139 | { 140 | #ifdef CLIENT 141 | // crosshair 142 | Cross_DrawSub(g_cross_spr, [24,24], [24/128,48/128], [0.1875, 0.1875]); 143 | // ammo counter 144 | HUD_DrawAmmo2(); 145 | vector aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42]; 146 | drawsubpic(aicon_pos, [24,24], g_hud7_spr, [120/256,72/128],[24/256, 24/128], g_hud_color, pSeatLocal->m_flAmmo2Alpha, DRAWFLAG_ADDITIVE); 147 | #endif 148 | } 149 | 150 | void 151 | w_incendiary_hudpic(player pl, int selected, vector pos, float a) 152 | { 153 | #ifdef CLIENT 154 | if (selected) { 155 | drawsubpic( 156 | pos, 157 | [170,45], 158 | g_tfchud5_spr, 159 | [0,90/256], 160 | [170/256,45/256], 161 | g_hud_color, 162 | a, 163 | DRAWFLAG_ADDITIVE 164 | ); 165 | } else { 166 | drawsubpic( 167 | pos, 168 | [170,45], 169 | g_tfchud6_spr, 170 | [0,0], 171 | [170/256,45/256], 172 | g_hud_color, 173 | a, 174 | DRAWFLAG_ADDITIVE 175 | ); 176 | } 177 | #endif 178 | } 179 | 180 | weapon_t w_incendiary = 181 | { 182 | .name = "incendiary", 183 | .id = ITEM_INCENDIARY, 184 | .slot = 4, 185 | .slot_pos = 3, 186 | .weight = WEIGHT_INCENDIARY, 187 | .draw = w_incendiary_draw, 188 | .holster = __NULL__, 189 | .primary = w_incendiary_primary, 190 | .secondary = __NULL__, 191 | .reload = __NULL__, 192 | .release = __NULL__, 193 | .postdraw = w_incendiary_postdraw, 194 | .precache = w_incendiary_precache, 195 | .pickup = __NULL__, 196 | .updateammo = w_incendiary_updateammo, 197 | .wmodel = w_incendiary_wmodel, 198 | .pmodel = w_incendiary_pmodel, 199 | .deathmsg = w_incendiary_deathmsg, 200 | .aimanim = w_incendiary_aimanim, 201 | .hudpic = w_incendiary_hudpic, 202 | .isempty = w_asscan_isempty 203 | }; 204 | -------------------------------------------------------------------------------- /src/shared/w_knife.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2023 Marco Cawthorne 3 | * Copyright (c) 2023 Gethyn ThomasQuail 4 | * 5 | * Permission to use, copy, modify, and distribute this software for any 6 | * purpose with or without fee is hereby granted, provided that the above 7 | * copyright notice and this permission notice appear in all copies. 8 | * 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 14 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 15 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | */ 17 | 18 | enum 19 | { 20 | KNIFE_IDLE, 21 | KNIFE_IDLE2, 22 | KNIFE_SLASH, 23 | KNIFE_STAB, 24 | KNIFE_DRAW, 25 | KNIFE_HOLSTER 26 | }; 27 | 28 | void 29 | w_knife_precache(void) 30 | { 31 | Sound_Precache("weapon_crowbar.hit"); 32 | Sound_Precache("weapon_crowbar.miss"); 33 | Sound_Precache("weapon_crowbar.hitbody"); 34 | precache_model("models/v_tfc_knife.mdl"); 35 | precache_model("models/w_knife.mdl"); 36 | precache_model("models/p_knife.mdl"); 37 | } 38 | 39 | void 40 | w_knife_updateammo(player pl) 41 | { 42 | #ifdef SERVER 43 | Weapons_UpdateAmmo(pl, __NULL__, __NULL__, __NULL__); 44 | #endif 45 | } 46 | 47 | string 48 | w_knife_wmodel(void) 49 | { 50 | return "models/w_knife.mdl"; 51 | } 52 | string 53 | w_knife_pmodel(player pl) 54 | { 55 | return "models/p_knife.mdl"; 56 | } 57 | 58 | string 59 | w_knife_deathmsg(void) 60 | { 61 | return "%s was assaulted by %s's Assault Cannon."; 62 | } 63 | 64 | void 65 | w_knife_draw(player pl) 66 | { 67 | Weapons_SetModel("models/v_tfc_knife.mdl"); 68 | Weapons_ViewAnimation(pl, KNIFE_DRAW); 69 | } 70 | 71 | void 72 | w_knife_holster(player pl) 73 | { 74 | Weapons_ViewAnimation(pl, KNIFE_HOLSTER); 75 | } 76 | 77 | void 78 | w_knife_primary(player pl) 79 | { 80 | int anim = 0; 81 | vector src; 82 | 83 | if (pl.w_attack_next) { 84 | return; 85 | } 86 | 87 | Weapons_MakeVectors(pl); 88 | src = pl.origin + pl.view_ofs; 89 | 90 | /* make sure we can gib corpses */ 91 | int oldhitcontents = self.hitcontentsmaski; 92 | self.hitcontentsmaski = CONTENTBITS_POINTSOLID | CONTENTBIT_CORPSE; 93 | traceline(src, src + (v_forward * 32), FALSE, pl); 94 | self.hitcontentsmaski = oldhitcontents; 95 | 96 | pl.w_attack_next = 0.4f; 97 | 98 | pl.w_idle_next = 2.5f; 99 | 100 | Weapons_ViewAnimation(pl, KNIFE_SLASH); 101 | 102 | if (pl.flags & FL_CROUCHING) 103 | Animation_PlayerTop(pl, ANIM_CR_SHOOTCROWBAR, 0.41f); 104 | else 105 | Animation_PlayerTop(pl, ANIM_SHOOTCROWBAR, 0.5f); 106 | 107 | Weapons_Sound(pl, CHAN_WEAPON, "weapon_crowbar.miss"); 108 | 109 | #ifdef SERVER 110 | 111 | if (trace_fraction >= 1.0) { 112 | return; 113 | } 114 | 115 | /* don't bother with decals, we got squibs */ 116 | if (trace_ent.iBleeds) { 117 | FX_Blood(trace_endpos, [1,0,0]); 118 | } else { 119 | SurfData_Impact(trace_ent, trace_endpos, trace_plane_normal); 120 | } 121 | 122 | // Backstab detection 123 | if (trace_ent.takedamage) { 124 | int damage = 36; 125 | damageType_t dmgtype = DMG_BLUNT; 126 | 127 | if (trace_ent.classname == "player") { 128 | player otherpl = (player) trace_ent; 129 | if (otherpl.IsFacing(pl) == false) { 130 | damage = 500; 131 | dmgtype = DMG_CRUSH; 132 | } 133 | } 134 | Damage_Apply(trace_ent, pl, damage, WEAPON_KNIFE, dmgtype); 135 | if (trace_ent.iBleeds) { 136 | Weapons_Sound(pl, CHAN_WEAPON, "weapon_crowbar.hitbody"); 137 | } else { 138 | Weapons_Sound(pl, CHAN_WEAPON, "weapon_crowbar.hit"); 139 | } 140 | } 141 | #endif 142 | } 143 | 144 | float 145 | w_knife_aimanim(player pl) 146 | { 147 | return pl.flags & FL_CROUCHING ? ANIM_CR_AIMCROWBAR : ANIM_AIMCROWBAR; 148 | } 149 | 150 | void 151 | w_knife_hudpic(player pl, int selected, vector pos, float a) 152 | { 153 | #ifdef CLIENT 154 | if (selected) { 155 | drawsubpic( 156 | pos, 157 | [170,45], 158 | g_tfchud4_spr, 159 | [0,135/256], 160 | [170/256,45/256], 161 | g_hud_color, 162 | a, 163 | DRAWFLAG_ADDITIVE 164 | ); 165 | } else { 166 | drawsubpic( 167 | pos, 168 | [170,45], 169 | g_tfchud3_spr, 170 | [0,90/256], 171 | [170/256,45/256], 172 | g_hud_color, 173 | a, 174 | DRAWFLAG_ADDITIVE 175 | ); 176 | } 177 | #endif 178 | } 179 | 180 | weapon_t w_knife = 181 | { 182 | .name = "knife", 183 | .id = ITEM_KNIFE, 184 | .slot = 0, 185 | .slot_pos = 2, 186 | .weight = WEIGHT_KNIFE, 187 | .draw = w_knife_draw, 188 | .holster = w_knife_holster, 189 | .primary = w_knife_primary, 190 | .secondary = __NULL__, 191 | .reload = __NULL__, 192 | .release = __NULL__, 193 | .postdraw = __NULL__, 194 | .precache = w_knife_precache, 195 | .pickup = __NULL__, 196 | .updateammo = w_knife_updateammo, 197 | .wmodel = w_knife_wmodel, 198 | .pmodel = w_knife_pmodel, 199 | .deathmsg = w_knife_deathmsg, 200 | .aimanim = w_knife_aimanim, 201 | .hudpic = w_knife_hudpic, 202 | .isempty = w_asscan_isempty 203 | }; 204 | -------------------------------------------------------------------------------- /src/shared/w_medkit.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2023 Marco Cawthorne 3 | * Copyright (c) 2023 Gethyn ThomasQuail 4 | * 5 | * Permission to use, copy, modify, and distribute this software for any 6 | * purpose with or without fee is hereby granted, provided that the above 7 | * copyright notice and this permission notice appear in all copies. 8 | * 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 14 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 15 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | */ 17 | enum 18 | { 19 | MEDKIT_IDLE1, 20 | MEDKIT_IDLE2, 21 | MEDKIT_USE, 22 | MEDKIT_UNUSED, 23 | MEDKIT_HOLSTER, 24 | MEDKIT_DRAW 25 | }; 26 | 27 | void 28 | w_medkit_precache(void) 29 | { 30 | precache_model("models/v_tfc_medkit.mdl"); 31 | precache_model("models/w_medkit.mdl"); 32 | precache_model("models/p_medkit.mdl"); 33 | } 34 | 35 | void 36 | w_medkit_updateammo(player pl) 37 | { 38 | #ifdef SERVER 39 | Weapons_UpdateAmmo(pl, __NULL__, __NULL__, __NULL__); 40 | #endif 41 | } 42 | 43 | string 44 | w_medkit_wmodel(void) 45 | { 46 | return "models/w_medkit.mdl"; 47 | } 48 | string 49 | w_medkit_pmodel(player pl) 50 | { 51 | return "models/p_medkit.mdl"; 52 | } 53 | 54 | string 55 | w_medkit_deathmsg(void) 56 | { 57 | return "%s was assaulted by %s's Assault Cannon."; 58 | } 59 | 60 | void 61 | w_medkit_draw(player pl) 62 | { 63 | Weapons_SetModel("models/v_tfc_medkit.mdl"); 64 | Weapons_ViewAnimation(pl, 0); 65 | } 66 | 67 | void 68 | w_medkit_primary(player pl) 69 | { 70 | vector src; 71 | 72 | if (pl.w_attack_next > 0.0) 73 | return; 74 | 75 | // cast our traceline 76 | Weapons_MakeVectors(pl); 77 | src = pl.origin + pl.view_ofs; 78 | 79 | traceline(src, src + (v_forward * 64), FALSE, pl); 80 | 81 | Weapons_ViewAnimation(pl, MEDKIT_USE); 82 | 83 | if (pl.flags & FL_CROUCHING) 84 | Animation_PlayerTop(pl, TFCANIM_CR_SHOOTMEDKIT, 0.45f); 85 | else 86 | Animation_PlayerTop(pl, TFCANIM_SHOOTMEDKIT, 0.45f); 87 | 88 | if (trace_ent.classname == "player") { 89 | player otherpl = (player) trace_ent; 90 | 91 | #ifdef SERVER 92 | if (otherpl.GetTeam() == pl.GetTeam()) { 93 | /* Don't give the player more than 100% health */ 94 | if (otherpl.health < otherpl.m_iMaxHealth) { 95 | /* We want to only give health to our teammate & skip armor */ 96 | otherpl.health = bound(0, otherpl.health + 15, otherpl.m_iMaxHealth); 97 | } 98 | } else { 99 | /* Poison the enemey */ 100 | // TODO 101 | // Needs to last for 10+ seconds and spread to others 102 | Damage_Apply(otherpl, pl, 15, WEAPON_MEDKIT, DMG_GENERIC); 103 | } 104 | Weapons_Sound(pl, CHAN_WEAPON, "weapon_medkit.heal"); 105 | #endif 106 | } 107 | pl.w_attack_next = 0.4f; 108 | pl.w_idle_next = 5.0f; 109 | } 110 | 111 | void 112 | w_medkit_release(player pl) 113 | { 114 | 115 | if (pl.w_idle_next > 0.0) 116 | return; 117 | 118 | int r = (float)input_sequence % 2; 119 | switch (r) { 120 | case 0: 121 | Weapons_ViewAnimation(pl, MEDKIT_IDLE1); 122 | pl.w_idle_next = 1.16f; 123 | break; 124 | default: 125 | Weapons_ViewAnimation(pl, MEDKIT_IDLE2); 126 | pl.w_idle_next = 2.36f; 127 | break; 128 | } 129 | } 130 | 131 | float 132 | w_medkit_aimanim(player pl) 133 | { 134 | return pl.flags & FL_CROUCHING ? TFCANIM_CR_AIMMEDKIT : TFCANIM_AIMMEDKIT; 135 | } 136 | 137 | void 138 | w_medkit_hudpic(player pl, int selected, vector pos, float a) 139 | { 140 | #ifdef CLIENT 141 | if (selected) { 142 | drawsubpic( 143 | pos, 144 | [170,45], 145 | g_tfchud5_spr, 146 | [0,180/256], 147 | [170/256,45/256], 148 | g_hud_color, 149 | a, 150 | DRAWFLAG_ADDITIVE 151 | ); 152 | } else { 153 | drawsubpic( 154 | pos, 155 | [170,45], 156 | g_tfchud6_spr, 157 | [0,90/256], 158 | [170/256,45/256], 159 | g_hud_color, 160 | a, 161 | DRAWFLAG_ADDITIVE 162 | ); 163 | } 164 | #endif 165 | } 166 | 167 | weapon_t w_medkit = 168 | { 169 | .name = "medkit", 170 | .id = ITEM_MEDKIT, 171 | .slot = 0, 172 | .slot_pos = 1, 173 | .weight = WEIGHT_MEDKIT, 174 | .draw = w_medkit_draw, 175 | .holster = __NULL__, 176 | .primary = w_medkit_primary, 177 | .secondary = __NULL__, 178 | .reload = __NULL__, 179 | .release = w_medkit_release, 180 | .postdraw = __NULL__, 181 | .precache = w_medkit_precache, 182 | .pickup = __NULL__, 183 | .updateammo = w_medkit_updateammo, 184 | .wmodel = w_medkit_wmodel, 185 | .pmodel = w_medkit_pmodel, 186 | .deathmsg = w_medkit_deathmsg, 187 | .aimanim = w_medkit_aimanim, 188 | .hudpic = w_medkit_hudpic, 189 | .isempty = w_asscan_isempty 190 | }; 191 | -------------------------------------------------------------------------------- /src/shared/w_nailgun.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2024 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | enum 18 | { 19 | NAILGUN_IDLE, 20 | NAILGUN_FIDGET1, 21 | NAILGUN_UNUSED1, 22 | NAILGUN_UNUSED2, 23 | NAILGUN_DEPLOY, 24 | NAILGUN_SHOOT1, 25 | NAILGUN_SHOOT2, 26 | NAILGUN_SHOOT3, 27 | }; 28 | 29 | void 30 | w_nailgun_precache(void) 31 | { 32 | precache_model("models/v_tfc_nailgun.mdl"); 33 | precache_model("models/w_nailgun.mdl"); 34 | precache_model("models/p_nailgun.mdl"); 35 | precache_model("models/nail.mdl"); 36 | Sound_Precache("weapon_nailgun.fire"); 37 | } 38 | 39 | void 40 | w_nailgun_updateammo(player pl) 41 | { 42 | Weapons_UpdateAmmo(pl, __NULL__, pl.m_iAmmoNails, __NULL__); 43 | } 44 | 45 | string 46 | w_nailgun_wmodel(void) 47 | { 48 | return "models/w_nailgun.mdl"; 49 | } 50 | string 51 | w_nailgun_pmodel(player pl) 52 | { 53 | return "models/p_nailgun2.mdl"; 54 | } 55 | 56 | string 57 | w_nailgun_deathmsg(void) 58 | { 59 | return "%s was assaulted by %s's Assault Cannon."; 60 | } 61 | 62 | void 63 | w_nailgun_draw(player pl) 64 | { 65 | Weapons_SetModel("models/v_tfc_nailgun.mdl"); 66 | Weapons_ViewAnimation(pl, NAILGUN_DEPLOY); 67 | } 68 | 69 | float 70 | w_nailgun_aimanim(player pl) 71 | { 72 | return pl.flags & FL_CROUCHING ? TFCANIM_CR_AIMMP5 : TFCANIM_AIMMP5; 73 | } 74 | 75 | void 76 | w_nailgun_shootnail(player pl) 77 | { 78 | static void w_rpg_shootrocket_touch(void) { 79 | #ifndef CLIENT 80 | /* impact per bullet */ 81 | if (trace_ent.iBleeds == 0) { 82 | DecalGroups_Place("Impact.Shot", trace_endpos + (v_forward * -2)); 83 | SurfData_Impact(trace_ent, trace_endpos, trace_plane_normal); 84 | } 85 | if (trace_ent.takedamage == DAMAGE_YES) { 86 | Damage_Apply(trace_ent, self.owner, 9, WEAPON_NAILGUN, DMG_BULLET); 87 | } 88 | #endif 89 | remove(self); 90 | } 91 | 92 | Weapons_MakeVectors(pl); 93 | entity p = spawn(); 94 | setmodel(p, "models/nail.mdl"); 95 | setorigin(p, Weapons_GetCameraPos(pl) + (v_forward * 14) + (v_up * -4) + (v_right * 2)); 96 | p.owner = self; 97 | p.movetype = MOVETYPE_FLYMISSILE; 98 | p.solid = SOLID_BBOX; 99 | p.gravity = 0.5f; 100 | p.velocity = (v_forward * 1000) + (v_up * 4) + (v_right * -2); 101 | p.angles = vectoangles(p.velocity); 102 | p.touch = w_rpg_shootrocket_touch; 103 | p.think = Util_Destroy; 104 | p.nextthink = time + 5.0f; 105 | } 106 | 107 | void 108 | w_nailgun_primary(player pl) 109 | { 110 | int s = w_baseprojectile_fire(pl, WEAPON_NAILGUN, player::m_iAmmoNails, w_nailgun_shootnail); 111 | 112 | switch (s) { 113 | case AUTO_FIRE_FAILED: 114 | return; 115 | break; 116 | case AUTO_FIRED: 117 | case AUTO_LAST: 118 | int r = (float)input_sequence % 3; 119 | if (r == 1) { 120 | Weapons_ViewAnimation(pl, NAILGUN_SHOOT1); 121 | } else if (r == 2) { 122 | Weapons_ViewAnimation(pl, NAILGUN_SHOOT2); 123 | } else { 124 | Weapons_ViewAnimation(pl, NAILGUN_SHOOT3); 125 | } 126 | Weapons_ViewAnimation(pl, NAILGUN_SHOOT2); 127 | Weapons_ViewPunchAngle(pl, [-1,0,0]); 128 | 129 | if (pl.flags & FL_CROUCHING) 130 | Animation_PlayerTop(pl, TFCANIM_CR_SHOOTMP5, 0.45f); 131 | else 132 | Animation_PlayerTop(pl, TFCANIM_SHOOTMP5, 0.45f); 133 | 134 | #ifdef CLIENT 135 | View_SetMuzzleflash(MUZZLE_RIFLE); 136 | #endif 137 | #ifndef CLIENT 138 | Sound_Play(pl, CHAN_WEAPON, "weapon_nailgun.fire"); 139 | #endif 140 | pl.w_attack_next = 0.1f; 141 | break; 142 | case AUTO_EMPTY: 143 | pl.w_attack_next = 0.2f; 144 | break; 145 | } 146 | 147 | pl.w_idle_next = 1.5f; 148 | } 149 | 150 | void 151 | w_nailgun_crosshair(player pl) 152 | { 153 | #ifdef CLIENT 154 | Cross_DrawSub(g_cross_spr, [24,24], [0.1875,0], [0.1875, 0.1875]); 155 | HUD_DrawAmmo2(); 156 | vector aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42]; 157 | drawsubpic(aicon_pos, [24,24], g_hud7_spr, [0,72/128],[24/256, 24/128], g_hud_color, pSeatLocal->m_flAmmo2Alpha, DRAWFLAG_ADDITIVE); 158 | #endif 159 | } 160 | 161 | void 162 | w_nailgun_hudpic(player pl, int selected, vector pos, float a) 163 | { 164 | #ifdef CLIENT 165 | if (selected) { 166 | drawsubpic( 167 | pos, 168 | [170,45], 169 | g_tfchud7_spr, 170 | [0,90/256], 171 | [170/256,45/256], 172 | g_hud_color, 173 | a, 174 | DRAWFLAG_ADDITIVE 175 | ); 176 | } else { 177 | drawsubpic( 178 | pos, 179 | [170,45], 180 | g_tfchud7_spr, 181 | [0,90/256], 182 | [170/256,45/256], 183 | g_hud_color, 184 | a, 185 | DRAWFLAG_ADDITIVE 186 | ); 187 | } 188 | #endif 189 | } 190 | 191 | weapon_t w_nailgun = 192 | { 193 | .name = "nailgun", 194 | .id = ITEM_NAILGUN, 195 | .slot = 3, 196 | .slot_pos = 0, 197 | .weight = WEIGHT_NAILGUN, 198 | .draw = w_nailgun_draw, 199 | .holster = __NULL__, 200 | .primary = w_nailgun_primary, 201 | .secondary = __NULL__, 202 | .reload = __NULL__, 203 | .release = __NULL__, 204 | .postdraw = w_nailgun_crosshair, 205 | .precache = w_nailgun_precache, 206 | .pickup = __NULL__, 207 | .updateammo = w_nailgun_updateammo, 208 | .wmodel = w_nailgun_wmodel, 209 | .pmodel = w_nailgun_pmodel, 210 | .deathmsg = w_nailgun_deathmsg, 211 | .aimanim = w_nailgun_aimanim, 212 | .hudpic = w_nailgun_hudpic, 213 | .isempty = w_asscan_isempty 214 | }; 215 | -------------------------------------------------------------------------------- /src/shared/w_railgun.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2023 Marco Cawthorne 3 | * Copyright (c) 2023 Gethyn ThomasQuail 4 | * 5 | * Permission to use, copy, modify, and distribute this software for any 6 | * purpose with or without fee is hereby granted, provided that the above 7 | * copyright notice and this permission notice appear in all copies. 8 | * 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 14 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 15 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | */ 17 | 18 | enum 19 | { 20 | RAILGUN_IDLE, 21 | RAILGUN_SHOOT, 22 | RAILGUN_DRAW, 23 | RAILGUN_HOLSTER, 24 | }; 25 | 26 | void 27 | w_railgun_precache(void) 28 | { 29 | precache_model("models/v_tfc_railgun.mdl"); 30 | precache_model("models/w_railgun.mdl"); 31 | precache_model("models/p_railgun.mdl"); 32 | Sound_Precache("weapon_railgun.fire"); 33 | } 34 | 35 | void 36 | w_railgun_updateammo(player pl) 37 | { 38 | Weapons_UpdateAmmo(pl, __NULL__, pl.m_iAmmoNails, __NULL__); 39 | } 40 | 41 | string 42 | w_railgun_wmodel(void) 43 | { 44 | return "models/w_railgun.mdl"; 45 | } 46 | string 47 | w_railgun_pmodel(player pl) 48 | { 49 | return "models/p_9mmhandgun.mdl"; 50 | } 51 | 52 | string 53 | w_railgun_deathmsg(void) 54 | { 55 | return "%s was assaulted by %s's railgun."; 56 | } 57 | 58 | void 59 | w_railgun_draw(player pl) 60 | { 61 | Weapons_SetModel("models/v_tfc_railgun.mdl"); 62 | Weapons_ViewAnimation(pl, RAILGUN_DRAW); 63 | } 64 | 65 | float 66 | w_railgun_aimanim(player pl) 67 | { 68 | return pl.flags & FL_CROUCHING ? TFCANIM_CR_AIM1HAND : TFCANIM_AIM1HAND; 69 | } 70 | 71 | void 72 | w_railgun_shootbeam(player pl) 73 | { 74 | #ifdef SERVER 75 | static void w_railgun_shootbeam_touch(void) { 76 | #ifndef CLIENT 77 | /* impact per bullet */ 78 | if (trace_ent.iBleeds == 0) { 79 | DecalGroups_Place("Impact.BigShot", trace_endpos + (v_forward * -2)); 80 | SurfData_Impact(trace_ent, trace_surfaceflagsi, trace_endpos, trace_plane_normal); 81 | } 82 | if (trace_ent.takedamage == DAMAGE_YES) { 83 | Damage_Apply(trace_ent, self.owner, 23, WEAPON_RAILGUN, DMG_BULLET); 84 | } 85 | #endif 86 | remove(self); 87 | } 88 | 89 | Weapons_MakeVectors(pl); 90 | entity p = spawn(); 91 | setmodel(p, "models/nail.mdl"); 92 | setorigin(p, Weapons_GetCameraPos(pl) + (v_forward * 14) + (v_up * -5) + (v_right * 3.5)); 93 | p.owner = self; 94 | p.movetype = MOVETYPE_FLYMISSILE; 95 | p.solid = SOLID_BBOX; 96 | p.gravity = 0.5f; 97 | p.velocity = (v_forward * 1000) + (v_up * 5) + (v_right * -3.5); 98 | p.angles = vectoangles(p.velocity); 99 | p.touch = w_railgun_shootbeam_touch; 100 | p.think = Util_Destroy; 101 | p.nextthink = time + 5.0f; 102 | p.alpha = 0.01f; 103 | p.traileffectnum = particleeffectnum("weapon_railgun.trail"); 104 | #endif 105 | } 106 | 107 | void 108 | w_railgun_primary(player pl) 109 | { 110 | int s = w_baseprojectile_fire(pl, WEAPON_RAILGUN, player::m_iAmmoNails, w_railgun_shootbeam); 111 | 112 | switch (s) { 113 | case AUTO_FIRE_FAILED: 114 | return; 115 | break; 116 | case AUTO_FIRED: 117 | case AUTO_LAST: 118 | int r = (float)input_sequence % 3; 119 | Weapons_ViewAnimation(pl, RAILGUN_SHOOT); 120 | Weapons_ViewPunchAngle(pl, [-1,0,0]); 121 | 122 | if (pl.flags & FL_CROUCHING) 123 | Animation_PlayerTop(pl, TFCANIM_CR_SHOOT1HAND, 0.45f); 124 | else 125 | Animation_PlayerTop(pl, TFCANIM_SHOOT1HAND, 0.45f); 126 | 127 | Weapons_Sound(pl, CHAN_WEAPON, "weapon_railgun.fire"); 128 | pl.w_attack_next = 0.4f; 129 | break; 130 | case AUTO_EMPTY: 131 | pl.w_attack_next = 0.2f; 132 | break; 133 | } 134 | 135 | pl.w_idle_next = 1.5f; 136 | } 137 | 138 | void 139 | w_railgun_postdraw(player pl) 140 | { 141 | #ifdef CLIENT 142 | // crosshair 143 | Cross_DrawSub(g_cross_spr, [24,24], [48/128,24/128], [0.1875, 0.1875]); 144 | // ammo counter 145 | HUD_DrawAmmo2(); 146 | vector aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42]; 147 | drawsubpic(aicon_pos, [24,24], g_hud7_spr, [0,72/128],[24/256, 24/128], g_hud_color, pSeatLocal->m_flAmmo2Alpha, DRAWFLAG_ADDITIVE); 148 | #endif 149 | } 150 | 151 | void 152 | w_railgun_hudpic(player pl, int selected, vector pos, float a) 153 | { 154 | #ifdef CLIENT 155 | if (selected) { 156 | drawsubpic( 157 | pos, 158 | [170,45], 159 | g_tfchud7_spr, 160 | [0,0], 161 | [170/256,45/256], 162 | g_hud_color, 163 | a, 164 | DRAWFLAG_ADDITIVE 165 | ); 166 | } else { 167 | drawsubpic( 168 | pos, 169 | [170,45], 170 | g_tfchud7_spr, 171 | [0,0], 172 | [170/256,45/256], 173 | g_hud_color, 174 | a, 175 | DRAWFLAG_ADDITIVE 176 | ); 177 | } 178 | #endif 179 | } 180 | 181 | weapon_t w_railgun = 182 | { 183 | .name = "railgun", 184 | .id = ITEM_RAILGUN, 185 | .slot = 1, 186 | .slot_pos = 3, 187 | .weight = WEIGHT_RAILGUN, 188 | .draw = w_railgun_draw, 189 | .holster = __NULL__, 190 | .primary = w_railgun_primary, 191 | .secondary = __NULL__, 192 | .reload = __NULL__, 193 | .release = __NULL__, 194 | .postdraw = w_railgun_postdraw, 195 | .precache = w_railgun_precache, 196 | .pickup = __NULL__, 197 | .updateammo = w_railgun_updateammo, 198 | .wmodel = w_railgun_wmodel, 199 | .pmodel = w_railgun_pmodel, 200 | .deathmsg = w_railgun_deathmsg, 201 | .aimanim = w_railgun_aimanim, 202 | .hudpic = w_railgun_hudpic, 203 | .isempty = w_asscan_isempty 204 | }; 205 | -------------------------------------------------------------------------------- /src/shared/w_rpg.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2020 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #define TFC_RPG_ROCKET_SPEED 900.0f 18 | 19 | enum 20 | { 21 | RPG_IDLE1, 22 | RPG_FIDGET1, 23 | RPG_FIRE, 24 | RPG_HOLSTER1, 25 | RPG_DRAW1, 26 | RPG_HOLSTER2, 27 | RPG_DRAW2, 28 | RPG_RELOAD_START, 29 | RPG_RELOAD, 30 | RPG_RELOAD_END, 31 | RPG_IDLE2, 32 | RPG_FIDGET2 33 | }; 34 | 35 | void 36 | w_rpg_precache(void) 37 | { 38 | precache_model("models/v_tfc_rpg.mdl"); 39 | precache_model("models/w_rpg.mdl"); 40 | precache_model("models/p_rpg.mdl"); 41 | precache_model("models/rpgrocket.mdl"); 42 | Sound_Precache("weapon_rpg.fire"); 43 | } 44 | 45 | int 46 | w_rpg_pickup(player pl, int new, int startammo) 47 | { 48 | #ifdef SERVER 49 | pl.mag_rpg = bound(0, pl.mag_rpg + 4, 4); 50 | #endif 51 | return (1); 52 | } 53 | 54 | void 55 | w_rpg_updateammo(player pl) 56 | { 57 | Weapons_UpdateAmmo(pl, pl.mag_rpg, pl.m_iAmmoRockets, __NULL__); 58 | } 59 | 60 | string 61 | w_rpg_wmodel(void) 62 | { 63 | return "models/w_rpg.mdl"; 64 | } 65 | 66 | string 67 | w_rpg_pmodel(player pl) 68 | { 69 | return "models/p_rpg.mdl"; 70 | } 71 | 72 | string 73 | w_rpg_deathmsg(void) 74 | { 75 | return "%s was assaulted by %s's Assault Cannon."; 76 | } 77 | 78 | void 79 | w_rpg_draw(player pl) 80 | { 81 | Weapons_SetModel("models/v_tfc_rpg.mdl"); 82 | Weapons_ViewAnimation(pl, 0); 83 | } 84 | 85 | void 86 | w_rpg_shootrocket(player pl) 87 | { 88 | static void w_rpg_shootrocket_touch(void) { 89 | pointparticles(particleeffectnum("fx_explosion.main"), self.origin, [0,0,0], 1); 90 | remove(self); 91 | } 92 | 93 | Weapons_MakeVectors(pl); 94 | entity p = spawn(); 95 | setmodel(p, "models/rpgrocket.mdl"); 96 | setorigin(p, Weapons_GetCameraPos(pl) + (v_forward * 8)); 97 | p.owner = self; 98 | p.movetype = MOVETYPE_FLYMISSILE; 99 | p.solid = SOLID_BBOX; 100 | p.gravity = 0.5f; 101 | p.velocity = (v_forward * TFC_RPG_ROCKET_SPEED); 102 | p.angles = vectoangles(p.velocity); 103 | p.touch = w_rpg_shootrocket_touch; 104 | p.think = Util_Destroy; 105 | p.nextthink = time + 5.0f; 106 | } 107 | 108 | void 109 | w_rpg_primary(player pl) 110 | { 111 | int s = w_baseprojectile_fire(pl, WEAPON_RPG, player::mag_rpg, w_rpg_shootrocket); 112 | 113 | switch (s) { 114 | case AUTO_FIRE_FAILED: 115 | return; 116 | break; 117 | case AUTO_LAST: 118 | case AUTO_FIRED: 119 | Weapons_ViewAnimation(pl, RPG_FIRE); 120 | Weapons_ViewPunchAngle(pl, [-2,0,0]); 121 | Weapons_Sound(pl, CHAN_WEAPON, "weapon_rpg.fire"); 122 | 123 | if (pl.flags & FL_CROUCHING) 124 | Animation_PlayerTop(pl, TFCANIM_CR_SHOOTRPG, 0.45f); 125 | else 126 | Animation_PlayerTop(pl, TFCANIM_SHOOTRPG, 0.45f); 127 | 128 | pl.w_attack_next = 0.8f; 129 | break; 130 | case AUTO_EMPTY: 131 | pl.w_attack_next = 0.2f; 132 | break; 133 | } 134 | 135 | pl.w_idle_next = 1.5f; 136 | } 137 | 138 | void 139 | w_rpg_reload(player pl) 140 | { 141 | w_baseshotgun_reload(player::mag_rpg, player::m_iAmmoRockets, 4); 142 | } 143 | 144 | void 145 | w_rpg_release(player pl) 146 | { 147 | int s = w_baseshotgun_release(player::mag_rpg, player::m_iAmmoRockets, 4); 148 | 149 | switch (s) { 150 | case SHOTGUN_IDLE: 151 | int r = (float)input_sequence % 3; 152 | if (r == 1) { 153 | Weapons_ViewAnimation(pl, RPG_IDLE1); 154 | } else if (r == 2) { 155 | Weapons_ViewAnimation(pl, RPG_FIDGET1); 156 | } else { 157 | Weapons_ViewAnimation(pl, RPG_FIDGET2); 158 | } 159 | pl.w_idle_next = 5.0f; 160 | break; 161 | case SHOTGUN_BUSY: 162 | break; 163 | case SHOTGUN_START_RELOAD: 164 | Weapons_ViewAnimation(pl, RPG_RELOAD_START); 165 | break; 166 | case SHOTGUN_RELOAD: 167 | Weapons_ViewAnimation(pl, RPG_RELOAD); 168 | break; 169 | case SHOTGUN_END_RELOAD: 170 | Weapons_ViewAnimation(pl, RPG_RELOAD_END); 171 | break; 172 | } 173 | } 174 | 175 | float 176 | w_rpg_aimanim(player pl) 177 | { 178 | return pl.flags & FL_CROUCHING ? TFCANIM_CR_AIMRPG : TFCANIM_AIMRPG; 179 | } 180 | 181 | void 182 | w_rpg_hud(player pl) 183 | { 184 | #ifdef CLIENT 185 | vector aicon_pos; 186 | 187 | Cross_DrawSub(g_cross_spr, [24,24], [24/128,48/128], [0.1875, 0.1875]); 188 | 189 | /* ammo counters */ 190 | HUD_DrawAmmo1(); 191 | HUD_DrawAmmo2(); 192 | 193 | /* ammo icon */ 194 | aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42]; 195 | drawsubpic( 196 | aicon_pos, 197 | [24,24], 198 | g_hud7_spr, 199 | [120/256,72/128], 200 | [24/256, 24/128], 201 | g_hud_color, 202 | pSeatLocal->m_flAmmo2Alpha, 203 | DRAWFLAG_ADDITIVE 204 | ); 205 | #endif 206 | } 207 | 208 | 209 | void 210 | w_rpg_hudpic(player pl, int selected, vector pos, float a) 211 | { 212 | #ifdef CLIENT 213 | if (selected) { 214 | drawsubpic(pos, [170,45], g_hud5_spr, [0,45/256], [170/256,45/256], g_hud_color, a, DRAWFLAG_ADDITIVE); 215 | } else { 216 | drawsubpic(pos, [170,45], g_hud2_spr, [0,45/256], [170/256,45/256], g_hud_color, a, DRAWFLAG_ADDITIVE); 217 | } 218 | #endif 219 | } 220 | 221 | weapon_t w_rpg = 222 | { 223 | .name = "rpg", 224 | .id = ITEM_RPG, 225 | .slot = 4, 226 | .slot_pos = 0, 227 | .weight = WEIGHT_RPG, 228 | .draw = w_rpg_draw, 229 | .holster = __NULL__, 230 | .primary = w_rpg_primary, 231 | .secondary = __NULL__, 232 | .reload = w_rpg_reload, 233 | .release = w_rpg_release, 234 | .postdraw = w_rpg_hud, 235 | .precache = w_rpg_precache, 236 | .pickup = w_rpg_pickup, 237 | .updateammo = w_rpg_updateammo, 238 | .wmodel = w_rpg_wmodel, 239 | .pmodel = w_rpg_pmodel, 240 | .deathmsg = w_rpg_deathmsg, 241 | .aimanim = w_rpg_aimanim, 242 | .hudpic = w_rpg_hudpic, 243 | .isempty = w_asscan_isempty 244 | }; 245 | -------------------------------------------------------------------------------- /src/shared/w_sbs.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2020 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | enum 18 | { 19 | SBS_IDLE1, 20 | SBS_FIRE1, 21 | SBS_FIRE2, 22 | SBS_ADDSHELL, 23 | SBS_PUMP, 24 | SBS_START_RELOAD, 25 | SBS_DRAW, 26 | SBS_HOLSTER, 27 | SBS_IDLE2, 28 | SBS_IDLE3 29 | }; 30 | 31 | void 32 | w_sbs_precache(void) 33 | { 34 | #ifdef SERVER 35 | Sound_Precache("weapon_sbs.cock"); 36 | Sound_Precache("weapon_sbs.fire"); 37 | Sound_Precache("weapon_sbs.reload"); 38 | #endif 39 | precache_model("models/v_tfc_12gauge.mdl"); 40 | precache_model("models/p_shotgun.mdl"); 41 | precache_sound("weapons/dbarrel1.wav"); 42 | } 43 | 44 | void 45 | w_sbs_updateammo(player pl) 46 | { 47 | Weapons_UpdateAmmo(pl, pl.mag_sbs, pl.m_iAmmoShells, __NULL__); 48 | } 49 | string w_sbs_wmodel(void) 50 | { 51 | return "models/ball.mdl"; 52 | } 53 | string w_sbs_pmodel(player pl) 54 | { 55 | return "models/p_shotgun.mdl"; 56 | } 57 | string w_sbs_deathmsg(void) 58 | { 59 | return ""; 60 | } 61 | 62 | int 63 | w_sbs_pickup(player pl, int new, int startammo) 64 | { 65 | #ifdef SERVER 66 | pl.mag_sbs = bound(0, pl.mag_sbs + 8, 8); 67 | #endif 68 | return (1); 69 | } 70 | 71 | void 72 | w_sbs_draw(player pl) 73 | { 74 | Weapons_SetModel("models/v_tfc_12gauge.mdl"); 75 | Weapons_ViewAnimation(pl, SBS_DRAW); 76 | } 77 | 78 | void 79 | w_sbs_holster(player pl) 80 | { 81 | Weapons_ViewAnimation(pl, SBS_HOLSTER); 82 | } 83 | 84 | void 85 | w_sbs_primary(player pl) 86 | { 87 | int s = w_baseshotgun_fire(WEAPON_SBS, player::mag_sbs, 6, 4, [0.04, 0.04, 0]); 88 | 89 | switch (s) { 90 | case AUTO_FIRE_FAILED: 91 | return; 92 | break; 93 | case AUTO_LAST: 94 | case AUTO_FIRED: 95 | #ifdef CLIENT 96 | View_SetMuzzleflash(MUZZLE_ROUND); 97 | #endif 98 | Weapons_ViewAnimation(pl, SBS_FIRE1); 99 | Weapons_ViewPunchAngle(pl, [-2,0,0]); 100 | 101 | if (pl.flags & FL_CROUCHING) 102 | Animation_PlayerTop(pl, TFCANIM_CR_SHOOTSHOTGUN, 0.45f); 103 | else 104 | Animation_PlayerTop(pl, TFCANIM_SHOOTSHOTGUN, 0.45f); 105 | 106 | Weapons_Sound(pl, CHAN_WEAPON, "weapon_sbs.fire"); 107 | pl.w_attack_next = 0.5f; 108 | break; 109 | case AUTO_EMPTY: 110 | Weapons_Sound(pl, CHAN_WEAPON, "weapon_sbs.fire_empty"); 111 | pl.w_attack_next = 0.2f; 112 | break; 113 | } 114 | 115 | pl.w_idle_next = 1.5f; 116 | } 117 | 118 | void 119 | w_sbs_reload(player pl) 120 | { 121 | w_baseshotgun_reload(player::mag_sbs, player::m_iAmmoShells, 8); 122 | } 123 | 124 | void 125 | w_sbs_release(player pl) 126 | { 127 | int s = w_baseshotgun_release(player::mag_sbs, player::m_iAmmoShells, 8); 128 | 129 | switch (s) { 130 | case SHOTGUN_IDLE: 131 | int r = (float)input_sequence % 3; 132 | if (r == 1) { 133 | Weapons_ViewAnimation(pl, SBS_IDLE1); 134 | } else if (r == 2) { 135 | Weapons_ViewAnimation(pl, SBS_IDLE2); 136 | } else { 137 | Weapons_ViewAnimation(pl, SBS_IDLE3); 138 | } 139 | pl.w_idle_next = 5.0f; 140 | break; 141 | case SHOTGUN_BUSY: 142 | break; 143 | case SHOTGUN_START_RELOAD: 144 | Weapons_ViewAnimation(pl, SBS_START_RELOAD); 145 | break; 146 | case SHOTGUN_RELOAD: 147 | Weapons_ViewAnimation(pl, SBS_ADDSHELL); 148 | Weapons_Sound(pl, CHAN_WEAPON, "weapon_sbs.reload"); 149 | break; 150 | case SHOTGUN_END_RELOAD: 151 | Weapons_ViewAnimation(pl, SBS_PUMP); 152 | Weapons_Sound(pl, CHAN_WEAPON, "weapon_sbs.cock"); 153 | break; 154 | } 155 | } 156 | 157 | void 158 | w_sbs_crosshair(player pl) 159 | { 160 | #ifdef CLIENT 161 | Cross_DrawSub(g_cross_spr, [24,24], [48/128,24/128], [0.1875, 0.1875]); 162 | HUD_DrawAmmo1(); 163 | HUD_DrawAmmo2(); 164 | vector aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42]; 165 | drawsubpic(aicon_pos, [24,24], "sprites/640hud7.spr_0.tga", [72/256,72/128], [24/256, 24/128], g_hud_color, pSeatLocal->m_flAmmo2Alpha, DRAWFLAG_ADDITIVE); 166 | #endif 167 | } 168 | 169 | float 170 | w_sbs_aimanim(player pl) 171 | { 172 | return pl.flags & FL_CROUCHING ? ANIM_CR_AIMSHOTGUN : ANIM_AIMSHOTGUN; 173 | } 174 | 175 | void 176 | w_sbs_hudpic(player pl, int s, vector pos, float a) 177 | { 178 | #ifdef CLIENT 179 | if (s) { 180 | drawsubpic(pos, [170,45], g_tfchud2_spr, [0,180/256], [170/256,45/256], g_hud_color, a, DRAWFLAG_ADDITIVE); 181 | } else { 182 | drawsubpic(pos, [170,45], g_tfchud1_spr, [0,180/256], [170/256,45/256], g_hud_color, a, DRAWFLAG_ADDITIVE); 183 | } 184 | #endif 185 | } 186 | 187 | weapon_t w_sbs = 188 | { 189 | .name = "sbs", 190 | .id = ITEM_SBS, 191 | .slot = 1, 192 | .slot_pos = 0, 193 | .weight = WEIGHT_SBS, 194 | .draw = w_sbs_draw, 195 | .holster = w_sbs_holster, 196 | .primary = w_sbs_primary, 197 | .secondary = w_sbs_release, 198 | .reload = w_sbs_reload, 199 | .release = w_sbs_release, 200 | .postdraw = w_sbs_crosshair, 201 | .precache = w_sbs_precache, 202 | .pickup = w_sbs_pickup, 203 | .updateammo = w_sbs_updateammo, 204 | .wmodel = w_sbs_wmodel, 205 | .pmodel = w_sbs_pmodel, 206 | .deathmsg = w_sbs_deathmsg, 207 | .aimanim = w_sbs_aimanim, 208 | .hudpic = w_sbs_hudpic, 209 | .isempty = w_asscan_isempty 210 | }; 211 | -------------------------------------------------------------------------------- /src/shared/w_sniper.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2020 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | enum 18 | { 19 | SNIPER_IDLE, 20 | SNIPER_AIM, 21 | SNIPER_FIRE, 22 | SNIPER_DRAW, 23 | SNIPER_HOLSTER, 24 | SNIPER_AUTOIDLE, 25 | SNIPER_AUTOFIRE, 26 | SNIPER_AUTODRAW, 27 | SNIPER_AUTOHOLSTER, 28 | }; 29 | 30 | void 31 | w_sniper_precache(void) 32 | { 33 | precache_model("models/v_tfc_sniper.mdl"); 34 | precache_model("models/p_sniper.mdl"); 35 | Sound_Precache("weapon_sniper.fire"); 36 | } 37 | 38 | void 39 | w_sniper_updateammo(player pl) 40 | { 41 | Weapons_UpdateAmmo(pl, __NULL__, pl.m_iAmmoShells, __NULL__); 42 | } 43 | 44 | string 45 | w_sniper_wmodel(void) 46 | { 47 | return ""; 48 | } 49 | string 50 | w_sniper_pmodel(player pl) 51 | { 52 | return "models/p_sniper.mdl"; 53 | } 54 | 55 | string 56 | w_sniper_deathmsg(void) 57 | { 58 | return "%s was assaulted by %s's Assault Cannon."; 59 | } 60 | 61 | void 62 | w_sniper_draw(player pl) 63 | { 64 | Weapons_SetModel("models/v_tfc_sniper.mdl"); 65 | Weapons_ViewAnimation(pl, SNIPER_DRAW); 66 | pl.w_idle_next = 1.0f; 67 | } 68 | 69 | float 70 | w_sniper_aimanim(player pl) 71 | { 72 | return pl.flags & FL_CROUCHING ? TFCANIM_CR_AIMSNIPER : TFCANIM_AIMSNIPER; 73 | } 74 | 75 | void 76 | w_sniper_release(player pl) 77 | { 78 | if (pl.w_idle_next > 0.0) 79 | return; 80 | 81 | if (pl.mode_tempstate > 0) { 82 | float dmg = bound(75, (pl.mode_tempstate/2) * 75, 375); 83 | w_baseauto_fire(WEAPON_SNIPER, player::m_iAmmoShells, dmg, [0,0]); 84 | Weapons_ViewAnimation(pl, SNIPER_FIRE); 85 | 86 | if (pl.flags & FL_CROUCHING) 87 | Animation_PlayerTop(pl, TFCANIM_CR_SHOOTSNIPER, 0.45f); 88 | else 89 | Animation_PlayerTop(pl, TFCANIM_SHOOTSNIPER, 0.45f); 90 | 91 | #ifdef CLIENT 92 | View_SetMuzzleflash(MUZZLE_RIFLE); 93 | #endif 94 | Weapons_Sound(pl, CHAN_WEAPON, "weapon_sniper.fire"); 95 | pl.w_attack_next = 2.0f; 96 | pl.w_idle_next = 0.5f; 97 | pl.mode_tempstate = 0; 98 | } 99 | } 100 | 101 | void 102 | w_sniper_primary(player pl) 103 | { 104 | /* when moving, immediately release */ 105 | if (vlen(pl.velocity) > 0) { 106 | w_sniper_release(pl); 107 | return; 108 | } 109 | 110 | /* weapon speed check */ 111 | if (pl.w_attack_next > 0.0) 112 | return; 113 | 114 | /* if we aren't already, 'aim' down... */ 115 | 116 | pl.mode_tempstate += 1; 117 | pl.w_attack_next = 1.0f; 118 | 119 | if (pl.mode_tempstate == 0) { 120 | Weapons_ViewAnimation(pl, SNIPER_AIM); 121 | pl.w_idle_next = pl.w_attack_next; 122 | } 123 | } 124 | 125 | void 126 | w_sniper_secondary(player pl) 127 | { 128 | if (!(input_buttons & INPUT_BUTTON0)) { 129 | if (pl.mode_tempstate != 0) { 130 | w_sniper_release(pl); 131 | return; 132 | } 133 | } 134 | 135 | if (pl.w_idle_next > 0) { 136 | return; 137 | } 138 | 139 | /* Simple toggle of fovs */ 140 | if (pl.viewzoom == 1.0f) { 141 | pl.viewzoom = 0.2f; 142 | } else { 143 | pl.viewzoom = 1.0f; 144 | } 145 | 146 | pl.w_idle_next = 0.25f; 147 | } 148 | 149 | void 150 | w_sniper_postdraw(player pl) 151 | { 152 | #ifdef CLIENT 153 | Cross_DrawSub(g_cross_spr, [24,24], [72/128,0], [0.1875, 0.1875]); 154 | 155 | if (pl.mode_tempstate) { 156 | vector laser_pos; 157 | float lerp; 158 | vector jitter = [0.0f, 0.0f, 0.0f]; 159 | Weapons_MakeVectors(pl); 160 | vector src = pl.origin + pl.view_ofs; 161 | float a = bound(0.0, (pl.mode_tempstate / 10), 1.0) * 0.75; 162 | traceline(src, src + (v_forward * 256), FALSE, pl); 163 | lerp = Math_Lerp(32,16, trace_fraction); 164 | jitter[0] = (random(0,2) - 2) * (1 - trace_fraction); 165 | jitter[1] = (random(0,2) - 2) * (1 - trace_fraction); 166 | laser_pos = g_hudmins + (g_hudres / 2) + ([-lerp,-lerp] / 2); 167 | 168 | drawsubpic( 169 | laser_pos + jitter, 170 | [lerp,lerp], 171 | g_laser_spr, 172 | [0,0], 173 | [1.0, 1.0], 174 | [1,1,1] * (0.25 + a), 175 | 1.0, 176 | DRAWFLAG_ADDITIVE 177 | ); 178 | } 179 | 180 | // ammo counter 181 | HUD_DrawAmmo2(); 182 | vector aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42]; 183 | drawsubpic(aicon_pos, [24,24], g_hud7_spr, [72/256,72/128], [24/256, 24/128], g_hud_color, pSeatLocal->m_flAmmo2Alpha, DRAWFLAG_ADDITIVE); 184 | #endif 185 | } 186 | 187 | void 188 | w_sniper_hudpic(player pl, int selected, vector pos, float a) 189 | { 190 | #ifdef CLIENT 191 | if (selected) { 192 | drawsubpic( 193 | pos, 194 | [170,45], 195 | g_tfchud2_spr, 196 | [0,0], 197 | [170/256,45/256], 198 | g_hud_color, 199 | a, 200 | DRAWFLAG_ADDITIVE 201 | ); 202 | } else { 203 | drawsubpic( 204 | pos, 205 | [170,45], 206 | g_tfchud1_spr, 207 | [0,0], 208 | [170/256,45/256], 209 | g_hud_color, 210 | a, 211 | DRAWFLAG_ADDITIVE 212 | ); 213 | } 214 | #endif 215 | } 216 | 217 | weapon_t w_sniper = 218 | { 219 | .name = "sniper", 220 | .id = ITEM_SNIPER, 221 | .slot = 1, 222 | .slot_pos = 1, 223 | .weight = WEIGHT_SNIPER, 224 | .draw = w_sniper_draw, 225 | .holster = __NULL__, 226 | .primary = w_sniper_primary, 227 | .secondary = w_sniper_secondary, 228 | .reload = __NULL__, 229 | .release = w_sniper_release, 230 | .postdraw = w_sniper_postdraw, 231 | .precache = w_sniper_precache, 232 | .pickup = __NULL__, 233 | .updateammo = w_sniper_updateammo, 234 | .wmodel = __NULL__, 235 | .pmodel = w_sniper_pmodel, 236 | .deathmsg = w_sniper_deathmsg, 237 | .aimanim = w_sniper_aimanim, 238 | .hudpic = w_sniper_hudpic, 239 | .isempty = w_asscan_isempty 240 | }; 241 | -------------------------------------------------------------------------------- /src/shared/w_supernail.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2024 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | enum 18 | { 19 | NAILGUN_IDLE, 20 | NAILGUN_FIDGET1, 21 | NAILGUN_UNUSED1, 22 | NAILGUN_UNUSED2, 23 | NAILGUN_DEPLOY, 24 | NAILGUN_SHOOT1, 25 | NAILGUN_SHOOT2, 26 | NAILGUN_SHOOT3, 27 | }; 28 | 29 | void 30 | w_supernail_precache(void) 31 | { 32 | #ifdef CLIENT 33 | precache_model("models/v_tfc_supernailgun.mdl"); 34 | #else 35 | precache_model("models/w_supernail.mdl"); 36 | precache_model("models/p_supernail.mdl"); 37 | precache_model("models/nail.mdl"); 38 | Sound_Precache("weapon_nailgun.fire"); 39 | #endif 40 | } 41 | 42 | void 43 | w_supernail_updateammo(player pl) 44 | { 45 | Weapons_UpdateAmmo(pl, __NULL__, pl.m_iAmmoNails, __NULL__); 46 | } 47 | 48 | string 49 | w_supernail_wmodel(void) 50 | { 51 | return "models/p_snailgun2.mdl"; 52 | } 53 | string 54 | w_supernail_pmodel(player pl) 55 | { 56 | return "models/p_snailgun2.mdl"; 57 | } 58 | 59 | string 60 | w_supernail_deathmsg(void) 61 | { 62 | return "%s was assaulted by %s's Assault Cannon."; 63 | } 64 | 65 | void 66 | w_supernail_draw(player pl) 67 | { 68 | Weapons_SetModel("models/v_tfc_supernailgun.mdl"); 69 | Weapons_ViewAnimation(pl, NAILGUN_DEPLOY); 70 | } 71 | 72 | float 73 | w_supernail_aimanim(player pl) 74 | { 75 | return pl.flags & FL_CROUCHING ? TFCANIM_CR_AIMMP5 : TFCANIM_AIMMP5; 76 | } 77 | 78 | void 79 | w_supernail_shootnail(player pl) 80 | { 81 | static void w_rpg_shootrocket_touch(void) { 82 | #ifndef CLIENT 83 | /* impact per bullet */ 84 | if (trace_ent.iBleeds == 0) { 85 | DecalGroups_Place("Impact.BigShot", trace_endpos + (v_forward * -2)); 86 | SurfData_Impact(trace_ent, trace_endpos, trace_plane_normal); 87 | } 88 | if (trace_ent.takedamage == DAMAGE_YES) { 89 | Damage_Apply(trace_ent, self.owner, 14, WEAPON_NAILGUN, DMG_BULLET); 90 | } 91 | #endif 92 | remove(self); 93 | } 94 | 95 | Weapons_MakeVectors(pl); 96 | entity p = spawn(); 97 | setmodel(p, "models/nail.mdl"); 98 | setorigin(p, Weapons_GetCameraPos(pl) + (v_forward * 14) + (v_up * -4) + (v_right * 2)); 99 | p.owner = self; 100 | p.movetype = MOVETYPE_FLYMISSILE; 101 | p.solid = SOLID_BBOX; 102 | p.gravity = 0.5f; 103 | p.velocity = (v_forward * 1000) + (v_up * 4) + (v_right * -2); 104 | p.angles = vectoangles(p.velocity); 105 | p.touch = w_rpg_shootrocket_touch; 106 | p.think = Util_Destroy; 107 | p.nextthink = time + 5.0f; 108 | } 109 | 110 | void 111 | w_supernail_primary(player pl) 112 | { 113 | int s = w_baseprojectile_fire_num(pl, WEAPON_NAILGUN, player::m_iAmmoNails, w_supernail_shootnail, 2); 114 | 115 | switch (s) { 116 | case AUTO_FIRE_FAILED: 117 | return; 118 | break; 119 | case AUTO_FIRED: 120 | case AUTO_LAST: 121 | int r = (float)input_sequence % 3; 122 | if (r == 1) { 123 | Weapons_ViewAnimation(pl, NAILGUN_SHOOT1); 124 | } else if (r == 2) { 125 | Weapons_ViewAnimation(pl, NAILGUN_SHOOT2); 126 | } else { 127 | Weapons_ViewAnimation(pl, NAILGUN_SHOOT3); 128 | } 129 | Weapons_ViewAnimation(pl, NAILGUN_SHOOT2); 130 | Weapons_ViewPunchAngle(pl, [-1,0,0]); 131 | 132 | if (pl.flags & FL_CROUCHING) 133 | Animation_PlayerTop(pl, TFCANIM_CR_SHOOTMP5, 0.45f); 134 | else 135 | Animation_PlayerTop(pl, TFCANIM_SHOOTMP5, 0.45f); 136 | 137 | #ifdef CLIENT 138 | View_SetMuzzleflash(MUZZLE_RIFLE); 139 | #endif 140 | #ifndef CLIENT 141 | Sound_Play(pl, CHAN_WEAPON, "weapon_nailgun.fire"); 142 | #endif 143 | pl.w_attack_next = 0.1f; 144 | break; 145 | case AUTO_EMPTY: 146 | pl.w_attack_next = 0.2f; 147 | break; 148 | } 149 | 150 | pl.w_idle_next = 1.5f; 151 | } 152 | 153 | void 154 | w_supernail_hud(player pl) 155 | { 156 | #ifdef CLIENT 157 | vector aicon_pos; 158 | 159 | Cross_DrawSub(g_cross_spr, [24,24], [0.1875,0], [0.1875, 0.1875]); 160 | HUD_DrawAmmo2(); 161 | 162 | aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42]; 163 | drawsubpic( 164 | aicon_pos, 165 | [24,24], 166 | g_hud7_spr, 167 | [0,72/128], 168 | [24/256, 24/128], 169 | g_hud_color, 170 | pSeatLocal->m_flAmmo2Alpha, 171 | DRAWFLAG_ADDITIVE 172 | ); 173 | #endif 174 | } 175 | 176 | void 177 | w_supernail_hudpic(player pl, int selected, vector pos, float a) 178 | { 179 | #ifdef CLIENT 180 | if (selected) { 181 | drawsubpic( 182 | pos, 183 | [170,45], 184 | g_tfchud7_spr, 185 | [0,135/256], 186 | [170/256,45/256], 187 | g_hud_color, 188 | a, 189 | DRAWFLAG_ADDITIVE 190 | ); 191 | } else { 192 | drawsubpic( 193 | pos, 194 | [170,45], 195 | g_tfchud7_spr, 196 | [0,135/256], 197 | [170/256,45/256], 198 | g_hud_color, 199 | a, 200 | DRAWFLAG_ADDITIVE 201 | ); 202 | } 203 | #endif 204 | } 205 | 206 | weapon_t w_supernail = 207 | { 208 | .name = "supernail", 209 | .id = ITEM_SUPERNAIL, 210 | .slot = 3, 211 | .slot_pos = 2, 212 | .weight = WEIGHT_SUPERNAIL, 213 | .draw = w_supernail_draw, 214 | .holster = __NULL__, 215 | .primary = w_supernail_primary, 216 | .secondary = __NULL__, 217 | .reload = __NULL__, 218 | .release = __NULL__, 219 | .postdraw = w_supernail_hud, 220 | .precache = w_supernail_precache, 221 | .pickup = __NULL__, 222 | .updateammo = w_supernail_updateammo, 223 | .wmodel = w_supernail_wmodel, 224 | .pmodel = w_supernail_pmodel, 225 | .deathmsg = w_supernail_deathmsg, 226 | .aimanim = w_supernail_aimanim, 227 | .hudpic = w_supernail_hudpic, 228 | .isempty = w_asscan_isempty 229 | }; 230 | -------------------------------------------------------------------------------- /src/shared/w_tranquil.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2020 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | enum 18 | { 19 | TRANQUIL_IDLE1, 20 | TRANQUIL_IDLE2, 21 | TRANQUIL_IDLE3, 22 | TRANQUIL_SHOOT, 23 | TRANQUIL_SHOOT_EMPTY, 24 | TRANQUIL_RELOAD_EMPTY, 25 | TRANQUIL_RELOAD, 26 | TRANQUIL_DRAW, 27 | TRANQUIL_HOLSTER 28 | }; 29 | 30 | void 31 | w_tranquil_precache(void) 32 | { 33 | precache_model("models/v_tfc_pistol.mdl"); 34 | precache_model("models/w_tranquil.mdl"); 35 | precache_model("models/p_tranquil.mdl"); 36 | Sound_Precache("weapon_tranquilizer.fire"); 37 | } 38 | 39 | void 40 | w_tranquil_updateammo(player pl) 41 | { 42 | Weapons_UpdateAmmo(pl, __NULL__, pl.m_iAmmoShells, __NULL__); 43 | } 44 | 45 | string 46 | w_tranquil_wmodel(void) 47 | { 48 | return "models/w_tranquil.mdl"; 49 | } 50 | string 51 | w_tranquil_pmodel(player pl) 52 | { 53 | return "models/p_9mmhandgun2.mdl"; 54 | } 55 | 56 | string 57 | w_tranquil_deathmsg(void) 58 | { 59 | return "%s is put to sleep by %s."; 60 | } 61 | 62 | void 63 | w_tranquil_draw(player pl) 64 | { 65 | Weapons_SetModel("models/v_tfc_pistol.mdl"); 66 | Weapons_ViewAnimation(pl, TRANQUIL_DRAW); 67 | Weapons_SetGeomset("geomset 2 2\n"); 68 | } 69 | 70 | void 71 | w_tranquil_shootdart(player pl) 72 | { 73 | static void w_rpg_shootrocket_touch(void) { 74 | #ifndef CLIENT 75 | /* impact per bullet */ 76 | if (trace_ent.iBleeds == 0) { 77 | DecalGroups_Place("Impact.BigShot", trace_endpos + (v_forward * -2)); 78 | SurfData_Impact(trace_ent, trace_surfaceflagsi, trace_endpos, trace_plane_normal); 79 | } 80 | if (trace_ent.takedamage == DAMAGE_YES) { 81 | Damage_Apply(trace_ent, self.owner, 18, WEAPON_TRANQUIL, DMG_BULLET); 82 | } 83 | #endif 84 | remove(self); 85 | } 86 | 87 | Weapons_MakeVectors(pl); 88 | entity p = spawn(); 89 | setmodel(p, "models/nail.mdl"); 90 | setorigin(p, Weapons_GetCameraPos(pl) + (v_forward * 14) + (v_up * -4) + (v_right * 2)); 91 | p.owner = self; 92 | p.movetype = MOVETYPE_FLYMISSILE; 93 | p.solid = SOLID_BBOX; 94 | p.gravity = 0.5f; 95 | p.velocity = (v_forward * 1000) + (v_up * 4) + (v_right * -2); 96 | p.angles = vectoangles(p.velocity); 97 | p.touch = w_rpg_shootrocket_touch; 98 | p.think = Util_Destroy; 99 | p.nextthink = time + 5.0f; 100 | } 101 | 102 | void 103 | w_tranquil_primary(player pl) 104 | { 105 | int s = w_baseprojectile_fire(pl, WEAPON_TRANQUIL, player::m_iAmmoShells, w_tranquil_shootdart); 106 | 107 | switch (s) { 108 | case AUTO_FIRE_FAILED: 109 | return; 110 | break; 111 | case AUTO_FIRED: 112 | case AUTO_LAST: 113 | Weapons_ViewAnimation(pl, TRANQUIL_SHOOT); 114 | Weapons_ViewPunchAngle(pl, [-2,0,0]); 115 | Weapons_Sound(pl, CHAN_WEAPON, "weapon_tranquilizer.fire"); 116 | 117 | if (pl.flags & FL_CROUCHING) 118 | Animation_PlayerTop(pl, TFCANIM_CR_SHOOT1HAND, 0.45f); 119 | else 120 | Animation_PlayerTop(pl, TFCANIM_SHOOT1HAND, 0.45f); 121 | 122 | pl.w_attack_next = 1.5f; 123 | break; 124 | case AUTO_EMPTY: 125 | pl.w_attack_next = 0.2f; 126 | break; 127 | } 128 | 129 | pl.w_idle_next = 2.5f; 130 | } 131 | 132 | float 133 | w_tranquil_aimanim(player pl) 134 | { 135 | return pl.flags & FL_CROUCHING ? TFCANIM_CR_AIM1HAND : TFCANIM_AIM1HAND; 136 | } 137 | 138 | void 139 | w_tranquil_hud(player pl) 140 | { 141 | #ifdef CLIENT 142 | vector aicon_pos; 143 | 144 | aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42]; 145 | 146 | Cross_DrawSub(g_cross_spr, [24,24], [0.1875,0], [0.1875, 0.1875]); 147 | 148 | HUD_DrawAmmo2(); 149 | 150 | 151 | drawsubpic(aicon_pos, [24,24], g_hud7_spr, [72/256,72/128], [24/256, 24/128], g_hud_color, pSeatLocal->m_flAmmo2Alpha, DRAWFLAG_ADDITIVE); 152 | #endif 153 | } 154 | 155 | void 156 | w_tranquil_hudpic(player pl, int selected, vector pos, float a) 157 | { 158 | #ifdef CLIENT 159 | if (selected) { 160 | drawsubpic( 161 | pos, 162 | [170,45], 163 | g_tfchud5_spr, 164 | [0,135/256], 165 | [170/256,45/256], 166 | g_hud_color, 167 | a, 168 | DRAWFLAG_ADDITIVE 169 | ); 170 | } else { 171 | drawsubpic( 172 | pos, 173 | [170,45], 174 | g_tfchud6_spr, 175 | [0,45/256], 176 | [170/256,45/256], 177 | g_hud_color, 178 | a, 179 | DRAWFLAG_ADDITIVE 180 | ); 181 | } 182 | #endif 183 | } 184 | 185 | weapon_t w_tranquil = 186 | { 187 | .name = "tranquil", 188 | .id = ITEM_TRANQUIL, 189 | .slot = 1, 190 | .slot_pos = 2, 191 | .weight = WEIGHT_TRANQUIL, 192 | .draw = w_tranquil_draw, 193 | .holster = __NULL__, 194 | .primary = w_tranquil_primary, 195 | .secondary = __NULL__, 196 | .reload = __NULL__, 197 | .release = __NULL__, 198 | .postdraw = w_tranquil_hud, 199 | .precache = w_tranquil_precache, 200 | .pickup = __NULL__, 201 | .updateammo = w_tranquil_updateammo, 202 | .wmodel = w_tranquil_wmodel, 203 | .pmodel = w_tranquil_pmodel, 204 | .deathmsg = w_tranquil_deathmsg, 205 | .aimanim = w_tranquil_aimanim, 206 | .hudpic = w_tranquil_hudpic, 207 | .isempty = w_asscan_isempty 208 | }; 209 | -------------------------------------------------------------------------------- /src/shared/w_umbrella.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2020 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* stat wise is this the same as the crowbar, but we might tweak it, so it's a 18 | * seperate weapon entry. who knows what modders/servers come up with, too */ 19 | 20 | enum 21 | { 22 | UMBRELLA_IDLE, 23 | UMBRELLA_DRAW, 24 | UMBRELLA_HOLSTER, 25 | UMBRELLA_ATTACK1HIT, 26 | UMBRELLA_ATTACK1MISS, 27 | UMBRELLA_ATTACK2MISS, 28 | UMBRELLA_ATTACK2HIT, 29 | UMBRELLA_ATTACK3MISS, 30 | UMBRELLA_ATTACK3HIT 31 | }; 32 | 33 | void 34 | w_umbrella_precache(void) 35 | { 36 | precache_sound("weapons/cbar_miss1.wav"); 37 | precache_sound("weapons/cbar_hit1.wav"); 38 | precache_sound("weapons/cbar_hit2.wav"); 39 | precache_sound("weapons/cbar_hitbod1.wav"); 40 | precache_sound("weapons/cbar_hitbod2.wav"); 41 | precache_sound("weapons/cbar_hitbod3.wav"); 42 | precache_model("models/v_umbrella.mdl"); 43 | precache_model("models/w_umbrella.mdl"); 44 | precache_model("models/p_umbrella.mdl"); 45 | } 46 | 47 | void 48 | w_umbrella_updateammo(player pl) 49 | { 50 | #ifdef SERVER 51 | Weapons_UpdateAmmo(pl, __NULL__, __NULL__, __NULL__); 52 | #endif 53 | } 54 | 55 | string 56 | w_umbrella_wmodel(void) 57 | { 58 | return "models/w_umbrella.mdl"; 59 | } 60 | string 61 | w_umbrella_pmodel(player pl) 62 | { 63 | return "models/p_umbrella.mdl"; 64 | } 65 | 66 | string 67 | w_umbrella_deathmsg(void) 68 | { 69 | return "%s was assaulted by %s's Umbrella."; 70 | } 71 | 72 | void 73 | w_umbrella_draw(player pl) 74 | { 75 | Weapons_SetModel("models/v_umbrella.mdl"); 76 | Weapons_ViewAnimation(pl, UMBRELLA_DRAW); 77 | } 78 | 79 | void 80 | w_umbrella_holster(player pl) 81 | { 82 | Weapons_ViewAnimation(pl, UMBRELLA_HOLSTER); 83 | } 84 | 85 | void 86 | w_umbrella_primary(player pl) 87 | { 88 | int anim = 0; 89 | vector src; 90 | 91 | if (pl.w_attack_next) { 92 | return; 93 | } 94 | 95 | Weapons_MakeVectors(pl); 96 | src = pl.origin + pl.view_ofs; 97 | traceline(src, src + (v_forward * 32), FALSE, pl); 98 | 99 | int r = (float)input_sequence % 3; 100 | switch (r) { 101 | case 0: 102 | anim = trace_fraction >= 1 ? UMBRELLA_ATTACK1MISS:UMBRELLA_ATTACK1HIT; 103 | break; 104 | case 1: 105 | anim = trace_fraction >= 1 ? UMBRELLA_ATTACK2MISS:UMBRELLA_ATTACK2HIT; 106 | break; 107 | default: 108 | anim = trace_fraction >= 1 ? UMBRELLA_ATTACK3MISS:UMBRELLA_ATTACK3HIT; 109 | } 110 | Weapons_ViewAnimation(pl, anim); 111 | 112 | if (trace_fraction >= 1.0) { 113 | pl.w_attack_next = 0.5f; 114 | } else { 115 | pl.w_attack_next = 0.25f; 116 | } 117 | 118 | pl.w_idle_next = 2.5f; 119 | 120 | #ifdef SERVER 121 | if (pl.flags & FL_CROUCHING) { 122 | Animation_PlayerTop(pl, ANIM_SHOOTCROWBAR, 0.5f); 123 | } else { 124 | Animation_PlayerTop(pl, ANIM_CR_SHOOTCROWBAR, 0.42f); 125 | } 126 | 127 | sound(pl, CHAN_WEAPON, "weapons/cbar_miss1.wav", 1, ATTN_NORM); 128 | 129 | if (trace_fraction >= 1.0) { 130 | return; 131 | } 132 | 133 | /* don't bother with decals, we got squibs */ 134 | if (trace_ent.iBleeds) { 135 | FX_Blood(trace_endpos, [1,0,0]); 136 | } else { 137 | SurfData_Impact(trace_ent, trace_endpos, trace_plane_normal); 138 | } 139 | 140 | if (trace_ent.takedamage) { 141 | Damage_Apply(trace_ent, self, 18, WEAPON_UMBRELLA, DMG_BLUNT); 142 | 143 | if (!trace_ent.iBleeds) { 144 | return; 145 | } 146 | 147 | if (random() < 0.33) { 148 | sound(pl, 8, "weapons/cbar_hitbod1.wav", 1, ATTN_NORM); 149 | } else if (random() < 0.66) { 150 | sound(pl, 8, "weapons/cbar_hitbod2.wav", 1, ATTN_NORM); 151 | } else { 152 | sound(pl, 8, "weapons/cbar_hitbod3.wav", 1, ATTN_NORM); 153 | } 154 | } else { 155 | if (random() < 0.5) { 156 | sound(pl, 8, "weapons/cbar_hit1.wav", 1, ATTN_NORM); 157 | } else { 158 | sound(pl, 8, "weapons/cbar_hit2.wav", 1, ATTN_NORM); 159 | } 160 | } 161 | #endif 162 | } 163 | 164 | void 165 | w_umbrella_release(player pl) 166 | { 167 | 168 | if (pl.w_idle_next) { 169 | return; 170 | } 171 | 172 | Weapons_ViewAnimation(pl, UMBRELLA_IDLE); 173 | pl.w_idle_next = 15.0f; 174 | } 175 | 176 | float 177 | w_umbrella_aimanim(player pl) 178 | { 179 | return pl.flags & FL_CROUCHING ? ANIM_CR_AIMCROWBAR : ANIM_AIMCROWBAR; 180 | } 181 | 182 | void 183 | w_umbrella_hudpic(player pl, int selected, vector pos, float a) 184 | { 185 | #ifdef CLIENT 186 | if (selected) { 187 | drawsubpic( 188 | pos, 189 | [170,45], 190 | g_hud4_spr, 191 | [0,0], 192 | [170/256,45/256], 193 | g_hud_color, 194 | a, 195 | DRAWFLAG_ADDITIVE 196 | ); 197 | } else { 198 | drawsubpic( 199 | pos, 200 | [170,45], 201 | g_hud1_spr, 202 | [0,0], 203 | [170/256,45/256], 204 | g_hud_color, 205 | a, 206 | DRAWFLAG_ADDITIVE 207 | ); 208 | } 209 | #endif 210 | } 211 | 212 | weapon_t w_umbrella = 213 | { 214 | .name = "umbrella", 215 | .id = ITEM_UMBRELLA, 216 | .slot = 0, 217 | .slot_pos = 4, 218 | .weight = WEIGHT_UMBRELLA, 219 | .draw = w_umbrella_draw, 220 | .holster = w_umbrella_holster, 221 | .primary = w_umbrella_primary, 222 | .secondary = __NULL__, 223 | .reload = __NULL__, 224 | .release = w_umbrella_release, 225 | .postdraw = __NULL__, 226 | .precache = w_umbrella_precache, 227 | .pickup = __NULL__, 228 | .updateammo = w_umbrella_updateammo, 229 | .wmodel = w_umbrella_wmodel, 230 | .pmodel = w_umbrella_pmodel, 231 | .deathmsg = w_umbrella_deathmsg, 232 | .aimanim = w_umbrella_aimanim, 233 | .hudpic = w_umbrella_hudpic, 234 | .isempty = w_asscan_isempty 235 | }; 236 | -------------------------------------------------------------------------------- /src/shared/w_wrench.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2020 Marco Cawthorne 3 | * Copyright (c) 2022 Gethyn ThomasQuail 4 | * 5 | * Permission to use, copy, modify, and distribute this software for any 6 | * purpose with or without fee is hereby granted, provided that the above 7 | * copyright notice and this permission notice appear in all copies. 8 | * 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 14 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 15 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | */ 17 | 18 | enum 19 | { 20 | WRENCH_IDLE, 21 | WRENCH_ATTACK1, 22 | WRENCH_ATTACK2, 23 | WRENCH_USE, 24 | WRENCH_DRAW, 25 | WRENCH_HOLSTER 26 | }; 27 | 28 | void 29 | w_wrench_precache(void) 30 | { 31 | precache_sound("weapons/cbar_miss1.wav"); 32 | precache_sound("weapons/cbar_hit1.wav"); 33 | precache_sound("weapons/cbar_hit2.wav"); 34 | precache_sound("weapons/cbar_hitbod1.wav"); 35 | precache_sound("weapons/cbar_hitbod2.wav"); 36 | precache_sound("weapons/cbar_hitbod3.wav"); 37 | precache_model("models/v_tfc_spanner.mdl"); 38 | precache_model("models/p_spanner.mdl"); 39 | } 40 | 41 | void 42 | w_wrench_updateammo(player pl) 43 | { 44 | Weapons_UpdateAmmo(pl, __NULL__, pl.m_iAmmoCells, __NULL__); 45 | } 46 | 47 | string 48 | w_wrench_wmodel(void) 49 | { 50 | return "models/ball.mdl"; 51 | } 52 | string 53 | w_wrench_pmodel(player pl) 54 | { 55 | return "models/p_spanner.mdl"; 56 | } 57 | 58 | string 59 | w_wrench_deathmsg(void) 60 | { 61 | return "%s was assaulted by %s's wrench."; 62 | } 63 | 64 | void 65 | w_wrench_draw(player pl) 66 | { 67 | Weapons_SetModel("models/v_tfc_spanner.mdl"); 68 | Weapons_ViewAnimation(pl, WRENCH_DRAW); 69 | } 70 | 71 | void 72 | w_wrench_holster(player pl) 73 | { 74 | Weapons_ViewAnimation(pl, WRENCH_HOLSTER); 75 | } 76 | 77 | void 78 | w_wrench_primary(player pl) 79 | { 80 | int anim = 0; 81 | vector src; 82 | 83 | if (pl.w_attack_next) { 84 | return; 85 | } 86 | 87 | Weapons_MakeVectors(pl); 88 | src = pl.origin + pl.view_ofs; 89 | traceline(src, src + (v_forward * 32), FALSE, pl); 90 | 91 | int r = (float)input_sequence % 2; 92 | switch (r) { 93 | case 0: 94 | anim = WRENCH_ATTACK1; 95 | break; 96 | default: 97 | anim = WRENCH_ATTACK2; 98 | } 99 | Weapons_ViewAnimation(pl, anim); 100 | 101 | if (trace_fraction < 1.0) { 102 | pl.w_attack_next = 0.25f; 103 | } else { 104 | pl.w_attack_next = 0.5f; 105 | } 106 | 107 | pl.w_idle_next = 2.5f; 108 | 109 | #ifdef SERVER 110 | if (pl.flags & FL_CROUCHING) { 111 | Animation_PlayerTop(pl, ANIM_SHOOTCROWBAR, 0.5f); 112 | } else { 113 | Animation_PlayerTop(pl, ANIM_CR_SHOOTCROWBAR, 0.42f); 114 | } 115 | 116 | sound(pl, CHAN_WEAPON, "weapons/cbar_miss1.wav", 1, ATTN_NORM); 117 | 118 | if (trace_fraction >= 1.0) { 119 | return; 120 | } 121 | 122 | if (trace_ent.classname == "TFCSentry") { 123 | TFCSentry sentry = (TFCSentry)trace_ent; 124 | /* todo 125 | } else if (trace_ent.classname == "TFCDispenser") { 126 | TFCDispenser dispenser = (TFCDispenser)trace_ent; 127 | todo 128 | } else if (trace_ent.classname == "TFCTeleporter") { 129 | TFCTeleporter teleporter = (TFCTeleporter)trace_ent; 130 | todo 131 | } else if (trace_ent.classname == "TFCTeleporterExit") { 132 | TFCTeleporterExit teleporterexit = (TFCTeleporterExit)trace_ent; 133 | todo */ 134 | } else { 135 | /* don't bother with decals, we got squibs */ 136 | if (trace_ent.iBleeds) { 137 | FX_Blood(trace_endpos, [1,0,0]); 138 | } else { 139 | SurfData_Impact(trace_ent, trace_endpos, trace_plane_normal); 140 | } 141 | 142 | /* Damage without armor is between 12 - 20, so let's just do 15 for now */ 143 | if (trace_ent.takedamage) { 144 | Damage_Apply(trace_ent, pl, 18, WEAPON_WRENCH, DMG_BLUNT); 145 | if (trace_ent.iBleeds) { 146 | Sound_Play(self, CHAN_WEAPON, "weapon_crowbar.hitbody"); 147 | } 148 | } else { 149 | Sound_Play(self, CHAN_WEAPON, "weapon_crowbar.hit"); 150 | } 151 | } 152 | 153 | #endif 154 | } 155 | 156 | void 157 | w_wrench_release(player pl) 158 | { 159 | 160 | if (pl.w_idle_next) { 161 | return; 162 | } 163 | 164 | Weapons_ViewAnimation(pl, WRENCH_IDLE); 165 | pl.w_idle_next = 15.0f; 166 | } 167 | 168 | void 169 | w_wrench_crosshair(player pl) 170 | { 171 | #ifdef CLIENT 172 | vector aicon_pos; 173 | 174 | aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42]; 175 | 176 | drawsubpic( 177 | aicon_pos, 178 | [24,24], 179 | g_hud7_spr, 180 | [0,96/128], 181 | [24/256,24/128], 182 | g_hud_color, 183 | pSeatLocal->m_flAmmo2Alpha, 184 | DRAWFLAG_ADDITIVE 185 | ); 186 | 187 | HUD_DrawAmmo2(); 188 | #endif 189 | } 190 | 191 | float 192 | w_wrench_aimanim(player pl) 193 | { 194 | return pl.flags & FL_CROUCHING ? ANIM_CR_AIMCROWBAR : ANIM_AIMCROWBAR; 195 | } 196 | 197 | void 198 | w_wrench_hudpic(player pl, int selected, vector pos, float a) 199 | { 200 | #ifdef CLIENT 201 | if (selected) { 202 | drawsubpic( 203 | pos, 204 | [170,45], 205 | g_tfchud4_spr, 206 | [0,180/256], 207 | [170/256,45/256], 208 | g_hud_color, 209 | a, 210 | DRAWFLAG_ADDITIVE 211 | ); 212 | } else { 213 | drawsubpic( 214 | pos, 215 | [170,45], 216 | g_tfchud3_spr, 217 | [0,135/256], 218 | [170/256,45/256], 219 | g_hud_color, 220 | a, 221 | DRAWFLAG_ADDITIVE 222 | ); 223 | } 224 | 225 | HUD_DrawAmmoBar(pos, pl.m_iAmmoCells, MAX_A_CELLS, a); 226 | #endif 227 | } 228 | 229 | weapon_t w_wrench = 230 | { 231 | .name = "wrench", 232 | .id = ITEM_WRENCH, 233 | .slot = 0, 234 | .slot_pos = 3, 235 | .weight = WEIGHT_WRENCH, 236 | .draw = w_wrench_draw, 237 | .holster = w_wrench_holster, 238 | .primary = w_wrench_primary, 239 | .secondary = __NULL__, 240 | .reload = __NULL__, 241 | .release = w_wrench_release, 242 | .postdraw = w_wrench_crosshair, 243 | .precache = w_wrench_precache, 244 | .pickup = __NULL__, 245 | .updateammo = w_wrench_updateammo, 246 | .wmodel = w_wrench_wmodel, 247 | .pmodel = w_wrench_pmodel, 248 | .deathmsg = w_wrench_deathmsg, 249 | .aimanim = w_wrench_aimanim, 250 | .hudpic = w_wrench_hudpic, 251 | .isempty = w_asscan_isempty 252 | }; 253 | -------------------------------------------------------------------------------- /src/shared/weapon_baseautomatic.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2022 Vera Visions LLC. 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | enum 18 | { 19 | AUTO_FIRE_FAILED, 20 | AUTO_FIRED, 21 | AUTO_LAST, 22 | AUTO_EMPTY 23 | }; 24 | 25 | int 26 | w_baseauto_fire(int w, .int mag, int d, vector bs) 27 | { 28 | player pl = (player)self; 29 | 30 | if (pl.w_attack_next > 0.0) { 31 | return (AUTO_FIRE_FAILED); 32 | } 33 | if (pl.gflags & GF_SEMI_TOGGLED) { 34 | return (AUTO_FIRE_FAILED); 35 | } 36 | if (pl.(mag) <= 0) { 37 | pl.gflags |= GF_SEMI_TOGGLED; 38 | return (AUTO_EMPTY); 39 | } 40 | 41 | pl.(mag)--; 42 | 43 | #ifdef SERVER 44 | TraceAttack_FireBullets(1, pl.origin + pl.view_ofs, d, bs, w); 45 | #endif 46 | 47 | if (pl.(mag) == 0) 48 | return (AUTO_LAST); 49 | else 50 | return (AUTO_FIRED); 51 | } 52 | -------------------------------------------------------------------------------- /src/shared/weapon_basemelee.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2022 Vera Visions LLC. 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | enum 18 | { 19 | MELEE_FAILED, 20 | MELEE_MISS, 21 | MELEE_HIT, 22 | MELEE_HITBODY 23 | }; 24 | 25 | int 26 | w_basemelee_fire(int d, int w) 27 | { 28 | int anim = 0; 29 | vector src; 30 | player pl = (player)self; 31 | 32 | if (pl.w_attack_next > 0.0) { 33 | return (MELEE_FAILED); 34 | } 35 | 36 | Weapons_MakeVectors(pl); 37 | src = pl.origin + pl.view_ofs; 38 | 39 | /* make sure we can gib corpses */ 40 | int oldhitcontents = self.hitcontentsmaski; 41 | self.hitcontentsmaski = CONTENTBITS_POINTSOLID | CONTENTBIT_CORPSE; 42 | traceline(src, src + (v_forward * 32), FALSE, pl); 43 | self.hitcontentsmaski = oldhitcontents; 44 | 45 | pl.w_attack_next = 0.5f; 46 | pl.w_idle_next = 2.5f; 47 | 48 | if (trace_fraction >= 1.0) { 49 | return (MELEE_MISS); 50 | } 51 | 52 | #ifdef SERVER 53 | if (trace_ent.takedamage) { 54 | Damage_Apply(trace_ent, pl, d, w, DMG_BLUNT); 55 | } 56 | #endif 57 | 58 | return (MELEE_HIT); 59 | } 60 | -------------------------------------------------------------------------------- /src/shared/weapon_baseprojectile.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2022 Vera Visions LLC. 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | enum 18 | { 19 | SEMI_FIRE_FAILED, 20 | SEMI_FIRED, 21 | SEMI_LAST, 22 | SEMI_EMPTY 23 | }; 24 | 25 | int 26 | w_baseprojectile_fire(player pl, int w, .int mag, void(player) spawnfunc) 27 | { 28 | if (pl.w_attack_next > 0.0) { 29 | return (SEMI_FIRE_FAILED); 30 | } 31 | if (pl.gflags & GF_SEMI_TOGGLED) { 32 | return (SEMI_FIRE_FAILED); 33 | } 34 | if (pl.(mag) <= 0) { 35 | return (SEMI_EMPTY); 36 | } 37 | 38 | pl.(mag)--; 39 | 40 | #ifdef SERVER 41 | spawnfunc(pl); 42 | #endif 43 | 44 | if (pl.(mag) == 0) 45 | return (SEMI_LAST); 46 | else 47 | return (SEMI_FIRED); 48 | } 49 | 50 | int 51 | w_baseprojectile_fire_num(player pl, int w, .int mag, void(player) spawnfunc, int num) 52 | { 53 | if (pl.w_attack_next > 0.0) { 54 | return (SEMI_FIRE_FAILED); 55 | } 56 | if (pl.gflags & GF_SEMI_TOGGLED) { 57 | return (SEMI_FIRE_FAILED); 58 | } 59 | if ((pl.(mag) - num) < 0) { 60 | return (SEMI_EMPTY); 61 | } 62 | 63 | pl.(mag) -= num; 64 | 65 | #ifdef SERVER 66 | spawnfunc(pl); 67 | #endif 68 | 69 | if (pl.(mag) == 0) 70 | return (SEMI_LAST); 71 | else 72 | return (SEMI_FIRED); 73 | } 74 | 75 | -------------------------------------------------------------------------------- /src/shared/weapon_basesemi.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2022 Vera Visions LLC. 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | enum 18 | { 19 | SEMI_FIRE_FAILED, 20 | SEMI_FIRED, 21 | SEMI_LAST, 22 | SEMI_EMPTY 23 | }; 24 | 25 | int 26 | w_basesemi_fire(int w, .int mag, int d, vector bs) 27 | { 28 | player pl = (player)self; 29 | 30 | if (pl.w_attack_next > 0.0) { 31 | return (SEMI_FIRE_FAILED); 32 | } 33 | if (pl.gflags & GF_SEMI_TOGGLED) { 34 | return (SEMI_FIRE_FAILED); 35 | } 36 | if (pl.(mag) <= 0) { 37 | pl.gflags |= GF_SEMI_TOGGLED; 38 | return (SEMI_EMPTY); 39 | } 40 | 41 | pl.(mag)--; 42 | 43 | #ifdef SERVER 44 | TraceAttack_FireBullets(1, pl.origin + pl.view_ofs, d, bs, w); 45 | #endif 46 | 47 | pl.gflags |= GF_SEMI_TOGGLED; 48 | 49 | if (pl.(mag) == 0) 50 | return (SEMI_LAST); 51 | else 52 | return (SEMI_FIRED); 53 | } 54 | -------------------------------------------------------------------------------- /src/shared/weapon_baseshotgun.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2022 Vera Visions LLC. 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | enum 18 | { 19 | SHOTGUN_FIRE_FAILED, 20 | SHOTGUN_FIRED, 21 | SHOTGUN_LAST, 22 | SHOTGUN_EMPTY 23 | }; 24 | 25 | int 26 | w_baseshotgun_fire(int w, .int mag, int c, int d, vector bs) 27 | { 28 | player pl = (player)self; 29 | 30 | if (pl.w_attack_next > 0.0) { 31 | return (SHOTGUN_FIRE_FAILED); 32 | } 33 | if (pl.gflags & GF_SEMI_TOGGLED) { 34 | return (SHOTGUN_FIRE_FAILED); 35 | } 36 | if (pl.(mag) <= 0) { 37 | pl.gflags |= GF_SEMI_TOGGLED; 38 | return (SHOTGUN_EMPTY); 39 | } 40 | 41 | pl.(mag)--; 42 | 43 | #ifdef SERVER 44 | TraceAttack_FireBullets(c, pl.origin + pl.view_ofs, d, bs, w); 45 | #endif 46 | 47 | if (pl.(mag) == 0) 48 | return (SHOTGUN_LAST); 49 | else 50 | return (SHOTGUN_FIRED); 51 | } 52 | 53 | enum 54 | { 55 | SHOTTY_IDLE, 56 | SHOTTY_RELOAD_START, 57 | SHOTTY_RELOAD, 58 | SHOTTY_RELOAD_END, 59 | SHOTTY_COCKSOUND 60 | }; 61 | 62 | void 63 | w_baseshotgun_reload(.int mag, .int ammo, int max) 64 | { 65 | player pl = (player)self; 66 | 67 | if (pl.(mag) >= max) { 68 | return; 69 | } 70 | if (pl.(ammo) <= 0) { 71 | return; 72 | } 73 | if (pl.mode_tempstate > SHOTTY_IDLE) { 74 | return; 75 | } 76 | 77 | pl.mode_tempstate = SHOTTY_RELOAD_START; 78 | pl.w_idle_next = 0.0f; 79 | } 80 | 81 | enum 82 | { 83 | SHOTGUN_IDLE, 84 | SHOTGUN_BUSY, 85 | SHOTGUN_START_RELOAD, 86 | SHOTGUN_RELOAD, 87 | SHOTGUN_END_RELOAD 88 | }; 89 | 90 | int 91 | w_baseshotgun_release(.int mag, .int ammo, int max) 92 | { 93 | player pl = (player)self; 94 | 95 | if (pl.w_idle_next > 0.0) { 96 | return (SHOTGUN_BUSY); 97 | } 98 | 99 | if (pl.mode_tempstate == SHOTTY_RELOAD_START) { 100 | pl.mode_tempstate = SHOTTY_RELOAD; 101 | pl.w_idle_next = 0.65f; 102 | return (SHOTGUN_START_RELOAD); 103 | } else if (pl.mode_tempstate == SHOTTY_RELOAD) { 104 | pl.(mag)++; 105 | pl.(ammo)--; 106 | 107 | if (pl.(ammo) <= 0 || pl.(mag) >= max) { 108 | pl.mode_tempstate = SHOTTY_RELOAD_END; 109 | } 110 | Weapons_UpdateAmmo(pl, pl.(mag), pl.(ammo), pl.mode_tempstate); 111 | pl.w_idle_next = 0.5f; 112 | return (SHOTGUN_RELOAD); 113 | } else if (pl.mode_tempstate == SHOTTY_RELOAD_END) { 114 | pl.mode_tempstate = SHOTTY_IDLE; 115 | pl.w_idle_next = 10.0f; 116 | pl.w_attack_next = 0.5f; 117 | return (SHOTGUN_END_RELOAD); 118 | } 119 | 120 | return (SHOTGUN_IDLE); 121 | } 122 | -------------------------------------------------------------------------------- /src/shared/weapons.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2020 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* weapon Indices for the weapon table */ 18 | enum 19 | { 20 | WEAPON_NONE, 21 | WEAPON_CROWBAR, 22 | WEAPON_MEDKIT, 23 | WEAPON_KNIFE, 24 | WEAPON_WRENCH, 25 | WEAPON_UMBRELLA, 26 | WEAPON_SBS, 27 | WEAPON_SNIPER, 28 | WEAPON_TRANQUIL, 29 | WEAPON_RAILGUN, 30 | WEAPON_AUTORIFLE, 31 | WEAPON_DBS, 32 | WEAPON_NAILGUN, 33 | WEAPON_GLAUNCHER, 34 | WEAPON_SUPERNAIL, 35 | WEAPON_FLAMER, 36 | WEAPON_RPG, 37 | WEAPON_PIPEBOMB, 38 | WEAPON_ASSCAN, 39 | WEAPON_INCENDIARY, 40 | WEAPON_GRAPPLE 41 | }; 42 | 43 | 44 | #define WEIGHT_CROWBAR -1 45 | #define WEIGHT_MEDKIT 1 46 | #define WEIGHT_KNIFE 1 47 | #define WEIGHT_WRENCH 1 48 | #define WEIGHT_UMBRELLA 1 49 | #define WEIGHT_SBS 10 50 | #define WEIGHT_SNIPER 10 51 | #define WEIGHT_TRANQUIL 10 52 | #define WEIGHT_RAILGUN 10 53 | #define WEIGHT_AUTORIFLE 10 54 | #define WEIGHT_DBS 20 55 | #define WEIGHT_NAILGUN 20 56 | #define WEIGHT_GLAUNCHER 20 57 | #define WEIGHT_SUPERNAIL 20 58 | #define WEIGHT_FLAMER 20 59 | #define WEIGHT_RPG 20 60 | #define WEIGHT_PIPEBOMB 0 61 | #define WEIGHT_ASSCAN 20 62 | #define WEIGHT_INCENDIARY 20 63 | #define WEIGHT_GRAPPLE -1 -------------------------------------------------------------------------------- /src/shared/weapons.qc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2020 Marco Cawthorne 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 13 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 14 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | weapon_t w_null = {}; 18 | weapon_t g_weapons[] = { 19 | w_null, 20 | w_crowbar, 21 | w_medkit, 22 | w_knife, 23 | w_wrench, 24 | w_umbrella, 25 | w_sbs, 26 | w_sniper, 27 | w_tranquil, 28 | w_railgun, 29 | w_autorifle, 30 | w_dbs, 31 | w_nailgun, 32 | w_glauncher, 33 | w_supernail, 34 | w_flamer, 35 | w_rpg, 36 | w_pipebomb, 37 | w_asscan, 38 | w_incendiary, 39 | w_grapple 40 | }; 41 | -------------------------------------------------------------------------------- /zpak001.pk3dir/def/armor.def: -------------------------------------------------------------------------------- 1 | entityDef item_armor1 2 | { 3 | spawnclass TFCArmor 4 | model "models/g_armor.mdl" 5 | armorvalue "100" 6 | snd_pickup "item_armor_tfc.pickup" 7 | } 8 | 9 | entityDef item_armor2 10 | { 11 | spawnclass TFCArmor 12 | model "models/y_armor.mdl" 13 | armorvalue "150" 14 | snd_pickup "item_armor_tfc.pickup" 15 | } 16 | 17 | entityDef item_armor3 18 | { 19 | spawnclass TFCArmor 20 | model "models/r_armor.mdl" 21 | armorvalue "200" 22 | snd_pickup "item_armor_tfc.pickup" 23 | } -------------------------------------------------------------------------------- /zpak001.pk3dir/def/bot.def: -------------------------------------------------------------------------------- 1 | entityDef bot 2 | { 3 | spawnclass TFCBot 4 | } -------------------------------------------------------------------------------- /zpak001.pk3dir/def/monsters.def: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eukara/freetfc/1152939d934726b261b2f3ce74692ffc707c4e36/zpak001.pk3dir/def/monsters.def -------------------------------------------------------------------------------- /zpak001.pk3dir/def/spawns.def: -------------------------------------------------------------------------------- 1 | entityDef info_player_start 2 | { 3 | editor_mins "-16 -16 -36" 4 | editor_maxs "16 16 36" 5 | editor_description "Singleplayer Spawn" 6 | 7 | spawnclass NSSpawnPoint 8 | } 9 | 10 | entityDef info_teamspawn_blue 11 | { 12 | editor_mins "-16 -16 -36" 13 | editor_maxs "16 16 36" 14 | editor_description "Blue Team Spawn" 15 | 16 | spawnclass NSSpawnPoint 17 | } 18 | 19 | entityDef info_teamspawn_red 20 | { 21 | editor_mins "-16 -16 -36" 22 | editor_maxs "16 16 36" 23 | editor_description "Red Team Spawn" 24 | 25 | spawnclass NSSpawnPoint 26 | } 27 | 28 | entityDef info_teamspawn_green 29 | { 30 | editor_mins "-16 -16 -36" 31 | editor_maxs "16 16 36" 32 | editor_description "Yellow Team Spawn" 33 | 34 | spawnclass NSSpawnPoint 35 | } 36 | 37 | entityDef info_teamspawn_yellow 38 | { 39 | editor_mins "-16 -16 -36" 40 | editor_maxs "16 16 36" 41 | editor_description "Yellow Team Spawn" 42 | 43 | spawnclass NSSpawnPoint 44 | } -------------------------------------------------------------------------------- /zpak001.pk3dir/default.cfg: -------------------------------------------------------------------------------- 1 | // Generic Binds 2 | bind "ESC" "togglemenu" 3 | bind "w" "+forward" 4 | bind "s" "+back" 5 | bind "a" "+moveleft" 6 | bind "d" "+moveright" 7 | bind "SPACE" "+jump" 8 | bind "CTRL" "+duck" 9 | bind "SHIFT" "+speed" 10 | bind "0" "slot10" 11 | bind "1" "slot1" 12 | bind "2" "slot2" 13 | bind "3" "slot3" 14 | bind "4" "slot4" 15 | bind "5" "slot5" 16 | bind "6" "slot6" 17 | bind "7" "slot7" 18 | bind "8" "slot8" 19 | bind "9" "slot9" 20 | bind "UPARROW" "+forward" 21 | bind "DOWNARROW" "+back" 22 | bind "LEFTARROW" "+left" 23 | bind "RIGHTARROW" "+right" 24 | bind "MOUSE1" "+attack" 25 | bind "MOUSE2" "+attack2" 26 | bind "MWHEELDOWN" "invnext" 27 | bind "MWHEELUP" "invprev" 28 | bind "r" "+reload" 29 | bind "e" "+use" 30 | bind "TAB" "+showscores" 31 | bind "y" "messagemode" 32 | bind "u" "messagemode2" 33 | bind "t" "impulse 201" 34 | bind "f" "impulse 100" 35 | bind "f1" "vote yes" 36 | bind "f2" "vote no" 37 | 38 | // Game Variables 39 | seta "hostname" "FreeTFC Server" 40 | seta "maxplayers" "8" 41 | 42 | // disable some nuclide niceties 43 | seta v_muzzledlight 0 44 | 45 | // config compat 46 | alias mp_timelimit timelimit 47 | alias mp_fraglimit fraglimit 48 | 49 | // video settings 50 | seta gl_overbright 0 51 | seta gl_ldr 1 52 | seta r_lightmap_format rgb8 53 | -------------------------------------------------------------------------------- /zpak001.pk3dir/maps/2fort_src.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eukara/freetfc/1152939d934726b261b2f3ce74692ffc707c4e36/zpak001.pk3dir/maps/2fort_src.jpg -------------------------------------------------------------------------------- /zpak001.pk3dir/maps/avanti_src.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eukara/freetfc/1152939d934726b261b2f3ce74692ffc707c4e36/zpak001.pk3dir/maps/avanti_src.jpg -------------------------------------------------------------------------------- /zpak001.pk3dir/maps/badlands_src.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eukara/freetfc/1152939d934726b261b2f3ce74692ffc707c4e36/zpak001.pk3dir/maps/badlands_src.jpg -------------------------------------------------------------------------------- /zpak001.pk3dir/maps/casbah_src.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eukara/freetfc/1152939d934726b261b2f3ce74692ffc707c4e36/zpak001.pk3dir/maps/casbah_src.jpg -------------------------------------------------------------------------------- /zpak001.pk3dir/maps/crossover2_src.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eukara/freetfc/1152939d934726b261b2f3ce74692ffc707c4e36/zpak001.pk3dir/maps/crossover2_src.jpg -------------------------------------------------------------------------------- /zpak001.pk3dir/maps/cz2_src.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eukara/freetfc/1152939d934726b261b2f3ce74692ffc707c4e36/zpak001.pk3dir/maps/cz2_src.jpg -------------------------------------------------------------------------------- /zpak001.pk3dir/maps/dustbowl_src.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eukara/freetfc/1152939d934726b261b2f3ce74692ffc707c4e36/zpak001.pk3dir/maps/dustbowl_src.jpg -------------------------------------------------------------------------------- /zpak001.pk3dir/maps/epicenter_src.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eukara/freetfc/1152939d934726b261b2f3ce74692ffc707c4e36/zpak001.pk3dir/maps/epicenter_src.jpg -------------------------------------------------------------------------------- /zpak001.pk3dir/maps/flagrun_src.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eukara/freetfc/1152939d934726b261b2f3ce74692ffc707c4e36/zpak001.pk3dir/maps/flagrun_src.jpg -------------------------------------------------------------------------------- /zpak001.pk3dir/maps/hunted_src.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eukara/freetfc/1152939d934726b261b2f3ce74692ffc707c4e36/zpak001.pk3dir/maps/hunted_src.jpg -------------------------------------------------------------------------------- /zpak001.pk3dir/maps/push_src.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eukara/freetfc/1152939d934726b261b2f3ce74692ffc707c4e36/zpak001.pk3dir/maps/push_src.jpg -------------------------------------------------------------------------------- /zpak001.pk3dir/maps/rock2_src.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eukara/freetfc/1152939d934726b261b2f3ce74692ffc707c4e36/zpak001.pk3dir/maps/rock2_src.jpg -------------------------------------------------------------------------------- /zpak001.pk3dir/maps/warpath_src.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eukara/freetfc/1152939d934726b261b2f3ce74692ffc707c4e36/zpak001.pk3dir/maps/warpath_src.jpg -------------------------------------------------------------------------------- /zpak001.pk3dir/maps/well_src.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eukara/freetfc/1152939d934726b261b2f3ce74692ffc707c4e36/zpak001.pk3dir/maps/well_src.jpg -------------------------------------------------------------------------------- /zpak001.pk3dir/particles/weapon_railgun.cfg: -------------------------------------------------------------------------------- 1 | r_part trail 2 | { 3 | texture "particles/fteparticlefont.tga" 4 | tcoords 97 97 191 191 256 5 | scale 1 6 | rgbf 0 1 0 7 | blend add 8 | step 4 9 | die 0.075 10 | randomvel 0 11 | type beam 12 | } 13 | -------------------------------------------------------------------------------- /zpak001.pk3dir/scripts/constants.txt: -------------------------------------------------------------------------------- 1 | // weapon constants 2 | WEAPON_NONE 0 3 | WEAPON_CROWBAR 1 4 | WEAPON_MEDKIT 2 5 | WEAPON_KNIFE 3 6 | WEAPON_WRENCH 4 7 | WEAPON_UMBRELLA 5 8 | WEAPON_SBS 6 9 | WEAPON_SNIPER 7 10 | WEAPON_TRANQUIL 8 11 | WEAPON_RAILGUN 9 12 | WEAPON_AUTORIFLE 10 13 | WEAPON_DBS 11 14 | WEAPON_NAILGUN 12 15 | WEAPON_GLAUNCHER 13 16 | WEAPON_SUPERNAIL 14 17 | WEAPON_FLAMER 15 18 | WEAPON_RPG 16 19 | WEAPON_PIPEBOMB 17 20 | WEAPON_ASSCAN 18 21 | WEAPON_INCENDIARY 19 22 | WEAPON_GRAPPLE 20 -------------------------------------------------------------------------------- /zpak001.pk3dir/sound/items_tfc.sndshd: -------------------------------------------------------------------------------- 1 | item_armor_tfc.pickup 2 | { 3 | sample items/armoron_1.wav 4 | } 5 | item_healthkit_tfc.pickup 6 | { 7 | sample items/smallmedkit1.wav 8 | } -------------------------------------------------------------------------------- /zpak001.pk3dir/sound/player_tfc.sndshd: -------------------------------------------------------------------------------- 1 | player_tfc.death 2 | { 3 | sample player/death1.wav 4 | sample player/death2.wav 5 | sample player/death3.wav 6 | sample player/death4.wav 7 | sample player/death5.wav 8 | } 9 | 10 | player_tfc.jump 11 | { 12 | sample player/plyrjmp8.wav 13 | } 14 | -------------------------------------------------------------------------------- /zpak001.pk3dir/sound/turret_tfc.sndshd: -------------------------------------------------------------------------------- 1 | turret_tfc.idle_noise 2 | { 3 | sample "weapons/turridle.wav" 4 | } 5 | 6 | turret_tfc.target_spotted 7 | { 8 | sample "weapons/turrspot.wav" 9 | } 10 | -------------------------------------------------------------------------------- /zpak001.pk3dir/sound/weapons_tfc.sndshd: -------------------------------------------------------------------------------- 1 | weapon_asscan.fire 2 | { 3 | //pitch 1.15 4 | sample weapons/asscan2.wav 5 | } 6 | 7 | weapon_asscan.reload 8 | { 9 | sample weapons/.wav 10 | } 11 | 12 | weapon_asscan.spin 13 | { 14 | sample weapons/asscan4.wav 15 | } 16 | 17 | weapon_asscan.spindown 18 | { 19 | sample weapons/asscan3.wav 20 | } 21 | 22 | weapon_asscan.spinup 23 | { 24 | sample weapons/asscan1.wav 25 | } 26 | 27 | weapon_dbs.fire 28 | { 29 | sample weapons/shotgn2.wav 30 | } 31 | 32 | weapon_dbs.fire 33 | { 34 | sample weapons/shotgn2.wav 35 | } 36 | 37 | weapon_dbs.cock 38 | { 39 | sample weapons/scock1.wav 40 | } 41 | 42 | weapon_dbs.reload 43 | { 44 | sample weapons/reload3.wav 45 | } 46 | 47 | weapon_flame.fire 48 | { 49 | sample weapons/flmfire2.wav 50 | } 51 | 52 | weapon_incendiary.fire 53 | { 54 | sample weapons/sgun1.wav 55 | } 56 | 57 | weapon_medkit.heal 58 | { 59 | sample items/smallmedkit1.wav 60 | } 61 | 62 | weapon_sbs.cock 63 | { 64 | sample weapons/scock1.wav 65 | } 66 | 67 | weapon_sbs.fire 68 | { 69 | sample weapons/sbarrel1.wav 70 | } 71 | 72 | weapon_sbs.reload 73 | { 74 | sample weapons/reload3.wav 75 | } 76 | 77 | weapon_nailgun.fire 78 | { 79 | sample weapons/airgun_1.wav 80 | } 81 | 82 | weapon_rpg.fire 83 | { 84 | sample weapons/rocketfire1.wav 85 | } 86 | 87 | weapon_railgun.fire 88 | { 89 | sample weapons/railgun.wav 90 | } 91 | 92 | weapon_sniper.fire 93 | { 94 | sample weapons/sniper.wav 95 | } 96 | 97 | weapon_tranquilizer.fire 98 | { 99 | sample weapons/dartgun.wav 100 | } 101 | 102 | engineer.build 103 | { 104 | sample weapons/building.wav 105 | } 106 | 107 | engineer.turret_set 108 | { 109 | sample weapons/turrset.wav 110 | } 111 | --------------------------------------------------------------------------------