void DroidObjectImplementation::initDroidModules(bool init){
	modules.removeAll();
	ManagedReference<SceneObject*> container = getSlottedObject("crafted_components");
	if(container != NULL && container->getContainerObjectsSize() > 0) {
		SceneObject* satchel = container->getContainerObject(0);
		if(satchel != NULL && satchel->getContainerObjectsSize() > 0) {
			for (int i = 0; i < satchel->getContainerObjectsSize(); ++i) {
				ManagedReference<SceneObject*> sceno = satchel->getContainerObject(i);
				if( sceno == NULL ){
					continue;
				}
				DataObjectComponentReference* data = sceno->getDataObjectComponent();
				if(data == NULL || data->get() == NULL || !data->get()->isDroidModuleData() ){
					continue;
				}
				BaseDroidModuleComponent* module = cast<BaseDroidModuleComponent*>(data->get());
				if( module != NULL ){
					modules.add(module);
					if (init) {
						module->initialize( _this.get());
					}
				}
			}
		} else {
			// no modules, so disable some combat stats.
			setResists(0);
			setHitChance(0);
		}
	}
}
void DroidObjectImplementation::runModulePowerDrain() {
	for( int i=0; i<modules.size(); i++){
		BaseDroidModuleComponent* module = modules.get(i);
		int drain = module->getBatteryDrain();
		if(drain > 0)
			usePower(drain);
	}
}
bool DroidObjectImplementation::isMerchantBarker() {
	for( int i=0; i<modules.size(); i++){
		BaseDroidModuleComponent* module = modules.get(i);
		if(module->getModuleName() == "merchant_barker") {
			return true;
		}
	}
	return false;
}
bool DroidObjectImplementation::isMaintenanceDroid() {
	for( int i=0; i<modules.size(); i++){
		BaseDroidModuleComponent* module = modules.get(i);
		if(module->getModuleName() == "maintenance_module") {
			return true;
		}
	}
	return false;
}
BaseDroidModuleComponent* DroidObjectImplementation::getModule(const String& name) {
	for(int i=0;i<modules.size();i++) {
		BaseDroidModuleComponent* module = modules.get(i);
		if(module->getModuleName() == name) {
			return module;
		}
	}
	return NULL;
}
bool DroidObjectImplementation::hasStorage() {
	for( int i=0; i<modules.size(); i++){
		BaseDroidModuleComponent* module = modules.get(i);
		if(module->getModuleName() == "item_storage_module") {
			return true;
		}
	}
	return false;
}
int DroidObjectImplementation::handleObjectMenuSelect(CreatureObject* player, byte selectedID){

	// Allow modules to handle radials if desired
	PetControlDevice* pcd = getControlDevice().get().castTo<PetControlDevice*>();
	for( int i=0; i<modules.size(); i++){
		BaseDroidModuleComponent* module = modules.get(i);
		module->handleObjectMenuSelect(player, selectedID, pcd);
	}

	return SceneObjectImplementation::handleObjectMenuSelect(player, selectedID); // PetMenuComponent

}
void DroidObjectImplementation::fillObjectMenuResponse(ObjectMenuResponse* menuResponse, CreatureObject* player){

	SceneObjectImplementation::fillObjectMenuResponse( menuResponse, player ); // PetMenuComponent

	// Allow modules to add radials
	PetControlDevice* pcd = getControlDevice().get().castTo<PetControlDevice*>();
	for( int i=0; i<modules.size(); i++){
		BaseDroidModuleComponent* module = modules.get(i);
		module->fillObjectMenuResponse( _this.get(), menuResponse, player );
	}

}
bool DroidObjectImplementation::isStructureAssigned( StructureObject* structure ){
	for( int i=0; i<modules.size(); i++){
		BaseDroidModuleComponent* module = modules.get(i);
		if(module->getModuleName() == "maintenance_module") {
			DroidMaintenanceModuleDataComponent* maintModule = dynamic_cast<DroidMaintenanceModuleDataComponent*>(module);
			if( maintModule != NULL ){
				return maintModule->isAssignedTo( structure->getObjectID() );
			}
		}
	}
	return false;
}
bool DroidObjectImplementation::isCombatDroid() {
	for( int i=0; i<modules.size(); i++){
		BaseDroidModuleComponent* module = modules.get(i);
		if(module->isCombatModule()) {
			return true;
		}
	}
	// inante comabt ability, regardless of module installed
	if (getSpecies() == PROBOT || getSpecies() == DZ70)
		return true;

	return false;
}
void DroidDeedImplementation::processModule(BaseDroidModuleComponent* module, uint32 crc) {
	if (module == NULL)
		return;
	if (module->isStackable()) {
		if (modules.containsKey(module->getModuleName())) {
			// add to the stack if stackable.
			DroidComponent* comp = modules.get(module->getModuleName());
			BaseDroidModuleComponent* bmodule = cast<BaseDroidModuleComponent*>(comp->getDataObjectComponent()->get());
			bmodule->addToStack(module);
		} else {
			ManagedReference<DroidComponent*> dcomp = (this->getZoneServer()->createObject(crc,1)).castTo<DroidComponent*>();
			dcomp->setParent(NULL);
			BaseDroidModuleComponent* bmodule = cast<BaseDroidModuleComponent*>(dcomp->getDataObjectComponent()->get());
			bmodule->copy(module);
			bmodule->setSpecies(species);
			modules.put(module->getModuleName(),dcomp);
		}
	} else {
		ManagedReference<DroidComponent*> dcomp = (this->getZoneServer()->createObject(crc,1)).castTo<DroidComponent*>();
		dcomp->setParent(NULL);
		BaseDroidModuleComponent* bmodule = cast<BaseDroidModuleComponent*>(dcomp->getDataObjectComponent()->get());
		bmodule->copy(module);
		bmodule->setSpecies(species);
		modules.put(module->getModuleName(),dcomp);
	}

}
void DroidObjectImplementation::handleLowPower(){

	// Send fly text
	showFlyText("npc_reaction/flytext","low_power", 204, 0, 0);  // "*Low Power*"
	doAnimation("power_down");

	// Stop following
	setOblivious();

	// Deactivate all modules
	for( int i=0; i<modules.size(); i++){
		BaseDroidModuleComponent* module = modules.get(i);
		module->deactivate();
	}

	return;
}
void DroidDeedImplementation::fillAttributeList(AttributeListMessage* alm, CreatureObject* object) {
	DeedImplementation::fillAttributeList(alm, object);

	// @TODO Add attributes
	// Deed needs to show a few important bits
	// 1.) HAM
	int maxHam = DroidMechanics::determineHam(overallQuality,species);
	alm->insertAttribute("challenge_level", level);
	alm->insertAttribute("creature_health", maxHam);
	alm->insertAttribute("creature_action", maxHam);
	alm->insertAttribute("creature_mind", maxHam);
	if(combatRating > 0 || (species == DroidObject::DZ70 || species == DroidObject::PROBOT) ) {
		StringBuffer attdisplayValue;
		float attackSpeed = DroidMechanics::determineSpeed(species,maxHam);
		float chanceHit = DroidMechanics::determineHit(species,maxHam);
		// do we have a combat module installed?
		float damageMin = DroidMechanics::determineMinDamage(species,combatRating);
		float damageMax = DroidMechanics::determineMaxDamage(species,combatRating);
		attdisplayValue << Math::getPrecision(attackSpeed, 2);
		StringBuffer hitdisplayValue;
		hitdisplayValue << Math::getPrecision(chanceHit, 2);
		alm->insertAttribute("creature_attack", attdisplayValue);
		alm->insertAttribute("creature_tohit", hitdisplayValue);
		alm->insertAttribute("creature_damage", String::valueOf(damageMin) + " - " + String::valueOf(damageMax));
	}
	// hit and speed?
	// if object is the master
	String key;
	ManagedReference<DroidComponent*> comp = NULL;
	HashTableIterator<String, ManagedReference<DroidComponent*> > iterator = modules.iterator();
	for(int i = 0; i < modules.size(); ++i) {
		iterator.getNextKeyAndValue(key, comp);
		if (comp) {
			DataObjectComponentReference* data = comp->getDataObjectComponent();
			BaseDroidModuleComponent* module = NULL;
			if(data != NULL && data->get() != NULL && data->get()->isDroidModuleData() ){
				module = cast<BaseDroidModuleComponent*>(data->get());
			}
			if (module == NULL) {
				continue;
			}
			module->fillAttributeList(alm,object);
		}
	}
}
int DroidObjectImplementation::handleObjectMenuSelect(CreatureObject* player, byte selectedID){

	PetControlDevice* pcd = getControlDevice().get().castTo<PetControlDevice*>();
	if (getLinkedCreature().get() == player) {
		// Allow modules to handle radials if desired
		for( int i=0; i<modules.size(); i++){
			BaseDroidModuleComponent* module = modules.get(i);
			module->handleObjectMenuSelect(player, selectedID, pcd);
		}
	}
	else if (isMerchantBarker()) {
		BaseDroidModuleComponent* module = getModule("merchant_barker");
		if(module != NULL)
			module->handleObjectMenuSelect(player, selectedID, pcd);
	}
	return SceneObjectImplementation::handleObjectMenuSelect(player, selectedID); // PetMenuComponent

}
CraftingStation* DroidObjectImplementation::getCraftingStation(int type){
	for( int i=0; i<modules.size(); i++){
		BaseDroidModuleComponent* module = modules.get(i);
		if( module != NULL && module->actsAsCraftingStation()){
			DroidCraftingModuleDataComponent* craftingModule = dynamic_cast<DroidCraftingModuleDataComponent*>(module);
			if( craftingModule != NULL ){
				CraftingStation* craftingStation = craftingModule->getCraftingStation();
				if (craftingStation != NULL) {
					// case here to check each type
					if (craftingModule->validCraftingType(type) || (type == CraftingTool::JEDI && craftingModule->isWeaponDroidGeneric()) || (type == CraftingTool::GENERIC && craftingModule->isWeaponDroidGeneric()))
					{
						return craftingStation;
					}
				}
			}
		}
	}
	return NULL;
}
void DroidObjectImplementation::fillAttributeList(AttributeListMessage* msg, CreatureObject* object){

	AiAgentImplementation::fillAttributeList( msg, object );

	float percentPower = ((float)power/(float)MAX_POWER)*100.0;
	msg->insertAttribute("@obj_attr_n:battery_power", String::valueOf((int)percentPower) + "%");

	if (paintCount > 0){
		msg->insertAttribute("customization_cnt", paintCount);
	}
	// only the owner should see module stats. AiAgent will fill in normal stuff
	if (getLinkedCreature().get() == object || getLinkedCreature().get() == NULL || object == NULL) {
		for( int i=0; i<modules.size(); i++){
			BaseDroidModuleComponent* module = modules.get(i);
			if( module != NULL ){
				module->fillAttributeList(msg, object);
			}
		}
	}
}
void DroidObjectImplementation::fillObjectMenuResponse(ObjectMenuResponse* menuResponse, CreatureObject* player){

	SceneObjectImplementation::fillObjectMenuResponse( menuResponse, player ); // PetMenuComponent
	if (isMerchantBarker() && getLinkedCreature().get() != player) {
		BaseDroidModuleComponent* module = getModule("merchant_barker");
		if (module != NULL)
			module->fillObjectMenuResponse( _this.getReferenceUnsafeStaticCast(), menuResponse, player );
		return;
	}
	if (getLinkedCreature().get() != player) {
		return;
	}

	// Allow modules to add radials
	PetControlDevice* pcd = getControlDevice().get().castTo<PetControlDevice*>();
	for( int i=0; i<modules.size(); i++){
		BaseDroidModuleComponent* module = modules.get(i);
		module->fillObjectMenuResponse( _this.getReferenceUnsafeStaticCast(), menuResponse, player );
	}

}
void DroidObjectImplementation::fillAttributeList(AttributeListMessage* msg, CreatureObject* object){

	AiAgentImplementation::fillAttributeList( msg, object );

	ManagedReference<ControlDevice*> device = getControlDevice().get();

	if (device != NULL && device->isASubChildOf(object)) {
		float percentPower = ((float)power/(float)MAX_POWER)*100.0;
		msg->insertAttribute("@obj_attr_n:battery_power", String::valueOf((int)percentPower) + "%");

		if (paintCount > 0){
			msg->insertAttribute("customization_cnt", paintCount);
		}

		for( int i=0; i<modules.size(); i++){
			BaseDroidModuleComponent* module = modules.get(i);
			if( module != NULL ){
				module->fillAttributeList(msg, object);
			}
		}
	}
}
void DroidObjectImplementation::unloadSkillMods(CreatureObject* player) {
	for( int i=0; i<modules.size(); i++){
		BaseDroidModuleComponent* module = modules.get(i);
		module->unloadSkillMods(player);
	}
}
void DroidObjectImplementation::onCall() {
	for( int i=0; i<modules.size(); i++){
		BaseDroidModuleComponent* module = modules.get(i);
		module->onCall();
	}
}
int DroidDeedImplementation::handleObjectMenuSelect(CreatureObject* player, byte selectedID) {

	if (selectedID == 20) {

		if (generated || !isASubChildOf(player))
			return 1;

		if (player->isInCombat() || player->isRidingMount() || player->isSwimming() || player->isDead() || player->isIncapacitated() ){
			player->sendSystemMessage("@pet/pet_menu:cant_call"); // "You cannot call this pet right now."
			return 1;
		}

		ManagedReference<SceneObject*> datapad = player->getSlottedObject("datapad");

		if (datapad == NULL) {
			player->sendSystemMessage("Datapad doesn't exist when trying to generate droid");
			return 1;
		}

		// Check if this will exceed maximum number of droids allowed
		ManagedReference<PlayerManager*> playerManager = player->getZoneServer()->getPlayerManager();

		int droidsInDatapad = 0;
		int maxStoredDroids = playerManager->getBaseStoredDroids();

		for (int i = 0; i < datapad->getContainerObjectsSize(); i++) {
			Reference<SceneObject*> obj =  datapad->getContainerObject(i).castTo<SceneObject*>();

			if (obj != NULL && obj->isPetControlDevice() ){
				Reference<PetControlDevice*> petDevice = cast<PetControlDevice*>(obj.get());
				if( petDevice != NULL && petDevice->getPetType() == PetManager::DROIDPET){
					droidsInDatapad++;
				}
			}
		}

		if( droidsInDatapad >= maxStoredDroids){
			player->sendSystemMessage("You have too many droids in your datapad");
			return 1;
		}

		Reference<CreatureManager*> creatureManager = player->getZone()->getCreatureManager();
		if( creatureManager == NULL )
			return 1;

		CreatureTemplateManager* creatureTemplateManager = CreatureTemplateManager::instance();
		Reference<CreatureTemplate*> creatureTemplate =  creatureTemplateManager->getTemplate( mobileTemplate.hashCode() );
		if( creatureTemplate == NULL ){
			player->sendSystemMessage("wrong droid template;mobileTemplate=[" + mobileTemplate + "]" );
			return 1;
		}

		Reference<PetControlDevice*> controlDevice = (server->getZoneServer()->createObject(controlDeviceObjectTemplate.hashCode(), 1)).castTo<PetControlDevice*>();
		if( controlDevice == NULL ){
			player->sendSystemMessage("wrong droid control device template " + controlDeviceObjectTemplate);
			return 1;
		}

		Locker locker(controlDevice);

		Reference<CreatureObject*> creatureObject = creatureManager->createCreature(generatedObjectTemplate.hashCode(), true, mobileTemplate.hashCode() );
		if( creatureObject == NULL ){
			controlDevice->destroyObjectFromDatabase(true);
			player->sendSystemMessage("wrong droid templates;mobileTemplate=[" + mobileTemplate + "];generatedObjectTemplate=[" + generatedObjectTemplate + "]" );
			return 1;
		}

		Locker clocker(creatureObject, player);

		Reference<DroidObject*> droid = creatureObject.castTo<DroidObject*>();
		if( droid == NULL ) {
			controlDevice->destroyObjectFromDatabase(true);
			creatureObject->destroyObjectFromDatabase(true);
			return 1;
		}

		droid->loadTemplateData( creatureTemplate );
		droid->setCustomObjectName(StringIdManager::instance()->getStringId(*droid->getObjectName()), true);

		// Transfer crafting components from deed to droid
		ManagedReference<SceneObject*> craftingComponents = getSlottedObject("crafted_components");
		if(craftingComponents != NULL) {
			SceneObject* satchel = craftingComponents->getContainerObject(0);
			// remove all items form satchel and add int he new items
			Vector<ManagedReference<SceneObject*> > toRemove;
			for (int i = 0; i < satchel->getContainerObjectsSize(); ++i) {
				ManagedReference<SceneObject*> sceno = satchel->getContainerObject(i);
				if (sceno != NULL) {
					toRemove.add(sceno);
				}
			}
			satchel->removeAllContainerObjects();
			for(int i=0;i<toRemove.size();i++) {
				SceneObject* component = toRemove.get(i);
				Locker componenetLocker(component);
				component->destroyObjectFromWorld(true);
			}
			// this will change to use stacked modules. we wont care about non droid modules as they arent needed.
			String key;
			ManagedReference<DroidComponent*> comp = NULL;
			HashTableIterator<String, ManagedReference<DroidComponent*> > iterator = modules.iterator();
			droid->setResists(0);
			droid->setHitChance(0);
			for(int i = 0; i < modules.size(); ++i) {
				iterator.getNextKeyAndValue(key, comp);
				if (comp) {
					satchel->transferObject(comp, -1, false);
					DataObjectComponentReference* data = comp->getDataObjectComponent();
					BaseDroidModuleComponent* module = NULL;
					if(data != NULL && data->get() != NULL && data->get()->isDroidModuleData()) {
						module = cast<BaseDroidModuleComponent*>(data->get());
						module->initialize(droid);
					}
				}
			}
			droid->transferObject(craftingComponents, 4, false);
			craftingComponents->setSendToClient(false);
		}
		// Copy color customization from deed to droid
		CustomizationVariables* customVars = getCustomizationVariables();
		if( customVars != NULL ){
			for (int i = 0; i < customVars->size(); ++i) {
				uint8 id = customVars->elementAt(i).getKey();
				int16 val = customVars->elementAt(i).getValue();

				String name = CustomizationIdManager::instance()->getCustomizationVariable(id);
				if( name.contains( "color" ) ){
					droid->setCustomizationVariable( name, val, true );
				}
			}
			droid->refreshPaint();
		}

		StringId s;
		s.setStringId(droid->getObjectName()->getFullPath());
		controlDevice->setObjectName(s);
		controlDevice->setPetType(PetManager::DROIDPET);
		controlDevice->setMaxVitality(100);
		controlDevice->setVitality(100);
		droid->createChildObjects();
		controlDevice->setControlledObject(droid);
		controlDevice->setDefaultCommands();

		if (!datapad->transferObject(controlDevice, -1)) {
			controlDevice->destroyObjectFromDatabase(true);
			return 1;
		}

		datapad->broadcastObject(controlDevice, true);

		controlDevice->callObject(player);
		droid->initDroidModules(true);
		float maxHam = DroidMechanics::determineHam(overallQuality,species);
		for (int i = 0; i < 9; ++i) {
			if (i % 3 == 0) {
				droid->setBaseHAM(i,maxHam,true);
				droid->setHAM(i,maxHam,true);
			} else {
				droid->setBaseHAM(i,maxHam/100,true);
				droid->setHAM(i,maxHam/100,true);
			}
		}

		//Remove the deed from its container.
		ManagedReference<SceneObject*> deedContainer = getParent().get();

		if (deedContainer != NULL) {
			destroyObjectFromWorld(true);
		}
		generated = true;
		destroyObjectFromDatabase(true);

		player->sendSystemMessage("@pet/pet_menu:device_added"); // "A control device has been added to your datapad."
		return 0;
	}

	return DeedImplementation::handleObjectMenuSelect(player, selectedID);
}
void DroidObjectImplementation::handleChat(CreatureObject* speaker, const String& message){
	for( int i=0; i<modules.size(); i++){
		BaseDroidModuleComponent* module = modules.get(i);
		module->handlePetCommand( message, speaker );
	}
}