content: /**
   * This file is part of Aion-Lightning <aion-lightning.org>.
   *
   *  Aion-Lightning is free software: you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation, either version 3 of the License, or
   *  (at your option) any later version.
   *
   *  Aion-Lightning is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details. *
   *  You should have received a copy of the GNU General Public License
   *  along with Aion-Lightning.
   *  If not, see <http://www.gnu.org/licenses/>.
   */
  package com.aionemu.gameserver.spawnengine;
  
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  import com.aionemu.gameserver.configs.main.CustomConfig;
  import com.aionemu.gameserver.configs.main.SiegeConfig;
  import com.aionemu.gameserver.controllers.GatherableController;
  import com.aionemu.gameserver.controllers.MinionController;
  import com.aionemu.gameserver.controllers.NpcController;
  import com.aionemu.gameserver.controllers.PetController;
  import com.aionemu.gameserver.controllers.SiegeWeaponController;
  import com.aionemu.gameserver.controllers.SummonController;
  import com.aionemu.gameserver.controllers.effect.EffectController;
  import com.aionemu.gameserver.dataholders.DataManager;
  import com.aionemu.gameserver.dataholders.NpcData;
  import com.aionemu.gameserver.geoEngine.collision.CollisionIntention;
  import com.aionemu.gameserver.geoEngine.math.Vector3f;
  import com.aionemu.gameserver.model.Race;
  import com.aionemu.gameserver.model.base.BaseLocation;
  import com.aionemu.gameserver.model.gameobjects.Creature;
  import com.aionemu.gameserver.model.gameobjects.Gatherable;
  import com.aionemu.gameserver.model.gameobjects.GroupGate;
  import com.aionemu.gameserver.model.gameobjects.Homing;
  import com.aionemu.gameserver.model.gameobjects.Kisk;
  import com.aionemu.gameserver.model.gameobjects.Minion;
  import com.aionemu.gameserver.model.gameobjects.Npc;
  import com.aionemu.gameserver.model.gameobjects.NpcObjectType;
  import com.aionemu.gameserver.model.gameobjects.Pet;
  import com.aionemu.gameserver.model.gameobjects.Servant;
  import com.aionemu.gameserver.model.gameobjects.Summon;
  import com.aionemu.gameserver.model.gameobjects.SummonedHouseNpc;
  import com.aionemu.gameserver.model.gameobjects.Trap;
  import com.aionemu.gameserver.model.gameobjects.VisibleObject;
  import com.aionemu.gameserver.model.gameobjects.player.MinionCommonData;
  import com.aionemu.gameserver.model.gameobjects.player.PetCommonData;
  import com.aionemu.gameserver.model.gameobjects.player.Player;
  import com.aionemu.gameserver.model.gameobjects.siege.SiegeNpc;
  import com.aionemu.gameserver.model.gameobjects.state.CreatureState;
  import com.aionemu.gameserver.model.gameobjects.state.CreatureVisualState;
  import com.aionemu.gameserver.model.house.House;
  import com.aionemu.gameserver.model.rift.RiftLocation;
  import com.aionemu.gameserver.model.siege.SiegeLocation;
  import com.aionemu.gameserver.model.siege.SiegeRace;
  import com.aionemu.gameserver.model.templates.VisibleObjectTemplate;
  import com.aionemu.gameserver.model.templates.minion.MinionTemplate;
  import com.aionemu.gameserver.model.templates.npc.NpcTemplate;
  import com.aionemu.gameserver.model.templates.pet.PetTemplate;
  import com.aionemu.gameserver.model.templates.spawns.SpawnTemplate;
  import com.aionemu.gameserver.model.templates.spawns.basespawns.BaseSpawnTemplate;
  import com.aionemu.gameserver.model.templates.spawns.riftspawns.RiftSpawnTemplate;
  import com.aionemu.gameserver.model.templates.spawns.siegespawns.SiegeSpawnTemplate;
  import com.aionemu.gameserver.model.templates.spawns.vortexspawns.VortexSpawnTemplate;
  import com.aionemu.gameserver.model.vortex.VortexLocation;
  import com.aionemu.gameserver.network.aion.serverpackets.SM_PLAYER_STATE;
  import com.aionemu.gameserver.services.BaseService;
  import com.aionemu.gameserver.services.RiftService;
  import com.aionemu.gameserver.services.SiegeService;
  import com.aionemu.gameserver.services.SkillLearnService;
  import com.aionemu.gameserver.services.VortexService;
  import com.aionemu.gameserver.skillengine.effect.SummonOwner;
  import com.aionemu.gameserver.skillengine.model.SkillTemplate;
  import com.aionemu.gameserver.utils.MathUtil;
  import com.aionemu.gameserver.utils.PacketSendUtility;
  import com.aionemu.gameserver.utils.idfactory.IDFactory;
  import com.aionemu.gameserver.world.World;
  import com.aionemu.gameserver.world.geo.GeoService;
  import com.aionemu.gameserver.world.knownlist.CreatureAwareKnownList;
  import com.aionemu.gameserver.world.knownlist.NpcKnownList;
  import com.aionemu.gameserver.world.knownlist.PlayerAwareKnownList;
  
  /**
   * @author ATracer
   */
  public class VisibleObjectSpawner {
  
  	private static final Logger log = LoggerFactory.getLogger(VisibleObjectSpawner.class);
  
  	/**
  	 * @param spawn
  	 * @param instanceIndex
  	 * @return
  	 */
  	protected static VisibleObject spawnNpc(SpawnTemplate spawn, int instanceIndex) {
  		int objectId = spawn.getNpcId();
  		NpcTemplate npcTemplate = DataManager.NPC_DATA.getNpcTemplate(objectId);
  		if (npcTemplate == null) {
  			log.error("No template for NPC " + String.valueOf(objectId));
  			return null;
  		}
  		IDFactory iDFactory = IDFactory.getInstance();
  		Npc npc = new Npc(iDFactory.nextId(), new NpcController(), spawn, npcTemplate);
  		npc.setCreatorId(spawn.getCreatorId());
  		npc.setMasterName(spawn.getMasterName());
  		npc.setKnownlist(new NpcKnownList(npc));
  		npc.setEffectController(new EffectController(npc));
  
  		if (WalkerFormator.processClusteredNpc(npc, spawn.getWorldId(), instanceIndex)) {
  			return npc;
  		}
  
  		try {
  			SpawnEngine.bringIntoWorld(npc, spawn, instanceIndex);
  		}
  		catch (Exception ex) {
  			log.error("Error during spawn of npc {}, world {}, x-y {}-{}", new Object[] { npcTemplate.getTemplateId(), spawn.getWorldId(), spawn.getX(), spawn.getY() });
  			log.error("Npc {} will be despawned", npcTemplate.getTemplateId(), ex);
  			World.getInstance().despawn(npc);
  		}
  		return npc;
  	}
  
  	public static SummonedHouseNpc spawnHouseNpc(SpawnTemplate spawn, int instanceIndex, House creator, String masterName) {
  		int npcId = spawn.getNpcId();
  		NpcTemplate template = DataManager.NPC_DATA.getNpcTemplate(npcId);
  		SummonedHouseNpc npc = new SummonedHouseNpc(IDFactory.getInstance().nextId(), new NpcController(), spawn, template, creator, masterName);
  		npc.setKnownlist(new PlayerAwareKnownList(npc));
  		npc.setEffectController(new EffectController(npc));
  		SpawnEngine.bringIntoWorld(npc, spawn, instanceIndex);
  		return npc;
  	}
  
  	protected static VisibleObject spawnBaseNpc(BaseSpawnTemplate spawn, int instanceIndex) {
  		int objectId = spawn.getNpcId();
  		NpcTemplate npcTemplate = DataManager.NPC_DATA.getNpcTemplate(objectId);
  
  		if (npcTemplate == null) {
  			log.error("No template for Base NPC " + String.valueOf(objectId));
  			return null;
  		}
  
  		boolean isActive = BaseService.getInstance().isActive(spawn.getId());
  		if (!isActive) {
  			return null;
  		}
  
  		// Chk owner race for non handled spawn
  		BaseLocation base = BaseService.getInstance().getBaseLocation(spawn.getId());
  		if (spawn.getHandlerType() == null && !spawn.getBaseRace().equals(base.getRace())) {
  			return null;
  		}
  
  		IDFactory iDFactory = IDFactory.getInstance();
  		Npc npc = new Npc(iDFactory.nextId(), new NpcController(), spawn, npcTemplate);
  
  		npc.setKnownlist(new NpcKnownList(npc));
  		npc.setEffectController(new EffectController(npc));
  		SpawnEngine.bringIntoWorld(npc, spawn, instanceIndex);
  
  		return npc;
  	}
  
  	protected static VisibleObject spawnRiftNpc(RiftSpawnTemplate spawn, int instanceIndex) {
  		if (!CustomConfig.RIFT_ENABLED) {
  			return null;
  		}
  
  		int objectId = spawn.getNpcId();
  		NpcTemplate npcTemplate = DataManager.NPC_DATA.getNpcTemplate(objectId);
  		if (npcTemplate == null) {
  			log.error("No template for NPC " + String.valueOf(objectId));
  			return null;
  		}
  		IDFactory iDFactory = IDFactory.getInstance();
  		Npc npc;
  
  		int spawnId = spawn.getId();
  		RiftLocation loc = RiftService.getInstance().getRiftLocation(spawnId);
  		if (loc.isOpened() && spawnId == loc.getId()) {
  			npc = new Npc(iDFactory.nextId(), new NpcController(), spawn, npcTemplate);
  			npc.setKnownlist(new NpcKnownList(npc));
  		}
  		else {
  			return null;
  		}
  		npc.setEffectController(new EffectController(npc));
  		SpawnEngine.bringIntoWorld(npc, spawn, instanceIndex);
  		return npc;
  	}
  
  	/**
  	 * @param spawn
  	 * @param instanceIndex
  	 * @return
  	 */
  	protected static VisibleObject spawnSiegeNpc(SiegeSpawnTemplate spawn, int instanceIndex) {
  		if (!SiegeConfig.SIEGE_ENABLED) {
  			return null;
  		}
  
  		int objectId = spawn.getNpcId();
  		NpcTemplate npcTemplate = DataManager.NPC_DATA.getNpcTemplate(objectId);
  		if (npcTemplate == null) {
  			log.error("No template for NPC " + String.valueOf(objectId));
  			return null;
  		}
  		IDFactory iDFactory = IDFactory.getInstance();
  		Npc npc = null;
  
  		int spawnSiegeId = spawn.getSiegeId();
  		SiegeLocation loc = SiegeService.getInstance().getSiegeLocation(spawnSiegeId);
  		if ((spawn.isPeace() || loc.isVulnerable()) && spawnSiegeId == loc.getLocationId() && spawn.getSiegeRace() == loc.getRace()) {
  			// default: GUARD
  			npc = new SiegeNpc(iDFactory.nextId(), new NpcController(), spawn, npcTemplate);
  			npc.setKnownlist(new NpcKnownList(npc));
  		}
  		else if (spawn.isAssault() && loc.isVulnerable() && spawn.getSiegeRace().equals(SiegeRace.BALAUR)) {
  			// attakers
  			npc = new SiegeNpc(iDFactory.nextId(), new NpcController(), spawn, npcTemplate);
  			npc.setKnownlist(new NpcKnownList(npc));
  		}
  		else {
  			return null;
  		}
  		npc.setEffectController(new EffectController(npc));
  		SpawnEngine.bringIntoWorld(npc, spawn, instanceIndex);
  		return npc;
  	}
  
  	protected static VisibleObject spawnInvasionNpc(VortexSpawnTemplate spawn, int instanceIndex) {
  		if (!CustomConfig.VORTEX_ENABLED) {
  			return null;
  		}
  
  		int objectId = spawn.getNpcId();
  		NpcTemplate npcTemplate = DataManager.NPC_DATA.getNpcTemplate(objectId);
  		if (npcTemplate == null) {
  			log.error("No template for NPC " + String.valueOf(objectId));
  			return null;
  		}
  		IDFactory iDFactory = IDFactory.getInstance();
  		Npc npc;
  
  		int spawnId = spawn.getId();
  		VortexLocation loc = VortexService.getInstance().getVortexLocation(spawnId);
  		if (loc.isActive() && spawnId == loc.getId() && spawn.isInvasion()) {
  			npc = new Npc(iDFactory.nextId(), new NpcController(), spawn, npcTemplate);
  			npc.setKnownlist(new NpcKnownList(npc));
  		}
  		else if (!loc.isActive() && spawnId == loc.getId() && spawn.isPeace()) {
  			npc = new Npc(iDFactory.nextId(), new NpcController(), spawn, npcTemplate);
  			npc.setKnownlist(new NpcKnownList(npc));
  		}
  		else {
  			return null;
  		}
  		npc.setEffectController(new EffectController(npc));
  		SpawnEngine.bringIntoWorld(npc, spawn, instanceIndex);
  		return npc;
  	}
  
  	/**
  	 * @param spawn
  	 * @param instanceIndex
  	 * @return
  	 */
  	protected static VisibleObject spawnGatherable(SpawnTemplate spawn, int instanceIndex) {
  		int objectId = spawn.getNpcId();
  		VisibleObjectTemplate template = DataManager.GATHERABLE_DATA.getGatherableTemplate(objectId);
  		Gatherable gatherable = new Gatherable(spawn, template, IDFactory.getInstance().nextId(), new GatherableController());
  		gatherable.setKnownlist(new PlayerAwareKnownList(gatherable));
  		SpawnEngine.bringIntoWorld(gatherable, spawn, instanceIndex);
  		return gatherable;
  	}
  
  	/**
  	 * @param spawn
  	 * @param instanceIndex
  	 * @param creator
  	 * @return
  	 */
  	public static Trap spawnTrap(SpawnTemplate spawn, int instanceIndex, Creature creator, int skillId) {
  		int objectId = spawn.getNpcId();
  		NpcTemplate npcTemplate = DataManager.NPC_DATA.getNpcTemplate(objectId);
  		Trap trap = new Trap(IDFactory.getInstance().nextId(), new NpcController(), spawn, npcTemplate);
  		trap.setKnownlist(new NpcKnownList(trap));
  		trap.setEffectController(new EffectController(trap));
  		trap.setCreator(creator);
  		trap.getSkillList().addSkill(trap, skillId, 1);
  		if (objectId != 749300 || objectId != 749300) {
  			trap.setVisualState(CreatureVisualState.HIDE1);
  		}
  		try {
  			trap.getAi2().onCustomEvent(1, DataManager.SKILL_DATA.getSkillTemplate(skillId).getProperties().getEffectiveRange());
  		}
  		catch (Exception e) {
  			trap.getAi2().onCustomEvent(1, creator);
  		}
  		SpawnEngine.bringIntoWorld(trap, spawn, instanceIndex);
  		PacketSendUtility.broadcastPacket(trap, new SM_PLAYER_STATE(trap));
  		return trap;
  	}
  
  	/**
  	 * @param spawn
  	 * @param instanceIndex
  	 * @param creator
  	 * @return
  	 */
  	public static GroupGate spawnGroupGate(SpawnTemplate spawn, int instanceIndex, Creature creator) {
  		int objectId = spawn.getNpcId();
  		NpcTemplate npcTemplate = DataManager.NPC_DATA.getNpcTemplate(objectId);
  		GroupGate groupgate = new GroupGate(IDFactory.getInstance().nextId(), new NpcController(), spawn, npcTemplate);
  		groupgate.setKnownlist(new PlayerAwareKnownList(groupgate));
  		groupgate.setEffectController(new EffectController(groupgate));
  		groupgate.setCreator(creator);
  		SpawnEngine.bringIntoWorld(groupgate, spawn, instanceIndex);
  		return groupgate;
  	}
  
  	/**
  	 * @param spawn
  	 * @param instanceIndex
  	 * @param creator
  	 * @return
  	 */
  	public static Kisk spawnKisk(SpawnTemplate spawn, int instanceIndex, Player creator) {
  		int npcId = spawn.getNpcId();
  		NpcTemplate template = DataManager.NPC_DATA.getNpcTemplate(npcId);
  		Kisk kisk = new Kisk(IDFactory.getInstance().nextId(), new NpcController(), spawn, template, creator);
  		kisk.setKnownlist(new PlayerAwareKnownList(kisk));
  		kisk.setCreator(creator);
  		kisk.setEffectController(new EffectController(kisk));
  		SpawnEngine.bringIntoWorld(kisk, spawn, instanceIndex);
  		return kisk;
  	}
  
  	/**
  	 * @param owner
  	 * @author ViAl Spawns postman for express mail
  	 */
  	public static Npc spawnPostman(final Player owner) {
  		int npcId = owner.getRace() == Race.ELYOS ? 798100 : 798101;
  		NpcData npcData = DataManager.NPC_DATA;
  		NpcTemplate template = npcData.getNpcTemplate(npcId);
  		IDFactory iDFactory = IDFactory.getInstance();
  		int worldId = owner.getWorldId();
  		int instanceId = owner.getInstanceId();
  		double radian = Math.toRadians(MathUtil.convertHeadingToDegree(owner.getHeading()));
  		Vector3f pos = GeoService.getInstance().getClosestCollision(owner, owner.getX() + (float) (Math.cos(radian) * 5), owner.getY() + (float) (Math.sin(radian) * 5), owner.getZ(), false, CollisionIntention.PHYSICAL.getId());
  		SpawnTemplate spawn = SpawnEngine.addNewSingleTimeSpawn(worldId, npcId, pos.getX(), pos.getY(), pos.getZ(), (byte) 0);
  		final Npc postman = new Npc(iDFactory.nextId(), new NpcController(), spawn, template);
  		postman.setKnownlist(new PlayerAwareKnownList(postman));
  		postman.setEffectController(new EffectController(postman));
  		postman.getAi2().onCustomEvent(1, owner);
  		SpawnEngine.bringIntoWorld(postman, spawn, instanceId);
  		owner.setPostman(postman);
  		return postman;
  	}
  
  	/**
  	 * @param summonOwner
  	 */
  	public static Npc spawnFunctionalNpc(final Player owner, int npcId, SummonOwner summonOwner) {
  		NpcData npcData = DataManager.NPC_DATA;
  		NpcTemplate template = npcData.getNpcTemplate(npcId);
  		IDFactory iDFactory = IDFactory.getInstance();
  		int worldId = owner.getWorldId();
  		int instanceId = owner.getInstanceId();
  		double radian = Math.toRadians(MathUtil.convertHeadingToDegree(owner.getHeading()));
  		Vector3f pos = GeoService.getInstance().getClosestCollision(owner, owner.getX() + (float) (Math.cos(radian) * 1), owner.getY() + (float) (Math.sin(radian) * 1), owner.getZ(), false, CollisionIntention.PHYSICAL.getId());
  		SpawnTemplate spawn = SpawnEngine.addNewSingleTimeSpawn(worldId, npcId, pos.getX(), pos.getY(), pos.getZ(), (byte) 0);
  		final Npc functionalNpc = new Npc(iDFactory.nextId(), new NpcController(), spawn, template);
  		functionalNpc.setKnownlist(new PlayerAwareKnownList(functionalNpc));
  		functionalNpc.setEffectController(new EffectController(functionalNpc));
  		functionalNpc.getAi2().onCustomEvent(1, owner);
  		SpawnEngine.bringIntoWorld(functionalNpc, spawn, instanceId);
  		return functionalNpc;
  	}
  
  	/**
  	 * @param spawn
  	 * @param instanceIndex
  	 * @param creator
  	 * @param skillId
  	 * @param level
  	 * @return
  	 */
  	public static Servant spawnServant(SpawnTemplate spawn, int instanceIndex, Creature creator, int skillId, int level, NpcObjectType objectType) {
  		int objectId = spawn.getNpcId();
  		NpcTemplate npcTemplate = DataManager.NPC_DATA.getNpcTemplate(objectId);
  		int creatureLevel = creator.getLevel();
  		level = SkillLearnService.getSkillLearnLevel(skillId, creatureLevel, level);
  		byte servantLevel = (byte) SkillLearnService.getSkillMinLevel(skillId, creatureLevel, level);
  
  		Servant servant = new Servant(IDFactory.getInstance().nextId(), new NpcController(), spawn, npcTemplate, servantLevel);
  		servant.setKnownlist(new NpcKnownList(servant));
  		servant.setEffectController(new EffectController(servant));
  		servant.setCreator(creator);
  		servant.setNpcObjectType(objectType);
  		servant.getSkillList().addSkill(servant, skillId, 1);
  		SpawnEngine.bringIntoWorld(servant, spawn, instanceIndex);
  		SkillTemplate st = DataManager.SKILL_DATA.getSkillTemplate(skillId);
  		if (st.getStartconditions() != null && st.getHpCondition() != null) {
  			int hp = (st.getHpCondition().getHpValue() * 3);
  			servant.getLifeStats().setCurrentHp(hp);
  		}
  		return servant;
  	}
  
  	/**
  	 * @param spawn
  	 * @param instanceIndex
  	 * @param creator
  	 * @param skillId
  	 * @param level
  	 * @return
  	 */
  	public static Servant spawnEnemyServant(SpawnTemplate spawn, int instanceIndex, Creature creator, byte servantLvl) {
  		int objectId = spawn.getNpcId();
  		NpcTemplate npcTemplate = DataManager.NPC_DATA.getNpcTemplate(objectId);
  		Servant servant = new Servant(IDFactory.getInstance().nextId(), new NpcController(), spawn, npcTemplate, servantLvl);
  		servant.setKnownlist(new NpcKnownList(servant));
  		servant.setEffectController(new EffectController(servant));
  		servant.setCreator(creator);
  		servant.setNpcObjectType(NpcObjectType.SERVANT);
  		SpawnEngine.bringIntoWorld(servant, spawn, instanceIndex);
  		return servant;
  	}
  
  	/**
  	 * @param spawn
  	 * @param instanceIndex
  	 * @param creator
  	 * @param attackCount
  	 * @return
  	 */
  	public static Homing spawnHoming(SpawnTemplate spawn, int instanceIndex, Creature creator, int attackCount, int skillId, int level, int homingSkillId) {
  		int objectId = spawn.getNpcId();
  		NpcTemplate npcTemplate = DataManager.NPC_DATA.getNpcTemplate(objectId);
  		int creatureLevel = creator.getLevel();
  		level = SkillLearnService.getSkillLearnLevel(skillId, creatureLevel, level);
  		byte homingLevel = (byte) SkillLearnService.getSkillMinLevel(skillId, creatureLevel, level);
  		Homing homing = new Homing(IDFactory.getInstance().nextId(), new NpcController(), spawn, npcTemplate, homingLevel, skillId);
  		homing.setState(CreatureState.WEAPON_EQUIPPED);
  		homing.setKnownlist(new NpcKnownList(homing));
  		homing.setEffectController(new EffectController(homing));
  		homing.setCreator(creator);
  		if (homingSkillId != 0) {
  			homing.getSkillList().addSkill(homing, homingSkillId, 1);
  		}
  		homing.setActiveSkillId(homingSkillId);
  		homing.setAttackCount(attackCount);
  		SpawnEngine.bringIntoWorld(homing, spawn, instanceIndex);
  		return homing;
  	}
  
  	/**
  	 * @param creator
  	 * @param npcId
  	 * @param skillLevel
  	 * @return
  	 */
  	public static Summon spawnSummon(Player creator, int npcId, int skillId, int skillLevel, int time) {
  		float x = creator.getX() - 2;
  		float y = creator.getY();
  		float z = creator.getZ();
  		byte heading = creator.getHeading();
  		int worldId = creator.getWorldId();
  		int instanceId = creator.getInstanceId();
  
  		SpawnTemplate spawn = SpawnEngine.createSpawnTemplate(worldId, npcId, x, y, z, heading);
  		NpcTemplate npcTemplate = DataManager.NPC_DATA.getNpcTemplate(npcId);
  
  		skillLevel = SkillLearnService.getSkillLearnLevel(skillId, creator.getCommonData().getLevel(), skillLevel);
  		byte level = (byte) SkillLearnService.getSkillMinLevel(skillId, creator.getCommonData().getLevel(), skillLevel);
  		boolean isSiegeWeapon = npcTemplate.getAi().equals("siege_weapon");
  		Summon summon = new Summon(IDFactory.getInstance().nextId(), isSiegeWeapon ? new SiegeWeaponController(npcId) : new SummonController(), spawn, npcTemplate, isSiegeWeapon ? npcTemplate.getLevel() : level, time);
  		summon.setKnownlist(new CreatureAwareKnownList(summon));
  		summon.setEffectController(new EffectController(summon));
  		summon.setMaster(creator);
  		summon.getLifeStats().synchronizeWithMaxStats();
  
  		SpawnEngine.bringIntoWorld(summon, spawn, instanceId);
  		return summon;
  	}
  
  	/**
  	 * @param player
  	 * @param petId
  	 * @return
  	 */
  	public static Pet spawnPet(Player player, int petId) {
  
  		PetCommonData petCommonData = player.getPetList().getPet(petId);
  		if (petCommonData == null) {
  			return null;
  		}
  		PetTemplate petTemplate = DataManager.PET_DATA.getPetTemplate(petId);
  		if (petTemplate == null) {
  			return null;
  		}
  
  		PetController controller = new PetController();
  		Pet pet = new Pet(petTemplate, controller, petCommonData, player);
  		pet.setKnownlist(new PlayerAwareKnownList(pet));
  		player.setToyPet(pet);
  
  		float x = player.getX() - 2;
  		float y = player.getY();
  		float z = player.getZ();
  		byte heading = player.getHeading();
  		int worldId = player.getWorldId();
  		int instanceId = player.getInstanceId();
  		SpawnTemplate spawn = SpawnEngine.createSpawnTemplate(worldId, petId, x, y, z, heading);
  
  		SpawnEngine.bringIntoWorld(pet, spawn, instanceId);
  		return pet;
  	}
  
  	/**
  	 * @param player
  	 * @param minionId
  	 * @return
  	 */
      public static Minion spawnMinion(Player player, int minionObjId, int minionId) {
  
          MinionCommonData mcd = player.getMinionList().getMinion(minionId);
          if (mcd == null) {
              return null;
          }
          MinionTemplate mt = DataManager.MINION_DATA.getMinionTemplate(minionObjId);
          if (mt == null) {
              return null;
          }
  
          MinionController controller = new MinionController();
          Minion minion = new Minion(mt, controller, mcd, player);
          minion.setKnownlist(new PlayerAwareKnownList(minion));
          player.setMinion(minion);
  
          float x = player.getX();
          float y = player.getY();
          float z = player.getZ();
          byte heading = player.getHeading();
          int worldId = player.getWorldId();
          int instanceId = player.getInstanceId();
          SpawnTemplate spawn = SpawnEngine.createSpawnTemplate(worldId, minionObjId, x, y, z, heading);
  
          SpawnEngine.bringIntoWorld(minion, spawn, instanceId);
          return minion;
      }
  }
  