• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Feature Auto detect combo bot and punish

LucasFerraz

Systems Analyst
Joined
Jun 10, 2010
Messages
2,858
Reaction score
96
Location
Brazil
Gesior.pl made a Combo bot auto detector (beta). Unfortunately it isn't compiling in dev0.4 without problem.
For that reason I decided to post here his code with a change.

Explaining
His original code: Detect combo and broadcast who did it.
This code: Detect combo and add five seconds of exaustion to players. (Made by Summ, here)

You can change exaustion time here:
Code:
player->addExhaust(5*1000, EXHAUST_COMBAT);
Defualt is 5 seconds.

Default config:
comboTime = 100 -- check sds in last 0.1 sec
comboMembers = 2 -- show animation (if animation = 1) when 2 or more players do combo
comboFriends = 3 -- save uid of players as 'friends' when more then 3 players do combo / broadcast nicks of players when 3 or more 'friends' do combo more then one time
comboFriendsClearTime = 5 * 60 * 1000 -- remove 'friend' from player 'friends' list when he didnt do combo for 5 minutes
comboFriendsClearInterval = 1 * 60 * 1000 -- remove 'old' 'friends' every minute
comboShowAnimation = 1 -- show animation on target/attackers and text "COMBO X" (x - number of combo players)

Under (spells.cpp) [add in valid place! check 'if(result)']:
PHP:
if(result)
	{
		Spell::postCastSpell(player);
Add:
PHP:
		if(item->getID() == 2268 && creatureId)
        {
            // check combos in last XX miliseconds
    		uint32_t time = OTSYS_TIME();
            AttackersMap tmpAttackersMap;
            AttackersMap tmpAttackersMap2;
            uint32_t comboTime = g_config.getNumber(ConfigManager::COMBO_CT);
            uint32_t comboMembers = g_config.getNumber(ConfigManager::COMBO_CM);
            uint32_t comboFriends = g_config.getNumber(ConfigManager::COMBO_CF);
            uint32_t comboFriendsClearTime = g_config.getNumber(ConfigManager::COMBO_FCT);
            uint32_t comboFriendsClearInterval = g_config.getNumber(ConfigManager::COMBO_FCI);
            uint32_t comboShowAnim = g_config.getNumber(ConfigManager::COMBO_SA);
            // remove old friends from list
            if(comboTime && comboFriends && time - comboFriendsListLastClear >= comboFriendsClearInterval)
            {
                    for(ComboFriendsList::iterator cflit = comboFriendsList.begin(); cflit != comboFriendsList.end(); ++cflit)
                            for(AttackersMap::iterator rfit = cflit->second.begin(); rfit != cflit->second.end(); ++rfit)
                                    if(rfit->second < time - comboFriendsClearTime)
                                            cflit->second.erase(rfit->first);
            }
    		if(comboTime && comboMembers && time - comboLastCheck >= comboTime)
    		{
                    for(AttackersMap::iterator acit = comboAttackersCount.begin(); acit != comboAttackersCount.end(); ++acit)
                    {
                              if(acit->second >= comboMembers)
                              {
                                          // make combo members list
                                          for(AttackersMap::iterator alit = comboAttackersList.begin(); alit != comboAttackersList.end(); ++alit)
                                          {
                                                  if(alit->second == acit->first)
                                                  {
                                                            comboList[alit->first] = alit->first;
                                                  }
                                          }
                                          // show combo animations
                                          if(comboShowAnim)
                                          {
                                                  Creature* creature = g_game.getCreatureByID(acit->first);
                                                  if(creature != NULL)
                                                  {
                                                        char buffer[20];
                                            			sprintf(buffer, "COMBO %d", acit->second);
                                                  }
                                                  for(AttackersMap::iterator sait = comboList.begin(); sait != comboList.end(); ++sait)
                                                  {
                                                        Creature* creature = g_game.getCreatureByID(sait->first);
                                                        if(creature != NULL)
                                                        {
                                                        }
                                                  }
                                          }
                                          comboFriendsNumber = 0;
                                          // make friends list
                                          for(AttackersMap::iterator cit = comboList.begin(); cit != comboList.end(); ++cit)
                                          {
                                                    if(comboFriendsList.find(cit->first) != comboFriendsList.end())
                                                    {
                                                              tmpAttackersMap2 = comboFriendsList[cit->first];
                                                              for(AttackersMap::iterator tait = tmpAttackersMap2.begin(); tait != tmpAttackersMap2.end(); ++tait)
                                                                        tmpAttackersMap[tait->first] = tait->first;
                                                    }
                                          }
                                          for(AttackersMap::iterator ccit = tmpAttackersMap.begin(); ccit != tmpAttackersMap.end(); ++ccit)
                                                    if(comboList.find(ccit->first) != comboList.end())
                                                              ++comboFriendsNumber;
                                          // broadcast combo members
                                          if(comboFriendsNumber >= comboFriends)
                                          {
                                                    std::stringstream comboNamesList;
                                              for(AttackersMap::iterator ccit2 = tmpAttackersMap.begin(); ccit2 != tmpAttackersMap.end(); ++ccit2)
                                                        if(comboList.find(ccit2->first) != comboList.end())
                                                        {
                                                                  Creature* creature = g_game.getCreatureByID(ccit2->first);
									if(Player* player = creature->getPlayer())
       										player->addExhaust(5*1000, EXHAUST_COMBAT);
                                                        }
                                              comboNamesList << " - did combo!";
                                              g_game.broadcastMessage(comboNamesList.str(), MSG_STATUS_WARNING);
                                              // add new 'friends'
                                              for(AttackersMap::iterator cit = comboList.begin(); cit != comboList.end(); ++cit)
                                              {
                                                        tmpAttackersMap.clear();
                                                        if(comboFriendsList.find(cit->first) != comboFriendsList.end())
                                                                  tmpAttackersMap = comboFriendsList[cit->first];
                                                        for(AttackersMap::iterator tcit = comboList.begin(); tcit != comboList.end(); ++tcit)
                                                        {
                                                                  tmpAttackersMap[tcit->first] = time;
                                                        }
                                                        comboFriendsList[cit->first] = tmpAttackersMap;
                                                        
                                              }
                                          }
                                          comboList.clear();
                              }    
                    }
                    comboAttackersList.clear();
                    comboAttackersCount.clear();
                    comboLastCheck = time;
    		}
    		// add player to attackers list
            comboAttackersList[player->getID()] = creatureId;
            comboAttackersCount[creatureId] += 1;
        }
Under (spells.h):
PHP:
RuneSpellFunction* function;
Add:
PHP:
		typedef std::map<uint32_t, uint32_t> AttackersMap;
		AttackersMap comboAttackersList;
		AttackersMap comboAttackersCount;
		AttackersMap comboList;

		typedef std::map<uint32_t, AttackersMap> ComboFriendsList;
		ComboFriendsList comboFriendsList;
		
		uint32_t comboLastCheck;
		uint32_t comboFriendsNumber;
		uint32_t comboFriendsListLastClear;
Under (configmanager.cpp):
PHP:
m_confNumber[MAXIMUM_DOOR_LEVEL] = getGlobalNumber("maximumDoorLevel", 500);
Add:
PHP:
	m_confNumber[COMBO_CT] = getGlobalNumber("comboTime", 0);
	m_confNumber[COMBO_CM] = getGlobalNumber("comboMembers", 0);
	m_confNumber[COMBO_CF] = getGlobalNumber("comboFriends", 0);
	m_confNumber[COMBO_FCT] = getGlobalNumber("comboFriendsClearTime", 0);
	m_confNumber[COMBO_FCI] = getGlobalNumber("comboFriendsClearInterval", 0);
	m_confNumber[COMBO_SA] = getGlobalNumber("comboShowAnimation", 0);
Under (configmanager.h):
PHP:
MAXIMUM_DOOR_LEVEL,
Add:
PHP:
			COMBO_CT,
			COMBO_CM,
			COMBO_CF,
			COMBO_FCT,
			COMBO_FCI,
			COMBO_SA,
In config.lua add:
PHP:
	comboTime = 100
	comboMembers = 2
	comboFriends = 3
	comboFriendsClearTime = 5 * 60 * 1000
	comboFriendsClearInterval = 1 * 60 * 1000
	comboShowAnimation = 1

It's working 100%, tested in War Server with 230+ players online, uptime 300h+.
Remember: I didn't nothing then I don't deserve credits or/and reputation.

I don't know if this post is illegal or rule infraction. I hope it's not. I'm waiting for response of moderators
 
Last edited:
I'm sure it's 'legal' post.
Good job :thumbup:
I've received many PMs about my combo detector and problems with it on new TFSes.
 
Lucas i used this in my server and nothing happens when people uses combo
 
Since you have this linked in your signature, I would think you wouldn't want people to come to this thread and have the last thing they see in it is an unanswered post stating it is malfunctioning. Just saying!

Also, I think you should re-add the broadcast feature from the original, because while not a punishment per se, it may draw the attention of any online GM/CM to come investigate; for those who would do this are likely those who are prone to using other 'cheats' as well. And I do mean this as additional to the exhaust, perhaps adding another config.lua setting (a boolean) to enable/disable. Just a suggestion.
 
This is a really, really stupid stupid idea. People sitting on skype/TS, vent or w/e will get affected by this.
Anyway, good stuff.
 
Back
Top