void Party::updateSharedExperience()
{
if (sharedExpActive) {
bool result = getSharedExperienceStatus() == SHAREDEXP_OK;
if (result != sharedExpEnabled) {
sharedExpEnabled = result;
updateAllPartyIcons();
}
}
}
namespace {
const char* getSharedExpReturnMessage(SharedExpStatus_t value)
{
switch (value) {
case SHAREDEXP_OK:
return "Shared Experience is now active.";
case SHAREDEXP_TOOFARAWAY:
return "Shared Experience has been activated, but some members of your party are too far away.";
case SHAREDEXP_LEVELDIFFTOOLARGE:
return "Shared Experience has been activated, but the level spread of your party is too wide.";
case SHAREDEXP_MEMBERINACTIVE:
return "Shared Experience has been activated, but some members of your party are inactive.";
case SHAREDEXP_EMPTYPARTY:
return "Shared Experience has been activated, but you are alone in your party.";
default:
return "An error occured. Unable to activate shared experience.";
}
}
}
bool Party::setSharedExperience(Player* player, bool sharedExpActive)
{
if (!player || leader != player) {
return false;
}
if (this->sharedExpActive == sharedExpActive) {
return true;
}
this->sharedExpActive = sharedExpActive;
if (sharedExpActive) {
SharedExpStatus_t sharedExpStatus = getSharedExperienceStatus();
this->sharedExpEnabled = sharedExpStatus == SHAREDEXP_OK;
leader->sendTextMessage(MESSAGE_INFO_DESCR, getSharedExpReturnMessage(sharedExpStatus));
} else {
leader->sendTextMessage(MESSAGE_INFO_DESCR, "Shared Experience has been deactivated.");
}
updateAllPartyIcons();
return true;
}
void Party::shareExperience(uint64_t experience, Creature* source/* = nullptr*/)
{
uint64_t shareExperience = experience;
g_events->eventPartyOnShareExperience(this, shareExperience);
for (Player* member : memberList) {
member->onGainSharedExperience(shareExperience, source);
}
leader->onGainSharedExperience(shareExperience, source);
}
bool Party::canUseSharedExperience(const Player* player) const
{
return getMemberSharedExperienceStatus(player) == SHAREDEXP_OK;
}
SharedExpStatus_t Party::getMemberSharedExperienceStatus(const Player* player) const
{
if (memberList.empty()) {
return SHAREDEXP_EMPTYPARTY;
}
uint32_t highestLevel = leader->getLevel();
for (Player* member : memberList) {
if (member->getLevel() > highestLevel) {
highestLevel = member->getLevel();
}
}
uint32_t minLevel = static_cast<uint32_t>(std::ceil((static_cast<float>(highestLevel) * 2) / 3));
if (player->getLevel() < minLevel) {
return SHAREDEXP_LEVELDIFFTOOLARGE;
}
if (!Position::areInRange<EXPERIENCE_SHARE_RANGE, EXPERIENCE_SHARE_RANGE, EXPERIENCE_SHARE_FLOORS>(leader->getPosition(), player->getPosition())) {
return SHAREDEXP_TOOFARAWAY;
}
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 SHAREDEXP_MEMBERINACTIVE;
}
uint64_t timeDiff = OTSYS_TIME() - it->second;
if (timeDiff > static_cast<uint64_t>(g_config.getNumber(ConfigManager::PZ_LOCKED))) {
return SHAREDEXP_MEMBERINACTIVE;
}
}
return SHAREDEXP_OK;
}
SharedExpStatus_t Party::getSharedExperienceStatus()
{
SharedExpStatus_t leaderStatus = getMemberSharedExperienceStatus(leader);
if (leaderStatus != SHAREDEXP_OK) {
return leaderStatus;
}
for (Player* member : memberList) {
SharedExpStatus_t memberStatus = getMemberSharedExperienceStatus(member);
if (memberStatus != SHAREDEXP_OK) {
return memberStatus;
}
}
return SHAREDEXP_OK;
}
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();
}
}