int SingleUseBuffObserverImplementation::notifyObserverEvent(unsigned int eventType, Observable* observable, ManagedObject* arg1, int64 arg2) {
	ManagedReference<SingleUseBuff* > buff = this->buff.get();

	if (buff == NULL)
		return 1;

	ManagedReference<CreatureObject*> player = buff.get()->getPlayer();
	if (player == NULL)
		return 1;

	ManagedReference<ObjectController*> objectController = player->getZoneServer()->getObjectController();

	unsigned int commandCRC = buff.get()->getCommandCRC();
	QueueCommand* queueCommand = objectController->getQueueCommand(commandCRC);

	SceneObject* creature = cast<SceneObject*>( observable);

	queueCommand->handleBuff(creature, arg1, (int)arg2);

	return 0;
}
float ObjectControllerImplementation::activateCommand(CreatureObject* object, unsigned int actionCRC, unsigned int actionCount, uint64 targetID, const UnicodeString& arguments) {
	// Pre: object is wlocked
	// Post: object is wlocked

	QueueCommand* queueCommand = getQueueCommand(actionCRC);

	float durationTime = 0.f;

	if (queueCommand == NULL) {
		StringBuffer msg;
		msg << "unregistered queue command 0x" << hex << actionCRC << " arguments: " << arguments.toString();
		object->error(msg.toString());

		return 0.f;
	}

	/*StringBuffer infoMsg;
	infoMsg << "activating queue command 0x" << hex << actionCRC << " " << queueCommand->getQueueCommandName() << " arguments='" << arguments.toString() << "'";
	object->info(infoMsg.toString(), true);*/

	String characterAbility = queueCommand->getCharacterAbility();

	if (characterAbility.length() > 1) {
		object->info("activating characterAbility " + characterAbility);

		if (object->isPlayerCreature()) {
			Reference<PlayerObject*> playerObject =  object->getSlottedObject("ghost").castTo<PlayerObject*>();

			if (!playerObject->hasAbility(characterAbility)) {
				object->clearQueueAction(actionCount, 0, 2);

				return 0.f;
			}
		}
	}

	uint32 commandGroup = queueCommand->getCommandGroup();

	if (commandGroup != 0) {
		if (commandGroup == 0xe1c9a54a && queueCommand->getQueueCommandName() != "attack") {
			if (!object->isAiAgent()) {
				object->clearQueueAction(actionCount, 0, 2);

				return 0.f;
			}
		}
	}


	if(queueCommand->requiresAdmin()) {

		try {

			if(object->isPlayerCreature()) {
				Reference<PlayerObject*> ghost =  object->getSlottedObject("ghost").castTo<PlayerObject*>();
				if (ghost == NULL || !ghost->isPrivileged() || !ghost->hasAbility(queueCommand->getQueueCommandName())) {

					StringBuffer logEntry;
					logEntry << object->getDisplayedName() << " attempted to use the '/" << queueCommand->getQueueCommandName()
							<< "' command without permissions";
					adminLog.warning(logEntry.toString());
					object->sendSystemMessage("@error_message:insufficient_permissions");
					object->clearQueueAction(actionCount, 0, 2);
					return 0.f;
				}
			} else {
				return 0.f;
			}


			String name = "unknown";

			Reference<SceneObject*> targetObject = Core::getObjectBroker()->lookUp(targetID).castTo<SceneObject*>();
			if(targetObject != NULL) {
				name = targetObject->getDisplayedName();
				if(targetObject->isPlayerCreature())
					name += "(Player)";
				else
					name += "(NPC)";
			} else {
				name = "(null)";
			}

			StringBuffer logEntry;
			logEntry << object->getDisplayedName() << " used '/" << queueCommand->getQueueCommandName()
					<< "' on " << name << " with params '" << arguments.toString() << "'";
			adminLog.info(logEntry.toString());
		} catch (Exception& e) {
			Logger::error("Unhandled Exception logging admin commands" + e.getMessage());
		}
	}

	/// Add Skillmods if any
	for(int i = 0; i < queueCommand->getSkillModSize(); ++i) {
		String skillMod;
		int value = queueCommand->getSkillMod(i, skillMod);
		object->addSkillMod(SkillModManager::ABILITYBONUS, skillMod, value, false);
	}


	int errorNumber = queueCommand->doQueueCommand(object, targetID, arguments);

	/// Remove Skillmods if any
	for(int i = 0; i < queueCommand->getSkillModSize(); ++i) {
		String skillMod;
		int value = queueCommand->getSkillMod(i, skillMod);
		object->addSkillMod(SkillModManager::ABILITYBONUS, skillMod, -value, false);
	}

	//onFail onComplete must clear the action from client queue
	if (errorNumber != QueueCommand::SUCCESS)
		queueCommand->onFail(actionCount, object, errorNumber);
	else {
		if (queueCommand->getDefaultPriority() != QueueCommand::IMMEDIATE)
			durationTime = queueCommand->getCommandDuration(object, arguments);

		queueCommand->onComplete(actionCount, object, durationTime);
	}

	/*if (actionCRC == String("stand").hashCode()) {
		Time start;

		for (int i = 0; i < 10000; ++i) {
			LuaFunction func(L, "runScript", 0);
			func << object;

			callFunction(&func);
			//int cred = object->getBankCredits();
		}

		info("time elapsed " + String::valueOf(start.miliDifference()), true);
	}*/

	return durationTime;
}
float ObjectControllerImplementation::activateCommand(CreatureObject* object, unsigned int actionCRC, unsigned int actionCount, uint64 targetID, const UnicodeString& arguments) {
	// Pre: object is wlocked
	// Post: object is wlocked

	QueueCommand* queueCommand = getQueueCommand(actionCRC);

	float durationTime = 0.f;

	if (queueCommand == NULL) {
		StringBuffer msg;
		msg << "unregistered queue command 0x" << hex << actionCRC << " arguments: " << arguments.toString();
		object->error(msg.toString());

		return 0.f;
	}

	/*StringBuffer infoMsg;
	infoMsg << "activating queue command 0x" << hex << actionCRC << " " << queueCommand->getQueueCommandName() << " arguments='" << arguments.toString() << "'";
	object->info(infoMsg.toString(), true);*/

	const String& characterAbility = queueCommand->getCharacterAbility();

	if (characterAbility.length() > 1) {
		object->info("activating characterAbility " + characterAbility);

		if (object->isPlayerCreature()) {
			Reference<PlayerObject*> playerObject =  object->getSlottedObject("ghost").castTo<PlayerObject*>();

			if (!playerObject->hasAbility(characterAbility)) {
				object->clearQueueAction(actionCount, 0, 2);

				return 0.f;
			}
		}
	}

	uint32 commandGroup = queueCommand->getCommandGroup();

	if (commandGroup != 0) {
		if (commandGroup == 0xe1c9a54a && queueCommand->getQueueCommandName() != "attack") {
			if (!object->isAiAgent()) {
				object->clearQueueAction(actionCount, 0, 2);

				return 0.f;
			}
		}
	}

	if (queueCommand->requiresAdmin()) {
		try {
			if(object->isPlayerCreature()) {
				Reference<PlayerObject*> ghost =  object->getSlottedObject("ghost").castTo<PlayerObject*>();

				if (ghost == NULL || !ghost->hasGodMode() || !ghost->hasAbility(queueCommand->getQueueCommandName())) {
					StringBuffer logEntry;
					logEntry << object->getDisplayedName() << " attempted to use the '/" << queueCommand->getQueueCommandName()
							<< "' command without permissions";
					adminLog.warning(logEntry.toString());
					object->sendSystemMessage("@error_message:insufficient_permissions");
					object->clearQueueAction(actionCount, 0, 2);
					return 0.f;
				}
			} else {
				return 0.f;
			}

			logAdminCommand(object, queueCommand, targetID, arguments);
		} catch (Exception& e) {
			Logger::error("Unhandled Exception logging admin commands" + e.getMessage());
		}
	}

	/// Add Skillmods if any
	for(int i = 0; i < queueCommand->getSkillModSize(); ++i) {
		String skillMod;
		int value = queueCommand->getSkillMod(i, skillMod);
		object->addSkillMod(SkillModManager::ABILITYBONUS, skillMod, value, false);
	}

	int errorNumber = queueCommand->doQueueCommand(object, targetID, arguments);

	/// Remove Skillmods if any
	for(int i = 0; i < queueCommand->getSkillModSize(); ++i) {
		String skillMod;
		int value = queueCommand->getSkillMod(i, skillMod);
		object->addSkillMod(SkillModManager::ABILITYBONUS, skillMod, -value, false);
	}

	//onFail onComplete must clear the action from client queue
	if (errorNumber != QueueCommand::SUCCESS)
		queueCommand->onFail(actionCount, object, errorNumber);
	else {
		if (queueCommand->getDefaultPriority() != QueueCommand::IMMEDIATE)
			durationTime = queueCommand->getCommandDuration(object, arguments);

		queueCommand->onComplete(actionCount, object, durationTime);
	}

	return durationTime;
}