void EntertainingSessionImplementation::doPerformanceAction() {
	ManagedReference<CreatureObject*> entertainer = this->entertainer.get();

	if (entertainer == NULL)
		return;

	Locker locker(entertainer);

	Performance* performance = NULL;

	PerformanceManager* performanceManager = SkillManager::instance()->getPerformanceManager();
	ManagedReference<Instrument*> instrument = getInstrument(entertainer);

	if (isDancing())
		performance = performanceManager->getDance(performanceName);
	else if (isPlayingMusic() && instrument)
		performance = performanceManager->getSong(performanceName, instrument->getInstrumentType());
	else {
		cancelSession();
		return;
	}

	if (performance == NULL) { // shouldn't happen
		StringBuffer msg;
		msg << "Performance was null.  Please report to www.swgemu.com/bugs ! Name: " << performanceName << " and Type: " << dec << instrument->getInstrumentType();

		entertainer->sendSystemMessage(msg.toString());
		return;
	}

	int actionDrain = performance->getActionPointsPerLoop();

	//Adjust cost based upon player's quickness
	actionDrain = entertainer->calculateCostAdjustment(CreatureAttribute::QUICKNESS, actionDrain);

	if (entertainer->getHAM(CreatureAttribute::ACTION) <= actionDrain) {
		if (isDancing()) {
			stopDancing();
			entertainer->sendSystemMessage("@performance:dance_too_tired");
		}

		if (isPlayingMusic()) {
			stopPlayingMusic();
			entertainer->sendSystemMessage("@performance:music_too_tired");
		}
	} else {
		entertainer->inflictDamage(entertainer, CreatureAttribute::ACTION, actionDrain, false, true);
	}
}
void EntertainingSessionImplementation::activateAction() {
	ManagedReference<CreatureObject*> entertainer = this->entertainer.get();

	if (entertainer == NULL)
		return;

	Locker locker(entertainer);

	if (!isDancing() && !isPlayingMusic()) {
		return; // don't tick action if they aren't doing anything
	}

	doEntertainerPatronEffects();
	awardEntertainerExperience();
	doPerformanceAction();


	startTickTask();

	entertainer->info("EntertainerEvent completed.");
}
//Play / Pause / Resume / Stop
void AudioManager::playMusic(
        const std::string &musicId,
        float volume /* = 1.0f  */,
        bool  loop   /* = false */,
        const MusicFinishCallback &callback /*= MusicFinishCallback() */
)
{
    _CHECK_AND_WARN_IF_NOT_EXISTS(
        "AudioManager::playMusic",
        "MusicId is not loaded: (%s)",
        m_musicMap,
        musicId
    );

    if(isPlayingMusic(musicId))
    {
        MF_LOG_WARNING_EX(
            "AudioManager::playMusic",
            "Already playing MusicId: (%s)",
            musicId.c_str()
        );
        return;
    }

    //Get the sound info object.
    auto& sound = m_musicMap[musicId];

    //Upadte the current internal id.
    sound.currInternalId = _AE::play2d(sound.filepath, loop, volume);

    //Set the callback if needed.
    if(callback)
    {
        _AE::setFinishCallback(sound.currInternalId,
                               [musicId, callback](int, const std::string &){
            callback(musicId);
        });
    }
}
void EntertainingSessionImplementation::awardEntertainerExperience() {
	ManagedReference<CreatureObject*> entertainer = this->entertainer.get();
	ManagedReference<PlayerManager*> playerManager = entertainer->getZoneServer()->getPlayerManager();

	CreatureObject* player = entertainer->isPlayerCreature() ? cast<CreatureObject*>(entertainer.get()) : NULL;

	if (player != NULL) {
		if (flourishXp > 0 && (isDancing() || isPlayingMusic())) {
			String xptype;

			if (isDancing())
				xptype = "dance";
			else if (isPlayingMusic())
				xptype = "music";

			int groupBonusPercent = 0;
			int groupBonus  = 0;

			if(player->getGroup() != NULL) {

				ManagedReference<GroupObject*> group = player->getGroup();
				int groupSize = group->getGroupSize();

				for(int i = 0; i < groupSize; ++i) {
					ManagedReference<CreatureObject*> groupMember = group->getGroupMember(i)->isPlayerCreature() ? group->getGroupMember(i).castTo<CreatureObject*>() : NULL;

					if (groupMember != NULL) {
						Locker clocker(groupMember, entertainer);

						if (groupMember->isEntertaining() && groupMember->isInRange(entertainer, 40.0f)
								&& groupMember->hasSkill("social_entertainer_novice")) {
							++groupBonusPercent;
						}
					}
				}

				groupBonus = ceil(flourishXp * (groupBonusPercent / 100));

			}

			flourishXp += groupBonus;

			if (playerManager != NULL)
				playerManager->awardExperience(player, xptype, flourishXp, true);

			//flourishXp--;
			flourishXp = 0;
		}

		if (healingXp > 0) {
			String healxptype("entertainer_healing");

			if (playerManager != NULL)
				playerManager->awardExperience(player, healxptype, healingXp, true);

			healingXp = 0;
		}
	}

	healingXp = 0;
	flourishCount = 0;
}