Jump to content
  • 0

How To Make It Random? Instance


Question

Posted

Hello guys! i have been working on my custom instance, its kamaloka like, but using Tower of insolence, i need help to make "random spawns".

Red letter are the moobs ids declaration and their spawn use, i want to make a list where i declare them and use Random get to spawn. i tried but i failed several times, trust me i spend maaany time on it.

 

Well here is my full code:

package instances.RaidTower;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.logging.Level;

import com.l2jserver.gameserver.datatables.SkillData;
import com.l2jserver.gameserver.instancemanager.InstanceManager;
import com.l2jserver.gameserver.model.L2Party;
import com.l2jserver.gameserver.model.L2Spawn;
import com.l2jserver.gameserver.model.L2World;
import com.l2jserver.gameserver.model.Location;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2MonsterInstance;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.entity.Instance;
import com.l2jserver.gameserver.model.instancezone.InstanceWorld;
import com.l2jserver.gameserver.model.quest.Quest;
import com.l2jserver.gameserver.model.skills.BuffInfo;
import com.l2jserver.gameserver.model.skills.Skill;
import com.l2jserver.gameserver.network.SystemMessageId;
import com.l2jserver.gameserver.network.serverpackets.SystemMessage;

public final class RaidTower extends Quest
{
	/*
	 * Reset time for all RaidTower Default: 6:30AM on server time
	 */
	private static final int RESET_HOUR = 6;
	private static final int RESET_MIN = 30;
	
	/*
	 * Time after which instance without players will be destroyed Default: 5 minutes
	 */
	private static final int EMPTY_DESTROY_TIME = 5;
	
	/*
	 * Time to destroy instance (and eject players away) after boss defeat Default: 5 minutes
	 */
	private static final int EXIT_TIME = 5;
	
	/*
	 * Maximum level difference between players level and RaidTower level Default: 5
	 */
	private static final int MAX_LEVEL_DIFFERENCE = 5;
	
	/*
	 * If true shaman in the first room will have same npcId as other mobs, making radar useless Default: true (but not retail like)
	 */
	private static final boolean STEALTH_SHAMAN = true;
	// Template IDs for RaidTower
	// @formatter:off
	private static final int[] TEMPLATE_IDS =
	{
		1000, 1001, 1002, 1003, 1004
	};
	// Level of the RaidTower
	private static final int[] LEVEL =
	{
		26, 46, 66, 76, 86
	};
	// Duration of the instance, minutes
	private static final int[] DURATION =
	{
		45, 45, 45, 45, 45
	};
	// Maximum party size for the instance
	private static final int[] MAX_PARTY_SIZE =
	{
		2, 2, 2, 2, 2
	};
	
	/**
	 * List of buffs NOT removed on enter from player and pet<br>
	 * On retail only newbie guide buffs not removed<br>
	 * CAUTION: array must be sorted in ascension order!
	 */
	protected static final int[] BUFFS_WHITELIST =
	{
		4322, 4323, 4324, 4325, 4326, 4327, 4328, 4329, 4330, 4331, 5632, 5637, 5950
	};
	// @formatter:on
	// Teleport points into instances x, y, z
	private static final Location[] TELEPORTS =
	{
		new Location(114674, 11458, -5125),
		new Location(114674, 11458, -5125),
		new Location(114674, 11458, -5125), // -76280, -185540, -10936
		new Location(114674, 11458, -5125),
		new Location(114674, 11458, -5125),
	};
	
	// Respawn delay for the mobs in the first room, seconds Default: 25
	private static final int FIRST_ROOM_RESPAWN_DELAY = 25;
	
	/**
	 * First room information, null if room not spawned.<br>
	 * Skill is casted on the boss when shaman is defeated and mobs respawn stopped<br>
	 * Default: 5699 (decrease pdef)<br>
	 * shaman npcId, minions npcId, skillId, skillLvl
	 */
	private static final int[][] FIRST_ROOM =
	{
		{
			22485,
			22486,
			5699,
			1
		},
		{
			22485,
			22486,
			5699,
			1
		},
		{
			22485,
			22486,
			5699,
			1
		},
		{
			22485,
			22486,
			5699,
			1
		},
		{
			22485,
			22486,
			5699,
			1
		},
	};
	
	/*
	 * First room spawns, null if room not spawned x, y, z
	 */
	private static final int[][][] FIRST_ROOM_SPAWNS =
	{
		/* instancia 26 */
		{
			{
				114636,
				15532,
				-5100
			},
			{
				114711,
				15536,
				-5100
			},
			{
				114567,
				15539,
				-5100
			},
			{
				114485,
				15700,
				-5100
			},
			{
				114638,
				15719,
				-5100
			},
			{
				112965,
				17291,
				-4378
			},
			{
				112890,
				17380,
				-4378
			},
			{
				113096,
				17179,
				-4378
			},
			{
				112759,
				16815,
				-4378
			}
		},
		
		/* instancia 46 */
		{
			{
				114636,
				15532,
				-5100
			},
			{
				114711,
				15536,
				-5100
			},
			{
				114567,
				15539,
				-5100
			},
			{
				114485,
				15700,
				-5100
			},
			{
				114638,
				15719,
				-5100
			},
			{
				112965,
				17291,
				-4378
			},
			{
				112890,
				17380,
				-4378
			},
			{
				113096,
				17179,
				-4378
			},
			{
				112759,
				16815,
				-4378
			}
		},
		
		/* instancia 66 */
		{
			{
				114636,
				15532,
				-5100
			},
			{
				114711,
				15536,
				-5100
			},
			{
				114567,
				15539,
				-5100
			},
			{
				114485,
				15700,
				-5100
			},
			{
				114638,
				15719,
				-5100
			},
			{
				112965,
				17291,
				-4378
			},
			{
				112890,
				17380,
				-4378
			},
			{
				113096,
				17179,
				-4378
			},
			{
				112759,
				16815,
				-4378
			}
		},
		
		/* instancia 76 */
		{
			{
				114636,
				15532,
				-5100
			},
			{
				114711,
				15536,
				-5100
			},
			{
				114567,
				15539,
				-5100
			},
			{
				114485,
				15700,
				-5100
			},
			{
				114638,
				15719,
				-5100
			},
			{
				112965,
				17291,
				-4378
			},
			{
				112890,
				17380,
				-4378
			},
			{
				113096,
				17179,
				-4378
			},
			{
				112759,
				16815,
				-4378
			}
		},
		
		/* instancia 86 */
		{
			{
				114636,
				15532,
				-5100
			},
			{
				114711,
				15536,
				-5100
			},
			{
				114567,
				15539,
				-5100
			},
			{
				114485,
				15700,
				-5100
			},
			{
				114638,
				15719,
				-5100
			},
			{
				112965,
				17291,
				-4378
			},
			{
				112890,
				17380,
				-4378
			},
			{
				113096,
				17179,
				-4378
			},
			{
				112759,
				16815,
				-4378
			}
		}
	};
	
	/*
	 * Second room information, null if room not spawned Skill is casted on the boss when all mobs are defeated Default: 5700 (decrease mdef) npcId, skillId, skillLvl
	 */
	private static final int[][] SECOND_ROOM =
	{
		{
			22487,
			5700,
			1
		},
		{
			22490,
			5700,
			2
		},
		{
			22493,
			5700,
			3
		},
		{
			22496,
			5700,
			4
		},
		{
			22499,
			5700,
			5
		}
	};
	
	/*
	 * Spawns for second room, null if room not spawned x, y, z
	 */
	private static final int[][][] SECOND_ROOM_SPAWNS =
	{
		/*instancia 26 */
		{
			{
				114637,
				16223,
				-2127
			},
			{
				114543,
				16083,
				-2127
			},
			{
				114833,
				16099,
				-2127
			},
			{
				114618,
				15848,
				-2127
			},
			{
				114627,
				15637,
				-2127
			},
			{
				116230,
				14822,
				-1414
			},
			{
				116460,
				14922,
				-1417
			},
			{
				116303,
				14973,
				-1414
			},
			{
				116598,
				15466,
				-1414
			}
		},
		/*instancia 46 */
		{
			{
				114637,
				16223,
				-2127
			},
			{
				114543,
				16083,
				-2127
			},
			{
				114833,
				16099,
				-2127
			},
			{
				114618,
				15848,
				-2127
			},
			{
				114627,
				15637,
				-2127
			},
			{
				116230,
				14822,
				-1414
			},
			{
				116460,
				14922,
				-1417
			},
			{
				116303,
				14973,
				-1414
			},
			{
				116598,
				15466,
				-1414
			}
		},
		/*instancia 66 */
		{
			{
				114637,
				16223,
				-2127
			},
			{
				114543,
				16083,
				-2127
			},
			{
				114833,
				16099,
				-2127
			},
			{
				114618,
				15848,
				-2127
			},
			{
				114627,
				15637,
				-2127
			},
			{
				116230,
				14822,
				-1414
			},
			{
				116460,
				14922,
				-1417
			},
			{
				116303,
				14973,
				-1414
			},
			{
				116598,
				15466,
				-1414
			}
		},
		/*instancia 76 */
		{
			{
				114637,
				16223,
				-2127
			},
			{
				114543,
				16083,
				-2127
			},
			{
				114833,
				16099,
				-2127
			},
			{
				114618,
				15848,
				-2127
			},
			{
				114627,
				15637,
				-2127
			},
			{
				116230,
				14822,
				-1414
			},
			{
				116460,
				14922,
				-1417
			},
			{
				116303,
				14973,
				-1414
			},
			{
				116598,
				15466,
				-1414
			}
		},
		/*instancia 86 */
		{
			{
				114637,
				16223,
				-2127
			},
			{
				114543,
				16083,
				-2127
			},
			{
				114833,
				16099,
				-2127
			},
			{
				114618,
				15848,
				-2127
			},
			{
				114627,
				15637,
				-2127
			},
			{
				116230,
				14822,
				-1414
			},
			{
				116460,
				14922,
				-1417
			},
			{
				116303,
				14973,
				-1414
			},
			{
				116598,
				15466,
				-1414
			}
		}
	};
	
	// miniboss info
	// skill is casted on the boss when miniboss is defeated
	// npcId, x, y, z, skill id, skill level
	/*
	 * Miniboss information, null if miniboss not spawned Skill is casted on the boss when miniboss is defeated Default: 5701 (decrease patk) npcId, x, y, z, skillId, skillLvl
	 */
	private static final int[][] MINIBOSS =
	{
		/*intancia 26 */
		{
			25616,
			115376,
			16225,
			-645,
			5701,
			1
		},
		/*intancia 46 */
		{
			25616,
			115376,
			16225,
			-645,
			5701,
			1
		},
		/*intancia 66 */
		{
			25616,
			115376,
			16225,
			-645,
			5701,
			1
		},
		/*intancia 76 */
		{
			25616,
			115376,
			16225,
			-645,
			5701,
			1
		},
		/*intancia 86 */
		{
			25616,
			115376,
			16225,
			-645,
			5701,
			1
		}
	};
	
	/*
	 * Bosses of the RaidTower Instance ends when boss is defeated npcId, x, y, z
	 */
	private static final int[][] BOSS =
	{
		/*intancia 26 */
		{
			18554,
			114671,
			16976,
			928
		},
		/*intancia 46 */
		{
			18555,
			114671,
			16976,
			928
		},
		/*intancia 66 */
		{
			29129,
			114671,
			16976,
			928
		},
		/*intancia 76 */
		{
			18558,
			114671,
			16976,
			928
		},
		/*intancia 86 */
		{
			18559,
			114671,
			16976,
			928
		}
	};
	
	/*
	 * Escape telepoters spawns, null if not spawned x, y, z
	 */
	private static final int[][] TELEPORTERS =
	{
		/*intancia 26 */
		{
			114649,
			17642,
			925
		},
		/*intancia 46 */
		{
			114649,
			17642,
			925
		},
		/*intancia 66 */
		{
			114649,
			17642,
			925
		},
		/*intancia 76 */
		{
			114649,
			17642,
			925
		},
		/*intancia 86 */
		{
			114649,
			17642,
			925
		}
	};
	
	/*
	 * Escape teleporter npcId
	 */
	private static final int TELEPORTER = 80026;
	
	/** RaidTower captains (start npc's) npcIds. */
	private static final int[] CAPTAINS =
	{
		80020,
		80021,
		80022,
		80023,
		80024,
		80026
	};
	
	protected class RaidTowerWorld extends InstanceWorld
	{
		public int index; // 0-18 index of the Raid type in arrays
		public int shaman = 0; // objectId of the shaman
		public List<L2Spawn> firstRoom; // list of the spawns in the first room (excluding shaman)
		public List<Integer> secondRoom;// list of objectIds mobs in the second room
		public int miniBoss = 0; // objectId of the miniboss
		public L2Npc boss = null; // boss
	}
	
	private RaidTower()
	{
		super(-1, RaidTower.class.getSimpleName(), "instances");
		addFirstTalkId(TELEPORTER);
		addTalkId(TELEPORTER);
		for (int cap : CAPTAINS)
		{
			addStartNpc(cap);
			addTalkId(cap);
		}
		for (int[] mob : FIRST_ROOM)
		{
			if (mob != null)
			{
				if (STEALTH_SHAMAN)
				{
					addKillId(mob[1]);
				}
				else
				{
					addKillId(mob[0]);
				}
			}
		}
		for (int[] mob : SECOND_ROOM)
		{
			if (mob != null)
			{
				addKillId(mob[0]);
			}
		}
		for (int[] mob : MINIBOSS)
		{
			if (mob != null)
			{
				addKillId(mob[0]);
			}
		}
		for (int[] mob : BOSS)
		{
			addKillId(mob[0]);
		}
	}
	
	/**
	 * Check if party with player as leader allowed to enter
	 * @param player party leader
	 * @param index (0-18) index of the RaidTower in arrays
	 * @return true if party allowed to enter
	 */
	private static final boolean checkConditions(L2PcInstance player, int index)
	{
		final L2Party party = player.getParty();
		// player must be in party
		if (party == null)
		{
			player.sendPacket(SystemMessageId.NOT_IN_PARTY_CANT_ENTER);
			return false;
		}
		// ...and be party leader
		if (party.getLeader() != player)
		{
			player.sendPacket(SystemMessageId.ONLY_PARTY_LEADER_CAN_ENTER);
			return false;
		}
		// party must not exceed max size for selected instance
		if (party.getMemberCount() > MAX_PARTY_SIZE[index])
		{
			player.sendPacket(SystemMessageId.PARTY_EXCEEDED_THE_LIMIT_CANT_ENTER);
			return false;
		}
		
		// get level of the instance
		final int level = LEVEL[index];
		// and client name
		final String instanceName = InstanceManager.getInstance().getInstanceIdName(TEMPLATE_IDS[index]);
		
		Map<Integer, Long> instanceTimes;
		// for each party member
		for (L2PcInstance partyMember : party.getMembers())
		{
			// player level must be in range
			if (Math.abs(partyMember.getLevel() - level) > MAX_LEVEL_DIFFERENCE)
			{
				SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_LEVEL_REQUIREMENT_NOT_SUFFICIENT);
				sm.addPcName(partyMember);
				player.sendPacket(sm);
				return false;
			}
			// player must be near party leader
			if (!partyMember.isInsideRadius(player, 1000, true, true))
			{
				SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_IN_LOCATION_THAT_CANNOT_BE_ENTERED);
				sm.addPcName(partyMember);
				player.sendPacket(sm);
				return false;
			}
			// get instances reenter times for player
			instanceTimes = InstanceManager.getInstance().getAllInstanceTimes(partyMember.getObjectId());
			if (instanceTimes != null)
			{
				for (int id : instanceTimes.keySet())
				{
					// find instance with same name (RaidTower or labyrinth)
					// TODO: Zoey76: Don't use instance name, use other system.
					if (!instanceName.equals(InstanceManager.getInstance().getInstanceIdName(id)))
					{
						continue;
					}
					// if found instance still can't be reentered - exit
					if (System.currentTimeMillis() < instanceTimes.get(id))
					{
						SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_MAY_NOT_REENTER_YET);
						sm.addPcName(partyMember);
						player.sendPacket(sm);
						return false;
					}
				}
			}
		}
		return true;
	}
	
	/**
	 * Removing all buffs from player and pet except BUFFS_WHITELIST
	 * @param ch player
	 */
	private static final void removeBuffs(L2Character ch)
	{
		Function<BuffInfo, Boolean> removeBuffs = info ->
		{
			if ((info != null) && !info.getSkill().isStayAfterDeath() && (Arrays.binarySearch(BUFFS_WHITELIST, info.getSkill().getId()) < 0))
			{
				info.getEffected().getEffectList().stopSkillEffects(true, info.getSkill());
			}
			return true;
		};
		
		ch.getEffectList().forEach(removeBuffs, false);
		
		if (ch.hasSummon())
		{
			ch.getSummon().getEffectList().forEach(removeBuffs, false);
		}
	}
	
	/**
	 * Handling enter of the players into RaidTower
	 * @param player party leader
	 * @param index (0-18) RaidTower index in arrays
	 */
	private final synchronized void enterInstance(L2PcInstance player, int index)
	{
		int templateId;
		try
		{
			templateId = TEMPLATE_IDS[index];
		}
		catch (ArrayIndexOutOfBoundsException e)
		{
			throw e;
		}
		
		// check for existing instances for this player
		InstanceWorld world = InstanceManager.getInstance().getPlayerWorld(player);
		// player already in the instance
		if (world != null)
		{
			// but not in RaidTower
			if (!(world instanceof RaidTowerWorld) || (world.getTemplateId() != templateId))
			{
				player.sendPacket(SystemMessageId.ALREADY_ENTERED_ANOTHER_INSTANCE_CANT_ENTER);
				return;
			}
			// check for level difference again on reenter
			if (Math.abs(player.getLevel() - LEVEL[((RaidTowerWorld) world).index]) > MAX_LEVEL_DIFFERENCE)
			{
				SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_LEVEL_REQUIREMENT_NOT_SUFFICIENT);
				sm.addPcName(player);
				player.sendPacket(sm);
				return;
			}
			// check what instance still exist
			Instance inst = InstanceManager.getInstance().getInstance(world.getInstanceId());
			if (inst != null)
			{
				removeBuffs(player);
				teleportPlayer(player, TELEPORTS[index], world.getInstanceId());
			}
			return;
		}
		// Creating new RaidTower instance
		if (!checkConditions(player, index))
		{
			return;
		}
		
		// Creating dynamic instance without template
		final int instanceId = InstanceManager.getInstance().createDynamicInstance(null);
		final Instance inst = InstanceManager.getInstance().getInstance(instanceId);
		// set name for the RaidTower
		inst.setName(InstanceManager.getInstance().getInstanceIdName(templateId));
		// set return location
		inst.setSpawnLoc(new Location(player));
		// disable summon friend into instance
		inst.setAllowSummon(false);
		// set duration and empty destroy time
		inst.setDuration(DURATION[index] * 60000);
		inst.setEmptyDestroyTime(EMPTY_DESTROY_TIME * 60000);
		
		// Creating new instanceWorld, using our instanceId and templateId
		world = new RaidTowerWorld();
		world.setInstanceId(instanceId);
		world.setTemplateId(templateId);
		// set index for easy access to the arrays
		((RaidTowerWorld) world).index = index;
		InstanceManager.getInstance().addWorld(world);
		world.setStatus(0);
		// spawn npcs
		spawnRaidTower((RaidTowerWorld) world);
		
		// and finally teleport party into instance
		final L2Party party = player.getParty();
		for (L2PcInstance partyMember : party.getMembers())
		{
			world.addAllowed(partyMember.getObjectId());
			removeBuffs(partyMember);
			teleportPlayer(partyMember, TELEPORTS[index], instanceId);
		}
		return;
	}
	
	/**
	 * Called on instance finish and handles reenter time for instance
	 * @param world instanceWorld
	 */
	private static final void finishInstance(InstanceWorld world)
	{
		if (world instanceof RaidTowerWorld)
		{
			Calendar reenter = Calendar.getInstance();
			reenter.set(Calendar.MINUTE, RESET_MIN);
			// if time is >= RESET_HOUR - roll to the next day
			if (reenter.get(Calendar.HOUR_OF_DAY) >= RESET_HOUR)
			{
				reenter.add(Calendar.DATE, 1);
			}
			reenter.set(Calendar.HOUR_OF_DAY, RESET_HOUR);
			
			SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.INSTANT_ZONE_S1_RESTRICTED);
			sm.addInstanceName(world.getTemplateId());
			
			// set instance reenter time for all allowed players
			for (int objectId : world.getAllowed())
			{
				L2PcInstance obj = L2World.getInstance().getPlayer(objectId);
				if ((obj != null) && obj.isOnline())
				{
					InstanceManager.getInstance().setInstanceTime(objectId, world.getTemplateId(), reenter.getTimeInMillis());
					obj.sendPacket(sm);
				}
			}
			
			// destroy instance after EXIT_TIME
			Instance inst = InstanceManager.getInstance().getInstance(world.getInstanceId());
			inst.setDuration(EXIT_TIME * 60000);
			inst.setEmptyDestroyTime(0);
		}
	}
	
	/**
	 * Spawn all NPCs in RaidTower
	 * @param world instanceWorld
	 */
	@SuppressWarnings("all")
	private final void spawnRaidTower(RaidTowerWorld world)
	{
		int[] npcs;
		int[][] spawns;
		L2Npc npc;
		final int index = world.index;
		
		// first room
		npcs = FIRST_ROOM[index];
		spawns = FIRST_ROOM_SPAWNS[index];
		if (npcs != null)
		{
			world.firstRoom = new ArrayList<L2Spawn>(spawns.length - 1);
			int shaman = getRandom(spawns.length); // random position for shaman
			
			for (int i = 0; i < spawns.length; i++)
			{
				if (i == shaman)
				{
					// stealth shaman use same npcId as other mobs
					npc = addSpawn(STEALTH_SHAMAN ? npcs[1] : npcs[0], spawns[i][0], spawns[i][1], spawns[i][2], 0, false, 0, false, world.getInstanceId());
					world.shaman = npc.getObjectId();
				}
				else
				{
					npc = addSpawn(npcs[1], spawns[i][0], spawns[i][1], spawns[i][2], 0, false, 0, false, world.getInstanceId());
					L2Spawn spawn = npc.getSpawn();
					spawn.setRespawnDelay(FIRST_ROOM_RESPAWN_DELAY);
					spawn.setAmount(1);
					spawn.startRespawn();
					world.firstRoom.add(spawn); // store mobs spawns
				}
				npc.setIsNoRndWalk(true);
			}
		}
		
		// second room
		npcs = SECOND_ROOM[index];
		spawns = SECOND_ROOM_SPAWNS[index];
		if (npcs != null)
		{
			world.secondRoom = new ArrayList<Integer>(spawns.length);
			
			for (int[] spawn : spawns)
			{
				npc = addSpawn(npcs[0], spawn[0], spawn[1], spawn[2], 0, false, 0, false, world.getInstanceId());
				npc.setIsNoRndWalk(true);
				world.secondRoom.add(npc.getObjectId());
			}
		}
		
		// miniboss
		if (MINIBOSS[index] != null)
		{
			npc = addSpawn(MINIBOSS[index][0], MINIBOSS[index][1], MINIBOSS[index][2], MINIBOSS[index][3], 0, false, 0, false, world.getInstanceId());
			npc.setIsNoRndWalk(true);
			world.miniBoss = npc.getObjectId();
		}
		
		// escape teleporter
		if (TELEPORTERS[index] != null)
		{
			addSpawn(TELEPORTER, TELEPORTERS[index][0], TELEPORTERS[index][1], TELEPORTERS[index][2], 0, false, 0, false, world.getInstanceId());
		}
		
		// boss
		npc = addSpawn(BOSS[index][0], BOSS[index][1], BOSS[index][2], BOSS[index][3], 0, false, 0, false, world.getInstanceId());
		((L2MonsterInstance) npc).setOnKillDelay(100);
		world.boss = npc;
	}
	
	/**
	 * Handles only player's enter, single parameter - integer RaidTower index
	 */
	@Override
	public final String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
	{
		if (npc == null)
		{
			return "";
		}
		
		try
		{
			enterInstance(player, Integer.parseInt(event));
		}
		catch (Exception e)
		{
			_log.log(Level.WARNING, "", e);
		}
		return "";
	}
	
	/**
	 * Talk with captains and using of the escape teleporter
	 */
	@Override
	public final String onTalk(L2Npc npc, L2PcInstance player)
	{
		final int npcId = npc.getId();
		
		if (npcId == TELEPORTER)
		{
			final L2Party party = player.getParty();
			// only party leader can talk with escape teleporter
			if ((party != null) && party.isLeader(player))
			{
				final InstanceWorld world = InstanceManager.getInstance().getWorld(npc.getInstanceId());
				if (world instanceof RaidTowerWorld)
				{
					// party members must be in the instance
					if (world.isAllowed(player.getObjectId()))
					{
						Instance inst = InstanceManager.getInstance().getInstance(world.getInstanceId());
						
						// teleports entire party away
						for (L2PcInstance partyMember : party.getMembers())
						{
							if ((partyMember != null) && (partyMember.getInstanceId() == world.getInstanceId()))
							{
								teleportPlayer(partyMember, inst.getSpawnLoc(), 0);
							}
						}
					}
				}
			}
		}
		else
		{
			return npcId + ".htm";
		}
		
		return "";
	}
	
	/**
	 * Only escape teleporters first talk handled
	 */
	@Override
	public final String onFirstTalk(L2Npc npc, L2PcInstance player)
	{
		if (npc.getId() == TELEPORTER)
		{
			if (player.isInParty() && player.getParty().isLeader(player))
			{
				return "80026.htm";
			}
			return "80026-no.htm";
		}
		return "";
	}
	
	@Override
	public final String onKill(L2Npc npc, L2PcInstance player, boolean isSummon)
	{
		final InstanceWorld tmpWorld = InstanceManager.getInstance().getWorld(npc.getInstanceId());
		if (tmpWorld instanceof RaidTowerWorld)
		{
			final RaidTowerWorld world = (RaidTowerWorld) tmpWorld;
			final int objectId = npc.getObjectId();
			
			// first room was spawned ?
			if (world.firstRoom != null)
			{
				// is shaman killed ?
				if ((world.shaman != 0) && (world.shaman == objectId))
				{
					world.shaman = 0;
					// stop respawn of the minions
					for (L2Spawn spawn : world.firstRoom)
					{
						if (spawn != null)
						{
							spawn.stopRespawn();
						}
					}
					world.firstRoom.clear();
					world.firstRoom = null;
					
					if (world.boss != null)
					{
						final int skillId = FIRST_ROOM[world.index][2];
						final int skillLvl = FIRST_ROOM[world.index][3];
						if ((skillId != 0) && (skillLvl != 0))
						{
							final Skill skill = SkillData.getInstance().getSkill(skillId, skillLvl);
							if (skill != null)
							{
								skill.applyEffects(world.boss, world.boss);
							}
						}
					}
					
					return super.onKill(npc, player, isSummon);
				}
			}
			
			// second room was spawned ?
			if (world.secondRoom != null)
			{
				boolean all = true;
				// check for all mobs in the second room
				for (int i = 0; i < world.secondRoom.size(); i++)
				{
					// found killed now mob
					if (world.secondRoom.get(i) == objectId)
					{
						world.secondRoom.set(i, 0);
					}
					else if (world.secondRoom.get(i) != 0)
					{
						all = false;
					}
				}
				// all mobs killed ?
				if (all)
				{
					world.secondRoom.clear();
					world.secondRoom = null;
					
					if (world.boss != null)
					{
						final int skillId = SECOND_ROOM[world.index][1];
						final int skillLvl = SECOND_ROOM[world.index][2];
						if ((skillId != 0) && (skillLvl != 0))
						{
							final Skill skill = SkillData.getInstance().getSkill(skillId, skillLvl);
							if (skill != null)
							{
								skill.applyEffects(world.boss, world.boss);
							}
						}
					}
					
					return super.onKill(npc, player, isSummon);
				}
			}
			
			// miniboss spawned ?
			if ((world.miniBoss != 0) && (world.miniBoss == objectId))
			{
				world.miniBoss = 0;
				
				if (world.boss != null)
				{
					final int skillId = MINIBOSS[world.index][4];
					final int skillLvl = MINIBOSS[world.index][5];
					if ((skillId != 0) && (skillLvl != 0))
					{
						final Skill skill = SkillData.getInstance().getSkill(skillId, skillLvl);
						if (skill != null)
						{
							skill.applyEffects(world.boss, world.boss);
						}
					}
				}
				
				return super.onKill(npc, player, isSummon);
			}
			
			// boss was killed, finish instance
			if ((world.boss != null) && (world.boss == npc))
			{
				world.boss = null;
				finishInstance(world);
			}
		}
		return super.onKill(npc, player, isSummon);
	}
	
	public static void main(String[] args)
	{
		new RaidTower();
	}
}

And parts that i think i should do changes...

private static final int[][] FIRST_ROOM =
	{
		{
			22485,
			22486,
			5699,
			1
		},
		{
			22485,
			22486,
			5699,
			1
		},
		{
			22485,
			22486,
			5699,
			1
		},
		{
			22485,
			22486,
			5699,
			1
		},
		{
			22485,
			22486,
			5699,
			1
		},
	};

_____________________________

private static final int[][] SECOND_ROOM =
	{
		{
			22487,
			5700,
			1
		},
		{
			22490,
			5700,
			2
		},
		{
			22493,
			5700,
			3
		},
		{
			22496,
			5700,
			4
		},
		{
			22499,
			5700,
			5
		}
	};

________________________________________

private static final int[][] MINIBOSS =
	{
		/*intancia 26 */
		{
			25616,
			115376,
			16225,
			-645,
			5701,
			1
		},
		/*intancia 46 */
		{
			25616,
			115376,
			16225,
			-645,
			5701,
			1
		},
		/*intancia 66 */
		{
			25616,
			115376,
			16225,
			-645,
			5701,
			1
		},
		/*intancia 76 */
		{
			25616,
			115376,
			16225,
			-645,
			5701,
			1
		},
		/*intancia 86 */
		{
			25616,
			115376,
			16225,
			-645,
			5701,
			1
		}
	};
	
	/*
	 * Bosses of the RaidTower Instance ends when boss is defeated npcId, x, y, z
	 */
	private static final int[][] BOSS =
	{
		/*intancia 26 */
		{
			18554,
			114671,
			16976,
			928
		},
		/*intancia 46 */
		{
			18555,
			114671,
			16976,
			928
		},
		/*intancia 66 */
		{
			29129,
			114671,
			16976,
			928
		},
		/*intancia 76 */
		{
			18558,
			114671,
			16976,
			928
		},
		/*intancia 86 */
		{
			18559,
			114671,
			16976,
			928
		}
	};
	
	/*
	 * Escape telepoters spawns, null if not spawned x, y, z
	 */
	private static final int[][] TELEPORTERS =
	{
		/*intancia 26 */
		{
			114649,
			17642,
			925
		},
		/*intancia 46 */
		{
			114649,
			17642,
			925
		},
		/*intancia 66 */
		{
			114649,
			17642,
			925
		},
		/*intancia 76 */
		{
			114649,
			17642,
			925
		},
		/*intancia 86 */
		{
			114649,
			17642,
			925
		}
	};

Spawn thing

private final void spawnRaidTower(RaidTowerWorld world)
	{
		int[] npcs;
		int[][] spawns;
		L2Npc npc;
		final int index = world.index;
		
		// first room
		npcs = FIRST_ROOM[index];
		spawns = FIRST_ROOM_SPAWNS[index];
		if (npcs != null)
		{
			world.firstRoom = new ArrayList<L2Spawn>(spawns.length - 1);
			int shaman = getRandom(spawns.length); // random position for shaman
			
			for (int i = 0; i < spawns.length; i++)
			{
				if (i == shaman)
				{
					// stealth shaman use same npcId as other mobs
					npc = addSpawn(STEALTH_SHAMAN ? npcs[1] : npcs[0], spawns[i][0], spawns[i][1], spawns[i][2], 0, false, 0, false, world.getInstanceId());
					world.shaman = npc.getObjectId();
				}
				else
				{
					npc = addSpawn(npcs[1], spawns[i][0], spawns[i][1], spawns[i][2], 0, false, 0, false, world.getInstanceId());
					L2Spawn spawn = npc.getSpawn();
					spawn.setRespawnDelay(FIRST_ROOM_RESPAWN_DELAY);
					spawn.setAmount(1);
					spawn.startRespawn();
					world.firstRoom.add(spawn); // store mobs spawns
				}
				npc.setIsNoRndWalk(true);
			}
		}
		
		// second room
		npcs = SECOND_ROOM[index];
		spawns = SECOND_ROOM_SPAWNS[index];
		if (npcs != null)
		{
			world.secondRoom = new ArrayList<Integer>(spawns.length);
			
			for (int[] spawn : spawns)
			{
				npc = addSpawn(npcs[0], spawn[0], spawn[1], spawn[2], 0, false, 0, false, world.getInstanceId());
				npc.setIsNoRndWalk(true);
				world.secondRoom.add(npc.getObjectId());
			}
		}
		
		// miniboss
		if (MINIBOSS[index] != null)
		{
			npc = addSpawn(MINIBOSS[index][0], MINIBOSS[index][1], MINIBOSS[index][2], MINIBOSS[index][3], 0, false, 0, false, world.getInstanceId());
			npc.setIsNoRndWalk(true);
			world.miniBoss = npc.getObjectId();
		}
		
		// escape teleporter
		if (TELEPORTERS[index] != null)
		{
			addSpawn(TELEPORTER, TELEPORTERS[index][0], TELEPORTERS[index][1], TELEPORTERS[index][2], 0, false, 0, false, world.getInstanceId());
		}
		
		// boss
		npc = addSpawn(BOSS[index][0], BOSS[index][1], BOSS[index][2], BOSS[index][3], 0, false, 0, false, world.getInstanceId());
		((L2MonsterInstance) npc).setOnKillDelay(100);
		world.boss = npc;
	}

Thanks in advance... i have maaany ideas but my java skills are killing meh... i learn so fcking slow

13 answers to this question

Recommended Posts

  • 0
Posted (edited)

Can't understand very clearly that "random spawns"..

 

as u can see there is listed every npc to each room:

 

/**

     * First room information, null if room not spawned.<br>

     * Skill is casted on the boss when shaman is defeated and mobs respawn stopped<br>

     * Default: 5699 (decrease pdef)<br>

     * shaman npcId, minions npcId, skillId, skillLvl

     */

private static final int[][] FIRST_ROOM =

    {

        {                                                            THIS IS FOR instance lvl 26

            22485,

            22486,

            5699,

            1

        },

        {                                                            THIS IS FOR instance lvl 36

            22485,

            22486,

            5699,

            1

        },

 

so i want to change it to 3 or 4 npcs, and when instance start spawns just take 1 of these 4 npc's ids

 

live this

 

{                                                            THIS IS FOR instance lvl 26

            22485, 22486, 5699,1;

            22585, 22586, 5699,1;

            22685, 22686, 5699,1;

        },

        {                                                            THIS IS FOR instance lvl 36

            22485, 22486, 5699,1;

            22585, 22586, 5699,1;

            22685, 22686, 5699,1;

        },

Edited by Rsx - HellaFlush
  • 0
Posted (edited)

Use multiple XML template.

 

You can manage different spawn from there with the same name.

 

You can also spawn any group define in here with 2 lines of code instead of managing ugly array in java.

Edited by Sdw
  • 0
Posted

Small hint, if you really want to use arrays:

import java.util.Random;

public class Test {

	private static final int[][][] FIRST_ROOM =
	{
		{
			{22485, 22486, 5699,1},
			{22585, 22586, 5699,1},
			{22685, 22686, 5699,1}
		},
		{
			{22785, 22786, 5699,1},
			{22885, 22886, 5699,1},
			{22985, 22986, 5699,1}
		}
	};
	
	
	public static void main(String[] args) {
		
		System.out.printf("element[%d] = %s%n", 0, FIRST_ROOM[0][randomTemplate(0, FIRST_ROOM[0].length - 1)][0]);
	}
	
	
	public static int randomTemplate(int min, int max)
	{
	    Random rand = new Random();

	    int randomNum = rand.nextInt((max - min) + 1) + min;

	    return randomNum;
	}
}
  • 0
Posted

Just don't do that :|

 

It's less messier, easier to read, whatever you want to do 2 XML templates and based on which version he wants just load the proper xml.

 

Then having groups like this in his templates :

		<group name="my_first_room_whatever">
			<!-- Krakia Bathus -->
			<spawn npcId="27437" x="-107726" y="209248" z="-10872" heading="49536" respawn="0" allowRandomWalk="false"  />
			<spawn npcId="27437" x="-107926" y="209248" z="-10872" heading="49536" respawn="0" allowRandomWalk="false"  />
			<spawn npcId="27437" x="-108096" y="209248" z="-10872" heading="49536" respawn="0" allowRandomWalk="false"  />
		</group>

with shared names for the first room, he can spawn them using :

final Instance inst = InstanceManager.getInstance().getInstance(world.getInstanceId());
final List<L2Npc> spawnedNpcs = inst.spawnGroup("my_first_room_whatever");
  • 0
Posted (edited)
final Instance inst = InstanceManager.getInstance().getInstance(world.getInstanceId());
final List<L2Npc> spawnedNpcs = inst.spawnGroup("my_first_room_whatever");

 

lmao, you really felt that you had to include the final even in the damn example

Edited by drake2wow
  • 0
Posted (edited)

Or I just made a copy paste

 

Thats an acceptable excuse but the point is, do you and the l2j guys know that final vars inside methods have no performance impact or whatsoever? They are just used for code readability and on rare cases as precompile info for the compiler when in rare cases it will ignore dead code

Edited by drake2wow
  • 0
Posted

We do know what assumed final is, but it's oftenly used for readability in company world. Why not here ?

  • 0
Posted

We do know what assumed final is, but it's oftenly used for readability in company world. Why not here ?

 

I remember back in some l2j refactoring era, they really felt like they had to set everything final

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



  • Posts

    • Super responsive, clearly understood what I needed, and delivered everything on time — even going the extra mile with small details I hadn’t thought of. The CMS looks amazing and runs flawlessly on all devices. If you’re looking for reliable, skilled, and easy-to-work-with web devs, I 100% recommend him.
    • Hello guys, I’d like to introduce your audience to my original project, which has gained popularity in Europe and among the Russian-speaking community. I just never got around to posting about it here until now. At one point, I wanted to develop a launcher (game file downloader) in the browser, and that idea eventually evolved into a full-fledged CMS engine with extensive functionality. SphereWeb is a massive ecosystem for Lineage 2 JAVA servers, packed with everything a server administrator and players might need. From October 2024 to April 24, 2025, my project has been installed on 250 different domains. SphereWeb is your best choice — a modern web engine designed specifically for administrators of Lineage 2 Java game servers. It offers a rich and user-friendly interface for managing your server with ease. ✅ Player Control Panel – covers all player needs: Authorization, registration, password change, account linking and synchronization, contacting the admin via support system, teleporting a character (and sending items to warehouse) to a town, warehouse management (sending items in-game), and making server donations. ✅ Admin Control Panel – opens up new horizons, giving you access to: Extensive panel customization (more on this later) Donation history with charts News and page creation Stream management (add streams) Item shop creation Starter packs creation Bonus code generation XenForo news integration Email message settings Global activity log Traffic insights (track where your users come from) Extensions section (plugins – more on that later) Server management Auto software updates Tech support Custom translations Now, about the Control Panel settings: The standard settings are organized into several tabs: Language There are 5 available languages: Russian, English, Spanish, Portuguese, and Greek, covering 99% of translation needs. You can also set a default language for the panel.   Features Toggle built-in features of the control panel: News, Shop, Balance, Statistics, Support, Balance Transfer, Bonus Code, Streams, Data Emulation. Enable/disable options to keep the panel clean and focused on what you need. Captcha Support for Google reCAPTCHA, Cloudflare Turnstile, or default hCaptcha. Old-school recommendation: use Google reCAPTCHA v2. Fake Online Boosting Basic settings for boosting the online counter. Registration Settings Configuration options for the registration process. Email Connect your panel to an SMTP server. Misc General-purpose settings and adjustments. Template Choose and preview the design template for your landing page. Logo Upload your control panel logo and favicon. Palette Customize the color scheme of your control panel interface. Menu Add links to your site’s navigation menu. Background Upload high-resolution background images for login, registration, and password recovery pages. Notifications Set up Telegram notifications for selected events. In Sphere 2, I’ve paid special attention to plugins, making it easy to add and expand functionality. By default, the panel includes several built-in extensions (plugins).   Giveaway – allows you to host item giveaways for users directly on the website. Internal Forum – a built-in forum system inside the Control Panel (more details on it below). Launcher – a free solution for updating game files. It delivers unmatched speed and runs directly in the browser, allowing full design customization. Traders – (currently for Lucera2 only) displays a list of offline shops, their items, prices, and player locations directly on the website. Roulette – a fun game where users spin the wheel to win items. Item Editor – a tool for creating custom in-game items. Item Increase – tracks and displays item count by ID across the server in graph form, showing which players hold the most. Registration Statistics – a simple chart showing registration trends over time. SQL Collection – a plugin for adding or adjusting Java server builds if your current build isn’t supported or needs customization. ✅ Supported Java Server Builds The system currently supports a variety of popular Java server builds. Full list available in the admin panel. 🧩 Forum Plugin In the first version of Sphere, a basic internal forum was quite popular among server admins — so in Sphere 2, it came back better than ever. Inspired by XenForo, the forum is rich in features and designed for both community and solo players: Players can create clan communities to connect and play together. Clan creators can upload clan logos and header banners, customize text color for the clan name. Clan members can post on the public clan wall or chat in a dedicated clan chat. Clan logos and banners appear across the forum for all members. For players who like to show off: Under each username, the forum can display PvP/PK stats, in-game time, and character list. Players can choose to hide this data if they prefer privacy. Admins can assign moderator roles to users for specific forum sections, ensuring proper content management and community moderation.   💰 Donations & Rewards The administrator has a wide range of reward settings for player donations — almost every suggested method has been implemented: Cumulative discount system – discounts increase as the total donation amount grows. One-time bonus – an extra reward for a specific donation. Permanent shop discounts – based on the player's total donation history. One-time item shop discounts – also based on total donations. Item-based rewards – configurable rewards delivered automatically after donation. ✅ Supported Payment Systems (Current list is available in the admin panel and may vary by region.) 🔄 SphereWeb Auto-Update System Sphere is actively developed — I improve it almost daily. To ensure everyone stays updated, I’ve implemented multiple update methods: Automatic – once I push updates to GitHub, they are downloaded to Sphere clients within 5 minutes. Manual – if automatic updates are disabled or your site was offline during update release, you can trigger the update manually with one click. File Scanner – this feature scans your Sphere installation, compares files with the latest version, and shows missing or modified files you can restore. 📸 Control Panel Screenshots (Here you’d typically show screenshots or say where they can be found.)   💬 Final Words A lot of work has gone into this project. I occasionally post updates in the Sphere Telegram channel — when I don’t forget. I’m truly proud of the results. 🚀 Want to Install It? Before you rush in, please note: Installation won’t work on localhost. A valid SSL certificate is required. Repo: GitHub - Cannabytes/SphereWeb2 Upload the archive to your hosting. Open your website in the browser — the installer will guide you. ⚠️ Some Russian hosting providers block wide IP ranges, which may interfere with installation. 💸 Pricing Three usage plans available: Free – limited to 20 game account registrations per day. $12.5/month – no Sphere limitations. $20/month – no Sphere limitations + access to all commercial plugins. Your balance is shown in the admin panel, and you can renew access anytime. ✅ All users receive updates, regardless of subscription tier. A lot of work has been done, and from time to time I share updates in the Sphere Telegram channel — when I don’t forget. I’m truly proud of what I’ve built. Did you like it? Want to install it yourself? Please note — you won’t be able to install it on a local server. A valid SSL certificate is also required. Steps to install: Download the package from the GitHub repository: Cannabytes/SphereWeb2 Extract the archive on your hosting. Open your website in a browser — the installer will launch automatically. Just follow the instructions. 🔧 Minimum Requirements: PHP 8.2 MariaDB or MySQL 5.8 SSL certificate for your website   💵 Pricing SphereWeb offers 3 usage options: Free Plan – limited to 20 game account registrations per day. $12.5/month – no limitations, full access to Sphere features. 3. $20/month – no limitations + access to all commercial plugins. Your current balance is shown in the admin panel, and you can renew your license whenever you wish. Regardless of your plan, you will always receive updates. 🆕 Latest Updates: User Registration Source Tracking: Now, when a user registers, you can see where they came from before landing on the site via Telegram notifications. Bulk Deletion of Bonus Codes: Added functionality to bulk delete bonus codes for better management. Starter Pack Editor: A new editor for creating and managing starter packs is now available. Item Removal from Warehouse: Admins can now remove items from a user's warehouse. Server-Specific Settings: Each server now has a "Functions" button, providing additional customization options for each server. Warehouse Cleanup: Admins can now clear the warehouse for all users or by specific item ID. Custom Return Button: The "Return to Site" button can now be disabled, and you can set a custom link for it. Character List UI Overhaul: The character list in the admin panel has been redesigned to be more minimalist and user-friendly. User Info Page Improvements: The user information page has been enhanced for better navigation and access to key data. Donation History Updates: The donation history page has been improved for better data presentation. Item Stacking and Splitting: Users can now stack or split identical items (e.g., ID 57 (150) + ID 150 = ID 57 (300)). Admins can configure which items can be stacked and split. Account Deletion: Users now have the option to delete their own accounts from the account list. Success Chest Plugin: A new "Success Chest" plugin has been added, allowing admins to define chests with specific items, their prices, and visual parameters. Reworked Warehouse: The warehouse now operates in a separate modal window. When items are purchased, they are automatically added to the warehouse without page reloads. Registration Reward: Admins now have the ability to reward users for registration, adding more incentives. Item Stacking and Splitting Customization: Admins can now specify which items players can split and stack in their warehouse. These settings are available in the admin panel under the server's "Functions" button, offering granular control over item management. Account Deletion Feature: Players now have the ability to remove their accounts from the account list (but not from the server). In the future, this feature will be customizable for each server. Success Chest Plugin: A new "Success Chest" plugin has been added, allowing admins to define the items inside the chest. Players can then randomly draw one item from the chest. This feature is still in early testing, and any feedback or issues will be addressed in future updates. Improved Warehouse/Inventory: The warehouse/inventory system has been enhanced. Now, when items (such as starter packs or chests) are purchased, they are immediately added to the warehouse without requiring a page refresh. Additionally, the modal window for the warehouse now opens when the warehouse button is clicked with the mouse wheel. 😊 Log Sorting by Server: Logs now include the ability to sort by server, making it easier to manage and review data for each individual server. Registration Source Tracking: Telegram notifications now include information about where a user came from before registering on your site. Bulk Deletion of Bonus Codes: Admins can now bulk delete server-specific bonus codes, as well as bonus codes that were generated for all servers. Customizable Starter Packs: A new option has been added to modify and customize starter packs, giving more flexibility to server admins. Item Removal from Warehouse in Profile: Admins can now remove items from a user's warehouse directly from their profile. "Functions" Button in Admin Panel: A new "Functions" button has been added to the admin panel, offering additional tools for server management. This includes the ability to clear the server’s warehouse entirely or by specific item ID. Disabling the "Return to Site" Button: Under Admin Panel -> Settings -> Miscellaneous, there is now an option to disable the "Return to Site" button in the site menu
    • We are waiting you today at 8pm +3 GMT website: https://l2evo.net The patch will be available 30 min before the grand opening. Come join the best Interlude pvp server.  
    • We are certainly not an ambulance, but we will definitely cure you of blacklists and empty pockets. Live freely with SX! Each of you will receive a trial version of SX to familiarize yourself with the product, all you have to do is post in this thread
  • Topics

×
×
  • Create New...