diff --git a/src/GroupManager.cpp b/src/GroupManager.cpp index 592a73a..fac1b2f 100644 --- a/src/GroupManager.cpp +++ b/src/GroupManager.cpp @@ -33,9 +33,6 @@ void GroupManager::requestGroup(CNSocket* sock, CNPacketData* data) { otherPlr = PlayerManager::getPlayerFromID(otherPlr->iIDGroup); - if (otherPlr == nullptr) - return; - if (otherPlr == nullptr) return; diff --git a/src/ItemManager.cpp b/src/ItemManager.cpp index 27f7f43..b4328cb 100644 --- a/src/ItemManager.cpp +++ b/src/ItemManager.cpp @@ -1074,6 +1074,7 @@ void ItemManager::setItemStats(Player* plr) { plr->pointDamage = 8 + plr->level * 2; plr->groupDamage = 8 + plr->level * 2; + plr->fireRate = 0; plr->defense = 16 + plr->level * 4; Item* itemStatsDat; @@ -1086,6 +1087,7 @@ void ItemManager::setItemStats(Player* plr) { } plr->pointDamage += itemStatsDat->pointDamage; plr->groupDamage += itemStatsDat->groupDamage; + plr->fireRate += itemStatsDat->fireRate; plr->defense += itemStatsDat->defense; } } diff --git a/src/ItemManager.hpp b/src/ItemManager.hpp index a5a4588..d726a2e 100644 --- a/src/ItemManager.hpp +++ b/src/ItemManager.hpp @@ -23,7 +23,7 @@ namespace ItemManager { }; struct Item { bool tradeable, sellable; - int buyPrice, sellPrice, stackSize, level, rarity, pointDamage, groupDamage, defense, gender; // TODO: implement more as needed + int buyPrice, sellPrice, stackSize, level, rarity, pointDamage, groupDamage, fireRate, defense, gender; // TODO: implement more as needed }; // hopefully this is fine since it's never modified after load extern std::map, Item> ItemData; // -> data diff --git a/src/MobManager.cpp b/src/MobManager.cpp index a97d455..7d4a2eb 100644 --- a/src/MobManager.cpp +++ b/src/MobManager.cpp @@ -62,6 +62,21 @@ void MobManager::pcAttackNpcs(CNSocket *sock, CNPacketData *data) { return; } + // rapid fire anti-cheat + time_t currTime = getTime(); + if (currTime - plr->lastShot < plr->fireRate * 80) + plr->suspicionRating += plr->fireRate * 100 + plr->lastShot - currTime; // gain suspicion for rapid firing + else if (currTime - plr->lastShot < plr->fireRate * 180 && plr->suspicionRating > 0) + plr->suspicionRating += plr->fireRate * 100 + plr->lastShot - currTime; // lose suspicion for delayed firing + + plr->lastShot = currTime; + + if (pkt->iNPCCnt > 3) // 3+ targets should never be possible + plr->suspicionRating += 10000; + + if (plr->suspicionRating > 10000) // kill the socket when the player is too suspicious + sock->kill(); + // initialize response struct size_t resplen = sizeof(sP_FE2CL_PC_ATTACK_NPCs_SUCC) + pkt->iNPCCnt * sizeof(sAttackResult); uint8_t respbuf[CN_PACKET_BUFFER_SIZE]; @@ -1389,6 +1404,18 @@ void MobManager::projectileHit(CNSocket* sock, CNPacketData* data) { return; } + // rapid fire anti-cheat + time_t currTime = getTime(); + if (currTime - plr->lastShot < plr->fireRate * 80) + plr->suspicionRating += plr->fireRate * 100 + plr->lastShot - currTime; // gain suspicion for rapid firing + else if (currTime - plr->lastShot < plr->fireRate * 180 && plr->suspicionRating > 0) + plr->suspicionRating += plr->fireRate * 100 + plr->lastShot - currTime; // lose suspicion for delayed firing + + plr->lastShot = currTime; + + if (plr->suspicionRating > 10000) // kill the socket when the player is too suspicious + sock->kill(); + /* * initialize response struct * rocket style hit doesn't work properly, so we're always sending this one diff --git a/src/Player.hpp b/src/Player.hpp index c4dc729..2d7221e 100644 --- a/src/Player.hpp +++ b/src/Player.hpp @@ -57,6 +57,7 @@ struct Player { int pointDamage; int groupDamage; + int fireRate; int defense; int64_t aQuestFlag[16]; @@ -85,4 +86,7 @@ struct Player { ChunkPos chunkPos; std::set* viewableChunks; time_t lastHeartbeat; + + int suspicionRating; + time_t lastShot; }; diff --git a/src/TableData.cpp b/src/TableData.cpp index f517dd2..b96aad4 100644 --- a/src/TableData.cpp +++ b/src/TableData.cpp @@ -157,6 +157,7 @@ void TableData::init() { itemData.level = item["m_iMinReqLev"]; itemData.pointDamage = item["m_iPointRat"]; itemData.groupDamage = item["m_iGroupRat"]; + itemData.fireRate = item["m_iDelayTime"]; itemData.defense = item["m_iDefenseRat"]; itemData.gender = item["m_iReqSex"]; } else {