• 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!

Solved Enable Shared Experience at any time

shivaria

Active Member
Joined
Sep 2, 2009
Messages
158
Reaction score
36
I am trying to make it so players can enable shared experience even when in combat. Right now you have to wait for PZ or INFIGHT and I want that to go away. I am using TFS 1.x (10.77), looking to do this in source. Heres some of my party.cpp (if the solution is there)

Code:
Party::Party(Player* leader)
{
    extraExpRate = 0.20f;

    sharedExpActive = false;
    sharedExpEnabled = false;

    this->leader = leader;
    leader->setParty(this);
}

void Party::disband()
{
    if (!g_events->eventPartyOnDisband(this)) {
        return;
    }

    Player* currentLeader = leader;
    leader = nullptr;

    currentLeader->setParty(nullptr);
    currentLeader->sendClosePrivate(CHANNEL_PARTY);
    g_game.updatePlayerShield(currentLeader);
    g_game.updatePlayerHelpers(*currentLeader);
    currentLeader->sendCreatureSkull(currentLeader);
    currentLeader->sendTextMessage(MESSAGE_INFO_DESCR, "Your party has been disbanded.");

    for (Player* invitee : inviteList) {
        invitee->removePartyInvitation(this);
        currentLeader->sendCreatureShield(invitee);
    }
    inviteList.clear();

    for (Player* member : memberList) {
        member->setParty(nullptr);
        member->sendClosePrivate(CHANNEL_PARTY);
        member->sendTextMessage(MESSAGE_INFO_DESCR, "Your party has been disbanded.");
    }

    for (Player* member : memberList) {
        g_game.updatePlayerShield(member);

        for (Player* otherMember : memberList) {
            otherMember->sendCreatureSkull(member);
        }

        member->sendCreatureSkull(currentLeader);
        currentLeader->sendCreatureSkull(member);
        g_game.updatePlayerHelpers(*member);
    }
    memberList.clear();
    delete this;
}

bool Party::leaveParty(Player* player)
{
    if (!player) {
        return false;
    }

    if (player->getParty() != this && leader != player) {
        return false;
    }

    if (!g_events->eventPartyOnLeave(this, player)) {
        return false;
    }

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

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

    player->setParty(nullptr);
    player->sendClosePrivate(CHANNEL_PARTY);
    g_game.updatePlayerShield(player);
    g_game.updatePlayerHelpers(*player);

    for (Player* member : memberList) {
        member->sendCreatureSkull(player);
        player->sendPlayerPartyIcons(member);
        g_game.updatePlayerHelpers(*member);
    }

    leader->sendCreatureSkull(player);
    player->sendCreatureSkull(player);
    player->sendPlayerPartyIcons(leader);

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

    updateSharedExperience();
    updateVocationsList();

    clearPlayerPoints(player);

    std::ostringstream ss;
    ss << player->getName() << " has left the party.";
    broadcastPartyMessage(MESSAGE_INFO_DESCR, ss.str());

    if (missingLeader || empty()) {
        disband();
    }

    return true;
}

bool Party::passPartyLeadership(Player* player)
{
    if (!player || leader == player || player->getParty() != this) {
        return false;
    }

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

    std::ostringstream ss;
    ss << player->getName() << " is now the leader of the party.";
    broadcastPartyMessage(MESSAGE_INFO_DESCR, ss.str(), true);

    Player* oldLeader = leader;
    leader = player;

    memberList.insert(memberList.begin(), oldLeader);

    updateSharedExperience();

    for (Player* member : memberList) {
        member->sendCreatureShield(oldLeader);
        member->sendCreatureShield(leader);
    }

    for (Player* invitee : inviteList) {
        invitee->sendCreatureShield(oldLeader);
        invitee->sendCreatureShield(leader);
    }

    leader->sendCreatureShield(oldLeader);
    leader->sendCreatureShield(leader);

    player->sendTextMessage(MESSAGE_INFO_DESCR, "You are now the leader of the party.");
    return true;
}


void Party::updateSharedExperience()
{
    if (sharedExpActive) {
        bool result = canEnableSharedExperience();
        if (result != sharedExpEnabled) {
            sharedExpEnabled = result;
            updateAllPartyIcons();
        }
    }
}


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

    if (sharedExpActive == _sharedExpActive) {
        return true;
    }

    sharedExpActive = _sharedExpActive;

    if (sharedExpActive) {
        sharedExpEnabled = canEnableSharedExperience();

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

    updateAllPartyIcons();
    return true;
}

void Party::shareExperience(uint64_t experience, Creature* source/* = nullptr*/)
{
    uint32_t shareExperience = static_cast<uint64_t>(std::ceil(((static_cast<double>(experience) / (memberList.size() + 1)) + (static_cast<double>(experience) * extraExpRate))));
    for (Player* member : memberList) {
        member->onGainSharedExperience(shareExperience, source);
    }
    leader->onGainSharedExperience(shareExperience, source);
}

bool Party::canUseSharedExperience(const Player* player) const
{
    if (memberList.empty()) {
        return false;
    }

    uint32_t highestLevel = leader->getLevel();
    for (Player* member : memberList) {
        if (member->getLevel() > highestLevel) {
            highestLevel = member->getLevel();
        }
    }

    uint32_t minLevel = static_cast<int32_t>(std::ceil((static_cast<float>(highestLevel) * 2) / 3));
    if (player->getLevel() < minLevel) {
        return false;
    }

    if (!Position::areInRange<30, 30, 1>(leader->getPosition(), player->getPosition())) {
        return false;
    }

    if (!player->hasFlag(PlayerFlag_NotGainInFight)) {
        //check if the player has healed/attacked anything recently
        auto it = ticksMap.find(player->getID());
        if (it == ticksMap.end()) {
            return false;
        }

        uint64_t timeDiff = OTSYS_TIME() - it->second;
        if (timeDiff > static_cast<uint64_t>(g_config.getNumber(ConfigManager::PZ_LOCKED))) {
            return false;
        }
    }
    return true;
}

bool Party::canEnableSharedExperience()
{
    if (!canUseSharedExperience(leader)) {
        return false;
    }

    for (Player* member : memberList) {
        if (!canUseSharedExperience(member)) {
            return false;
        }
    }
    return true;
}

void Party::updatePlayerTicks(Player* player, uint32_t points)
{
    if (points != 0 && !player->hasFlag(PlayerFlag_NotGainInFight)) {
        ticksMap[player->getID()] = OTSYS_TIME();
        updateSharedExperience();
    }
}

void Party::clearPlayerPoints(Player* player)
{
    auto it = ticksMap.find(player->getID());
    if (it != ticksMap.end()) {
        ticksMap.erase(it);
        updateSharedExperience();
    }
}
 
Might want to edit this block, instead of returning false, return true.
I am just guessing :p
Code:
    if (!player->hasFlag(PlayerFlag_NotGainInFight)) {
        //check if the player has healed/attacked anything recently
        auto it = ticksMap.find(player->getID());
        if (it == ticksMap.end()) {
            return false;
        }

        uint64_t timeDiff = OTSYS_TIME() - it->second;
        if (timeDiff > static_cast<uint64_t>(g_config.getNumber(ConfigManager::PZ_LOCKED))) {
            return false;
        }
    }
https://github.com/otland/forgotten...2c6625d322d60cf1e43ba/src/party.cpp#L450-L460
 
I am trying to make it so players can enable shared experience even when in combat. Right now you have to wait for PZ or INFIGHT and I want that to go away. I am using TFS 1.x (10.77), looking to do this in source. Heres some of my party.cpp (if the solution is there)

Code:
Party::Party(Player* leader)
{
    extraExpRate = 0.20f;

    sharedExpActive = false;
    sharedExpEnabled = false;

    this->leader = leader;
    leader->setParty(this);
}

void Party::disband()
{
    if (!g_events->eventPartyOnDisband(this)) {
        return;
    }

    Player* currentLeader = leader;
    leader = nullptr;

    currentLeader->setParty(nullptr);
    currentLeader->sendClosePrivate(CHANNEL_PARTY);
    g_game.updatePlayerShield(currentLeader);
    g_game.updatePlayerHelpers(*currentLeader);
    currentLeader->sendCreatureSkull(currentLeader);
    currentLeader->sendTextMessage(MESSAGE_INFO_DESCR, "Your party has been disbanded.");

    for (Player* invitee : inviteList) {
        invitee->removePartyInvitation(this);
        currentLeader->sendCreatureShield(invitee);
    }
    inviteList.clear();

    for (Player* member : memberList) {
        member->setParty(nullptr);
        member->sendClosePrivate(CHANNEL_PARTY);
        member->sendTextMessage(MESSAGE_INFO_DESCR, "Your party has been disbanded.");
    }

    for (Player* member : memberList) {
        g_game.updatePlayerShield(member);

        for (Player* otherMember : memberList) {
            otherMember->sendCreatureSkull(member);
        }

        member->sendCreatureSkull(currentLeader);
        currentLeader->sendCreatureSkull(member);
        g_game.updatePlayerHelpers(*member);
    }
    memberList.clear();
    delete this;
}

bool Party::leaveParty(Player* player)
{
    if (!player) {
        return false;
    }

    if (player->getParty() != this && leader != player) {
        return false;
    }

    if (!g_events->eventPartyOnLeave(this, player)) {
        return false;
    }

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

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

    player->setParty(nullptr);
    player->sendClosePrivate(CHANNEL_PARTY);
    g_game.updatePlayerShield(player);
    g_game.updatePlayerHelpers(*player);

    for (Player* member : memberList) {
        member->sendCreatureSkull(player);
        player->sendPlayerPartyIcons(member);
        g_game.updatePlayerHelpers(*member);
    }

    leader->sendCreatureSkull(player);
    player->sendCreatureSkull(player);
    player->sendPlayerPartyIcons(leader);

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

    updateSharedExperience();
    updateVocationsList();

    clearPlayerPoints(player);

    std::ostringstream ss;
    ss << player->getName() << " has left the party.";
    broadcastPartyMessage(MESSAGE_INFO_DESCR, ss.str());

    if (missingLeader || empty()) {
        disband();
    }

    return true;
}

bool Party::passPartyLeadership(Player* player)
{
    if (!player || leader == player || player->getParty() != this) {
        return false;
    }

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

    std::ostringstream ss;
    ss << player->getName() << " is now the leader of the party.";
    broadcastPartyMessage(MESSAGE_INFO_DESCR, ss.str(), true);

    Player* oldLeader = leader;
    leader = player;

    memberList.insert(memberList.begin(), oldLeader);

    updateSharedExperience();

    for (Player* member : memberList) {
        member->sendCreatureShield(oldLeader);
        member->sendCreatureShield(leader);
    }

    for (Player* invitee : inviteList) {
        invitee->sendCreatureShield(oldLeader);
        invitee->sendCreatureShield(leader);
    }

    leader->sendCreatureShield(oldLeader);
    leader->sendCreatureShield(leader);

    player->sendTextMessage(MESSAGE_INFO_DESCR, "You are now the leader of the party.");
    return true;
}


void Party::updateSharedExperience()
{
    if (sharedExpActive) {
        bool result = canEnableSharedExperience();
        if (result != sharedExpEnabled) {
            sharedExpEnabled = result;
            updateAllPartyIcons();
        }
    }
}


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

    if (sharedExpActive == _sharedExpActive) {
        return true;
    }

    sharedExpActive = _sharedExpActive;

    if (sharedExpActive) {
        sharedExpEnabled = canEnableSharedExperience();

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

    updateAllPartyIcons();
    return true;
}

void Party::shareExperience(uint64_t experience, Creature* source/* = nullptr*/)
{
    uint32_t shareExperience = static_cast<uint64_t>(std::ceil(((static_cast<double>(experience) / (memberList.size() + 1)) + (static_cast<double>(experience) * extraExpRate))));
    for (Player* member : memberList) {
        member->onGainSharedExperience(shareExperience, source);
    }
    leader->onGainSharedExperience(shareExperience, source);
}

bool Party::canUseSharedExperience(const Player* player) const
{
    if (memberList.empty()) {
        return false;
    }

    uint32_t highestLevel = leader->getLevel();
    for (Player* member : memberList) {
        if (member->getLevel() > highestLevel) {
            highestLevel = member->getLevel();
        }
    }

    uint32_t minLevel = static_cast<int32_t>(std::ceil((static_cast<float>(highestLevel) * 2) / 3));
    if (player->getLevel() < minLevel) {
        return false;
    }

    if (!Position::areInRange<30, 30, 1>(leader->getPosition(), player->getPosition())) {
        return false;
    }

    if (!player->hasFlag(PlayerFlag_NotGainInFight)) {
        //check if the player has healed/attacked anything recently
        auto it = ticksMap.find(player->getID());
        if (it == ticksMap.end()) {
            return false;
        }

        uint64_t timeDiff = OTSYS_TIME() - it->second;
        if (timeDiff > static_cast<uint64_t>(g_config.getNumber(ConfigManager::PZ_LOCKED))) {
            return false;
        }
    }
    return true;
}

bool Party::canEnableSharedExperience()
{
    if (!canUseSharedExperience(leader)) {
        return false;
    }

    for (Player* member : memberList) {
        if (!canUseSharedExperience(member)) {
            return false;
        }
    }
    return true;
}

void Party::updatePlayerTicks(Player* player, uint32_t points)
{
    if (points != 0 && !player->hasFlag(PlayerFlag_NotGainInFight)) {
        ticksMap[player->getID()] = OTSYS_TIME();
        updateSharedExperience();
    }
}

void Party::clearPlayerPoints(Player* player)
{
    auto it = ticksMap.find(player->getID());
    if (it != ticksMap.end()) {
        ticksMap.erase(it);
        updateSharedExperience();
    }
}

You can't, its related to the icon of battle, you cant activate it through the client if you have that icon, the only way would be creating a talkaction. Or using otclient.

You can confirm commenting this line:
//icons |= ICON_SWORDS;
in condition.cpp.
 
You can't, its related to the icon of battle, you cant activate it through the client if you have that icon, the only way would be creating a talkaction. Or using otclient.

You can confirm commenting this line:
//icons |= ICON_SWORDS;
in condition.cpp.
Is there any way to make it so XP share is always active or that it never wears off or something. The only way I know is to make PZ time really short so you can activate while out of battle. But I need PZ time as long as possible cause thats how long XP share is active
 
Is there any way to make it so XP share is always active or that it never wears off or something. The only way I know is to make PZ time really short so you can activate while out of battle. But I need PZ time as long as possible cause thats how long XP share is active
Code:
        g_game.updatePlayerShield(leader);
        leader->sendCreatureSkull(leader);
        setSharedExperience(leader, true);

In Player:invitePlayer "party.cpp".
 
this might work, else if it is related to the client ...

PHP:
bool Party::canEnableSharedExperience()
{
/**
    if (!canUseSharedExperience(leader)) {
        return false;
    }

    for (Player* member : memberList) {
        if (!canUseSharedExperience(member)) {
            return false;
        }
    }
**/
    return true;
}
 
this might work, else if it is related to the client ...

PHP:
bool Party::canEnableSharedExperience()
{
/**
    if (!canUseSharedExperience(leader)) {
        return false;
    }

    for (Player* member : memberList) {
        if (!canUseSharedExperience(member)) {
            return false;
        }
    }
**/
    return true;
}
The problem is the option wont show up in the client if the client has the battle icon, it would be possible with talkactions or otclient tho
 
Removing the condition from the if won't work, the option to enable/disable doesn't show up in the client if you have the battle icon.

So editting this parse function is useless if the client can't click to send the packet in the client.
 
I did not mean about remove the condition, more that tricking the client. I did the same thing with my duel system.

Or does it now show up at all?
 
i think u just need to remove this
Code:
if (!player->hasFlag(PlayerFlag_NotGainInFight)) {
        //check if the player has healed/attacked anything recently
        auto it = ticksMap.find(player->getID());
        if (it == ticksMap.end()) {
            return false;
        }

        uint64_t timeDiff = OTSYS_TIME() - it->second;
        if (timeDiff > static_cast<uint64_t>(g_config.getNumber(ConfigManager::PZ_LOCKED))) {
            return false;
        }
    }
 
Back
Top