From 9132b8470e5edea7552dff6cbe2bc4e7808d0fd0 Mon Sep 17 00:00:00 2001 From: BenCat07 Date: Mon, 11 Oct 2021 22:13:00 +0200 Subject: [PATCH] Add a spell forcer and fix a bunch of issues - Crithack + nospread compatibility fixes - Automelee hitting air - Nospread ghost crash --- data/menu/nullifiedcat/misc.xml | 1 + data/menu/nullifiedcat/misc/spellforcer.xml | 114 +++++++ include/core/netvars.hpp | 1 + include/playerresource.h | 1 + include/sdk/CGameRules.h | 19 +- src/core/netvars.cpp | 1 + src/crits.cpp | 2 +- src/hacks/CMakeLists.txt | 1 + src/hacks/Misc.cpp | 2 - src/hacks/NavBot.cpp | 2 +- src/hacks/SpellForcer.cpp | 321 ++++++++++++++++++++ src/hacks/Warp.cpp | 2 + src/hooks/GetUserCmd.cpp | 6 +- src/itemtypes.cpp | 182 +++++------ src/nospread.cpp | 2 +- src/playerresource.cpp | 10 + 16 files changed, 569 insertions(+), 98 deletions(-) create mode 100644 data/menu/nullifiedcat/misc/spellforcer.xml create mode 100644 src/hacks/SpellForcer.cpp diff --git a/data/menu/nullifiedcat/misc.xml b/data/menu/nullifiedcat/misc.xml index 6ad6c7f7..cd49315c 100755 --- a/data/menu/nullifiedcat/misc.xml +++ b/data/menu/nullifiedcat/misc.xml @@ -8,5 +8,6 @@ + diff --git a/data/menu/nullifiedcat/misc/spellforcer.xml b/data/menu/nullifiedcat/misc/spellforcer.xml new file mode 100644 index 00000000..00768cc3 --- /dev/null +++ b/data/menu/nullifiedcat/misc/spellforcer.xml @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/include/core/netvars.hpp b/include/core/netvars.hpp index 24af4f05..9cc9135a 100644 --- a/include/core/netvars.hpp +++ b/include/core/netvars.hpp @@ -171,6 +171,7 @@ public: offset_t res_iTeam; offset_t res_iScore; offset_t res_bAlive; + offset_t res_bValid; offset_t m_nChargeResistType; offset_t m_hHealingTarget; offset_t m_flChargeLevel; // Medigun diff --git a/include/playerresource.h b/include/playerresource.h index c54002e5..7abb62c7 100755 --- a/include/playerresource.h +++ b/include/playerresource.h @@ -29,6 +29,7 @@ public: int getClass(int idx); int getTeam(int idx); bool isAlive(int idx); + bool isValid(int idx); int entity; }; diff --git a/include/sdk/CGameRules.h b/include/sdk/CGameRules.h index 6b4095fa..94043007 100755 --- a/include/sdk/CGameRules.h +++ b/include/sdk/CGameRules.h @@ -15,4 +15,21 @@ public: int winning_team; // 56 | 4 bytes | 60 char pad2[974]; // 60 | 974 bytes | 1034 bool isPVEMode; // 1034 | 1 byte | 1035 -}; + char pad3[15]; // 1035 | 15 bytes | 1050 + int isUsingSpells; // 1050 | 4 bytes | 1054 + char pad4[790]; // 1054 | 790 bytes | 1844 + int halloweenScenario; // 1844 | 4 bytes | 1848 + + bool isUsingSpells_fn() + { + auto tf_spells_enabled = g_ICvar->FindVar("tf_spells_enabled"); + if (tf_spells_enabled->GetBool()) + return true; + + // Hightower + if (halloweenScenario == 4) + return true; + + return isUsingSpells; + } +} __attribute__((packed)); diff --git a/src/core/netvars.cpp b/src/core/netvars.cpp index 44c0ca6b..de92d12b 100644 --- a/src/core/netvars.cpp +++ b/src/core/netvars.cpp @@ -39,6 +39,7 @@ void NetVars::Init() this->m_flMaxspeed = gNetvars.get_offset("DT_BasePlayer", "m_flMaxspeed"); res_iTeam = gNetvars.get_offset("DT_TFPlayerResource", "baseclass", "m_iTeam"); res_bAlive = gNetvars.get_offset("DT_TFPlayerResource", "baseclass", "m_bAlive"); + res_bValid = gNetvars.get_offset("DT_TFPlayerResource", "baseclass", "m_bValid"); this->res_iMaxBuffedHealth = gNetvars.get_offset("DT_TFPlayerResource", "m_iMaxBuffedHealth"); m_angEyeAngles = gNetvars.get_offset("DT_TFPlayer", "tfnonlocaldata", "m_angEyeAngles[0]"); m_angEyeAnglesLocal = gNetvars.get_offset("DT_TFPlayer", "tflocaldata", "m_angEyeAngles[0]"); diff --git a/src/crits.cpp b/src/crits.cpp index f4242969..b23a97a2 100644 --- a/src/crits.cpp +++ b/src/crits.cpp @@ -1160,7 +1160,7 @@ static CatCommand debug_print_crit_info("debug_print_crit_info", "Print a bunch static InitRoutine init( []() { - EC::Register(EC::CreateMoveLate, CreateMove, "crit_cm"); + EC::Register(EC::CreateMoveLate, CreateMove, "crit_cm", EC::late); #if ENABLE_VISUALS EC::Register(EC::Draw, Draw, "crit_draw"); #endif diff --git a/src/hacks/CMakeLists.txt b/src/hacks/CMakeLists.txt index 7eb9e198..1523f167 100755 --- a/src/hacks/CMakeLists.txt +++ b/src/hacks/CMakeLists.txt @@ -37,6 +37,7 @@ set(files "${CMAKE_CURRENT_LIST_DIR}/AutoJoin.cpp" "${CMAKE_CURRENT_LIST_DIR}/Noisemaker.cpp" "${CMAKE_CURRENT_LIST_DIR}/PureBypass.cpp" "${CMAKE_CURRENT_LIST_DIR}/Trigger.cpp" + "${CMAKE_CURRENT_LIST_DIR}/SpellForcer.cpp" "${CMAKE_CURRENT_LIST_DIR}/UberSpam.cpp" "${CMAKE_CURRENT_LIST_DIR}/Walkbot.cpp" "${CMAKE_CURRENT_LIST_DIR}/Warp.cpp") diff --git a/src/hacks/Misc.cpp b/src/hacks/Misc.cpp index ec698252..00756d9e 100644 --- a/src/hacks/Misc.cpp +++ b/src/hacks/Misc.cpp @@ -958,8 +958,6 @@ static InitRoutine init_pyrovision( { if (HasCondition(LOCAL_E)) RemoveCondition(LOCAL_E); - if (HasCondition(LOCAL_E)) - RemoveCondition(LOCAL_E); } }, "remove_cart_cond"); diff --git a/src/hacks/NavBot.cpp b/src/hacks/NavBot.cpp index dd6ef646..b6531b85 100644 --- a/src/hacks/NavBot.cpp +++ b/src/hacks/NavBot.cpp @@ -266,7 +266,7 @@ static std::pair getNearestPlayerDistance() for (int i = 1; i <= g_IEngine->GetMaxClients(); i++) { CachedEntity *ent = ENTITY(i); - if (CE_VALID(ent) && ent->m_vecDormantOrigin() && ent->m_bAlivePlayer() && ent->m_bEnemy() && g_pLocalPlayer->v_Origin.DistTo(ent->m_vecOrigin()) < distance && player_tools::shouldTarget(ent) && !IsPlayerInvisible(ent)) + if (CE_VALID(ent) && ent->m_vecDormantOrigin() && g_pPlayerResource->isAlive(ent->m_IDX) && ent->m_bEnemy() && g_pLocalPlayer->v_Origin.DistTo(ent->m_vecOrigin()) < distance && player_tools::shouldTarget(ent) && !IsPlayerInvisible(ent)) { distance = g_pLocalPlayer->v_Origin.DistTo(*ent->m_vecDormantOrigin()); best_ent = ent; diff --git a/src/hacks/SpellForcer.cpp b/src/hacks/SpellForcer.cpp new file mode 100644 index 00000000..8680f27d --- /dev/null +++ b/src/hacks/SpellForcer.cpp @@ -0,0 +1,321 @@ +#include "common.hpp" +#include "AntiCheatBypass.hpp" + +namespace hacks::tf2::spellforcer +{ +static settings::Boolean enabled("spellforce.enabled", "false"); + +static settings::Int default_spell("spellforce.default_spell", "-1"); +static settings::Int default_spell_rare("spellforce.default_spell.rare", "-1"); +static settings::Int default_spell_enemies("spellforce.default_spell.enemies", "-1"); + +static settings::Int doomsday_spell("spellforce.doomsday_spell", "-1"); +static settings::Int doomsday_spell_rare("spellforce.doomsday_spell.rare", "-1"); +static settings::Int doomsday_spell_enemies("spellforce.doomsday_spell.enemies", "-1"); + +static settings::Int helltower_spell("spellforce.helltower_spell", "-1"); +static settings::Int helltower_spell_enemies("spellforce.helltower_spell.enemies", "-1"); + +static settings::Int bumper_spell("spellforce.bumper_spell", "-1"); +static settings::Int bumper_spell_enemies("spellforce.bumper_spell.enemies", "-1"); + +static settings::Boolean debug_use_set_cmd("spellforce.debug.use_set_cmd", "false"); +static settings::Boolean debug_inverse_enemy("spellforce.debug.inverse-enemy", "false"); + +enum spelltypes +{ + BUMPER_CARS = 0, + DOOMSDAY = 1, + HELLTOWER = 2, + NORMAL = 3 +}; + +enum halloween_scenario +{ + HALLOWEEN_SCENARIO_NONE = 0, + HALLOWEEN_SCENARIO_MANN_MANOR, + HALLOWEEN_SCENARIO_VIADUCT, + HALLOWEEN_SCENARIO_LAKESIDE, + HALLOWEEN_SCENARIO_HIGHTOWER, + HALLOWEEN_SCENARIO_DOOMSDAY +}; + +spelltypes getSpellMode() +{ + if (HasCondition(LOCAL_E)) + return BUMPER_CARS; + + int scenario = g_pGameRules->halloweenScenario; + switch (scenario) + { + case HALLOWEEN_SCENARIO_DOOMSDAY: + return DOOMSDAY; + case HALLOWEEN_SCENARIO_HIGHTOWER: + return HELLTOWER; + default: + return NORMAL; + } +} + +// Too much random noise on these maps to force spells +// static std::array noisy_maps{ "" }; + +static std::unordered_map spellmap_normal({ { 0, 4206970 }, { 1, 4206969 }, { 2, 4206972 }, { 3, 4206997 }, { 4, 4206971 }, { 5, 4206977 }, { 7, 4206973 }, { 8, 4206982 }, { 9, 4206976 } }); +static std::unordered_map spellmap_normal_rare({ { 7, 4206987 }, { 8, 4206982 }, { 9, 4207006 }, { 10, 4206983 }, { 11, 4206984 } }); + +static std::unordered_map spellmap_helltower({ { 0, 4206998 }, { 1, 4206984 }, { 2, 4206985 }, { 3, 4206986 }, { 4, 4206987 }, { 5, 4206982 }, { 6, 4206983 } }); + +static std::unordered_map spellmap_doomsday_normal({ { 0, 4206982 }, { 2, 4207006 }, { 4, 4206983 }, { 5, 4206984 } }); +static std::unordered_map spellmap_doomsday_rare({ { 7, 4207009 }, { 8, 4207014 }, { 9, 4207008 }, { 10, 4207007 } }); + +static std::unordered_map spellmap_bumpercar({ { 12, 4206982 }, { 13, 4206983 }, { 14, 4206987 }, { 15, 4206988 } }); +// static std::unordered_map hasslecastle_normal({ { 0, 4206990 }, { 1, 4206989 }, { 2, 4206986 }, { 3, 4206997 }, { 4, 4206984 }, { 5, 4206983 }, { 7, 4207000 }, { 8, 4206982 }, { 9, 4207027 } }); + +int getCommandForSpellID(int spellidx, int spelltype) +{ + std::unordered_map spellmap; + + // if (levelname.find("koth_slasher") != levelname.npos || levelname.find("pl_bloodwater") != levelname.npos || levelname.find("pl_rumble_event") != levelname.npos) + + auto spellmode = getSpellMode(); + + switch (spellmode) + { + case HELLTOWER: + spellmap = spellmap_helltower; + break; + case BUMPER_CARS: + spellmap = spellmap_bumpercar; + break; + case DOOMSDAY: + spellmap = spelltype ? spellmap_doomsday_rare : spellmap_doomsday_normal; + break; + default: + spellmap = spelltype ? spellmap_normal_rare : spellmap_normal; + } + + int value = spellmap[spellidx]; + + // "No entry" should be returned as -1 + return value ? value : -1; +} + +// Doomsday spell list + +static const int g_doomsdayNormalSpellIndexList[] = { + 0, // Fireball + 0, // Fireball x2 + 2, // overheal + 4, // Jump + 5, // Stealth +}; + +// Side note: 6 is the Teleport spell + +static const int g_doomsdayRareSpellIndexList[] = { + 7, // Lightning + 8, // Mini + 9, // Meteor + 7, // Lightning + 8, // Mini + 9, // Meteor + 10 // Boss / Monoculus. Smaller chance +}; + +// "Normal" Spell list +static const int g_generalSpellIndexList[] = { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 7, 8, 9 }; + +// Saves command that have a specific spell id +std::unordered_map command_to_spell_map; + +int current_index = 0; + +int getStaticCmd() +{ + return 4206982 + current_index; +} + +CachedEntity *getClosestSpell() +{ + CachedEntity *ent = nullptr; + float best_dist = FLT_MAX; + bool is_dormant = false; + + if (CE_BAD(LOCAL_E) || !LOCAL_E->m_bAlivePlayer()) + return ent; + for (int i = g_IEngine->GetMaxClients(); i < HIGHEST_ENTITY; i++) + { + CachedEntity *spell = ENTITY(i); + if (CE_INVALID(spell) || !spell->m_vecDormantOrigin() || (spell->m_ItemType() != ITEM_SPELL && spell->m_ItemType() != ITEM_SPELL_RARE)) + continue; + float dist = spell->m_flDistance(); + if (dist < best_dist || (is_dormant && !RAW_ENT(spell)->IsDormant() && dist <= 300.0f)) + { + ent = spell; + best_dist = dist; + is_dormant = RAW_ENT(spell)->IsDormant(); + } + } + return ent; +} + +void CreateMoveLate() +{ + if (hacks::tf2::antianticheat::enabled || !g_pGameRules->isUsingSpells_fn()) + return; + auto cmd = 0; + if (debug_use_set_cmd) + cmd = getStaticCmd(); + else + { + auto spell = getClosestSpell(); + + // Apply bad effects for enemies + if (debug_inverse_enemy || CE_BAD(spell) || spell->m_flDistance() > 300.0f) + { + int spellindex; + + auto spellmode = getSpellMode(); + switch (spellmode) + { + case BUMPER_CARS: + spellindex = *bumper_spell_enemies; + break; + case DOOMSDAY: + spellindex = *doomsday_spell_enemies; + break; + case HELLTOWER: + spellindex = *helltower_spell_enemies; + break; + case NORMAL: + spellindex = *default_spell_enemies; + break; + } + + cmd = getCommandForSpellID(spellindex, 0); + } + else if (spell->m_ItemType() == ITEM_SPELL) + { + int spellindex; + + auto spellmode = getSpellMode(); + switch (spellmode) + { + case BUMPER_CARS: + spellindex = *bumper_spell; + break; + case DOOMSDAY: + spellindex = *doomsday_spell; + break; + case HELLTOWER: + spellindex = *helltower_spell; + break; + case NORMAL: + spellindex = *default_spell; + break; + } + + cmd = getCommandForSpellID(spellindex, 0); + } + else + { + int spellindex; + + auto spellmode = getSpellMode(); + switch (spellmode) + { + case DOOMSDAY: + spellindex = *doomsday_spell_rare; + break; + case HELLTOWER: + case BUMPER_CARS: + case NORMAL: + spellindex = *default_spell_rare; + break; + } + cmd = getCommandForSpellID(spellindex, 1); + } + } + + if (cmd != -1) + { + current_late_user_cmd->command_number = cmd; + current_late_user_cmd->random_seed = MD5_PseudoRandom(cmd) & 0x7FFFFFFF; + } +} + +#if ENABLE_VISUALS +static Timer draw_timer; +void Draw() +{ + if (!enabled || !g_IEngine->IsInGame()) + { + draw_timer.update(); + return; + } + static bool previously_highest = true; + // Is the player the highest IDX of all players? + bool is_player_highest = true; + + int players_above = 0; + + // Check if there is a valid player exceeding our IDX + for (int i = g_pLocalPlayer->entity_idx + 1; i <= g_IEngine->GetMaxClients(); i++) + { + if (g_pPlayerResource->isValid(i)) + { + is_player_highest = false; + players_above++; + } + } + if (is_player_highest != previously_highest) + draw_timer.update(); + + previously_highest = is_player_highest; + + if (!draw_timer.check(60000)) + { + if (is_player_highest) + AddCenterString("Forcing Spells.", colors::green); + else + AddCenterString(format("Cannot Force Spells, entity idx is ", players_above, " too low :("), colors::red); + } +} +#endif + +CatCommand enter_spell_data("spellforcer_enter_data", "Debug", + [](const CCommand &args) + { + if (args.ArgC() < 2) + { + return; + } + try + { + // Grab spellidx + int spellidx = std::stoi(args.Arg(1)); + + if (command_to_spell_map[spellidx] == 0) + command_to_spell_map[spellidx] = getStaticCmd(); + for (auto &entry : command_to_spell_map) + logging::Info("%d: %d", entry.first, entry.second); + current_index++; + } + catch (const std::invalid_argument &) + { + logging::Info("Invalid Steamid32 provided."); + } + }); + +static InitRoutine init( + []() + { +#if ENABLE_VISUALS + EC::Register(EC::Draw, Draw, "spellforcer_draw", EC::early); + EC::Register( + EC::LevelInit, []() { draw_timer.update(); }, "spellforcer_lvlinit"); +#endif + EC::Register(EC::CreateMoveLate, CreateMoveLate, "spellforcer_cml", EC::early); + }); + +} // namespace hacks::tf2::spellforcer diff --git a/src/hacks/Warp.cpp b/src/hacks/Warp.cpp index cca19bca..6ac3d62d 100644 --- a/src/hacks/Warp.cpp +++ b/src/hacks/Warp.cpp @@ -45,6 +45,8 @@ static settings::Boolean warp_backwards{ "warp.on-hit.backwards", "false" }; static settings::Boolean warp_left{ "warp.on-hit.left", "true" }; static settings::Boolean warp_right{ "warp.on-hit.right", "true" }; +static settings::Boolean debug_seqout{ "debug.warp_seqout", "false" }; + // Hidden control rvars for communtiy servers static settings::Int maxusrcmdprocessticks("warp.maxusrcmdprocessticks", "24"); diff --git a/src/hooks/GetUserCmd.cpp b/src/hooks/GetUserCmd.cpp index 375b213c..af976b7b 100644 --- a/src/hooks/GetUserCmd.cpp +++ b/src/hooks/GetUserCmd.cpp @@ -10,10 +10,6 @@ namespace hooked_methods DEFINE_HOOKED_METHOD(GetUserCmd, CUserCmd *, IInput *this_, int sequence_number) { - // We need to overwrite this if crithack is on - if (criticals::isEnabled()) - return &GetCmds(this_)[sequence_number % VERIFIED_CMD_SIZE]; - else - return original::GetUserCmd(this_, sequence_number); + return &GetCmds(this_)[sequence_number % VERIFIED_CMD_SIZE]; } } // namespace hooked_methods diff --git a/src/itemtypes.cpp b/src/itemtypes.cpp index b76f6c4b..0e4a7bec 100644 --- a/src/itemtypes.cpp +++ b/src/itemtypes.cpp @@ -83,6 +83,9 @@ ItemManager::ItemManager() : mapper() RegisterModelMapping("models/items/crystal_ball_pickup_major.mdl", ITEM_SPELL_RARE); RegisterModelMapping("models/props_monster_mash/flask_vial_purple.mdl", ITEM_SPELL_RARE); + // Thanks valve + RegisterSpecialMapping([](CachedEntity *ent) -> bool { return g_ItemManager.mapper.GetItemType(ent) == ITEM_SPELL && ent->m_iClassID() == CL_CLASS(CDynamicProp); }, ITEM_SPELL_RARE); + // == GHOSTS RegisterModelMapping("models/props_halloween/ghost.mdl", HALLOWEEN_GHOST); RegisterModelMapping("models/props_halloween/ghost_no_hat_red.mdl", HALLOWEEN_GHOST); @@ -118,90 +121,93 @@ ItemManager::ItemManager() : mapper() RegisterModelMapping("models/items/medkit_overheal.mdl", ITEM_TF2C_PILL); // TF2C spawners - specials.push_back([](CachedEntity *entity) -> k_EItemType { - static ItemModelMapper tf2c_weapon_mapper = []() -> ItemModelMapper { - ItemModelMapper result; - result.RegisterItem("models/weapons/w_models/w_bottle.mdl", ITEM_TF2C_W_BOTTLE); - result.RegisterItem("models/weapons/w_models/w_grenade_napalm.mdl", ITEM_TF2C_W_GRENADE_NAPALM); - result.RegisterItem("models/weapons/w_models/w_supershotgun_mercenary.mdl", ITEM_TF2C_W_SUPERSHOTGUN_MERCENARY); - result.RegisterItem("models/weapons/w_models/w_rocketbeta.mdl", ITEM_TF2C_W_ROCKETBETA); - result.RegisterItem("models/weapons/w_models/w_grenade_grenadelauncher.mdl", ITEM_TF2C_W_GRENADE_GRENADELAUNCHER); - result.RegisterItem("models/weapons/w_models/w_grenadelauncher.mdl", ITEM_TF2C_W_GRENADELAUNCHER); - result.RegisterItem("models/weapons/w_models/w_grenade_pipebomb.mdl", ITEM_TF2C_W_GRENADE_PIPEBOMB); - result.RegisterItem("models/weapons/w_models/w_cigarette_case.mdl", ITEM_TF2C_W_CIGARETTE_CASE); - result.RegisterItem("models/weapons/w_models/w_brandingiron.mdl", ITEM_TF2C_W_BRANDINGIRON); - result.RegisterItem("models/weapons/w_models/w_banhammer.mdl", ITEM_TF2C_W_BANHAMMER); - result.RegisterItem("models/weapons/w_models/w_sniperrifle.mdl", ITEM_TF2C_W_SNIPERRIFLE); - result.RegisterItem("models/weapons/w_models/w_grenade_heal.mdl", ITEM_TF2C_W_GRENADE_HEAL); - result.RegisterItem("models/weapons/w_models/w_hammerfists.mdl", ITEM_TF2C_W_HAMMERFISTS); - result.RegisterItem("models/weapons/w_models/w_grenade_nail.mdl", ITEM_TF2C_W_GRENADE_NAIL); - result.RegisterItem("models/weapons/w_models/w_dart.mdl", ITEM_TF2C_W_DART); - result.RegisterItem("models/weapons/w_models/w_rpg.mdl", ITEM_TF2C_W_RPG); - result.RegisterItem("models/weapons/w_models/w_umbrella_civilian.mdl", ITEM_TF2C_W_UMBRELLA_CIVILIAN); - result.RegisterItem("models/weapons/w_models/w_grenade_frag.mdl", ITEM_TF2C_W_GRENADE_FRAG); - result.RegisterItem("models/weapons/w_models/w_grenade_mirv.mdl", ITEM_TF2C_W_GRENADE_MIRV); - result.RegisterItem("models/weapons/w_models/w_medigun.mdl", ITEM_TF2C_W_MEDIGUN); - result.RegisterItem("models/weapons/w_models/w_grenade_mirv_demo.mdl", ITEM_TF2C_W_GRENADE_MIRV_DEMO); - result.RegisterItem("models/weapons/w_models/w_pickaxe.mdl", ITEM_TF2C_W_PICKAXE); - result.RegisterItem("models/weapons/w_models/w_syringegun.mdl", ITEM_TF2C_W_SYRINGEGUN); - result.RegisterItem("models/weapons/w_models/w_scattergun.mdl", ITEM_TF2C_W_SCATTERGUN); - result.RegisterItem("models/weapons/w_models/w_stengun.mdl", ITEM_TF2C_W_STENGUN); - result.RegisterItem("models/weapons/w_models/w_snubnose.mdl", ITEM_TF2C_W_SNUBNOSE); - result.RegisterItem("models/weapons/w_models/w_minigun.mdl", ITEM_TF2C_W_MINIGUN); - result.RegisterItem("models/weapons/w_models/w_wrench.mdl", ITEM_TF2C_W_WRENCH); - result.RegisterItem("models/weapons/w_models/w_bat.mdl", ITEM_TF2C_W_BAT); - result.RegisterItem("models/weapons/w_models/w_sapper.mdl", ITEM_TF2C_W_SAPPER); - result.RegisterItem("models/weapons/w_models/w_rocket.mdl", ITEM_TF2C_W_ROCKET); - result.RegisterItem("models/weapons/w_models/w_hammer.mdl", ITEM_TF2C_W_HAMMER); - result.RegisterItem("models/weapons/w_models/w_fishwhacker.mdl", ITEM_TF2C_W_FISHWHACKER); - result.RegisterItem("models/weapons/w_models/w_kritzkrieg.mdl", ITEM_TF2C_W_KRITZKRIEG); - result.RegisterItem("models/weapons/w_models/w_flaregun.mdl", ITEM_TF2C_W_FLAREGUN); - result.RegisterItem("models/weapons/w_models/w_shovel.mdl", ITEM_TF2C_W_SHOVEL); - result.RegisterItem("models/weapons/w_models/w_pistol.mdl", ITEM_TF2C_W_PISTOL); - result.RegisterItem("models/weapons/w_models/w_smg.mdl", ITEM_TF2C_W_SMG); - result.RegisterItem("models/weapons/w_models/w_leadpipe.mdl", ITEM_TF2C_W_LEADPIPE); - result.RegisterItem("models/weapons/w_models/w_flaregun_shell.mdl", ITEM_TF2C_W_FLAREGUN_SHELL); - result.RegisterItem("models/weapons/w_models/w_grenade_emp.mdl", ITEM_TF2C_W_GRENADE_EMP); - result.RegisterItem("models/weapons/w_models/w_cyclops.mdl", ITEM_TF2C_W_CYCLOPS); - result.RegisterItem("models/weapons/w_models/w_machete.mdl", ITEM_TF2C_W_MACHETE); - result.RegisterItem("models/weapons/w_models/w_shotgun.mdl", ITEM_TF2C_W_SHOTGUN); - result.RegisterItem("models/weapons/w_models/w_revolver.mdl", ITEM_TF2C_W_REVOLVER); - result.RegisterItem("models/weapons/w_models/w_grenade_gas.mdl", ITEM_TF2C_W_GRENADE_GAS); - result.RegisterItem("models/weapons/w_models/w_grenade_beartrap.mdl", ITEM_TF2C_W_GRENADE_BEARTRAP); - result.RegisterItem("models/weapons/w_models/w_fireaxe.mdl", ITEM_TF2C_W_FIREAXE); - result.RegisterItem("models/weapons/w_models/w_grenade_conc.mdl", ITEM_TF2C_W_GRENADE_CONC); - result.RegisterItem("models/weapons/w_models/w_nailgun.mdl", ITEM_TF2C_W_NAILGUN); - result.RegisterItem("models/weapons/w_models/w_bonesaw.mdl", ITEM_TF2C_W_BONESAW); - result.RegisterItem("models/weapons/w_models/w_stickybomb_launcher.mdl", ITEM_TF2C_W_STICKYBOMB_LAUNCHER); - result.RegisterItem("models/weapons/w_models/w_grenade_bomblet.mdl", ITEM_TF2C_W_GRENADE_BOMBLET); - result.RegisterItem("models/weapons/w_models/w_tranq.mdl", ITEM_TF2C_W_TRANQ); - result.RegisterItem("models/weapons/w_models/w_dynamite.mdl", ITEM_TF2C_W_DYNAMITE); - result.RegisterItem("models/weapons/w_models/w_club.mdl", ITEM_TF2C_W_CLUB); - result.RegisterItem("models/weapons/w_models/w_tommygun.mdl", ITEM_TF2C_W_TOMMYGUN); - result.RegisterItem("models/weapons/w_models/w_coffepot.mdl", ITEM_TF2C_W_COFFEPOT); - result.RegisterItem("models/weapons/w_models/w_stickybomb.mdl", ITEM_TF2C_W_STICKYBOMB); - result.RegisterItem("models/weapons/w_models/w_rocketlauncher.mdl", ITEM_TF2C_W_ROCKETLAUNCHER); - result.RegisterItem("models/weapons/w_models/w_flamethrower.mdl", ITEM_TF2C_W_FLAMETHROWER); - result.RegisterItem("models/weapons/w_models/w_crowbar.mdl", ITEM_TF2C_W_CROWBAR); - result.RegisterItem("models/weapons/w_models/w_builder.mdl", ITEM_TF2C_W_BUILDER); - result.RegisterItem("models/weapons/w_models/w_heavy_artillery.mdl", ITEM_TF2C_W_HEAVY_ARTILLERY); - result.RegisterItem("models/weapons/w_models/w_knife.mdl", ITEM_TF2C_W_KNIFE); - result.RegisterItem("models/weapons/w_models/w_pda_engineer.mdl", ITEM_TF2C_W_PDA_ENGINEER); - result.RegisterItem("models/weapons/w_models/w_bottle_broken.mdl", ITEM_TF2C_W_BOTTLE_BROKEN); - result.RegisterItem("models/weapons/w_models/w_toolbox.mdl", ITEM_TF2C_W_TOOLBOX); - result.RegisterItem("models/weapons/w_models/w_syringe_proj.mdl", ITEM_TF2C_W_SYRINGE_PROJ); - result.RegisterItem("models/weapons/w_models/w_nail.mdl", ITEM_TF2C_W_NAIL); - result.RegisterItem("models/weapons/w_models/w_syringe.mdl", ITEM_TF2C_W_SYRINGE); - result.RegisterItem("models/weapons/w_models/w_overhealer.mdl", ITEM_TF2C_W_OVERHEALER); - return result; - }(); - - if (entity->m_iClassID() == CL_CLASS(CWeaponSpawner)) + specials.push_back( + [](CachedEntity *entity) -> k_EItemType { - return tf2c_weapon_mapper.GetItemType(entity); - } - return ITEM_NONE; - }); + static ItemModelMapper tf2c_weapon_mapper = []() -> ItemModelMapper + { + ItemModelMapper result; + result.RegisterItem("models/weapons/w_models/w_bottle.mdl", ITEM_TF2C_W_BOTTLE); + result.RegisterItem("models/weapons/w_models/w_grenade_napalm.mdl", ITEM_TF2C_W_GRENADE_NAPALM); + result.RegisterItem("models/weapons/w_models/w_supershotgun_mercenary.mdl", ITEM_TF2C_W_SUPERSHOTGUN_MERCENARY); + result.RegisterItem("models/weapons/w_models/w_rocketbeta.mdl", ITEM_TF2C_W_ROCKETBETA); + result.RegisterItem("models/weapons/w_models/w_grenade_grenadelauncher.mdl", ITEM_TF2C_W_GRENADE_GRENADELAUNCHER); + result.RegisterItem("models/weapons/w_models/w_grenadelauncher.mdl", ITEM_TF2C_W_GRENADELAUNCHER); + result.RegisterItem("models/weapons/w_models/w_grenade_pipebomb.mdl", ITEM_TF2C_W_GRENADE_PIPEBOMB); + result.RegisterItem("models/weapons/w_models/w_cigarette_case.mdl", ITEM_TF2C_W_CIGARETTE_CASE); + result.RegisterItem("models/weapons/w_models/w_brandingiron.mdl", ITEM_TF2C_W_BRANDINGIRON); + result.RegisterItem("models/weapons/w_models/w_banhammer.mdl", ITEM_TF2C_W_BANHAMMER); + result.RegisterItem("models/weapons/w_models/w_sniperrifle.mdl", ITEM_TF2C_W_SNIPERRIFLE); + result.RegisterItem("models/weapons/w_models/w_grenade_heal.mdl", ITEM_TF2C_W_GRENADE_HEAL); + result.RegisterItem("models/weapons/w_models/w_hammerfists.mdl", ITEM_TF2C_W_HAMMERFISTS); + result.RegisterItem("models/weapons/w_models/w_grenade_nail.mdl", ITEM_TF2C_W_GRENADE_NAIL); + result.RegisterItem("models/weapons/w_models/w_dart.mdl", ITEM_TF2C_W_DART); + result.RegisterItem("models/weapons/w_models/w_rpg.mdl", ITEM_TF2C_W_RPG); + result.RegisterItem("models/weapons/w_models/w_umbrella_civilian.mdl", ITEM_TF2C_W_UMBRELLA_CIVILIAN); + result.RegisterItem("models/weapons/w_models/w_grenade_frag.mdl", ITEM_TF2C_W_GRENADE_FRAG); + result.RegisterItem("models/weapons/w_models/w_grenade_mirv.mdl", ITEM_TF2C_W_GRENADE_MIRV); + result.RegisterItem("models/weapons/w_models/w_medigun.mdl", ITEM_TF2C_W_MEDIGUN); + result.RegisterItem("models/weapons/w_models/w_grenade_mirv_demo.mdl", ITEM_TF2C_W_GRENADE_MIRV_DEMO); + result.RegisterItem("models/weapons/w_models/w_pickaxe.mdl", ITEM_TF2C_W_PICKAXE); + result.RegisterItem("models/weapons/w_models/w_syringegun.mdl", ITEM_TF2C_W_SYRINGEGUN); + result.RegisterItem("models/weapons/w_models/w_scattergun.mdl", ITEM_TF2C_W_SCATTERGUN); + result.RegisterItem("models/weapons/w_models/w_stengun.mdl", ITEM_TF2C_W_STENGUN); + result.RegisterItem("models/weapons/w_models/w_snubnose.mdl", ITEM_TF2C_W_SNUBNOSE); + result.RegisterItem("models/weapons/w_models/w_minigun.mdl", ITEM_TF2C_W_MINIGUN); + result.RegisterItem("models/weapons/w_models/w_wrench.mdl", ITEM_TF2C_W_WRENCH); + result.RegisterItem("models/weapons/w_models/w_bat.mdl", ITEM_TF2C_W_BAT); + result.RegisterItem("models/weapons/w_models/w_sapper.mdl", ITEM_TF2C_W_SAPPER); + result.RegisterItem("models/weapons/w_models/w_rocket.mdl", ITEM_TF2C_W_ROCKET); + result.RegisterItem("models/weapons/w_models/w_hammer.mdl", ITEM_TF2C_W_HAMMER); + result.RegisterItem("models/weapons/w_models/w_fishwhacker.mdl", ITEM_TF2C_W_FISHWHACKER); + result.RegisterItem("models/weapons/w_models/w_kritzkrieg.mdl", ITEM_TF2C_W_KRITZKRIEG); + result.RegisterItem("models/weapons/w_models/w_flaregun.mdl", ITEM_TF2C_W_FLAREGUN); + result.RegisterItem("models/weapons/w_models/w_shovel.mdl", ITEM_TF2C_W_SHOVEL); + result.RegisterItem("models/weapons/w_models/w_pistol.mdl", ITEM_TF2C_W_PISTOL); + result.RegisterItem("models/weapons/w_models/w_smg.mdl", ITEM_TF2C_W_SMG); + result.RegisterItem("models/weapons/w_models/w_leadpipe.mdl", ITEM_TF2C_W_LEADPIPE); + result.RegisterItem("models/weapons/w_models/w_flaregun_shell.mdl", ITEM_TF2C_W_FLAREGUN_SHELL); + result.RegisterItem("models/weapons/w_models/w_grenade_emp.mdl", ITEM_TF2C_W_GRENADE_EMP); + result.RegisterItem("models/weapons/w_models/w_cyclops.mdl", ITEM_TF2C_W_CYCLOPS); + result.RegisterItem("models/weapons/w_models/w_machete.mdl", ITEM_TF2C_W_MACHETE); + result.RegisterItem("models/weapons/w_models/w_shotgun.mdl", ITEM_TF2C_W_SHOTGUN); + result.RegisterItem("models/weapons/w_models/w_revolver.mdl", ITEM_TF2C_W_REVOLVER); + result.RegisterItem("models/weapons/w_models/w_grenade_gas.mdl", ITEM_TF2C_W_GRENADE_GAS); + result.RegisterItem("models/weapons/w_models/w_grenade_beartrap.mdl", ITEM_TF2C_W_GRENADE_BEARTRAP); + result.RegisterItem("models/weapons/w_models/w_fireaxe.mdl", ITEM_TF2C_W_FIREAXE); + result.RegisterItem("models/weapons/w_models/w_grenade_conc.mdl", ITEM_TF2C_W_GRENADE_CONC); + result.RegisterItem("models/weapons/w_models/w_nailgun.mdl", ITEM_TF2C_W_NAILGUN); + result.RegisterItem("models/weapons/w_models/w_bonesaw.mdl", ITEM_TF2C_W_BONESAW); + result.RegisterItem("models/weapons/w_models/w_stickybomb_launcher.mdl", ITEM_TF2C_W_STICKYBOMB_LAUNCHER); + result.RegisterItem("models/weapons/w_models/w_grenade_bomblet.mdl", ITEM_TF2C_W_GRENADE_BOMBLET); + result.RegisterItem("models/weapons/w_models/w_tranq.mdl", ITEM_TF2C_W_TRANQ); + result.RegisterItem("models/weapons/w_models/w_dynamite.mdl", ITEM_TF2C_W_DYNAMITE); + result.RegisterItem("models/weapons/w_models/w_club.mdl", ITEM_TF2C_W_CLUB); + result.RegisterItem("models/weapons/w_models/w_tommygun.mdl", ITEM_TF2C_W_TOMMYGUN); + result.RegisterItem("models/weapons/w_models/w_coffepot.mdl", ITEM_TF2C_W_COFFEPOT); + result.RegisterItem("models/weapons/w_models/w_stickybomb.mdl", ITEM_TF2C_W_STICKYBOMB); + result.RegisterItem("models/weapons/w_models/w_rocketlauncher.mdl", ITEM_TF2C_W_ROCKETLAUNCHER); + result.RegisterItem("models/weapons/w_models/w_flamethrower.mdl", ITEM_TF2C_W_FLAMETHROWER); + result.RegisterItem("models/weapons/w_models/w_crowbar.mdl", ITEM_TF2C_W_CROWBAR); + result.RegisterItem("models/weapons/w_models/w_builder.mdl", ITEM_TF2C_W_BUILDER); + result.RegisterItem("models/weapons/w_models/w_heavy_artillery.mdl", ITEM_TF2C_W_HEAVY_ARTILLERY); + result.RegisterItem("models/weapons/w_models/w_knife.mdl", ITEM_TF2C_W_KNIFE); + result.RegisterItem("models/weapons/w_models/w_pda_engineer.mdl", ITEM_TF2C_W_PDA_ENGINEER); + result.RegisterItem("models/weapons/w_models/w_bottle_broken.mdl", ITEM_TF2C_W_BOTTLE_BROKEN); + result.RegisterItem("models/weapons/w_models/w_toolbox.mdl", ITEM_TF2C_W_TOOLBOX); + result.RegisterItem("models/weapons/w_models/w_syringe_proj.mdl", ITEM_TF2C_W_SYRINGE_PROJ); + result.RegisterItem("models/weapons/w_models/w_nail.mdl", ITEM_TF2C_W_NAIL); + result.RegisterItem("models/weapons/w_models/w_syringe.mdl", ITEM_TF2C_W_SYRINGE); + result.RegisterItem("models/weapons/w_models/w_overhealer.mdl", ITEM_TF2C_W_OVERHEALER); + return result; + }(); + + if (entity->m_iClassID() == CL_CLASS(CWeaponSpawner)) + { + return tf2c_weapon_mapper.GetItemType(entity); + } + return ITEM_NONE; + }); } void ItemManager::RegisterModelMapping(std::string path, k_EItemType type) @@ -266,7 +272,9 @@ k_EItemType ItemModelMapper::GetItemType(CachedEntity *entity) } ItemManager g_ItemManager; -static InitRoutine init_itemtypes([]() { - EC::Register( - EC::LevelInit, []() { g_ItemManager = ItemManager{}; }, "clear_itemtypes"); -}); +static InitRoutine init_itemtypes( + []() + { + EC::Register( + EC::LevelInit, []() { g_ItemManager = ItemManager{}; }, "clear_itemtypes"); + }); diff --git a/src/nospread.cpp b/src/nospread.cpp index 0933b03e..ea86ef42 100644 --- a/src/nospread.cpp +++ b/src/nospread.cpp @@ -609,7 +609,7 @@ void CL_SendMove_hook() current_weapon_spread = 0.0; // first try to get the player and check if he is valid - if (!RAW_ENT(LOCAL_E)) + if (!RAW_ENT(LOCAL_E) || HasCondition(LOCAL_E)) { // don't set called_from_sendmove here cuz we don't care CL_SendMove_t original = (CL_SendMove_t) cl_nospread_sendmovedetour.GetOriginalFunc(); diff --git a/src/playerresource.cpp b/src/playerresource.cpp index 969d500a..2f858370 100755 --- a/src/playerresource.cpp +++ b/src/playerresource.cpp @@ -190,6 +190,16 @@ bool TFPlayerResource::isAlive(int idx) return *(bool *) ((unsigned) ent + netvar.res_bAlive + idx); } +bool TFPlayerResource::isValid(int idx) +{ + IClientEntity *ent = g_IEntityList->GetClientEntity(entity); + if (!ent || ent->GetClientClass()->m_ClassID != RCC_PLAYERRESOURCE) + return 0; + if (idx >= MAX_PLAYERS || idx < 0) + return false; + return *(bool *) ((unsigned) ent + netvar.res_bValid + idx); +} + int TFPlayerResource::getClass(int idx) { IClientEntity *ent = g_IEntityList->GetClientEntity(entity);