diff --git a/src/Makefile b/src/Makefile index cc3f82d..c2ba2d8 100644 --- a/src/Makefile +++ b/src/Makefile @@ -3,3 +3,4 @@ CC=fteqcc all: cd client && $(MAKE) cd server && $(MAKE) + cd rules && $(MAKE) diff --git a/src/client/cmds.qc b/src/client/cmds.qc index 7a0608b..ab3b654 100644 --- a/src/client/cmds.qc +++ b/src/client/cmds.qc @@ -115,164 +115,7 @@ ClientGame_ConsoleCommand(void) case "drop": sendevent("DropWeapon", ""); break; - case "glock": - sendevent("CSBuy", "f", BUY_GLOCK18); - break; - case "usp": - sendevent("CSBuy", "f", BUY_USP45); - break; - case "p228": - sendevent("CSBuy", "f", BUY_P228); - break; - case "deagle": - sendevent("CSBuy", "f", BUY_DEAGLE); - break; - case "fn57": - sendevent("CSBuy", "f", BUY_FIVESEVEN); - break; - case "elites": - sendevent("CSBuy", "f", BUY_ELITES); - break; - case "m3": - sendevent("CSBuy", "f", BUY_M3); - break; - case "xm1014": - sendevent("CSBuy", "f", BUY_XM1014); - break; - case "tmp": - sendevent("CSBuy", "f", BUY_TMP); - break; - case "mac10": - sendevent("CSBuy", "f", BUY_MAC10); - break; - case "mp5": - sendevent("CSBuy", "f", BUY_MP5); - break; - case "ump45": - sendevent("CSBuy", "f", BUY_UMP45); - break; - case "p90": - sendevent("CSBuy", "f", BUY_P90); - break; - case "ak47": - sendevent("CSBuy", "f", BUY_AK47); - break; - case "m4a1": - sendevent("CSBuy", "f", BUY_M4A1); - break; - case "sg552": - sendevent("CSBuy", "f", BUY_SG552); - break; - case "aug": - sendevent("CSBuy", "f", BUY_AUG); - break; - case "scout": - sendevent("CSBuy", "f", BUY_SCOUT); - break; - case "sg550": - sendevent("CSBuy", "f", BUY_SG550); - break; - case "awp": - sendevent("CSBuy", "f", BUY_AWP); - break; - case "g3sg1": - sendevent("CSBuy", "f", BUY_G3SG1); - break; - case "m249": - sendevent("CSBuy", "f", BUY_PARA); - break; - case "buyammo1": - case "primammo": - sendevent("CSBuy", "f", BUY_PRIMARYAMMO); - break; - case "buyammo2": - case "secammo": - sendevent("CSBuy", "f", BUY_SECONDARYAMMO); - break; - case "vest": - sendevent("CSBuy", "f", BUY_VEST); - break; - case "vesthelm": - sendevent("CSBuy", "f", BUY_VESTHELMET); - break; - case "flash": - sendevent("CSBuy", "f", BUY_FLASHBANG); - break; - case "hegren": - sendevent("CSBuy", "f", BUY_HEGRENADE); - break; - case "vsgren": - sendevent("CSBuy", "f", BUY_SMOKEGRENADE); - break; - case "defuser": - sendevent("CSBuy", "f", BUY_DEFUSALKIT); - break; - case "nvg": - sendevent("CSBuy", "f", BUY_NIGHTVISION); - break; - case "coverme": - sendevent("Radio", "f", RADIO_CT_COVERME); - break; - case "takepoint": - sendevent("Radio", "f", RADIO_CT_POINT); - break; - case "takepoint": - sendevent("Radio", "f", RADIO_POSITION); - break; - case "regroup": - sendevent("Radio", "f", RADIO_REGROUP); - break; - case "followme": - sendevent("Radio", "f", RADIO_FOLLOWME); - break; - case "takingfire": - sendevent("Radio", "f", RADIO_FIREASSIS); - break; - case "go": - sendevent("Radio", "f", RADIO_GO); - break; - case "fallback": - sendevent("Radio", "f", RADIO_FALLBACK); - break; - case "sticktog": - sendevent("Radio", "f", RADIO_STICKTOG); - break; - case "getinpos": - sendevent("Radio", "f", RADIO_COM_GETINPOS); - break; - case "stormfront": - sendevent("Radio", "f", RADIO_STORMFRONT); - break; - case "report": - sendevent("Radio", "f", RADIO_COM_REPORTIN); - break; - case "roger": - sendevent("Radio", "f", RADIO_ROGER); - break; - case "enemyspot": - sendevent("Radio", "f", RADIO_CT_ENEMYS); - break; - case "needbackup": - sendevent("Radio", "f", RADIO_CT_BACKUP); - break; - case "sectorclear": - sendevent("Radio", "f", RADIO_CLEAR); - break; - case "inposition": - sendevent("Radio", "f", RADIO_CT_INPOS); - break; - case "reportingin": - sendevent("Radio", "f", RADIO_CT_REPORTINGIN); - break; - case "getout": - sendevent("Radio", "f", RADIO_GETOUT); - break; - case "negative": - sendevent("Radio", "f", RADIO_NEGATIVE); - break; - case "enemydown": - sendevent("Radio", "f", RADIO_ENEMYDOWN); - break; + default: return (0); } diff --git a/src/client/defs.h b/src/client/defs.h index d1f835d..0017576 100644 --- a/src/client/defs.h +++ b/src/client/defs.h @@ -94,3 +94,9 @@ void HUD_DrawAmmoBar(vector pos, float val, float max, float a); void Cstrike_DrawSimpleCrosshair(void); void Cstrike_DrawScope(void); void Textmenu_Call(string); + +float +GetGameTime(void) +{ + return max(0.0f, serverkeyfloat("cs_gametime") - time); +} diff --git a/src/client/hud.qc b/src/client/hud.qc index 28e9744..0a285d9 100644 --- a/src/client/hud.qc +++ b/src/client/hud.qc @@ -127,12 +127,12 @@ HUD_DrawTimer(int NSClientSpectator) time_pos = g_hudmins + [(g_hudres[0] / 2) - 62, g_hudres[1] - 42]; } - if (getstatf(STAT_GAMETIME) == -1) { + if (GetGameTime() < -1) { return; } - iMinutes = getstatf(STAT_GAMETIME) / 60; - iSeconds = getstatf(STAT_GAMETIME) - 60 * iMinutes; + iMinutes = GetGameTime() / 60; + iSeconds = GetGameTime() - 60 * iMinutes; iTens = iSeconds / 10; iUnits = iSeconds - 10 * iTens; @@ -190,31 +190,32 @@ HUD_DrawMoney(void) { vector money_pos; float endalpha; + float moneyValue = getplayerkeyfloat(player_localnum, "*money"); money_pos = g_hudmins + [g_hudres[0] - 160, g_hudres[1] - 72]; /* if the money differs from last frame, paint it appropriately */ - if (getstati(STAT_MONEY) > pSeatLocal->m_iMoneyOld) { + if (moneyValue > pSeatLocal->m_iMoneyOld) { /* effect already in progress from something else, go add on top of it! */ if (pSeatLocal->m_flMoneyAlpha > 0) { - pSeatLocal->m_iMoneyDelta += (pSeatLocal->m_iMoneyOld - getstati(STAT_MONEY)); + pSeatLocal->m_iMoneyDelta += (pSeatLocal->m_iMoneyOld - moneyValue); } else { - pSeatLocal->m_iMoneyDelta = pSeatLocal->m_iMoneyOld - getstati(STAT_MONEY); + pSeatLocal->m_iMoneyDelta = pSeatLocal->m_iMoneyOld - moneyValue; } /* make it green for a short time */ pSeatLocal->m_vecMoneyColor = [0,1,0]; pSeatLocal->m_flMoneyAlpha = 1.0; - } else if (getstati(STAT_MONEY) < pSeatLocal->m_iMoneyOld) { + } else if (moneyValue < pSeatLocal->m_iMoneyOld) { /* same one as above */ if (pSeatLocal->m_flMoneyAlpha > 0) { - pSeatLocal->m_iMoneyDelta += (pSeatLocal->m_iMoneyOld - getstati(STAT_MONEY)); + pSeatLocal->m_iMoneyDelta += (pSeatLocal->m_iMoneyOld - moneyValue); } else { - pSeatLocal->m_iMoneyDelta = pSeatLocal->m_iMoneyOld - getstati(STAT_MONEY); + pSeatLocal->m_iMoneyDelta = pSeatLocal->m_iMoneyOld - moneyValue; } /* make it red */ pSeatLocal->m_vecMoneyColor = [1,0,0]; pSeatLocal->m_flMoneyAlpha = 1.0; - pSeatLocal->m_iMoneyDelta = pSeatLocal->m_iMoneyOld - getstati(STAT_MONEY); + pSeatLocal->m_iMoneyDelta = pSeatLocal->m_iMoneyOld - moneyValue; } /* maximum alpha is variable. */ @@ -259,7 +260,7 @@ HUD_DrawMoney(void) money_pos[0] += (24 * 5); /* draw the red/green overlay numbers on top of ours */ - HUD_DrawNums(getstati(STAT_MONEY), money_pos, endalpha, pSeatLocal->m_vecMoneyColor); + HUD_DrawNums(moneyValue, money_pos, endalpha, pSeatLocal->m_vecMoneyColor); /* draw above how much money we've lost/gotten from all this */ HUD_DrawNums(fabs(pSeatLocal->m_iMoneyDelta), money_pos + [0,-32], endalpha, pSeatLocal->m_vecMoneyColor); @@ -269,13 +270,13 @@ HUD_DrawMoney(void) /* regular number */ HUD_DrawNums( - getstati(STAT_MONEY), + moneyValue, money_pos, HUD_ALPHA - endalpha, g_hud_color ); - pSeatLocal->m_iMoneyOld = getstati(STAT_MONEY); + pSeatLocal->m_iMoneyOld = moneyValue; pSeatLocal->m_flMoneyAlpha = max(0, pSeatLocal->m_flMoneyAlpha - (clframetime * 0.5)); } @@ -345,7 +346,7 @@ HUD_DrawArmor(void) pSeatLocal->m_flArmorAlpha = HUD_ALPHA; } - if (pl.g_items & ITEM_HELMET) { + if (pl.HasItem("item_kevlar_helmet")) { drawsubpic( pos + [-80,1], [24,24], @@ -370,7 +371,7 @@ HUD_DrawArmor(void) } if (pl.armor > 0) { - if (pl.g_items & ITEM_HELMET) { + if (pl.HasItem("item_kevlar_helmet")) { drawsubpic( pos + [-80,1], [24, 24 * (pl.armor / 100)], @@ -536,13 +537,13 @@ HUD_DrawZones(void) if (pl.gflags & GF_BUYZONE) { zc++; } - if (pl.g_items & ITEM_C4BOMB) { + if (pl.HasItem("weapon_c4")) { zc++; } if (pl.gflags & GF_RESCUEZONE) { zc++; } - if (pl.g_items & ITEM_DEFUSAL) { + if (pl.HasItem("item_defuse")) { zc++; } @@ -561,7 +562,7 @@ HUD_DrawZones(void) ); pos[1] += 32; } - if (pl.g_items & ITEM_C4BOMB) { + if (pl.HasItem("item_defuse")) { bool isRed = false; if (pl.gflags & GF_BOMBZONE) { @@ -607,7 +608,7 @@ HUD_DrawZones(void) ); pos[1] += 32; } - if (pl.g_items & ITEM_DEFUSAL) { + if (pl.HasItem("item_defuse")) { drawsubpic( pos, [32,32], @@ -695,17 +696,13 @@ HUD_PlayerNames(void) float own_team = getplayerkeyfloat(player_localnum, "*team"); string strAlliance; - if ((own_team == TEAM_CT || own_team == TEAM_VIP) && - (player_team == TEAM_VIP || player_team == TEAM_CT)) { - strAlliance = "Friend"; + if (own_team != player_team) { + strAlliance = "Enemy"; } else { - if (own_team != player_team) { - strAlliance = "Enemy"; - } else { - strAlliance = "Friend"; - } + strAlliance = "Friend"; } + if (player_team == TEAM_T) { Font_DrawText(vecTextPos, sprintf("%s%s: %s", \ HUD_GetChatColorHEX (TEAM_T), strAlliance, getplayerkeyvalue(player_num, "name")), FONT_CON); diff --git a/src/client/hud_ammonotify.qc b/src/client/hud_ammonotify.qc index a161404..6e3f43b 100644 --- a/src/client/hud_ammonotify.qc +++ b/src/client/hud_ammonotify.qc @@ -99,7 +99,7 @@ HUD_AmmoNotify_Insert(int type, int count) /* called whenever we should check for pickup updates */ void -HUD_AmmoNotify_Check(CSPlayer pl) +HUD_AmmoNotify_Check(NSClientPlayer pl) { #if 0 HUD_AmmoNotify_Insert(0, pl.ammo_50ae - pl.ammo_50ae_net); @@ -116,4 +116,9 @@ HUD_AmmoNotify_Check(CSPlayer pl) HUD_AmmoNotify_Insert(11, pl.ammo_fbgrenade - pl.ammo_fbgrenade_net); HUD_AmmoNotify_Insert(12, pl.ammo_smokegrenade - pl.ammo_smokegrenade_net); #endif +} + +void +HUD_ItemNotify_Check(NSClientPlayer pl) +{ } \ No newline at end of file diff --git a/src/client/init.qc b/src/client/init.qc index 72efe0d..ec1038d 100644 --- a/src/client/init.qc +++ b/src/client/init.qc @@ -36,76 +36,6 @@ ClientGame_Init(float apilevel, string enginename, float engineversion) registercommand("drop"); registercommand("nightvision"); - /* pistols */ - registercommand("glock"); - registercommand("usp"); - registercommand("p228"); - registercommand("deagle"); - registercommand("fn57"); - registercommand("elites"); - - /* shotties */ - registercommand("m3"); - registercommand("xm1014"); - - /* smg */ - registercommand("tmp"); - registercommand("mac10"); - registercommand("mp5"); - registercommand("ump45"); - - /* rifles */ - registercommand("p90"); - registercommand("ak47"); - registercommand("m4a1"); - registercommand("sg552"); - registercommand("aug"); - registercommand("scout"); - registercommand("sg550"); - registercommand("awp"); - registercommand("g3sg1"); - - /* lonely */ - registercommand("m249"); - - /* ammo */ - registercommand("primammo"); - registercommand("buyammo1"); - registercommand("secammo"); - registercommand("buyammo2"); - - /* equipment */ - registercommand("vest"); - registercommand("vesthelm"); - registercommand("flash"); - registercommand("hegren"); - registercommand("vsgren"); - registercommand("defuser"); - registercommand("nvg"); - - /* radio */ - registercommand("coverme"); - registercommand("takepoint"); - registercommand("holdpos"); - registercommand("regroup"); - registercommand("followme"); - registercommand("takingfire"); - registercommand("go"); - registercommand("fallback"); - registercommand("sticktog"); - registercommand("getinpos"); - registercommand("stormfront"); - registercommand("report"); - registercommand("roger"); - registercommand("enemyspot"); - registercommand("needbackup"); - registercommand("sectorclear"); - registercommand("inposition"); - registercommand("reportingin"); - registercommand("getout"); - registercommand("negative"); - registercommand("enemydown"); - /* hud */ registercommand("lastinv"); registercommand("invnext"); diff --git a/src/client/progs.src b/src/client/progs.src index 4a10522..73a5c38 100644 --- a/src/client/progs.src +++ b/src/client/progs.src @@ -1,11 +1,10 @@ #pragma target fte_5768 //#pragma flag enable assumeint -#pragma progs_dat "../../zpak001.pk3dir/csprogs.dat" +#pragma progs_dat "../../csprogs.dat" #define CSQC #define CLIENT #define CSTRIKE -#define CLASSIC_VGUI #includelist ../../../src/shared/fteextensions.qc diff --git a/src/client/textmenu.qc b/src/client/textmenu.qc index 9ca20a8..9b19efc 100644 --- a/src/client/textmenu.qc +++ b/src/client/textmenu.qc @@ -20,12 +20,14 @@ TEAM_SELECT(int n) switch (n) { case 1: Textmenu_Call("TERRORIST_SELECT"); + localcmd("cmd joinTeam 1\n"); break; case 2: Textmenu_Call("CT_SELECT"); + localcmd("cmd joinTeam 2\n"); break; case 5: - sendevent("JoinAuto", ""); + localcmd("cmd joinTeam 9\n"); Textmenu_Call(""); break; } @@ -33,55 +35,54 @@ TEAM_SELECT(int n) void TERRORIST_SELECT(int n) { + if (n == 5) + n = floor(random(1, 5)); + switch (n) { case 1: - sendevent("JoinTeam", "f", 1); + localcmd("cmd terror\n"); Textmenu_Call(""); break; case 2: - sendevent("JoinTeam", "f", 2); + localcmd("cmd leet\n"); Textmenu_Call(""); break; case 3: - sendevent("JoinTeam", "f", 3); + localcmd("cmd arctic\n"); Textmenu_Call(""); break; case 4: - sendevent("JoinTeam", "f", 4); - Textmenu_Call(""); - break; - case 5: - sendevent("JoinTeam", "f", floor(random(1,5))); + localcmd("cmd guerilla\n"); Textmenu_Call(""); break; } } void -CT_SELECT(int n) +CT_SELECT(int classSelection) { - switch (n) { + if (classSelection == 5) + classSelection = floor(random(1, 5)); + + switch (classSelection) { case 1: - sendevent("JoinTeam", "f", 5); + localcmd("cmd urban\n"); Textmenu_Call(""); break; case 2: - sendevent("JoinTeam", "f", 6); + localcmd("cmd gsg9\n"); Textmenu_Call(""); break; case 3: - sendevent("JoinTeam", "f", 7); + localcmd("cmd sas\n"); Textmenu_Call(""); break; case 4: - sendevent("JoinTeam", "f", 8); - Textmenu_Call(""); - break; - case 5: - sendevent("JoinTeam", "f", floor(random(1,5))); + localcmd("cmd gign\n"); Textmenu_Call(""); break; } } + void BUY(int n) { diff --git a/src/client/vgui_changeclass_ct.qc b/src/client/vgui_changeclass_ct.qc index 5c532fa..f471a6b 100644 --- a/src/client/vgui_changeclass_ct.qc +++ b/src/client/vgui_changeclass_ct.qc @@ -59,7 +59,21 @@ CSClassButtonCT::OnMouseUp(void) if (classSelection == 5) classSelection = floor(random(1, 5)); - sendevent("JoinTeam", "f", (float)classSelection + 4); + switch (classSelection) { + case 1: + localcmd("cmd urban\n"); + break; + case 2: + localcmd("cmd gsg9\n"); + break; + case 3: + localcmd("cmd sas\n"); + break; + case 4: + localcmd("cmd gign\n"); + break; + } + winClassSelectionCT.Hide(); } @@ -193,4 +207,4 @@ VGUI_ChooseClassCT(void) winClassSelectionCT.Show(); winClassSelectionCT.SetPos((g_vidsize / 2) - (winClassSelectionCT.GetSize() / 2)); -} \ No newline at end of file +} diff --git a/src/client/vgui_changeclass_t.qc b/src/client/vgui_changeclass_t.qc index bbe07d3..e08a9d8 100644 --- a/src/client/vgui_changeclass_t.qc +++ b/src/client/vgui_changeclass_t.qc @@ -60,7 +60,21 @@ CSClassButtonT::OnMouseUp(void) if (classSelection == 5) classSelection = floor(random(1, 5)); - sendevent("JoinTeam", "f", (float)classSelection); + switch (classSelection) { + case 1: + localcmd("cmd terror\n"); + break; + case 2: + localcmd("cmd leet\n"); + break; + case 3: + localcmd("cmd arctic\n"); + break; + case 4: + localcmd("cmd guerilla\n"); + break; + } + winClassSelection.Hide(); } @@ -194,4 +208,4 @@ VGUI_ChooseClassT(void) winClassSelection.Show(); winClassSelection.SetPos((g_vidsize / 2) - (winClassSelection.GetSize() / 2)); -} \ No newline at end of file +} diff --git a/src/client/vgui_chooseteam.qc b/src/client/vgui_chooseteam.qc index e5cb099..b8b6541 100644 --- a/src/client/vgui_chooseteam.qc +++ b/src/client/vgui_chooseteam.qc @@ -73,24 +73,23 @@ VGUI_ChooseTeam(void) static VGUILabel lblMapInfo; static void VGUI_ChooseTeam_CT(void) { + localcmd("cmd joinTeam 2\n"); VGUI_ChooseClassCT(); winChooseTeam.Hide(); } static void VGUI_ChooseTeam_T(void) { + localcmd("cmd joinTeam 1\n"); VGUI_ChooseClassT(); winChooseTeam.Hide(); } static void VGUI_ChooseTeam_Auto(void) { - if (VGUI_ChooseTeam_AutoQuery()) - VGUI_ChooseTeam_CT(); - else - VGUI_ChooseTeam_T(); + localcmd("cmd joinTeam 9\n"); } static void VGUI_ChooseTeam_Spec(void) { - sendevent("JoinSpectator", ""); + localcmd("cmd joinTeam 1002\n"); winChooseTeam.Hide(); } diff --git a/src/client/vgui_spectator.qc b/src/client/vgui_spectator.qc index 0865717..e77ac54 100644 --- a/src/client/vgui_spectator.qc +++ b/src/client/vgui_spectator.qc @@ -40,6 +40,7 @@ CSSpectateHUD::Draw(void) string strText; int iMinutes, iSeconds; NSClientSpectator spec = (NSClientSpectator)pSeat->m_ePlayer; + float moneyValue = getplayerkeyfloat(player_localnum, "*money"); /* parts on top and bottom */ drawfill(m_vecOrigin, [m_vecSize[0], 32], [0,0,0], 0.75f, DRAWFLAG_NORMAL); @@ -70,7 +71,7 @@ CSSpectateHUD::Draw(void) #endif /* money */ - strText = sprintf("$ %i", getstati(STAT_MONEY)); + strText = sprintf("$ %d", moneyValue); flSep = stringwidth(strText, TRUE, [12,12]); if (flSep < 42) @@ -99,8 +100,8 @@ CSSpectateHUD::Draw(void) /* time display */ drawpic([flSep + 8, 15], "gfx/vgui/640_timer", [14, 14], [1,1,1], 1.0f, DRAWFLAG_NORMAL); - iMinutes = getstatf(STAT_GAMETIME) / 60; - iSeconds = getstatf(STAT_GAMETIME) - 60 * iMinutes; + iMinutes = GetGameTime() / 60; + iSeconds = GetGameTime() - 60 * iMinutes; strText = sprintf("%i:%02i", iMinutes, iSeconds); vecPos[0] = flSep + 8 + 17; vecPos[1] = g_hudmins[1] + 17; diff --git a/src/rules/Makefile b/src/rules/Makefile new file mode 100644 index 0000000..ed59d91 --- /dev/null +++ b/src/rules/Makefile @@ -0,0 +1,5 @@ +QCC=fteqcc + +all: + mkdir -pv ../../zpak001.pk3dir/progs/ + $(QCC) counterstrike.qc diff --git a/src/rules/counterstrike.qc b/src/rules/counterstrike.qc new file mode 100644 index 0000000..48f75a6 --- /dev/null +++ b/src/rules/counterstrike.qc @@ -0,0 +1,1077 @@ +/* + * Copyright (c) 2016-2024 Marco Cawthorne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#pragma PROGS_DAT "../../zpak001.pk3dir/progs/counterstrike.dat" + +#include "../../../src/server/api.h" + +#define TEAM_NONE 0i +#define TEAM_T 1i +#define TEAM_CT 2i + +typedef enum +{ + STATE_INACTIVE = 0i, + STATE_COMMENCING = 1i, + STATE_FREEZE = 2i, + STATE_ACTIVE = 3i, + STATE_END = 4i, + STATE_OVER = 5i +} csGameState_t; + +var csGameState_t g_csGameState; +var float g_cs_gametime; +var int g_csSwapTeamRoundCounter; +var int g_iEscapedTerrorists; + +/** @return If the usage of the flashlight is allowed. */ +bool +AllowFlashlight(void) +{ + return cvars.GetBool("mp_flashlight"); +} + +/** @return Number of hostages in the map. */ +int +HostageCount(void) +{ + return serverinfo.GetInteger("cs_hostages"); +} + +/** @return Number of different bomb zones/areas. Not bomb-sites. */ +int +BombZones(void) +{ + return serverinfo.GetInteger("cs_bombzones"); +} + +/** @return Number of different escape zones/areas. */ +int +EscapeZones(void) +{ + return serverinfo.GetInteger("cs_escapezones"); +} + +/** @return Number of different vip zones/areas. */ +int +VIPZones(void) +{ + return serverinfo.GetInteger("cs_vipzones"); +} + +/** @return If hostage rescue rules apply. */ +bool +IsHostageRescue(void) +{ + return (HostageCount() > 0i) ? (true) : (false); +} + +/** @return If bomb defusal rules apply. */ +bool +IsBombDefusal(void) +{ + return (BombZones() > 0i) ? (true) : (false); +} + +/** @return If escape mode rules apply. */ +bool +IsEscape(void) +{ + return (EscapeZones() > 0i) ? (true) : (false); +} + +/** @return If assassination rules apply. */ +bool +IsAssassination(void) +{ + return (VIPZones() > 0i) ? (true) : (false); +} + +/** Called to set the internal CS ruleset game state. */ +void +GameState_Set(csGameState_t newState) +{ + g_csGameState = newState; + + /* we need to be able to query it on the client. */ + serverinfo.SetInteger("cs_gamestate", newState); +} + +/** @return Current rule state. See csGameState_t for valid states. */ +csGameState_t +GameState(void) +{ + return (g_csGameState); +} + +float +GameTime(void) +{ + return (g_cs_gametime); +} + +/** @return Whether the bomb had been planted yet. */ +bool +BombHasBeenPlanted(void) +{ + return serverinfo.GetBool("cs_bombplanted"); +} + +/** @return Whether the bomb is being defused. */ +bool +BombIsBeingDefused(void) +{ + return serverinfo.GetBool("cs_bombbeingdefused"); +} + +/** @return How many rounds have been played on this map. */ +int +RoundsPlayed(void) +{ + return serverinfo.GetInteger("cs_roundsplayed"); +} + +/** @return How many hostages have been rescued this round. */ +int +HostagesRescued(void) +{ + return serverinfo.GetInteger("cs_hostagesrescued"); +} + +/** @return The desired CS round time, in seconds. */ +float +RoundTime(void) +{ + return cvars.GetFloat("mp_roundtime") * 60; +} + +/** @return The desired map time limit, in seconds. */ +float +TimeLimit(void) +{ + return cvars.GetFloat("mp_timelimit") * 60; +} + +/** @return The desired map win limit, in rounds won. */ +int +WinLimit(void) +{ + return cvars.GetInteger("mp_winlimit"); +} + +/** @return The amount of frozen time at the start of each round. */ +float +FreezeTime(void) +{ + return cvars.GetFloat("mp_freezetime"); +} + +/** @parm playerCheck Player to check the status from. +@return Whether the given player is a VIP in the Assassination mode. */ +bool +IsVIP(entity playerCheck) +{ + return userinfo.GetBool(playerCheck, "*csvip"); +} + +/** Turns a player into a bomber. Tasked to plant the bomb at a given site. +@parm targetPlayer Player to turn into a bomber. */ +void +MakeBomber(entity targetPlayer) +{ + if (!targetPlayer) { + return; + } + + ents.Input(targetPlayer, "GiveItem", "weapon_c4", targetPlayer); + /* env_message_single(pl, "Hint_you_have_the_bomb"); */ +} + +/** Turns a player into a VIP. He has to escape from the terrorist threat. +@parm targetPlayer Player to turn into a bomber. */ +void +MakeVIP(entity targetPlayer) +{ + if (!targetPlayer) { + return; + } + + userinfo.SetBool(targetPlayer, "*csvip", true); + targetPlayer.modelindex = getmodelindex(entityDef.GetString("player_vip", "model")); +} + +/** Sets the target player's T model class. Visual fluff. */ +void +SetTClass(entity targetPlayer, integer modelIndex) +{ + userinfo.SetInteger(targetPlayer, "t_class", modelIndex); +} + +/** Sets the target player's CT model class. Visual fluff. */ +void +SetCTClass(entity targetPlayer, integer modelIndex) +{ + userinfo.SetInteger(targetPlayer, "ct_class", modelIndex); +} + +/** Returns the modelindex the target player desires to use for the CT team. */ +float +GetCTModelIndex(entity targetPlayer) +{ + int classID = userinfo.GetInteger(targetPlayer, "ct_class"); + string keyName = sprintf("model_class%i", classID); + return getmodelindex(entityDef.GetString("player_counterterrorist", keyName)); +} + +/** Returns the modelindex the target player desires to use for the T team. */ +float +GetTModelIndex(entity targetPlayer) +{ + int classID = userinfo.GetInteger(targetPlayer, "t_class"); + string keyName = sprintf("model_class%i", classID); + return getmodelindex(entityDef.GetString("player_terrorist", keyName)); +} + +/** Instantiates a player into the world. Playable by the end. */ +void +SoftRespawn(entity targetPlayer) +{ + if (!targetPlayer) { + return; + } + + /* override any currently set model with the desired class model. */ + if (userinfo.GetInteger(targetPlayer, "*team") == TEAM_T) { + targetPlayer.modelindex = GetTModelIndex(targetPlayer); + + /* fallback if no "class" key is specified. */ + if (targetPlayer.modelindex == 0) { + targetPlayer.modelindex = getmodelindex(entityDef.GetString("player_terrorist", "model_class1")); + } + } else { + targetPlayer.modelindex = GetCTModelIndex(targetPlayer); + + /* fallback 2nd */ + if (targetPlayer.modelindex == 0) { + targetPlayer.modelindex = getmodelindex(entityDef.GetString("player_counterterrorist", "model_class1")); + } + } + + userinfo.SetBool(targetPlayer, "*csvip", false); + targetPlayer.health = 100; + game.TeleportToSpawn(targetPlayer); +} + +/** Instantiates a player into the world. Playable by the end. */ +void +HardRespawn(entity targetPlayer) +{ + if (!targetPlayer) { + return; + } + + /* decl transformation */ + if (userinfo.GetInteger(targetPlayer, "*team") == TEAM_CT) { + ents.ChangeToClass(targetPlayer, "player_counterterrorist"); + } else { + ents.ChangeToClass(targetPlayer, "player_terrorist"); + } + + userinfo.SetString(targetPlayer, "*icon1", ""); + SoftRespawn(targetPlayer); +} + +/** Will swap teams (and their scores) in the current map. */ +void +SwapTeams(void) +{ + int ctScore = 0i; + int tScore = 0i; + + for (entity teamPlayer = world; (teamPlayer = find(teamPlayer, ::classname, "player"));) { + if (teamPlayer.team == TEAM_CT) { + ents.Input(teamPlayer, "SetTeam", "1", world); + /*teamPlayer.charmodel -= 4;*/ + } else if (teamPlayer.team == TEAM_T) { + ents.Input(teamPlayer, "SetTeam", "2", world); + /*teamPlayer.charmodel += 4;*/ + } + } + + ctScore = teams.Score(TEAM_CT); + tScore = teams.Score(TEAM_T); + + teams.SetScore(TEAM_CT, tScore); + teams.SetScore(TEAM_T, ctScore); +} + +#include "radio.h" +#include "money.h" + +/* ROUND: related to the round timer only */ +void Round_Finished(int winningTeam, int moneyReward, bool silentRadio); +void Round_Restart(bool wipeProgress); + +/** Called when forcing a state change, with a specific count-down timer. */ +void +Round_TimerStart(float secondsLeft, int desiredState) +{ + g_cs_gametime = secondsLeft; + serverinfo.SetFloat("cs_gametime", time + secondsLeft); + + if (desiredState == STATE_FREEZE) { + GameState_Set(STATE_FREEZE); + } else if (desiredState == STATE_ACTIVE) { + GameState_Set(STATE_ACTIVE); + + if (teams.NumPlayers(TEAM_T) <= 1i || teams.NumPlayers(TEAM_CT) <= 1i) + return; + + /* if no players are present in the chosen team, force restart round */ + if (teams.NumAlivePlayers(TEAM_T) == 0i) { + Round_Finished(TEAM_CT, 3600i, false); + return; + } else if (teams.NumAlivePlayers(TEAM_CT) == 0i) { + Round_Finished(TEAM_T, 3600i, false); + return; + } + + } else if (desiredState == STATE_END) { + GameState_Set(STATE_END); + } else if (desiredState == STATE_COMMENCING) { + GameState_Set(STATE_COMMENCING); + } else if (desiredState == STATE_OVER) { + GameState_Set(STATE_OVER); + } +} + +/** This gets called whenever an objective is completed or time is up. */ +void +Round_Finished(int winningTeam, int moneyReward, bool silentRadio) +{ + if (GameState() != STATE_ACTIVE && GameState() != STATE_FREEZE) { + return; + } + + if (winningTeam == TEAM_T) { + if (silentRadio == false) { + Radio_BroadcastMessage(RADIO_TERWIN); + } + + g_csSwapTeamRoundCounter++; + teams.AddScore(TEAM_T, 1i); + } else if (winningTeam == TEAM_CT) { + if (silentRadio == false) { + Radio_BroadcastMessage(RADIO_CTWIN); + } + + g_csSwapTeamRoundCounter++; + teams.AddScore(TEAM_CT, 1i); + + /* In Bomb Defusal, if Terrorists were able to plant the bomb + * but lose the round, all Terrorists receive an $800 bonus. */ + if (BombHasBeenPlanted()) { + Money_QueTeamReward(TEAM_T, 800i); + } + } else { + if (silentRadio == false) { + Radio_BroadcastMessage(RADIO_ROUNDDRAW); + } + } + + Money_HandleRoundReward(winningTeam); + Money_QueTeamReward(winningTeam, moneyReward); + Round_TimerStart(5.0f, STATE_END); /* Round is over, 5 seconds til a new round starts. */ + + serverinfo.SetInteger("cs_hostagesrescued", 0i); + serverinfo.SetBool("cs_bombbeingdefused", false); + serverinfo.SetBool("cs_bombplanted", false); + serverinfo.SetInteger("cs_roundsplayed", serverinfo.GetInteger("cs_roundsplayed") + 1i); +} + +/** Called when the state timer ends, which was started with Round_TimerStart(). */ +void +Round_TimerEnd(void) +{ + if (IsEscape() == true) { + Round_Finished(TEAM_T, 3250i, false); + } else if (IsBombDefusal() == true) { + /* In Bomb Defusal, all Counter-Terrorists receive $3250 + * if they won running down the time. */ + Round_Finished(TEAM_CT, 3250i, false); + } else if (IsHostageRescue() == true) { + // TODO: Broadcast_Print: Hostages have not been rescued! + Round_Finished(TEAM_T, 3250i, false); + } else { + Round_Finished(TEAM_NONE, 0i, false); + } +} + +/** Run every single frame. */ +void +Round_TimerUpdate(void) +{ + /* if we've got hostages in the map... */ + if (IsHostageRescue()) { + /* and they're all rescued.... */ + if (HostagesRescued() >= HostageCount()) { + /* CTs win! */ + Round_Finished(TEAM_CT, 0i, false); + return; + } + } + + /* This map has been played enough we think */ + if (GameState() != STATE_OVER) { + if (TimeLimit() > 0i) { + if (time >= TimeLimit()) { + /* IntermissionStart(); */ + GameState_Set(STATE_OVER); + } + } + } + + /* Okay, this means that timelimit is not the only deciding factor */ + if (WinLimit() > 0i && GameState() != STATE_OVER) { + /* if either win, go end this map.*/ + if (teams.Score(TEAM_CT) >= WinLimit() || + teams.Score(TEAM_T) >= WinLimit()) { + /* IntermissionStart(); */ + } + } + + /* INACTIVE means no one is registered as a player */ + if (GameState() == STATE_INACTIVE) { + return; + } + + /* our continously running down timer */ + g_cs_gametime = bound(0.0f, g_cs_gametime - frametime, g_cs_gametime); + + //printf("%f\n", g_cs_gametime); + + /* if the round is over or the game is done with... */ + if (GameState() == STATE_COMMENCING || GameState() == STATE_END) { + if (GameTime() <= 0.0f) { + if (teams.Score(TEAM_T) == 0i && teams.Score(TEAM_CT) == 0i) { + Money_ResetTeamReward(); + Money_ResetRoundReward(); + Round_Restart(true); + } else { + if (cvars.GetBool("mp_halftime") == true && ((WinLimit() / 2i) == RoundsPlayed())) { + Money_ResetTeamReward(); + SwapTeams(); + Round_Restart(true); + } else { + Round_Restart(false); + } + } + } + return; + } + + if ((GameState() == STATE_ACTIVE) || (GameState() == STATE_FREEZE)) { + if (GameTime() <= 0.0f) { + if (GameState() == STATE_ACTIVE) { + /* 1.5 will make the T's lose if time runs out no matter what */ + if (cvars.GetBool("fcs_fix_bombtimer") == true) { + if (IsBombDefusal() == true && BombHasBeenPlanted() == true) { + return; + } + } + + Round_TimerEnd(); + Round_TimerStart(5.0f, STATE_END); /* Round is over, 5 seconds til a new round starts */ + } else { + Round_TimerStart(RoundTime(), STATE_ACTIVE); // Unfreeze + Radio_StartMessage(); + /* CSBot_RoundStart(); */ + } + } + } +} + +/** Called to forcefully respawn everything in the map, and players. */ +void +Round_Restart(bool wipeProgress) +{ + /* shall we swap teams? */ + if (cvars.GetInteger("fcs_swaponround") > 0i) { + if (g_csSwapTeamRoundCounter >= cvars.GetInteger("fcs_swaponround")) { + g_csSwapTeamRoundCounter = 0i; + SwapTeams(); + } + } + + + for (entity teamPlayer = world; (teamPlayer = find(teamPlayer, ::classname, "player"));) { + if (teamPlayer.team != TEAM_CT && teamPlayer.team != TEAM_T) { + continue; + } + + ents.Input(teamPlayer, "NotifyRoundRestarted", "", world); + + if (ents.isAlive(teamPlayer) == true && wipeProgress == false) { + SoftRespawn(teamPlayer); + } else { + HardRespawn(teamPlayer); + } + + if (wipeProgress == false) { + Money_GiveTeamReward(teamPlayer); + } else { + Money_WipeProgress(teamPlayer); + } + + ents.Input(teamPlayer, "NotifyBuyStart", "", world); + } + + /* sometimes, even when the bomb was planted, the round may end early. + so get rid of any bombs that may be on the level. */ + for (entity bombFinder = world; (bombFinder = find(bombFinder, ::classname, "item_c4"));) { + ents.Input(bombFinder, "Kill", "", world); + } + + /* Select a random Terrorist player for the bomb duty, if needed */ + if (IsBombDefusal() == true) { + MakeBomber(teams.RandomPlayer(TEAM_T)); + } + + /* if there is meant to be a VIP, select a random CT to be it */ + if (IsAssassination() == true) { + MakeVIP(teams.RandomPlayer(TEAM_CT)); + } + + /* Respawn all the entities */ + game.CleanUpMap(); + Round_TimerStart(FreezeTime(), STATE_FREEZE); + Money_ResetTeamReward(); +} + +void +Round_CheckUponDeath(entity playerCheck) +{ + /* don't count kills at this stage */ + if (GameState() == STATE_END) { + return; + } + + /* hack so that we can kill rounds. */ + if ((teams.NumAlivePlayers(TEAM_T) == 0i) && (teams.NumAlivePlayers(TEAM_CT) == 0i)) { + GameState_Set(STATE_ACTIVE); + } + + switch (GameState()) { + case STATE_INACTIVE: + case STATE_COMMENCING: + case STATE_END: + case STATE_OVER: + return; + break; + } + + if ((teams.NumAlivePlayers(TEAM_T) == 0i) && (teams.NumAlivePlayers(TEAM_CT) == 0i)) { + if (BombHasBeenPlanted() == true) { + Round_Finished(TEAM_T, 3600i, false); + } else { + Round_Finished(TEAM_NONE, 0i, false); + } + } else { + int winningTeam; + + if ((playerCheck.team == TEAM_T) && (teams.NumAlivePlayers(TEAM_T) == 0i)) { + winningTeam = TEAM_CT; + } else if ((playerCheck.team == TEAM_CT) && (teams.NumAlivePlayers(TEAM_CT) == 0i)) { + winningTeam = TEAM_T; + } else { + return; + } + + if (IsBombDefusal() == true) { + /* In Bomb Defusal, the winning team receives $3250 + * if they won by eliminating the enemy team. */ + if (BombHasBeenPlanted() == false || teams.NumAlivePlayers(TEAM_CT) == 0i) { + Round_Finished(winningTeam, 3250i, false); + } + } else { + /* In Hostage Rescue, the winning team receives $3600 + * if they won by eliminating the enemy team. */ + Round_Finished(winningTeam, 3600i, false); + } + } +} + +void +CS_CountHostages(void) +{ + int counter = 0i; + + for (entity e = world; (e = find(e, ::classname, "hostage_entity"));) { + counter++; + } + + serverinfo.SetInteger("cs_hostages", counter); +} + +void +CS_CountBombZones(void) +{ + int counter = 0i; + + for (entity e = world; (e = find(e, ::classname, "func_bomb_target"));) { + counter++; + } + + serverinfo.SetInteger("cs_bombzones", counter); +} + +void +CS_CountEscapeZones(void) +{ + int counter = 0i; + + for (entity e = world; (e = find(e, ::classname, "func_escape_zone"));) { + counter++; + } + + serverinfo.SetInteger("cs_escapezones", counter); +} + +void +CS_CountVIPZones(void) +{ + int counter = 0i; + + for (entity e = world; (e = find(e, ::classname, "func_vip_safetyzone"));) { + counter++; + } + + serverinfo.SetInteger("cs_vipzones", counter); +} + +void +CS_GoSpectator(entity targetPlayer) +{ + if (!targetPlayer) { + return; + } + + ents.ChangeToClass(targetPlayer, "spectator"); + game.TeleportToSpawn(targetPlayer); +} + +/* This player requests a spawn, usually when having chosen a team + model. */ +void +CS_RequestSpawn(entity targetPlayer) +{ + if (!targetPlayer) { + return; + } + + switch (GameState()) { + /* spawn the players immediately when its in the freeze state */ + case STATE_FREEZE: + HardRespawn(targetPlayer); + + /* we're the first people to join in this state. make them bomber, vip */ + if (targetPlayer.team == TEAM_T && teams.NumAlivePlayers(TEAM_T) == 1i) { + if (IsBombDefusal() == true) { + MakeBomber(targetPlayer); + } + } else if (targetPlayer.team == TEAM_CT && teams.NumAlivePlayers(TEAM_CT) == 1i) { + if (IsAssassination() == true) { + MakeVIP(targetPlayer); + } + } + + break; + } + + /* if no players are present in the chosen team, force restart round */ + if (targetPlayer.team == TEAM_T && teams.NumAlivePlayers(TEAM_T) == 0i) { + Round_Finished(TEAM_NONE, 0i, false); + } else if (targetPlayer.team == TEAM_CT && teams.NumAlivePlayers(TEAM_CT) == 0i) { + Round_Finished(TEAM_NONE, 0i, false); + } +} + +void +CS_PlayerRemovedFromGame(entity targetPlayer) +{ + /* In Assassination, all Terrorists receive a $2500 + * reward if they won by killing the VIP. */ + if (IsVIP(targetPlayer) == true) { + Round_Finished(TEAM_T, 2500i, false); + return; + } + + Round_CheckUponDeath(targetPlayer); +} + +/* Callbacks, functions that are called from Nuclide */ +void +CodeCallback_StartGameType(void) +{ + string spawnCT; + string spawnT; + + /* players can buy these any time. so they should be precached for speed. */ + ents.Precache("player_vip"); + ents.Precache("player_terrorist"); + ents.Precache("player_counterterrorist"); + + spawnCT = entityDef.GetString("player_counterterrorist", "spawnpoint"); + spawnT = entityDef.GetString("player_terrorist", "spawnpoint"); + + /* let Nuclide decide which motd to read */ + motd.LoadDefault(); + + /* the only teams CS will ever need... ? */ + teams.SetUp(TEAM_T, "Terrorist", [153, 204, 255], true); + teams.SetSpawnPoint(TEAM_T, spawnT); + teams.SetUp(TEAM_CT, "Counter-Terrorist", [255, 63, 63], true); + teams.SetSpawnPoint(TEAM_CT, spawnCT); + + /* evaluate our world */ + CS_CountHostages(); + CS_CountBombZones(); + CS_CountEscapeZones(); + CS_CountVIPZones(); + + /* create gameplay elements on top */ + if (IsHostageRescue() == true) { + if (exists.InMap("func_hostage_rescue") == false) { + for (entity testEnt = world; (testEnt = find(testEnt, ::classname, spawnCT));) { + ents.Create("info_hostage_rescue", testEnt.origin); + } + } + } + + /* we don't need to create any additional CT zones. */ + if (exists.InMap("func_buyzone") == false) { + /* since no buyzones are available, let's create one around every spawn */ + for (entity testEnt = world; (testEnt = find(testEnt, ::classname, spawnCT));) { + entity buyZone = ents.Create("info_buyzone", testEnt.origin); + buyZone.angles = testEnt.angles; + buyZone.team = TEAM_CT; + } + + for (entity testEnt = world; (testEnt = find(testEnt, ::classname, spawnT));) { + entity buyZone = ents.Create("info_buyzone", testEnt.origin); + buyZone.angles = testEnt.angles; + buyZone.team = TEAM_T; + } + } + + /* function to create spawn points for spectators. */ + other = world; + + while ((other = nextent(other))) { + switch (other.classname) { + case "info_player_start": + case "trigger_camera": + case "info_player_deathmatch": + entity specSpawn = ents.Create("info_spectator_start", other.origin); + specSpawn.angles = other.angles; + break; + default: + break; + } + } +} + +void +CodeCallback_FrameStart(void) +{ + int totalPlayers = teams.NumPlayers(TEAM_T) + teams.NumPlayers(TEAM_CT); + + /* if we suddenly have players, commence a new round. */ + if (totalPlayers > 0i && GameState() == STATE_INACTIVE) { + Round_TimerStart(2.0f, STATE_COMMENCING); + return; + } + + /* if there are 0 players whatsoever, forget most state, + so we can commence (see above) a game later. */ + if (totalPlayers == 0i) { + GameState_Set(STATE_INACTIVE); + g_cs_gametime = 0.0f; + teams.SetScore(TEAM_T, 0i); + teams.SetScore(TEAM_CT, 0i); + serverinfo.SetInteger("cs_roundsplayed", 0i); + return; + } + + /* should only ever run when players are actually present. */ + Round_TimerUpdate(); +} + +void +CodeCallback_Input(entity activator, string inputName, string dataString) +{ + switch (inputName) { + case "BombDefused": + /* In Bomb Defusal, all Counter-Terrorists receive $3600 + if they won by defusing the bomb. */ + Round_Finished(TEAM_CT, 3600i, true); + Radio_BroadcastMessage(RADIO_BOMBDEF); + break; + case "BombExploded": + /* In Bomb Defusal, all Terrorists receive $3500 + if they won by detonating the bomb. */ + Round_Finished(TEAM_T, 3500i, false); + break; + case "HostageContacted": + Money_AddMoney(activator, 150i); + break; + case "HostageKilled": + int damageDealt = stoi(dataString); + + if (damageDealt >= 100i) { + Money_AddMoney(activator, -2500i); + } else { + Money_AddMoney(activator, -500i); + } + + Radio_BroadcastMessage(RADIO_HOSDOWN); + break; + case "HostageRescued": + Radio_BroadcastMessage(RADIO_RESCUED); + serverinfo.SetInteger("cs_hostagesrescued", serverinfo.GetInteger("cs_hostagesrescued") + 1i); + + Money_AddMoney(activator, 1000i); + //CSBot_HostageRescueNotify(); + + /* In Hostage Rescue, all Counter-Terrorists receive an $850 + * bonus for every hostage that was rescued, even if they lose the round. */ + Money_QueTeamReward(TEAM_CT, 850i); + break; + case "HostageInjured": + Money_AddMoney(activator, -(stoi(dataString) * 25i)); + break; + case "Escaped": + int to_escape = teams.NumPlayers(TEAM_T); + + /* don't matter when rules are not active */ + if (GameState() != STATE_ACTIVE) { + return; + } + + g_iEscapedTerrorists++; + + if (to_escape > 3i) { + to_escape = 3i; + } + + /* balancing tweak: for every escaped T, each and every CT will lose funds */ + if (cvars.GetInteger("fcs_escapepenalty") != 0i) { + for (entity teamPlayer = world; (teamPlayer = find(teamPlayer, ::classname, "player"));) { + if (teamPlayer.team == TEAM_CT) { + Money_AddMoney(teamPlayer, cvars.GetInteger("fcs_escapepenalty")); + } + } + } + + /* mark player as spectator for the end of this 'round' */ + ents.Input(activator, "Spectate", "", world); + + /* threshold has been met to trigger the end of the round */ + if (g_iEscapedTerrorists >= to_escape) { + /* reset */ + g_iEscapedTerrorists = 0i; + + /* Ts win the round */ + Round_Finished(TEAM_T, 3600i, false); + } + break; + } +} + +int +CodeCallback_MaxItemPerSlot(int weaponSlot) +{ + /* grenades can have more */ + if (weaponSlot == 3) { + return (3); + } + + return (1); +} + +void +CodeCallback_PlayerSpawn(void) +{ + /* first course of action is to kick players into spectator cam */ + CS_GoSpectator(self); +} + +void +CodeCallback_PlayerDisconnect(void) +{ + /* if they leave, timeout, get kicked (or banned), we gotta know! */ + CS_PlayerRemovedFromGame(self); +} + +void +CodeCallback_PlayerDamage(entity inflictor, entity attacker) +{ + +} + +void +CodeCallback_PlayerKilled(entity inflictor, entity attacker, string weapon) +{ + combat.Obituary(self.netname, attacker.netname, weapon, ""); + + /* death-counter */ + self.deaths++; + + /* update player scores */ + if (ents.isPlayer(attacker)) { + if (self == attacker) { + attacker.frags--; + } else if (self.team == attacker.team) { + attacker.frags--; + Money_AddMoney(attacker, cvars.GetInteger("fcs_penalty_teamkill")); + } else { + attacker.frags++; + Money_AddMoney(attacker, cvars.GetInteger("fcs_reward_kill")); + } + } + + /* scoreboard death icon */ + if (ents.isPlayer(self)) { + userinfo.SetString(self, "*icon1", "d_skull"); + userinfo.SetString(self, "*icon1_r", "1"); + userinfo.SetString(self, "*icon1_g", "0"); + userinfo.SetString(self, "*icon1_b", "0"); + + /* turn into a fake spec */ + ents.Input(self, "Spectate", "", world); + } + + CS_PlayerRemovedFromGame(self); +} + +bool +CodeCallback_CallRequestTeam(int teamNum) +{ + /* can't switch teams while alive. */ + if (ents.isAlive(self) == true) { + return (false); + } + + /* can't switch teams while we're a VIP */ + if (IsVIP(self) == true) { + return (false); + } + + /* sanity check, invalid team ID? auto team! */ + if (teamNum != TEAM_CT && teamNum != TEAM_T) { + teamNum = teams.BestAutoJoinTeam(); + } + + switch (teamNum) { + case TEAM_T: + ents.Input(self, "SetTeam", "1", self); + break; + case TEAM_CT: + ents.Input(self, "SetTeam", "2", self); + break; + default: + CS_GoSpectator(self); + return (true); + } + + return (true); +} + +bool +CodeCallback_ClientCommand(string command) +{ + float commandArgs = tokenize(command); + + switch (argv(0)) { + /* class selection */ + case "terror": + SetTClass(self, 1); + CodeCallback_CallRequestTeam(TEAM_T); + CS_RequestSpawn(self); + break; + case "leet": + SetTClass(self, 2); + CodeCallback_CallRequestTeam(TEAM_T); + CS_RequestSpawn(self); + break; + case "arctic": + SetTClass(self, 3); + CodeCallback_CallRequestTeam(TEAM_T); + CS_RequestSpawn(self); + break; + case "guerilla": + SetTClass(self, 4); + CodeCallback_CallRequestTeam(TEAM_T); + CS_RequestSpawn(self); + break; + case "urban": + SetCTClass(self, 1); + CodeCallback_CallRequestTeam(TEAM_CT); + CS_RequestSpawn(self); + break; + case "gsg9": + SetCTClass(self, 2); + CodeCallback_CallRequestTeam(TEAM_CT); + CS_RequestSpawn(self); + break; + case "sas": + SetCTClass(self, 3); + CodeCallback_CallRequestTeam(TEAM_CT); + CS_RequestSpawn(self); + break; + case "gign": + SetCTClass(self, 4); + CodeCallback_CallRequestTeam(TEAM_CT); + CS_RequestSpawn(self); + break; + case "buy": + Money_Purchase(self, argv(1)); + break; + case "buyammo": + Money_PurchaseAmmoForSlot(self, stoi(argv(1))); + break; + default: + return (false); + } + + return (true); +} + +bool +CodeCallback_ImpulseCommand(float impulseNum) +{ + switch (impulseNum) { + /* this is how Half-Life triggers the flashlight. `impulse 100`. */ + case 100: + if (AllowFlashlight() == true) { + ents.Input(self, "UseItem", "item_suit", self); + } + break; + default: + return (false); + } + + return (true); +} diff --git a/src/rules/money.h b/src/rules/money.h new file mode 100644 index 0000000..7174344 --- /dev/null +++ b/src/rules/money.h @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2016-2024 Marco Cawthorne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +var int g_cs_moneyreward_t; +var int g_cs_moneyreward_ct; +var int g_cs_roundslost_ct; +var int g_cs_roundslost_t; +var int g_cs_winstreak_ct; +var int g_cs_winstreak_t; +var bool g_cs_bonus_ct; +var bool g_cs_bonus_t; + +void +Money_AddMoney(entity targetPlayer, int addCash) +{ + int currentCash = userinfo.GetInteger(targetPlayer, "*money"); + currentCash += addCash; + + /* clamp at the classic 160000. */ + if (currentCash > 16000i) { + currentCash = 16000i; + } else if (currentCash < 0i) { + currentCash = 0i; + } + + if (addCash > 0i) { + NSLog("Paying %s ^7$%i. Cash = $%i\n", targetPlayer.netname, addCash, currentCash); + } else if (addCash < 0i) { + NSLog("Fining %s ^7$%i. Cash = $%i\n", targetPlayer.netname, addCash, currentCash); + } + + userinfo.SetInteger(targetPlayer, "*money", currentCash); +} + +int +Money_GetCapital(entity targetPlayer) +{ + return userinfo.GetInteger(targetPlayer, "*money"); +} + +void +Money_QueTeamReward(int targetTeam, int iMoneyValue) +{ + if (targetTeam == TEAM_T) { + g_cs_moneyreward_t += iMoneyValue; + } else { + g_cs_moneyreward_ct += iMoneyValue; + } +} + +void +Money_GiveTeamReward(entity targetPlayer) +{ + if (targetPlayer.team == TEAM_T) { + Money_AddMoney(targetPlayer, g_cs_moneyreward_t); + } else { + Money_AddMoney(targetPlayer, g_cs_moneyreward_ct); + } +} + +void +Money_ResetTeamReward(void) +{ + g_cs_moneyreward_t = 0i; + g_cs_moneyreward_ct = 0i; +} + +int +Money_GetLosses(int queryTeam) +{ + if (queryTeam == TEAM_T) { + return (g_cs_roundslost_t); + } else { + return (g_cs_roundslost_ct); + } +} + +bool +Money_HasBonus(int queryTeam) +{ + if (queryTeam == TEAM_T) { + return (g_cs_bonus_t); + } else { + return (g_cs_bonus_ct); + } +} + +void +Money_HandleRoundReward(int winningTeam) +{ + int losingTeam = -1i; /* womp */ + + if (winningTeam == TEAM_CT) { + g_cs_winstreak_ct++; + g_cs_winstreak_t = 0i; + g_cs_roundslost_t++; + g_cs_roundslost_ct = 0i; + losingTeam = TEAM_T; + + if (g_cs_winstreak_ct >= 2i) { + g_cs_bonus_ct = true; + } + } else { + g_cs_winstreak_t++; + g_cs_winstreak_ct = 0i; + g_cs_roundslost_ct++; + g_cs_roundslost_t = 0i; + losingTeam = TEAM_CT; + + if (g_cs_winstreak_t >= 2i) { + g_cs_bonus_t = true; + } + } + + /* After the condition of a team winning two consecutive rounds is + * satisfied then the loss bonus money changes to above where their + * first loss means they receive $1500 and not $1400. */ + if (Money_HasBonus(losingTeam)) { + switch (Money_GetLosses(losingTeam)) { + case 1i: + Money_QueTeamReward(losingTeam, 1500i); + break; + case 2i: + Money_QueTeamReward(losingTeam, 2000i); + break; + case 3i: + Money_QueTeamReward(losingTeam, 2500i); + break; + default: + Money_QueTeamReward(losingTeam, 3000i); + break; + } + } else { + switch (Money_GetLosses(losingTeam)) { + case 1i: + Money_QueTeamReward(losingTeam, 1400i); + break; + case 2i: + Money_QueTeamReward(losingTeam, 1900i); + break; + case 3i: + Money_QueTeamReward(losingTeam, 2400i); + break; + case 4i: + Money_QueTeamReward(losingTeam, 2900i); + break; + default: + Money_QueTeamReward(losingTeam, 3400i); + break; + } + } +} + +void +Money_ResetRoundReward(void) +{ + g_cs_roundslost_ct = + g_cs_roundslost_t = + g_cs_winstreak_ct = + g_cs_winstreak_t = 0i; + g_cs_bonus_ct = + g_cs_bonus_t = false; +} + +void +Money_WipeProgress(entity targetPlayer) +{ + userinfo.SetInteger(targetPlayer, "*money", 0i); + Money_AddMoney(targetPlayer, cvars.GetInteger("mp_startmoney")); +} + +void +Money_PurchaseAmmoForSlot(entity customer, int slot) +{ + string inventory = actor.GetInventory(customer); + + /* we get to iterate over the whole inventory */ + for (int i = 0; i < tokenize(inventory); i++) { + string declName = argv(i); + int slotNum = entityDef.GetInteger(declName, "hudSlot"); + string ammoType = entityDef.GetString(declName, "ammoType"); + + /* validity check */ + if (slotNum != slot || !STRING_SET(ammoType)) { + continue; + } + + /* we found a weapon that will get filled up. */ + int itemPrice = entityDef.GetInteger(ammoType, "price"); + int ammoAmount = entityDef.GetInteger(ammoType, strcat("inv_", ammoType)); + int ammoID = ammo.NumForName(ammoType); + + /* invalid weapon. */ + if (itemPrice <= 0i || ammoAmount <= 0i) { + return; + } + + /* as long as we're not full... */ + while (actor.MaxAmmo(customer, ammoID) == false) { + /* and we can afford it... */ + if ((Money_GetCapital(customer) - itemPrice) >= 0) { + ents.Input(customer, "GiveAmmo", sprintf("%s %i", ammoType, ammoAmount), world); + Money_AddMoney(customer, -itemPrice); + } else { + break; + } + } + } +} + +void +Money_Purchase(entity customer, string desiredItem) +{ + int itemPrice = entityDef.GetInteger(desiredItem, "price"); + + /* no free things in CS */ + if (itemPrice <= 0i) { + return; + } + + if ((Money_GetCapital(customer) - itemPrice) >= 0) { + ents.Input(customer, "GiveItem", desiredItem, world); + Money_AddMoney(customer, -itemPrice); + } +} diff --git a/src/rules/radio.h b/src/rules/radio.h new file mode 100644 index 0000000..28e00dc --- /dev/null +++ b/src/rules/radio.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2016-2020 Marco Cawthorne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "../shared/radio.h" +#include "../shared/events.h" + +/* +================= +Radio_BroadcastMessage + +A global radio message for all players +================= +*/ +void +Radio_BroadcastMessage(float fMessage) +{ + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, EV_RADIOMSG); + WriteByte(MSG_MULTICAST, fMessage); + msg_entity = self; + multicast([0,0,0], MULTICAST_ALL); +} + +/* +================= +Radio_TeamMessage + +A radio message targetted at members of a specific team +================= +*/ +void +Radio_TeamMessage(float fMessage, float fTeam) +{ + for (entity teamPlayer = world; (teamPlayer = find(teamPlayer, classname, "player"));) { + if (teamPlayer.team == fTeam) { + ents.Input(teamPlayer, "RadioMessage", ftos(fMessage), world); + } + } +} + +/* +================= +Radio_DefaultStart + +Pick a generic, random radio string for global start messages +================= +*/ +float +Radio_DefaultStart(void) +{ + float fRand = floor(random(1, 4)); + + if (fRand == 1) { + return RADIO_MOVEOUT; + } else if (fRand == 2) { + return RADIO_LOCKNLOAD; + } else { + return RADIO_LETSGO; + } +} + +/* +================= +Radio_StartMessage + +Decide which startmessage to play at the beginning of each round +================= +*/ +void +Radio_StartMessage(void) +{ + if (IsAssassination()) { + Radio_TeamMessage(RADIO_VIP, TEAM_CT); + Radio_TeamMessage(Radio_DefaultStart(), TEAM_T); + } else if (IsEscape()) { + Radio_TeamMessage(RADIO_GETOUT, TEAM_T); + Radio_TeamMessage(Radio_DefaultStart(), TEAM_CT); + } else { + Radio_BroadcastMessage(Radio_DefaultStart()); + } +} + +/* +================= +CSEv_Radio_f + +Triggered by clients, plays a message to members of the same team +================= +*/ +void +CSEv_Radio_f(float fMessage) +{ + // Don't allow spamming + /*if (self.fRadioFinished > time) { + return; + }*/ + + // When dead, don't talk + if (self.health <= 0) { + return; + } + + for (entity teamPlayer = world; (teamPlayer = find(teamPlayer, classname, "player"));) { + ents.Input(teamPlayer, "RadioTeamMessage", sprintf("%d %d", num_for_edict(teamPlayer) - 1, fMessage), world); + } + + /*self.fRadioFinished = time + 3.0f;*/ +} diff --git a/src/server/ammo.h b/src/server/ammo.h deleted file mode 100644 index d106df1..0000000 --- a/src/server/ammo.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2016-2020 Marco Cawthorne - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -void Ammo_BuyPrimary(NSClientPlayer pl, int free); -void Ammo_BuySecondary(NSClientPlayer pl, int free); -void Ammo_AutoFill(NSClientPlayer); diff --git a/src/server/ammo.qc b/src/server/ammo.qc deleted file mode 100644 index be622f2..0000000 --- a/src/server/ammo.qc +++ /dev/null @@ -1,349 +0,0 @@ -/* - * Copyright (c) 2016-2020 Marco Cawthorne - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* Ammo information courtesy of https://wiki.alliedmods.net/CS_weapons_information */ - -enum -{ - CALIBER_NONE, - CALIBER_50AE, - CALIBER_762MM, - CALIBER_556MM, - CALIBER_556MMBOX, - CALIBER_338MAG, - CALIBER_9MM, - CALIBER_BUCKSHOT, - CALIBER_45ACP, - CALIBER_357SIG, - CALIBER_57MM -}; - -typedef struct -{ - int a_size; - int a_max; - int price; -} ammoinfo_t; - -#if 0 -ammoinfo_t cs_ammoinfo[11] = { - /* CALIBER_NONE */ - { - .a_size = 0, - .a_max = 0, - .price = 0 - }, - /* CALIBER_50AE */ - { - .a_size = 7, - .a_max = AMMO_MAX_50AE, - .price = 40 - }, - /* CALIBER_762MM */ - { - .a_size = 30, - .a_max = AMMO_MAX_762MM, - .price = 80 - }, - /* CALIBER_556MM */ - { - .a_size = 30, - .a_max = AMMO_MAX_556MM, - .price = 60 - }, - /* CALIBER_556MMBOX */ - { - .a_size = 30, - .a_max = AMMO_MAX_556MMBOX, - .price = 60 - }, - /* CALIBER_338MAG */ - { - .a_size = 10, - .a_max = AMMO_MAX_338MAG, - .price = 125 - }, - /* CALIBER_9MM */ - { - .a_size = 30, - .a_max = AMMO_MAX_9MM, - .price = 20 - }, - /* CALIBER_BUCKSHOT */ - { - .a_size = 8, - .a_max = AMMO_MAX_BUCKSHOT, - .price = 65 - }, - /* CALIBER_45ACP */ - { - .a_size = 12, - .a_max = AMMO_MAX_45ACP, - .price = 25 - }, - /* CALIBER_357SIG */ - { - .a_size = 13, - .a_max = AMMO_MAX_357SIG, - .price = 50 - }, - /* CALIBER_57MM */ - { - .a_size = 50, - .a_max = AMMO_MAX_57MM, - .price = 50 - } -}; -#endif - -int -Ammo_BuyCaliber(CSPlayer pl, int cal, int free) -{ - int *ptr_ammo = __NULL__; - int rv = 0; - -#if 0 - while (pl.money - cs_ammoinfo[cal].price > 0 || free) { - switch (cal) { - case CALIBER_50AE: - ptr_ammo = &pl.ammo_50ae; - break; - case CALIBER_762MM: - ptr_ammo = &pl.ammo_762mm; - break; - case CALIBER_556MM: - ptr_ammo = &pl.ammo_556mm; - break; - case CALIBER_556MMBOX: - ptr_ammo = &pl.ammo_556mmbox; - break; - case CALIBER_338MAG: - ptr_ammo = &pl.ammo_338mag; - break; - case CALIBER_9MM: - ptr_ammo = &pl.ammo_9mm; - break; - case CALIBER_BUCKSHOT: - ptr_ammo = &pl.ammo_buckshot; - break; - case CALIBER_45ACP: - ptr_ammo = &pl.ammo_45acp; - break; - case CALIBER_357SIG: - ptr_ammo = &pl.ammo_357sig; - break; - case CALIBER_57MM: - ptr_ammo = &pl.ammo_57mm; - break; - default: - error("Ammo_BuyCaliber: Impossible caliber definition."); - } - - if (*ptr_ammo >= cs_ammoinfo[cal].a_max) { - break; - } - - *ptr_ammo += cs_ammoinfo[cal].a_size; - - /* clamp */ - if (*ptr_ammo >= cs_ammoinfo[cal].a_max) { - *ptr_ammo = cs_ammoinfo[cal].a_max; - } - - if (!free) - Money_AddMoney(pl, -cs_ammoinfo[cal].price); - - rv = 1; - } - -#endif - return rv; -} - - -void -Ammo_BuySecondary(NSClientPlayer pp, int free) -{ -#if 0 - int cal = 0; - int ps = 0; - CSPlayer pl = (CSPlayer)pp; - - for (int i = 1; i < g_weapons.length; i++) { - if ((pl.g_items & g_weapons[i].id) && (g_weapons[i].slot == 1)) { - switch (i) { - case WEAPON_USP45: - cal = CALIBER_45ACP; - break; - case WEAPON_GLOCK18: - cal = CALIBER_9MM; - break; - case WEAPON_DEAGLE: - cal = CALIBER_50AE; - break; - case WEAPON_P228: - cal = CALIBER_357SIG; - break; - case WEAPON_ELITES: - cal = CALIBER_9MM; - break; - case WEAPON_FIVESEVEN: - cal = CALIBER_57MM; - break; - } - - if (Ammo_BuyCaliber(pl, cal, FALSE) == 1) { - ps = 1; - } - } - } - - if (ps && !free) { - Sound_Play(pl, CHAN_ITEM, "buy.ammo"); - } - Weapons_RefreshAmmo(pl); -#endif -} - -/* We want to loop through all the possible weapons in case the server - * enabled the ability to pick up more than one primary/secondary weapon */ -void -CSEv_AmmoBuySecondary(void) -{ - CSPlayer pl = (CSPlayer)self; - - CSGameRules rules = (CSGameRules)g_grMode; - if (rules.BuyingPossible(pl) == FALSE) { - return; - } - - Ammo_BuySecondary(pl, FALSE); -} - -void -Ammo_BuyPrimary(NSClientPlayer pp, int free) -{ -#if 0 - int ps = 0; - int cal = 0; - CSPlayer pl = (CSPlayer)pp; - - for (int i = 1; i < g_weapons.length; i++) { - if ((pl.g_items & g_weapons[i].id) && (g_weapons[i].slot == 0)) { - switch (i) { - case WEAPON_M3: - cal = CALIBER_BUCKSHOT; - break; - case WEAPON_XM1014: - cal = CALIBER_BUCKSHOT; - break; - case WEAPON_MP5: - cal = CALIBER_9MM; - break; - case WEAPON_P90: - cal = CALIBER_57MM; - break; - case WEAPON_UMP45: - cal = CALIBER_45ACP; - break; - case WEAPON_MAC10: - cal = CALIBER_45ACP; - break; - case WEAPON_TMP: - cal = CALIBER_9MM; - break; -#if defined(CZERO) || defined(CSSOURCE) - case WEAPON_GALIL: - cal = CALIBER_762MM; - break; - case WEAPON_FAMAS: - cal = CALIBER_762MM; - break; -#endif - case WEAPON_AK47: - cal = CALIBER_762MM; - break; - case WEAPON_SG552: - cal = CALIBER_556MM; - break; - case WEAPON_M4A1: - cal = CALIBER_556MM; - break; - case WEAPON_AUG: - cal = CALIBER_762MM; - break; - case WEAPON_SCOUT: - cal = CALIBER_762MM; - break; - case WEAPON_AWP: - cal = CALIBER_338MAG; - break; - case WEAPON_G3SG1: - cal = CALIBER_762MM; - break; - case WEAPON_SG550: - cal = CALIBER_556MM; - break; - case WEAPON_PARA: - cal = CALIBER_556MMBOX; - break; - } - - if (Ammo_BuyCaliber(pl, cal, free) == 1) { - ps = 1; - } - } - } - - if (ps && !free) { - Sound_Play(pl, CHAN_ITEM, "buy.ammo"); - } - - Weapons_RefreshAmmo(pl); -#endif -} - -void -CSEv_AmmoBuyPrimary(void) -{ - CSPlayer pl = (CSPlayer)self; - - CSGameRules rules = (CSGameRules)g_grMode; - if (rules.BuyingPossible(pl) == FALSE) { - return; - } - - //Ammo_BuyPrimary(pl, FALSE); -} - -void -Ammo_AutoFill(NSClientPlayer pp) -{ - CSPlayer pl = (CSPlayer)pp; - - if (autocvar_fcs_fillweapons == FALSE) { - return; - } - - //Ammo_BuyPrimary(pl, true); - //Ammo_BuySecondary(pl, true); -} - -void -Ammo_Clear(void) -{ - -} diff --git a/src/server/armoury_entity.qc b/src/server/armoury_entity.qc index 83f6660..b78e63e 100644 --- a/src/server/armoury_entity.qc +++ b/src/server/armoury_entity.qc @@ -183,8 +183,8 @@ armoury_entity::Touch(entity eToucher) } /* we may need a helmet though */ - if (!(pl.g_items & ITEM_HELMET) && m_iID == 17) { - pl.g_items |= ITEM_HELMET; + if (pl.HasItem("item_kevlar_helmet") == false && m_iID == 17) { + pl.GiveItem("item_kevlar_helmet"); picked_up = true; } diff --git a/src/server/bot.h b/src/server/bot.h deleted file mode 100644 index 0a16ec0..0000000 --- a/src/server/bot.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2016-2021 Marco Cawthorne - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -void CSBot_BombPlantedNotify(void); -void CSBot_HostageRescueNotify(void); -void CSBot_RoundStart(void); -void CSBot_RestartRound(void); diff --git a/src/server/bot.qc b/src/server/bot.qc deleted file mode 100644 index 227ebe8..0000000 --- a/src/server/bot.qc +++ /dev/null @@ -1,587 +0,0 @@ -/* - * Copyright (c) 2016-2021 Marco Cawthorne - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/** @brief Get the absolute center pos of a entity */ -vector getEntityCenterPos(entity e) { - vector newVec; - newVec[0] = e.absmin[0] + (0.5 * (e.absmax[0] - e.absmin[0])); - newVec[1] = e.absmin[1] + (0.5 * (e.absmax[1] - e.absmin[1])); - newVec[2] = e.absmin[2] + (0.5 * (e.absmax[2] - e.absmin[2])); - return newVec; -} - -class csbot:NSBot -{ - void(void) csbot; - - /* some objectives */ - virtual void(void) RunToConfront; - virtual void(void) RunToBomb; - virtual void(int) RunToBombsite; - virtual void(void) RunToRandomBombsite; - virtual void(int) RunToEscapeZone; - virtual void(void) RunToRandomEscapeZone; - virtual void(int) RunToVIPSafetyZone; - virtual void(void) RunToRandomVIPSafetyZone; - virtual void(void) RunToHostages; - virtual void(vector, int) Roam; - - virtual void(void) CreateObjective; - virtual void(void) PostFrame; - virtual void(void) WeaponThink; - - /* helpers */ - virtual entity(string, int) GetEntityByNameAndIndex; - virtual entity(int) GetBombsiteByIndex; - virtual entity(int) GetEscapeZoneByIndex; - virtual entity(int) GetVIPSafetyZoneByIndex; - virtual void(vector, float) AimLerp; - - int m_actionIsPlanting; - int m_actionIsDefusing; - - /* Workaround: - * gflags is not yet set when CSBot_BuyStart_Shop() or CreateObjective() - * are called, so we back it up on PostFrame() and use that instead. - * Known issues it solves: - * - Check if the bot is in a Bomb Zone (gflags & GF_BOMBZONE) - * - Check if the bot is in a Buy Zone (gflags & GF_BUYZONE) */ - int m_gflagsBackup; -}; - -void -csbot::RunToConfront(void) -{ - entity t; - if (team == TEAM_T) { - t = Route_SelectRandom("info_player_start"); - } else { - t = Route_SelectRandom("info_player_deathmatch"); - } - - ChatSayTeam("Going to run to the Enemy Spawn!"); - - if (t) - RouteToPosition(t.origin); -} -/* go to the planted bomb */ -void -csbot::RunToBomb(void) -{ - entity e = world; - e = find(e, ::model, "models/w_c4.mdl"); - - if (e) { - RouteToPosition(e.origin); - ChatSayTeam("Going to run to the Bomb!"); - } -} - -/* go to given bombsite */ -void -csbot::RunToBombsite(int bombsiteIndex) -{ - entity e = GetBombsiteByIndex(bombsiteIndex); - RouteToPosition(getEntityCenterPos(e)); - ChatSayTeam(strcat("Going to run to Bomb Site ", itos(bombsiteIndex), "!")); -} - -/* go to random bombsite */ -void -csbot::RunToRandomBombsite(void) -{ - RunToBombsite(random(0, g_cs_bombzones)); -} - -/* go to given escape zone */ -void -csbot::RunToEscapeZone(int index) -{ - entity e = GetEscapeZoneByIndex(index); - RouteToPosition(getEntityCenterPos(e)); - ChatSayTeam(strcat("Going to run to Escape Zone ", itos(index), "!")); -} - -/* go to a random escape zone */ -void -csbot::RunToRandomEscapeZone(void) -{ - RunToEscapeZone(random(0, g_cs_escapezones)); -} - -/* go to given VIP Safety Zone */ -void -csbot::RunToVIPSafetyZone(int index) -{ - entity e = GetVIPSafetyZoneByIndex(index); - RouteToPosition(getEntityCenterPos(e)); - ChatSayTeam(strcat("Going to run to VIP Safety Zone ", itos(index), "!")); -} - -/* go to a random VIP Safety Zone */ -void -csbot::RunToRandomVIPSafetyZone(void) -{ - RunToVIPSafetyZone(random(0, g_cs_vipzones)); -} - -void -csbot::RunToHostages(void) -{ - entity e = world; - - e = find(e, ::classname, "hostage_entity"); - - RouteToPosition(e.origin); - ChatSayTeam("Going to run to the hostages!"); -} - -/** @brief Let the bot roam within a maximum distance from a given origin. */ -void csbot::Roam(vector roamOrigin, int maxDistance) { - /* Get random point whitin a radius from the given origin */ - int angle = random(0, 360); /* random angle. */ - int distance = random(0, maxDistance); /* random distance */ - float radian = angle * 3.145238095238 / 180; - vector randLoc = roamOrigin; - randLoc.x += sin(radian) * distance; - randLoc.y += cos(radian) * distance; - - /* Go to the random waypoint. */ - RouteToPosition(Nodes_PositionOfClosestNode(randLoc)); -} - -void -csbot::CreateObjective(void) -{ - /* Bomb defuse map */ - if (g_cs_bombzones > 0) { - /* Bomb is planted */ - if (g_cs_bombplanted) { - entity eBomb = find(world, ::model, "models/w_c4.mdl"); - if (eBomb == world) { - /* No bomb model found, but it is/was planted */ - - /* RoundOver: Bomb is defused */ - if (g_cs_gamestate == GAME_END) { - RunToRandomBombsite(); - return; - } - - /* Error */ - print("WARNING! g_cs_bombplanted == TRUE, but bomb model " - "cannot be found in the world.\n"); - return; - } - - if (team == TEAM_CT) { - if (g_cs_bombbeingdefused && m_actionIsDefusing == FALSE) { - /* Bomb is being defused but not by this bot */ - /* Go and roam the defuser */ - Roam(eBomb.origin, 300); - return; - } - - if (m_actionIsDefusing) { - if (!g_cs_bombbeingdefused) { - /* Defusing complete or somehow failed. */ - m_actionIsDefusing = FALSE; - } else { - /* Continue defusing. */ - input_buttons |= (INPUT_BUTTON5 | INPUT_BUTTON8); - input_movevalues = [0,0,0]; - button5 = input_buttons & INPUT_BUTTON5; // don't release button5 - } - } - else { - int distToBomb = floor(vlen(eBomb.origin - origin)); - if (distToBomb > 60) { - /* To far away from the bomb to defuse it, run to it! */ - RunToBomb(); - } else { - /* Aim at the bomb. */ - input_buttons |= INPUT_BUTTON8; // duck - if ((HasVFlags(VFL_ONUSABLE))) { - // Aimed at the bomb, ready to defuse! - ChatSayTeam("Defusing!"); - input_buttons |= INPUT_BUTTON5; - input_movevalues = [0,0,0]; - button5 = input_buttons & INPUT_BUTTON5; // don't release button5 - m_actionIsDefusing = TRUE; - } else { - // Do the real aiming - float flLerp = bound(0.0f, frametime * 45, 1.0f); // aim speed - AimLerp(eBomb.origin + [0, 0, -6], flLerp); - } - } - } - } - /* team == TEAM_T */ - else { - /* Let T bots roam around the planted bomb */ - Roam(eBomb.origin, 500); - } - return; - } - /* Bomb is NOT planted */ - else { - if (team == TEAM_T) { - /* T-bot: plant bomb */ - if (HasItem("weapon_c4")) { - /* We carry the bomb */ - if (m_gflagsBackup & GF_BOMBZONE) { - /* We are at a bombsite and ready to plant the bomb */ - if (GetCurrentWeapon() != "weapon_c4") { - /* TODO: REPLACE THIS WITH NSNAVAI METHOD */ - SwitchToWeapon("weapon_c4"); - //Weapons_Draw((CSPlayer)self); - } - - if (!m_actionIsPlanting) { - ChatSayTeam("Going to plant the bomb!"); - m_actionIsPlanting = TRUE; - } - - /* Workaround */ - gflags = m_gflagsBackup; - - /* Duck and plant bomb. */ - input_buttons = (INPUT_BUTTON0 | INPUT_BUTTON8); - input_movevalues = [0,0,0]; - } - else { - /* Go to a bombsite first */ - RunToRandomBombsite(); - } - return; - } - else { - /* T-bot: check if the bomb has been dropped */ - entity e = find(world, ::model, "models/w_backpack.mdl"); - if (e != world) { - /* The bomb backpack has been dropped */ - /* Go fetch dropped bomb! */ - ChatSayTeam("Arrr! Bomb on the ground, going to fetch it!"); - RouteToPosition(getEntityCenterPos(e)); - return; - } - } - } - } - } - - if (g_cs_escapezones && team == TEAM_T) { - RunToRandomEscapeZone(); - return; - } - - if (random() < 0.5 && g_cs_escapezones > 0 && team == TEAM_CT) { - RunToRandomEscapeZone(); - return; - } - - if (g_cs_vipzones > 0 && team == TEAM_CT) { - RunToRandomVIPSafetyZone(); - return; - } - - if (random() < 0.5 && g_cs_vipzones > 0 && team == TEAM_T) { - RunToRandomVIPSafetyZone(); - return; - } - - if (random() < 0.5) { - if (g_cs_hostagestotal > 0) - RunToHostages(); - if (g_cs_bombzones > 0) - RunToRandomBombsite(); - } else { - RunToConfront(); - } -} - -/** @brief Aim towards a given (vector)aimpos with a given (float)lerp speed. - * - * @note - * Copied code from nuclide botlib (inside bot::RunAI), maybe make this a - * method there, could be usefull for other stuff? - **/ -void csbot::AimLerp(vector aimpos, float flLerp) { - vector aimdir, vecNewAngles; - - vector oldAngle = v_angle; - - /* that's the old angle */ - vecNewAngles = anglesToForward(v_angle); - - /* aimdir = new final angle */ - aimdir = vectorToAngles(aimpos - origin); - - /* slowly lerp towards the final angle */ - vecNewAngles = vectorLerp(vecNewAngles, anglesToForward(aimdir), flLerp); - - /* make sure we're aiming tight */ - v_angle = vectorToAngles(vecNewAngles); - input_angles = angles = v_angle = fixAngle(v_angle); -} - -void -csbot::PostFrame(void) -{ - if (team == 0) { - CSEv_JoinAuto(); - } - - team = infokeyf(this, "*team"); - m_gflagsBackup = gflags; -}; - -void -csbot::WeaponThink(void) -{ - if (GetCurrentWeapon() == "weapon_knife") - return; - -#if FIXME - /* clip empty */ - if (a_ammo1 == 0) { - /* still got ammo left, reload! */ - if (a_ammo2 != 0) { - input_buttons &= ~INPUT_BUTTON0; - input_buttons |= INPUT_BUTTON4; - } else { - Weapons_SwitchBest(this); - } - } -#endif -}; - -/** @brief Get entity by class name and index **/ -entity -csbot::GetEntityByNameAndIndex(string name, int index) -{ - int curIndex = 0; - for (entity a = world; (a = find(a, ::classname, name));) { - if (curIndex == index) { - return a; - } - ++curIndex; - } - print("WARNING: cstrike/server/bot.qc GetEntityByNameAndIndex: no entity '", - name, "' with index ", itos(index), "!\n"); - return world; -} - -/** @brief Get bombsite entity by bombsite index - * - * @note - * When there are for example 2 bombsites (g_cs_bombzones == 2) then valid - * indexes would be 0 and 1. - * */ -entity -csbot::GetBombsiteByIndex(int index) -{ - return GetEntityByNameAndIndex("func_bomb_target", index); -} - -/** @brief Get Escape Zone entity by index **/ -entity -csbot::GetEscapeZoneByIndex(int index) -{ - return GetEntityByNameAndIndex("func_escapezone", index); -} - -/** @brief Get VIP Safety Zone entity by index **/ -entity -csbot::GetVIPSafetyZoneByIndex(int index) -{ - return GetEntityByNameAndIndex("func_vip_safetyzone", index); -} - -void -csbot::csbot(void) -{ - targetname = "_csbot_"; - team = infokeyf(this, "*team"); - m_actionIsPlanting = FALSE; - m_actionIsDefusing = FALSE; - m_gflagsBackup = 0; -} - -void -CSBot_BombPlantedNotify(void) -{ - for (entity a = world; (a = find(a, classname, "player"));) { - if (clienttype(a) != CLIENTTYPE_REAL) { - csbot targ; - targ = (csbot)a; - - if (targ.team == TEAM_T) - continue; - if (targ.health <= 0) - continue; - - targ.RunToRandomBombsite(); - } - } -} - -void -CSBot_HostageRescueNotify(void) -{ - for (entity a = world; (a = find(a, classname, "player"));) { - if (clienttype(a) != CLIENTTYPE_REAL) { - csbot targ; - targ = (csbot)a; - - if (targ.team == TEAM_T) - continue; - if (targ.health <= 0) - continue; - - targ.RunToHostages(); - } - } -} - -void -CSBot_BuyStart_Shop(void) -{ - int done = 0; - int count = 0; - CSPlayer pl = (CSPlayer)self; - - pl.team = infokeyf(pl, "*team"); - - /* Workaround */ - pl.gflags = ((csbot)pl).m_gflagsBackup; - - count = 0; - while (done != 1) { - int r = floor(random(1,17)); - - if (pl.team == TEAM_T) { - if (r == BUY_M4A1) { continue; } - if (r == BUY_AUG) { continue; } - if (r == BUY_SG550) { continue; } - if (r == BUY_FIVESEVEN) { continue; } - if (r == BUY_TMP) { continue; } - } else if (pl.team == TEAM_CT) { - if (r == BUY_AK47) { continue; } - if (r == BUY_SG552) { continue; } - if (r == BUY_G3SG1) { continue; } - if (r == BUY_ELITES) { continue; } - if (r == BUY_MAC10) { continue; } - } - - if (cs_buyprices[r] <= pl.money) { - CSEv_CSBuy_f((float)r); - done = 1; - } - count++; - - /* give it enough attempts */ - if (count > 17) - done = 1; - } - - /* CT: Random buy bomb defuse kit when enough money left */ - if (pl.team == TEAM_CT && g_cs_bombzones > 0 && - cs_buyprices[BUY_DEFUSALKIT] <= pl.money && - random() < 0.5) - { - CSEv_CSBuy_f(BUY_DEFUSALKIT); // ITEM_DEFUSAL - } - - /* need armor */ - if (pl.armor < 100) { - if (pl.money >= cs_buyprices[1]) /* kevlar and helmet */ - CSEv_CSBuy_f(BUY_VESTHELMET); - else if (pl.money >= cs_buyprices[0]) /* just kevlar */ - CSEv_CSBuy_f(BUY_VEST); - } else if (!(pl.g_items & ITEM_HELMET)) { /* we need helmet */ - if (pl.money >= 350) /* kevlar and helmet */ - CSEv_CSBuy_f(BUY_VESTHELMET); - } - -#if FIXME - /* make SURE we switch to it */ - for (int i = 0; i < g_weapons.length; i++) - if (pl.g_items & g_weapons[i].id) { - pl.activeweapon = i; - Weapons_Draw(pl); - return; - } -#endif - - /* force buy right now */ - CSEv_CSBuy_f(BUY_PRIMARYAMMO); - CSEv_CSBuy_f(BUY_SECONDARYAMMO); -} - -void -CSBot_BuyStart(void) -{ - for (entity a = world; (a = find(a, classname, "player"));) { - if (clienttype(a) != CLIENTTYPE_REAL) { - if (a.health <= 0) - continue; - - a.think = CSBot_BuyStart_Shop; - a.nextthink = time + random(0, autocvar_mp_freezetime); - } - } -} - -void -CSBot_RoundStart(void) -{ - /* if (g_cs_bombzones <= 0) { - return; - } - for (entity a = world; (a = find(a, classname, "player"));) { - if (clienttype(a) != CLIENTTYPE_REAL) { - csbot targ; - targ = (csbot)a; - - if (targ.team == TEAM_T) - continue; - if (targ.health <= 0) - continue; - - targ.RunToRandomBombsite(); - } - } - } */ -} - -void -CSBot_RestartRound(void) -{ - // Reset some variables for all bots - for (entity a = world; (a = find(a, classname, "player"));) { - if (clienttype(a) != CLIENTTYPE_REAL) { - csbot targ; - targ = (csbot)a; - - if (targ.team == TEAM_T) { - targ.m_actionIsPlanting = FALSE; - } - else { - targ.m_actionIsDefusing = FALSE; - } - } - } -} diff --git a/src/server/buy.h b/src/server/buy.h deleted file mode 100644 index 15cae04..0000000 --- a/src/server/buy.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2016-2021 Marco Cawthorne - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* values courtesy of https://wiki.alliedmods.net/Cs_weapons_information */ -int cs_buyprices[] = -{ - 0, /* WEAPON_NONE */ - 1700, /* WEAPON_M3 */ - 3000, /* WEAPON_XM1014 */ - 1500, /* WEAPON_MP5 */ - 2350, /* WEAPON_P90 */ - 1700, /* WEAPON_UMP45 */ - 1400, /* WEAPON_MAC10 */ - 1250, /* WEAPON_TMP */ - 2500, /* WEAPON_AK47 */ - 3500, /* WEAPON_SG552 */ - 3100, /* WEAPON_M4A1 */ - 3500, /* WEAPON_AUG */ - 2750, /* WEAPON_SCOUT */ - 4750, /* WEAPON_AWP */ - 5000, /* WEAPON_G3SG1 */ - 4200, /* WEAPON_SG550 */ - 5750, /* WEAPON_PARA */ - 500, /* WEAPON_USP45 */ - 400, /* WEAPON_GLOCK18 */ - 650, /* WEAPON_DEAGLE */ - 600, /* WEAPON_P228 */ - 800, /* WEAPON_ELITES */ - 750, /* WEAPON_FIVESEVEN */ - 0, /* WEAPON_KNIFE */ - 300, /* WEAPON_HEGRENADE */ - 200, /* WEAPON_FLASHBANG */ - 300, /* WEAPON_SMOKEGRENADE */ - 0, /* WEAPON_C4BOMB */ - 0, /* padding */ - 0, /* padding */ - 650, /* Kevlar Vest */ - 1000, /* Kevlar Vest & Helmet */ - 200, /* Defuse Kit */ - 1250 /* NightVision Goggles */ -}; - -void CSEv_CSBuy_f(float itemID); diff --git a/src/server/buy.qc b/src/server/buy.qc deleted file mode 100644 index 7648733..0000000 --- a/src/server/buy.qc +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) 2016-2020 Marco Cawthorne - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -void -CSEv_CSBuy_f(float fWeapon) -{ -#if 0 - CSGameRules rules = (CSGameRules)g_grMode; - - int iWeapon; - CSPlayer pl = (CSPlayer)self; - iWeapon = (int)fWeapon; - - if (rules.BuyingPossible(pl) == FALSE) { - return; - } - - if (pl.team == TEAM_T) { - if (iWeapon == WEAPON_M4A1) { return; } - if (iWeapon == WEAPON_AUG) { return; } - if (iWeapon == WEAPON_SG550) { return; } - if (iWeapon == WEAPON_FIVESEVEN) { return; } - if (iWeapon == WEAPON_TMP) { return; } - } else if (pl.team == TEAM_CT) { - if (iWeapon == WEAPON_AK47) { return; } - if (iWeapon == WEAPON_SG552) { return; } - if (iWeapon == WEAPON_G3SG1) { return; } - if (iWeapon == WEAPON_ELITES) { return; } - if (iWeapon == WEAPON_MAC10) { return; } - } - - if (Weapons_IsPresent(pl, iWeapon)) - return; - - if ((pl.money - g_cstrikeWeaponPrice[iWeapon]) >= 0) { - /* let's check if we've got a limit */ - int maxit; - maxit = rules.MaxItemPerSlot(g_weapons[iWeapon].slot); - if (maxit > 0) { - int wantslot = g_weapons[iWeapon].slot; - int c = 0; - for (int i = 0; i < g_weapons.length; i++) { - if (pl.g_items & g_weapons[i].id && g_weapons[i].slot == wantslot) { - c++; - - /* we're over the slot limit. */ - if (c >= maxit) { - pl.activeweapon = i; - Weapon_DropCurrentWeapon(pl); - } - } - } - } - - Weapons_AddItem(pl, iWeapon, -1); - Money_AddMoney(pl, -g_cstrikeWeaponPrice[iWeapon]); - Sound_Play(pl, CHAN_ITEM, "buy.weapon"); - - if (autocvar_fcs_fillweapons) { - if (g_weapons[iWeapon].slot == 0) - Ammo_BuyPrimary(pl, TRUE); - else if (g_weapons[iWeapon].slot == 1) - Ammo_BuySecondary(pl, TRUE); - } - } else { - //centerprint(pl, "You have insufficient funds!"); - } -#endif -} - -void -CSEv_BuyEquipment_f(float fUtil) -{ -#if 0 - CSGameRules rules = (CSGameRules)g_grMode; - - int iUtil; - CSPlayer pl = (CSPlayer)self; - iUtil = (int)fUtil; - - if (rules.BuyingPossible(pl) == FALSE) { - return; - } - - if (pl.team == TEAM_T) { - if (iUtil == 5) { return; } - } - - if ((pl.money - g_cstrikeUtilPrice[iUtil]) >= 0) { - switch (iUtil) { - case 0: - if (pl.armor >= 100) - return; - - pl.armor = 100; - Sound_Play(pl, CHAN_ITEM, "buy.kevlar"); - break; - case 1: - /* if we already have a helmet, buy just armor */ - if (pl.g_items & ITEM_HELMET && pl.armor >= 0) { - CSEv_BuyEquipment_f(0); - return; - } else if (!(pl.g_items & ITEM_HELMET) && pl.armor >= 100) { /* only need helmet, so add it */ - pl.g_items |= ITEM_HELMET; - Money_AddMoney(pl, -350); - Sound_Play(pl, CHAN_ITEM, "buy.kevlar"); - return; - } - - pl.armor = 100; - pl.g_items |= ITEM_HELMET; - Sound_Play(pl, CHAN_ITEM, "buy.kevlar"); - break; - case 2: - if (Weapons_IsPresent(pl, WEAPON_FLASHBANG)) { - if (pl.ammo_fbgrenade >= AMMO_MAX_FLASHBANG) - return; - else - pl.ammo_fbgrenade++; - } else - Weapons_AddItem(pl, WEAPON_FLASHBANG, -1); - - Sound_Play(pl, CHAN_ITEM, "buy.weapon"); - break; - case 3: - if (Weapons_IsPresent(pl, WEAPON_HEGRENADE)) { - if (pl.ammo_hegrenade >= AMMO_MAX_HENADE) - return; - else - pl.ammo_hegrenade++; - } else - Weapons_AddItem(pl, WEAPON_HEGRENADE, -1); - - Sound_Play(pl, CHAN_ITEM, "buy.weapon"); - break; - case 4: - if (Weapons_IsPresent(pl, WEAPON_SMOKEGRENADE)) { - if (pl.ammo_smokegrenade >= AMMO_MAX_SMOKE) - return; - else - pl.ammo_smokegrenade++; - } else - Weapons_AddItem(pl, WEAPON_SMOKEGRENADE, -1); - - Sound_Play(pl, CHAN_ITEM, "buy.weapon"); - break; - case 5: - if (pl.g_items & ITEM_DEFUSAL) - return; - - pl.g_items |= ITEM_DEFUSAL; - Sound_Play(pl, CHAN_ITEM, "buy.weapon"); - break; - case 6: - if (pl.m_bHasNightvision == true) - return; - - pl.m_bHasNightvision = true; - Sound_Play(pl, CHAN_ITEM, "buy.weapon"); - break; - } - Money_AddMoney(pl, -g_cstrikeUtilPrice[iUtil]); - } else { - centerprint(pl, "You have insufficient funds!"); - } -#endif -} diff --git a/src/server/defs.h b/src/server/defs.h index 64107b3..d9cafb9 100644 --- a/src/server/defs.h +++ b/src/server/defs.h @@ -14,47 +14,9 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "ammo.h" -#include "bot.h" -#include "buy.h" -#include "gamerules.h" -#include "money.h" -#include "radio.h" -#include "../../../valve/src/server/items.h" -#include "../../../valve/src/server/flashlight.h" - var int g_cstrike_buying = 0; var float g_cstrike_bombradius = 500; -var int g_cs_vipzones; -var int g_cs_escapezones; -var int g_cs_bombzones; - -var int g_cs_bombbeingdefused; -var int g_cs_bombplanted; -var int g_cs_roundswon_ct; -var int g_cs_roundswon_t; -var int g_cs_roundsplayed; - -var int g_cs_alive_t; -var int g_cs_alive_ct; - -var int g_cs_total_t; -var int g_cs_total_ct; - -var int g_total_players; - -var int g_cs_hostagesrescued; -var int g_cs_hostagestotal; -var int g_cs_roundslost_ct; -var int g_cs_roundslost_t; -var int g_cs_winstreak_ct; -var int g_cs_winstreak_t; -var int g_cs_bonus_ct; -var int g_cs_bonus_t; -var int g_cs_gamestate; -var float g_cs_gametime; - /* Counter-Strike's own cvars */ var int autocvar_mp_winlimit = 0; var int autocvar_mp_halftime = 0; diff --git a/src/server/func_bomb_target.qc b/src/server/func_bomb_target.qc index f68cfd0..31fd733 100644 --- a/src/server/func_bomb_target.qc +++ b/src/server/func_bomb_target.qc @@ -38,7 +38,6 @@ func_bomb_target:NSBrushTrigger void func_bomb_target::func_bomb_target(void) { - g_cs_bombzones++; } void @@ -54,7 +53,7 @@ func_bomb_target::Touch(entity eToucher) return; } - if (g_csMode.ShowHints() && pl.m_seenBombSite == false) { + if (serverinfo.GetBool("cs_hints") && pl.m_seenBombSite == false) { env_message_single(pl, "Hint_you_are_in_targetzone"); pl.m_seenBombSite = true; } diff --git a/src/server/func_buyzone.qc b/src/server/func_buyzone.qc index f7f883c..d161a80 100644 --- a/src/server/func_buyzone.qc +++ b/src/server/func_buyzone.qc @@ -84,7 +84,7 @@ func_buyzone::Touch(entity eToucher) if (team == 0 || team == pl.team) pl.gflags |= GF_BUYZONE; - if (g_csMode.ShowHints() == true) + if (serverinfo.GetBool("cs_hints") == true) if (pl.m_buyMessage == false) { env_message_single(pl, "Hint_press_buy_to_purchase"); pl.m_buyMessage = true; diff --git a/src/server/func_escapezone.qc b/src/server/func_escapezone.qc index cf1d6f3..0851885 100644 --- a/src/server/func_escapezone.qc +++ b/src/server/func_escapezone.qc @@ -38,7 +38,6 @@ func_escapezone:NSBrushTrigger void func_escapezone::func_escapezone(void) { - g_cs_escapezones++; } void @@ -51,51 +50,14 @@ func_escapezone::Respawn(void) void func_escapezone::Touch(entity eToucher) { - CSMultiplayerRules rule = (CSMultiplayerRules)g_grMode; - int to_escape = 0; - - rule.CountPlayers(); - to_escape = g_cs_total_t; - - /* only 3 Ts need to escape, max */ - if (to_escape > 3) - to_escape = 3; - CSPlayer pl = (CSPlayer)eToucher; - /* don't matter when rules are not active */ - if (g_cs_gamestate != GAME_ACTIVE) - return; - /* disallow the wrong players */ if (pl.classname != "player") return; if (pl.team != TEAM_T) return; - rule.m_iEscapedTerrorists++; + g_grMode.Input(eToucher, "Escaped", ""); - /* balancing tweak: for every escaped T, each and every CT will lose funds */ - if (autocvar_fcs_escapepenalty != 0) { - for (entity eFind = world; (eFind = find(eFind, ::classname, "player"));) { - CSPlayer ct = (CSPlayer)eFind; - - if (ct.team == TEAM_CT) { - Money_AddMoney(ct, autocvar_fcs_escapepenalty); - } - } - } - - /* mark player as spectator for the end of this 'round' */ - pl.MakeTempSpectator(); - pl.gflags &= ~GF_FLASHLIGHT; - - /* threshold has been met to trigger the end of the round */ - if (rule.m_iEscapedTerrorists >= to_escape) { - /* reset */ - rule.m_iEscapedTerrorists = 0; - - /* Ts win the round */ - rule.RoundOver(TEAM_T, 3600, FALSE); - } } diff --git a/src/server/func_hostage_rescue.qc b/src/server/func_hostage_rescue.qc index e15fba8..dca820d 100644 --- a/src/server/func_hostage_rescue.qc +++ b/src/server/func_hostage_rescue.qc @@ -70,15 +70,7 @@ func_hostage_rescue::Touch(entity eToucher) if (!(hosty.m_eFollowing)) return; - Radio_BroadcastMessage(RADIO_RESCUED); - g_cs_hostagesrescued++; - - Money_AddMoney((CSPlayer)hosty.m_eFollowing, 1000); - CSBot_HostageRescueNotify(); - - /* In Hostage Rescue, all Counter-Terrorists receive an $850 - * bonus for every hostage that was rescued, even if they lose the round. */ - Money_QueTeamReward(TEAM_CT, 850); + g_grMode.Input(hosty.m_eFollowing, "HostageRescued", ""); hosty.Disappear(); } diff --git a/src/server/func_vip_safetyzone.qc b/src/server/func_vip_safetyzone.qc index f588375..dab8218 100644 --- a/src/server/func_vip_safetyzone.qc +++ b/src/server/func_vip_safetyzone.qc @@ -38,7 +38,6 @@ class func_vip_safetyzone:NSBrushTrigger void func_vip_safetyzone::func_vip_safetyzone(void) { - g_cs_vipzones++; } void @@ -50,12 +49,11 @@ func_vip_safetyzone::Respawn(void) void func_vip_safetyzone::Touch(entity eToucher) { - CSMultiplayerRules rule = (CSMultiplayerRules)g_grMode; - CSPlayer pl = (CSPlayer)eToucher; if (pl.classname != "player") return; +#if 0 if (pl.team != TEAM_VIP) return; @@ -67,4 +65,5 @@ func_vip_safetyzone::Touch(entity eToucher) /* mark player as spectator for the end of this 'round' */ pl.MakeTempSpectator(); pl.gflags &= ~GF_FLASHLIGHT; +#endif } diff --git a/src/server/game_money.qc b/src/server/game_money.qc deleted file mode 100644 index b29ab41..0000000 --- a/src/server/game_money.qc +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2016-2019 Marco Cawthorne - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -void -Money_AddMoney(NSClientPlayer pp, int iMoneyValue) -{ - CSPlayer pl = (CSPlayer)pp; - dprint(sprintf("^2Money_AddMoney^7: giving %s $%i\n", pl.netname, iMoneyValue)); - pl.money += (float)iMoneyValue; - - if (pl.money > autocvar_fcs_maxmoney) { - pl.money = autocvar_fcs_maxmoney; - } - - /* Because people do tend to kill hostages... */ - if (pl.money < 0) { - pl.money = 0; - } -} - -void -Money_QueTeamReward(int t, int iMoneyValue) -{ - if (t == TEAM_T) { - g_cs_moneyreward_t += iMoneyValue; - } else { - g_cs_moneyreward_ct += iMoneyValue; - } -} - -void -Money_GiveTeamReward(NSClientPlayer pl) -{ - if (pl.team == TEAM_T) { - Money_AddMoney(pl, g_cs_moneyreward_t); - } else { - Money_AddMoney(pl, g_cs_moneyreward_ct); - } -} - -void -Money_ResetTeamReward(void) -{ - g_cs_moneyreward_t = 0; - g_cs_moneyreward_ct = 0; -} - -int -Money_GetLosses(int team) -{ - if (team == TEAM_T) { - return g_cs_roundslost_t; - } else { - return g_cs_roundslost_ct; - } -} - -int -Money_HasBonus(int team) -{ - if (team == TEAM_T) { - return g_cs_bonus_t; - } else { - return g_cs_bonus_ct; - } -} - -void -Money_HandleRoundReward(int winner) -{ - int loser = -1; - - if (winner == TEAM_CT) { - g_cs_winstreak_ct++; - g_cs_winstreak_t = 0; - g_cs_roundslost_t++; - g_cs_roundslost_ct = 0; - loser = TEAM_T; - - if (g_cs_winstreak_ct >= 2) { - g_cs_bonus_ct = TRUE; - } - } else { - g_cs_winstreak_t++; - g_cs_winstreak_ct = 0; - g_cs_roundslost_ct++; - g_cs_roundslost_t = 0; - loser = TEAM_CT; - - if (g_cs_winstreak_t >= 2) { - g_cs_bonus_t = TRUE; - } - } - - /* After the condition of a team winning two consecutive rounds is - * satisfied then the loss bonus money changes to above where their - * first loss means they receive $1500 and not $1400. */ - if (Money_HasBonus(loser)) { - switch (Money_GetLosses(loser)) { - case 1: - Money_QueTeamReward(loser, 1500); - break; - case 2: - Money_QueTeamReward(loser, 2000); - break; - case 3: - Money_QueTeamReward(loser, 2500); - break; - default: - Money_QueTeamReward(loser, 3000); - break; - } - } else { - switch (Money_GetLosses(loser)) { - case 1: - Money_QueTeamReward(loser, 1400); - break; - case 2: - Money_QueTeamReward(loser, 1900); - break; - case 3: - Money_QueTeamReward(loser, 2400); - break; - case 4: - Money_QueTeamReward(loser, 2900); - break; - default: - Money_QueTeamReward(loser, 3400); - break; - } - } -} - -void -Money_ResetRoundReward(void) -{ - g_cs_roundslost_ct = - g_cs_roundslost_t = - g_cs_winstreak_ct = - g_cs_winstreak_t = - g_cs_bonus_ct = - g_cs_bonus_t = 0; -} diff --git a/src/server/game_rules.qc b/src/server/game_rules.qc deleted file mode 100644 index 0375c53..0000000 --- a/src/server/game_rules.qc +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2016-2019 Marco Cawthorne - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* Edit this for a custom gun-game order */ -int gg_order[] = { - WEAPON_KNIFE, - WEAPON_GLOCK18, - WEAPON_USP45, - WEAPON_P228, - WEAPON_FIVESEVEN, - WEAPON_ELITES, - WEAPON_DEAGLE, - WEAPON_M3, - WEAPON_XM1014, - WEAPON_TMP, - WEAPON_MAC10, - WEAPON_MP5, - WEAPON_UMP45, - WEAPON_P90, - WEAPON_AK47, - WEAPON_SCOUT, - WEAPON_M4A1, - WEAPON_SG552, - WEAPON_AUG, - WEAPON_G3SG1, - WEAPON_SG550, - WEAPON_AWP, - WEAPON_PARA -}; - - diff --git a/src/server/gamerules.h b/src/server/gamerules.h deleted file mode 100644 index 2988265..0000000 --- a/src/server/gamerules.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2016-2020 Marco Cawthorne - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -class CSGameRules:CGameRules -{ - virtual void PlayerPreFrame(NSClientPlayer); - virtual void PlayerDeath(NSClientPlayer); - virtual void PlayerPain(NSClientPlayer); - -/* level transitions */ - virtual void LevelChangeParms(NSClientPlayer); - virtual void LevelDecodeParms(NSClientPlayer); - virtual void LevelNewParms(void); - - virtual bool BuyingPossible(NSClientPlayer); - virtual bool ShowHints(void); - - virtual bool ImpulseCommand(NSClient, float); -}; - -class CSSingleplayerRules:CSGameRules -{ - virtual string Title(void); - - /* client */ - virtual void PlayerSpawn(NSClientPlayer); - virtual void PlayerDeath(NSClientPlayer); -}; - -class CSDeathmatchRules:CSGameRules -{ - int m_iIntermission; - int m_iIntermissionTime; - string m_strTeamList; - - void(void) CSDeathmatchRules; - - virtual string Title(void); - virtual void(void) FrameStart; - virtual void(void) CheckRules; - virtual bool(void) MonstersSpawn; - - /* client */ - virtual void(NSClientPlayer) PlayerSpawn; - virtual void(NSClientPlayer) PlayerDeath; - virtual bool(NSClientPlayer, string) ConsoleCommand; - virtual bool(void) IsMultiplayer; - virtual bool(void) IsTeamplay; - virtual void(void) InitPostEnts; - virtual bool PlayerRequestRespawn(NSClientPlayer); - virtual bool ShowHints(void); -}; - -class CSMultiplayerRules:CSGameRules -{ - entity m_eLastTSpawn; - entity m_eLastCTSpawn; - - int m_iEscapedTerrorists; - int m_iSwapTeamRoundCounter; - - void CSMultiplayerRules(void); - - virtual string Title(void); - virtual void InitPostEnts(void); - virtual void FrameStart(void); - virtual void PlayerDisconnect(NSClientPlayer); - virtual void PlayerSpawn(NSClientPlayer); - virtual void PlayerPreFrame(NSClientPlayer); - virtual void PlayerDeath(NSClientPlayer); - virtual int MaxItemPerSlot(int); - virtual bool ConsoleCommand(NSClientPlayer, string); - - /* CS specific */ - virtual void CreateRescueZones(void); - virtual void CreateCTBuyzones(void); - virtual void CreateTBuyzones(void); - virtual void TimerBegin(float, int); - virtual void TimerUpdate(void); - - virtual bool BuyingPossible(NSClientPlayer); - virtual void RoundOver(int, int, int); - virtual void RestartRound(int); - virtual void DeathCheck(NSClientPlayer); - virtual void MakeBomber(NSClientPlayer); - virtual void MakeVIP(NSClientPlayer); - virtual void CountPlayers(void); - virtual void SwitchTeams(void); - virtual void TimeOut(void); - virtual bool IsTeamplay(void); - - virtual void PlayerClearWeaponry(NSClientPlayer); - virtual void PlayerMakePlayable(NSClientPlayer, int); - virtual void PlayerMakeSpectator(NSClientPlayer); - virtual void PlayerRespawn(NSClientPlayer, int); - virtual entity PlayerFindSpawn(float); - virtual void PlayerReset(NSClientPlayer); - -}; - -void CSEv_JoinAuto(void); - -CSGameRules g_csMode; diff --git a/src/server/gamerules.qc b/src/server/gamerules.qc deleted file mode 100644 index 23f765e..0000000 --- a/src/server/gamerules.qc +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2016-2021 Marco Cawthorne - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -void -CSGameRules::PlayerDeath(NSClientPlayer pl) -{ -} - -void -CSGameRules::PlayerPain(NSClientPlayer pl) -{ -} - -bool -CSGameRules::ShowHints(void) -{ - return (true); -} - -bool -CSGameRules::BuyingPossible(NSClientPlayer pl) -{ - return (false); -} - -/* we check what fields have changed over the course of the frame and network - * only the ones that have actually changed */ -void -CSGameRules::PlayerPreFrame(NSClientPlayer pp) -{ - pp.gflags &= ~GF_BUYZONE; - pp.gflags &= ~GF_RESCUEZONE; - pp.gflags &= ~GF_BOMBZONE; -} - -void -CSGameRules::LevelDecodeParms(NSClientPlayer pp) -{ - CSPlayer pl = (CSPlayer)pp; - g_landmarkpos[0] = parm1; - g_landmarkpos[1] = parm2; - g_landmarkpos[2] = parm3; - pl.angles[0] = parm4; - pl.angles[1] = parm5; - pl.angles[2] = parm6; - pl.velocity[0] = parm7; - pl.velocity[1] = parm8; - pl.velocity[2] = parm9; - pl.g_items = parm10; - pl.activeweapon = parm11; - pl.flags = parm64; - pl.gflags = parm63; - - if (pl.IsCrouching()) { - setsize(pl, VEC_CHULL_MIN, VEC_CHULL_MAX); - } else { - setsize(pl, VEC_HULL_MIN, VEC_HULL_MAX); - } -} - -void -CSGameRules::LevelChangeParms(NSClientPlayer pp) -{ - CSPlayer pl = (CSPlayer)pp; - parm1 = g_landmarkpos[0]; - parm2 = g_landmarkpos[1]; - parm3 = g_landmarkpos[2]; - parm4 = pl.angles[0]; - parm5 = pl.angles[1]; - parm6 = pl.angles[2]; - parm7 = pl.velocity[0]; - parm8 = pl.velocity[1]; - parm9 = pl.velocity[2]; - parm63 = pl.gflags; - parm64 = pl.flags; - parm10 = pl.g_items; - parm11 = pl.activeweapon; -} - -void -CSGameRules::LevelNewParms(void) -{ - parm1 = parm2 = parm3 = parm4 = parm5 = parm6 = parm7 = - parm8 = parm9 = parm10 = parm11 = parm12 = parm13 = parm14 = - parm15 = parm16 = parm17 = parm18 = parm19 = parm20 = parm21 = - parm22 = parm23 = parm24 = parm25 = parm26 = parm27 = parm28 = - parm29 = parm30 = parm31 = parm32 = parm33 = parm34 = parm35 = - parm36 = parm37 = parm38 = parm39 = parm40 = parm41 = parm42 = - parm43 = parm44 = parm45 = parm46 = parm63= 0; - parm64 = FL_CLIENT; -} - -bool -CSGameRules::ImpulseCommand(NSClient bp, float num) -{ - switch (num) { - default: - return super::ImpulseCommand(bp, num); - } - - return true; -} \ No newline at end of file diff --git a/src/server/gamerules_deathmatch.qc b/src/server/gamerules_deathmatch.qc deleted file mode 100644 index 7e6043c..0000000 --- a/src/server/gamerules_deathmatch.qc +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (c) 2016-2023 Marco Cawthorne - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -string -CSDeathmatchRules::Title(void) -{ - return "Deathmatch"; -} - -bool -CSDeathmatchRules::ShowHints(void) -{ - return (false); -} - -bool -CSDeathmatchRules::IsMultiplayer(void) -{ - return (true); -} - -bool -CSDeathmatchRules::PlayerRequestRespawn(NSClientPlayer bp) -{ - if (bp.TimeSinceDeath() > 0.5f) { - bp.ScheduleThink(PutClientInServer, 0.0f); - return (true); - } - - return (false); -} - -bool -CSDeathmatchRules::IsTeamplay(void) -{ - return cvar("mp_teamplay") == 1 ? true : false; -} - -void -CSDeathmatchRules::InitPostEnts(void) -{ - MOTD_LoadDefault(); - - forceinfokey(world, "scorepoints", "0"); - - if (IsTeamplay() == true) { - forceinfokey(world, "teams", "2"); - forceinfokey(world, "team_1", "Counter-Terrorist"); - forceinfokey(world, "teamscore_1", "0"); - forceinfokey(world, "team_2", "Terrorist"); - forceinfokey(world, "teamscore_2", "0"); - } else { - forceinfokey(world, "teams", "0"); - } -} - -void -CSDeathmatchRules::FrameStart(void) -{ - if (cvar("timelimit")) - if (time >= (cvar("timelimit") * 60)) { - IntermissionStart(); - } - - IntermissionCycle(); -} - -void -CSDeathmatchRules::CheckRules(void) -{ - /* last person who killed somebody has hit the limit */ - if (cvar("fraglimit")) - if (g_dmg_eAttacker.frags >= cvar("fraglimit")) - IntermissionStart(); -} - -void -CSDeathmatchRules::PlayerDeath(NSClientPlayer pl) -{ - /* obituary networking */ - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, EV_OBITUARY); - WriteString(MSG_MULTICAST, (g_dmg_eAttacker.netname) ? g_dmg_eAttacker.netname : g_dmg_eAttacker.classname); - WriteString(MSG_MULTICAST, pl.netname); - WriteByte(MSG_MULTICAST, g_dmg_iWeapon); - WriteByte(MSG_MULTICAST, 0); - msg_entity = world; - multicast([0,0,0], MULTICAST_ALL); - - Plugin_PlayerObituary(g_dmg_eAttacker, g_dmg_eTarget, g_dmg_iWeapon, g_dmg_iHitBody, g_dmg_iDamage); - - /* death-counter */ - pl.deaths++; - pl.SetInfoKey("*deaths", ftos(pl.deaths)); - - /* update score-counter */ - if (pl.flags & FL_CLIENT || pl.flags & FL_MONSTER) - if (g_dmg_eAttacker.flags & FL_CLIENT) { - if (pl == g_dmg_eAttacker) - g_dmg_eAttacker.frags--; - else - g_dmg_eAttacker.frags++; - } - -#if 0 - /* explode all satchels */ - s_satchel_detonate((entity)pl); - /* drop their posessions into a weaponbox item */ - weaponbox_spawn((CSPlayer)pl); -#endif - - /* either gib, or make a corpse */ - if (pl.health < -50) { - vector gibDir = vectoangles(pl.origin - g_dmg_eAttacker.origin); - float gibStrength = g_dmg_iDamage * 2.0f; - BreakModel_Entity(pl, gibDir, gibStrength); - } else { - FX_Corpse_Spawn((CSPlayer)pl, ANIM_DEATH1); - //FX_Corpse_Spawn((CSPlayer)pl, ANIM_DIESIMPLE); - } - - /* now let's make the real client invisible */ - //pl.Death(); - pl.SetTakedamage(DAMAGE_NO); - pl.gflags &= ~GF_FLASHLIGHT; - - Sound_Play(pl, CHAN_AUTO, "player.die"); - - /* force respawn */ - pl.ScheduleThink(PutClientInServer, 4.0f); - - /* have we gone over the fraglimit? */ - CheckRules(); -} - -void -CSDeathmatchRules::PlayerSpawn(NSClientPlayer pp) -{ - CSPlayer pl = (CSPlayer)pp; - /* this is where the mods want to deviate */ - entity spot; - - pl.classname = "player"; - pl.SetMaxHealth(100); - pl.SetHealth(100); - pl.SetArmor(100); - pl.SetTakedamage(DAMAGE_YES); - pl.SetSolid(SOLID_SLIDEBOX); - pl.SetMovetype(MOVETYPE_WALK); - pl.AddFlags(FL_CLIENT); - pl.viewzoom = 1.0; - - /* player model selection */ - if (IsTeamplay() == true) { - int teamCount = tokenizebyseparator(m_strTeamList, ";"); - int playerTeam = (int)pl.GetTeam(); - - /* not part of a team? pick one of the ones we have */ - /* TODO: this should sort us into the lowest team */ - if (playerTeam == 0) { - playerTeam = 1i + (int)floor(random(0, (float)teamCount)); /* teams start at 1 after all */ - pl.SetTeam(random() < 0.5 ? TEAM_CT : TEAM_T); - } - - if (playerTeam == TEAM_T) - pl.charmodel = floor(random(1,5)); - else - pl.charmodel = floor(random(5,9)); - } else { - pl.charmodel = rint(random(1,9)); - } - - switch (pl.charmodel) { - case 1: - pl.model = "models/player/terror/terror.mdl"; - break; - case 2: - pl.model = "models/player/leet/leet.mdl"; - break; - case 3: - pl.model = "models/player/arctic/arctic.mdl"; - break; - case 4: - pl.model = "models/player/guerilla/guerilla.mdl"; - break; - case 5: - pl.model = "models/player/urban/urban.mdl"; - break; - case 6: - pl.model = "models/player/gsg9/gsg9.mdl"; - break; - case 7: - pl.model = "models/player/sas/sas.mdl"; - break; - case 8: - pl.model = "models/player/gign/gign.mdl"; - break; - default: - pl.model = "models/player/vip/vip.mdl"; - } - - - pl.SetModel(pl.model); - pl.SetSize(VEC_HULL_MIN, VEC_HULL_MAX); - pl.ClearVelocity(); - pl.gravity = __NULL__; - pl.SetFrame(1); - pl.SendFlags = UPDATE_ALL; - pl.SetInfoKey("*spec", "0"); - pl.SetInfoKey("*dead", "0"); - pl.SetInfoKey("*deaths", ftos(pl.deaths)); - pl.SetPropData("actor_human"); - pl.EnableBleeding(); - - LevelNewParms(); - LevelDecodeParms(pl); - - pl.GiveItem("item_suit"); - pl.GiveItem("weapon_knife"); - -#if 0 - int randomGun = (int)rint(random(WEAPON_USP45, WEAPON_FIVESEVEN)); - //Weapons_AddItem(pl, randomGun, -1); - randomGun = (int)rint(random(WEAPON_M3, WEAPON_PARA)); - //Weapons_AddItem(pl, randomGun, -1); - pl.activeweapon = randomGun; -#endif - - Ammo_BuyPrimary(pl, TRUE); - Ammo_BuySecondary(pl, TRUE); - - spot = Spawn_SelectRandom("info_player_deathmatch"); - pl.Transport(spot.origin, spot.angles); - Client_FixAngle(pl, pl.angles); -} - -bool -CSDeathmatchRules::ConsoleCommand(NSClientPlayer pp, string cmd) -{ - tokenize(cmd); - - switch (argv(0)) { -#if 0 - case "bot_add": - bot pete = (bot)Bot_AddQuick(); - Bot_RandomColormap(pete); - searchhandle pm = search_begin("models/player/*/*.mdl", TRUE, TRUE); - int r = floor(random(0, search_getsize(pm))); - string mdl = substring(search_getfilename(pm, r), 0, -5); - tokenizebyseparator(mdl, "/"); - pete.SetInfoKey("model", argv(2)); - search_end(pm); - break; -#endif - case "jumptest": - makevectors(pp.v_angle); - traceline(pp.origin + pp.view_ofs, pp.origin + pp.view_ofs + v_forward * 1024, FALSE, pp); - pp.velocity = Route_GetJumpVelocity(pp.origin, trace_endpos, pp.gravity); - break; - default: - return (false); - } - - return (true); -} - -bool -CSDeathmatchRules::MonstersSpawn(void) -{ - return (autocvar(mp_allowmonsters, 0)) ? true : false; -} - -void -CSDeathmatchRules::CSDeathmatchRules(void) -{ - /* these lines do nothing but tell the server to register those cvars */ - autocvar(timelimit, 15, "Timelimit for multiplayer rounds"); - autocvar(fraglimit, 15, "Points limit for multiplayer rounds"); -} \ No newline at end of file diff --git a/src/server/gamerules_multiplayer.qc b/src/server/gamerules_multiplayer.qc deleted file mode 100644 index e5f0a6e..0000000 --- a/src/server/gamerules_multiplayer.qc +++ /dev/null @@ -1,1291 +0,0 @@ -/* - * Copyright (c) 2016-2021 Marco Cawthorne - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifdef CSSOURCE - #define SPAWNPOINT_CT "info_player_counterterrorist" - #define SPAWNPOINT_T "info_player_terrorist" -#else - #define SPAWNPOINT_CT "info_player_start" - #define SPAWNPOINT_T "info_player_deathmatch" -#endif - -string -CSMultiplayerRules::Title(void) -{ - return "Counter-Strike"; -} - -int -CSMultiplayerRules::MaxItemPerSlot(int slot) -{ - /* grenades */ - if (slot == 3) { - return (3); - } - return (1); -} - -void -CSMultiplayerRules::PlayerDisconnect(NSClientPlayer pl) -{ - if (health > 0) - PlayerDeath(pl); - - super::PlayerDisconnect(pl); -} - -void -CSMultiplayerRules::PlayerDeath(NSClientPlayer pl) -{ - CSPlayer targ = (CSPlayer)g_dmg_eTarget; - CSPlayer attk = (CSPlayer)g_dmg_eAttacker; - NSRenderableEntity newCorpse; - float deathAnimation = ANIM_DEATH1; - - if (targ.IsCrouching()) { - deathAnimation = ANIM_CROUCH_DIE; - } else { - switch (g_dmg_iHitBody) { - case BODY_HEAD: - deathAnimation = ANIM_DIE_HEAD; - break; - case BODY_STOMACH: - deathAnimation = ANIM_DIE_GUT; - break; - case BODY_ARMLEFT: - deathAnimation = ANIM_DIE_LEFT; - break; - case BODY_ARMRIGHT: - deathAnimation = ANIM_DIE_RIGHT; - break; - default: - bool isFacing = targ.IsFacingPosition(g_dmg_vecLocation); - - /* still want to play ANIM_DEATH1 */ - if (random() < 0.5f) { - if (isFacing == false) { - deathAnimation = ANIM_DIE_FORWARD; - } else { - deathAnimation = ANIM_DIE_BACK; - } - } - - break; - } - } - - newCorpse = (NSRenderableEntity)FX_Corpse_Spawn(targ, deathAnimation); - - targ.SpectatorDeathcam(newCorpse, attk, 3.0f); - - /* obituary networking */ - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, EV_OBITUARY); - if (g_dmg_eAttacker.netname) - WriteString(MSG_MULTICAST, strcat(HUD_GetChatColorHEX(g_dmg_eAttacker.team), g_dmg_eAttacker.netname)); - else - WriteString(MSG_MULTICAST, g_dmg_eAttacker.classname); - - WriteString(MSG_MULTICAST, strcat(HUD_GetChatColorHEX(targ.team), targ.netname)); - - WriteByte(MSG_MULTICAST, g_dmg_iWeapon); - WriteByte(MSG_MULTICAST, 0); - msg_entity = world; - multicast([0,0,0], MULTICAST_ALL); - - Plugin_PlayerObituary(g_dmg_eAttacker, g_dmg_eTarget, g_dmg_iWeapon, g_dmg_iHitBody, g_dmg_iDamage); - - /* death-counter */ - targ.deaths++; - forceinfokey(targ, "*deaths", ftos(targ.deaths)); - - /* update score-counter */ - if (isClient(g_dmg_eTarget) || isAI(g_dmg_eTarget)) - if (isClient(g_dmg_eAttacker)) { - float vip = (g_dmg_eTarget.team == TEAM_VIP && g_dmg_eAttacker.team == TEAM_CT); - - if (g_dmg_eTarget == g_dmg_eAttacker) { - g_dmg_eAttacker.frags--; - } else if (g_dmg_eTarget.team == g_dmg_eAttacker.team || vip) { - g_dmg_eAttacker.frags--; - Money_AddMoney((NSClientPlayer)g_dmg_eAttacker, autocvar_fcs_penalty_teamkill); - } else { - g_dmg_eAttacker.frags++; - Money_AddMoney((NSClientPlayer)g_dmg_eAttacker, autocvar_fcs_reward_kill); - } - } - - /* scoreboard death icon */ - if (isClient(g_dmg_eTarget)) { - targ.SetInfoKey("*icon1", "d_skull"); - targ.SetInfoKey("*icon1_r", "1"); - targ.SetInfoKey("*icon1_g", "0"); - targ.SetInfoKey("*icon1_b", "0"); - } - - /* TODO: implement this in NSNavAI */ - //targ.DropActiveWeapon(); - - ///Weapon_DropCurrentWeapon(targ); - - /* if we're the bomb carrier, make sure we drop the bomb. */ - if (targ.HasItem("weapon_c4")) { - //targ.SwitchToWeapon("weapon_c4"); - //Weapon_DropCurrentWeapon(targ); - } else { - //targ.activeweapon = Cstrike_WeaponToDropUponDeath(targ); - //Weapon_DropCurrentWeapon(targ); - } - - /* clear all ammo and inventory... */ - targ.RemoveAllWeapons(); -// targ.Death(); - targ.gflags &= ~GF_FLASHLIGHT; - targ.m_bHasNightvision = false; - - targ.StartSoundDef("Player.Death", CHAN_AUTO, true); - - /* gamerule stuff */ - targ.MakeTempSpectator(); - forceinfokey(targ, "*dead", "1"); - forceinfokey(targ, "*team", ftos(targ.team)); - CountPlayers(); - - /* In Assassination, all Terrorists receive a $2500 - * reward if they won by killing the VIP. */ - if (targ.team == TEAM_VIP) { - RoundOver(TEAM_T, 2500, FALSE); - return; - } - DeathCheck(targ); -} - -void -CSMultiplayerRules::PlayerPreFrame(NSClientPlayer pl) -{ - super::PlayerPreFrame(pl); - - /* the messages that get printed when you aim at something - happen here */ - { - vector sourcePos, destPos; - CSPlayer p = (CSPlayer)pl; - - sourcePos = pl.GetEyePos(); - destPos = sourcePos + (pl.GetForward() * 512); - traceline(sourcePos, destPos, MOVE_NORMAL, pl); - - if (trace_ent) { - if (trace_ent.classname == "player") - if (trace_ent.team == p.team && p.m_seenFriend == false) { - env_message_single(pl, "Hint_spotted_a_friend"); - p.m_seenFriend = true; - } else if (trace_ent.team != p.team && p.m_seenEnemy == false) { - env_message_single(pl, "Hint_spotted_an_enemy"); - p.m_seenEnemy = true; - } - - if (trace_ent.classname == "hostage_entity" && p.m_seenHostage == false) { - if (p.team == TEAM_T) { - env_message_single(pl, "Hint_prevent_hostage_rescue"); - } else { - env_message_single(pl, "Hint_rescue_the_hostages"); - env_message_single(pl, "Hint_press_use_so_hostage_will_follow"); - } - p.m_seenHostage = true; - } - } - } -} - -void -CSMultiplayerRules::FrameStart(void) -{ - if ((g_total_players > 0) && (g_cs_gamestate == GAME_INACTIVE)) { - TimerBegin(2, GAME_COMMENCING); - } else if (g_total_players == 0) { - g_cs_gamestate = GAME_INACTIVE; - g_cs_gametime = 0; - g_cs_roundswon_t = 0; - g_cs_roundswon_ct = 0; - g_cs_roundsplayed = 0; - } else { - TimerUpdate(); // Timer that happens once players have started joining - } -} - -void -CSMultiplayerRules::CreateRescueZones(void) -{ - int zones = 0; - - /* not in hostage rescue mode */ - if (g_cs_hostagestotal <= 0) { - return; - } - - /* count the already existing rescue zones. */ - for (entity e = world; (e = find(e, ::classname, "func_hostage_rescue"));) { - zones++; - } - - /* we don't need to create any additional rescue zones. */ - if (zones > 0) - return; - - /* hostage zones need to go somewhere */ - for (entity e = world; (e = find(e, ::classname, SPAWNPOINT_CT));) { - info_hostage_rescue newzone = spawn(info_hostage_rescue, origin: e.origin); - newzone.Respawn(); - } -} - -void -CSMultiplayerRules::CreateCTBuyzones(void) -{ - int zones = 0; - - /* count the already existing CT zones. */ - for (entity e = world; (e = find(e, ::classname, "func_buyzone"));) { - if (e.team == 0 || e.team == TEAM_CT) { - zones++; - } - } - - /* we don't need to create any additional CT zones. */ - if (zones > 0) - return; - - /* since no buyzones are available, let's create one around every CT spawn */ - for (entity e = world; (e = find(e, ::classname, SPAWNPOINT_CT));) { - info_buyzone newzone = spawn(info_buyzone, origin: e.origin); - newzone.Respawn(); - newzone.team = TEAM_CT; - } -} - -void -CSMultiplayerRules::CreateTBuyzones(void) -{ - int zones = 0; - - /* count the already existing T zones. */ - for (entity e = world; (e = find(e, ::classname, "func_buyzone"));) { - if (e.team == 0 || e.team == TEAM_T) { - zones++; - } - } - - /* we don't need to create any additional T zones. */ - if (zones > 0) - return; - - /* since no buyzones are available, let's create one around every T spawn */ - for (entity e = world; (e = find(e, ::classname, SPAWNPOINT_T));) { - info_buyzone newzone = spawn(info_buyzone, origin: e.origin); - newzone.Respawn(); - newzone.team = TEAM_T; - } -} - -void -CSMultiplayerRules::InitPostEnts(void) -{ - EntityDef_Precache("CSBasePistol"); - EntityDef_Precache("CSBaseRifle"); - EntityDef_Precache("CSBaseShotgun"); - EntityDef_Precache("weapon_ak47"); - EntityDef_Precache("weapon_aug"); - EntityDef_Precache("weapon_awp"); - EntityDef_Precache("weapon_c4"); - EntityDef_Precache("weapon_deagle"); - EntityDef_Precache("weapon_elite"); - EntityDef_Precache("weapon_famas"); - EntityDef_Precache("weapon_fiveseven"); - EntityDef_Precache("weapon_flashbang"); - EntityDef_Precache("weapon_g3sg1"); - EntityDef_Precache("weapon_galil"); - EntityDef_Precache("weapon_glock18"); - EntityDef_Precache("weapon_hegrenade"); - EntityDef_Precache("weapon_knife"); - EntityDef_Precache("weapon_m249"); - EntityDef_Precache("weapon_m3"); - EntityDef_Precache("weapon_m4a1"); - EntityDef_Precache("weapon_mac10"); - EntityDef_Precache("weapon_mp5navy"); - EntityDef_Precache("weapon_p228"); - EntityDef_Precache("weapon_p90"); - EntityDef_Precache("weapon_scout"); - EntityDef_Precache("weapon_sg550"); - EntityDef_Precache("weapon_sg552"); - EntityDef_Precache("weapon_smokegrenade"); - EntityDef_Precache("weapon_tmp"); - EntityDef_Precache("weapon_ump45"); - EntityDef_Precache("weapon_usp"); - EntityDef_Precache("weapon_xm1014"); - - MOTD_LoadDefault(); - - /* let's check if we need to create buyzones */ - switch (g_cstrike_buying) { - case BUY_CT: - CreateCTBuyzones(); - break; - case BUY_T: - CreateTBuyzones(); - break; - case BUY_NEITHER: - break; - default: - CreateCTBuyzones(); - CreateTBuyzones(); - } - - CreateRescueZones(); - - /* get all of the vip zones */ - g_cs_vipzones = 0; - for (entity e = world; (e = find(e, ::classname, "func_vip_safetyzone"));) { - g_cs_vipzones++; - } -} - -void -CSMultiplayerRules::TimerBegin(float tleft, int mode) -{ - g_cs_gametime = tleft; - - if (mode == GAME_FREEZE) { - g_cs_gamestate = GAME_FREEZE; - } else if (mode == GAME_ACTIVE) { - g_cs_gamestate = GAME_ACTIVE; - CountPlayers(); - - if (g_cs_total_t <= 1 || g_cs_total_ct <= 1) - return; - - /* if no players are present in the chosen team, force restart round */ - if ((g_cs_alive_t == 0)) { - RoundOver(TEAM_CT, 3600, FALSE); - return; - } else if (g_cs_alive_ct == 0) { - RoundOver(TEAM_T, 3600, FALSE); - return; - } - - } else if (mode == GAME_END) { - g_cs_gamestate = GAME_END; - } else if (mode == GAME_COMMENCING) { - g_cs_gamestate = GAME_COMMENCING; - } else if (mode == GAME_OVER) { - g_cs_gamestate = GAME_OVER; - } -} - -void -CSMultiplayerRules::TimerUpdate(void) -{ - /* if we've got hostages in the map... */ - if (g_cs_hostagestotal > 0) { - /* and they're all rescued.... */ - if (g_cs_hostagesrescued >= g_cs_hostagestotal) { - /* CTs win! */ - RoundOver(TEAM_CT, 0, FALSE); - return; - } - } - - /* This map has been played enough we think */ - if (g_cs_gamestate != GAME_OVER) { - if (cvar("mp_timelimit") > 0) { - if (time >= (cvar("mp_timelimit") * 60)) { - IntermissionStart(); - g_cs_gamestate = GAME_OVER; - } - } - } - - /* Okay, this means that timelimit is not the only deciding factor */ - if (autocvar_mp_winlimit > 0 && g_cs_gamestate != GAME_OVER) { - /* It really doesn't matter who won. Do some logging perhaps? */ - if (g_cs_roundswon_ct == autocvar_mp_winlimit || - g_cs_roundswon_t == autocvar_mp_winlimit) { - IntermissionStart(); - } - } - - /* INACTIVE means no one is registered as a player */ - if (g_cs_gamestate == GAME_INACTIVE) { - return; - } - - /* our continously running down timer */ - g_cs_gametime = bound(0, g_cs_gametime - frametime, g_cs_gametime); - - /* if the round is over or the game is done with... */ - if (g_cs_gamestate == GAME_COMMENCING || g_cs_gamestate == GAME_END) { - if (g_cs_gametime <= 0) { - if (g_cs_roundswon_t == 0 && g_cs_roundswon_ct == 0) { - Money_ResetTeamReward(); - Money_ResetRoundReward(); - RestartRound(TRUE); - } else { - if (autocvar_mp_halftime == TRUE && (autocvar_mp_winlimit / 2 == g_cs_roundsplayed)) { - Money_ResetTeamReward(); - SwitchTeams(); - RestartRound(TRUE); - } else { - RestartRound(FALSE); - } - } - } - return; - } - - if ((g_cs_gamestate == GAME_ACTIVE) || (g_cs_gamestate == GAME_FREEZE)) { - if (g_cs_gametime <= 0) { - if (g_cs_gamestate == GAME_ACTIVE) { - /* 1.5 will make the T's lose if time runs out no matter what */ - if (autocvar_fcs_fix_bombtimer == TRUE) { - if (g_cs_bombzones > 0 && g_cs_bombplanted == TRUE) { - return; - } - } - TimeOut(); - TimerBegin(5, GAME_END); /* Round is over, 5 seconds til a new round starts */ - } else { - TimerBegin(autocvar_mp_roundtime * 60, GAME_ACTIVE); // Unfreeze - Radio_StartMessage(); - CSBot_RoundStart(); - } - } - } -} - -/* -================= -BuyingPossible - -Checks if it is possible for players to buy anything -================= -*/ -bool -CSMultiplayerRules::BuyingPossible(NSClientPlayer pl) -{ - if (pl.IsDead()) { - return (false); - } - - if (g_cs_gamestate == GAME_ACTIVE) { - if (((autocvar_mp_roundtime * 60) - g_cs_gametime) > autocvar_mp_buytime) { - centerprint(pl, sprintf("%d seconds have passed...\nYou can't buy anything now!", autocvar_mp_buytime)); - return (false); - } - } - - if (pl.team == TEAM_VIP) { - centerprint(pl, "You are the VIP...\nYou can't buy anything!\n"); - return (false); - } - - if (g_cstrike_buying == BUY_NEITHER) { - centerprint(pl, "Sorry, you aren't meant\nto be buying anything.\n"); - return (false); - } - - if (g_cstrike_buying != BUY_BOTH) { - if (g_cstrike_buying == BUY_CT && pl.team == TEAM_T) { - centerprint(pl, "Terrorists aren't allowed to\nbuy anything on this map!\n"); - return (false); - } else if (g_cstrike_buying == BUY_T && pl.team == TEAM_CT) { - centerprint(pl, "CTs aren't allowed to buy\nanything on this map!\n"); - return (false); - } - } - - if (!(pl.gflags & GF_BUYZONE)) { - centerprint(pl, "Sorry, you aren't in a buyzone.\n"); - return (false); - } - - return (true); -} - -void -CSMultiplayerRules::MakeBomber(NSClientPlayer pl) -{ - pl.GiveItem("weapon_c4"); - env_message_single(pl, "Hint_you_have_the_bomb"); -} - -void -CSMultiplayerRules::MakeVIP(NSClientPlayer pl) -{ - pl.team = TEAM_VIP; - PlayerRespawn(pl, pl.team); - env_message_single(pl, "Hint_you_are_the_vip"); - pl.SetInfoKey("*dead", "2"); - pl.SetModel("models/player/vip/vip.mdl"); -} - -/* -================= -RestartRound - -Loop through all ents and handle them -================= -*/ -void -CSMultiplayerRules::RestartRound(int iWipe) -{ - if (autocvar_fcs_swaponround > 0) - if (m_iSwapTeamRoundCounter >= autocvar_fcs_swaponround) { - m_iSwapTeamRoundCounter = 0; - - for (entity eFind = world; (eFind = find(eFind, ::classname, "player"));) { - CSPlayer pl = (CSPlayer)eFind; - - if (pl.team == TEAM_T) { - pl.team = TEAM_CT; /* temp for CT */ - pl.charmodel += 4; - pl.health = 0; - } else if (pl.team == TEAM_VIP || pl.team == TEAM_CT) { - pl.team = TEAM_T; /* temp for CT */ - pl.charmodel -= 4; - pl.health = 0; - } - } - } - - // Reset CSBot vars - CSBot_RestartRound(); - - for (entity eFind = world; (eFind = findfloat(eFind, ::team, TEAM_T));) { - if (isClient(eFind) == false) { - continue; - } - - CSPlayer pl = (CSPlayer)eFind; - - if (pl.health > 0 && iWipe == FALSE) { - PlayerRespawn(pl, pl.team); - } else { - PlayerMakeSpectator(pl); - PlayerMakePlayable(pl, pl.charmodel); - } - - if (iWipe == FALSE) { - Money_GiveTeamReward(pl); - } else { - PlayerReset(pl); - } - } - for (entity eFind = world; (eFind = findfloat(eFind, ::team, TEAM_CT));) { - if (isClient(eFind) == false) { - continue; - } - - CSPlayer pl = (CSPlayer)eFind; - - if (pl.health > 0 && iWipe == FALSE) { - PlayerRespawn(pl, pl.team); - } else { - PlayerMakeSpectator(pl); - PlayerMakePlayable(pl, pl.charmodel); - } - - if (iWipe == FALSE) { - Money_GiveTeamReward(pl); - } else { - PlayerReset(pl); - } - } - - /* respawn the VIP as well, but turn them back into a CT. */ - for (entity eFind = world; (eFind = findfloat(eFind, ::team, TEAM_VIP));) { - if (isClient(eFind) == false) { - continue; - } - - CSPlayer pl = (CSPlayer)eFind; - pl.team = TEAM_CT; - - if (pl.health > 0 && iWipe == FALSE) { - PlayerRespawn(pl, TEAM_CT); - } else { - PlayerMakeSpectator(pl); - PlayerMakePlayable(pl, pl.charmodel); - } - - if (iWipe == FALSE) { - Money_GiveTeamReward(pl); - } else { - PlayerReset(pl); - } - } - - for (entity eFind = world; (eFind = find(eFind, ::classname, "tempdecal"));) { - NSDecal dec = (NSDecal)eFind; - dec.m_strTexture = ""; - dec.SendFlags = -1; - } - for (entity eFind = world; (eFind = find(eFind, ::classname, "item_c4"));) { - NSEntity e = (NSEntity)eFind; - e.Destroy(); - } - - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, EV_CLEARDECALS); - msg_entity = world; - multicast([0,0,0], MULTICAST_ALL); - - // Select a random Terrorist for the bomb, if needed - if (g_cs_bombzones > 0) { - int iRandomT = floor(random(1, (float)g_cs_alive_t + 1)); - int iPickT = 0; - - for (entity eFind = world; (eFind = find(eFind, ::classname, "player"));) { - if (eFind.team == TEAM_T) { - iPickT++; - - if (iPickT == iRandomT) { - MakeBomber((CSPlayer)eFind); - } - } - } - } - - // If there is a VIP, select a random CT to be it - if (g_cs_vipzones > 0) { - int iRandomCT = floor(random(1, (float)g_cs_alive_ct + 1)); - int iPickCT = 0; - - for (entity eFind = world; (eFind = find(eFind, ::classname, "player"));) { - if (eFind.team == TEAM_CT) { - iPickCT++; - if (iPickCT == iRandomCT) { - MakeVIP((CSPlayer)eFind); - } - } - } - } - - // Respawn all the entities - for (entity a = world; (a = findfloat(a, ::identity, 1));) { - NSEntity caw = (NSEntity)a; - if (caw.classname != "player") - caw.Respawn(); - } - - /* clear the corpses/items/bombs */ - for (entity eFind = world; (eFind = find(eFind, ::classname, "remove_me"));) { - if (eFind.identity) { - NSEntity toRemove = (NSEntity)eFind; - toRemove.Destroy(); - } else { - remove(eFind); - } - } - -#ifdef BOT - CSBot_BuyStart(); -#endif - - TimerBegin(autocvar_mp_freezetime, GAME_FREEZE); - Money_ResetTeamReward(); -} - -/* -================= -RoundOver - -This happens whenever an objective is complete or time is up -================= -*/ -void -CSMultiplayerRules::RoundOver(int iTeamWon, int iMoneyReward, int fSilent) -{ - if (g_cs_gamestate != GAME_ACTIVE && g_cs_gamestate != GAME_FREEZE) { - return; - } - - if (iTeamWon == TEAM_T) { - if (fSilent == FALSE) { - Radio_BroadcastMessage(RADIO_TERWIN); - } - g_cs_roundswon_t++; - m_iSwapTeamRoundCounter++; - } else if (iTeamWon == TEAM_CT) { - if (fSilent == FALSE) { - Radio_BroadcastMessage(RADIO_CTWIN); - } - g_cs_roundswon_ct++; - m_iSwapTeamRoundCounter++; - - /* In Bomb Defusal, if Terrorists were able to plant the bomb - * but lose the round, all Terrorists receive an $800 bonus. */ - if (g_cs_bombplanted) { - Money_QueTeamReward(TEAM_T, 800); - } - } else { - if (fSilent == FALSE) { - Radio_BroadcastMessage(RADIO_ROUNDDRAW); - } - } - - Money_HandleRoundReward(iTeamWon); - Money_QueTeamReward(iTeamWon, iMoneyReward); - TimerBegin(5, GAME_END); // Round is over, 5 seconds til a new round starts - - g_cs_hostagesrescued = 0; - g_cs_bombbeingdefused = 0; - g_cs_bombplanted = 0; - g_cs_roundsplayed++; - - forceinfokey(world, "teamscore_1", sprintf("%i", g_cs_roundswon_t)); - forceinfokey(world, "teamscore_2", sprintf("%i", g_cs_roundswon_ct)); -} - -/* -================= -TimeOut - -Whenever mp_roundtime was being counted down to 0 -================= -*/ -void -CSMultiplayerRules::TimeOut(void) -{ - if (g_cs_vipzones > 0) { - RoundOver(TEAM_T, 3250, FALSE); - } else if (g_cs_bombzones > 0) { - /* In Bomb Defusal, all Counter-Terrorists receive $3250 - * if they won running down the time. */ - RoundOver(TEAM_CT, 3250, FALSE); - } else if (g_cs_hostagestotal > 0) { - // TODO: Broadcast_Print: Hostages have not been rescued! - RoundOver(TEAM_T, 3250, FALSE); - } else { - RoundOver(0, 0, FALSE); - } -} - -/* -================= -SwitchTeams - -Happens rarely -================= -*/ -void -CSMultiplayerRules::SwitchTeams(void) -{ - int iCTW, iTW; - - for (entity eFind = world; (eFind = find(eFind, ::classname, "player"));) { - CSPlayer pl = (CSPlayer)eFind; - if (pl.team == TEAM_CT) { - pl.team = TEAM_T; - pl.charmodel -= 4; - } else if (pl.team == TEAM_T) { - pl.team = TEAM_CT; - pl.charmodel += 4; - } - pl.SetInfoKey("*team", ftos(pl.team)); - } - - iCTW = g_cs_roundswon_ct; - iTW = g_cs_roundswon_t; - - g_cs_roundswon_t = iCTW; - g_cs_roundswon_ct = iTW; - - iCTW = g_cs_alive_ct; - iTW = g_cs_alive_t; - - g_cs_alive_ct = iTW; - g_cs_alive_t = iCTW; - - forceinfokey(world, "teamscore_1", sprintf("%i", g_cs_roundswon_t)); - forceinfokey(world, "teamscore_2", sprintf("%i", g_cs_roundswon_ct)); -} - -void -CSMultiplayerRules::CountPlayers(void) -{ - g_cs_alive_t = 0; - g_cs_alive_ct = 0; - g_cs_total_t = 0; - g_cs_total_ct = 0; - - for (entity eFind = world; (eFind = find(eFind, ::classname, "player"));) { - if (eFind.team == TEAM_T) { - g_cs_total_t++; - - if (eFind.health > 0) - g_cs_alive_t++; - } else if (eFind.team == TEAM_CT || eFind.team == TEAM_VIP) { - g_cs_total_ct++; - - if (eFind.health > 0) - g_cs_alive_ct++; - } - } - - g_total_players = g_cs_total_t + g_cs_total_ct; -} - -void -CSMultiplayerRules::DeathCheck(NSClientPlayer pl) -{ - if (g_cs_gamestate == GAME_END) - return; - - /* hack so that we can kill rounds */ - if ((g_cs_alive_t == 0) && (g_cs_alive_ct == 0)) { - g_cs_gamestate = GAME_ACTIVE; - } - - switch (g_cs_gamestate) { - case GAME_INACTIVE: - case GAME_COMMENCING: - case GAME_END: - case GAME_OVER: - return; - break; - } - - if ((g_cs_alive_t == 0) && (g_cs_alive_ct == 0)) { - if (g_cs_bombplanted == TRUE) { - RoundOver(TEAM_T, 3600, FALSE); - } else { - RoundOver(FALSE, 0, FALSE); - } - } else { - int winner; - if ((pl.team == TEAM_T) && (g_cs_alive_t == 0)) { - winner = TEAM_CT; - } else if ((pl.team == TEAM_CT) && (g_cs_alive_ct == 0)) { - winner = TEAM_T; - } else { - return; - } - - if (g_cs_bombzones > 0) { - /* In Bomb Defusal, the winning team receives $3250 - * if they won by eliminating the enemy team. */ - if (!g_cs_bombplanted || g_cs_alive_ct == 0) { - RoundOver(winner, 3250, FALSE); - } - } else { - /* In Hostage Rescue, the winning team receives $3600 - * if they won by eliminating the enemy team. */ - RoundOver(winner, 3600, FALSE); - } - } -} - -/* -================= -PlayerFindSpawn - -Recursive function that gets the next spawnpoint -================= -*/ -entity -CSMultiplayerRules::PlayerFindSpawn(float t) -{ - entity point = world; - - if (t == TEAM_T) { - m_eLastTSpawn = find(m_eLastTSpawn, ::classname, SPAWNPOINT_T); - - if (m_eLastTSpawn == world) { - m_eLastTSpawn = find(m_eLastTSpawn, ::classname, SPAWNPOINT_T); - } - point = m_eLastTSpawn; - } else if (t == TEAM_CT) { - m_eLastCTSpawn = find(m_eLastCTSpawn, ::classname, SPAWNPOINT_CT); - - if (m_eLastCTSpawn == world) { - m_eLastCTSpawn = find(m_eLastCTSpawn, ::classname, SPAWNPOINT_CT); - } - point = m_eLastCTSpawn; - } else if (t == TEAM_VIP) { - point = find(world, ::classname, "info_vip_start"); - - if (!point) - point = find(m_eLastTSpawn, ::classname, SPAWNPOINT_CT); - } - - if (point == world) { - error("Error: No valid spawnpoints available."); - } - - return point; -} - -/* -================= -PlayerRespawn - -Called whenever a player survived a round and needs a basic respawn. -================= -*/ -void -CSMultiplayerRules::PlayerRespawn(NSClientPlayer pp, int fTeam) -{ - CSPlayer pl = (CSPlayer)pp; - NSEntity eSpawn = (NSEntity)PlayerFindSpawn(pl.team); - - pl.MakePlayer(); - pl.GiveItem("item_suit"); - pl.SetOrigin(eSpawn.origin); - pl.SetAngles(eSpawn.angles); - Client_FixAngle(pl, pl.angles); - - CountPlayers(); - - pl.SetInfoKey("*icon1", ""); - pl.SetInfoKey("*icon1_r", "1"); - pl.SetInfoKey("*icon1_g", "1"); - pl.SetInfoKey("*icon1_b", "1"); - - /* VIP starts with 200 armor and an extra mag */ - if (pl.team == TEAM_VIP) { - pl.SetArmor(200); - pl.GiveItem("weapon_usp"); - } - -#ifndef CSSOURCE - switch (pl.charmodel) { - case 1: - pl.model = "models/player/terror/terror.mdl"; - break; - case 2: - pl.model = "models/player/leet/leet.mdl"; - break; - case 3: - pl.model = "models/player/arctic/arctic.mdl"; - break; - case 4: - pl.model = "models/player/guerilla/guerilla.mdl"; - break; - case 5: - pl.model = "models/player/urban/urban.mdl"; - break; - case 6: - pl.model = "models/player/gsg9/gsg9.mdl"; - break; - case 7: - pl.model = "models/player/sas/sas.mdl"; - break; - case 8: - pl.model = "models/player/gign/gign.mdl"; - break; - default: - pl.model = "models/player/vip/vip.mdl"; - } -#else - switch (pl.charmodel) { - case 1: - pl.model = "models/player/t_phoenix.mdl"; - break; - case 2: - pl.model = "models/player/t_leet.mdl"; - break; - case 3: - pl.model = "models/player/t_arctic.mdl"; - break; - case 4: - pl.model = "models/player/t_guerilla.mdl"; - break; - case 5: - pl.model = "models/player/ct_urban.mdl"; - break; - case 6: - pl.model = "models/player/ct_gsg9.mdl"; - break; - case 7: - pl.model = "models/player/ct_sas.mdl"; - break; - case 8: - pl.model = "models/player/ct_gign.mdl"; - break; - default: - pl.model = "models/player/vip/vip.mdl"; - } -#endif - - pl.SetModel(pl.model); - pl.SetSize(VEC_HULL_MIN, VEC_HULL_MAX); - - pl.ClearVelocity(); - pl.progress = 0.0f; - pl.SwitchToBestWeapon(false); - Ammo_AutoFill(pl); -} - -void -CSMultiplayerRules::PlayerClearWeaponry(NSClientPlayer pp) -{ - CSPlayer pl = (CSPlayer)pp; - - pl.g_items = 0x0; - pl.activeweapon = 0; - pl.viewzoom = 1.0f; - pl.m_bHasNightvision = false; -} - -void -CSMultiplayerRules::PlayerMakePlayable(NSClientPlayer pp, int chara) -{ - CSPlayer pl = (CSPlayer)pp; - - /* spectator */ - if (chara == 0) { - PlayerSpawn(pl); - return; - } - - pl.RemoveAllItems(false); - pl.ingame = TRUE; - pl.SetInfoKey("*team", ftos(pl.team)); - PlayerRespawn(pl, pl.team); - - /* terrorists */ - if (chara < 5) { - pl.team = TEAM_T; - - if (autocvar_fcs_knifeonly == FALSE) { - pl.GiveItem("weapon_glock18"); - pl.GiveAmmo(ammoNumForName("ammo_9mm"), 40); - } - } else { - pl.team = TEAM_CT; - - if (autocvar_fcs_knifeonly == FALSE) { - pl.GiveItem("weapon_usp"); - pl.GiveAmmo(ammoNumForName("ammo_45acp"), 24); - } - } - - pl.GiveItem("weapon_knife"); -} - -/* -================= -PlayerMakeSpectator - -Force the player to become an observer. -================= -*/ -void -CSMultiplayerRules::PlayerMakeSpectator(NSClientPlayer pp) -{ - CSPlayer pl = (CSPlayer)pp; - pl.MakeTempSpectator(); - PlayerClearWeaponry(pl); - pl.view_ofs = g_vec_null; -} - -/* -================= -PlayerReset - -Called when we give the initial starting money, and also when -another player joins and causes the game rules/scores to reset fully -================= -*/ -void -CSMultiplayerRules::PlayerReset(NSClientPlayer pl) -{ - CSPlayer p = (CSPlayer)pl; - - /* give the initial server-joining money */ - p.money = 0; - Money_AddMoney(pl, autocvar_mp_startmoney); - p.m_buyMessage = false; /* unset the buy message. */ - p.m_hostMessageT = false; - p.m_seenFriend = false; - p.m_seenEnemy = false; - p.m_seenHostage = false; - p.m_bHasNightvision = false; -} - -/* -================= -PlayerSpawn - -Called on the client first joining the server. -================= -*/ -void -CSMultiplayerRules::PlayerSpawn(NSClientPlayer pl) -{ - /* immediately put us into spectating mode */ - PlayerMakeSpectator(pl); - Spawn_ObserverCam(pl); - - PlayerReset(pl); - - /* we don't belong to any team */ - pl.team = TEAM_SPECTATOR; - pl.SetInfoKey("*team", "0"); -} - -bool -CSMultiplayerRules::ConsoleCommand(NSClientPlayer pp, string cmd) -{ - tokenize(cmd); - - switch (argv(0)) { - default: - return (false); - } - - return (true); -} - -bool -CSMultiplayerRules::IsTeamplay(void) -{ - return true; -} - -void -CSMultiplayerRules::CSMultiplayerRules(void) -{ - forceinfokey(world, "teams", "2"); - forceinfokey(world, "team_1", "Terrorist"); - forceinfokey(world, "teamscore_1", "0"); - forceinfokey(world, "teamcolor_1", "1 0 0" ); - forceinfokey(world, "team_2", "Counter-Terrorist"); - forceinfokey(world, "teamscore_2", "0"); - forceinfokey(world, "teamcolor_2", "0.25 0.25 1" ); - m_iEscapedTerrorists = 0; -} - -/* -================= -CSEv_JoinTeam_f - -Event Handling, called by the Client codebase via 'sendevent' -================= -*/ -void -CSEv_JoinTeam_f(float flChar) -{ - CSMultiplayerRules rules; - CSPlayer pl; - - /* matches Game_InitRules() */ - if (cvar("sv_playerslots") == 1 || cvar("coop") == 1) { - return; - } - - rules = (CSMultiplayerRules)g_grMode; - pl = (CSPlayer)self; - - /* VIPs cannot change teams... ? */ - if (pl.team == TEAM_VIP) { - centerprint(pl, "You are the VIP!\nYou cannot switch roles now.\n"); - return; - } - - if (pl.IsAlive()) { - rules.PlayerKill(pl); - } - - /* team switching, var reset */ - if (flChar < 5) { - pl.team = TEAM_T; - } else { - pl.team = TEAM_CT; - } - - pl.frags = 0; - pl.deaths = 0; - pl.SetInfoKey("*deaths", ftos(pl.deaths)); - pl.SetInfoKey("*team", ftos(pl.team)); - - switch (g_cs_gamestate) { - /* spawn the players immediately when its in the freeze state */ - case GAME_FREEZE: - pl.charmodel = (int)flChar; - rules.PlayerMakePlayable(pl, (int)flChar); - - if ((pl.team == TEAM_T) && (g_cs_alive_t == 1)) { - if (g_cs_bombzones > 0) { - rules.MakeBomber(pl); - } - } else if ((pl.team == TEAM_CT) && (g_cs_alive_ct == 1)) { - if (g_cs_vipzones > 0) { - rules.MakeVIP(pl); - } - } - - break; - /* otherwise, just prepare their fields for the next round */ - default: - if (flChar == 0) { - rules.PlayerSpawn(pl); - return; - } - - rules.PlayerMakeSpectator(pl); - pl.charmodel = (int)flChar; - pl.SetInfoKey("*dead", "1"); - break; - } - - rules.CountPlayers(); - - /* if no players are present in the chosen team, force restart round */ - if ((pl.team == TEAM_T) && (g_cs_alive_t == 0)) { - rules.RoundOver(FALSE, 0, FALSE); - } else if ((pl.team == TEAM_CT) && (g_cs_alive_ct == 0)) { - rules.RoundOver(FALSE, 0, FALSE); - } -} - -void -CSEv_JoinAuto(void) -{ - CSMultiplayerRules rules; - - /* matches Game_InitRules() */ - if (cvar("sv_playerslots") == 1 || cvar("coop") == 1) { - return; - } - - rules = (CSMultiplayerRules)g_grMode; - rules.CountPlayers(); - - if (g_cs_total_ct >= g_cs_total_t) { - CSEv_JoinTeam_f(floor(random(1,5))); - } else { - CSEv_JoinTeam_f(floor(random(5,9))); - } -} - -void -CSEv_JoinSpectator(void) -{ - NSClientPlayer pl = (NSClientPlayer)self; - ClientKill(); - pl.MakeSpectator(); -} diff --git a/src/server/gamerules_singleplayer.qc b/src/server/gamerules_singleplayer.qc deleted file mode 100644 index 9f5e977..0000000 --- a/src/server/gamerules_singleplayer.qc +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2016-2021 Marco Cawthorne - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -string -CSSingleplayerRules::Title(void) -{ - return "Singleplayer"; -} - -void -CSSingleplayerRules::PlayerDeath(NSClientPlayer pl) -{ - pl.movetype = MOVETYPE_NONE; - pl.solid = SOLID_NOT; - pl.takedamage = DAMAGE_NO; - pl.gflags &= ~GF_FLASHLIGHT; - pl.armor = pl.activeweapon = pl.g_items = 0; - - if (pl.health < -50) { - pl.health = 0; - //FX_GibHuman(pl.origin, vectoangles(pl.origin - g_dmg_eAttacker.origin), g_dmg_iDamage * 2.0f); - return; - } - - pl.health = 0; -} - -void -CSSingleplayerRules::PlayerSpawn(NSClientPlayer pl) -{ - pl.classname = "player"; - pl.health = pl.max_health = 100; - pl.takedamage = DAMAGE_YES; - pl.solid = SOLID_SLIDEBOX; - pl.movetype = MOVETYPE_WALK; - pl.flags = FL_CLIENT; - pl.viewzoom = 1.0; - pl.model = "models/player.mdl"; - setmodel(pl, pl.model); - - setsize(pl, VEC_HULL_MIN, VEC_HULL_MAX); - pl.velocity = [0,0,0]; - pl.gravity = __NULL__; - pl.frame = 1; - pl.SendFlags = UPDATE_ALL; - pl.customphysics = Empty; - pl.EnableBleeding(); - pl.SetInfoKey("*spec", "0"); - pl.SetInfoKey("*deaths", ftos(pl.deaths)); - - entity spot; - - if (startspot != "") { - dprint(sprintf("^3Gamerules_Spawn^7: Startspot is %s\n", startspot)); - LevelDecodeParms(pl); - setorigin(pl, Landmark_GetSpot()); - } else { - LevelNewParms(); - spot = find(world, ::classname, "info_player_start"); - setorigin(pl, spot.origin); - pl.angles = spot.angles; - } - - Client_FixAngle(pl, pl.angles); -} diff --git a/src/server/hostage_entity.qc b/src/server/hostage_entity.qc index ecba907..7ac4af0 100644 --- a/src/server/hostage_entity.qc +++ b/src/server/hostage_entity.qc @@ -81,7 +81,7 @@ enum class CSHostage:NSTalkMonster { - int m_iUsedOnce; + bool m_bUsedOnce; void CSHostage(void); @@ -91,13 +91,21 @@ class CSHostage:NSTalkMonster }; +void +CSHostage::CSHostage(void) +{ + Sound_Precache("hostage_entity.follow"); + m_bUsedOnce = false; +} + + void CSHostage::OnPlayerUse(void) { if (eActivator.team == TEAM_T) { CSPlayer pl = (CSPlayer)eActivator; - if (g_csMode.ShowHints() == true) + if (serverinfo.GetBool("cs_hints") == true) if (pl.m_hostMessageT == false) { env_message_single(pl, "Only_CT_Can_Move_Hostages"); pl.m_hostMessageT = true; @@ -110,9 +118,9 @@ CSHostage::OnPlayerUse(void) } /* CT reward, first time only */ - if (m_iUsedOnce == FALSE) { - Money_AddMoney((CSPlayer)eActivator, 150); - m_iUsedOnce = TRUE; + if (m_bUsedOnce == false) { + g_grMode.Input(eActivator, "HostageContacted", ""); + m_bUsedOnce = true; } NSTalkMonster::OnPlayerUse(); @@ -153,7 +161,7 @@ CSHostage::Pain(entity inflictor, entity attacker, int damageDealt, vector dir, return; } - Money_AddMoney((NSClientPlayer)attacker, -(damageDealt * 25i)); + g_grMode.Input(attacker, "HostageInjured", itos(damageDealt)); } void @@ -175,13 +183,7 @@ CSHostage::Death(entity inflictor, entity attacker, int damageDealt, vector dir, } if (isPlayer(attacker) == true) { - if (damageDealt >= 100) { - Money_AddMoney((NSClientPlayer)attacker, -2500); - } else { - Money_AddMoney((NSClientPlayer)attacker, -500); - } - - Radio_BroadcastMessage(RADIO_HOSDOWN); + g_grMode.Input(attacker, "HostageKilled", itos(damageDealt)); } } @@ -192,10 +194,3 @@ CSHostage::Death(entity inflictor, entity attacker, int damageDealt, vector dir, super::Death(inflictor, attacker, damageDealt, dir, location); SetSolid(SOLID_NOT); } - -void -CSHostage::CSHostage(void) -{ - Sound_Precache("hostage_entity.follow"); - g_cs_hostagestotal++; -} diff --git a/src/server/info_hostage_rescue.qc b/src/server/info_hostage_rescue.qc index a250e6c..2232972 100644 --- a/src/server/info_hostage_rescue.qc +++ b/src/server/info_hostage_rescue.qc @@ -72,14 +72,6 @@ info_hostage_rescue::Touch(entity eToucher) if (!((CSPlayer)hosty.m_eFollowing)) return; - Radio_BroadcastMessage(RADIO_RESCUED); - CSBot_HostageRescueNotify(); - g_cs_hostagesrescued++; - - Money_AddMoney((CSPlayer)hosty.m_eFollowing, 1000); - - /* In Hostage Rescue, all Counter-Terrorists receive an $850 - * bonus for every hostage they rescue, even if they lose the round. */ - Money_QueTeamReward(TEAM_CT, 850); + g_grMode.Input(hosty.m_eFollowing, "HostageRescued", ""); hosty.Disappear(); } diff --git a/src/server/money.h b/src/server/money.h deleted file mode 100644 index 477c28a..0000000 --- a/src/server/money.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2016-2019 Marco Cawthorne - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -int g_cs_moneyreward_ct; -int g_cs_moneyreward_t; - -void Money_AddMoney(NSClientPlayer, int); -void Money_QueTeamReward(int, int); -void Money_GiveTeamReward(NSClientPlayer); -void Money_ResetTeamReward(void); -void Money_HandleRoundReward(int) -void Money_ResetRoundReward(void); -int Money_GetLosses(int); -int Money_HasBonus(int); diff --git a/src/server/progs.src b/src/server/progs.src index 16df440..568142d 100644 --- a/src/server/progs.src +++ b/src/server/progs.src @@ -1,6 +1,6 @@ #pragma target fte_5768 //#pragma flag enable assumeint -#pragma progs_dat "../../zpak001.pk3dir/progs.dat" +#pragma progs_dat "../../progs.dat" #define QWSSQC #define SERVER @@ -30,17 +30,7 @@ info_hostage_rescue.qc func_vip_safetyzone.qc info_map_parameters.qc ../../../src/botlib/include.src -bot.qc -game_money.qc -gamerules.qc -gamerules_singleplayer.qc -gamerules_deathmatch.qc -gamerules_multiplayer.qc -radio.qc -ammo.qc -buy.qc server.qc -../../../valve/src/server/flashlight.qc ../../../src/server/include.src ../../../src/shared/include.src #endlist diff --git a/src/server/radio.h b/src/server/radio.h deleted file mode 100644 index 2bbbfcb..0000000 --- a/src/server/radio.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2016-2020 Marco Cawthorne - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -void Radio_BroadcastMessage(float fMessage); -void Radio_TeamMessage(float fMessage, float fTeam); -float Radio_DefaultStart(void); -void Radio_StartMessage(void); diff --git a/src/server/radio.qc b/src/server/radio.qc index dd2732d..46df00c 100644 --- a/src/server/radio.qc +++ b/src/server/radio.qc @@ -52,8 +52,6 @@ Radio_TeamMessage(float fMessage, float fTeam) for (entity eFind = world; (eFind = find(eFind, classname, "player"));) { if (eFind.team == fTeam) { Radio_TeamMessage_Send(fMessage, eFind); - } else if (eFind.team == TEAM_VIP && fTeam == TEAM_CT) { - Radio_TeamMessage_Send(fMessage, eFind); } } } @@ -131,15 +129,11 @@ CSEv_Radio_f(float fMessage) // Make sure that VIPs and CTs get eachother float fTargetTeam = self.team; - if (fTargetTeam == TEAM_VIP) { - fTargetTeam = TEAM_CT; - } + for (entity eFind = world; (eFind = find(eFind, classname, "player"));) { if (eFind.team == fTargetTeam) { CSEv_Radio_Send(fMessage, self, eFind); - } else if (eFind.team == TEAM_VIP && fTargetTeam == TEAM_CT) { - CSEv_Radio_Send(fMessage, self, eFind); } } diff --git a/src/server/server.qc b/src/server/server.qc index fc586c7..c1daa49 100644 --- a/src/server/server.qc +++ b/src/server/server.qc @@ -18,30 +18,19 @@ void Game_InitRules(void) { if (cvar("sv_playerslots") == 1 || cvar("coop") == 1) { - g_grMode = spawn(CSSingleplayerRules); + g_grMode = NSGameRules::InitFromProgs("progs/singleplayer.dat"); } else { if (cvar("fcs_deathmatch") == 1) { - g_grMode = spawn(CSDeathmatchRules); + g_grMode = NSGameRules::InitFromProgs("progs/deathmatch.dat"); } else { - g_grMode = spawn(CSMultiplayerRules); + g_grMode = NSGameRules::InitFromProgs("progs/counterstrike.dat"); } } - - g_csMode = (CSGameRules)g_grMode; } void Game_Worldspawn(void) { - precache_model("models/player/arctic/arctic.mdl"); - precache_model("models/player/gign/gign.mdl"); - precache_model("models/player/gsg9/gsg9.mdl"); - precache_model("models/player/guerilla/guerilla.mdl"); - precache_model("models/player/leet/leet.mdl"); - precache_model("models/player/sas/sas.mdl"); - precache_model("models/player/terror/terror.mdl"); - precache_model("models/player/urban/urban.mdl"); - precache_model("models/player/vip/vip.mdl"); precache_sound("weapons/ric_metal-2.wav"); precache_sound("player/pl_pain2.wav"); precache_sound("player/pl_pain4.wav"); @@ -54,17 +43,5 @@ Game_Worldspawn(void) Sound_Precache("Player.FlashLightOff"); Sound_Precache("Player.FlashLightOn"); - /* some Counter-Strike maps do not have weapon pickups, so we want to - * precache these regardless in case of someone dropping a weapon, - * which happens quite often (buying weapons, etc.) */ - Sound_Precache("item.respawn"); - Sound_Precache("weapon.pickup"); - FX_Corpse_Init(); - - clientstat(STAT_MONEY, EV_INTEGER, CSPlayer::money); - clientstat(STAT_PROGRESS, EV_FLOAT, CSPlayer::progress); - - pointerstat(STAT_GAMETIME, EV_FLOAT, &g_cs_gametime); - pointerstat(STAT_GAMESTATE, EV_INTEGER, &g_cs_gamestate); } diff --git a/src/shared/animations.qc b/src/shared/animations.qc index 4c8daf5..4728056 100644 --- a/src/shared/animations.qc +++ b/src/shared/animations.qc @@ -40,7 +40,7 @@ void Animation_Print(string sWow) { } void -Animation_TimerUpdate(CSPlayer pl, float ftime) +Animation_TimerUpdate(HLPlayer pl, float ftime) { makevectors([0, pl.v_angle[1], 0]); @@ -65,7 +65,7 @@ depending on what the player is doing ================= */ void -Animation_PlayerUpdate(CSPlayer pl) +Animation_PlayerUpdate(HLPlayer pl) { pl.basebone = gettagindex(pl, "-- R shoulder outside"); @@ -128,7 +128,7 @@ Animation_PlayerUpdate(CSPlayer pl) } void -Animation_PlayerTop(CSPlayer pl, float topanim, float timer) +Animation_PlayerTop(HLPlayer pl, float topanim, float timer) { #if 0 pl.anim_top = topanim; @@ -138,7 +138,7 @@ Animation_PlayerTop(CSPlayer pl, float topanim, float timer) } void -Animation_PlayerBottom(CSPlayer pl, float botanim, float timer) +Animation_PlayerBottom(HLPlayer pl, float botanim, float timer) { pl.anim_bottom = botanim; } diff --git a/src/shared/defs.h b/src/shared/defs.h index 1c26c59..17f8d17 100644 --- a/src/shared/defs.h +++ b/src/shared/defs.h @@ -17,16 +17,13 @@ #include "animations.h" #include "radio.h" #include "buying.h" -#include "items.h" #include "entities.h" #include "events.h" #include "CSProjectile.h" #include "../../../valve/src/shared/HLWeapon.h" -#define TEAM_SPECTATOR 0 #define TEAM_T 1 #define TEAM_CT 2 -#define TEAM_VIP 3 enum { diff --git a/src/shared/include.src b/src/shared/include.src index 97bb5d3..e75fbb9 100644 --- a/src/shared/include.src +++ b/src/shared/include.src @@ -1,19 +1,18 @@ #includelist -flags.h -player.h -animations.h -animations.qc - -item_c4bomb.h - +../../../cstrike/src/shared/flags.h +../../../cstrike/src/shared/skeleton.h +../../../valve/src/shared/player.qc +../../../cstrike/src/shared/player.h +../../../cstrike/src/shared/animations.h +../../../cstrike/src/shared/animations.qc +../../../cstrike/src/shared/item_c4bomb.h ../../../valve/src/shared/fx_blood.qc ../../../valve/src/shared/fx_corpse.qc -fx_flashbang.qc -fx_smokenade.qc -item_c4bomb.qc -weapons_cstrike.qc -CSProjectile.qc +../../../cstrike/src/shared/fx_flashbang.qc +../../../cstrike/src/shared/fx_smokenade.qc +../../../cstrike/src/shared/item_c4bomb.qc +../../../cstrike/src/shared/weapons_cstrike.qc +../../../cstrike/src/shared/CSProjectile.qc ../../../valve/src/shared/HLWeapon.qc -CSWeapon.qc -pmove.qc +../../../cstrike/src/shared/CSWeapon.qc #endlist diff --git a/src/shared/item_c4bomb.qc b/src/shared/item_c4bomb.qc index 3ac239c..4e2d053 100644 --- a/src/shared/item_c4bomb.qc +++ b/src/shared/item_c4bomb.qc @@ -98,8 +98,6 @@ CSBombEntity::OnPlayerUse(void) void CSBombEntity::Logic(void) { - CSMultiplayerRules rules = (CSMultiplayerRules)g_grMode; - /* check if we're being used */ if (m_eUser != world) { CSPlayer pl = (CSPlayer)m_eUser; @@ -111,11 +109,11 @@ CSBombEntity::Logic(void) /* clear user */ m_eUser = world; m_flDefusalState = 0.0f; - g_cs_bombbeingdefused = FALSE; + serverinfo.SetBool("cs_bombbeingdefused", false); } else { /* defusal kit always cuts the time in half */ - if (pl.g_items & ITEM_DEFUSAL) + if (pl.HasItem("item_defuse")) m_flDefusalState += (frametime * 2); else m_flDefusalState += frametime; @@ -123,15 +121,13 @@ CSBombEntity::Logic(void) /* tracked stat */ pl.progress = m_flDefusalState; pl.AddVFlags(VFL_FROZEN); - - g_cs_bombbeingdefused = TRUE; + serverinfo.SetBool("cs_bombbeingdefused", true); } } if (m_flDefusalState > 10.0f) { StartSoundDef("weapon_c4bomb.disarmed", CHAN_VOICE, true); - rules.RoundOver(TEAM_CT, 3600, TRUE); - Radio_BroadcastMessage(RADIO_BOMBDEF); + g_grMode.Input(m_eUser, "BombDisarmed", ""); Destroy(); return; } @@ -140,12 +136,9 @@ CSBombEntity::Logic(void) if (m_flExplodeTime < time) { float bestDist = 9999.0f; NSEntity bestTarget = __NULL__; + g_grMode.Input(m_eUser, "BombExploded", ""); - /* In Bomb Defusal, all Terrorists receive $3500 - * if they won by detonating the bomb. */ - rules.RoundOver(TEAM_T, 3500, FALSE); - - radiusDamage(origin, -g_cstrike_bombradius, 0i, 500i, real_owner); + combat.RadiusDamage(origin, -g_cstrike_bombradius, 0i, 500i, real_owner, ""); //Damage_Radius(origin, this.real_owner, 500, g_cstrike_bombradius, false, WEAPON_C4BOMB); @@ -193,8 +186,8 @@ CSBombEntity::OnRemoveEntity(void) ClearProgress(); m_flBeepTime = 0.0f; m_flDefusalState = 0; - g_cs_bombbeingdefused = FALSE; - g_cs_bombplanted = false; + serverinfo.SetBool("cs_bombbeingdefused", false); + serverinfo.SetBool("cs_bombplanted", false); } void @@ -214,6 +207,7 @@ CSBombEntity::Spawned(void) PlayerUse = OnPlayerUse; m_flExplodeTime = time + 45.0f; StartSoundDef("c4.plant", CHAN_WEAPON, true); + serverinfo.SetBool("cs_bombplanted", true); } #endif diff --git a/src/shared/items.h b/src/shared/items.h deleted file mode 100644 index 1dc336f..0000000 --- a/src/shared/items.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2016-2020 Marco Cawthorne - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#define ITEM_KNIFE 0x00000001i -#define ITEM_USP45 0x00000002i -#define ITEM_GLOCK18 0x00000004i -#define ITEM_DEAGLE 0x00000008i -#define ITEM_P228 0x00000010i -#define ITEM_ELITES 0x00000020i -#define ITEM_FIVESEVEN 0x00000040i -#define ITEM_M3 0x00000080i - -#define ITEM_XM1014 0x00000100i -#define ITEM_MP5 0x00000200i -#define ITEM_P90 0x00000400i -#define ITEM_UMP45 0x00000800i -#define ITEM_MAC10 0x00001000i -#define ITEM_TMP 0x00002000i -#define ITEM_SUIT 0x00004000i -#define ITEM_FAMAS 0x00008000i - -#define ITEM_AK47 0x00010000i -#define ITEM_SG552 0x00020000i -#define ITEM_M4A1 0x00040000i -#define ITEM_AUG 0x00080000i -#define ITEM_SCOUT 0x00100000i -#define ITEM_AWP 0x00200000i -#define ITEM_G3SG1 0x00400000i -#define ITEM_SG550 0x00800000i - -#define ITEM_PARA 0x01000000i -#define ITEM_C4BOMB 0x02000000i -#define ITEM_FLASHBANG 0x04000000i -#define ITEM_HEGRENADE 0x08000000i -#define ITEM_SMOKEGRENADE 0x10000000i -#define ITEM_DEFUSAL 0x20000000i -#define ITEM_GALIL 0x40000000i -#define ITEM_HELMET 0x80000000i diff --git a/src/shared/player.h b/src/shared/player.h index bcf3d50..915a3d5 100644 --- a/src/shared/player.h +++ b/src/shared/player.h @@ -14,88 +14,47 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifdef CLIENT -/* Here's a list of bone names that we are aware of on HL player models. - Usually we'd use skeletalobjects to share the same skeleton/anim with - another model - but because FTEQW does not support that for HLMDL we - are forced to manually position the bones of our attachnment - by iterating over them and manually setting their position in 3D-space. -*/ -string g_pbones[] = +/** @brief Get entity by class name and index **/ +NSEntity +GetEntityByNameAndIndex(string name, int index) { - "Bip01", - "Bip01 Footsteps", - "Bip01 Pelvis", - "Bip01 L Leg", - "Bip01 L Leg1", - "Bip01 L Foot", - "Bip01 L Toe0", - "Bip01 L Toe01", - "Bip01 L Toe02", - "Dummy16", - "Bip01 R Leg", - "Bip01 R Leg1", - "Bip01 R Foot", - "Bip01 R Toe0", - "Bip01 R Toe01", - "Bip01 R Toe02", - "Dummy11", - "Bip01 Spine", - "Bip01 Spine1", - "Bip01 Spine2", - "Bip01 Spine3", - "Bip01 Neck", - "Bip01 Head", - "Dummy21", - "Dummy08", - "Bone02", - "Bone03", - "Bone04", - "Dummy05", - "Bone09", - "Bone10", - "Dummy04", - "Bone05", - "Bone06", - "Dummy03", - "Bone07", - "Bone08", - "Dummy09", - "Bone11", - "Bone12", -"Dummy10", - "Bone13", - "Bone14", - "Bone15", - "Bip01 L Arm", - "Bip01 L Arm1", - "Bip01 L Arm2", - "Bip01 L Hand", - "Bip01 L Finger0", - "Bip01 L Finger01", - "Bip01 L Finger02", - "Dummy06", - "Bip01 L Finger1", - "Bip01 L Finger11", - "Bip01 L Finger12", - "Dummy07", - "Bip01 R Arm", - "Bip01 R Arm1", - "Bip01 R Arm2", - "Bip01 R Hand", - "Bip01 R Finger0", - "Bip01 R Finger01", - "Bip01 R Finger02", - "Dummy01", - "Bip01 R Finger1", - "Bip01 R Finger11", - "Bip01 R Finger12", - "Dummy02", - "Box02", - "Bone08", - "Bone15" -}; -#endif + int curIndex = 0; + for (entity a = world; (a = find(a, ::classname, name));) { + if (curIndex == index) { + return (NSEntity)a; + } + ++curIndex; + } + print("WARNING: cstrike/server/bot.qc GetEntityByNameAndIndex: no entity '", + name, "' with index ", itos(index), "!\n"); + return __NULL__; +} + +/** @brief Get bombsite entity by bombsite index + * + * @note + * When there are for example 2 bombsites (g_cs_bombzones == 2) then valid + * indexes would be 0 and 1. + * */ +NSEntity +GetBombsiteByIndex(int index) +{ + return GetEntityByNameAndIndex("func_bomb_target", index); +} + +/** @brief Get Escape Zone entity by index **/ +NSEntity +GetEscapeZoneByIndex(int index) +{ + return GetEntityByNameAndIndex("func_escapezone", index); +} + +/** @brief Get VIP Safety Zone entity by index **/ +NSEntity +GetVIPSafetyZoneByIndex(int index) +{ + return GetEntityByNameAndIndex("func_vip_safetyzone", index); +} /* all potential SendFlags bits we can possibly send */ enumflags @@ -105,27 +64,23 @@ enumflags PLAYER_CSTIMERS = PLAYER_CUSTOMFIELDSTART }; -class CSPlayer:NSClientPlayer +class +CSPlayer:HLPlayer { int ingame; + void CSPlayer(void); + PREDICTED_FLOAT(cs_shotmultiplier) PREDICTED_FLOAT(cs_shottime) PREDICTED_FLOAT(cs_prev_hor_rec) PREDICTED_INT(cs_hor_rec_sign) PREDICTED_FLOAT(cs_rec_reverse_chance) - PREDICTED_FLOAT(anim_top) - PREDICTED_FLOAT(anim_top_time) - PREDICTED_FLOAT(anim_top_delay) - PREDICTED_FLOAT(anim_bottom) - PREDICTED_FLOAT(anim_bottom_time) - virtual void(float) Physics_Fall; virtual void(void) Physics_Jump; virtual void(void) Physics_InputPostMove; - virtual void UpdatePlayerAnimation(float); #ifdef CLIENT int playertype; @@ -134,17 +89,29 @@ class CSPlayer:NSClientPlayer int cs_cross_deltadist; float cs_crosshairdistance; - virtual void UpdatePlayerAttachments(bool); virtual void ReceiveEntity(float, float); virtual void PredictPreFrame(void); virtual void PredictPostFrame(void); - virtual void UpdateAliveCam(void); - virtual void ClientInputFrame(void); #else + virtual void Input(entity, string, string); virtual void ServerInputFrame(void); virtual void EvaluateEntity(void); virtual float SendEntity(entity, float); + nonvirtual void Bot_RunToConfront(void); + nonvirtual void Bot_RunToBomb(void); + nonvirtual void Bot_RunToBombsite(int); + nonvirtual void Bot_RunToRandomBombsite(void); + nonvirtual void Bot_RunToEscapeZone(int); + nonvirtual void Bot_RunToRandomEscapeZone(void); + nonvirtual void Bot_RunToVIPSafetyZone(int); + nonvirtual void Bot_RunToRandomVIPSafetyZone(void); + nonvirtual void Bot_RunToHostages(void); + nonvirtual void Bot_Roam(vector, int); + nonvirtual void Bot_CreateObjective(void); + nonvirtual void Bot_Buy(void); + nonvirtual void Bot_AimLerp(vector, float); + int charmodel; int money; float progress; @@ -156,9 +123,54 @@ class CSPlayer:NSClientPlayer bool m_seenHostage; bool m_seenBombSite; bool m_bHasNightvision; + + /* bot related vars */ + int m_actionIsPlanting; + int m_actionIsDefusing; + + /* Workaround: + * gflags is not yet set when CSBot_BuyStart_Shop() or Bot_CreateObjective() + * are called, so we back it up on PostFrame() and use that instead. + * Known issues it solves: + * - Check if the bot is in a Bomb Zone (gflags & GF_BOMBZONE) + * - Check if the bot is in a Buy Zone (gflags & GF_BUYZONE) */ + int m_gflagsBackup; #endif }; +void +CSPlayer::CSPlayer(void) +{ + ingame = false; + cs_shotmultiplier = 0; + cs_shottime = 0; + cs_prev_hor_rec = 0; + cs_hor_rec_sign = 0; + cs_rec_reverse_chance = 0; + +#ifdef CLIENT + playertype = 0; + cs_cross_mindist = 0; + cs_cross_deltadist = 0; + cs_crosshairdistance = 0; +#else + charmodel = 0; + money = 0; + progress = 0; + m_buyMessage = 0; + m_hostMessageT = 0; + m_seenFriend = 0; + m_seenEnemy = 0; + m_seenHostage = 0; + m_seenBombSite = 0; + m_bHasNightvision = 0; + /* bot related maps */ + m_actionIsPlanting = FALSE; + m_actionIsDefusing = FALSE; + m_gflagsBackup = 0; +#endif +} + float punchangle_recovery(float punchangle) { return 0.05 * (-0.2 * pow(1.2, fabs(punchangle)) + 4); } @@ -183,166 +195,20 @@ CSPlayer::Physics_InputPostMove(void) RemoveVFlags(VFL_FROZEN); RemoveVFlags(VFL_NOATTACK); -#ifdef SERVER - if (g_cs_gamestate == GAME_FREEZE) { -#else - if (getstati(STAT_GAMESTATE) == GAME_FREEZE) { -#endif + if (serverkeyfloat("cs_gamestate") == GAME_FREEZE) { AddVFlags(VFL_FROZEN); AddVFlags(VFL_NOATTACK); if (input_buttons & INPUT_BUTTON0) { w_attack_next = (w_attack_next > 0.1) ? w_attack_next : 0.1f; } - } + ProcessInput(); } - -void Animation_PlayerUpdate(CSPlayer); -void Animation_TimerUpdate(CSPlayer, float); - -void -CSPlayer::UpdatePlayerAnimation(float timelength) -{ - /* calculate our skeletal progression */ - Animation_PlayerUpdate(this); - /* advance animation timers */ - Animation_TimerUpdate(this, timelength); -} - #ifdef CLIENT -void -CSPlayer::ClientInputFrame(void) -{ - if (pSeatLocal->weaponSelectionHUD.Active()) { - if (input_buttons & INPUT_PRIMARY) { - pSeatLocal->weaponSelectionHUD.Trigger(); - } else if (input_buttons & INPUT_SECONDARY) { - pSeatLocal->weaponSelectionHUD.Deactivate(); - } - pSeat->m_flInputBlockTime = time + 0.2; - } - super::ClientInputFrame(); -} - -void Camera_RunPosBob(vector angles, __inout vector camera_pos); -void Camera_StrafeRoll(__inout vector camera_angle); -void Shake_Update(NSClientPlayer); - -void -CSPlayer::UpdateAliveCam(void) -{ - vector cam_pos = GetEyePos(); - Camera_RunPosBob(view_angles, cam_pos); - - g_view.SetCameraOrigin(cam_pos); - Camera_StrafeRoll(view_angles); - g_view.SetCameraAngle(view_angles); - - if (vehicle) { - NSVehicle veh = (NSVehicle)vehicle; - - if (veh.UpdateView) - veh.UpdateView(); - } else if (health) { - if (autocvar_pm_thirdPerson == TRUE) { - makevectors(view_angles); - vector vStart = [pSeat->m_vecPredictedOrigin[0], pSeat->m_vecPredictedOrigin[1], pSeat->m_vecPredictedOrigin[2] + 16] + (v_right * 4); - vector vEnd = vStart + (v_forward * -48) + [0,0,16] + (v_right * 4); - traceline(vStart, vEnd, FALSE, this); - g_view.SetCameraOrigin(trace_endpos + (v_forward * 5)); - } - } - - Shake_Update(this); - g_view.AddPunchAngle(punchangle); -} - -.string oldmodel; -///string Weapons_GetPlayermodel(NSClientPlayer, int); - -void -CSPlayer::UpdatePlayerAttachments(bool visible) -{ - /* draw the flashlight */ - if (gflags & GF_FLASHLIGHT) { - vector src; - vector ang; - - if (entnum != player_localentnum) { - src = origin + view_ofs; - ang = v_angle; - } else { - src = pSeat->m_vecPredictedOrigin + [0,0,-8]; - ang = view_angles; - } - - makevectors(ang); - traceline(src, src + (v_forward * 8096), MOVE_NORMAL, this); - - if (serverkeyfloat("*bspversion") == BSPVER_HL) { - dynamiclight_add(trace_endpos + (v_forward * -2), 128, [1,1,1]); - } else { - float p = dynamiclight_add(src, 512, [1,1,1], 0, "textures/flashlight"); - dynamiclight_set(p, LFIELD_ANGLES, ang); - dynamiclight_set(p, LFIELD_FLAGS, 3); - } - } - - /* FIXME: this needs to be incorporated and simplified, now that we can handle it all in-class */ - if (!visible) - return; - - /* what's the current weapon model supposed to be anyway? */ - p_model.oldmodel = 0;//Weapons_GetPlayermodel(this, activeweapon); - - /* we changed weapons, update skeletonindex */ - if (p_model.model != p_model.oldmodel) { - /* free memory */ - if (p_model.skeletonindex) - skel_delete(p_model.skeletonindex); - - /* set the new model and mark us updated */ - setmodel(p_model, p_model.oldmodel); - p_model.model = p_model.oldmodel; - - /* set the new skeletonindex */ - p_model.skeletonindex = skel_create(p_model.modelindex); - - /* hack this thing in here FIXME: this should be done when popping in/out of a pvs */ - if (autocvar(cl_himodels, 1, "Use high-quality thisayer models over lower-definition ones")) - setcustomskin(this, "", "geomset 0 2\n"); - else - setcustomskin(this, "", "geomset 0 1\n"); - } - - /* follow thisayer at all times */ - setorigin(p_model, origin); - p_model.angles = angles; - skel_build(p_model.skeletonindex, p_model, p_model.modelindex,0, 0, -1); - - /* we have to loop through all valid bones of the weapon model and match them - * to the thisayer one */ - for (float i = 0; i < g_pbones.length; i++) { - vector bpos; - float pbone = gettagindex(this, g_pbones[i]); - float wbone = gettagindex(p_model, g_pbones[i]); - - /* if the bone doesn't ignore in either skeletal mesh, ignore */ - if (wbone <= 0 || pbone <= 0) - continue; - - bpos = gettaginfo(this, pbone); - - /* the most expensive bit */ - skel_set_bone_world(p_model, wbone, bpos, v_forward, v_right, v_up); - } -} - -void HUD_AmmoNotify_Check(CSPlayer pl); /* ================= CSPlayer::ReceiveEntity @@ -351,7 +217,7 @@ CSPlayer::ReceiveEntity void CSPlayer::ReceiveEntity(float flIsNew, float flChanged) { - super::ReceiveEntity(flIsNew, flChanged); + NSClientPlayer::ReceiveEntity(flIsNew, flChanged); /* animation */ READENTITY_BYTE(anim_top, PLAYER_TOPFRAME) @@ -393,11 +259,6 @@ CSPlayer::PredictPreFrame(void) SAVE_STATE(cs_prev_hor_rec) SAVE_STATE(cs_hor_rec_sign) SAVE_STATE(cs_rec_reverse_chance) - SAVE_STATE(anim_top) - SAVE_STATE(anim_top_time) - SAVE_STATE(anim_top_delay) - SAVE_STATE(anim_bottom) - SAVE_STATE(anim_bottom_time) } /* @@ -417,14 +278,429 @@ CSPlayer::PredictPostFrame(void) ROLL_BACK(cs_prev_hor_rec) ROLL_BACK(cs_hor_rec_sign) ROLL_BACK(cs_rec_reverse_chance) - ROLL_BACK(anim_top) - ROLL_BACK(anim_top_time) - ROLL_BACK(anim_top_delay) - ROLL_BACK(anim_bottom) - ROLL_BACK(anim_bottom_time) } #else +/** @brief Aim towards a given (vector)aimpos with a given (float)lerp speed. + * + * @note + * Copied code from nuclide botlib (inside bot::RunAI), maybe make this a + * method there, could be usefull for other stuff? + **/ +void CSPlayer::Bot_AimLerp(vector aimpos, float flLerp) { + vector aimdir, vecNewAngles; + + vector oldAngle = v_angle; + + /* that's the old angle */ + vecNewAngles = anglesToForward(v_angle); + + /* aimdir = new final angle */ + aimdir = vectorToAngles(aimpos - origin); + + /* slowly lerp towards the final angle */ + vecNewAngles = vectorLerp(vecNewAngles, anglesToForward(aimdir), flLerp); + + /* make sure we're aiming tight */ + v_angle = vectorToAngles(vecNewAngles); + input_angles = angles = v_angle = fixAngle(v_angle); +} + +void +CSPlayer::Bot_RunToConfront(void) +{ + entity t; + + if (team == TEAM_T) { + t = Route_SelectRandom(teams.SpawnPoint(TEAM_CT)); + } else { + t = Route_SelectRandom(teams.SpawnPoint(TEAM_T)); + } + + ChatSayTeam("Going to run to the Enemy Spawn!"); + + if (t) + RouteToPosition(t.origin); +} +/* go to the planted bomb */ +void +CSPlayer::Bot_RunToBomb(void) +{ + NSEntity e = __NULL__; + e = (NSEntity)find(e, ::model, "models/w_c4.mdl"); + + if (e) { + RouteToPosition(e.WorldSpaceCenter()); + ChatSayTeam("Going to run to the Bomb!"); + } +} + +/* go to given bombsite */ +void +CSPlayer::Bot_RunToBombsite(int bombsiteIndex) +{ + NSEntity e = GetBombsiteByIndex(bombsiteIndex); + RouteToPosition(e.WorldSpaceCenter()); + ChatSayTeam(strcat("Going to run to Bomb Site ", itos(bombsiteIndex), "!")); +} + +/* go to random bombsite */ +void +CSPlayer::Bot_RunToRandomBombsite(void) +{ + Bot_RunToBombsite(random(0, serverinfo.GetInteger("cs_bombzones"))); +} + +/* go to given escape zone */ +void +CSPlayer::Bot_RunToEscapeZone(int index) +{ + NSEntity e = GetEscapeZoneByIndex(index); + RouteToPosition(e.WorldSpaceCenter()); + ChatSayTeam(strcat("Going to run to Escape Zone ", itos(index), "!")); +} + +/* go to a random escape zone */ +void +CSPlayer::Bot_RunToRandomEscapeZone(void) +{ + Bot_RunToEscapeZone(random(0, serverinfo.GetInteger("cs_escapezones"))); +} + +/* go to given VIP Safety Zone */ +void +CSPlayer::Bot_RunToVIPSafetyZone(int index) +{ + NSEntity e = GetVIPSafetyZoneByIndex(index); + RouteToPosition(e.WorldSpaceCenter()); + ChatSayTeam(strcat("Going to run to VIP Safety Zone ", itos(index), "!")); +} + +/* go to a random VIP Safety Zone */ +void +CSPlayer::Bot_RunToRandomVIPSafetyZone(void) +{ + Bot_RunToVIPSafetyZone(random(0, serverinfo.GetInteger("cs_vipzones"))); +} + +void +CSPlayer::Bot_RunToHostages(void) +{ + NSEntity e = __NULL__; + + e = (NSEntity)find(e, ::classname, "hostage_entity"); + + RouteToPosition(e.origin); + ChatSayTeam("Going to run to the hostages!"); +} + +/** @brief Let the bot roam within a maximum distance from a given origin. */ +void CSPlayer::Bot_Roam(vector roamOrigin, int maxDistance) { + /* Get random point whitin a radius from the given origin */ + int angle = random(0, 360); /* random angle. */ + int distance = random(0, maxDistance); /* random distance */ + float radian = angle * 3.145238095238 / 180; + vector randLoc = roamOrigin; + randLoc.x += sin(radian) * distance; + randLoc.y += cos(radian) * distance; + + /* Go to the random waypoint. */ + RouteToPosition(Nodes_PositionOfClosestNode(randLoc)); +} + +void +CSPlayer::Bot_CreateObjective(void) +{ + /* Bomb defuse map */ + if (serverinfo.GetInteger("cs_bombzones") > 0) { + /* Bomb is planted */ + if (serverinfo.GetBool("cs_bombplanted")) { + entity eBomb = find(world, ::model, "models/w_c4.mdl"); + if (eBomb == world) { + /* No bomb model found, but it is/was planted */ + + /* RoundOver: Bomb is defused */ + if (serverkeyfloat("cs_gamestate") == GAME_END) { + Bot_RunToRandomBombsite(); + return; + } + + /* Error */ + print("WARNING! g_cs_bombplanted == TRUE, but bomb model " + "cannot be found in the world.\n"); + return; + } + + if (team == TEAM_CT) { + if (serverinfo.GetBool("cs_bombbeingdefused") && m_actionIsDefusing == FALSE) { + /* Bomb is being defused but not by this bot */ + /* Go and roam the defuser */ + Bot_Roam(eBomb.origin, 300); + return; + } + + if (m_actionIsDefusing) { + if (serverinfo.GetBool("cs_bombbeingdefused") == false) { + /* Defusing complete or somehow failed. */ + m_actionIsDefusing = FALSE; + } else { + /* Continue defusing. */ + input_buttons |= (INPUT_BUTTON5 | INPUT_BUTTON8); + input_movevalues = [0,0,0]; + button5 = input_buttons & INPUT_BUTTON5; // don't release button5 + } + } + else { + int distToBomb = floor(vlen(eBomb.origin - origin)); + if (distToBomb > 60) { + /* To far away from the bomb to defuse it, run to it! */ + Bot_RunToBomb(); + } else { + /* Aim at the bomb. */ + input_buttons |= INPUT_BUTTON8; // duck + if ((HasVFlags(VFL_ONUSABLE))) { + // Aimed at the bomb, ready to defuse! + ChatSayTeam("Defusing!"); + input_buttons |= INPUT_BUTTON5; + input_movevalues = [0,0,0]; + button5 = input_buttons & INPUT_BUTTON5; // don't release button5 + m_actionIsDefusing = TRUE; + } else { + // Do the real aiming + float flLerp = bound(0.0f, frametime * 45, 1.0f); // aim speed + Bot_AimLerp(eBomb.origin + [0, 0, -6], flLerp); + } + } + } + } + /* team == TEAM_T */ + else { + /* Let T bots roam around the planted bomb */ + Bot_Roam(eBomb.origin, 500); + } + return; + } + /* Bomb is NOT planted */ + else { + if (team == TEAM_T) { + /* T-bot: plant bomb */ + if (HasItem("weapon_c4")) { + /* We carry the bomb */ + if (m_gflagsBackup & GF_BOMBZONE) { + /* We are at a bombsite and ready to plant the bomb */ + if (GetCurrentWeapon() != "weapon_c4") { + /* TODO: REPLACE THIS WITH NSNAVAI METHOD */ + SwitchToWeapon("weapon_c4"); + //Weapons_Draw((CSPlayer)self); + } + + if (!m_actionIsPlanting) { + ChatSayTeam("Going to plant the bomb!"); + m_actionIsPlanting = TRUE; + } + + /* Workaround */ + gflags = m_gflagsBackup; + + /* Duck and plant bomb. */ + input_buttons = (INPUT_BUTTON0 | INPUT_BUTTON8); + input_movevalues = [0,0,0]; + } + else { + /* Go to a bombsite first */ + Bot_RunToRandomBombsite(); + } + return; + } + else { + /* T-bot: check if the bomb has been dropped */ + NSEntity e = (NSEntity)find(world, ::model, "models/w_backpack.mdl"); + + if (e != __NULL__) { + /* The bomb backpack has been dropped */ + /* Go fetch dropped bomb! */ + ChatSayTeam("Arrr! Bomb on the ground, going to fetch it!"); + RouteToPosition(e.WorldSpaceCenter()); + return; + } + } + } + } + } + + if (serverinfo.GetInteger("cs_escapezones") > 0i && team == TEAM_T) { + Bot_RunToRandomEscapeZone(); + return; + } + + if (random() < 0.5 && serverinfo.GetInteger("cs_escapezones") > 0i && team == TEAM_CT) { + Bot_RunToRandomEscapeZone(); + return; + } + + if (serverinfo.GetInteger("cs_vipzones") > 0i && team == TEAM_CT) { + Bot_RunToRandomVIPSafetyZone(); + return; + } + + if (random() < 0.5 && serverinfo.GetInteger("cs_vipzones") > 0i && team == TEAM_T) { + Bot_RunToRandomVIPSafetyZone(); + return; + } + + if (random() < 0.5) { + if (serverinfo.GetInteger("cs_hostages") > 0) { + Bot_RunToHostages(); + } + if (serverinfo.GetInteger("cs_bombzones") > 0) { + Bot_RunToRandomBombsite(); + } + } else { + Bot_RunToConfront(); + } +} + +float ConsoleCmd(string cmd); + +void +CSPlayer::Bot_Buy(void) +{ + int done = 0; + int count = 0; + CSPlayer pl = (CSPlayer)self; + int playerMoney = userinfo.GetInteger(pl, "*money"); + string weaponToBuy = ""; + int weaponPrice = 0i; + + if (pl.team == TEAM_T) { + weaponToBuy = userinfo.GetString(pl, "fav_primary_ct"); + } else if (pl.team == TEAM_CT) { + weaponToBuy = userinfo.GetString(pl, "fav_primary_t"); + } + + /* Workaround */ + pl.gflags = m_gflagsBackup; + + if (STRING_SET(weaponToBuy)) { + weaponPrice = entityDef.GetInteger(weaponToBuy, "price"); + + if (weaponPrice <= userinfo.GetInteger(pl, "*money")) { + ConsoleCmd(strcat("buy ", weaponToBuy)); + playerMoney = userinfo.GetInteger(pl, "*money"); + } else { + weaponToBuy = ""; + } + } + + + /* CT: Random buy bomb defuse kit when enough money left */ + if (pl.team == TEAM_CT && serverinfo.GetInteger("cs_bombzones") > 0 && + entityDef.GetInteger("item_defuse", "price") <= playerMoney && + random() < 0.5) + { + ConsoleCmd("item_defuse"); + playerMoney = userinfo.GetInteger(pl, "*money"); + } + + /* need armor */ + if (pl.armor < 100) { + if (playerMoney >= entityDef.GetInteger("item_kevlar_helmet", "price")) { + ConsoleCmd("buy item_kevlar_helmet"); + } else if (playerMoney >= entityDef.GetInteger("item_kevlar", "price")) { + ConsoleCmd("buy item_kevlar"); + } + } else if (pl.HasItem("item_kevlar_helmet") == false) { + if (playerMoney >= 350) { + ConsoleCmd("buy item_kevlar_helmet"); + } + } + + if (STRING_SET(weaponToBuy)) { + SwitchToWeapon(weaponToBuy); + } + + /* force buy right now */ + ConsoleCmd("buyammo 0"); + ConsoleCmd("buyammo 1"); +} + + +void +CSPlayer::Input(entity eAct, string strInput, string strData) +{ + switch (strInput) { + case "RadioMessage": + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, EV_RADIOMSG); + WriteByte(MSG_MULTICAST, stof(strData)); + msg_entity = this; + multicast([0,0,0], MULTICAST_ONE); + break; + case "RadioTeamMessage": + tokenize(strData); + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, EV_RADIOMSG2); + WriteByte(MSG_MULTICAST, stof(argv(0))); + WriteByte(MSG_MULTICAST, stof(argv(1))); + msg_entity = this; + multicast([0,0,0], MULTICAST_ONE); + break; + case "NotifyBuyStart": + if (IsAlive() == false) { + return; + } + + ScheduleThink(Bot_Buy, random(0, cvars.GetFloat("mp_freezetime"))); + break; + case "NotifyRoundStarted": + if (clienttype(this) != CLIENTTYPE_REAL) { + if (IsAlive() == false) { + return; + } + + if (GetTeam() == TEAM_T) { + return; + } + + Bot_RunToRandomBombsite(); + } + break; + case "NotifyRoundRestarted": + /* bot stuff */ + m_actionIsPlanting = FALSE; + m_actionIsDefusing = FALSE; + break; + case "NotifyBombPlanted": + if (clienttype(this) != CLIENTTYPE_REAL) { + if (IsAlive() == false) { + return; + } + + if (GetTeam() == TEAM_T) { + return; + } + + Bot_RunToRandomBombsite(); + } + break; + case "NotifyHostageRescued": + if (clienttype(this) != CLIENTTYPE_REAL) { + if (IsAlive() == false) { + return; + } + + if (GetTeam() == TEAM_T) { + return; + } + + Bot_RunToHostages(); + } + break; + default: + super::Input(eAct, strInput, strData); + } +} + void CSPlayer::ServerInputFrame(void) { @@ -465,7 +741,7 @@ CSPlayer::SendEntity(entity ePEnt, float flChanged) flChanged = OptimiseChangedFlags(ePEnt, flChanged); - super::SendEntity(ePEnt, flChanged); + NSClientPlayer::SendEntity(ePEnt, flChanged); SENDENTITY_BYTE(anim_top, PLAYER_TOPFRAME) SENDENTITY_FLOAT(anim_top_time, PLAYER_TOPFRAME) @@ -481,3 +757,50 @@ CSPlayer::SendEntity(entity ePEnt, float flChanged) return (1); } #endif + +void +CSPlayer::Physics_Fall(float impactspeed) +{ + /* apply some predicted punch to the player */ + if (impactspeed >= 580) + punchangle += [15,0,(input_sequence & 1) ? 15 : -15]; + else if (impactspeed >= 400) + punchangle += [15,0,0]; + + impactspeed *= 1.25f; + + /* basic server-side falldamage */ +#ifdef SERVER + /* if we've reached a fallheight of PHY_FALLDMG_DISTANCE qu, start applying damage */ + if (impactspeed >= 580) { + float impactDamage = (impactspeed - 580) * (100 / (1024 - 580)) * 0.75f; + + /* this is kinda ugly, but worth the price */ + NSDict damageDecl = spawn(NSDict); + damageDecl.AddKey("damage", ftos((int)impactDamage)); + Damage(this, this, damageDecl, 1.0, g_vec_null, origin); + remove(damageDecl); + StartSoundDef("Player.FallDamage", CHAN_VOICE, true); + } else if (impactspeed >= 400) { + StartSoundDef("Player.LightFall", CHAN_VOICE, true); + } +#endif +} + +void +CSPlayer::Physics_Jump(void) +{ + if (waterlevel >= 2) { + if (watertype == CONTENT_WATER) { + velocity[2] = 100; + } else if (watertype == CONTENT_SLIME) { + velocity[2] = 80; + } else { + velocity[2] = 50; + } + } else { + /* slow the player down a bit to prevent bhopping like crazy */ + velocity *= 0.80f; + velocity[2] += 260; + } +} diff --git a/src/shared/pmove.qc b/src/shared/pmove.qc deleted file mode 100644 index 9a67b0a..0000000 --- a/src/shared/pmove.qc +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2016-2024 Marco Cawthorne - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#define PMOVE_STEPHEIGHT 18 -#define PMOVE_AIRSTEPHEIGHT 0 -#define PMOVE_FRICTION 4 -#define PMOVE_EDGEFRICTION 1 -#define PMOVE_STOPSPEED 75 -#define PMOVE_GRAVITY 800 -#define PMOVE_AIRACCELERATE 10 -#define PMOVE_WATERACCELERATE 8 -#define PMOVE_ACCELERATE 4 -#define PMOVE_MAXSPEED 250 -#define PMOVE_STEP_WALKSPEED 270 -#define PMOVE_STEP_CROUCHSPEED 90 -#define PMOVE_BOXCENTER true -#define PMOVE_NORMAL_HEIGHT 72 -#define PMOVE_NORMAL_VIEWHEIGHT 54 -#define PMOVE_CROUCH_HEIGHT 36 -#define PMOVE_CROUCH_VIEWHEIGHT 30 - -/* disable prone, run and lean */ -#define PMOVE_STEP_RUNSPEED 0 -#define PMOVE_PRONE_HEIGHT 0 - -.float waterlevel; -.float watertype; - -void -CSPlayer::Physics_Fall(float impactspeed) -{ - impactspeed *= 1.25f; - if (impactspeed > 580) { -#ifdef SERVER - float fFallDamage = (impactspeed - 580) * (100 / (1024 - 580)) * 0.75f; - //Damage_Apply(this, world, fFallDamage, 0, DMG_FALL | DMG_SKIP_ARMOR); - - if (random() < 0.5) - sound(this, CHAN_AUTO, "player/pl_pain2.wav", 1.0, ATTN_NORM); - else - sound(this, CHAN_AUTO, "player/pl_pain4.wav", 1.0, ATTN_NORM); -#endif - } -} - -void -CSPlayer::Physics_Jump(void) -{ - if (waterlevel >= 2) { - if (watertype == CONTENT_WATER) { - velocity[2] = 100; - } else if (watertype == CONTENT_SLIME) { - velocity[2] = 80; - } else { - velocity[2] = 50; - } - } else { - /* slow the player down a bit to prevent bhopping like crazy */ - velocity *= 0.80f; - velocity[2] += 260; - } -} diff --git a/src/shared/skeleton.h b/src/shared/skeleton.h new file mode 100644 index 0000000..d587b4e --- /dev/null +++ b/src/shared/skeleton.h @@ -0,0 +1,82 @@ +#ifdef CLIENT +/* Here's a list of bone names that we are aware of on HL player models. + Usually we'd use skeletalobjects to share the same skeleton/anim with + another model - but because FTEQW does not support that for HLMDL we + are forced to manually position the bones of our attachnment + by iterating over them and manually setting their position in 3D-space. +*/ +string g_pbones[] = +{ + "Bip01", + "Bip01 Footsteps", + "Bip01 Pelvis", + "Bip01 L Leg", + "Bip01 L Leg1", + "Bip01 L Foot", + "Bip01 L Toe0", + "Bip01 L Toe01", + "Bip01 L Toe02", + "Dummy16", + "Bip01 R Leg", + "Bip01 R Leg1", + "Bip01 R Foot", + "Bip01 R Toe0", + "Bip01 R Toe01", + "Bip01 R Toe02", + "Dummy11", + "Bip01 Spine", + "Bip01 Spine1", + "Bip01 Spine2", + "Bip01 Spine3", + "Bip01 Neck", + "Bip01 Head", + "Dummy21", + "Dummy08", + "Bone02", + "Bone03", + "Bone04", + "Dummy05", + "Bone09", + "Bone10", + "Dummy04", + "Bone05", + "Bone06", + "Dummy03", + "Bone07", + "Bone08", + "Dummy09", + "Bone11", + "Bone12", +"Dummy10", + "Bone13", + "Bone14", + "Bone15", + "Bip01 L Arm", + "Bip01 L Arm1", + "Bip01 L Arm2", + "Bip01 L Hand", + "Bip01 L Finger0", + "Bip01 L Finger01", + "Bip01 L Finger02", + "Dummy06", + "Bip01 L Finger1", + "Bip01 L Finger11", + "Bip01 L Finger12", + "Dummy07", + "Bip01 R Arm", + "Bip01 R Arm1", + "Bip01 R Arm2", + "Bip01 R Hand", + "Bip01 R Finger0", + "Bip01 R Finger01", + "Bip01 R Finger02", + "Dummy01", + "Bip01 R Finger1", + "Bip01 R Finger11", + "Bip01 R Finger12", + "Dummy02", + "Box02", + "Bone08", + "Bone15" +}; +#endif \ No newline at end of file diff --git a/zpak001.pk3dir/decls/def/ammo.def b/zpak001.pk3dir/decls/def/ammo.def index f4bc7ee..3286acd 100644 --- a/zpak001.pk3dir/decls/def/ammo.def +++ b/zpak001.pk3dir/decls/def/ammo.def @@ -1,116 +1,69 @@ -// these have to be defined by the game. +// these have to be defined by the game. +// Counter-Strike ammo data courtesy of https://wiki.alliedmods.net/CS_weapons_information entityDef ammo_types { "ammo_none" "0" - "ammo_338magnum" "1" - "ammo_357sig" "2" - "ammo_45acp" "3" - "ammo_50ae" "4" - "ammo_556nato" "5" - "ammo_556natobox" "6" - "ammo_57mm" "7" - "ammo_762nato" "8" - "ammo_9mm" "9" - "ammo_buckshot" "10" - "ammo_hegrenade" "11" - "ammo_smokegrenade" "12" - "ammo_flashbang" "13" + "ammo_338magnum" "1" + "ammo_357sig" "2" + "ammo_45acp" "3" + "ammo_50ae" "4" + "ammo_556nato" "5" + "ammo_556natobox" "6" + "ammo_57mm" "7" + "ammo_762nato" "8" + "ammo_9mm" "9" + "ammo_buckshot" "10" + "ammo_hegrenade" "11" + "ammo_smokegrenade" "12" + "ammo_flashbang" "13" } entityDef ammo_names { "ammo_none" "None" - "ammo_338magnum" ".338 Lapua Magnum" - "ammo_357sig" ".357 SIG" - "ammo_45acp" ".45 ACP" - "ammo_50ae" ".50 Action Express" - "ammo_556nato" "5.56×45mm NATO" - "ammo_556natobox" "5.56×45mm NATO BOX" - "ammo_57mm" "FN 5.7×28mm" - "ammo_762nato" "7.62×51mm NATO" - "ammo_9mm" "9×19mm Parabellum" - "ammo_buckshot" "Buckshot" - "ammo_hegrenade" "HE Grenade" - "ammo_smokegrenade" "Smoke Grenade" - "ammo_flashbang" "Flashbang" + "ammo_338magnum" ".338 Lapua Magnum" + "ammo_357sig" ".357 SIG" + "ammo_45acp" ".45 ACP" + "ammo_50ae" ".50 Action Express" + "ammo_556nato" "5.56×45mm NATO" + "ammo_556natobox" "5.56×45mm NATO BOX" + "ammo_57mm" "FN 5.7×28mm" + "ammo_762nato" "7.62×51mm NATO" + "ammo_9mm" "9×19mm Parabellum" + "ammo_buckshot" "Buckshot" + "ammo_hegrenade" "HE Grenade" + "ammo_smokegrenade" "Smoke Grenade" + "ammo_flashbang" "Flashbang" } - -entityDef ammo_base -{ - "spawnclass" "NSItem" - "snd_acquire" "ammo.pickup" - "snd_respawn" "ammo.respawn" - "mins" "-16 -16 0" - "maxs" "16 16 16" - "model" "models/w_backpack.mdl" -} - -// these don't exist as pickups in the game, but -// might be helpful nonetheless -entityDef ammo_338magnum -{ - "editor_usage" "Ammo used by weapon_awp" - "inherit" "ammo_base" - "inv_ammo_338magnum" "10" -} - -entityDef ammo_357sig -{ - "editor_usage" "Ammo used by weapon_p228" - "inherit" "ammo_base" - "inv_ammo_357sig" "13" -} - -entityDef ammo_45acp -{ - "editor_usage" "Ammo used by weapon_mac10, weapon_ump45, weapon_usp45" - "inherit" "ammo_base" - "inv_ammo_45acp" "12" -} - -entityDef ammo_50ae -{ - "editor_usage" "Ammo used by weapon_deagle" - "inherit" "ammo_base" - "inv_ammo_50ae" "7" -} - -entityDef ammo_556nato -{ - "editor_usage" "Ammo used by weapon_m4a1, weapon_sg550, weapon_sg552" - "inherit" "ammo_base" - "inv_ammo_556nato" "30" -} - -entityDef ammo_556natobox -{ - "editor_usage" "Ammo used by weapon_m249" - "inherit" "ammo_base" - "inv_ammo_556natobox" "30" -} - -entityDef ammo_57mm -{ - "editor_usage" "Ammo used by weapon_fiveseven, weapon_p90" - "inherit" "ammo_base" - "inv_ammo_57mm" "50" -} - -entityDef ammo_762nato -{ - "editor_usage" "Ammo used by weapon_aug, weapon_famas, weapon_g3sg1, weapon_galil, weapon_ak47, weapon_scout" - "inherit" "ammo_base" - "inv_ammo_762nato" "30" -} - -entityDef ammo_9mm -{ - "editor_usage" "Ammo used by weapon_elites, weapon_glock18, weapon_mp5navy, weapon_tmp" - "inherit" "ammo_base" - "inv_ammo_9mm" "30" -} - -entityDef ammo_buckshot -{ - "editor_usage" "Ammo used by weapon_m3, weapon_xm1014" - "inherit" "ammo_base" - "inv_ammo_buckshot" "8" -} + +entityDef ammo_max { + "ammo_none" "0" + "ammo_338magnum" "30" + "ammo_357sig" "52" + "ammo_45acp" "100" + "ammo_50ae" "35" + "ammo_556nato" "90" + "ammo_556natobox" "200" + "ammo_57mm" "100" + "ammo_762nato" "90" + "ammo_9mm" "120" + "ammo_buckshot" "32" + "ammo_hegrenade" "1" + "ammo_smokegrenade" "1" + "ammo_flashbang" "2" +} + + +// these don't exist as pickups in the game, but +// might be helpful nonetheless for level designers + +#include "ammo/base.def" +#include "ammo/556natobox.def" +#include "ammo/338magnum.def" +#include "ammo/9mm.def" +#include "ammo/556nato.def" +#include "ammo/762nato.def" +#include "ammo/50ae.def" +#include "ammo/45acp.def" +#include "ammo/buckshot.def" +#include "ammo/base.def" +#include "ammo/57mm.def" +#include "ammo/357sig.def" diff --git a/zpak001.pk3dir/decls/def/ammo/338magnum.def b/zpak001.pk3dir/decls/def/ammo/338magnum.def new file mode 100644 index 0000000..aa33fdf --- /dev/null +++ b/zpak001.pk3dir/decls/def/ammo/338magnum.def @@ -0,0 +1,7 @@ +entityDef ammo_338magnum +{ + "editor_usage" "Ammo used by weapon_awp" + "inherit" "ammo_base" + "inv_ammo_338magnum" "10" + "price" "125" +} diff --git a/zpak001.pk3dir/decls/def/ammo/357sig.def b/zpak001.pk3dir/decls/def/ammo/357sig.def new file mode 100644 index 0000000..22bdfbb --- /dev/null +++ b/zpak001.pk3dir/decls/def/ammo/357sig.def @@ -0,0 +1,7 @@ +entityDef ammo_357sig +{ + "editor_usage" "Ammo used by weapon_p228" + "inherit" "ammo_base" + "inv_ammo_357sig" "13" + "price" "50" +} diff --git a/zpak001.pk3dir/decls/def/ammo/45acp.def b/zpak001.pk3dir/decls/def/ammo/45acp.def new file mode 100644 index 0000000..f726e8c --- /dev/null +++ b/zpak001.pk3dir/decls/def/ammo/45acp.def @@ -0,0 +1,7 @@ +entityDef ammo_45acp +{ + "editor_usage" "Ammo used by weapon_mac10, weapon_ump45, weapon_usp45" + "inherit" "ammo_base" + "inv_ammo_45acp" "12" + "price" "25" +} diff --git a/zpak001.pk3dir/decls/def/ammo/50ae.def b/zpak001.pk3dir/decls/def/ammo/50ae.def new file mode 100644 index 0000000..2fe878e --- /dev/null +++ b/zpak001.pk3dir/decls/def/ammo/50ae.def @@ -0,0 +1,7 @@ +entityDef ammo_50ae +{ + "editor_usage" "Ammo used by weapon_deagle" + "inherit" "ammo_base" + "inv_ammo_50ae" "7" + "price" "40" +} diff --git a/zpak001.pk3dir/decls/def/ammo/556nato.def b/zpak001.pk3dir/decls/def/ammo/556nato.def new file mode 100644 index 0000000..38aa1d1 --- /dev/null +++ b/zpak001.pk3dir/decls/def/ammo/556nato.def @@ -0,0 +1,7 @@ +entityDef ammo_556nato +{ + "editor_usage" "Ammo used by weapon_m4a1, weapon_sg550, weapon_sg552" + "inherit" "ammo_base" + "inv_ammo_556nato" "30" + "price" "60" +} diff --git a/zpak001.pk3dir/decls/def/ammo/556natobox.def b/zpak001.pk3dir/decls/def/ammo/556natobox.def new file mode 100644 index 0000000..dc6b555 --- /dev/null +++ b/zpak001.pk3dir/decls/def/ammo/556natobox.def @@ -0,0 +1,7 @@ +entityDef ammo_556natobox +{ + "editor_usage" "Ammo used by weapon_m249" + "inherit" "ammo_base" + "inv_ammo_556natobox" "30" + "price" "60" +} diff --git a/zpak001.pk3dir/decls/def/ammo/57mm.def b/zpak001.pk3dir/decls/def/ammo/57mm.def new file mode 100644 index 0000000..bef6162 --- /dev/null +++ b/zpak001.pk3dir/decls/def/ammo/57mm.def @@ -0,0 +1,7 @@ +entityDef ammo_57mm +{ + "editor_usage" "Ammo used by weapon_fiveseven, weapon_p90" + "inherit" "ammo_base" + "inv_ammo_57mm" "50" + "price" "50" +} diff --git a/zpak001.pk3dir/decls/def/ammo/762nato.def b/zpak001.pk3dir/decls/def/ammo/762nato.def new file mode 100644 index 0000000..a16dec0 --- /dev/null +++ b/zpak001.pk3dir/decls/def/ammo/762nato.def @@ -0,0 +1,7 @@ +entityDef ammo_762nato +{ + "editor_usage" "Ammo used by weapon_aug, weapon_famas, weapon_g3sg1, weapon_galil, weapon_ak47, weapon_scout" + "inherit" "ammo_base" + "inv_ammo_762nato" "30" + "price" "80" +} diff --git a/zpak001.pk3dir/decls/def/ammo/9mm.def b/zpak001.pk3dir/decls/def/ammo/9mm.def new file mode 100644 index 0000000..85c56f6 --- /dev/null +++ b/zpak001.pk3dir/decls/def/ammo/9mm.def @@ -0,0 +1,7 @@ +entityDef ammo_9mm +{ + "editor_usage" "Ammo used by weapon_elites, weapon_glock18, weapon_mp5navy, weapon_tmp" + "inherit" "ammo_base" + "inv_ammo_9mm" "30" + "price" "20" +} diff --git a/zpak001.pk3dir/decls/def/ammo/base.def b/zpak001.pk3dir/decls/def/ammo/base.def new file mode 100644 index 0000000..47c319c --- /dev/null +++ b/zpak001.pk3dir/decls/def/ammo/base.def @@ -0,0 +1,9 @@ +entityDef ammo_base +{ + "spawnclass" "NSItem" + "snd_acquire" "ammo.pickup" + "snd_respawn" "ammo.respawn" + "mins" "-16 -16 0" + "maxs" "16 16 16" + "model" "models/w_backpack.mdl" +} diff --git a/zpak001.pk3dir/decls/def/ammo/buckshot.def b/zpak001.pk3dir/decls/def/ammo/buckshot.def new file mode 100644 index 0000000..b11d9c0 --- /dev/null +++ b/zpak001.pk3dir/decls/def/ammo/buckshot.def @@ -0,0 +1,7 @@ +entityDef ammo_buckshot +{ + "editor_usage" "Ammo used by weapon_m3, weapon_xm1014" + "inherit" "ammo_base" + "inv_ammo_buckshot" "8" + "price" "65" +} diff --git a/zpak001.pk3dir/decls/def/monsters.def b/zpak001.pk3dir/decls/def/monsters.def index e69de29..4ccaf31 100644 --- a/zpak001.pk3dir/decls/def/monsters.def +++ b/zpak001.pk3dir/decls/def/monsters.def @@ -0,0 +1 @@ +// we have none! go away! diff --git a/zpak001.pk3dir/decls/def/player.def b/zpak001.pk3dir/decls/def/player.def index bb234ef..d7e33a4 100644 --- a/zpak001.pk3dir/decls/def/player.def +++ b/zpak001.pk3dir/decls/def/player.def @@ -2,3 +2,80 @@ entityDef player { "spawnclass" "CSPlayer" } + +entityDef player_mp +{ + "inherit" "player" + "def_precache" "weapon_ak47" + "def_precache" "weapon_aug" + "def_precache" "weapon_awp" + "def_precache" "weapon_c4" + "def_precache" "weapon_deagle" + "def_precache" "weapon_elite" + "def_precache" "weapon_famas" + "def_precache" "weapon_fiveseven" + "def_precache" "weapon_flashbang" + "def_precache" "weapon_g3sg1" + "def_precache" "weapon_galil" + "def_precache" "weapon_glock18" + "def_precache" "weapon_hegrenade" + "def_precache" "weapon_knife" + "def_precache" "weapon_m249" + "def_precache" "weapon_m3" + "def_precache" "weapon_m4a1" + "def_precache" "weapon_mac10" + "def_precache" "weapon_mp5navy" + "def_precache" "weapon_p228" + "def_precache" "weapon_p90" + "def_precache" "weapon_scout" + "def_precache" "weapon_sg550" + "def_precache" "weapon_sg552" + "def_precache" "weapon_smokegrenade" + "def_precache" "weapon_tmp" + "def_precache" "weapon_ump45" + "def_precache" "weapon_usp" + "def_precache" "weapon_xm1014" +} + +entityDef player_terrorist +{ + "inherit" "player_mp" + "ammo_9mm" "40" + "current_weapon" "1" + "item" "item_suit" + "spawnpoint" "info_player_deathmatch" + "team" "1" + "weapon" "weapon_knife,weapon_glock18" + + "model_class1" "models/player/terror/terror.mdl" + "model_class2" "models/player/leet/leet.mdl" + "model_class3" "models/player/arctic/arctic.mdl" + "model_class4" "models/player/guerilla/guerilla.mdl" +} + +entityDef player_counterterrorist +{ + "inherit" "player_mp" + "ammo_45acp" "24" + "current_weapon" "1" + "item" "item_suit" + "spawnpoint" "info_player_start" + "team" "2" + "weapon" "weapon_knife,weapon_usp" + + "model_class1" "models/player/urban/urban.mdl" + "model_class2" "models/player/gsg9/gsg9.mdl" + "model_class3" "models/player/sas/sas.mdl" + "model_class4" "models/player/gign/gign.mdl" +} + +entityDef player_vip +{ + "inherit" "player_mp" + "ammo_45acp" "24" + "current_weapon" "1" + "item" "item_suit" + "model" "models/player/vip/vip.mdl" + "team" "2" + "weapon" "weapon_knife,weapon_usp" +} diff --git a/zpak001.pk3dir/decls/def/weapons/ak47.def b/zpak001.pk3dir/decls/def/weapons/ak47.def index d14fd50..78365f3 100644 --- a/zpak001.pk3dir/decls/def/weapons/ak47.def +++ b/zpak001.pk3dir/decls/def/weapons/ak47.def @@ -10,10 +10,10 @@ entityDef weapon_ak47 "def_fireInfo" "fireInfo_ak47" "clipSize" "30" - "actFire" "3,4,5" - "actReload" "1" - "actDraw" "2" - "actIdle" "0" + "act_fire" "3,4,5" + "act_reload" "1" + "act_draw" "2" + "act_idle" "0" "snd_fire" "Weapon_AK47.Single" diff --git a/zpak001.pk3dir/decls/def/weapons/aug.def b/zpak001.pk3dir/decls/def/weapons/aug.def index 795c19b..f8d7351 100644 --- a/zpak001.pk3dir/decls/def/weapons/aug.def +++ b/zpak001.pk3dir/decls/def/weapons/aug.def @@ -10,10 +10,10 @@ entityDef weapon_aug "def_fireInfo" "fireInfo_aug" "clipSize" "30" - "actFire" "3,4,5" - "actReload" "1" - "actDraw" "2" - "actIdle" "0" + "act_fire" "3,4,5" + "act_reload" "1" + "act_draw" "2" + "act_idle" "0" "snd_fire" "Weapon_AUG.Single" diff --git a/zpak001.pk3dir/decls/def/weapons/awp.def b/zpak001.pk3dir/decls/def/weapons/awp.def index 3cb1a50..ec6d979 100644 --- a/zpak001.pk3dir/decls/def/weapons/awp.def +++ b/zpak001.pk3dir/decls/def/weapons/awp.def @@ -10,12 +10,12 @@ entityDef weapon_awp "def_fireInfo" "fireInfo_awp" "clipSize" "5" - "actFire" "1,2,3" + "act_fire" "1,2,3" "actAltFire" "" - "actHolster" "" - "actReload" "4" - "actDraw" "5" - "actIdle" "0" + "act_holster" "" + "act_reload" "4" + "act_draw" "5" + "act_idle" "0" "snd_fire" "Weapon_AWP.Single" diff --git a/zpak001.pk3dir/decls/def/weapons/c4.def b/zpak001.pk3dir/decls/def/weapons/c4.def index 52ceac3..79407b9 100644 --- a/zpak001.pk3dir/decls/def/weapons/c4.def +++ b/zpak001.pk3dir/decls/def/weapons/c4.def @@ -17,9 +17,9 @@ entityDef weapon_c4 "clipSize" "1" "trigger_delay" "3" // takes three seconds to charge - "actFire" "2" - "actDraw" "1" - "actIdle" "0" + "act_fire" "2" + "act_draw" "1" + "act_idle" "0" "actDelay" "3" "snd_fire" "C4.PlantSound" diff --git a/zpak001.pk3dir/decls/def/weapons/deagle.def b/zpak001.pk3dir/decls/def/weapons/deagle.def index 9ff23a9..ebe76da 100644 --- a/zpak001.pk3dir/decls/def/weapons/deagle.def +++ b/zpak001.pk3dir/decls/def/weapons/deagle.def @@ -9,11 +9,11 @@ entityDef weapon_deagle "def_fireInfo" "fireInfo_deagle" "clipSize" "7" - "actFire" "1,2" - "actFireLast" "3" - "actReload" "4" - "actDraw" "5" - "actIdle" "0" + "act_fire" "1,2" + "act_fireLast" "3" + "act_reload" "4" + "act_draw" "5" + "act_idle" "0" "snd_fire" "Weapon_DEagle.Single" diff --git a/zpak001.pk3dir/decls/def/weapons/elite.def b/zpak001.pk3dir/decls/def/weapons/elite.def index ed61dda..578bb91 100644 --- a/zpak001.pk3dir/decls/def/weapons/elite.def +++ b/zpak001.pk3dir/decls/def/weapons/elite.def @@ -11,11 +11,11 @@ entityDef weapon_elite "def_altFireInfo" "fireInfo_elite_alt" "clipSize" "30" - "actFire" "2,3,4,5,6" - "actFireLast" "7" - "actReload" "14" - "actDraw" "15" - "actIdle" "0" + "act_fire" "2,3,4,5,6" + "act_fireLast" "7" + "act_reload" "14" + "act_draw" "15" + "act_idle" "0" "snd_fire" "Weapon_ELITE.Single" "snd_altfire" "Weapon_ELITE.Single" @@ -61,6 +61,6 @@ entityDef fireInfo_elite entityDef fireInfo_elite_alt { "inherit" "fireInfo_elite" - "actFire" "8,9,10,11,12" - "actFireLast" "13" + "act_fire" "8,9,10,11,12" + "act_fireLast" "13" } diff --git a/zpak001.pk3dir/decls/def/weapons/famas.def b/zpak001.pk3dir/decls/def/weapons/famas.def index 2fd44b4..23b5b9b 100644 --- a/zpak001.pk3dir/decls/def/weapons/famas.def +++ b/zpak001.pk3dir/decls/def/weapons/famas.def @@ -10,12 +10,12 @@ entityDef weapon_famas "def_fireInfo" "fireInfo_famas" "clipSize" "" - "actFire" "" + "act_fire" "" "actAltFire" "" - "actHolster" "" - "actReload" "" - "actDraw" "" - "actIdle" "" + "act_holster" "" + "act_reload" "" + "act_draw" "" + "act_idle" "" "snd_fire" "Weapon_FAMAS.Single" diff --git a/zpak001.pk3dir/decls/def/weapons/fiveseven.def b/zpak001.pk3dir/decls/def/weapons/fiveseven.def index 6bc86de..71ef11f 100644 --- a/zpak001.pk3dir/decls/def/weapons/fiveseven.def +++ b/zpak001.pk3dir/decls/def/weapons/fiveseven.def @@ -10,11 +10,11 @@ entityDef weapon_fiveseven "def_fireInfo" "fireInfo_fiveseven" "clipSize" "20" - "actFire" "1,2" - "actFireLast" "3" - "actReload" "4" - "actDraw" "5" - "actIdle" "0" + "act_fire" "1,2" + "act_fireLast" "3" + "act_reload" "4" + "act_draw" "5" + "act_idle" "0" "snd_fire" "Weapon_FiveSeven.Single" diff --git a/zpak001.pk3dir/decls/def/weapons/flashbang.def b/zpak001.pk3dir/decls/def/weapons/flashbang.def index a026c1b..ffe5e05 100644 --- a/zpak001.pk3dir/decls/def/weapons/flashbang.def +++ b/zpak001.pk3dir/decls/def/weapons/flashbang.def @@ -19,8 +19,8 @@ entityDef weapon_flashbang "silent_fire" "1" "primed_fuse" "4" - "actIdle" "0" - "actDraw" "3" + "act_idle" "0" + "act_draw" "3" "actPull" "1" "actThrow" "2" diff --git a/zpak001.pk3dir/decls/def/weapons/g3sg1.def b/zpak001.pk3dir/decls/def/weapons/g3sg1.def index 924149b..926928a 100644 --- a/zpak001.pk3dir/decls/def/weapons/g3sg1.def +++ b/zpak001.pk3dir/decls/def/weapons/g3sg1.def @@ -10,10 +10,10 @@ entityDef weapon_g3sg1 "def_fireInfo" "fireInfo_g3sg1" "clipSize" "20" - "actFire" "1,2" - "actReload" "3" - "actDraw" "4" - "actIdle" "0" + "act_fire" "1,2" + "act_reload" "3" + "act_draw" "4" + "act_idle" "0" "snd_fire" "Weapon_G3SG1.Single" diff --git a/zpak001.pk3dir/decls/def/weapons/galil.def b/zpak001.pk3dir/decls/def/weapons/galil.def index 974a647..50abe5b 100644 --- a/zpak001.pk3dir/decls/def/weapons/galil.def +++ b/zpak001.pk3dir/decls/def/weapons/galil.def @@ -12,12 +12,12 @@ entityDef weapon_galil "clipSizeDefault" "25" "ammoType" "ammo_762nato" - "actFire" "5,6,7" + "act_fire" "5,6,7" "actAltFire" "2" - "actHolster" "4" - "actReload" "3" - "actDraw" "4" - "actIdle" "0,1" + "act_holster" "4" + "act_reload" "3" + "act_draw" "4" + "act_idle" "0,1" "snd_fire" "Weapon_Galil.Single" diff --git a/zpak001.pk3dir/decls/def/weapons/glock18.def b/zpak001.pk3dir/decls/def/weapons/glock18.def index f540e6f..fd86448 100644 --- a/zpak001.pk3dir/decls/def/weapons/glock18.def +++ b/zpak001.pk3dir/decls/def/weapons/glock18.def @@ -13,12 +13,12 @@ entityDef weapon_glock18 "ammoRequired" "1" "model_flash" "sprites/muzzleflash2.spr" - "actFire" "5" - "actFireLast" "6" - "actHolster" "9" - "actReload" "7,12" - "actDraw" "9,11" - "actIdle" "0,1,2" + "act_fire" "5" + "act_fireLast" "6" + "act_holster" "9" + "act_reload" "7,12" + "act_draw" "9,11" + "act_idle" "0,1,2" "snd_fire" "Weapon_Glock.Single" @@ -64,6 +64,6 @@ entityDef fireInfo_altglock18 "numProjectiles" "3" "fireRate" "0.5" "accuracyDivisor" "75" - "actFire" "3,4" + "act_fire" "3,4" "snd_fire" "Weapon_Glock.Burst" } diff --git a/zpak001.pk3dir/decls/def/weapons/hegrenade.def b/zpak001.pk3dir/decls/def/weapons/hegrenade.def index 8dc0d46..3332e5b 100644 --- a/zpak001.pk3dir/decls/def/weapons/hegrenade.def +++ b/zpak001.pk3dir/decls/def/weapons/hegrenade.def @@ -17,8 +17,8 @@ entityDef weapon_hegrenade "silent_fire" "1" "primed_fuse" "4" - "actIdle" "0" - "actDraw" "3" + "act_idle" "0" + "act_draw" "3" "actPull" "1" "actThrow" "2" diff --git a/zpak001.pk3dir/decls/def/weapons/knife.def b/zpak001.pk3dir/decls/def/weapons/knife.def index 5cb2118..058dcdd 100644 --- a/zpak001.pk3dir/decls/def/weapons/knife.def +++ b/zpak001.pk3dir/decls/def/weapons/knife.def @@ -1,40 +1,38 @@ entityDef weapon_knife { - "inherit" "CSBaseMelee" + "inherit" "CSBaseMelee" "editor_usage" "Knife Weapon" - "model" "models/w_knife.mdl" + "model" "models/w_knife.mdl" "model_view" "models/v_knife.mdl" // weapon specific - "def_melee" "damage_knife" - "melee_distance" "48" - "inv_name" "Knife Weapon" - "clipSize" "6" - "ammoType" "" + "def_onFire" "projectile_knife" + "testDistance" "-48" + "inv_name" "Knife Weapon" "ammoRequired" "0" - "clipSize" "0" + "clipSize" "0" "silent_fire" "1" - "meleeRateMiss" "0.7" - "meleeRateHit" "0.7" - - "actIdle" "0" - "actDraw" "3" - "actMeleeMiss" "1,2" - "actMeleeHit" "1,2" - - "hudSlot" "2" - "hudSlotPos" "0" -} - -entityDef damage_knife -{ - "damage" "skill:plr_knife" -// "kickDir" "-1 0 0" -// "knockback" "20" -// "push" "20000" - + "failRate" "0.7" + "fireRate" "0.7" "snd_hit" "Weapon_Knife.Hit" - "snd_miss" "Weapon_Knife.Slash" + "snd_failed" "Weapon_Knife.Slash" + + "act_idle" "0" + "act_draw" "3" + "act_fireFailed" "1,2" + "act_fire" "1,2" + + "hudSlot" "2" + "hudSlotPos" "0" +} + +entityDef projectile_knife +{ + "spawnclass" "NSProjectile" + "damage" "skill:plr_knife" + "is_bullet" "1" + "decal_impact" "Impact.Shot" + "detonate_on_world" "1" } diff --git a/zpak001.pk3dir/decls/def/weapons/m249.def b/zpak001.pk3dir/decls/def/weapons/m249.def index 1605b0d..0478f47 100644 --- a/zpak001.pk3dir/decls/def/weapons/m249.def +++ b/zpak001.pk3dir/decls/def/weapons/m249.def @@ -10,10 +10,10 @@ entityDef weapon_m249 "def_fireInfo" "fireInfo_m249" "clipSize" "100" - "actFire" "1,2" - "actReload" "3" - "actDraw" "4" - "actIdle" "0" + "act_fire" "1,2" + "act_reload" "3" + "act_draw" "4" + "act_idle" "0" "snd_fire" "Weapon_M249.Single" diff --git a/zpak001.pk3dir/decls/def/weapons/m3.def b/zpak001.pk3dir/decls/def/weapons/m3.def index 8ae2a41..b2230c0 100644 --- a/zpak001.pk3dir/decls/def/weapons/m3.def +++ b/zpak001.pk3dir/decls/def/weapons/m3.def @@ -10,12 +10,12 @@ entityDef weapon_m3 "def_fireInfo" "fireInfo_m3" "clipSize" "8" - "actFire" "1,2" - "actReloadStart" "5" - "actReload" "3" - "actReloadEnd" "4" - "actDraw" "6" - "actIdle" "0" + "act_fire" "1,2" + "act_reloadStart" "5" + "act_reload" "3" + "act_reloadEnd" "4" + "act_draw" "6" + "act_idle" "0" "snd_fire" "Weapon_M3.Single" diff --git a/zpak001.pk3dir/decls/def/weapons/m4a1.def b/zpak001.pk3dir/decls/def/weapons/m4a1.def index 0b01711..f5bf480 100644 --- a/zpak001.pk3dir/decls/def/weapons/m4a1.def +++ b/zpak001.pk3dir/decls/def/weapons/m4a1.def @@ -15,15 +15,15 @@ entityDef weapon_m4a1 "ammoPerShot" "1" "fireRate" "0.0875" - "altSilences" "1" - "actAddSil" "6" - "actDetachSil" "13" + "altMode" "1" + "act_modeOn" "6" + "act_modeOff" "13" // Unsilenced - "actFire" "8,9,10" - "actReload" "11" - "actDraw" "12" - "actIdle" "7" + "act_fire" "8,9,10" + "act_reload" "11" + "act_draw" "12" + "act_idle" "7" "snd_fire" "Weapon_M4A1.Single" @@ -62,9 +62,9 @@ entityDef fireInfo_m4a1 entityDef fireInfo_m4a1_silenced { "inherit" "fireInfo_m4a1" - "actFire" "1,2,3" - "actReload" "4" - "actDraw" "5" - "actIdle" "0" + "act_fire" "1,2,3" + "act_reload" "4" + "act_draw" "5" + "act_idle" "0" "snd_fire" "Weapon_M4A1.Silenced" } diff --git a/zpak001.pk3dir/decls/def/weapons/mac10.def b/zpak001.pk3dir/decls/def/weapons/mac10.def index eb7d2ea..fc9223c 100644 --- a/zpak001.pk3dir/decls/def/weapons/mac10.def +++ b/zpak001.pk3dir/decls/def/weapons/mac10.def @@ -10,10 +10,10 @@ entityDef weapon_mac10 "def_fireInfo" "fireInfo_mac10" "clipSize" "30" - "actFire" "3,4,5" - "actReload" "1" - "actDraw" "2" - "actIdle" "0" + "act_fire" "3,4,5" + "act_reload" "1" + "act_draw" "2" + "act_idle" "0" "snd_fire" "Weapon_MAC10.Single" diff --git a/zpak001.pk3dir/decls/def/weapons/mp5navy.def b/zpak001.pk3dir/decls/def/weapons/mp5navy.def index 89179ea..49d3813 100644 --- a/zpak001.pk3dir/decls/def/weapons/mp5navy.def +++ b/zpak001.pk3dir/decls/def/weapons/mp5navy.def @@ -10,10 +10,10 @@ entityDef weapon_mp5navy "def_fireInfo" "fireInfo_mp5navy" "clipSize" "30" - "actFire" "3,4,5" - "actReload" "1" - "actDraw" "2" - "actIdle" "0" + "act_fire" "3,4,5" + "act_reload" "1" + "act_draw" "2" + "act_idle" "0" "snd_fire" "Weapon_MP5Navy.Single" diff --git a/zpak001.pk3dir/decls/def/weapons/p228.def b/zpak001.pk3dir/decls/def/weapons/p228.def index 4b70c1c..a3ce888 100644 --- a/zpak001.pk3dir/decls/def/weapons/p228.def +++ b/zpak001.pk3dir/decls/def/weapons/p228.def @@ -11,11 +11,11 @@ entityDef weapon_p228 "clipSize" "13" - "actFire" "1,2,3" - "actFireLast" "4" - "actReload" "5" - "actDraw" "6" - "actIdle" "0" + "act_fire" "1,2,3" + "act_fireLast" "4" + "act_reload" "5" + "act_draw" "6" + "act_idle" "0" "snd_fire" "Weapon_P228.Single" diff --git a/zpak001.pk3dir/decls/def/weapons/p90.def b/zpak001.pk3dir/decls/def/weapons/p90.def index afc2c1e..d2ffa6b 100644 --- a/zpak001.pk3dir/decls/def/weapons/p90.def +++ b/zpak001.pk3dir/decls/def/weapons/p90.def @@ -10,10 +10,10 @@ entityDef weapon_p90 "def_fireInfo" "fireInfo_p90" "clipSize" "50" - "actFire" "3,4,5" - "actReload" "1" - "actDraw" "2" - "actIdle" "0" + "act_fire" "3,4,5" + "act_reload" "1" + "act_draw" "2" + "act_idle" "0" "snd_fire" "Weapon_P90.Single" diff --git a/zpak001.pk3dir/decls/def/weapons/scout.def b/zpak001.pk3dir/decls/def/weapons/scout.def index 8c65233..2e75ded 100644 --- a/zpak001.pk3dir/decls/def/weapons/scout.def +++ b/zpak001.pk3dir/decls/def/weapons/scout.def @@ -11,10 +11,10 @@ entityDef weapon_scout "clipSize" "10" - "actFire" "1,2" - "actReload" "3" - "actDraw" "4" - "actIdle" "0" + "act_fire" "1,2" + "act_reload" "3" + "act_draw" "4" + "act_idle" "0" "snd_fire" "Weapon_Scout.Single" diff --git a/zpak001.pk3dir/decls/def/weapons/sg550.def b/zpak001.pk3dir/decls/def/weapons/sg550.def index a4b190d..469e7a3 100644 --- a/zpak001.pk3dir/decls/def/weapons/sg550.def +++ b/zpak001.pk3dir/decls/def/weapons/sg550.def @@ -10,10 +10,10 @@ entityDef weapon_sg550 "def_fireInfo" "fireInfo_sg550" "clipSize" "30" - "actFire" "1,2" - "actReload" "3" - "actDraw" "4" - "actIdle" "0" + "act_fire" "1,2" + "act_reload" "3" + "act_draw" "4" + "act_idle" "0" "snd_fire" "Weapon_SG550.Single" diff --git a/zpak001.pk3dir/decls/def/weapons/sg552.def b/zpak001.pk3dir/decls/def/weapons/sg552.def index 4b23007..a36a068 100644 --- a/zpak001.pk3dir/decls/def/weapons/sg552.def +++ b/zpak001.pk3dir/decls/def/weapons/sg552.def @@ -11,10 +11,10 @@ entityDef weapon_sg552 "clipSize" "30" - "actFire" "3,4,5" - "actReload" "1" - "actDraw" "2" - "actIdle" "0" + "act_fire" "3,4,5" + "act_reload" "1" + "act_draw" "2" + "act_idle" "0" "snd_fire" "Weapon_SG552.Single" diff --git a/zpak001.pk3dir/decls/def/weapons/smokegrenade.def b/zpak001.pk3dir/decls/def/weapons/smokegrenade.def index 5de28d5..9da5809 100644 --- a/zpak001.pk3dir/decls/def/weapons/smokegrenade.def +++ b/zpak001.pk3dir/decls/def/weapons/smokegrenade.def @@ -17,12 +17,12 @@ entityDef weapon_smokegrenade "clipSize" "50" "clipSizeDefault" "25" - "actFire" "5,6,7" + "act_fire" "5,6,7" "actAltFire" "2" - "actHolster" "4" - "actReload" "3" - "actDraw" "4" - "actIdle" "0,1" + "act_holster" "4" + "act_reload" "3" + "act_draw" "4" + "act_idle" "0,1" "snd_fire" "weapon_smokegrenade.shoot" "snd_altfire" "weapon_smokegrenade.gl" diff --git a/zpak001.pk3dir/decls/def/weapons/tmp.def b/zpak001.pk3dir/decls/def/weapons/tmp.def index c00050e..90010a1 100644 --- a/zpak001.pk3dir/decls/def/weapons/tmp.def +++ b/zpak001.pk3dir/decls/def/weapons/tmp.def @@ -11,10 +11,10 @@ entityDef weapon_tmp "clipSize" "30" - "actFire" "3,4,5" - "actReload" "1" - "actDraw" "2" - "actIdle" "0" + "act_fire" "3,4,5" + "act_reload" "1" + "act_draw" "2" + "act_idle" "0" "snd_fire" "Weapon_TMP.Single" diff --git a/zpak001.pk3dir/decls/def/weapons/ump45.def b/zpak001.pk3dir/decls/def/weapons/ump45.def index 71655b0..ffbabf8 100644 --- a/zpak001.pk3dir/decls/def/weapons/ump45.def +++ b/zpak001.pk3dir/decls/def/weapons/ump45.def @@ -11,10 +11,10 @@ entityDef weapon_ump45 "clipSize" "25" - "actFire" "3,4,5" - "actReload" "1" - "actDraw" "2" - "actIdle" "0" + "act_fire" "3,4,5" + "act_reload" "1" + "act_draw" "2" + "act_idle" "0" "snd_fire" "Weapon_UMP45.Single" diff --git a/zpak001.pk3dir/decls/def/weapons/usp.def b/zpak001.pk3dir/decls/def/weapons/usp.def index 60cc9fd..ac3eae0 100644 --- a/zpak001.pk3dir/decls/def/weapons/usp.def +++ b/zpak001.pk3dir/decls/def/weapons/usp.def @@ -32,9 +32,9 @@ entityDef weapon_usp "semiAuto" "1" "ammoRequired" "1" - "altSilences" "1" - "actAddSil" "7" - "actDetachSil" "15" + "altMode" "1" + "act_modeOn" "7" + "act_modeOff" "15" "crossMinDist" "4" "crossDeltaDist" "4" @@ -49,11 +49,11 @@ entityDef weapon_usp "multiplierInaccuracy" "0.5" // Unsilenced - "actDraw" "14" - "actIdle" "8" - "actFire" "9,10,11" - "actFireLast" "12" - "actReload" "13" + "act_draw" "14" + "act_idle" "8" + "act_fire" "9,10,11" + "act_fireLast" "12" + "act_reload" "13" "snd_fire" "Weapon_USP.Single" "hudSlot" "1" @@ -77,10 +77,10 @@ entityDef fireInfo_usp45_sil { "def_onFire" "projectile_usp45" "model_flash" "sprites/muzzleflash2.spr" - "actDraw" "6" - "actIdle" "0" - "actReload" "5" - "actFire" "1,2,3" - "actFireLast" "4" + "act_draw" "6" + "act_idle" "0" + "act_reload" "5" + "act_fire" "1,2,3" + "act_fireLast" "4" "snd_fire" "Weapon_USP.SilencedShot" } diff --git a/zpak001.pk3dir/decls/def/weapons/xm1014.def b/zpak001.pk3dir/decls/def/weapons/xm1014.def index 3dd9377..6864e4b 100644 --- a/zpak001.pk3dir/decls/def/weapons/xm1014.def +++ b/zpak001.pk3dir/decls/def/weapons/xm1014.def @@ -12,12 +12,12 @@ entityDef weapon_xm1014 "ammoType" "ammo_buckshot" - "actFire" "1,2" - "actReloadStart" "5" - "actReload" "3" - "actReloadEnd" "4" - "actDraw" "6" - "actIdle" "0" + "act_fire" "1,2" + "act_reloadStart" "5" + "act_reload" "3" + "act_reloadEnd" "4" + "act_draw" "6" + "act_idle" "0" "snd_fire" "Weapon_XM1014.Single" diff --git a/zpak001.pk3dir/decls/sound/player.sndshd b/zpak001.pk3dir/decls/sound/player.sndshd index d2d69d5..3a46640 100644 --- a/zpak001.pk3dir/decls/sound/player.sndshd +++ b/zpak001.pk3dir/decls/sound/player.sndshd @@ -15,6 +15,15 @@ player.hitarmor sample player/bhit_kevlar-1.wav } +Player.Pain +{ + sample player/pl_pain2.wav + sample player/pl_pain4.wav + sample player/pl_pain5.wav + sample player/pl_pain6.wav + sample player/pl_pain7.wav +} + Player.FallDamage { sample player/pl_pain2.wav @@ -139,4 +148,4 @@ Player.Swim Player.PickupWeapon { sample items/gunpickup2.wav -} \ No newline at end of file +} diff --git a/zpak001.pk3dir/decls/typeinfo/hlmat.decl b/zpak001.pk3dir/decls/typeinfo/hlmat.decl new file mode 100644 index 0000000..4085426 --- /dev/null +++ b/zpak001.pk3dir/decls/typeinfo/hlmat.decl @@ -0,0 +1,19 @@ +typeInfo material +{ + "C" "gs_material_concrete" + "D" "gs_material_dirt" + "F" "gs_material_flesh" + "G" "gs_material_grate" + "H" "gs_material_alien" + "M" "gs_material_metal" + "O" "gs_material_foliage" + "P" "gs_material_computer" + "R" "gs_material_rocks" + "S" "gs_material_slosh" + "T" "gs_material_tile" + "V" "gs_material_vent" + "W" "gs_material_wood" + "Y" "gs_material_glass" + "N" "gs_material_sand" + "K" "gs_material_snow" +} diff --git a/zpak001.pk3dir/default.cfg b/zpak001.pk3dir/default.cfg index 1ad6480..b344a6d 100644 --- a/zpak001.pk3dir/default.cfg +++ b/zpak001.pk3dir/default.cfg @@ -1,45 +1,5 @@ exec default_controls.cfg - -// game specific binds -bind "b" "buy" -bind "m" "chooseteam" -bind "g" "drop" - -exec cvar_defaults.cfg - -// game specific cvars -seta "hostname" "FreeCS Server" -seta "maxplayers" "8" -seta "mp_startmoney" "800" -seta "mp_buytime" "90" -seta "mp_freezetime" "6" -seta "mp_c4timer" "45" -seta "mp_roundtime" "5" -seta "fcs_knifeonly" "0" -seta "fcs_swapteams" "0" -seta "fcs_nopickups" "0" -seta "fcs_reward_kill" "300" -seta "fcs_penalty_pain" "-150" -seta "fcs_penalty_kill" "-1500" -seta "fcs_maxmoney" "16000" -seta "fcs_fillweapons" "0" -seta "fcs_autoreload" "0" - -// cosmetic branding changes -seta "con_color" "255 150 0" -seta "vgui_color" "255 170 0" -seta "cross_color" "0 255 0" - -// physics differences from valve/ -seta pm_accelerate "4" -seta pm_airaccelerate "10" -seta pm_airstepsize "18" -seta pm_crouchviewheight "30" -seta pm_edgefriction "1" -seta pm_friction "4" -seta pm_gravity "800" -seta pm_normalviewheight "54" -seta pm_stepsize "18" -seta pm_stopspeed "75" -seta pm_walkspeed "250" -seta pm_wateraccelerate "8" +exec default_cvar.cfg +exec default_video.cfg +exec default_cstrike.cfg +exec default_aliases.cfg diff --git a/zpak001.pk3dir/default_aliases.cfg b/zpak001.pk3dir/default_aliases.cfg new file mode 100644 index 0000000..0a8a274 --- /dev/null +++ b/zpak001.pk3dir/default_aliases.cfg @@ -0,0 +1,57 @@ +// buy commands +alias ak47 "cmd buy weapon_ak47" +alias aug "cmd buy weapon_aug" +alias awp "cmd buy weapon_awp" +alias deagle "cmd buy weapon_deagle" +alias elites "cmd buy weapon_elite" +alias fn57 "cmd buy weapon_fiveseven" +alias g3sg1 "cmd buy weapon_g3sg1" +alias glock "cmd buy weapon_glock18" +alias m249 "cmd buy weapon_m249" +alias m3 "cmd buy weapon_m3" +alias m4a1 "cmd buy weapon_m4a1" +alias mac10 "cmd buy weapon_mac10" +alias mp5 "cmd buy weapon_mp5" +alias p228 "cmd buy weapon_p228" +alias p90 "cmd buy weapon_p90" +alias scout "cmd buy weapon_scout" +alias sg550 "cmd buy weapon_sg550" +alias sg552 "cmd buy weapon_sg552" +alias tmp "cmd buy weapon_tmp" +alias ump45 "cmd buy weapon_ump45" +alias usp "cmd buy weapon_usp" +alias xm1014 "cmd buy weapon_xm1014" + +alias primammo "cmd buyammo 0" +alias secammo "cmd buyammo 1" +alias buyammo1 "primammo" +alias buyammo2 "secammo" +alias vest "cmd buy item_kevlar" +alias vesthelm "cmd buy item_kevlar_helmet" +alias flash "cmd buy weapon_flashbang" +alias hegren "cmd buy weapon_hegrenade" +alias vsgren "cmd buy weapon_smokegrenade" +alias defuser "cmd buy item_defuse" +alias nvg "cmd buy item_nightvision" + +// radio commands +alias coverme "cmd coverme" +alias takepoint "cmd takepoint" +alias regroup "cmd regroup" +alias followme "cmd followme" +alias takingfire "cmd takingfire" +alias go "cmd go" +alias fallback "cmd fallback" +alias sticktog "cmd sticktog" +alias getinpos "cmd getinpos" +alias stormfront "cmd stormfront" +alias report "cmd report" +alias roger "cmd roger" +alias enemyspot "cmd enemyspot" +alias needbackup "cmd needbackup" +alias sectorclear "cmd sectorclear" +alias inposition "cmd inposition" +alias reportingin "cmd reportingin" +alias getout "cmd getout" +alias negative "cmd negative" +alias enemydown "cmd enemydown" diff --git a/zpak001.pk3dir/default_cstrike.cfg b/zpak001.pk3dir/default_cstrike.cfg new file mode 100644 index 0000000..b00627c --- /dev/null +++ b/zpak001.pk3dir/default_cstrike.cfg @@ -0,0 +1,41 @@ +// game specific binds +bind b "buy" +bind m "chooseteam" +bind g "drop" + +// game specific cvars +set hostname "FreeCS Server" +set maxplayers "8" +set mp_startmoney "800" +set mp_buytime "90" +set mp_freezetime "6" +set mp_c4timer "45" +set mp_roundtime "5" +set fcs_knifeonly "0" +set fcs_swapteams "0" +set fcs_nopickups "0" +set fcs_reward_kill "300" +set fcs_penalty_pain "-150" +set fcs_penalty_kill "-1500" +set fcs_maxmoney "16000" +set fcs_fillweapons "0" +set fcs_autoreload "0" + +// cosmetic branding changes +set con_color "255 150 0" +set vgui_color "255 170 0" +set cross_color "0 255 0" + +// physics differences from valve/ +set pm_accelerate "4" +set pm_airaccelerate "10" +set pm_airstepsize "18" +set pm_crouchviewheight "30" +set pm_edgefriction "1" +set pm_friction "4" +set pm_gravity "800" +set pm_normalviewheight "54" +set pm_stepsize "18" +set pm_stopspeed "75" +set pm_walkspeed "250" +set pm_wateraccelerate "8" diff --git a/zpak001.pk3dir/scripts/bots.txt b/zpak001.pk3dir/scripts/bots.txt index b127b78..dcac977 100644 --- a/zpak001.pk3dir/scripts/bots.txt +++ b/zpak001.pk3dir/scripts/bots.txt @@ -9,6 +9,10 @@ { name marco funname "]I[ M4RC0 ]I[" + fav_primary_ct weapon_mp5 + fav_primary_t weapon_mac10 + fav_secondary_ct weapon_deagle + fav_secondary_t weapon_elite } { name rich @@ -56,4 +60,4 @@ } { name DEViL -} \ No newline at end of file +} diff --git a/zpak001.pk3dir/scripts/client_style.txt b/zpak001.pk3dir/scripts/client_style.txt new file mode 100644 index 0000000..567c47b --- /dev/null +++ b/zpak001.pk3dir/scripts/client_style.txt @@ -0,0 +1,11 @@ +BG_COLOR=0 0 0 +BG_ALPHA=128 +FG_COLOR=255 170 0 +HILIGHT_COLOR=255 170 0 +SHADOW_COLOR=255 170 0 +BORDER_COLOR=255 170 0 +BORDER_ALPHA=128 +NOICONS=1 +ROUNDED=0 +HOVER_COLOR=255 170 +HOVER_ALPHA=128 diff --git a/zpak001.pk3dir/scripts/surfaceproperties.txt b/zpak001.pk3dir/scripts/surfaceproperties.txt deleted file mode 100644 index 5c051e2..0000000 --- a/zpak001.pk3dir/scripts/surfaceproperties.txt +++ /dev/null @@ -1,224 +0,0 @@ -default -{ - part_bulletimpact "impact_default.main" - bulletimpact "sfx_impact.default" - stepleft "step_default.left" - stepright "step_default.right" - scraperough "scrape.default" - scrapesmooth "scrape.default" -} - -gs_material_glass -{ - gamematerial Y - part_bulletimpact "impact_glass.main" - bulletimpact "sfx_impact.glass" - stepleft "step_glass.left" - stepright "step_glass.right" - break "func_breakable.break_glass" -} - -gs_material_wood -{ - gamematerial W - part_bulletimpact "impact_default.main" - bulletimpact "sfx_impact.wood" - stepleft "step_wood.left" - stepright "step_wood.right" - break "func_breakable.break_wood" -} - -gs_material_metal -{ - gamematerial M - part_bulletimpact "impact_unbreakable.main" - bulletimpact "sfx_impact.metal" - stepleft "step_metal.left" - stepright "step_metal.right" - break "func_breakable.break_metal" -} - -gs_material_ladder -{ - part_bulletimpact "impact_default.main" - bulletimpact "sfx_impact.metal" - stepleft "step_ladder.left" - stepright "step_ladder.right" -} - -gs_material_flesh -{ - gamematerial F - part_bulletimpact "impact_default.main" - bulletimpact "sfx_impact.flesh" - stepleft "step_flesh.left" - stepright "step_flesh.right" - break "func_breakable.break_flesh" -} - -gs_material_cinderblock -{ - part_bulletimpact "impact_default.main" - bulletimpact "sfx_impact.concrete" - stepleft "step_default.left" - stepright "step_default.right" - break "func_breakable.break_cinder" -} - -gs_material_tile -{ - gamematerial T - part_bulletimpact "impact_default.main" - bulletimpact "sfx_impact.tile" - stepleft "step_tile.left" - stepright "step_tile.right" - break "func_breakable.break_cinder" -} - -gs_material_computer -{ - gamematerial P - part_bulletimpact "impact_default.main" - bulletimpact "sfx_impact.computer" - stepleft "step_computer.left" - stepright "step_computer.right" - break "func_breakable.break_computer" -} - -gs_material_unbreakableglass -{ - part_bulletimpact "impact_unbreakable.main" - bulletimpact "sfx_impact.glass" - stepleft "step_glass.left" - stepright "step_glass.right" - break "func_breakable.break_glass" -} - -gs_material_rocks -{ - part_bulletimpact "impact_default.main" - bulletimpact "sfx_impact.concrete" - stepleft "step_default.left" - stepright "step_default.right" - break "func_breakable.break_cinder" -} - -gs_material_flesh -{ - gamematerial F - part_bulletimpact "impact_default.main" - bulletimpact "sfx_impact.flesh" - stepleft "step_flesh.left" - stepright "step_flesh.right" - break "func_breakable.break_flesh" -} - -gs_material_concrete -{ - gamematerial C - part_bulletimpact "impact_default.main" - bulletimpact "sfx_impact.concrete" - stepleft "step_concrete.left" - stepright "step_concrete.right" - break "func_breakable.break_cinder" -} - -gs_material_dirt -{ - gamematerial D - part_bulletimpact "impact_default.main" - bulletimpact "sfx_impact.dirt" - stepleft "step_dirt.left" - stepright "step_dirt.right" - break "func_breakable.break_rocks" -} - -gs_material_grate -{ - gamematerial G - part_bulletimpact "impact_default.main" - bulletimpact "sfx_impact.grate" - stepleft "step_grate.left" - stepright "step_grate.right" - break "func_breakable.break_metal" -} - -gs_material_alien -{ - gamematerial H - part_bulletimpact "impact_default.main" - bulletimpact "sfx_impact.alien" - stepleft "step_alien.left" - stepright "step_alien.right" - break "func_breakable.break_flesh" -} - -gs_material_snow -{ - gamematerial K - part_bulletimpact "impact_default.main" - bulletimpact "sfx_impact.snow" - stepleft "step_snow.left" - stepright "step_snow.right" -} - -gs_material_sand -{ - gamematerial N - part_bulletimpact "impact_default.main" - bulletimpact "sfx_impact.sand" - stepleft "step_sand.left" - stepright "step_sand.right" -} - -gs_material_foliage -{ - gamematerial O - part_bulletimpact "impact_default.main" - bulletimpact "sfx_impact.foliage" - stepleft "step_foliage.left" - stepright "step_foliage.right" -} - -gs_material_slosh -{ - gamematerial S - part_bulletimpact "impact_default.main" - bulletimpact "sfx_impact.slosh" - stepleft "step_slosh.left" - stepright "step_slosh.right" -} - -gs_material_vent -{ - gamematerial V - part_bulletimpact "impact_default.main" - bulletimpact "sfx_impact.snow" - stepleft "step_vent.left" - stepright "step_vent.right" - break "func_breakable.break_metal" -} - -water -{ - part_bulletimpact "fx_impact.water" - bulletimpact "sfx_impact.slosh" - stepleft "step_slosh.left" - stepright "step_slosh.right" -} - -lava -{ - part_bulletimpact "impact_default.main" - bulletimpact "sfx_impact.slosh" - stepleft "step_slosh.left" - stepright "step_slosh.right" -} - -slime -{ - part_bulletimpact "impact_default.main" - bulletimpact "sfx_impact.slosh" - stepleft "step_slosh.left" - stepright "step_slosh.right" -} \ No newline at end of file diff --git a/zpak001.pk3dir/scripts/surfaceproperties_cstrike.txt b/zpak001.pk3dir/scripts/surfaceproperties_cstrike.txt new file mode 100644 index 0000000..1e5b5ac --- /dev/null +++ b/zpak001.pk3dir/scripts/surfaceproperties_cstrike.txt @@ -0,0 +1,17 @@ +gs_material_snow +{ + gamematerial K + part_bulletimpact "impact_default.main" + bulletimpact "sfx_impact.snow" + stepleft "step_snow.left" + stepright "step_snow.right" +} + +gs_material_sand +{ + gamematerial N + part_bulletimpact "impact_default.main" + bulletimpact "sfx_impact.sand" + stepleft "step_sand.left" + stepright "step_sand.right" +} diff --git a/zpak001.pk3dir/scripts/surfaceproperties_manifest.txt b/zpak001.pk3dir/scripts/surfaceproperties_manifest.txt new file mode 100644 index 0000000..67385d2 --- /dev/null +++ b/zpak001.pk3dir/scripts/surfaceproperties_manifest.txt @@ -0,0 +1,5 @@ +surfaceproperties_manifest +{ + file "scripts/surfaceproperties_cstrike.txt" + file "scripts/surfaceproperties_valve.txt" +} diff --git a/zpak001.pk3dir/scripts/ui_style.txt b/zpak001.pk3dir/scripts/ui_style.txt new file mode 100644 index 0000000..d339a64 --- /dev/null +++ b/zpak001.pk3dir/scripts/ui_style.txt @@ -0,0 +1,10 @@ +BG_COLOR=76 88 58 +BG_ALPHA=255 +FG_COLOR=216 222 211 +FILL_COLOR=196 181 80 +HILIGHT_COLOR=255 255 255 +SHADOW_COLOR=0 0 0 +BORDER_COLOR=0 0 0 +BORDER_ALPHA=0 +NOICONS=1 +ROUNDED=0