Jump to content

Salty Mike

Members
  • Posts

    164
  • Credits

  • Joined

  • Last visited

  • Days Won

    15
  • Feedback

    0%

Posts posted by Salty Mike

  1. Greetings, dear MXCheaters!

     I spent a few hours today attempting to take SysTextures *.utx files from new chornicles (think Icons, user interface, etc) and make them usable with H5 client.
    It turns out, the process is as easy as it can be! This method has been tested with H5 client but could be working on other chronicles as well. Furthermore, it might work for other files as well, I just haven't tested it.

     Tools/programmes needed:
     1 - L2Tool (acmi)
     2- mxencdec

    disclaimer: clicking on the names of the tools will send you to download them from my personal google drive stash as the download links of the original shares might be broken.

    Now to the fun part.

     STEP 1:  You download the files and extract them in a folder of your choice. I tend to use folders with directories (ex: D:\Client_Edit\UTX\).

     STEP 2:  Copy the desired *.UTX file from the new chronicle and place it in the folder where you extracted the tools like so:

    image.png.4001791622bff83f358e9df15328bc1e.png
     

    STEP 3:
    - Open the L2Tool_acmi folder and run "starter.bat" and click on the button with two dots on the UTX row (shown as 1 on the screenshot below).
    - Open the desired UTX file. 
    - Click on the "L2-> UnrealED" button of L2Tool (shown as 2 on the screenshot) and then save the file in the mxencdec folder.

    image.png.cbcdef613abb4e8e7f0e64e875880965.png


    STEP 4:
    - Open mxencdec folder and DRAG AND DROP the UTX file on top of the MXENCDEC.exe and wait for the command prompt window to show you SUCCESS like so:

    image.png.42fa373773fa793a3828292a07d58e0b.png


    STEP 5: Copy the newly encrypted file from the mxencdec folder to your Lineage 2's SysTextures folder and you are done.


    Credits go to Matrix (EDL Team) for mxencdec and to Aleksey Sazonov (acmi) for the L2Tool.

    • Like 3
    • Upvote 1
  2. 11 hours ago, wongerlt said:

    seems problem server side. 

    It is like this on every server I tested, at least 5. Also, it cannot be server sided. The server only sends the operational code of what has to be displayed, in this case, which adena message the client should display. This is how every server pack I know of operates.

    21 hours ago, MonokiniSix said:

      

    cuz some my shitcode

     

     

    Where do I find (place) the code you just shared? I do not have any interface-editing software. Does anybody have that issue fixed, and if so, would they be willing to share the fixed version?

  3. Thank you all! 
     I believe the guide Pamela shared looks good if I want it to work on all armors. However, I want the abnormal effect to be persistent and only on certain sets. In my case, I have all B-grade and above sets up to Elegia until Stage 5. And I want to add this bonus "aura" (in my case a skill) only to the last stage of all sets.

    Think of it as the hero aura, I want something similar but only visible when a full set Stage 5 is equipped. :)
    Please, throw some more ideas!
     

     

  4. Greetings, y'all beautiful people!
     
     I've been playing around with armors recently and I've had this great idea which I can't implement for some reason. 
     First things first. 
     I've made custom sets with stats and set bonuses etc. Now, the problem I'm facing is that I'd like to add something like lets say fire that surrounds them when the character wears the complete set, something like an aura of some kind. I've found this BEAUTIFULLY looking skill that is not used in the game but it is an active skill. I've made the skill passive with 2 seconds cooldown andtried TARGET_NONE/SELF/AURA. None of which helped. I couldn't make it so that it will show the visual effects. I've gone through most of the passive skills with extra effects that I could think of in order to figure it out but sadly I could not.
     So, what do You think? Is there a way to make an active skill act like a passive with persistent visual effects? Do you think something like this is possible and if so, which parts of the xml should be responsible for the persistent visual effect? Also, Ive tried to call both the skill andthe effect as part of my set's bonus. failed both times. :/


     (This is a repost since my other topic was in the wrong section).

  5. Greetings, y'all beautiful people!

     I've been playing around with armors recently and I've had this great idea which I can't implement for some reason. 
     First things first. 
     I've made custom sets with stats and set bonuses etc. Now, the problem I'm facing is that I'd like to add something like lets say fire that surrounds them when the character wears the complete set, something like an aura of some kind. I've found this BEAUTIFULLY looking skill that is not used in the game but it is an active skill. I've made the skill passive with 2 seconds cooldown and tried TARGET_NONE/SELF/AURA. None of which helped. I couldn't make it so that it will show the visual effects. I've gone through most of the passive skills with extra effects and I could think of in order to figure it out but sadly I could not.
     So, what do You think? Is there a way to make an active skill act like a passive with persistent visual effects? Do you think something like this is possible and if so, which parts of the xml should be responsible for the persistent visual effect? Also, Ive tried to call both the skill and the effect as part of my set's bonus. failed both times. :/

  6. Greetings,
     I've been messing around with the client's content for a while now and I can't find a way to implement a transparent *.tga file.
     The transparent tga file is supposed to be like a border, identical to the PVP border or the border of Common Items. However, it has a white background when in focus and when out of focus, it shows normally. Here are two screenshots:
     

    Spoiler

    onFocus_1.png.9b497bf511dda7a76adb2dadcaae2c73.png
    This is on focus.

     
     

    The link below is out of focus.
    https://imgur.com/a/7zL2Azy



    What am I doing wrong and what am I missing?
     I've added a transparent alpha channel to the icon in photoshop and when I import the *.tga into the *.utx file I'm using DTX3 compressing. I'm also using a separate (self-made) Icon2.utx file.

  7. Greetings,
     I'm looking for an experienced developer who could help me with several features for my yet-to-come Lineage 2 server on a pay-per-code basis. The server files are based on FandC build from 3 years ago with additional work being done on them, so many of the free codes in this community are useless or need heavy reworking. I am not in any sort of hurry but I expect the codes to be complete in a timely manner.

  8. I have a problem. They just refuse to spawn automatically...


    "INFO Spawning phantom Takeshi[268484832] through spawner. Cur/Max 0/35000"

    Could someone tell me what's wrong? I think the problem is on row 540. It calls _loc but this location hasnt been set nor linked to an outside source... i think.

    Here is the script:

    Spoiler
    
    package wp.gameserver.model;
    
    import java.io.File;
    import java.io.IOException;
    import java.nio.charset.StandardCharsets;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    import java.util.concurrent.ScheduledFuture;
    
    import org.apache.log4j.Logger;
    
    import com.google.common.io.Files;
    
    import wp.commons.util.Rnd;
    import wp.gameserver.Config;
    import wp.gameserver.ThreadPoolManager;
    import wp.gameserver.ai.PhantomPlayerAI;
    import wp.gameserver.dao.CharacterDAO;
    import wp.gameserver.dao.PhantomsDAO;
    import wp.gameserver.data.xml.holder.PhantomTemplateData;
    import wp.gameserver.data.xml.holder.SkillAcquireHolder;
    import wp.gameserver.instancemanager.CursedWeaponsManager;
    import wp.gameserver.model.base.AcquireType;
    import wp.gameserver.model.base.ClassId;
    import wp.gameserver.model.base.Experience;
    import wp.gameserver.model.base.InvisibleType;
    import wp.gameserver.model.base.RestartType;
    import wp.gameserver.model.entity.L2Event;
    import wp.gameserver.model.items.ItemInstance;
    import wp.gameserver.model.phantom.PhantomTemplate;
    import wp.gameserver.tables.SkillTable;
    import wp.gameserver.templates.item.CreateItem;
    import wp.gameserver.templates.item.ItemTemplate;
    import wp.gameserver.utils.Location;
    import wp.gameserver.utils.Util;
    
    public class PhantomPlayers
    {
    	private static final Logger _log = Logger.getLogger(PhantomPlayers.class.getName());
    	private static List<Integer> _phantoms;
    	private static List<String> _phantomNames;
    	private static List<PhantomSpawner> _phantomSpawners;
    	
    	public static void init()
    	{
    		_log.info("Loading phantom players...");
    		
    		try
    		{
    			File file = Config.findNonCustomResource("config/phantom/player_names.txt");
    			_phantomNames = Files.readLines(file, StandardCharsets.UTF_8);
    		}
    		catch (IOException e)
    		{
    			_log.warn("PhantomPlayers: Unable to load phantom player names.", e);
    			_phantomNames = Collections.emptyList();
    		}
    		
    		_phantoms = new ArrayList<>(PhantomsDAO.getInstance().selectAll().keySet());
    		_phantomSpawners = new ArrayList<>();
    		PhantomSpawner spawner = new PhantomSpawner();
    		ThreadPoolManager.getInstance().execute(spawner);
    		_phantomSpawners.add(spawner);
    		
    		_log.info("Loaded " + _phantoms.size() + " phantom players from database with a maximum of " + Config.PHANTOM_MAX_PLAYERS + " phantoms.");
    		_log.info("Loaded " + _phantomNames.size() + " possible phantom names.");
    		_log.info("Scheduled spawner with " + (Config.PHANTOM_SPAWN_DELAY / 1000) + " seconds delay.");
    	}
    	
    	public static Player createNewPhantom()
    	{
    		if (_phantomNames == null)
    		{
    			return null;
    		}
    		
    		for (int i = 0; i < 25; i++) // 25 tries to make a phantom player. Enough tries to avoid name duplicate and other stuff.
    		{
    			String name = Rnd.get(_phantomNames);
    			Player player = createNewPhantom(name);
    			if (player != null)
    			{
    				return player;
    			}
    		}
    		
    		return null;
    	}
    	
    	public static Player createNewPhantom(String name)
    	{
    		return createNewPhantom(name, PhantomTemplateData.getInstance().getRandomTemplate());
    	}
    	
    	public static Player createNewPhantom(String name, PhantomTemplate template)
    	{
    		boolean female = Rnd.nextBoolean();
    		int hairStyle = Rnd.get(3);
    		int hairColor = Rnd.get(3);
    		int face = Rnd.get(3);
    		return createNewPhantom(name, template, female, hairStyle, hairColor, face);
    	}
    	
    	public static Player createNewPhantom(String name, PhantomTemplate template, boolean female, int hairStyle, int hairColor, int face)
    	{
    		try
    		{
    			if (!Util.isMatchingRegexp(name, Config.CNAME_TEMPLATE))
    			{
    				return null;
    			}
    			if ((CharacterDAO.getInstance().getObjectIdByName(name) > 0) || Util.contains(Config.FORBIDDEN_CHAR_NAMES, name))
    			{
    				return null;
    			}
    			
    			if (template == null)
    			{
    				return null;
    			}
    			
    			final ClassId classId = ClassId.VALUES[template.getClassId()];
    			Player newChar = Player.create(classId.getId(), female ? 1 : 0, Config.PHANTOM_ACCOUNT, name, hairStyle, hairColor, face);
    			if (newChar == null)
    			{
    				return null;
    			}
    			
    			newChar.setCreateTime(System.currentTimeMillis());
    			try
    			{
    				switch (classId.getLevel())
    				{
    					case 2:
    						newChar.addExpAndSp(Experience.getExpForLevel(20), 835863);
    						break;
    					case 3:
    						newChar.addExpAndSp(Experience.getExpForLevel(40), 15422930);
    						break;
    					case 4:
    						newChar.addExpAndSp(Experience.getExpForLevel(76), 931275829);
    						break;
    				}
    			}
    			catch (ArrayIndexOutOfBoundsException | NullPointerException e)
    			{
    				_log.warn("PhantomPlayers: Failed to set appropreate level for classId " + classId, e);
    			}
    			
    			Player.restoreCharSubClasses(newChar);
    			
    			if (Config.STARTING_ADENA > 0)
    			{
    				newChar.addAdena(Config.STARTING_ADENA);
    			}
    			
    			if (Config.STARTING_LVL > newChar.getLevel())
    			{
    				newChar.addExpAndSp(Experience.LEVEL[Config.STARTING_LVL] - newChar.getExp(), 0, 0, 0, false, false);
    			}
    			
    			if (Config.SPAWN_CHAR)
    			{
    				newChar.teleToLocation(Config.SPAWN_X, Config.SPAWN_Y, Config.SPAWN_Z);
    			}
    			else
    			{
    				newChar.setLoc(Rnd.get(newChar.getTemplate().getSpawnLocs()));
    			}
    			
    			if (Config.CHAR_TITLE)
    			{
    				newChar.setTitle(Config.ADD_CHAR_TITLE);
    			}
    			else
    			{
    				newChar.setTitle("");
    			}
    			
    			for (CreateItem i : newChar.getTemplate().getItems())
    			{
    				ItemInstance item = new ItemInstance(i.getItemId());
    				newChar.getInventory().addItem(item);
    				
    				if (i.isEquipable() && item.isEquipable() && ((newChar.getActiveWeaponItem() == null) || (item.getTemplate().getType2() != ItemTemplate.TYPE2_WEAPON)))
    				{
    					newChar.getInventory().equipItem(item);
    				}
    			}
    			
    			if (Config.ALLOW_START_ITEMS)
    			{
    				if (classId.isMage())
    				{
    					for (int i = 0; i < Config.START_ITEMS_MAGE.length; i++)
    					{
    						ItemInstance item = new ItemInstance(Config.START_ITEMS_MAGE[i]);
    						item.setCount(Config.START_ITEMS_MAGE_COUNT[i]);
    						newChar.getInventory().addItem(item);
    					}
    					
    					if (Config.BIND_NEWBIE_START_ITEMS_TO_CHAR)
    					{
    						for (int i = 0; i < Config.START_ITEMS_MAGE_BIND_TO_CHAR.length; i++)
    						{
    							ItemInstance item = new ItemInstance(Config.START_ITEMS_MAGE_BIND_TO_CHAR[i]);
    							item.setCount(Config.START_ITEMS_MAGE_COUNT_BIND_TO_CHAR[i]);
    							item.setCustomFlags(ItemInstance.FLAG_NO_CRYSTALLIZE | ItemInstance.FLAG_NO_TRADE | ItemInstance.FLAG_NO_TRANSFER | ItemInstance.FLAG_NO_DROP | ItemInstance.FLAG_NO_SELL);
    							newChar.getInventory().addItem(item);
    						}
    					}
    				}
    				else
    				{
    					for (int i = 0; i < Config.START_ITEMS_FITHER.length; i++)
    					{
    						ItemInstance item = new ItemInstance(Config.START_ITEMS_FITHER[i]);
    						item.setCount(Config.START_ITEMS_FITHER_COUNT[i]);
    						newChar.getInventory().addItem(item);
    					}
    					
    					if (Config.BIND_NEWBIE_START_ITEMS_TO_CHAR)
    					{
    						for (int i = 0; i < Config.START_ITEMS_FITHER_BIND_TO_CHAR.length; i++)
    						{
    							ItemInstance item = new ItemInstance(Config.START_ITEMS_FITHER_BIND_TO_CHAR[i]);
    							item.setCount(Config.START_ITEMS_FITHER_COUNT_BIND_TO_CHAR[i]);
    							item.setCustomFlags(ItemInstance.FLAG_NO_CRYSTALLIZE | ItemInstance.FLAG_NO_TRADE | ItemInstance.FLAG_NO_TRANSFER | ItemInstance.FLAG_NO_DROP | ItemInstance.FLAG_NO_SELL);
    							newChar.getInventory().addItem(item);
    						}
    					}
    				}
    			}
    			
    			for (SkillLearn skill : SkillAcquireHolder.getInstance().getAvailableSkills(newChar, AcquireType.NORMAL))
    			{
    				newChar.addSkill(SkillTable.getInstance().getInfo(skill.getId(), skill.getLevel()), true);
    			}
    			
    			newChar.setCurrentHpMp(newChar.getMaxHp(), newChar.getMaxMp());
    			newChar.setCurrentCp(0); // retail
    			newChar.setOnlineStatus(true);
    			
    			newChar.store(true);
    			newChar.getInventory().store();
    			newChar.deleteMe();
    			
    			PhantomsDAO.getInstance().insert(newChar.getObjectId(), template);
    			
    			_phantoms.add(newChar.getObjectId());
    			return newChar;
    		}
    		catch (Exception e)
    		{
    			e.printStackTrace();
    		}
    		
    		return null;
    	}
    	
    	public static PhantomSpawner spawnPhantoms(int numSpawns, long delayInMilis, boolean generateNewPhantoms, Location loc)
    	{
    		PhantomSpawner spawner = new PhantomSpawner(numSpawns, delayInMilis, generateNewPhantoms).setLocation(loc);
    		ThreadPoolManager.getInstance().execute(spawner);
    		_phantomSpawners.add(spawner);
    		return spawner;
    	}
    	
    	/**
    	 * Gets the next unspawned phantom.
    	 * @return random free (unspawned) phantom object id or -1 if all are taken.
    	 */
    	private static int getUnspawnedPhantomObjId()
    	{
    		List<Integer> _unspawnedPhantoms = new ArrayList<>();
    		_unspawnedPhantoms.addAll(_phantoms);
    		
    		for (Player player : L2ObjectsStorage.getAllPlayersForIterate())
    		{
    			if (_unspawnedPhantoms.contains(Integer.valueOf(player.getObjectId())))
    			{
    				_unspawnedPhantoms.remove(Integer.valueOf(player.getObjectId()));
    			}
    		}
    		
    		if (!_unspawnedPhantoms.isEmpty())
    		{
    			return Rnd.get(_unspawnedPhantoms);
    		}
    		
    		return -1;
    	}
    	
    	public static class PhantomSpawn implements Runnable
    	{
    		private final int _objId;
    		private Location _loc;
    		
    		public PhantomSpawn()
    		{
    			_objId = getUnspawnedPhantomObjId();
    		}
    		
    		public PhantomSpawn(int objId)
    		{
    			_objId = objId;
    			_loc = null;
    		}
    		
    		public PhantomSpawn setLocation(Location loc)
    		{
    			_loc = new Location(loc.getX() + Rnd.get(200), loc.getY() + Rnd.get(200), loc.getZ());
    			return this;
    		}
    		
    		@Override
    		public void run()
    		{
    			
    			Player player = World.getPlayer(_objId);
    			if (player == null)
    			{
    				player = Player.restore(_objId);
    			}
    			if (player == null)
    			{
    				return;
    			}
    			
    			player.setOfflineMode(false);
    			player.setIsOnline(true);
    			player.updateOnlineStatus();
    			
    			player.setOnlineStatus(true);
    			player.setInvisibleType(InvisibleType.NONE);
    			player.setNonAggroTime(Long.MAX_VALUE);
    			player.spawnMe();
    			
    			player.setHero(Config.NEW_CHAR_IS_HERO);
    			player.setNoble(Config.NEW_CHAR_IS_NOBLE);
    			
    			player.getListeners().onEnter();
    			
    			// Backup to set default name color every time on login.
    			if ((player.getNameColor() != 0xFFFFFF) && ((player.getKarma() == 0) || (player.getRecomHave() == 0)) && !player.isGM())
    			{
    				player.setNameColor(0xFFFFFF);
    			}
    			
    			if ((player.getTitleColor() != Player.DEFAULT_TITLE_COLOR) && !player.isGM())
    			{
    				player.setTitleColor(Player.DEFAULT_TITLE_COLOR);
    			}
    			
    			// Restore after nocarrier title, title color.
    			if (player.getVar("NoCarrierTitle") != null)
    			{
    				player.setTitle(player.getVar("NoCarrierTitle"));
    				
    				if (player.getVar("NoCarrierTitleColor") != null)
    				{
    					player.setTitleColor(Integer.parseInt(player.getVar("NoCarrierTitleColor")));
    				}
    				
    				player.broadcastCharInfo();
    				
    				player.unsetVar("NoCarrierTitle");
    				player.unsetVar("NoCarrierTitleColor");
    			}
    			
    			if (player.isCursedWeaponEquipped())
    			{
    				CursedWeaponsManager.getInstance().showUsageTime(player, player.getCursedWeaponEquippedId());
    			}
    			
    			player.setCurrentHpMp(player.getMaxHp(), player.getMaxMp());
    			player.setCurrentCp(player.getMaxCp());
    			
    			player.setIsPhantom(true);
    			
    			if (player.getAI().isPhantomPlayerAI())
    			{
    				((PhantomPlayerAI) player.getAI()).startAITask();
    			}
    			
    			if (L2Event.isParticipant(player))
    			{
    				L2Event.restorePlayerEventStatus(player);
    			}
    			
    			player.setRunning();
    			player.standUp();
    			player.startTimers();
    			
    			player.broadcastCharInfo();
    			player.setHeading(Rnd.get(65535));
    			if (player.isDead())
    			{
    				player.teleToLocation(Location.getRestartLocation(player, RestartType.TO_VILLAGE));
    				player.doRevive(100);
    			}
    			else
    			{
    				player.teleToLocation(_loc == null ? player.getLoc() : _loc);
    			}
    		}
    	}
    	
    	/**
    	 * Checks if the given player is in the world, then logs out when he is out of combat.
    	 */
    	private static class PhantomDespawn implements Runnable
    	{
    		private final int _objId;
    		private final boolean _force;
    		
    		public PhantomDespawn(int objId, boolean force)
    		{
    			_objId = objId;
    			_force = force;
    		}
    		
    		@Override
    		public void run()
    		{
    			Player phantom = L2ObjectsStorage.getPlayer(_objId);
    			if (phantom == null)
    			{
    				return;
    			}
    			
    			if (!_force)
    			{
    				// Continue when phantom is out of combat.
    				if (phantom.isInCombat())
    				{
    					ThreadPoolManager.getInstance().schedule(this, 1000);
    					return;
    				}
    				
    				// When phantom is out of combat, stop moving.
    				if (phantom.isMoving)
    				{
    					phantom.stopMove();
    				}
    			}
    			
    			phantom.getAI().stopAITask();
    			phantom.kick();
    		}
    	}
    	
    	public static class PhantomSpawner implements Runnable
    	{
    		private final int _numSpawns;
    		private final long _delayInMilis;
    		private final boolean _generateNewPhantoms;
    		private int _curSpawns = 0;
    		private Location _loc = null;
    		private ScheduledFuture<?> _task = null;
    		
    		public PhantomSpawner()
    		{
    			_numSpawns = Config.PHANTOM_SPAWN_MAX;
    			_delayInMilis = Config.PHANTOM_SPAWN_DELAY;
    			_generateNewPhantoms = true;
    		}
    		
    		public PhantomSpawner(int numSpawns)
    		{
    			_numSpawns = numSpawns;
    			_delayInMilis = Config.PHANTOM_SPAWN_DELAY;
    			_generateNewPhantoms = true;
    		}
    		
    		public PhantomSpawner(int numSpawns, long delayInMilis)
    		{
    			_numSpawns = numSpawns;
    			_delayInMilis = delayInMilis;
    			_generateNewPhantoms = true;
    		}
    		
    		public PhantomSpawner(int numSpawns, long delayInMilis, boolean generateNewPhantoms)
    		{
    			_numSpawns = numSpawns;
    			_delayInMilis = delayInMilis;
    			_generateNewPhantoms = generateNewPhantoms;
    		}
    		
    		public PhantomSpawner setLocation(Location loc)
    		{
    			_loc = loc;
    			return this;
    		}
    		
    		@Override
    		public void run()
    		{
    			if (_numSpawns == 0)
    			{
    				return;
    			}
    			
    			_task = ThreadPoolManager.getInstance().scheduleAtFixedRate(() ->
    			{
    				if (_curSpawns < _numSpawns)
    				{
    					// Do not spawn more than max phantoms.
    					if (L2ObjectsStorage.getAllPlayersStream().filter(Player::isPhantom).count() >= Config.PHANTOM_MAX_PLAYERS)
    					{
    						return;
    					}
    					
    					int objId = getUnspawnedPhantomObjId();
    					if (objId > 0)
    					{
    						if (_generateNewPhantoms)
    						{
    							try
    							{
    								Player phantom = createNewPhantom();
    								if (phantom != null)
    								{
    									objId = phantom.getObjectId();
    									_log.info("Spawning phantom " + phantom + " through spawner. Cur/Max " + _curSpawns + "/" + _numSpawns);
    								}
    							}
    							catch (Exception e)
    							{
    								_log.error("ERROR: Spawning phantom  through spawner. Cur/Max " + _curSpawns + "/" + _numSpawns, e);
    							}
    						}
    						else
    						{
    							return;
    						}
    					}
    					
    					ThreadPoolManager.getInstance().execute(new PhantomSpawn(objId).setLocation(_loc));
    					_curSpawns++;
    				}
    			}, 0, _delayInMilis);
    		}
    		
    		public void cancel()
    		{
    			if (_task != null)
    			{
    				_task.cancel(true);
    				System.out.println("Canceling phantom scheduler");
    			}
    		}
    	}
    	
    	public static void stopSpawners()
    	{
    		if (_phantomSpawners != null)
    		{
    			for (PhantomSpawner thread : _phantomSpawners)
    			{
    				if (thread != null)
    				{
    					thread.cancel();
    				}
    			}
    		}
    	}
    	
    	public static void terminatePhantoms(boolean force)
    	{
    		stopSpawners();
    		
    		for (int objId : _phantoms)
    		{
    			new PhantomDespawn(objId, force).run();
    		}
    	}
    	
    	public static void terminatePhantom(int objId, boolean disableFromReenter)
    	{
    		if (disableFromReenter && (_phantoms != null))
    		{
    			_phantoms.remove(Integer.valueOf(objId));
    		}
    		
    		new PhantomDespawn(objId, true).run();
    	}
    }

     

     



    The following is a row I've taken from the admin commands java and it spawns the Phantoms.
     

    ThreadPoolManager.getInstance().execute(new PhantomPlayers.PhantomSpawn(phantom.getObjectId()).setLocation(activeChar.getLoc()));
     

  9. This is probably because you haven't set the path or you haven't linked the voice command with an HTML. I would have taken a look in .cfg/ccp if I were you. Also another shortcut would be to add the HTML in your Community board folder and bypass it from there. I believe there was a thing that one had to do in order to open HTMLs without the proper NPC around but I cant remember. Gonna take a look.

  10. Also if you have activated the random spawn loc, maybe they spawn like -5-10 Z which could cause the drop to disappear. Also you can try activating geodata, which I believe would resolve the issue. There are several good geodatas outthere but if you have problems finding one, I can share with you the L2World one. I have not found a single flaw so far.

     

    One last thing, do you kill them in 1 hit? Try leashing the monster away from its default spawn loc and check if the drop disappears.

  11. Once again, if the first run is never reached, the other internal can't be reached.

     

    And PhantomSpawn !=  PhantomSpawner. You must have a .run(), somewhere, for the PhantomSpawner instance. It's exactly like any Manager, you have to getInstance() to initialize the class and the content, otherwise it never loads.

     

    If it's a code issue, there isn't enough code to answer.

    I bet it is a code issue. I will provide the codes below, so if anyone has gone through this and has a quick fix, please do tell! :))

     

    This is the Spawner:

    package wp.gameserver.model;
    
    import java.io.File;
    import java.io.IOException;
    import java.nio.charset.StandardCharsets;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    import java.util.concurrent.ScheduledFuture;
    
    import org.apache.log4j.Logger;
    
    import com.google.common.io.Files;
    
    import wp.commons.util.Rnd;
    import wp.gameserver.Config;
    import wp.gameserver.ThreadPoolManager;
    import wp.gameserver.ai.PhantomPlayerAI;
    import wp.gameserver.dao.CharacterDAO;
    import wp.gameserver.dao.PhantomsDAO;
    import wp.gameserver.data.xml.holder.PhantomTemplateData;
    import wp.gameserver.data.xml.holder.SkillAcquireHolder;
    import wp.gameserver.instancemanager.CursedWeaponsManager;
    import wp.gameserver.model.base.AcquireType;
    import wp.gameserver.model.base.ClassId;
    import wp.gameserver.model.base.Experience;
    import wp.gameserver.model.base.InvisibleType;
    import wp.gameserver.model.base.RestartType;
    import wp.gameserver.model.entity.L2Event;
    import wp.gameserver.model.items.ItemInstance;
    import wp.gameserver.model.phantom.PhantomTemplate;
    import wp.gameserver.tables.SkillTable;
    import wp.gameserver.templates.item.CreateItem;
    import wp.gameserver.templates.item.ItemTemplate;
    import wp.gameserver.utils.Location;
    import wp.gameserver.utils.Util;
    
    public class PhantomPlayers
    {
    	private static final Logger _log = Logger.getLogger(PhantomPlayers.class.getName());
    	private static List<Integer> _phantoms;
    	private static List<String> _phantomNames;
    	private static List<PhantomSpawner> _phantomSpawners;
    	
    	public static void init()
    	{
    		_log.info("Loading phantom players...");
    		
    		try
    		{
    			File file = Config.findNonCustomResource("config/phantom/player_names.txt");
    			_phantomNames = Files.readLines(file, StandardCharsets.UTF_8);
    		}
    		catch (IOException e)
    		{
    			_log.warn("PhantomPlayers: Unable to load phantom player names.", e);
    			_phantomNames = Collections.emptyList();
    		}
    		
    		_phantoms = new ArrayList<>(PhantomsDAO.getInstance().selectAll().keySet());
    		_phantomSpawners = new ArrayList<>();
    		PhantomSpawner spawner = new PhantomSpawner();
    		ThreadPoolManager.getInstance().execute(spawner);
    		_phantomSpawners.add(spawner);
    		
    		_log.info("Loaded " + _phantoms.size() + " phantom players from database with a maximum of " + Config.PHANTOM_MAX_PLAYERS + " phantoms.");
    		_log.info("Loaded " + _phantomNames.size() + " possible phantom names.");
    		_log.info("Scheduled spawner with " + (Config.PHANTOM_SPAWN_DELAY / 1000) + " seconds delay.");
    	}
    	
    	public static Player createNewPhantom()
    	{
    		if (_phantomNames == null)
    		{
    			return null;
    		}
    		
    		for (int i = 0; i < 25; i++) // 25 tries to make a phantom player. Enough tries to avoid name duplicate and other stuff.
    		{
    			String name = Rnd.get(_phantomNames);
    			Player player = createNewPhantom(name);
    			if (player != null)
    			{
    				return player;
    			}
    		}
    		
    		return null;
    	}
    	
    	public static Player createNewPhantom(String name)
    	{
    		return createNewPhantom(name, PhantomTemplateData.getInstance().getRandomTemplate());
    	}
    	
    	public static Player createNewPhantom(String name, PhantomTemplate template)
    	{
    		boolean female = Rnd.nextBoolean();
    		int hairStyle = Rnd.get(3);
    		int hairColor = Rnd.get(3);
    		int face = Rnd.get(3);
    		return createNewPhantom(name, template, female, hairStyle, hairColor, face);
    	}
    	
    	public static Player createNewPhantom(String name, PhantomTemplate template, boolean female, int hairStyle, int hairColor, int face)
    	{
    		try
    		{
    			if (!Util.isMatchingRegexp(name, Config.CNAME_TEMPLATE))
    			{
    				return null;
    			}
    			if ((CharacterDAO.getInstance().getObjectIdByName(name) > 0) || Util.contains(Config.FORBIDDEN_CHAR_NAMES, name))
    			{
    				return null;
    			}
    			
    			if (template == null)
    			{
    				return null;
    			}
    			
    			final ClassId classId = ClassId.VALUES[template.getClassId()];
    			Player newChar = Player.create(classId.getId(), female ? 1 : 0, Config.PHANTOM_ACCOUNT, name, hairStyle, hairColor, face);
    			if (newChar == null)
    			{
    				return null;
    			}
    			
    			newChar.setCreateTime(System.currentTimeMillis());
    			try
    			{
    				switch (classId.getLevel())
    				{
    					case 2:
    						newChar.addExpAndSp(Experience.getExpForLevel(20), 835863);
    						break;
    					case 3:
    						newChar.addExpAndSp(Experience.getExpForLevel(40), 15422930);
    						break;
    					case 4:
    						newChar.addExpAndSp(Experience.getExpForLevel(76), 931275829);
    						break;
    				}
    			}
    			catch (ArrayIndexOutOfBoundsException | NullPointerException e)
    			{
    				_log.warn("PhantomPlayers: Failed to set appropreate level for classId " + classId, e);
    			}
    			
    			Player.restoreCharSubClasses(newChar);
    			
    			if (Config.STARTING_ADENA > 0)
    			{
    				newChar.addAdena(Config.STARTING_ADENA);
    			}
    			
    			if (Config.STARTING_LVL > newChar.getLevel())
    			{
    				newChar.addExpAndSp(Experience.LEVEL[Config.STARTING_LVL] - newChar.getExp(), 0, 0, 0, false, false);
    			}
    			
    			if (Config.SPAWN_CHAR)
    			{
    				newChar.teleToLocation(Config.SPAWN_X, Config.SPAWN_Y, Config.SPAWN_Z);
    			}
    			else
    			{
    				newChar.setLoc(Rnd.get(newChar.getTemplate().getSpawnLocs()));
    			}
    			
    			if (Config.CHAR_TITLE)
    			{
    				newChar.setTitle(Config.ADD_CHAR_TITLE);
    			}
    			else
    			{
    				newChar.setTitle("");
    			}
    			
    			for (CreateItem i : newChar.getTemplate().getItems())
    			{
    				ItemInstance item = new ItemInstance(i.getItemId());
    				newChar.getInventory().addItem(item);
    				
    				if (i.isEquipable() && item.isEquipable() && ((newChar.getActiveWeaponItem() == null) || (item.getTemplate().getType2() != ItemTemplate.TYPE2_WEAPON)))
    				{
    					newChar.getInventory().equipItem(item);
    				}
    			}
    			
    			if (Config.ALLOW_START_ITEMS)
    			{
    				if (classId.isMage())
    				{
    					for (int i = 0; i < Config.START_ITEMS_MAGE.length; i++)
    					{
    						ItemInstance item = new ItemInstance(Config.START_ITEMS_MAGE[i]);
    						item.setCount(Config.START_ITEMS_MAGE_COUNT[i]);
    						newChar.getInventory().addItem(item);
    					}
    					
    					if (Config.BIND_NEWBIE_START_ITEMS_TO_CHAR)
    					{
    						for (int i = 0; i < Config.START_ITEMS_MAGE_BIND_TO_CHAR.length; i++)
    						{
    							ItemInstance item = new ItemInstance(Config.START_ITEMS_MAGE_BIND_TO_CHAR[i]);
    							item.setCount(Config.START_ITEMS_MAGE_COUNT_BIND_TO_CHAR[i]);
    							item.setCustomFlags(ItemInstance.FLAG_NO_CRYSTALLIZE | ItemInstance.FLAG_NO_TRADE | ItemInstance.FLAG_NO_TRANSFER | ItemInstance.FLAG_NO_DROP | ItemInstance.FLAG_NO_SELL);
    							newChar.getInventory().addItem(item);
    						}
    					}
    				}
    				else
    				{
    					for (int i = 0; i < Config.START_ITEMS_FITHER.length; i++)
    					{
    						ItemInstance item = new ItemInstance(Config.START_ITEMS_FITHER[i]);
    						item.setCount(Config.START_ITEMS_FITHER_COUNT[i]);
    						newChar.getInventory().addItem(item);
    					}
    					
    					if (Config.BIND_NEWBIE_START_ITEMS_TO_CHAR)
    					{
    						for (int i = 0; i < Config.START_ITEMS_FITHER_BIND_TO_CHAR.length; i++)
    						{
    							ItemInstance item = new ItemInstance(Config.START_ITEMS_FITHER_BIND_TO_CHAR[i]);
    							item.setCount(Config.START_ITEMS_FITHER_COUNT_BIND_TO_CHAR[i]);
    							item.setCustomFlags(ItemInstance.FLAG_NO_CRYSTALLIZE | ItemInstance.FLAG_NO_TRADE | ItemInstance.FLAG_NO_TRANSFER | ItemInstance.FLAG_NO_DROP | ItemInstance.FLAG_NO_SELL);
    							newChar.getInventory().addItem(item);
    						}
    					}
    				}
    			}
    			
    			for (SkillLearn skill : SkillAcquireHolder.getInstance().getAvailableSkills(newChar, AcquireType.NORMAL))
    			{
    				newChar.addSkill(SkillTable.getInstance().getInfo(skill.getId(), skill.getLevel()), true);
    			}
    			
    			newChar.setCurrentHpMp(newChar.getMaxHp(), newChar.getMaxMp());
    			newChar.setCurrentCp(0); // retail
    			newChar.setOnlineStatus(false);
    			
    			newChar.store(false);
    			newChar.getInventory().store();
    			newChar.deleteMe();
    			
    			PhantomsDAO.getInstance().insert(newChar.getObjectId(), template);
    			
    			_phantoms.add(newChar.getObjectId());
    			return newChar;
    		}
    		catch (Exception e)
    		{
    			e.printStackTrace();
    		}
    		
    		return null;
    	}
    	
    	public static PhantomSpawner spawnPhantoms(int numSpawns, long delayInMilis, boolean generateNew, Location loc)
    	{
    		PhantomSpawner spawner = new PhantomSpawner(numSpawns, delayInMilis, generateNew).setLocation(loc);
    		ThreadPoolManager.getInstance().execute(spawner);
    		_phantomSpawners.add(spawner);
    		return spawner;
    	}
    	
    	/**
    	 * Gets the next unspawned phantom.
    	 * @return random free (unspawned) phantom object id or -1 if all are taken.
    	 */
    	private static int getUnspawnedPhantomObjId()
    	{
    		List<Integer> _unspawnedPhantoms = new ArrayList<>();
    		_unspawnedPhantoms.addAll(_phantoms);
    		
    		for (Player player : L2ObjectsStorage.getAllPlayersForIterate())
    		{
    			if (_unspawnedPhantoms.contains(Integer.valueOf(player.getObjectId())))
    			{
    				_unspawnedPhantoms.remove(Integer.valueOf(player.getObjectId()));
    			}
    		}
    		
    		if (!_unspawnedPhantoms.isEmpty())
    		{
    			return Rnd.get(_unspawnedPhantoms);
    		}
    		
    		return -1;
    	}
    	
    	public static class PhantomSpawn implements Runnable
    	{
    		private final int _objId;
    		private Location _loc;
    		
    		public PhantomSpawn()
    		{
    			_objId = getUnspawnedPhantomObjId();
    		}
    		
    		public PhantomSpawn(int objId)
    		{
    			_objId = objId;
    			_loc = null;
    		}
    		
    		public PhantomSpawn setLocation(Location loc)
    		{
    			_loc = new Location(loc.getX() + Rnd.get(200), loc.getY() + Rnd.get(200), loc.getZ());
    			return this;
    		}
    		
    		@Override
    		public void run()
    		{
    			
    			Player player = World.getPlayer(_objId);
    			if (player == null)
    			{
    				player = Player.restore(_objId);
    			}
    			if (player == null)
    			{
    				return;
    			}
    			
    			player.setOfflineMode(false);
    			player.setIsOnline(true);
    			player.updateOnlineStatus();
    			
    			player.setOnlineStatus(true);
    			player.setInvisibleType(InvisibleType.NONE);
    			player.setNonAggroTime(Long.MAX_VALUE);
    			player.spawnMe();
    			
    			player.setHero(Config.NEW_CHAR_IS_HERO);
    			player.setNoble(Config.NEW_CHAR_IS_NOBLE);
    			
    			player.getListeners().onEnter();
    			
    			// Backup to set default name color every time on login.
    			if ((player.getNameColor() != 0xFFFFFF) && ((player.getKarma() == 0) || (player.getRecomHave() == 0)) && !player.isGM())
    			{
    				player.setNameColor(0xFFFFFF);
    			}
    			
    			if ((player.getTitleColor() != Player.DEFAULT_TITLE_COLOR) && !player.isGM())
    			{
    				player.setTitleColor(Player.DEFAULT_TITLE_COLOR);
    			}
    			
    			// Restore after nocarrier title, title color.
    			if (player.getVar("NoCarrierTitle") != null)
    			{
    				player.setTitle(player.getVar("NoCarrierTitle"));
    				
    				if (player.getVar("NoCarrierTitleColor") != null)
    				{
    					player.setTitleColor(Integer.parseInt(player.getVar("NoCarrierTitleColor")));
    				}
    				
    				player.broadcastCharInfo();
    				
    				player.unsetVar("NoCarrierTitle");
    				player.unsetVar("NoCarrierTitleColor");
    			}
    			
    			if (player.isCursedWeaponEquipped())
    			{
    				CursedWeaponsManager.getInstance().showUsageTime(player, player.getCursedWeaponEquippedId());
    			}
    			
    			player.setCurrentHpMp(player.getMaxHp(), player.getMaxMp());
    			player.setCurrentCp(player.getMaxCp());
    			
    			player.setIsPhantom(true);
    			
    			if (player.getAI().isPhantomPlayerAI())
    			{
    				((PhantomPlayerAI) player.getAI()).startAITask();
    			}
    			
    			if (L2Event.isParticipant(player))
    			{
    				L2Event.restorePlayerEventStatus(player);
    			}
    			
    			player.setRunning();
    			player.standUp();
    			player.startTimers();
    			
    			player.broadcastCharInfo();
    			player.setHeading(Rnd.get(65535));
    			if (player.isDead())
    			{
    				player.teleToLocation(Location.getRestartLocation(player, RestartType.TO_VILLAGE));
    				player.doRevive(100);
    			}
    			else
    			{
    				player.teleToLocation(_loc == null ? player.getLoc() : _loc);
    			}
    		}
    	}
    	
    	/**
    	 * Checks if the given player is in the world, then logs out when he is out of combat.
    	 */
    	private static class PhantomDespawn implements Runnable
    	{
    		private final int _objId;
    		private final boolean _force;
    		
    		public PhantomDespawn(int objId, boolean force)
    		{
    			_objId = objId;
    			_force = force;
    		}
    		
    		@Override
    		public void run()
    		{
    			Player phantom = L2ObjectsStorage.getPlayer(_objId);
    			if (phantom == null)
    			{
    				return;
    			}
    			
    			if (!_force)
    			{
    				// Continue when phantom is out of combat.
    				if (phantom.isInCombat())
    				{
    					ThreadPoolManager.getInstance().schedule(this, 1000);
    					return;
    				}
    				
    				// When phantom is out of combat, stop moving.
    				if (phantom.isMoving)
    				{
    					phantom.stopMove();
    				}
    			}
    			
    			phantom.getAI().stopAITask();
    			phantom.kick();
    		}
    	}
    	
    	public static class PhantomSpawner implements Runnable
    	{
    		private final int _numSpawns;
    		private final long _delayInMilis;
    		private final boolean _generateNewPhantoms;
    		private int _curSpawns = 0;
    		private Location _loc = null;
    		private ScheduledFuture<?> _task = null;
    		
    		public PhantomSpawner()
    		{
    			_numSpawns = Config.PHANTOM_SPAWN_MAX;
    			_delayInMilis = Config.PHANTOM_SPAWN_DELAY;
    			_generateNewPhantoms = true;
    		}
    		
    		public PhantomSpawner(int numSpawns)
    		{
    			_numSpawns = numSpawns;
    			_delayInMilis = Config.PHANTOM_SPAWN_DELAY;
    			_generateNewPhantoms = true;
    		}
    		
    		public PhantomSpawner(int numSpawns, long delayInMilis)
    		{
    			_numSpawns = numSpawns;
    			_delayInMilis = delayInMilis;
    			_generateNewPhantoms = true;
    		}
    		
    		public PhantomSpawner(int numSpawns, long delayInMilis, boolean generateNewPhantoms)
    		{
    			_numSpawns = numSpawns;
    			_delayInMilis = delayInMilis;
    			_generateNewPhantoms = generateNewPhantoms;
    		}
    		
    		public PhantomSpawner setLocation(Location loc)
    		{
    			_loc = loc;
    			return this;
    		}
    		
    		@Override
    		public void run()
    		{
    			if (_numSpawns == 0)
    			{
    				return;
    			}
    			
    			_task = ThreadPoolManager.getInstance().scheduleAtFixedRate(() ->
    			{
    				if (_curSpawns < _numSpawns)
    				{
    					// Do not spawn more than max phantoms.
    					if (L2ObjectsStorage.getAllPlayersStream().filter(Player::isPhantom).count() >= Config.PHANTOM_MAX_PLAYERS)
    					{
    						return;
    					}
    					
    					int objId = getUnspawnedPhantomObjId();
    					if (objId < 0)
    					{
    						if (_generateNewPhantoms)
    						{
    							try
    							{
    								Player phantom = createNewPhantom();
    								if (phantom != null)
    								{
    									objId = phantom.getObjectId();
    									_log.info("Spawning phantom " + phantom + " through spawner. Cur/Max " + _curSpawns + "/" + _numSpawns);
    								}
    							}
    							catch (Exception e)
    							{
    								_log.error("ERROR: Spawning phantom  through spawner. Cur/Max " + _curSpawns + "/" + _numSpawns, e);
    							}
    						}
    						else
    						{
    							return;
    						}
    					}
    					
    					ThreadPoolManager.getInstance().execute(new PhantomSpawn(objId).setLocation(_loc));
    					_curSpawns++;
    				}
    			}, 0, _delayInMilis);
    		}
    		
    		public void cancel()
    		{
    			if (_task != null)
    			{
    				_task.cancel(true);
    				System.out.println("Canceling phantom scheduler");
    			}
    		}
    	}
    	
    	public static void stopSpawners()
    	{
    		if (_phantomSpawners != null)
    		{
    			for (PhantomSpawner thread : _phantomSpawners)
    			{
    				if (thread != null)
    				{
    					thread.cancel();
    				}
    			}
    		}
    	}
    	
    	public static void terminatePhantoms(boolean force)
    	{
    		stopSpawners();
    		
    		for (int objId : _phantoms)
    		{
    			new PhantomDespawn(objId, force).run();
    		}
    	}
    	
    	public static void terminatePhantom(int objId, boolean disableFromReenter)
    	{
    		if (disableFromReenter && (_phantoms != null))
    		{
    			_phantoms.remove(Integer.valueOf(objId));
    		}
    		
    		new PhantomDespawn(objId, true).run();
    	}
    }

     

    This is the AI, which does not start hitting:

    package wp.gameserver.ai;
    
    import java.util.Comparator;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.NavigableSet;
    import java.util.Objects;
    import java.util.concurrent.ConcurrentSkipListSet;
    import java.util.concurrent.ScheduledFuture;
    import java.util.stream.Collectors;
    
    import wp.commons.util.Rnd;
    import wp.gameserver.Config;
    import wp.gameserver.ThreadPoolManager;
    import wp.gameserver.ai.DefaultAI.Task;
    import wp.gameserver.ai.DefaultAI.TaskType;
    import wp.gameserver.dao.CharacterDAO;
    import wp.gameserver.dao.PhantomsDAO;
    import wp.gameserver.data.xml.holder.PhantomTemplateData;
    import wp.gameserver.geodata.GeoEngine;
    import wp.gameserver.handler.bbs.CommunityBoardManager;
    import wp.gameserver.instancemanager.ReflectionManager;
    import wp.gameserver.listener.actor.OnKillListener;
    import wp.gameserver.listener.actor.ai.OnAiEventListener;
    import wp.gameserver.model.Creature;
    import wp.gameserver.model.Effect;
    import wp.gameserver.model.L2Object;
    import wp.gameserver.model.PhantomPlayers;
    import wp.gameserver.model.Player;
    import wp.gameserver.model.Skill;
    import wp.gameserver.model.Skill.SkillTargetType;
    import wp.gameserver.model.Skill.SkillType;
    import wp.gameserver.model.World;
    import wp.gameserver.model.Zone;
    import wp.gameserver.model.base.ClassId;
    import wp.gameserver.model.base.Experience;
    import wp.gameserver.model.base.RestartType;
    import wp.gameserver.model.instances.ChestInstance;
    import wp.gameserver.model.items.ItemInstance;
    import wp.gameserver.model.phantom.PhantomItem;
    import wp.gameserver.model.phantom.PhantomItemAction;
    import wp.gameserver.model.phantom.PhantomSkill;
    import wp.gameserver.model.phantom.PhantomTemplate;
    import wp.gameserver.model.phantom.PhantomZone;
    import wp.gameserver.model.stats.Env;
    import wp.gameserver.model.stats.Stats;
    import wp.gameserver.model.stats.conditions.Condition;
    import wp.gameserver.model.stats.funcs.FuncAdd;
    import wp.gameserver.network.clientpackets.EnterWorld;
    import wp.gameserver.network.serverpackets.Say2;
    import wp.gameserver.network.serverpackets.components.ChatType;
    import wp.gameserver.network.serverpackets.components.IStaticPacket;
    import wp.gameserver.tables.AdminTable;
    import wp.gameserver.tables.SkillTable;
    import wp.gameserver.taskmanager.AiTaskManager;
    import wp.gameserver.templates.item.EtcItemTemplate.EtcItemType;
    import wp.gameserver.templates.item.ItemTemplate.Grade;
    import wp.gameserver.utils.Location;
    
    /**
     * @author Nik
     */
    @SuppressWarnings("unused")
    public class PhantomPlayerAI extends PlayerAI implements OnAiEventListener, OnKillListener
    {// TODO: Refuse trade and party and clan and shits.
    	public static final int TASK_DEFAULT_WEIGHT = 10000;
    	private static final int WAIT_TIMER_ID = 0;
    	private static final int BUFF_TIMER_ID = 1;
    	
    	public static final Comparator<Creature> lvlDiff = Comparator.comparingInt(Creature::getLevel);
    	public final Comparator<Creature> distanceComparator = (c1, c2) -> (Integer.compare((int) getActor().getDistance(c1), (int) getActor().getDistance(c2)));
    	public final Comparator<Creature> targetComparator = distanceComparator.thenComparing(lvlDiff);
    	
    	protected long AI_TASK_ATTACK_DELAY = Config.AI_TASK_ATTACK_DELAY;
    	protected long AI_TASK_ACTIVE_DELAY = Config.AI_TASK_ACTIVE_DELAY;
    	protected long AI_TASK_DELAY_CURRENT = AI_TASK_ACTIVE_DELAY;
    	
    	protected ScheduledFuture<?> _aiTask;
    	protected ScheduledFuture<?> _roamingTask;
    	private boolean _isWaiting = false;
    	private final int _thinkActiveExceptions = 0;
    	protected String _mood = "";
    	protected final NavigableSet<Task> _tasks = new ConcurrentSkipListSet<>(TaskComparator.getInstance());
    	
    	private long _buffTimeLastCached = 0;
    	private int _buffTimeCache = -1;
    	private final long _lastSelfBuffCheck = 0;
    	private long _lastMoveAround = 0;
    	private long _lastAiResponse = 0;
    	private long _lastWantToFarm = 0;
    	private final long _lastFarmStarted = System.currentTimeMillis();
    	
    	protected PhantomTemplate _template;
    	
    	// Roaming in town shits.
    	private boolean _offlineShopsChecked = false;
    	private int _warehouseChecked = 0;
    	private int _shopChecked = 0;
    	private int _npcChecked = 0;
    	
    	int maxChecksWh = Config.PHANTOM_ROAMING_MAX_WH_CHECKS; // Dwarfs check warehouse more often
    	int maxChecksShop = Config.PHANTOM_ROAMING_MAX_SHOP_CHECKS; // Dwarfs check shops more often
    	
    	public PhantomPlayerAI(Player actor)
    	{
    		super(actor);
    	}
    	
    	private static class TaskComparator implements Comparator<Task>
    	{
    		private static final Comparator<Task> _instance = new TaskComparator();
    		
    		public static final Comparator<Task> getInstance()
    		{
    			return _instance;
    		}
    		
    		@Override
    		public int compare(Task o1, Task o2)
    		{
    			if ((o1 == null) || (o2 == null))
    			{
    				return 0;
    			}
    			return o2.weight - o1.weight;
    		}
    	}
    	
    	public void addTaskCast(Creature target, Skill skill)
    	{
    		addTaskCast(target, skill, null, false, false);
    	}
    	
    	public void addTaskCast(Creature target, Skill skill, Condition cond)
    	{
    		addTaskCast(target, skill, cond, false, false);
    	}
    	
    	public void addTaskCast(Creature target, Skill skill, Condition cond, boolean forceUse)
    	{
    		addTaskCast(target, skill, cond, forceUse, false);
    	}
    	
    	public void addTaskCast(Creature target, Skill skill, Condition cond, boolean forceUse, boolean dontMove)
    	{
    		if (skill == null)
    		{
    			return;
    		}
    		
    		Task task = new Task();
    		task.type = TaskType.CAST;
    		task.target = target.getRef();
    		task.skill = skill;
    		task.cond = cond;
    		task.forceUse = forceUse;
    		task.dontMove = dontMove;
    		_tasks.add(task);
    	}
    	
    	public void addTaskBuff(Creature target, Skill skill)
    	{
    		addTaskBuff(target, skill, null);
    	}
    	
    	public void addTaskBuff(Creature target, Skill skill, Condition cond)
    	{
    		if (skill == null)
    		{
    			return;
    		}
    		
    		Task task = new Task();
    		task.type = TaskType.BUFF;
    		task.target = target.getRef();
    		task.skill = skill;
    		task.cond = cond;
    		_tasks.add(task);
    	}
    	
    	public void addTaskAttack(Creature target)
    	{
    		addTaskAttack(target, null, false, false);
    	}
    	
    	public void addTaskAttack(Creature target, Condition cond)
    	{
    		addTaskAttack(target, cond, false, false);
    	}
    	
    	public void addTaskAttack(Creature target, Condition cond, boolean forceUse)
    	{
    		addTaskAttack(target, cond, forceUse, false);
    	}
    	
    	public void addTaskAttack(Creature target, Condition cond, boolean forceUse, boolean dontMove)
    	{
    		if (target == null)
    		{
    			return;
    		}
    		
    		Task task = new Task();
    		task.type = TaskType.ATTACK;
    		task.target = target.getRef();
    		task.cond = cond;
    		task.forceUse = forceUse;
    		task.dontMove = dontMove;
    		_tasks.add(task);
    	}
    	
    	public void addTaskMove(Location loc, int offset)
    	{
    		addTaskMove(loc, offset, true, null);
    	}
    	
    	public void addTaskMove(Location loc, int offset, boolean pathfind)
    	{
    		addTaskMove(loc, offset, pathfind, null);
    	}
    	
    	public void addTaskMove(Location loc, int offset, boolean pathfind, Condition cond)
    	{
    		Task task = new Task();
    		task.type = TaskType.MOVE;
    		task.loc = loc;
    		task.pathfind = pathfind;
    		task.locationOffset = offset;
    		_tasks.add(task);
    	}
    	
    	public void addTaskInteract(Creature target)
    	{
    		Task task = new Task();
    		task.type = TaskType.INTERACT;
    		task.target = target.getRef();
    		task.pathfind = true;
    		_tasks.add(task);
    	}
    	
    	protected boolean maybeNextTask(Task currentTask)
    	{
    		// Next job
    		_tasks.remove(currentTask);
    		// If there are no more jobs - define new
    		if (_tasks.size() == 0)
    		{
    			return true;
    		}
    		return false;
    	}
    	
    	/**
    	 * @return true : clear all tasks
    	 */
    	protected void doTask()
    	{
    		Player actor = getActor();
    		
    		if (_tasks.isEmpty())
    		{
    			return;
    		}
    		
    		Task currentTask = _tasks.pollFirst();
    		if (currentTask == null)
    		{
    			return;
    		}
    		
    		if (actor.isDead() || actor.isAttackingNow() || actor.isCastingNow())
    		{
    			return;
    		}
    		
    		if (currentTask.cond != null)
    		{
    			if (currentTask.target == null)
    			{
    				return;
    			}
    			
    			final Env env = Env.valueOf(actor, currentTask.target.get(), currentTask.skill);
    			if (!currentTask.cond.test(env))
    			{
    				env.recycle();
    				return;
    			}
    			env.recycle();
    		}
    		
    		switch (currentTask.type)
    		{
    			case MOVE:
    				setNextAction(nextAction.MOVE, currentTask.loc, currentTask.locationOffset, currentTask.pathfind, currentTask.dontMove);
    				getActor().setRunning();
    				setNextIntention();
    				break;
    			case INTERACT:
    				setNextAction(nextAction.INTERACT, currentTask.target.get(), null, currentTask.forceUse, currentTask.dontMove);
    				getActor().setRunning();
    				setNextIntention();
    				break;
    			case ATTACK:
    				setNextAction(nextAction.ATTACK, currentTask.target.get(), null, false, currentTask.dontMove);
    				setNextIntention();
    				break;
    			case CAST:
    				setNextAction(nextAction.CAST, currentTask.skill, currentTask.target.get(), currentTask.forceUse, currentTask.dontMove);
    				setNextIntention();
    				break;
    		}
    	}
    	
    	@Override
    	public synchronized void startAITask()
    	{
    		if (_aiTask == null)
    		{
    			System.out.println("TESTTTTTTTTTTTTT");
    			
    			AI_TASK_DELAY_CURRENT = AI_TASK_ACTIVE_DELAY;
    			_aiTask = AiTaskManager.getInstance().scheduleAtFixedRate(this, 0L, AI_TASK_DELAY_CURRENT);
    			final int classId = PhantomsDAO.getInstance().select(getActor().getObjectId());
    			_template = PhantomTemplateData.getInstance().getTemplate(classId);
    			
    			if (_template == null)
    			{
    				_log.warn("startAITask called on phantom with no template " + getActor());
    				PhantomPlayers.terminatePhantom(getActor().getObjectId(), true);
    				return;
    			}
    			
    			getActor().addListener(this);
    			getActor().addStatFunc(new FuncAdd(Stats.MAX_NO_PENALTY_LOAD, 0x40, this, Integer.MAX_VALUE)); // I have reached a new level of laziness - avoid caring about weight penalty :D
    			waitTime(4000); // Wait t least 4secs until active, to not look suspicious.
    		}
    	}
    	
    	protected synchronized void switchAITask(long NEW_DELAY)
    	{
    		if (_aiTask == null)
    		{
    			return;
    		}
    		
    		if (AI_TASK_DELAY_CURRENT != NEW_DELAY)
    		{
    			_aiTask.cancel(false);
    			AI_TASK_DELAY_CURRENT = NEW_DELAY;
    			_aiTask = AiTaskManager.getInstance().scheduleAtFixedRate(this, 0L, AI_TASK_DELAY_CURRENT);
    			final int classId = PhantomsDAO.getInstance().select(getActor().getObjectId());
    			_template = PhantomTemplateData.getInstance().getTemplate(classId);
    			if (_template == null)
    			{
    				_log.warn("switchAITask called on phantom with no template " + getActor());
    				PhantomPlayers.terminatePhantom(getActor().getObjectId(), true);
    				return;
    			}
    			getActor().addListener(this);
    			getActor().addStatFunc(new FuncAdd(Stats.MAX_NO_PENALTY_LOAD, 0x40, this, Integer.MAX_VALUE)); // I have reached a new level of laziness - avoid caring about weight penalty :D
    		}
    	}
    	
    	@Override
    	public final synchronized void stopAITask()
    	{
    		if (_aiTask != null)
    		{
    			_aiTask.cancel(false);
    			_aiTask = null;
    			_template = null;
    			getActor().removeListener(this);
    			getActor().removeStatsOwner(this); // Remove the added weight bonus
    		}
    	}
    	
    	@Override
    	public boolean isActive()
    	{
    		return _aiTask != null;
    	}
    	
    	@Override
    	public void runImpl()
    	{
    		if (_aiTask == null)
    		{
    			return;
    		}
    		
    		onEvtThink();
    		_lastAiResponse = System.currentTimeMillis();
    		// say(this.getIntention().toString());
    	}
    	
    	public void waitTime(long timeInMilis)
    	{
    		_isWaiting = true;
    		addTimer(WAIT_TIMER_ID, timeInMilis);
    	}
    	
    	public void setMood(String mood)
    	{
    		say("Changing my mood [" + _mood + "] -> [" + mood + "]");
    		_mood = mood;
    	}
    	
    	public String getMood()
    	{
    		return _mood;
    	}
    	
    	@Override
    	protected void onIntentionActive()
    	{
    		clearNextAction();
    		changeIntention(CtrlIntention.AI_INTENTION_ACTIVE, null, null);
    	}
    	
    	@Override
    	protected void onIntentionIdle()
    	{
    		clearNextAction();
    		changeIntention(CtrlIntention.AI_INTENTION_ACTIVE, null, null);
    	}
    	
    	/**
    	 * @return true : block thinkAttack() execution <br>
    	 *         false : if the AI should continue and execute thinkAttack()
    	 */
    	@Override
    	protected boolean thinkActive()
    	{
    		return false;
    	}
    	
    	private void thinkCanFarm()
    	{
    		int playersAround = 0;
    		for (Player player : World.getAroundPlayers(getActor()))
    		{
    			if (getActor().getDistance(player) < Config.PHANTOM_MAX_PLAYERS_IN_FARMZONE_RANGE)
    			{
    				playersAround++;
    			}
    		}
    		
    		if (playersAround > Config.PHANTOM_MAX_PLAYERS_IN_FARMZONE)
    		{
    			say("There is more then " + Config.PHANTOM_MAX_PLAYERS_IN_FARMZONE + " players around me going to town and gonna try again after " + (Config.PHANTOM_RETRY_TO_FARM_DELAY / 1000) + " seconds..");
    			waitTime(Config.PHANTOM_RETRY_TO_FARM_DELAY);
    			getActor().doCast(findSoeSkill(), getActor(), false);
    		}
    	}
    	
    	private void thinkMoveAround()
    	{
    		final Player actor = getActor();
    		System.out.println("TTTTTTTTTTTTTTTTTTTTTTTTTTTTT");
    		if (!actor.isMoving && ((System.currentTimeMillis() - _lastMoveAround) > Config.PHANTOM_MOVE_AROUND_DELAY))
    		{
    			System.out.println("2222222222222222222222222");
    			say("No target? lets move around!");
    			final int radius = Config.PHANTOM_MOVE_AROUND_RANGE;
    			int x = actor.getX();
    			int y = actor.getY();
    			
    			x = Rnd.nextInt(radius * 2);
    			y = Rnd.get(x, radius * 2);
    			y = (int) Math.sqrt((y * y) - (x * x));
    			x += actor.getX() - radius;
    			y += actor.getY() - radius;
    			final Location loc = GeoEngine.moveCheck(actor.getX(), actor.getY(), actor.getZ(), x, y, actor.getGeoIndex());
    			addTaskMove(loc, 0, true);
    			_lastMoveAround = System.currentTimeMillis();
    			actor.setTarget(null);
    			setAttackTarget(null);
    		}
    	}
    	
    	@Override
    	protected void thinkAttack(boolean checkRange)
    	{
    		if (_template == null)
    		{
    			_log.warn("thinkAttack called on phantom with no template " + getActor());
    			PhantomPlayers.terminatePhantom(getActor().getObjectId(), true);
    			return;
    		}
    		
    		// Set last attack time.
    		getActor().setLastAttackPacket();
    		
    		// Activate shots if not activated.
    		if (getActor().getAutoSoulShot().isEmpty())
    		{
    			EnterWorld.verifyAndLoadShots(getActor());
    		}
    		
    		// Get a target to cast
    		Creature target = getAttackTarget();
    		if (target == null)
    		{
    			target = getActor().getTarget(Creature.class);
    		}
    		
    		// No valid target found? Do nothing
    		if (target != null)
    		{
    			boolean shouldCastSkill = target.isPlayer(); // In pvp always cast skills.
    			switch (_template.getType())
    			{
    				case WARRIOR:
    					shouldCastSkill = Rnd.chance(100);
    					break;
    				case DAGGER:
    					shouldCastSkill = Rnd.chance(60);
    					break;
    				case ARCHER:
    					shouldCastSkill = Rnd.chance(50);
    					break;
    				case MAGE:
    					shouldCastSkill = true;
    					break;
    			}
    			
    			// Check to cast skill
    			if (shouldCastSkill)
    			{
    				for (PhantomSkill skill : _template.getSkills().values())
    				{
    					if (GeoEngine.canSeeTarget(getActor(), target, false) && skill.canUseSkill(getActor(), target, false, false))
    					{
    						// Check if the skill is going to be casted or not.
    						if (cast(skill.getSkill(getActor()), target, false, false))
    						{
    							say("Casting " + skill.getSkill(getActor()).getName());
    							return;
    						}
    					}
    				}
    				
    				// couldn't cast?
    				thinkMoveAround();
    			}
    		}
    		
    		super.thinkAttack(checkRange);
    	}
    	
    	@Override
    	protected void thinkCast(boolean checkRange)
    	{
    		// Mage cant see target, let him press attack so he can let geodata lead him to the mob.
    		if (!GeoEngine.canSeeTarget(getActor(), getAttackTarget(), false))
    		{
    			// Catch new target.
    			setAttackTarget(null);
    			getActor().setTarget(null);
    			setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
    			return;
    		}
    		
    		super.thinkCast(checkRange);
    	}
    	
    	private Skill findSoeSkill()
    	{
    		Skill soe = SkillTable.getInstance().getInfo(2013, 1);
    		if (!Config.PHANTOM_SCROLLS_OF_ESCAPE.isEmpty())
    		{
    			final int skillId = Rnd.get(Config.PHANTOM_SCROLLS_OF_ESCAPE);
    			final Skill sk = SkillTable.getInstance().getInfo(skillId, 1);
    			if (sk != null)
    			{
    				return sk;
    			}
    		}
    		return soe;
    	}
    	
    	private void createNewItems()
    	{
    		if (_template == null)
    		{
    			_log.warn("createNewItems called on phantom with no template " + getActor());
    			PhantomPlayers.terminatePhantom(getActor().getObjectId(), true);
    			return;
    		}
    		
    		final Player actor = getActor();
    		
    		// Cleanup
    		say("Cleaning up some inventory junk");
    		for (ItemInstance item : actor.getInventory().getItems())
    		{
    			if (item.isEquipped())
    			{
    				continue;
    			}
    			
    			if (item.isAccessory() || item.isArmor() || item.isWeapon())
    			{
    				boolean noGradeJunk = (item.getCrystalType() == Grade.NONE) && (actor.getLevel() > 20);
    				boolean dGradeJunk = (item.getCrystalType() == Grade.D) && (actor.getLevel() > 40);
    				boolean cGradeJunk = (item.getCrystalType() == Grade.C) && (actor.getLevel() > 52);
    				boolean bGradeJunk = (item.getCrystalType() == Grade.B) && (actor.getLevel() > 61);
    				boolean aGradeJunk = (item.getCrystalType() == Grade.A) && (actor.getLevel() > 76);
    				if (noGradeJunk && dGradeJunk && cGradeJunk && bGradeJunk && aGradeJunk)
    				{
    					say("Destroying " + item);
    					actor.getInventory().destroyItem(item);
    				}
    				continue;
    			}
    			else if (item.isArrow() || item.isAdena() || (item.getItemType() == EtcItemType.SHOT) || (item.getItemType() == EtcItemType.POTION))
    			{
    				continue;
    			}
    			say("Destroying " + item);
    			actor.getInventory().destroyItem(item);
    		}
    		
    		for (PhantomItem item : _template.getItems().get(PhantomItemAction.EQUIP))
    		{
    			if (!item.checkCondition(getActor()))
    			{
    				continue;
    			}
    			else if (item.isEquipped(getActor()))
    			{
    				continue;
    			}
    			
    			item.createItemIfNotInInventory(getActor(), false);
    			item.equip(getActor(), false);
    			if (item.isWeapon())
    			{
    				item.equipThisWeaponAndActivateShots(getActor(), false);
    			}
    		}
    	}
    	
    	protected Creature getTarget()
    	{
    		final LinkedList<Creature> lowPriorityTargets = new LinkedList<>();
    		final List<Creature> list = World.getAroundCharacters(getActor()).stream().filter(Objects::nonNull).filter(t -> !t.isRaid() && !t.isDead() && !t.isMinion() && !t.isInvisible() && !t.isInvul() && t.isMonster() && !(t instanceof ChestInstance)).sorted(targetComparator).collect(Collectors.toList());
    		
    		// Find a valid target to attack.
    		OUT: for (Creature tgt : list)
    		{
    			for (Player player : tgt.getAroundPlayers())
    			{
    				if (player.isGM() || player.isInvisible())
    				{
    					continue;
    				}
    				
    				if ((player.getTarget() == tgt) && (tgt.getCurrentHpPercents() < 99))
    				{
    					continue OUT;
    				}
    			}
    			
    			if ((System.currentTimeMillis() - tgt.getLastAttackedTime()) < 5000) // Target attacked in the last 5 secs.
    			{
    				if ((tgt.getAggressionTarget() != null) && (tgt.getAggressionTarget() != getActor()))
    				{
    					continue;
    				}
    			}
    			if (getActor().checkTarget(tgt))
    			{
    				if ((getActor().getLevel() - tgt.getLevel()) > 5)
    				{
    					lowPriorityTargets.add(tgt);
    				}
    				else
    				{
    					return tgt;
    				}
    			}
    			else
    			{
    				if (Location.getDistance(getActor(), tgt) >= 2000)
    				{
    					lowPriorityTargets.add(tgt);
    				}
    			}
    		}
    		
    		lowPriorityTargets.sort(targetComparator);
    		return lowPriorityTargets.isEmpty() ? null : lowPriorityTargets.getFirst();
    	}
    	
    	/**
    	 * @return : A visible random location nearby. Null if it fails to find such.
    	 */
    	protected Location getRandomLocation(int minRange, int maxRange, int maximumAttemptsToFindSuchLocation)
    	{
    		int x = getActor().getX();
    		int y = getActor().getY();
    		int z = getActor().getZ();
    		int geoIndex = getActor().getGeoIndex();
    		
    		for (int i = 0; i < maximumAttemptsToFindSuchLocation; i++)
    		{
    			Location tmp = getActor().getLoc().coordsRandomize(minRange, maxRange);
    			if (GeoEngine.canMoveToCoord(x, y, z, tmp.x, tmp.y, tmp.z, geoIndex))
    			{
    				return tmp;
    			}
    		}
    		
    		return null;
    	}
    	
    	public void runAway(Location fromLoc, int timeInMilis)
    	{
    		int posX = getActor().getX();
    		int posY = getActor().getY();
    		int posZ = getActor().getZ();
    		
    		int old_posX = posX;
    		int old_posY = posY;
    		int old_posZ = posZ;
    		
    		int signx = posX < fromLoc.getX() ? -1 : 1;
    		int signy = posY < fromLoc.getY() ? -1 : 1;
    		
    		int range = (int) (((0.71 * timeInMilis) / 1000) * getActor().getMoveSpeed());
    		
    		posX += signx * range;
    		posY += signy * range;
    		posZ = GeoEngine.getHeight(posX, posY, posZ, getActor().getGeoIndex());
    		
    		if (GeoEngine.canMoveToCoord(old_posX, old_posY, old_posZ, posX, posY, posZ, getActor().getGeoIndex()))
    		{
    			addTaskMove(new Location(posX, posY, posZ), 0);
    		}
    	}
    	
    	public boolean hasBetterFarmZone()
    	{
    		if (_template == null)
    		{
    			_log.warn("hasBetterFarmZone called on phantom with no template " + getActor());
    			PhantomPlayers.terminatePhantom(getActor().getObjectId(), true);
    			return false;
    		}
    		
    		List<PhantomZone> availableZones = _template.getAvailableZones(getActor());
    		if ((availableZones == null) || availableZones.isEmpty())
    		{
    			return false;
    		}
    		
    		for (PhantomZone zone : availableZones)
    		{
    			// Already in good enough zone.
    			if (getActor().getDistance(zone.getRandomTeleportLoc()) <= 8_000)
    			{
    				return false;
    			}
    		}
    		
    		return true;
    	}
    	
    	private boolean isInTown()
    	{
    		if (!getActor().isInPeaceZone())
    		{
    			return false;
    		}
    		
    		for (Zone zone : getActor().getZones())
    		{
    			if (zone.getName().contains("talking_island_town_peace_zone") || zone.getName().contains("darkelf_town_peace_zone") || zone.getName().contains("elf_town_peace") || zone.getName().contains("guldiocastle_town_peace") || zone.getName().contains("gludin_town_peace") || zone.getName().contains("dion_town_peace") || zone.getName().contains("floran_town_peace") || zone.getName().contains("giran_town_peace") || zone.getName().contains("orc_town_peace") || zone.getName().contains("dwarf_town_peace") || zone.getName().contains("oren_town_peace") || zone.getName().contains("hunter_town_peace") || zone.getName().contains("aden_town_peace") || zone.getName().contains("speaking_port_peace") || zone.getName().contains("gludin_port") || zone.getName().contains("giran_port") || zone.getName().contains("heiness_peace") || zone.getName().contains("godad_peace") || zone.getName().contains("rune_peace") || zone.getName().contains("gludio_airship_peace") || zone.getName().contains("schuttgart_town_peace") || zone.getName().contains("kamael_village_town_peace") || zone.getName().contains("keucereus_alliance_base_town_peace") || zone.getName().contains("giran_harbor_peace_alt") || zone.getName().contains("parnassus_peace"))
    			{
    				return true;
    			}
    		}
    		
    		return false;
    	}
    	
    	public void buffFromNpcBuffer(int curTries)
    	{
    		if (!Config.ENABLE_SCHEME_BUFFER || !isInTown())
    		{
    			return;
    		}
    		
    		if (_template == null)
    		{
    			_log.warn("buffFromNpcBuffer called on phantom with no template " + getActor());
    			PhantomPlayers.terminatePhantom(getActor().getObjectId(), true);
    			return;
    		}
    		
    		// Fail buff, schedule another try in 30 sec.A
    		if ((getActor().getPvpFlag() > 0) || getActor().isInCombat())
    		{
    			addTimer(BUFF_TIMER_ID, curTries + 1, 30000);
    		}
    		else
    		{
    			switch (_template.getType())
    			{
    				
    				case DAGGER:
    				case ARCHER:
    					CommunityBoardManager.getInstance().executeBypass(getActor(), "_bbsbuffer getBuffs;Rogue");
    					break;
    				case MAGE:
    					CommunityBoardManager.getInstance().executeBypass(getActor(), "_bbsbuffer getBuffs;Wizzard");
    					break;
    				default: // WARRIOR
    					CommunityBoardManager.getInstance().executeBypass(getActor(), "_bbsbuffer getBuffs;Fighter");
    			}
    			
    			CommunityBoardManager.getInstance().executeBypass(getActor(), "_bbsbuffer getBuffs;noblesse");
    			CommunityBoardManager.getInstance().executeBypass(getActor(), "_bbsbuffer getBuffs;heal");
    			
    			if ((getActor().getEffectList().getAllFirstEffects().length < Config.ALT_BUFF_LIMIT) || (getRemaningBuffTime(false) < 7000)) // Just a check to see if there are any buffs
    			{
    				say("I tried to buff but it didn't buff me right :( I will try " + (5 - curTries) + " more times, next one in 1 min");
    				addTimer(BUFF_TIMER_ID, curTries + 1, 60000);
    			}
    			else
    			{
    				say("I have buffed.");
    			}
    		}
    	}
    	
    	private int getRemaningBuffTime(boolean useCache)
    	{
    		// If this is called in the last 1 minute, it will use cache instead.
    		if (useCache && ((System.currentTimeMillis() - _buffTimeLastCached) <= 60000) && (_buffTimeCache >= 0))
    		{
    			return _buffTimeCache;
    		}
    		
    		int buffTimeLeft = 0;
    		int buffsCount = 0;
    		for (Effect e : getActor().getEffectList().getAllEffects())
    		{
    			if ((e != null) && (e.getSkill().getSkillType() == SkillType.BUFF) && (e.getSkill().getTargetType() != SkillTargetType.TARGET_SELF))
    			{
    				buffTimeLeft += e.getTimeLeft();
    				buffsCount++;
    			}
    		}
    		
    		_buffTimeLastCached = System.currentTimeMillis();
    		
    		// Whoops, almost forgot... I was going to create a black hole if I didnt do that :D
    		if (buffsCount == 0)
    		{
    			_buffTimeCache = 0;
    			return 0;
    		}
    		
    		return _buffTimeCache = (buffTimeLeft / buffsCount);
    	}
    	
    	protected void upgradeClass()
    	{
    		if (_template == null)
    		{
    			_log.warn("upgradeClass called on phantom with no template " + getActor());
    			PhantomPlayers.terminatePhantom(getActor().getObjectId(), true);
    			return;
    		}
    		
    		if ((getActor().getClassId().getLevel() < 4) && // Not 3rd class
    			(((getActor().getLevel() >= 20) && (getActor().getClassId().getLevel() == 1)) || ((getActor().getLevel() >= 40) && (getActor().getClassId().getLevel() == 2)) || ((getActor().getLevel() >= 76) && (getActor().getClassId().getLevel() == 3))))
    		{
    			
    			ClassId nextClass = _template.getNextClass(getActor());
    			if (nextClass != null)
    			{
    				say("My class choice is from " + getActor().getClassId() + " to " + nextClass);
    				getActor().setClassId(nextClass.getId(), false, false);
    			}
    		}
    	}
    	
    	/**
    	 * @return true : if the packet should be forwarded to the client (active players can be set to phantoms too)
    	 */
    	public boolean onPacketRecieved(IStaticPacket p)
    	{
    		return false;
    	}
    	
    	@Override
    	public Player getActor()
    	{
    		return super.getActor();
    	}
    	
    	@Override
    	public boolean isPhantomPlayerAI()
    	{
    		return true;
    	}
    	
    	public long getLastAiResponse()
    	{
    		return _lastAiResponse;
    	}
    	
    	private void say(String text)
    	{
    		for (Player gm : AdminTable.getAllGms(false))
    		{
    			if ((gm != null) && !gm.isBlockAll() && gm.isInRange(getActor(), 500))
    			{
    				gm.sendPacket(new Say2(getActor().getObjectId(), ChatType.ALL, getActor().getName(), text));
    			}
    		}
    	}
    	
    	@Override
    	public void onAiEvent(Creature actor, CtrlEvent evt, Object[] args)
    	{
    		switch (evt)
    		{
    			case EVT_DEAD:
    			{
    				final Player player = actor.getPlayer();
    				int ressurectionDelay = Rnd.get(2, 10) * 1000; // This is here because I dont want instant revive. Lets make it look more player-like
    				_lastWantToFarm = System.currentTimeMillis();
    				
    				say("QQ im dead :( Going to village in " + (ressurectionDelay / 1000) + " seconds.");
    				
    				ThreadPoolManager.getInstance().schedule(() ->
    				{
    					Location loc = Location.getRestartLocation(player.getPlayer(), RestartType.TO_VILLAGE);
    					// Reflection ref = player.getReflection();
    					//
    					// if (ref == ReflectionManager.DEFAULT)
    					// {
    					// for (GlobalEvent e : player.getEvents())
    					// {
    					// loc = e.getRestartLoc(player.getPlayer(), RestartType.TO_VILLAGE);
    					// }
    					// }
    					//
    					// if (loc == null)
    					// {
    					// loc = Location.getRestartLocation(player.getPlayer(), RestartType.TO_VILLAGE);
    					// }
    					//
    					
    					if (loc != null)
    					{
    						player.setPendingRevive(true);
    						player.teleToLocation(loc, ReflectionManager.DEFAULT);
    					}
    					
    					createNewItems();
    				}, ressurectionDelay);
    				break;
    			}
    			case EVT_ATTACKED:
    			{
    				Creature attacker = (Creature) args[0];
    				int damage = (int) args[1];
    				double dmgPer = damage / actor.getCurrentHp();
    				if (attacker.isPlayer())
    				{
    					// Do not touch people in party.
    					if (attacker.getPlayer().isInParty())
    					{
    						return;
    					}
    					
    					if (actor != getActor())
    					{
    						return;
    					}
    					
    					int ggp = attacker.getPlayer().getGearScore();
    					if ((ggp <= actor.getPlayer().getGearScore()) && (dmgPer <= 0.2D)) // If damage is less than 20% of total HP
    					{
    						// If casts skill with remaning cast of 3s or more, abort.
    						if (actor.getCastingTime() > 3000)
    						{
    							actor.abortCast(false, false);
    						}
    						
    						actor.setTarget(attacker);
    						if (actor.isMoving)
    						{
    							thinkActive();
    						}
    						_isWaiting = false;
    					}
    				}
    				else
    				{
    					// If casts skill with remaning cast of 3s or more, abort.
    					if (actor.getCastingTime() > 3000)
    					{
    						actor.abortCast(false, false);
    					}
    					
    					if (getAttackTarget() == null)
    					{
    						setAttackTarget(attacker);
    					}
    					if (getAttackTarget() == attacker)
    					{
    						actor.setTarget(attacker);
    					}
    					Creature target = getAttackTarget();
    					if ((target == null) || (target == attacker) || !getActor().checkTarget(target))
    					{
    						setIntention(CtrlIntention.AI_INTENTION_ATTACK, attacker);
    					}
    					if (actor.isMoving)
    					{
    						thinkActive();
    					}
    					_isWaiting = false;
    				}
    				break;
    			}
    			case EVT_FORGET_OBJECT:
    			{
    				L2Object object = (L2Object) args[0];
    				if (object.isPlayer() && object.isInvisible())
    				{
    					waitTime(10000);
    				}
    				break;
    			}
    			case EVT_SEE_SPELL:
    			{
    				break;
    			}
    			case EVT_TELEPORTED:
    			{
    				final Player player = actor.getPlayer();
    				if (player == null)
    				{
    					return;
    				}
    				
    				if (!player.isPhantom() || !player.getAI().isPhantomPlayerAI())
    				{
    					return;
    				}
    				
    				PhantomPlayerAI ai = ((PhantomPlayerAI) player.getAI());
    				
    				if (ai.isInTown())
    				{
    					ai.say("Lawl, a town. Time to buff, equip and change class if needed.");
    					ai.buffFromNpcBuffer(0);
    					
    					ai.upgradeClass();
    					
    					ai.say("Meh in town, will roam around.");
    					ai.setMood(Rnd.get(new String[]
    					{
    						"free roam",
    						"check npcs",
    						"check shop",
    						"check warehouse"
    					}));
    					ai.createNewItems();
    				}
    				else
    				{
    					// TODO THIS IS FARM
    					waitTime(Rnd.get(2500, 6000));
    					setMood("");
    					_offlineShopsChecked = false;
    					_warehouseChecked = 0;
    					_shopChecked = 0;
    					_npcChecked = 0;
    				}
    				break;
    			}
    			case EVT_TIMER:
    			{
    				int timerId = (int) args[0];
    				switch (timerId)
    				{
    					case WAIT_TIMER_ID:
    						_isWaiting = false;
    						break;
    					case BUFF_TIMER_ID:
    						int tries = (int) args[1];
    						if (tries < 5)
    						{
    							buffFromNpcBuffer(tries);
    						}
    						break;
    				}
    				break;
    			}
    		}
    		
    	}
    	
    	@Override
    	public void onKill(Creature actor, Creature victim)
    	{
    		waitTime(Rnd.get(7, 15) * 100); // Wait 750-1500ms after kill, so it doesnt look like botting
    		
    		if (Rnd.chance(20)) // 20% chance to change loc a bit when killing
    		{
    			Location randomLocation = getRandomLocation(50, 120, 200);
    			if (randomLocation != null)
    			{
    				addTaskMove(randomLocation, 50, true);
    			}
    		}
    		else if (Rnd.chance(2)) // 2% chance to go a bit afk while farming
    		{
    			Location randomLocation = getRandomLocation(50, 200, 200);
    			if (randomLocation != null)
    			{
    				addTaskMove(randomLocation, 50, true);
    			}
    			
    			int time = Rnd.get(4, 10) * 1000;
    			waitTime(time);
    		}
    	}
    	
    	@Override
    	public boolean ignorePetOrSummon()
    	{
    		return true;
    	}
    	
    	@Override
    	public void onLevelChange(int oldLvl, int level)
    	{
    		// When phantom reach max level (85) terminate him.
    		if (level == Experience.getMaxLevel())
    		{
    			final int objectId = getActor().getObjectId();
    			PhantomPlayers.terminatePhantom(objectId, true);
    			PhantomsDAO.getInstance().delete(objectId);
    			CharacterDAO.getInstance().deleteCharByObjId(objectId);
    		}
    	}
    }
    
  12. They are not spawning on their own and they won't start spawning on themselves. Any idea how to fix that, or if there is a working phantoms shere somewhere on the web could you pls provide me with a link?

     

    I think there is an issue in the following code... Because I believe that somewhere in the code the minimum spawns has been set, and I cant change it in the configs so I have to change it from the code itself. The question, however, remains... How do you find where its written?

    	public static class PhantomSpawner implements Runnable
    	{
    		private final int _numSpawns;
    		private final long _delayInMilis;
    		private final boolean _generateNewPhantoms;
    		private int _curSpawns = 0;
    		private Location _loc = null;
    		private ScheduledFuture<?> _task = null;
    		
    		public PhantomSpawner()
    		{
    			_numSpawns = Config.PHANTOM_SPAWN_MAX;
    			_delayInMilis = Config.PHANTOM_SPAWN_DELAY;
    			_generateNewPhantoms = true;
    		}
    		
    		public PhantomSpawner(int numSpawns)
    		{
    			_numSpawns = numSpawns;
    			_delayInMilis = Config.PHANTOM_SPAWN_DELAY;
    			_generateNewPhantoms = true;
    		}
    		
    		public PhantomSpawner(int numSpawns, long delayInMilis)
    		{
    			_numSpawns = numSpawns;
    			_delayInMilis = delayInMilis;
    			_generateNewPhantoms = true;
    		}
    		
    		public PhantomSpawner(int numSpawns, long delayInMilis, boolean generateNewPhantoms)
    		{
    			_numSpawns = numSpawns;
    			_delayInMilis = delayInMilis;
    			_generateNewPhantoms = generateNewPhantoms;
    		}
    		
    		public PhantomSpawner setLocation(Location loc)
    		{
    			_loc = loc;
    			return this;
    		}
    		
    		@Override
    		public void run()
    		{
    			if (_numSpawns == 0)
    			{
    				return;
    			}
    			
    			_task = ThreadPoolManager.getInstance().scheduleAtFixedRate(() ->
    			{
    				if (_curSpawns < _numSpawns)
    				{
    					// Do not spawn more than max phantoms.
    					if (L2ObjectsStorage.getAllPlayersStream().filter(Player::isPhantom).count() >= Config.PHANTOM_MAX_PLAYERS)
    					{
    						return;
    					}
    					
    					int objId = getUnspawnedPhantomObjId();
    					if (objId < 0)
    					{
    						if (_generateNewPhantoms)
    						{
    							try
    							{
    								Player phantom = createNewPhantom();
    								if (phantom != null)
    								{
    									objId = phantom.getObjectId();
    									_log.info("Spawning phantom " + phantom + " through spawner. Cur/Max " + _curSpawns + "/" + _numSpawns);
    								}
    							}
    							catch (Exception e)
    							{
    								_log.error("ERROR: Spawning phantom  through spawner. Cur/Max " + _curSpawns + "/" + _numSpawns, e);
    							}
    						}
    						else
    						{
    							return;
    						}
    					}
    					
    					ThreadPoolManager.getInstance().execute(new PhantomSpawn(objId).setLocation(_loc));
    					_curSpawns++;
    				}
    			}, 0, _delayInMilis);
    		}
    
  13. Hello!

    It happens that I have several custom community boards (5 to be precise). They came with the server files but the problem is that only one is working. The rest have all the htmls and scripts but when I change the folder name in the config, the community board just wont load. PLS HELP!
    I've tried restarting the whole server, not just reloading the Config and Scripts.. it just won't cut it...

    Here are some screenshots:

     

    config
    http://prntscr.com/fnn4y3
     

    Ingrame:

    http://prntscr.com/fnn5gr

     

     The page seems to be blank...

     

    Is there a guide which I can follow in order to properly implement additional CBs?

  14. Heya. I have some real good files but the problem is that I get an error while installing the SQL.

    ERROR 1071 (42000) at line 1: Specified key was too long; max key length is 1000 bytes
    ERROR at line 4: Failed to open file 'Server : localhost', error: 2
    ERROR at line 4: Failed to open file 'Server : mysqlInstaller', error: 2

     

    This is the error I get during the installation of the SQLs into my MySQL. I wonder if it could be the java version or the MySQL version. Is there a way to check which was used while building the files? I mean I have the source and thus ive compiled them myself, but thats not the issue. I just cant figure it out. According to the error code there are too many variables, but where?

  15. Oh, well ... I've used the latest rev of this pack (or at least the latest I could find). I have not checked if the duplicate bug exists, but i believe it can be easily patched. However, If you want to use it - you have to put few days of work into it. The issue with the AIO collumns is easily fixed - there is a backup file, just make 2-nd DB in NaviCat, load the backup there, copy the characters tables and paste them on the first DB. There, however, are other issues, such as configs being in the wrong directory. For this to be fixed you just need to copy the files from config/default to config/. Issue 3 - missing stuff in some of the javas, for example, GiftOfVitality, MasterOfEnchant, etc. You have to manually add some stuff there.

     

    After two days of editing I have finally managed to run it with no errors and with everything on place and I can share with you the compiled pack, but still dont think its worth using it on a live server. I've played on a LIVE using these files and the dupe bug was existing, as well as huge unbalance inbetween classes on both PVP and PVE.

  16. I'm looking to buy a trusted Lineage 2 High Five server pack.
    Multilingual support would be an advantage.
    Also, I'm down for buying a server pack based on L2Emurt project with fixes. I have the latest emurt pack and many features are disabled, so with my limited knowledge, I cant make them work. If someone could help me with unlocking/fixing still works.

     

    Basicly, what I'm looking for is a stable H5 source with working features. Also, I'd like to test the pack I'm buying, so test servers are to be expected prior to the payment.

     

    I will be making customisation, and this is why I'm emphasising on the working features - Customisable and fully working features such as Phantoms, Rebirth, PvPtoExp, PvP reward (AutoEnchant via PvP), Full Community Board (teleporter, stats, shop, etc), event engines, editable formulas for dmg to different types of armor, voice commands, inbuilt protections (FirstGuard, antiBrut, etc), premium system, auction, voice commands, chance of skill success in the chat, etc.
    The following features will be taken into consideration as even greater bonus - Customisable FakeNPCs (NPCs looking like players and to be able to change weapon, armor, race/class), 

×
×
  • Create New...