void TangibleObjectImplementation::addDefender(SceneObject* defender) {
	if (defender == asTangibleObject())
		return;

	assert(defender);

	for (int i = 0; i < defenderList.size(); ++i) {
		if (defender == defenderList.get(i))
			return;
	}

	//info("adding defender");

	TangibleObjectDeltaMessage6* dtano6 = new TangibleObjectDeltaMessage6(asTangibleObject());
	dtano6->startUpdate(0x01);

	defenderList.add(defender, dtano6);

	dtano6->close();

	broadcastMessage(dtano6, true);

	setCombatState();

	notifyObservers(ObserverEventType::DEFENDERADDED, defender);
}
void TangibleObjectImplementation::removeDefender(SceneObject* defender) {
	//info("trying to remove defender");
	for (int i = 0; i < defenderList.size(); ++i) {
		if (defenderList.get(i) == defender) {
			info("removing defender");

			notifyObservers(ObserverEventType::DEFENDERDROPPED, defender);

			TangibleObjectDeltaMessage6* dtano6 = new TangibleObjectDeltaMessage6(asTangibleObject());

			dtano6->startUpdate(0x01);

			if (defenderList.size() == 1)
				defenderList.removeAll(dtano6);
			else
				defenderList.remove(i, dtano6);

			dtano6->close();

			broadcastMessage(dtano6, true);

			//info("defender found and removed");
			break;
		}
	}

	if (defenderList.size() == 0)
		clearCombatState(false);

	//info("finished removing defender");
}
bool TangibleObjectImplementation::isAttackableBy(CreatureObject* object) {
	if (isImperial() && !(object->isRebel())) {
		return false;
	} else if (isRebel() && !(object->isImperial())) {
		return false;
	} else if (object->isPlayerCreature() && object->getPlayerObject()) {
		if (isImperial() && (object->getPlayerObject())->getFactionStatus() == 0) {
			return false;
		}

		if (isRebel() && (object->getPlayerObject())->getFactionStatus() == 0) {
			return false;
		}

	} else if (object->isAiAgent()) {
		AiAgent* ai = object->asAiAgent();

		if (ai->getHomeObject().get() == asTangibleObject()) {
			return false;
		}

		if (ai->isPet()) {
			ManagedReference<PetControlDevice*> pcd = ai->getControlDevice().get().castTo<PetControlDevice*>();
			if (pcd != NULL && pcd->getPetType() == PetManager::FACTIONPET && isNeutral()) {
				return false;
			}
		}
	}

	return pvpStatusBitmask & CreatureFlag::ATTACKABLE;
}
int TangibleObjectImplementation::inflictDamage(TangibleObject* attacker, int damageType, float damage, bool destroy, bool notifyClient) {
	if(hasAntiDecayKit())
		return 0;

	float newConditionDamage = conditionDamage + damage;

	if (!destroy && newConditionDamage >= maxCondition)
		newConditionDamage = maxCondition - 1;
	else if (newConditionDamage >= maxCondition)
		newConditionDamage = maxCondition;

	setConditionDamage(newConditionDamage, notifyClient);

	if (attacker->isCreatureObject()) {
		CreatureObject* creature = attacker->asCreatureObject();

		if (damage > 0 && attacker != asTangibleObject())
			getThreatMap()->addDamage(creature, (uint32)damage);
	}

	if (newConditionDamage >= maxCondition)
		notifyObjectDestructionObservers(attacker, newConditionDamage);

	return 0;
}
void TangibleObjectImplementation::dropFromDefenderLists(TangibleObject* destructor) {
	if (defenderList.size() == 0)
		return;

	Reference<ClearDefenderListsTask*> task = new ClearDefenderListsTask(defenderList, asTangibleObject());
	Core::getTaskManager()->executeTask(task);

	clearCombatState(false);
}
ThreatMap* TangibleObjectImplementation::getThreatMap() {
	if (threatMap == NULL) {
		Reference<ThreatMap*> newMap = new ThreatMap(asTangibleObject());

		threatMap.compareAndSet(NULL, newMap.get());
	}

	return threatMap;
}
void TangibleObjectImplementation::setCustomizationVariable(byte type, int16 value, bool notifyClient) {
	customizationVariables.setVariable(type, value);

	if (!notifyClient)
		return;

	TangibleObjectDeltaMessage3* dtano3 = new TangibleObjectDeltaMessage3(asTangibleObject());
	dtano3->updateCustomizationString();
	dtano3->close();

	broadcastMessage(dtano3, true);
}
void TangibleObjectImplementation::setCustomObjectName(const UnicodeString& name, bool notifyClient) {
	customName = name;

	if (!notifyClient)
		return;

	TangibleObjectDeltaMessage3* dtano3 = new TangibleObjectDeltaMessage3(asTangibleObject());
	dtano3->updateName(name);
	dtano3->close();

	broadcastMessage(dtano3, true);
}
void TangibleObjectImplementation::setObjectName(StringId& stringID, bool notifyClient) {
	objectName = stringID;

	if (!notifyClient)
		return;

	TangibleObjectDeltaMessage3* dtano3 = new TangibleObjectDeltaMessage3(asTangibleObject());
	dtano3->updateObjectName(stringID);
	dtano3->close();

	broadcastMessage(dtano3, true);
}
void TangibleObjectImplementation::setDefender(SceneObject* defender) {
	if (defender == asTangibleObject())
		return;

	assert(defender);

	if (defenderList.size() == 0) {
		addDefender(defender);
		return;
	}

	ManagedReference<SceneObject*> temp = NULL;

	int i = 0;
	for (; i < defenderList.size(); i++) {
		if (defenderList.get(i) == defender) {
			if (i == 0)
				return;

			temp = defenderList.get(0);

			TangibleObjectDeltaMessage6* dtano6 = new TangibleObjectDeltaMessage6(asTangibleObject());
			dtano6->startUpdate(0x01);

			defenderList.set(0, defender, dtano6, 2);
			defenderList.set(i, temp, dtano6, 0);

			dtano6->close();

			broadcastMessage(dtano6, true);

			break;
		}
	}

	if (i == defenderList.size())
		addDefender(defender);
	else
		setCombatState();
}
void TangibleObjectImplementation::removeAllVisibleComponents(bool notifyClient) {
	if (notifyClient) {
		TangibleObjectDeltaMessage3* dtano3 = new TangibleObjectDeltaMessage3(asTangibleObject());
		dtano3->startUpdate(0x05);

		visibleComponents.removeAll(dtano3);

		dtano3->close();

		broadcastMessage(dtano3, true);
	} else {
		visibleComponents.removeAll();
	}
}
void TangibleObjectImplementation::sendPvpStatusTo(CreatureObject* player) {
	uint32 newPvpStatusBitmask = pvpStatusBitmask;

	if (!(newPvpStatusBitmask & CreatureFlag::ATTACKABLE)) {
		if (isAttackableBy(player))
			newPvpStatusBitmask |= CreatureFlag::ATTACKABLE;
	} else if (!isAttackableBy(player))
		newPvpStatusBitmask -= CreatureFlag::ATTACKABLE;

	if (!(newPvpStatusBitmask & CreatureFlag::AGGRESSIVE)) {
		if (isAggressiveTo(player))
			newPvpStatusBitmask |= CreatureFlag::AGGRESSIVE;
	} else if (!isAggressiveTo(player))
		newPvpStatusBitmask -= CreatureFlag::AGGRESSIVE;

	if (newPvpStatusBitmask & CreatureFlag::TEF) {
		if (player != asTangibleObject())
			newPvpStatusBitmask -= CreatureFlag::TEF;
	}

	BaseMessage* pvp = new UpdatePVPStatusMessage(asTangibleObject(), newPvpStatusBitmask);
	player->sendMessage(pvp);
}
void TangibleObjectImplementation::sendBaselinesTo(SceneObject* player) {
	info("sending tano baselines");

	Reference<TangibleObject*> thisPointer = asTangibleObject();

	BaseMessage* tano3 = new TangibleObjectMessage3(thisPointer);
	player->sendMessage(tano3);

	BaseMessage* tano6 = new TangibleObjectMessage6(thisPointer);
	player->sendMessage(tano6);

	if (player->isPlayerCreature())
		sendPvpStatusTo(player->asCreatureObject());
}
void TangibleObjectImplementation::setCountdownTimer(unsigned int newUseCount, bool notifyClient) {
	if (useCount == newUseCount)
		return;

	useCount = newUseCount;

	if (!notifyClient)
		return;

	TangibleObjectDeltaMessage3* dtano3 = new TangibleObjectDeltaMessage3(asTangibleObject());
	dtano3->updateCountdownTimer();
	dtano3->close();

	broadcastMessage(dtano3, true);
}
void TangibleObjectImplementation::setOptionsBitmask(uint32 bitmask, bool notifyClient) {
	if (bitmask == optionsBitmask)
		return;

	optionsBitmask = bitmask;

	if (!notifyClient)
		return;

	TangibleObjectDeltaMessage3* dtano3 = new TangibleObjectDeltaMessage3(asTangibleObject());
	dtano3->updateOptionsBitmask();
	dtano3->close();

	broadcastMessage(dtano3, true);
}
void TangibleObjectImplementation::setMaxCondition(int maxCond, bool notifyClient) {
	if (maxCondition == maxCond)
		return;

	maxCondition = maxCond;

	if (!notifyClient)
		return;

	TangibleObjectDeltaMessage3* dtano3 = new TangibleObjectDeltaMessage3(asTangibleObject());
	dtano3->updateMaxCondition();
	dtano3->close();

	broadcastMessage(dtano3, true);
}
void TangibleObjectImplementation::setConditionDamage(float condDamage, bool notifyClient) {
	if (conditionDamage == condDamage)
		return;

	conditionDamage = condDamage;

	if (!notifyClient)
		return;

	TangibleObjectDeltaMessage3* dtano3 = new TangibleObjectDeltaMessage3(asTangibleObject());
	dtano3->updateConditionDamage();
	dtano3->close();

	broadcastMessage(dtano3, true);
}
void TangibleObjectImplementation::removeVisibleComponent(int value, bool notifyClient) {
	if (!visibleComponents.contains(value))
		return;

	if (notifyClient) {
		TangibleObjectDeltaMessage3* dtano3 = new TangibleObjectDeltaMessage3(asTangibleObject());
		dtano3->startUpdate(0x05);

		visibleComponents.drop(value, dtano3);

		dtano3->close();

		broadcastMessage(dtano3, true);
	} else {
		visibleComponents.drop(value);
	}
}
void TangibleObjectImplementation::notifyLoadFromDatabase() {
	SceneObjectImplementation::notifyLoadFromDatabase();

	for (int i = 0; i < activeAreas.size(); ++i) {
		activeAreas.get(i)->notifyExit(asTangibleObject());
	}

	activeAreas.removeAll();

	if (hasAntiDecayKit()) {
		AntiDecayKit* adk = antiDecayKitObject.castTo<AntiDecayKit*>();

		if (adk != NULL && !adk->isUsed()) {
			Locker locker(adk);

			adk->setUsed(true);
		}
	}
}
void TangibleObjectImplementation::removeDefenders() {
	//info("removing all defenders");
	if (defenderList.size() == 0) {
		//info("no defenders in list");
		return;
	}

	for (int i = 0; i < defenderList.size(); i++)
		notifyObservers(ObserverEventType::DEFENDERDROPPED, defenderList.get(i));

	TangibleObjectDeltaMessage6* dtano6 = new TangibleObjectDeltaMessage6(asTangibleObject());
	dtano6->startUpdate(0x01);

	defenderList.removeAll(dtano6);

	dtano6->close();

	broadcastMessage(dtano6, true);

	//info("removed all defenders");
}
void TangibleObjectImplementation::synchronizedUIListen(SceneObject* player, int value) {
	// Send TANO7 Baseline
	TangibleObjectMessage7* tano7 = new TangibleObjectMessage7(asTangibleObject());
	player->sendMessage(tano7);
}
Reference<FactoryCrate*> TangibleObjectImplementation::createFactoryCrate(bool insertSelf) {
	String file;
	uint32 type = getGameObjectType();

	if(type & SceneObjectType::ARMOR)
		file = "object/factory/factory_crate_armor.iff";
	else if(type == SceneObjectType::CHEMICAL || type == SceneObjectType::PHARMACEUTICAL || type == SceneObjectType::PETMEDECINE)
		file = "object/factory/factory_crate_chemicals.iff";
	else if(type & SceneObjectType::CLOTHING)
		file = "object/factory/factory_crate_clothing.iff";
	else if(type == SceneObjectType::ELECTRONICS)
		file = "object/factory/factory_crate_electronics.iff";
	else if(type == SceneObjectType::FOOD || type == SceneObjectType::DRINK)
		file = "object/factory/factory_crate_food.iff";
	else if(type == SceneObjectType::FURNITURE)
		file = "object/factory/factory_crate_furniture.iff";
	else if(type & SceneObjectType::INSTALLATION)
		file = "object/factory/factory_crate_installation.iff";
	else if(type & SceneObjectType::WEAPON)
		file = "object/factory/factory_crate_weapon.iff";
	else
		file = "object/factory/factory_crate_generic_items.iff";

	SharedTangibleObjectTemplate* tanoData = dynamic_cast<SharedTangibleObjectTemplate*>(templateObject.get());

	if (tanoData == NULL)
		return NULL;

	ObjectManager* objectManager = ObjectManager::instance();

	Reference<FactoryCrate*> crate = (getZoneServer()->createObject(file.hashCode(), 2)).castTo<FactoryCrate*>();

	if (crate == NULL)
		return NULL;

	Locker locker(crate);

	crate->setMaxCapacity(tanoData->getFactoryCrateSize());

	if (insertSelf) {
		if (!crate->transferObject(asTangibleObject(), -1, false)) {
			crate->destroyObjectFromDatabase(true);
			return NULL;
		}
	} else {

		ManagedReference<TangibleObject*> protoclone = cast<TangibleObject*>( objectManager->cloneObject(asTangibleObject()));

		if (protoclone == NULL) {
			crate->destroyObjectFromDatabase(true);
			return NULL;
		}

		protoclone->setParent(NULL);
		if (!crate->transferObject(protoclone, -1, false)) {
			protoclone->destroyObjectFromDatabase(true);
			crate->destroyObjectFromDatabase(true);
			return NULL;
		}
	}

	crate->setCustomObjectName(getCustomObjectName(), false);

	crate->setUseCount(1);

	return crate;
}
void TangibleObjectImplementation::sendTo(SceneObject* player, bool doClose) {
	if (isInvisible() && player != asTangibleObject())
		return;

	SceneObjectImplementation::sendTo(player, doClose);
}