• 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!
  • 2026 staff recruitment is open! Check it out and consider applying!

party bonus exp

Dogrinha

New Member
Joined
Oct 6, 2019
Messages
206
Solutions
1
Reaction score
2
I would like my players to share experience with global equal calling bonus, but it works without this experience bonus, it just splits in half. Can someone help me? tfs 0.4

LUA:
////////////////////////////////////////////////////////////////////////
// OpenTibia - an opensource roleplaying game
////////////////////////////////////////////////////////////////////////
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
////////////////////////////////////////////////////////////////////////
#include "otpch.h"
#include "party.h"

#include "player.h"
#include "chat.h"
#include "game.h"
#include "configmanager.h"

extern Game g_game;
extern Chat g_chat;
extern ConfigManager g_config;

Party::Party(Player* _leader)
{
    sharedExpActive = sharedExpEnabled = false;
    if(_leader)
    {
        leader = _leader;
        leader->setParty(this);
        leader->sendPlayerIcons(leader);
    }
}

void Party::disband()
{
    leader->sendClosePrivate(CHANNEL_PARTY);
    leader->setParty(NULL);
    leader->sendTextMessage(MSG_INFO_DESCR, "Your party has been disbanded.");

    leader->sendPlayerIcons(leader);
    for(PlayerVector::iterator it = inviteList.begin(); it != inviteList.end(); ++it)
    {
        (*it)->removePartyInvitation(this);
        (*it)->sendPlayerIcons(leader);
        (*it)->sendPlayerIcons(*it);
        leader->sendPlayerIcons(*it);
    }

    inviteList.clear();
    for(PlayerVector::iterator it = memberList.begin(); it != memberList.end(); ++it)
    {
        (*it)->sendClosePrivate(CHANNEL_PARTY);
        (*it)->setParty(NULL);
        (*it)->sendTextMessage(MSG_INFO_DESCR, "Your party has been disbanded.");

        (*it)->sendPlayerIcons(*it);
        (*it)->sendPlayerIcons(leader);
        leader->sendPlayerIcons(*it);
    }

    memberList.clear();
    leader = NULL;
    delete this;
}

bool Party::leave(Player* player)
{
    if(!isPlayerMember(player) && player != leader)
        return false;

    bool missingLeader = false;
    if(leader == player)
    {
        if(!memberList.empty())
        {
            if(memberList.size() == 1 && inviteList.empty())
                missingLeader = true;
            else
                passLeadership(memberList.front());
        }
        else
            missingLeader = true;
    }

    //since we already passed the leadership, we remove the player from the list
    PlayerVector::iterator it = std::find(memberList.begin(), memberList.end(), player);
    if(it != memberList.end())
        memberList.erase(it);

    it = std::find(inviteList.begin(), inviteList.end(), player);
    if(it != inviteList.end())
        inviteList.erase(it);

    player->setParty(NULL);
    player->sendClosePrivate(CHANNEL_PARTY);

    player->sendTextMessage(MSG_INFO_DESCR, "You have left the party.");
    player->sendPlayerIcons(player);

    updateSharedExperience();
    updateIcons(player);
    clearPlayerPoints(player);

    char buffer[105];
    sprintf(buffer, "%s has left the party.", player->getName().c_str());

    broadcastMessage(MSG_INFO_DESCR, buffer);
    if(missingLeader || canDisband())
        disband();

    return true;
}

bool Party::passLeadership(Player* player)
{
    if(!isPlayerMember(player) || player == leader)
        return false;

    //Remove it before to broadcast the message correctly
    PlayerVector::iterator it = std::find(memberList.begin(), memberList.end(), player);
    if(it != memberList.end())
        memberList.erase(it);

    Player* oldLeader = leader;
    leader = player;
    memberList.insert(memberList.begin(), oldLeader);

    char buffer[125];
    sprintf(buffer, "%s is now the leader of the party.", player->getName().c_str());
    broadcastMessage(MSG_INFO_DESCR, buffer, true);

    player->sendTextMessage(MSG_INFO_DESCR, "You are now the leader of the party.");
    updateSharedExperience();

    updateIcons(oldLeader);
    updateIcons(player);
    return true;
}

bool Party::join(Player* player)
{
    if(isPlayerMember(player) || !isPlayerInvited(player))
        return false;

    memberList.push_back(player);
    player->setParty(this);

    player->removePartyInvitation(this);
    PlayerVector::iterator it = std::find(inviteList.begin(), inviteList.end(), player);
    if(it != inviteList.end())
        inviteList.erase(it);

    char buffer[200];
    sprintf(buffer, "%s has joined the party.", player->getName().c_str());
    broadcastMessage(MSG_INFO_DESCR, buffer);

    sprintf(buffer, "You have joined %s'%s party. Open the party channel to communicate with your companions.", leader->getName().c_str(), (leader->getName()[leader->getName().length() - 1] == 's' ? "" : "s"));
    player->sendTextMessage(MSG_INFO_DESCR, buffer);

    updateSharedExperience();
    updateIcons(player);
    return true;
}

bool Party::removeInvite(Player* player)
{
    if(!isPlayerInvited(player))
        return false;

    PlayerVector::iterator it = std::find(inviteList.begin(), inviteList.end(), player);
    if(it != inviteList.end())
        inviteList.erase(it);

    leader->sendPlayerIcons(player);
    player->sendPlayerIcons(leader);

    player->removePartyInvitation(this);
    if(canDisband())
        disband();

    return true;
}

void Party::revokeInvitation(Player* player)
{
    if(!player || player->isRemoved())
        return;

    char buffer[150];
    sprintf(buffer, "%s has revoked %s invitation.", leader->getName().c_str(), (leader->getSex(false) ? "his" : "her"));
    player->sendTextMessage(MSG_INFO_DESCR, buffer);

    sprintf(buffer, "Invitation for %s has been revoked.", player->getName().c_str());
    leader->sendTextMessage(MSG_INFO_DESCR, buffer);
    removeInvite(player);
}

bool Party::invitePlayer(Player* player)
{
    if(isPlayerInvited(player, true))
        return false;

    inviteList.push_back(player);
    player->addPartyInvitation(this);

    char buffer[150];
    sprintf(buffer, "%s has been invited.%s", player->getName().c_str(), (!memberList.size() ? " Open the party channel to communicate with your members." : ""));
    leader->sendTextMessage(MSG_INFO_DESCR, buffer);

    sprintf(buffer, "%s has invited you to %s party.", leader->getName().c_str(), (leader->getSex(false) ? "his" : "her"));
    player->sendTextMessage(MSG_INFO_DESCR, buffer);

    leader->sendPlayerIcons(player);
    player->sendPlayerIcons(leader);
    return true;
}

void Party::updateIcons(Player* player)
{
    if(!player || player->isRemoved())
        return;

    PlayerVector::iterator it;
    for(it = memberList.begin(); it != memberList.end(); ++it)
    {
        (*it)->sendPlayerIcons(player);
        player->sendPlayerIcons((*it));
    }

    for(it = inviteList.begin(); it != inviteList.end(); ++it)
    {
        (*it)->sendPlayerIcons(player);
        player->sendPlayerIcons((*it));
    }

    leader->sendPlayerIcons(player);
    player->sendPlayerIcons(leader);
}

void Party::updateAllIcons()
{
    PlayerVector::iterator it;
    for(it = memberList.begin(); it != memberList.end(); ++it)
    {
        for(PlayerVector::iterator iit = memberList.begin(); iit != memberList.end(); ++iit)
            (*it)->sendPlayerIcons((*iit));

        (*it)->sendPlayerIcons(leader);
        leader->sendPlayerIcons((*it));
    }

    leader->sendPlayerIcons(leader);
    for(it = inviteList.begin(); it != inviteList.end(); ++it)
        (*it)->sendPlayerIcons(leader);
}

void Party::broadcastMessage(MessageClasses messageClass, const std::string& text, bool sendToInvitations/* = false*/)
{
    PlayerVector::iterator it;
    if(!memberList.empty())
    {
        for(it = memberList.begin(); it != memberList.end(); ++it)
            (*it)->sendTextMessage(messageClass, text);
    }

    leader->sendTextMessage(messageClass, text);
    if(!sendToInvitations || inviteList.empty())
        return;

    for(it = inviteList.begin(); it != inviteList.end(); ++it)
        (*it)->sendTextMessage(messageClass, text);
}

void Party::updateSharedExperience()
{
    if(!sharedExpActive)
        return;

    bool result = canEnableSharedExperience();
    if(result == sharedExpEnabled)
        return;

    sharedExpEnabled = result;
    updateAllIcons();
}

bool Party::setSharedExperience(Player* player, bool _sharedExpActive)
{
    if(!player || player->isRemoved() || player != leader)
        return false;

    if(sharedExpActive == _sharedExpActive)
        return true;

    sharedExpActive = _sharedExpActive;
    if(sharedExpActive)
    {
        sharedExpEnabled = canEnableSharedExperience();
        if(sharedExpEnabled)
            leader->sendTextMessage(MSG_INFO_DESCR, "Shared Experience is now active.");
        else
            leader->sendTextMessage(MSG_INFO_DESCR, "Shared Experience has been activated, but some members of your party are inactive.");
    }
    else
        leader->sendTextMessage(MSG_INFO_DESCR, "Shared Experience has been deactivated.");

    updateAllIcons();
    return true;
}

void Party::shareExperience(double experience, Creature* target, bool multiplied)
{
    double shareExperience = experience;
    if(experience >= (double)g_config.getNumber(ConfigManager::EXTRA_PARTY_LIMIT))
        shareExperience += (experience * ((double)g_config.getNumber(ConfigManager::EXTRA_PARTY_PERCENT) / 100));

    shareExperience /= memberList.size() + 1;
    double tmpExperience = shareExperience; //we need this, as onGainSharedExperience increases the value

    leader->onGainSharedExperience(tmpExperience, target, multiplied);
    for(PlayerVector::iterator it = memberList.begin(); it != memberList.end(); ++it)
    {
        tmpExperience = shareExperience;
        (*it)->onGainSharedExperience(tmpExperience, target, multiplied);
    }
}

bool Party::canUseSharedExperience(const Player* player, uint32_t highestLevel/* = 0*/) const
{
    if(!player || player->isRemoved() || !memberList.size())
        return false;

    if(!highestLevel)
    {
        highestLevel = leader->getLevel();
        for(PlayerVector::const_iterator it = memberList.begin(); it != memberList.end(); ++it)
        {
            if((*it)->getLevel() > highestLevel)
                highestLevel = (*it)->getLevel();
        }
    }

    if(player->getLevel() < (uint32_t)std::ceil((double)highestLevel * g_config.getDouble(
        ConfigManager::PARTY_DIFFERENCE)) || !Position::areInRange(Position(
        g_config.getNumber(ConfigManager::PARTY_RADIUS_X), g_config.getNumber(
        ConfigManager::PARTY_RADIUS_Y), g_config.getNumber(ConfigManager::PARTY_RADIUS_Z)),
        leader->getPosition(), player->getPosition()))
        return false;

    CountMap::const_iterator it = pointMap.find(player->getID());
    return it != pointMap.end() && (OTSYS_TIME() - it->second.ticks) <= g_config.getNumber(
        ConfigManager::EXPERIENCE_SHARE_ACTIVITY);
}

bool Party::canEnableSharedExperience()
{
    if(!memberList.size())
        return false;

    uint32_t highestLevel = leader->getLevel();
    for(PlayerVector::iterator it = memberList.begin(); it != memberList.end(); ++it)
    {
        if((*it)->getLevel() > highestLevel)
            highestLevel = (*it)->getLevel();
    }

    for(PlayerVector::iterator it = memberList.begin(); it != memberList.end(); ++it)
    {
        if(!canUseSharedExperience((*it), highestLevel))
            return false;
    }

    return canUseSharedExperience(leader, highestLevel);
}

void Party::addPlayerHealedMember(Player* player, uint32_t points)
{
    if(points <= 0)
        return;

    CountMap::iterator it = pointMap.find(player->getID());
    if(it != pointMap.end())
    {
        it->second.totalHeal += points;
        it->second.ticks = OTSYS_TIME();
    }
    else
        pointMap[player->getID()] = CountBlock_t(points, 0);

    updateSharedExperience();
}

void Party::addPlayerDamageMonster(Player* player, uint32_t points)
{
    if(points <= 0)
        return;

    CountMap::iterator it = pointMap.find(player->getID());
    if(it != pointMap.end())
    {
        it->second.totalDamage += points;
        it->second.ticks = OTSYS_TIME();
    }
    else
        pointMap[player->getID()] = CountBlock_t(0, points);

    updateSharedExperience();
}

void Party::clearPlayerPoints(Player* player)
{
    CountMap::iterator it = pointMap.find(player->getID());
    if(it == pointMap.end())
        return;

    pointMap.erase(it);
    updateSharedExperience();
}

bool Party::isPlayerMember(const Player* player, bool result/* = false*/) const
{
    if(!player || player->isRemoved())
        return result;

    return std::find(memberList.begin(), memberList.end(), player) != memberList.end();
}

bool Party::isPlayerInvited(const Player* player, bool result/* = false*/) const
{
    if(!player || player->isRemoved())
        return result;

    return std::find(inviteList.begin(), inviteList.end(), player) != inviteList.end();
}

bool Party::canOpenCorpse(uint32_t ownerId)
{
    return leader->getGUID() == ownerId || isPlayerMember(g_game.getPlayerByGuid(ownerId));
}
 
Back
Top